Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

No Format
e : parse_expr[0] ; // rewrite e to this rule, which invokes the precedence engine

/** "Precedence climbing" engine
parse_expr[int p]
   :   primary
       (   {prec[input.LA(1)]>=p}?=>     bop r= parse_expr[nextp(p)]
       |   {postprec[input.LA(1)]>=p}?=> suffix[$e.tree]
       )*
   ;

where rule suffix is described below (basically we remove e references from the left edge). If there are no suffix operators, the 2nd alt of the (...)* is not generated.

...

No Format
s : e ';' // nondeterministic; must use option backtrack=true!!!
  | e '!'
  ;

Tree construction and actions

ANTLR can allow actions at the end of binary operator alternatives as well as anywhere else in the other rules. The binary operators are all combined into the parse_expr rule so ANTLR must collect all actions on the right-hand side and make a "switch on the operator" action within the parse_expr loop:

No Format

parse_expr[int p]
   :   primary
       (   {prec[input.LA(1)]>=p}?=>     bop r= parse_expr[nextp(p)]
           {
           switch ( $bop.start.getType() ) {
               case '+' :
               case '-' :
                  action-for-this-alt
                  break;
               ...
               case '=' :
                  action-for-this-alt
                  break;
               default : // no action
           }
           }
       |   {postprec[input.LA(1)]>=p}?=> suffix[$e.tree]
       )*
   ;

Trees for the binary operators could also be automatically done using the standard ANTLR mechanisms.

No Format

parse_expr[int p]
   :   (primary->primary)
       (   {prec[input.LA(1)]>=p}?=>     bop r=parse_expr[nextp(p)] -> ^(bop $parse_expr $r)
       |   {postprec[input.LA(1)]>=p}?=> suffix[$e.tree]            -> {$suffix.tree}
       )*
   ;

The other alternatives and rules create trees as usual:

No Format

    |   primary
    |   ('++'^|'--'^) e
    |   '(' e ')' -> e

Rule suffix is left alone except for the removal of the left recursion so you can add whatever tree construction you want but you must allow a $lhs parameter to come in. This parameter is the primary matched immediately to the left.

No Format

suffix[CommonTree lhs]
   :   t='[' expr ']'                -> ^(INDEX[$t] {$lhs} expr)
   |   t='(' (expr (',' expr)*)? ')' -> ^(CALL[$t] {$lhs} expr*)
   |   t='++'                        -> ^(POSTINC[$t] {$lhs})
   ;

Implementation

Have ANTLR build parse_expr rules as templates and then call ANTLRParser.rule() on that text. It will be like an include. This is the mechanism I use for nextToken generation.

...