一次处理一个孩子的n-ary ANTLR AST

时间:2010-04-20 21:10:48

标签: antlr

我目前有一个使用AST的编译器,其中代码块的所有子代都在同一级别上(即block.children == {stm1,stm2,stm3等...})。我试图对这棵树进行活性分析,这意味着我需要从stm1的处理中获取返回的值,然后将其传递给stm2,然后获取stm2返回的值并将其传递给stm3,依此类推。当AST以这种方式构建时,我没有看到以这种方式执行子规则的方法。

有没有办法允许我用我给定的AST链接子语法项的执行,或者我将不得不经历重构解析器以生成嵌套结构和更新其余部分的痛苦过程编译器使用新的AST?


示例ANTLR语法片段:

block
    : ^(BLOCK statement*)
    ;
statement
    : // stuff
    ;

我希望我不必去:

block
    : ^(BLOCK statementList)
    ;
statementList
    : ^(StmLst statement statement+) 
    | ^(StmLst statement)
    ;
statement
    : // stuff
    ;

1 个答案:

答案 0 :(得分:1)

Parser(或lexer)规则可以获取参数值并可以返回值。因此,在您的情况下,您可以执行以下操作:

block
@init {Object o = null; /* initialize the value being passed through */ }
  :  ^(BLOCK (s=statement[o] {$o = $s.returnValue; /*re-assign 'o' */ } )*)
  ;

statement [Object parameter] returns [Object returnValue]
  :  // do something with 'parameter' and 'returnValue'
  ;

这是一个非常简单的例子,你可以用它来玩:

grammar Test;

@members{
    public static void main(String[] args) throws Exception {
        ANTLRStringStream in = new ANTLRStringStream("1;2;3;4;");
        TestLexer lexer = new TestLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        TestParser parser = new TestParser(tokens);
        parser.parse();
    }
}

parse
  : block EOF
  ;

block
@init{int temp = 0;}
  :  (i=statement[temp] {temp = $i.ret;} ';')+
  ;

statement [int param] returns [int ret]
  :  Number {$ret = $param + Integer.parseInt($Number.text);} 
     {System.out.printf("param=\%d, Number=\%s, ret=\%d\n", $param, $Number.text, $ret);}
  ;

Number
  :  '0'..'9'+
  ;

当您从中生成解析器和词法分析器并编译这些类时,执行TestParser类,您将看到以下内容打印到您的控制台:

param=0, Number=1, ret=1
param=1, Number=2, ret=3
param=3, Number=3, ret=6
param=6, Number=4, ret=10