2011-04-03 96 views
4

我已阅读很多试图找到一种方法来干净地使用ANTLR树语法中的列表。以下是我已经尝试及其结果(我真的希望我失去了一些东西简单)...ANTLR的AST树语法+列表

使用+ =语法

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

method returns [SomeMethod result] : <definition here> 

这种失败...

规则 '+ =' 列表标签不允许 W/O输出选项

如果将输出设置为“AST”或“模板”(唯一选项),则生成的类的方法签名会更改。也就是说,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);}; 

这似乎是工作,但我得承认,我没有使用嵌套/递归的情况下测试它。

最终目标

我想建立一个组代表我的语言(类,方法,变量声明,ECT)类,这样我可以做一些静态分析和优化我产生编译之前码。为此,我需要能够使用列表。我期望+ =语法“只是工作”,但我可能会错过一些东西。第二种方法可行,但看起来过于冗长和不雅。

问题

什么是正确的,为什么要消耗的清单,ANTLR的语法树,传递给我的具体类?

+0

'+ ='只有当你事先知道你的规则返回了什么类型的对象('output = AST'使它们的类型为'CommonTree')时才告诉ANTLR。我认为这与ANTLR的代码基本相当于Java 1.4这一事实有关,因为规则也可以返回诸如“int”或“double”等原语,因为1.4没有自动装箱。 – 2011-04-03 07:30:15

+0

+1正在为此 – 2011-05-17 19:29:36

回答

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()递增填充。

+0

+1我同意:第一个选项是IMO的“最干净”。 – 2011-04-03 07:30:34