ANTLR4 AST 访问者和节点 return 类型:我应该有多个访问者吗?
ANTLR4 AST vistor and node return Type: should I have more than one visitor?
我正在尝试学习 ANTLR(使用 v4),并且我正在使用访问者来遍历 antlr 生成的 AST。
帮助我学习 - 我想出了一种愚蠢的语言来解析。它有 'senators'
的列表
FirstName LastName (party)
例如 BA Baracus (R)
这些填充了一个 universe(在 ArrayList()
中),您以后可以用它来做事
...还有一些 'actions' 比如
~printRhouse
打印出众议院(即打印出宇宙,按政党分组)
ANTLR 为我生成了一个基本访问者,它是一个参数化的 class - 所以我用一个 Class 作为 T
提供了 subclass - 这个 class 在他们看来似乎是访问者中的所有方法return。
Antlr 生成类似
的东西
public class SenatorBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements SenatorVisitor<T> {
然后我想出了这样的具体实现。
public class InitialParseVisitor extends SenatorBaseVisitor<SenatorASTContainer> {
我发现自己写了一个 'container' class(在本例中为 SenatorASTContainer
),而不是树方法可以捕获的任何东西 return - 在本例中定义新参议员的声明,或 'actions' 如 'printhouse'。这感觉很糟糕,因为这个 class 变得非常混乱和多功能,因为它必须处理树中的每种类型的节点。
我是不是想错了? - 我是否应该有 n 个助行器,每个助行器都有一个更单一用途的 return 类型,并且都设计用于做一件事。这些中的每一个都会通过选择不访问它们来忽略不同类型的节点。
然后将 AST 遍历 n 次,每次使用不同的 walker 来嗅探不同的东西,最后根据多次运行的输出将最终程序组合在一起。
如果不是,通常一种 walker 类型就足够了,那么当我有不同类型的节点时,我应该如何考虑方法的 return 类型?
与您的问题相关,Antlr 至少支持两种主要访问者策略:(1) return class 本质上用作累加器和 (2) 具有节点类型的解析树注释具体 属性 classes.
对于注释策略,扩展 ParseTreeProperty 以创建特定于上下文节点类型的 属性 classes。使用方法见class中的注释。
通常,遍历解析树一次或多次以创建、分析和修改 属性 数据。走最后一次以生成输出。这是一个 example project 使用注释策略的方法。
在 return class 策略倾向于过度使用单个 class 的情况下,注释策略倾向于大量使用较小的 classes样板。这是一个 code generator 可能有助于此 'problem.'
拥有多个访问者并不能解决问题:实际上,每个具有重要语法的规则都会有自己的访问者(和结果节点)。生成的代码将难以维护。
我认为最常见的方法是对所有生成的 AST 节点使用 SenatorASTContainer
作为超级 class:
FirstName
、LastName
、Party
可能是 StringNode extends SenatorASTContainer
,其中一行的类型是 Senator extends SenatorASTContainer
。然而 Senator
的访问者必须将较低节点的结果转换为 StringNode
(访问者只会 return 通用 SenatorASTContainer
)。
我正在尝试学习 ANTLR(使用 v4),并且我正在使用访问者来遍历 antlr 生成的 AST。
帮助我学习 - 我想出了一种愚蠢的语言来解析。它有 'senators'
的列表FirstName LastName (party)
例如 BA Baracus (R)
这些填充了一个 universe(在 ArrayList()
中),您以后可以用它来做事
...还有一些 'actions' 比如
~printRhouse
打印出众议院(即打印出宇宙,按政党分组)
ANTLR 为我生成了一个基本访问者,它是一个参数化的 class - 所以我用一个 Class 作为 T
提供了 subclass - 这个 class 在他们看来似乎是访问者中的所有方法return。
Antlr 生成类似
的东西public class SenatorBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements SenatorVisitor<T> {
然后我想出了这样的具体实现。
public class InitialParseVisitor extends SenatorBaseVisitor<SenatorASTContainer> {
我发现自己写了一个 'container' class(在本例中为 SenatorASTContainer
),而不是树方法可以捕获的任何东西 return - 在本例中定义新参议员的声明,或 'actions' 如 'printhouse'。这感觉很糟糕,因为这个 class 变得非常混乱和多功能,因为它必须处理树中的每种类型的节点。
我是不是想错了? - 我是否应该有 n 个助行器,每个助行器都有一个更单一用途的 return 类型,并且都设计用于做一件事。这些中的每一个都会通过选择不访问它们来忽略不同类型的节点。
然后将 AST 遍历 n 次,每次使用不同的 walker 来嗅探不同的东西,最后根据多次运行的输出将最终程序组合在一起。
如果不是,通常一种 walker 类型就足够了,那么当我有不同类型的节点时,我应该如何考虑方法的 return 类型?
与您的问题相关,Antlr 至少支持两种主要访问者策略:(1) return class 本质上用作累加器和 (2) 具有节点类型的解析树注释具体 属性 classes.
对于注释策略,扩展 ParseTreeProperty 以创建特定于上下文节点类型的 属性 classes。使用方法见class中的注释。
通常,遍历解析树一次或多次以创建、分析和修改 属性 数据。走最后一次以生成输出。这是一个 example project 使用注释策略的方法。
在 return class 策略倾向于过度使用单个 class 的情况下,注释策略倾向于大量使用较小的 classes样板。这是一个 code generator 可能有助于此 'problem.'
拥有多个访问者并不能解决问题:实际上,每个具有重要语法的规则都会有自己的访问者(和结果节点)。生成的代码将难以维护。
我认为最常见的方法是对所有生成的 AST 节点使用 SenatorASTContainer
作为超级 class:
FirstName
、LastName
、Party
可能是 StringNode extends SenatorASTContainer
,其中一行的类型是 Senator extends SenatorASTContainer
。然而 Senator
的访问者必须将较低节点的结果转换为 StringNode
(访问者只会 return 通用 SenatorASTContainer
)。