What should be the correct grammar for the correct assessment of priority +, -, /, *, etc.

My grammar has these rules

expression : expression EQ conditionalOrExpression #eqExpr | expression NEQ conditionalOrExpression #neqExpr | expression LT conditionalOrExpression #ltExpr | expression GT conditionalOrExpression #gtExpr | expression LTEQ conditionalOrExpression #lteqExpr | expression GTEQ conditionalOrExpression #gteqExpr | conditionalOrExpression #next ; conditionalOrExpression : conditionalOrExpression OR conditionalAndExpression #orExpr | conditionalAndExpression #and ; conditionalAndExpression : conditionalAndExpression AND additiveExpression #andExpr | additiveExpression #add ; additiveExpression : additiveExpression PLUS multiplicativeExpression #plusExpr | additiveExpression MINUS multiplicativeExpression #minusExpr | multiplicativeExpression #multiplicative ; multiplicativeExpression : multiplicativeExpression MULT unaryExpression #multExpr | multiplicativeExpression DIV unaryExpression #divExpr | unaryExpression #unary ; unaryExpression : MINUS unaryExpression #unaryMinusExpr | NOT unaryExpression #notExpr | atom #atomExpr ; function : ID OPAR (parameter (',' parameter)*)? CPAR ; parameter : STRING #stringParameter | expression #exprParameter ; atom : OPAR expression CPAR #parExpr | (INT | FLOAT) #numberAtom | (TRUE | FALSE) #booleanAtom | ID #idAtom | function #functionAtom ; 

I have implemented the appropriate visitor.

If I evaluate "40 + 10 - (2 * 40) + (100/40) + 0.2", the result is -32.7. This is because the expression evaluates to

 (40+10) - (((2*40) + (100/40)) + 0.2) 

which makes sense in accordance with the rules (PLUS to MINUS).

However, if I evaluate the same expression in Excel or, for example, assign it to a double in C #, in both cases the result is -27.3. This is because they rate the rule as

 (((40+10)-(2*40)) + (100/40)) + 0.2 

So what is "right"? -32.7 is technically correct, as it dictates the rules. But how to change the grammar according to the results in Excel / C #?

+5
source share
2 answers

If you group + and - into one alternative, it should work. I changed the grammar in my demo appraiser on GitHub as follows:

 expr : expr POW<assoc=right> expr #powExpr | MINUS expr #unaryMinusExpr | NOT expr #notExpr | expr op=(MULT | DIV | MOD) expr #multiplicationExpr | expr op=(PLUS | MINUS) expr #additiveExpr | expr op=(LTEQ | GTEQ | LT | GT) expr #relationalExpr | expr op=(EQ | NEQ) expr #equalityExpr | expr AND expr #andExpr | expr OR expr #orExpr | atom #atomExpr ; 

and then tested with the following code:

 MuLexer lexer = new MuLexer(new ANTLRInputStream("log(40 + 10 - (2*40) + (100/40) + 0.2);")); MuParser parser = new MuParser(new CommonTokenStream(lexer)); new EvalVisitor().visit(parser.parse()); 

a value of -27.3 will be printed on my console.

+5
source

To streamline the order of operations on such expressions, you want to set nested rules. Parse higher priority operators deeper , closer to the main expressions. For example, I would point you to the syntax that I wrote for Jison, a similar grammar tool. The code can be seen here .

You break up one expr expression into several smaller expressions for each “priority” level of the operator, for example:

 expr : comp_expr | expr0 ; expr0 : or_expr | expr1 ; expr1 : and_expr | expr2 ; expr2 : add_expr | expr3 ; expr3 : mult_expr | expr4 ; expr4 : exp_expr | primary ; 
+1
source

Source: https://habr.com/ru/post/1200783/


All Articles