我正在尝试学习ANTLR(使用v4),我正在使用访问者来引导antlr生成的AST。
帮助我学习 - 我想出了一种愚蠢的语言来解析。它有'参议员'的名单
FirstName LastName (party)
例如BA Baracus (R)
这些填充了一个Universe(在ArrayList()
中),您可以稍后使用
......还有一些'行动',比如
~printRhouse
打印出代表院(即打印出宇宙,按派对分组)
ANTLR为我生成了一个基本访问者,它是一个参数化的类 - 所以我将一个Class子类化为T
- 这个类似乎是访问者返回的所有方法。
Antlr生成类似
的内容public class SenatorBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements SenatorVisitor<T> {
然后我想出了这样的具体实现。
public class InitialParseVisitor extends SenatorBaseVisitor<SenatorASTContainer> {
我发现自己编写了一个'容器'类(在这种情况下为SenatorASTContainer
),而不是捕获树方法可以返回的任何内容 - 在这种情况下定义新参议员的语句,或者像'printhouse'这样的'动作' ”。这感觉很糟糕,因为这个类变得非常杂乱和多功能,因为它必须处理树中的每种类型的节点。
我是否以错误的方式思考这个问题? - 我应该有n个步行者,每个步行者都有更多的单一目的返回类型,而且都设计为做一件事。通过选择不访问它们,每个节点都会忽略不同类型的节点。
然后,人们会在AST上走n次,每次都有一个不同的助行器,嗅探不同的东西,最后将多个运行的输出组合成最终的程序。
如果没有,并且一个walker类型通常就足够了,那么当我有不同类型的节点时,我应该如何考虑方法的返回类型?
答案 0 :(得分:3)
拥有多个访问者并不能解决问题:实际上,每个具有非平凡语法的规则都将获得自己的访问者(和结果节点)。生成的代码难以维护。
我认为最常见的方法是使用SenatorASTContainer
作为所有生成的AST节点的超类:
FirstName
,LastName
,Party
可能是StringNode extends SenatorASTContainer
,一行的类型为Senator extends SenatorASTContainer
。然而,Senator
的访问者必须将较低节点的结果转换为StringNode
(访问者只会返回通用SenatorASTContainer
)。
答案 1 :(得分:1)
与您的问题相关,Antlr支持至少两个主要访问者策略:(1)返回类主要用作累加器;(2)具有节点类型特定属性类的解析树注释。
对于注释策略,请扩展ParseTreeProperty以创建特定于上下文节点类型的属性类。请参阅该类中的注释以了解如何使用。
通常,遍历解析树一次或多次以创建,分析和修改属性数据。走最后一次产生输出。这是使用注释策略方法的example project。
如果返回类策略倾向于严重过度使用单个类,则注释策略倾向于使用相当多的样板来扩散小类。这是code generator可能有助于解决这个问题。&#39;