I want a grammar and evaluator (ANTLR parse tree walker) that contains only binary non-terminals without the need to switch on the operator when visiting an expression node to determine what operation to take (as is the case for a pre-left factored grammar, since the visitor would visit an "additionNode" the visitor can assume statically that it must do an addition).
Fairly direct question. ANTLR supports left recursion, so this is a valid grammar
expr :
| expr ('+'|'-') expr
| expr ('*'|'/') expr
| '(' expr ')'
| literal
;
nifty, but any walker/visitor/compiler-back-end for this now has to do its own dispatching on types, which stinks:
onVisitExit(ExprContext ctx){
left = compiledMap.get(ctx.getChild(0));
right = compiledMap.get(ctx.getChild(2));
operator = ctx.getChild(1);
switch(operator.getToken()){
case "+": compiledMap.put(ctx, left + right);
case "-": compiledMap.put(ctx, left - right);
case "*": compiledMap.put(ctx, left * right);
case "/": compiledMap.put(ctx, left / right);
}
}
the pros and cons to this strategy:
- antlr builds a binary tree for me, where (binary) each rule has a left and a right argument, meaning I dont have to worry about while loops for kleene closures. I really like this
- I have to manually dispatch (switch) on the token, rather than on the type of the node.
Using the more traditional & already left-factored grammar
expr : addOrSub ;
addOrSub : multOrDiv (('+'/'-') multOrDiv)* ;
multOrDiv : bracks (('*'/'/') backs)* ;
bracks : '(' expr ')' | literal ;
literal : TOKEN ;
The corresponding visitor for this has the opposite pros and cons to the one 2 grammars above: ANTLR will do this dispatching on types for me --well mostly, still have to differentiate between '+' and '-' -- but now I have to include while loops for those kleene closures because I dont have a strict binary tree anymore which is annoying.
I think my ideal grammar would be like this
expression : expr ;
fragment expr :
(addition | subtraction)
| (multiplication | division)
| brackets
| literal
;
addition : expr '+' expr ;
subtraction : expr '-' expr ;
multiplication : expr '*' expr ;
division : expr '/' expr ;
brackets : '(' expr ')' ;
literal : TOKEN ;
And this would solve all my problems, except of course that is illegal in ANTLR