1

I already know the workaround for this problem, but I would like to really use this one approach, for at least one reason -- it should work.

This is rule taken from "The Definitive ANTLR Reference" by Terence Parr (the books is for ANTLR3):

expr : (INT -> INT) ('+' i=INT -> ^('+' $expr $i) )*;

If INT is not followed by + the result will be INT (single node), if it is -- subtree will be built with first INT (referred as $expr) as left branch.

I would like to build similar rule, yet with custom action:

mult_expr : (pow_expr -> pow_expr ) 
            (op=MUL exr=pow_expr 
              -> { new BinExpr($op,$mult_expr.tree,$exr.tree) })*; 

ANTLR accepts such rule, but when I run my parser with input (for example) "5 * 3" it gives me an error "line 1:1 missing EOF at '*'5".

QUESTION: how to use back reference with custom rewrite action?

4

2 回答 2

1

我建议您创建自己的CommonTreeAdaptor并将自定义节点的创建移至此,CommonTreeAdaptor而不是在您的语法文件中执行此操作。有关这方面的更多信息,请参阅:扩展 ANTLR3 AST's

如果运算符可能具有多种含义,例如减号(二元或一元运算符),请让您的解析器规则重写一元运算符,如下所示:

grammar X;

...

tokens { U_SUB; } 

add_expr
 : mult_expr ((SUB | ADD)^ mult_expr)*
 ;

...

unary_expr
 : SUB atom -> ^(U_SUB atom)
 | atom
 ;

...

然后在你的实现中CommonTreeAdaptor,做这样的事情:

@Override
public Object create(Token t) {
  ...
  switch(t.getType()) {
    case X.SUB   : /* return a binary-tree */
    ...
    case X.U_SUB : /* return an unary-tree */
  }
  ...
}
于 2012-08-20T10:12:23.633 回答
1

我是一个坚持不懈的人,一步使用自定义节点的想法让我很困扰...... ;-)

所以我做了。关键点是:

  • 放在EOF!“主要”规则的末尾,

  • 在标记标记时,将标签放在标记旁边,而不是分组,所以(op='*'|op='/'),不是op=('*'|'/')

我不确定这种使用语法规则来立即创建自定义节点的方法是否是一个好主意,但由于这解决了所提出的问题,我将其标记为解决方案。

为了记录,最有趣的规则现在看起来像这样:

mult_expr : (exl=pow_expr -> $exl ) 
        ((op=MUL|op=IDIV|op=RDIV|op=MOD) exr=pow_expr 
        -> { new BinaryExpression($op,$exl.tree,$exr.tree) })*; 
于 2012-08-22T16:22:19.897 回答