如何为可以匹配多个项目的规则中的每个项目执行ANTLR解析器操作?

时间:2010-02-01 19:31:48

标签: parsing antlr grammar

我正在尝试编写一个匹配事物列表的ANTLR解析器规则,我想编写一个解析器操作,可以独立处理列表中的每个项目。

这些规则的一些示例输入是:

$(A1 A2 A3)

我希望这会产生一个评估器,其中包含三个MyIdentEvaluator个对象的列表 - A1,A2和A3各一个。

这是我的语法片段:

my_list returns [IEvaluator e]
    : { $e = new MyListEvaluator(); }
      '$'
      LPAREN
      op=my_ident+ { 
                     /* want to do something here for each 'my_ident'. */ 
                     /* the following seems to see only the 'A3' my_ident */
                     $e.Add($op.e);
                   }
      RPAREN
    ;

my_ident returns [IEvaluator e]
    : IDENT { $e = new MyIdentEvaluator($IDENT.text); }
    ;

我认为my_ident已正确定义,因为我可以看到为我的输入字符串创建了三个MyIdentEvaluators,但只有最后my_ident被添加到列表中(在我的示例输入中的A3)。

如何通过语法更改或解析器操作更改来独立地处理每个元素?

我还想到,我对这些概念的词汇不是它应该是的,所以如果它看起来像是在滥用一个术语,我可能就是。


编辑回应Wayne的评论:

我尝试使用op+=my_ident+。在这种情况下,我的操作中的$op变为IList(在C#中),其中包含Antlr.Runtime.Tree.CommonTree个实例。它确实在$op中为每个匹配的令牌提供了一个条目,所以我看到了我的三个匹配,但我没有我真正想要的MyIdentEvaluator个实例。我希望我能在ANTLR文档中找到一个可能对此有帮助的规则属性,但似乎没有任何东西可以帮助我摆脱这个IList


结果...

根据chollida的回答,我最终得到了这个效果很好的方法:

my_list returns [IEvaluator e]
    : { $e = new MyListEvaluator(); }
      '$'
      LPAREN
      (op=my_ident    { $e.Add($op.e); } )+
      RPAREN
    ;

my_ident的每次匹配都会调用Add方法。

2 个答案:

答案 0 :(得分:1)

如果我写这篇文章,我会将个别匹配分成列表模式:

my_list returns [IEvaluator e]
: { $e = new MyListEvaluator(); }
  '$'
  LPAREN
  op=my_ident { $e.Add($op.e); }
  (opNext=my_ident { $e.Add($opNext.e); })*
  RPAREN
;


my_ident returns [IEvaluator e]
: IDENT { $e = new MyIdentEvaluator($IDENT.text); }
;

这里不是使用Antlr的内置+,而是自己进行迭代。我们匹配第一个项目并将其添加到列表中,然后我们匹配连续项目并存储它们。

答案 1 :(得分:1)

my_list returns [IEvaluator e]
  : '$' LPAREN ops+=my_ident+ RPAREN { e = new MyListEvaluator(list_ops); }
  ;

我在Java中做了类似的事情,不得不检查生成的代码,发现ANTLR3生成一个名为“list_NAME”的变量(在这种情况下NAME = ops),这是所有子令牌规则返回的列表值。我想它在C#中是一样的,虽然我可能是错的。您可能希望变量只被称为“ops”,但该变量将只包含最后匹配的规则值(至少在Java中)。