Implementing a prefix notation expression parser u

2019-04-13 13:54发布

问题:

I'm trying to parse user-inputted prefix notation logical expressions using a context-free-grammar with the Irony library. This is for a class assignment so if anybody happens to be an expert on this, I would love to know more.

I need to accept a user-inputted logical expression of the following format:

and P Q -- (meaning P ^ Q)
or P Q -- (meaning P v Q)
not P  -- (meaning ~P)
imp P Q -- (meaning P -> Q)

I'm attempting to parse these into expression trees using a context free grammar I'm implementing in Irony. The context-free grammar I'm using is here, in BNF:

<Expression> ::= <Not> | <And> | <Or> | <Implies> | <Identifier>
<Not>        ::= "not" <Expression>
<And>        ::= "and" <Expression> <Expression>
<Or>         ::= "or" <Expression> <Expression>
<Implies>    ::= "imp" <Expression> <Expression>

(<Identifier> is implemented as an IdentifierTerminal object).

I've used Irony to parse expressions before but for some reason, I cannot get it to work. When I type the expression and P Q it seems to be identifying "and" as an Identifier terminal, not part of the And nonterminal. I may be doing something obvious but I simply can't figure it out. Here is the language class I extended:

class LogicPrefix : Grammar
{
    public LogicPrefix()
        : base(false)
    {
        NonTerminal Expression = new NonTerminal("expression");
        NonTerminal Implies = new NonTerminal("implies");
        NonTerminal And = new NonTerminal("and");
        NonTerminal Or = new NonTerminal("or");
        NonTerminal Not = new NonTerminal("not");
        Terminal Identifier = new IdentifierTerminal("identifier");
        Root = Expression;

        Expression.Rule = And | Or | Not | Identifier;

        Not.Rule = "not" + Expression;
        Implies.Rule = "imp" + Expression + Expression;
        And.Rule = "and" + Expression + Expression;
        Or.Rule = "or" + Expression + Expression;

    }
}

And here is my driver class:

class Program
{
    static void Main(string[] args)
    {
        LogicPrefix grammar = new LogicPrefix();
        Parser p = new Parser(grammar);
        ParseTree pt = p.Parse("and P Q");
        //pt has thrown an error flag.
    }
}

Please let me know if I'm doing something wrong, I'd love some advice on this.

回答1:

Your identifier lexing seems to allow your other terminals to be lexed as identifiers because by definition IdentifierTerminal recognizes anything that "starts with an underscore or letter and contains only letters, numbers, and underscores" (source). This means that when your program reads the and, it can read it as the identifier and or the keyword and.

It looks to me like you can fix this by declaring your operators to be punctuation with the following line:

MarkPunctuation("imp", "and", "or", "not")