ANTLR的AST树语法+列表

And*_*ite 4 antlr antlr3 tree-grammar

我已经阅读了很多试图找到一种方法来干净地使用ANTLR的树语法中的列表.这是我尝试过的和他们的结果(我真的希望我错过了一些微不足道的事情)......

使用+ =语法

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

method returns [SomeMethod result] : <definition here>
Run Code Online (Sandbox Code Playgroud)

这失败了......

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

如果我将输出设置为"AST"或"template"(唯一选项),则生成的类的方法签名会更改.也就是说,m不是由SomeMethod列表,而是分别是节点或模板列表.如果有办法使这种方法有效,我愿意接受建议.

使用规则范围

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);};
Run Code Online (Sandbox Code Playgroud)

这似乎有效,但我承认我还没有用嵌套/递归的情况测试它.

最终目标

我想构建一组代表我的语言的类(Class,Method,Variable,Statement,ect),这样我就可以在生成编译代码之前做一些静态分析和优化.为此,我需要能够使用列表.我希望+ =语法"正常工作",但我可能会遗漏一些东西.第二种方法有效,但看起来过于冗长和不优雅.

问题

在ANTLR的树语法中使用列表传递给我的具体类的原因是什么?

Mat*_*att 6

您可以从示例中删除范围,并使用局部变量完成所有操作.

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

这就是我们在工作中为此案例所做的工作.另一种选择是让您的方法规则处理它:

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(...); };
Run Code Online (Sandbox Code Playgroud)

我不太喜欢第二个选项,因为方法规则可能不应该关心它的结果是做什么的.但是你可以想象一个顶级规则创建的结构,ClassBeingCompiled其余的代码会逐渐填充它.addMethod().