Antlr4 - 在侦听器和访客模式之间切换的最佳方式?

问题描述 投票:0回答:2

我目前正在规划语言解释器的结构,我意识到我不喜欢专门使用访问者或侦听器树遍历方法的想法。

由于这两种树遍历方法都有其优点,理想情况下,我想混合使用两种方法:

  • 在遍历任意语言块定义(函数/类定义、结构/枚举类定义)时,尤其是当它们可以嵌套时,使用侦听器最有意义。
  • 访问者似乎很自然地适合诸如表达式评估之类的情况,其中上下文更可预测,并且结果值可以返回到链上。

两种遍历方式之间的切换最“正确”的方法是什么?

到目前为止,我的想法如下:

对于解析树的一部分从侦听器切换到访问者

也就是说,当侦听器到达节点“Foo”时,我想使用访问者更明确地处理其子节点。我能想到的一种方法是:

  • 解析树遍历器调用
    enterFoo(ctx)
    • 创建 myFooVisitor 的实例
    • 明确拜访孩子、存储结果等
    • 设置
      ctx.children = []
      (或同等内容)
  • enterFoo()
    返回时,解析树遍历器会发现该节点不再有子节点,并且不会不必要地遍历 Foo 的所有子节点

对于解析树的一部分从访问者切换到监听者

这对我来说更明显一点。由于使用访问者时显式控制树遍历,因此切换似乎微不足道。

  • visitFoo()
    被叫到
    • 创建新的解析树遍历器和 myFooListener 的实例
    • 像平常一样使用监听器启动 walker。
parsing antlr4
2个回答
0
投票

您似乎已经知道听众和访客是模式,有点可以切换。这是错误的。

侦听器和访问者都是允许您对规则遍历进行操作的类。当规则被“输入”或“离开”时,侦听器通过在解析过程中从解析器调用来实现此目的。不涉及解析树。

然而,访问者使用解析树来遍历每个节点并为它们调用方法。您可以重写这些方法中的任何一个来执行任何关联的工作。这与评估结果没有必然关系。您可以独立使用它。

ANTLR4 为每个规则(在侦听器和访问者中)生成方法体,这使您可以轻松地仅实现您感兴趣的规则。

既然您知道监听器是在解析期间使用的,而访问者是在解析之后使用的,那么很明显您不能在它们之间切换。事实上,切换并没有多大帮助,因为两个类的作用本质上是相同的(调用遇到的规则的方法)。

如果您的问题实际上包含您想要实现的

什么,而不是如何实现,我可能可以为您提供更多信息。


0
投票
监听器用于以基于推送的方法处理解析树,这种方法通常不会对接收代码的迭代提供太多控制。不过,仍然有一些选择。

如果您使用

ParseTreeWalker

,这是一个非常简单的类,它只是递归地迭代树中的节点。您可以制作自己的节点,或者扩展它以覆盖 
Walk
,从而对不需要迭代的特定节点禁用它。您唯一需要决定的是如何将该信息提供给步行者,例如通过显式列出所有此类节点类型,通过将侦听器耦合到它并仅切换其状态,或者通过以某种方式从侦听器标记节点等。在任何情况下,您的侦听器都可以自由地在 
Enter
 中调用访问者或此类节点的 
Exit

如果在解析期间使用

AddParseListener

 来调用侦听器,您仍然需要处理解析树,但您可以以相同的方式调用访问者,只需在创建后从 
Exit
 开始即可。

© www.soinside.com 2019 - 2024. All rights reserved.