Reputation: 80
I'm new to ANTLR and I'm attempting to generate a relatively simply parser for a calculator application, using ANTLR4 and C#. Here is my grammar file.
parser grammar CalculatorExpressionParser;
options{
language = CSharp2;
}
expr: FUNC expr? (COMMA expr)* RIGHTPAREN #CallFunction
| LEFTPAREN expr RIGHTPAREN #Parens
| expr POW<assoc=right> expr #Pow
| expr op=(MULTIPLY | DIVIDE)? expr #MultDivide
| expr op=(ADD | SUBTRACT) expr #AddSubtract
| SUBTRACT expr #Negative
| NUMBER #Number
;
I wrote a custom lexer to generate the tokens in order to support implicit multiplication and conversion of variables to their numerical equivalent before parsing.
But upon input I get the following results.
2+6/3 => 4 (correct)
6/3+2 => 1.2 (should be 4)
6/(3+2) => 4 (also correct)
1+2*3 => 7 (correct)
2*3+1 => 8 (should be 7 too)
(2*3)+1 => 7 (correct)
Note that I tried turning off the error recovery capabilities and setting it to report all ambiguity errors and I don't appear to be getting any.
Anyways, if I change the grammar to the following by removing the ? after the division/multiplication operator, then it appears to work great, except implicit multiplication is no longer supported.
parser grammar CalculatorExpressionParser;
options{
language = CSharp2;
}
expr: FUNC expr? (COMMA expr)* RIGHTPAREN #CallFunction
| LEFTPAREN expr RIGHTPAREN #Parens
| expr POW<assoc=right> expr #Pow
| expr op=(MULTIPLY | DIVIDE) expr #MultDivide
| expr op=(ADD | SUBTRACT) expr #AddSubtract
| SUBTRACT expr #Negative
| NUMBER #Number
;
I was wondering why putting the ? breaks the matching order? And is there an easy way to fix this?
Upvotes: 2
Views: 1913
Reputation: 5962
"expr expr" doesn't fit the pattern of operators though ANTLR 4.2 might handle this. Sam is still working on updating C# target.
Upvotes: 1
Reputation: 7894
Split your expr statement into multiple statements in order to get proper order of operations.
Typically it goes like below:
Note how each expr only handles one set of mathematical operations and then calls down to a lower precedence rule. Typically the lowest rule is your atomic operator like INT
or FLOAT
So in this case you handle logical AND and OR's then comparisons, then exponents, then multiplications/division then addition/subtraction.
NOTE I should also point out, here I've created an AST tree instead of doing the operations inline.
expr
: subExpr -> ^(EXPR subExpr)
;
subExpr : logicalAndExp (addSubtractOp^ logicalAndExp)*
;
logicalAndExp
: logicalOrExp (multiplyDivideOp^ logicalOrExp)*
;
logicalOrExp
: comparatorExp (CARET^ comparatorExp)*
;
comparatorExp
: powExp (comparatorOp^ powExp)*
;
powExp : multExp (BARBAR^ multExp)*
;
multExp
: expressionAtom (AMPAMP^ expressionAtom)*
;expression
: subExpr -> ^(EXPR subExpr)
;
subExpr : logicalAndExp (addSubtractOp^ logicalAndExp)*
;
logicalAndExp
: logicalOrExp (multiplyDivideOp^ logicalOrExp)*
;
logicalOrExp
: comparatorExp (CARET^ comparatorExp)*
;
comparatorExp
: powExp (comparatorOp^ powExp)*
;
powExp : multExp (BARBAR^ multExp)*
;
multExp
: expressionAtom (AMPAMP^ expressionAtom)*
;
Upvotes: 1