3
votes

I have the following Antlr grammar rule:

expression1
  : e=expression2 (BINOR^ e2=expression2)*
  ;

However if I have '3 | 1 | 2 | 6' this results in a flat tree, with 3, 1, 2, 6 all children of the BINOR node. What I really want is to be able to pattern match on either

expression2
or
^(BINOR expression2 expression2)

How can I change the rewrite so that these are the 2 patterns?

EDIT:

If I use custom rewrites, I'm thinking along the lines of

expression1
  : e=expression2 (BINOR e2=expression2)*
            ->  {$BINOR != null}?   ^(BINOR $e $e2*)
            -> $e

But when I do this with '1|2|3' the resulting tree only has one BINOR node with two children which are 1 and 3, so 2 is missing.

Many thanks

1

1 Answers

2
votes

You were close, this would work:

expression1
@init{boolean or = false;}
 : e=expression2 (BINOR {or=true;} expression2)* -> {or}? ^(BINOR expression2+)
                                                 ->       $e
 ;

But this is preferred since it doesn't use any custom code:

grammar T;

options {
  output=AST;
}

expression1
 : (e=expression2 -> $e) ((BINOR expression2)+ -> ^(BINOR expression2+))?
 ;

expression2
 : NUMBER
 ;

NUMBER
 : '0'..'9'+
 ;

BINOR
 : '|'
 ;

The parser generated from the grammar above will parse the input "3|1|2|6" into the AST:

enter image description here

and the input "3" into the AST:

enter image description here

But your original try:

expression1
  : e=expression2 (BINOR^ e2=expression2)*
  ;

does not produce a flat tree (assuming you have output=AST; in your options). It generates the following AST for "3|1|2|6":

enter image description here

If you "see" a flat tree, I guess you're using the interpreter in ANTLRWorks, which does not show the AST but the parse tree of your parse. The interpreter is also rather buggy (does not handle predicates and does not evaluate custom code), so best not use it. Use ANTLRWorks debugger instead, which works like a charm (the images from my answer are from the debugger)!