FSharpGrammar

Jan 20, 2010 at 1:18 PM

Hello!

My task is to create Grammar for F# (functional programming language) using Irony.

Is there any sample open source projects been already developed?So I could expand it.

Thanks   

 

Coordinator
Jan 20, 2010 at 4:46 PM

No, there's no F# sample, and I never heard about anybody doing it. F# is indentation sensitive, as far as I remember, so your best approach would be to start with miniPython sample - it employs indentation stuff. Let me know if you need any help

Feb 9, 2010 at 2:47 PM

Thanks for your advice,it was helpfull. I've developed F# grammar that supports all the constructions I need.

The trouble is in error recovering : I need to be able to continue parsing input even if there is language expression that is unsupported by my grammar. Maybe this trouble can be resolved using  ErrorRule,but I do not understand how to use it correctly.

If I use Stmt.ErrorRule = SyntaxError + Eos;ExtStmt.ErrorRule = SyntaxError +Eos;//it does not work

Here is my grammar.I appreciate any your advice.

BNF rules
            //Basis
            Open.Rule = Empty | "open" + identifier + qual_name_segments_opt + Eos;
            //qualified_identifier.Rule = MakePlusRule(qualified_identifier, dot, identifier);
            qual_name_segments_opt.Rule = MakeStarRule(qual_name_segments_opt, null, qual_name_segment);
            qual_name_segment.Rule = dot + identifier;
            Expr.Rule = Term | UnExpr | BinExpr;
            expr_opt.Rule = Empty | Expr;
            Term.Rule = Literal | ParExpr | identifier | FunctionCall | identifier + qual_name_segments_opt;
            Literal.Rule = number | StringLiteral | "true" | "false" | "null";
            ParExpr.Rule = "(" + expr_opt + ")";
            UnExpr.Rule = UnOp + Term;
            UnOp.Rule = ToTerm("+") | "-";
            BinExpr.Rule = Expr + BinOp + Expr
                           | Expr + CmpOp + Expr;
            BinOp.Rule = ToTerm("+") | "-" | "*" | "/" | "**";
            CmpOp.Rule = ToTerm(">") | "<" | ">=" | "<=" | "<>" | "=" | "compare";
            CondExpr.Rule = "if" + Expr + "then" + Eos + Block
                            |"if" + Expr + "then" + Eos + Block + "else" + Eos + Block;
            AssignmentStmt.Rule = "let" + identifier + "=" + Expr;
            AssignmentStmt.ErrorRule = SyntaxError + Eos;
            Stmt.Rule =  AssignmentStmt | Expr;
            ExtStmt.Rule = Stmt + Eos | FunctionDef | module_declarations_opt | type_declarations_opt | CondExpr;
            Block.Rule = Indent + StmtList + Dedent;
            Block.ErrorRule = SyntaxError + Eos;

            block_opt.Rule = Empty | Eos | Block;
            StmtList.Rule = MakePlusRule(StmtList, ExtStmt);
            ParamWithType.Rule = identifier + ":" + identifier;
            ParamList.Rule = MakeStarRule(ParamList, comma, identifier) | "(" + MakeStarRule(ParamList,comma,ParamWithType) + ")";
            ArgList.Rule = MakeStarRule(ArgList, comma, Expr);
            FunctionDef.Rule = attributes_opt + "let" + identifier + ParamList + "=" + expr_opt + Eos + block_opt;
            FunctionCall.Rule = identifier + ArgList;
            
            //Namespaces,modules,types
            
            open_directives_opt.Rule = MakePlusRule(open_directives_opt, Open);
            namespace_declaration.Rule = "namespace" + identifier + qual_name_segments_opt + Eos + namespace_body;
            namespace_body.Rule = Indent + open_directives_opt + module_declarations_opt + Dedent;
            module_declarations_opt.Rule = Empty | "module" + identifier + "=" + Eos + module_body;
            module_body.Rule = Block;//not implemented yet
            type_declarations_opt.Rule = Empty | "type"  + identifier + "=" + Eos + type_body;
            type_body.Rule = Block;//not implemented yet 

            //Attributes

            attributes_opt.Rule = MakeStarRule(attributes_opt, null, attribute_section);
            attribute_section.Rule = "[" +"<" + attribute_list  + ">" + "]" + Eos;
            attribute_list.Rule = MakePlusRule(attribute_list, semicolon, attribute);
            attribute.Rule = identifier + attribute_arguments_par_opt;
            attribute_arguments_par_opt.Rule = Empty | "(" + attribute_arguments_opt + ")";
            attribute_arguments_opt.Rule = MakeStarRule(attribute_arguments_opt, comma, attr_arg);
            attr_arg.Rule = Expr;
            
            this.Root = namespace_declaration;       // Set grammar root

 

Coordinator
Feb 10, 2010 at 4:55 PM

Hi

First of all, before you try to add error recovery, you should make sure your grammar is OK and parses correctly some sample programs. So let's focus on correctness of the grammar. You listed only a grammar constructor code, but there are some other important pieces that should be there. Your grammar is indent-sensitive, like Python, you use Eos symbol in grammar just like Python grammar. It means that you need to add "CodeOutlineFilter" to scanner processing chain - are you doing this? Anyway, please post the entire source code for the grammar class. Or email me directly the zip with your project (contact me directly through codeplex, I will reply and you'll send me the zip).

Now to your current grammar -  I see some problems.

1. ParamList definition

   ParamList.Rule = MakeStarRule(ParamList, comma, identifier) | "(" + MakeStarRule(ParamList,comma,ParamWithType) + ")";

- this is a wrong way to use MakeStarRule, don't "OR" it this way. It should always be a single MakeStarRule on the right.

2. BlockRule:

            Block.Rule = Indent + StmtList + Dedent;
            Block.ErrorRule = SyntaxError + Eos;
  this is incorrect - ErrorRule should always end with the same symbol as the main "Rule". What you tell parser is that "in case of error, skip everything until this symbol" - where this symbol is the last terminal in regular Rule. So it should be "Block.ErrorRule = SyntaxError + Dedent;"

The same goes for AssignmentStmt. For now, remove all ErrorRule assignments, let's focus on building correct grammar, and then moving to error recovery

3. qual_name_segments_opt.Rule definition.

  You define name segment as "dot + identifier", and then build a star-list with null delimiter. It is better to simply build it as a star-list of identifiers with dot as list delimiter (second parameter to MakeStarRule function).

4. Minor things - I think you can simplify things a bit. Why you separate "BinOp" and "CmpOp", and define BinExpr as "OR" of two types? would be simpler to include CmpOp symbols into BinOp - they are all binary operators. CondExpr - should be simplified, define else_clause_opt expression and use it in a single "+" expression.

Let's clear it up