【问题标题】:How to create a custom AST using visitor in Antlr如何在 Antlr 中使用访问者创建自定义 AST
【发布时间】:2019-02-10 03:24:47
【问题描述】:

我想使用访问者模式遍历 ParserRuleContext 并使用预定义的节点构建 AST。

在我的语法中,我有以下规则:

expr
    : loop
    | block

我想生成一个具有以下结构的 AST:

    exprNode
      / 
loopNode

Antlr 生成的BaseVisitor 里面有如下方法:

public T visitExpr(MyParser.ExprContext ctx) { return visitChildren(ctx); }

ASTBuilder 覆盖此方法并创建一个exprNode。对于这个exprNode,我想通过调用visitLoopvisitBlock 的覆盖版本来附加loopNodeblockNode。我遇到的问题是我不知道expr 的身份,因为我只从父母那里获得了exprContext。如何检查使用了哪个 expr 规则调用?

【问题讨论】:

  • 当您说您想将LoopNodeBlockNode 附加到ExprNode 时是什么意思?这些类究竟是如何相互关联的,在这种情况下“附加”是什么意思?通常我会假设BlockNodeLoopNode 只是抽象类ExprNode 的子类,而您希望visitExpr 返回其中之一——不要在任何东西上附加任何东西。
  • 这或多或少是我想做的。抱歉解释模糊。我将如何决定visitExpr 将返回两个具体节点(BlockNodeLoopNode)中的哪一个?

标签: java parsing antlr antlr4 abstract-syntax-tree


【解决方案1】:

不要覆盖visitExpr。只需覆盖visitLoopvisitBlock

自动生成的visitExpr 将调用这两者中的适当一个(通过visitChildren)并返回visitLoopvisitBlock 返回的任何内容。因此,只要您重写这些方法以返回正确的结果,visitExpr 也会自动返回正确的结果。

【讨论】:

  • 澄清一下:我的语法中也有methodDefinition : ID PAREN_OPEN ....... expr ........。在visitMethodDefinition 方法中,我想创建一个MethodNode,其中包含ExprNode(抽象类)的字段。我是否应该让visitMethodDefinition 调用visitExpr(ctx.expr()) 并将结果转换为抽象ExprNode
  • @JanParzydło 根据经验,我只会调用visit,而不是特定的visitFoo 方法。但是是的,您可以调用visit(ctx.expr()),然后将结果转换为ExprNode。或者,您可以使用扩展 YourLangBaseVisitor<ExprNode> 的专用 ExpressionVisitor,因此您不必进行任何转换。
【解决方案2】:

标记规则 alts 为确定身份提供了便利的上下文:

expr
    : loop   #loopExpr
    | block  #blockExpr
    ;

生成的解析器现在将包含 LoopExprContext extends ExprContextBlockExprContext extends ExprContext 类以及行为适当的访问者进入和退出方法。

【讨论】:

  • 即使没有标记我的解析器的ExprContext 类包含返回正确上下文的loop()block()。在创建 AST 时,有时我会输入一个 ExprContext,这是我想要确定表达式的身份并返回对应于 loopblock 的节点之一。我该怎么做?
  • 当你标记时,你基本上忽略了基本上下文(ExprContext,至少在 Java 实现中,是LoopExprContextBlockExprContext 的公共超类)。因此,当访问者访问 expr 规则的 loop alt 时,LoopExprContext 的访问方法实际上被称为 ExprContext 访问方法的简单特化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多