5

自从我的(一个)编译器课程以来已经有很多年了,如果这个问题不恰当,请原谅我。我也是 ANTLR 和 C 而不是 Java 编码器的新手。我想做的是描述我的问题,然后寻求最佳技术的建议。

我正在尝试将 ASN.1 作品翻译成 ML。例如,

Foo ::= ENUMERATED {
  bar  (0),    -- some comment 0
  baz  (1)     -- some comment 1
}

进入

<Enumerated name="Foo">
  <NamedValues>
    <Unsigned name="bar" value="0" comment="some comment 0"/>
    <Unsigned name="baz" value="1" comment="some comment 1"/>
  </NamedValues>
</Enumerated>

我的(简化的)ASN1 语法是:

assignment : IDENTIFIER typeAssignment ;
typeAssignment : '::=' type ;
type : builtinType ;
builtinType : enumeratedType ;
enumeratedType : 'ENUMERATED' '{' enumerations '}' ;
...

“The Definitive ANTLR4 Reference”中的几个示例演示了在 BaseListener 中覆盖某些 enterNode 或 exitNode 方法,所需的一切都在 Node 的上下文中。我的问题是我想覆盖enterTypeAssignmentand exitTypeAssignment,但我需要的一些信息位于解析树上更高(例如分配)或更低(例如枚举)的节点中。

这里是否有足够的描述来询问我是否应该使用访问者或侦听器模式?任何关于关注哪些书本示例的建议将不胜感激。

我对蛮力方法有一些运气:

import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.misc.Interval;

public class MylListener extends ASN1BaseListener {
  ASN1Parser parser;
  String id = "";
  String assignedType =  "";

  public MyListener(ASN1Parser parser) {this.parser = parser;}

  @Override
  public void enterAssignment(ASN1Parser.AssignmentContext ctx) {
    id = ctx.IDENTIFIER().getText();
  }

  /** Listen to matches of typeAssignment **/
  @Override
  public void enterTypeAssignment(ASN1Parser.TypeAssignmentContext ctx) {
    if ( ctx.type() != null ) {
      if ( ctx.type().builtinType() != null ) {
        if ( ctx.type().builtinType().enumeratedType() != null ) {
          assignedType =  "Enumerated";
          System.out.println("");
          System.out.println("<Enumerated name=\""+id+"\">");
          ...
        }
      }
    }
  }

  @Override
  public void exitTypeAssignment(ASN1Parser.TypeAssignmentContext ctx) {
    if (assignedType.length() > 0) {
      System.out.println("</"+assignedType+">");
      assignedType =  "";
    }
  }
}

但可能有一个更优雅的解决方案......


更新:我得到了我想要的结果,方法是在树下的途中将 TerminalNodes 保存在全局变量中,并让这些变量可以访问以覆盖树下更远的侦听器中的方法。有没有更好的方法从给定节点访问父或祖父上下文?

4

1 回答 1

1

我会先解析这个东西,然后使用一个访问者。使用 Listener 的优势在于您拥有所有可用的信息。

您还可以使用 C# 目标,它可能更容易与 C 背景一起使用。

于 2014-04-11T08:43:04.357 回答