I'm new to ANTLR, and I'm trying to expand upon the example of a simple calculator presented here. Specifically, I've tried adding some simple functions, negative numbers and so on, to familiarize myself with ANTLR. However, I've run into a bit of a problem trying to implement "implicit" multiplication (for example, 3cos(2)sin(2) would be interpreted as 3*cos(2)*sin(2)).
I've found a question on Stack Overflow with the same kind of problem (here). The general form of the solution to that problem looks like what I'd found on my own, so I'm not sure where my problem lies.
My grammar is below. Without the | p2 = signExpr {$value *= $p2.value;}
line (the last line in the multiplicationExpr
), everything seems to work fine according to my tests. When I add this line and run it through antlr
, I receive the following errors:
error(211): calculator.g:24:3: [fatal] rule multiplicationExpr has non-LL(*) decision due to recursive rule invocations reachable from alts 3,4. Resolve by left-factoring or using syntactic predicates or using backtrack=true option.
warning(200): calculator.g:24:3: Decision can match input such as "'-' FLOAT" using multiple alternatives: 3, 4
As a result, alternative(s) 4 were disabled for that input
Enabling backtrack
results in wrong calculations for some of my (normally working) test expressions. Further, the warning talks about alternatives 3 and 4 for multiplicationExpr
, but I only have three alternatives in that block, which has me confused.
Would someone be able to point out the error in my grammar, given below?
grammar calculator;
eval returns [double value]
: exp = additionExpr {$value = $exp.value;}
;
additionExpr returns [double value]
: m1 = multiplicationExpr {$value = $m1.value;}
( '+' m2 = multiplicationExpr {$value += $m2.value;}
| '-' m2 = multiplicationExpr {$value -= $m2.value;}
)*
;
multiplicationExpr returns [double value]
: p1 = signExpr {$value = $p1.value;}
( '*' p2 = signExpr {$value *= $p2.value;}
| '/' p2 = signExpr {$value /= $p2.value;}
| p2 = signExpr {$value *= $p2.value;}
)*
;
signExpr returns [double value]
: ( '-' a = funcExpr {$value = -1*$a.value;}
) | ( a = funcExpr {$value = $a.value;}
)
;
funcExpr returns [double value]
: ( 'cos' s = signExpr {$value = Math.cos($s.value);}
) | ( 'sin' s = signExpr {$value = Math.sin($s.value);}
) | ( s = powExpr {$value = s;}
)
;
powExpr returns [double value]
: s1 = atomExpr {$value = $s1.value;}
( '^' s2 = signExpr {$value = Math.pow($value, $s2.value);}
)?
;
atomExpr returns [double value]
: f = FLOAT {$value = Double.parseDouble($f.text);}
| '(' exp = additionExpr ')' {$value = $exp.value;}
;
FLOAT
: ('0'..'9')+ ('.' ('0'..'9')*)? EXPONENT?
| '.' ('0'..'9')+ EXPONENT?
;
WS : ( ' '
| '\t'
| '\r'
| '\n'
) {$channel=HIDDEN;}
;
fragment
EXPONENT : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;