4

我已经阅读了很多内容,试图找到一种干净地使用 ANTLR 树语法中的列表的方法。这是我尝试过的方法及其结果(我真的希望我遗漏了一些微不足道的东西)......

使用 += 语法

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

method returns [SomeMethod result] : <definition here>

这失败了......

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

如果我将输出设置为“AST”或“模板”(唯一的选项),生成的类的方法签名会发生变化。也就是说,m不是通过 SomeMethod(s) 的列表,而是分别通过节点或模板的列表。如果有办法使这种方法起作用,我愿意接受建议。

使用规则范围

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 的树语法中使用列表传递给我的具体类的正确原因是什么?

4

1 回答 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(...); };

我不太喜欢第二个选项,因为方法规则可能不应该关心这样的结果正在做什么。但是您可以想象一个结构,其中顶部规则创建 aClassBeingCompiled并且其余代码逐渐用.addMethod().

于 2011-04-03T05:54:59.997 回答