Need Help

May 3, 2011 at 8:32 AM
Edited May 4, 2011 at 9:37 AM

I am trying to create the a parser with the following BNF

<action>                 ::= {<statement>} // How do I write this in irony ??
<statement>             ::= <FOR-statement>|
                            <IF-DO-statement>|
                            <IF-ELSE-statement>|
                            <effect>|
                            {}
<FOR-statement>         ::= FOR <FOR-variable>
                            <action>
                            ENDFOR
<FOR-variable>             ::= EACH BOOK|COVER TYPES [<cover-List>]
<cover-list>             ::= {<cover-type>}{;<cover-type>}
<cover-type>             ::= COMP|TPFT|TPO
<IF-DO-statement>         ::= IF
                                <condition>
                            DO
                                <action>
                            ENDIF
<IF-ELSE-statement>        ::= IF
                              <condition>
                            THEN
                                <action>
                            ELSE
                                <action>
                            ENDIF
<condition>             ::= <cause>|
                            ( NOT <condition> )|
                            ( <condition> <logic-operator> <condition>} )|
                            ()
<logic-operator>        ::= AND|OR
<cause>                 ::= "{"<text>|[<parameter>]"}"
<effect>                 ::= "{"<text>|[<parameter>]"}"
<text>                     ::= [<char>]
<parameter>             ::= "["<table-parameter-value>|<other-parametervalue>"]"
<table-parametervalue>  ::= [<alphanumeric>].<numeric><numeric><numeric>
<other-parametervalue>  ::= <text>
<char>                     ::= <alpha>|<numeric>|<TMSL-symbol>
<alpha>                 ::= "A"-"Z" "a"-"z" " "
<numeric>                 ::= "0"-"9"
<TMSL-symbol>             ::= "-" | "." | ";" | "%" | "£"

 

I have written the Grammar class for it as below but i get Parser error "expected For If..." Parser state s14

using System;
using System.Collections.Generic;
using System.Text;
using Irony.Parsing;
using Irony.Ast;

namespace Irony.Samples.My
{
    public class MyGrammar : Irony.Parsing.Grammar
    {
        public MyGrammar()
        {
            StringLiteral text = new StringLiteral("text", "\"", StringOptions.AllowsAllEscapes);
            NumberLiteral number = new NumberLiteral("number");

            NonTerminal text1 = new NonTerminal("text");
            NonTerminal acion = new NonTerminal("action");
            NonTerminal statement = new NonTerminal("statement");
            NonTerminal FOR_statement = new NonTerminal("FOR-statement");
            NonTerminal FOR_variable = new NonTerminal("FOR-variable");
            NonTerminal cover_list = new NonTerminal("cover-list");
            NonTerminal cover_type = new NonTerminal("cover-type");
            NonTerminal IF_DO_statement = new NonTerminal("IF-DO-statement");
            NonTerminal IF_ELSE_statement = new NonTerminal("IF-ELSE-statement");
            NonTerminal condition = new NonTerminal("condition");
            NonTerminal logic_operator = new NonTerminal("logic-operator");
            NonTerminal cause = new NonTerminal("cause");
            NonTerminal effect = new NonTerminal("effect");
            //NonTerminal text = new NonTerminal("text");
            NonTerminal parameter = new NonTerminal("parameter");
            NonTerminal table_parametervalue = new NonTerminal("table-parametervalue");
            NonTerminal other_parametervalue = new NonTerminal("other-parametervalue");
            //NonTerminal chars = new NonTerminal("char");
            //NonTerminal alpha = new NonTerminal("alpha");
            //NonTerminal numeric = new NonTerminal("numeric");

            text1.Rule = text | number ;

            // <statement> ::= <FOR-statement>|<IF-DO-statement>|<IF-ELSE-statement>|<effect>|{}
            statement.Rule = FOR_statement | IF_DO_statement | IF_ELSE_statement | effect | "(" + Empty + ")";

            //<FOR-statement>::= FOR <FOR-variable><action>ENDFOR
            FOR_statement.Rule = ToTerm("FOR") + FOR_variable + acion + ToTerm("ENDFOR");

            //<FOR-variable> ::= EACH BOOK|COVER TYPES [<cover-List>]
            FOR_variable.Rule = ToTerm("EACH BOOK") | ToTerm("COVER TYPES") + "[" + cover_list + "]";

            //<cover-type> ::= COMP|TPFT|TPO
            //cover_type.Rule = "COMP" | "TPFT" | "TPO";
            cover_type.Rule = "COMP";

            //<cover-list> ::= {<cover-type>}{;<cover-type>}
            cover_list.Rule = cover_type;

            // <IF-DO-statement> ::= IF	<condition>	DO <action> ENDIF
            IF_DO_statement.Rule = ToTerm("IF") + condition + ToTerm("DO") + acion + ToTerm("ENDIF");

            //<IF-ELSE-statement>	::= IF <condition> THEN <action> ELSE <action> ENDIF
            IF_ELSE_statement.Rule = ToTerm("IF") + condition + ToTerm("THEN") + acion + ToTerm("ELSE") + acion + ToTerm("ENDIF");

            // <condition> ::= <cause>|( NOT <condition> )|( <condition><logic-operator> <condition>} )|()
            condition.Rule = cause |
                            "(" + ToTerm("NOT") + condition + ")" |
                            "(" + condition + logic_operator + condition + ")" |
                            "(" + Empty + ")";

            //<logic-operator> ::= AND|OR
            logic_operator.Rule = ToTerm("AND") + ToTerm("OR");

            //<cause> ::= "{"<text>|[<parameter>]"}"
            cause.Rule = "{" + text1 | "[" + parameter + "]" + "}";

            //<effect> ::= "{"<text>|[<parameter>]"}"
            effect.Rule = "{" + text1 | "[" + parameter + "]" + "}";

            //<text> ::= [<char>]
            //text.Rule = new StringLiteral("text", "\"", StringOptions.AllowsAllEscapes);

            //<parameter> ::= "["<table-parameter-value>|<other-parametervalue>"]"
            //parameter.Rule = "[" + table_parametervalue | other_parametervalue + "]";
            parameter.Rule = "[" + other_parametervalue + "]";

            //<other-parametervalue>  ::= <text>
            other_parametervalue.Rule = text1;

            acion.Rule = MakePlusRule(acion, NewLine, statement);

            this.Root = acion;
        }
    }
}

I feel that I have not defined the options elements correctly. It would be great if anyone could point me to the right direction being a newbie I am stuck here.

Thanks

Muffadal.
Coordinator
May 3, 2011 at 8:25 PM

a few small things: 

"action" var is misspelled (acion)

you have 2 elements named "text", the non-terminal should be "text1" probably; from its definition "term" is a better name

logic_operator seems wrong - should be "|" between terms, not "+"

Now, after you fix these, load your grammar into grammar explorer - see if it shows any errors. If yes, fix them - fix grammar errors before you do any parsing

Then try to parse a sample. If it gives you error, double-click it and goto parser state for the error, look at productions, see what's wrong in your definitions

Roman

May 4, 2011 at 9:36 AM
Edited May 4, 2011 at 9:39 AM

Hello Roman,

Thanks for the prompt reply. I have managed to parse the sample text without any errors. However I am not sure if I have done this correctly.

  1. every cause will have a string that will have parameters wrapped inside square brackets "[]". I am planning to use regex to extract this info from the text.
  2. In the "FOR" rule the "[" & "]" is appearing in the parser tree as Keyword. How to remove these?
  3. Also constants values of the cover types (CP|TF|TP) are also appearing as keyword.
  4. I have changed the ctor of the StringLiteral class to accept different start and end strings. Is there a better way to do this
  5. If u see I have put NewLine in almost every rule, If I remove them I get syntax error. I want the parser to work the same way even if the New line feed is missing in the text.

I have put the code for the grammar below.

 

public class MyGrammar : Grammar
    {
        public MyGrammar()
        {
            StringLiteral stringLiteral = new StringLiteral("stringLiteral", "{", "}");
            NumberLiteral number = new NumberLiteral("number");

            NonTerminal text = new NonTerminal("text");
            NonTerminal block = new NonTerminal("block");
            NonTerminal statement = new NonTerminal("statement");
            NonTerminal for_cover = new NonTerminal("for-cover-types");
            NonTerminal for_each_driver = new NonTerminal("for-each-driver");
            NonTerminal cover_list = new NonTerminal("cover-list");
            NonTerminal cover_type = new NonTerminal("cover-type");
            NonTerminal if_do_endif = new NonTerminal("if-do-endif");
            NonTerminal if_else_endif = new NonTerminal("if-else-endif");
            NonTerminal condition = new NonTerminal("condition");
            NonTerminal logic_operator = new NonTerminal("logic-operator");
            NonTerminal cause = new NonTerminal("cause");
            NonTerminal effect = new NonTerminal("effect");
            NonTerminal TMSL_symbol = new NonTerminal("TMSL-symbol");

            //NonTerminal FOR_statement = new NonTerminal("FOR-statement");
            //NonTerminal parameter = new NonTerminal("parameter");
            //NonTerminal table_parametervalue = new NonTerminal("table-parametervalue");
            //NonTerminal other_parametervalue = new NonTerminal("other-parametervalue");
            //NonTerminal FOR_variable = new NonTerminal("FOR-variable");

            text.Rule = stringLiteral | number; 

            // <statement> ::= <FOR-statement>|<IF-DO-statement>|<IF-ELSE-statement>|<effect>|{}
            statement.Rule = for_cover | for_each_driver | if_do_endif | if_else_endif | cause | effect | "(" + Empty + ")";

            for_cover.Rule = ToTerm("FOR BOOK COVER") + "[" + cover_list + "]" + "DO" + NewLine +
                                block + NewLine +
                             ToTerm("ENDFOR");

            for_each_driver.Rule =  ToTerm("FOR EACH CUSTOMER DO") + NewLine +
                                        block + NewLine +
                                    ToTerm("ENDFOR");

            ////<FOR-statement>::= FOR <FOR-variable><action>ENDFOR
            //FOR_statement.Rule = ToTerm("FOR") + FOR_variable + "DO" + NewLine + 
            //                        action + NewLine +
            //                     ToTerm("ENDFOR");

            ////<FOR-variable> ::= EACH CUSTOMER|BOOK COVER [<cover-List>]
            //FOR_variable.Rule = ToTerm("EACH CUSTOMER") | ToTerm("BOOK COVER") + "[" + cover_list + "]";

            //<cover-type> ::= CP|TF|TP
            cover_type.Rule = ToTerm("CP") | "TF" | "TP";

            //<cover-list> ::= {<cover-type>}{;<cover-type>}
            cover_list.Rule = MakeStarRule(cover_list, ToTerm(";"), cover_type);

            // <IF-DO-statement> ::= IF	<condition>	DO <action> ENDIF
            if_do_endif.Rule = "IF" + 
                                    condition + 
                                "DO" + NewLine +
                                    block + NewLine +  //MakeStarRule(action, NewLine, action) + 
                                "ENDIF";

            //<IF-ELSE-statement>	::= IF <condition> THEN <action> ELSE <action> ENDIF
            if_else_endif.Rule = "IF" + 
                                      condition + 
                                  "THEN" + NewLine + 
                                      block + NewLine + 
                                  "ELSE" + NewLine + 
                                      block + NewLine + 
                                  "ENDIF";

            // <condition> ::= <cause>|( NOT <condition> )|( <condition><logic-operator> <condition>} )|()
            condition.Rule = NewLine + cause + NewLine |
                            NewLine + "(" + NewLine + ToTerm("NOT") + condition + ")" + NewLine |
                            NewLine + "(" + condition + logic_operator + condition + ")" + NewLine |
                            NewLine + "(" + Empty + ")" + NewLine;

            //<logic-operator> ::= AND|OR
            logic_operator.Rule = ToTerm("AND") | ToTerm("OR");

            //<cause> ::= "{"<text>|[<parameter>]"}"
            cause.Rule = text;

            //<effect> ::= "{"<text>|[<parameter>]"}"
            effect.Rule = text;

            //<text> ::= [<char>]

            block.Rule = MakePlusRule(block, NewLine, statement) ;

            RegisterBracePair("(", ")");
            RegisterBracePair("[", "]");
            RegisterBracePair("{", "}");

            //MarkPunctuation("[", "]");
            //MarkPunctuation("(", ")");
			
            this.Root = block;
            //base.MarkTransient(statement);
        }
}

 

Coordinator
May 5, 2011 at 6:44 PM

hmmm... the new version looks quite different, and to be honest - a bit messed up. Let's get back to original grammar (with fixes I proposed) and then see what the problems are there.

One note: you don't need all these "(" and ")" around expressions if you register AND and OR as operators with proper precedence and associativity.