ANTLR的AST树语法+列表

4

我已经读了很多资料,试图找到一种干净的方式来处理ANTLR的树语法中的列表。下面是我尝试过的方法及其结果(我真的希望我错过了一些微不足道的东西)...

使用+=语法

program returns [someInterface result]
  : m+=method* EOF {result = new SomeClass(m);};

method returns [SomeMethod result] : <definition here>

这个方法失败了...

规则“+=”列表标签不允许没有输出选项

如果我将输出设置为“AST”或“template”(仅有的选项),生成类的方法签名会发生变化。也就是说,m将不再是SomeMethod(s)的列表,而是Nodes或Templates的列表。如果有办法使该方法正常工作,我很乐意听取建议。

使用规则范围

program returns [CompilesToJavaByteCode result]
    scope {
      List<SomeMethod> methods;
    }
    @init {
      $program::methods = new ArrayList<SomeMethod>();
    }
    : (m=method {$program::methods.add(m);})*
      EOF {result = new SomeClass($program::methods);};

这个看起来可行,但我必须承认,我还没有测试过其中的嵌套/递归情况。

最终目标

我想构建一组代表我的语言 (类、方法、变量、语句等) 的类,以便我可以在生成编译后代码之前进行一些静态分析和优化。为此,我需要能够消耗列表。我预计使用 += 语法“只需工作”,但我可能错过了什么。第二种方法可行,但似乎过于冗长和不优美。

问题

在 ANTLR 的树语法中,消耗列表并传递给我的具体类的正确方式是什么?


只有在您事先“告诉”ANTLR规则返回什么类型的对象(output=AST使它们成为CommonTree类型)时,+=才能正常工作。我认为这与ANTLR的代码基本上是Java 1.4有关,因为规则也可以返回原始类型,如intdouble等,因为1.4没有自动装箱。 - Bart Kiers
1个回答

6
你可以从你的示例中删除作用域,并使用本地变量完成所有操作。
program returns [CompilesToJavaByteCode result]
    @init {
      List<SomeMethod> methods = new ArrayList<SomeMethod>();
    }
    : (m=method { methods.add($m.result); })* EOF 
      { $result = new SomeClass(methods); };

这是我们在工作中处理此案例的方法。另一个选择是让您的方法规则处理它:

program returns [CompilesToJavaByteCode result]
    @init {
      List<SomeMethod> methods = new ArrayList<SomeMethod>();
    }
    : method[methods]* EOF { $result = new SomeClass(methods); };

method [List<SomeMethod> methods]
    : ...
      { methods.add(new SomeMethod(...); };

我不太喜欢第二个选项作为一种方法规则,因为规则可能不应该关心对其结果的操作方式。但是你可以想象一个结构,其中顶部规则创建了一个ClassBeingCompiled,并且其余的代码会逐步使用.addMethod()来填充它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接