tags:

views:

67

answers:

1

I currently have a compiler that uses an AST where all children of a code block are on the same level (ie, block.children == {stm1, stm2, stm3, etc...}). I am trying to do liveness analysis on this tree, which means that I need to take the value returned from the processing of stm1 and then pass it to stm2, then take the value returned by stm2 and pass it to stm3, and so on. I do not see a way of executing the child rules in this fashion when the AST is structured this way.

Is there a way to allow me to chain the execution of the child grammar items with my given AST, or am I going to have to go through the painful process of refactoring the parser to generate a nested structure and updating the rest of the compiler to work with the new AST?


Example ANTLR grammar fragment:

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

What I hope I don't have to go to:

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

Parser (or lexer) rules can take parameter values and can return a value. So, in your case, you can do something like:

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'
  ;

Here's a very simple example that you can use to play around with:

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'+
  ;

When you've generated a parser and lexer from it and compiled these classes, execute the TestParser class and you'll see the following printed to your console:

param=0, Number=1, ret=1
param=1, Number=2, ret=3
param=3, Number=3, ret=6
param=6, Number=4, ret=10
Bart Kiers
Thank you so much. That's exactly what I needed.
Chris Lieb
Good to hear it @Chris. You're welcome.
Bart Kiers