3

Suppose that I have this simple and meaningless grammar:

propagate     :   what^ where*;
what          :   CHAR^;
where         :   NUMBER -> ^(PLUS NUMBER);

NUMBER        :   '0'..'9';
CHAR          :   'a'..'z';
PLUS          :   '+';

If it parses a string like a123456789, it generates an AST like: AST

What I would to do is to pass the token parsed by what to where and create an AST (for the same input) like: AST2

I tried in the following way:

propagate       :   w=what^ where[$w.text]*;
what            :   CHAR^;
where[String s] :   NUMBER -> ^(PLUS CHAR[s] NUMBER);

NUMBER          :   '0'..'9';
CHAR            :   'a'..'z';
PLUS            :   '+';

it works if what it's a single token, but what if it is a tree? Is this the correct approach?

marka.thore
  • 2,795
  • 2
  • 20
  • 35

1 Answers1

3

Here's how:

grammar T;

options {
  output=AST;
  ASTLabelType=CommonTree;
}

parse
 : propagate EOF!
 ;

propagate
 : what^ where[$what.tree]*
 ;

what
 : CHAR
 ;

where[CommonTree lhs]
 : NUMBER -> ^(PLUS {new CommonTree($lhs)} NUMBER)
 ;

NUMBER : '0'..'9';
CHAR   : 'a'..'z';
PLUS   : '+';

ANTLRWorks' debugger might not display the proper AST: create a small driver class yourself:

import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;

public class Main {
  public static void main(String[] args) throws Exception {
    TLexer lexer = new TLexer(new ANTLRStringStream("a123"));
    TParser parser = new TParser(new CommonTokenStream(lexer));
    CommonTree tree = (CommonTree)parser.parse().getTree();  
    DOTTreeGenerator gen = new DOTTreeGenerator();
    StringTemplate st = gen.toDOT(tree);
    System.out.println(st);
  }
}

To run it, do:

java -cp antlr-3.3.jar org.antlr.Tool T.g 
javac -cp antlr-3.3.jar *.java
java -cp .:antlr-3.3.jar Main > ast.dot

which will result in a DOT-file representing the following AST:

enter image description here

Bart Kiers
  • 166,582
  • 36
  • 299
  • 288
  • if `a` is a tree (with children), it seems to propagate only the root of the tree (only `a` without children), can you check it? Maybe it depends on the constructor of `CommonTree` ? – marka.thore Jan 10 '13 at 12:59
  • @SalvatoreD., well, isn't it what you asked? Your example and my demo do the same. Perhaps edit your question and rephrase it, or add more examples. – Bart Kiers Jan 10 '13 at 14:11
  • my question is what if I want to propagate an entire tree with its children instead of a single node. Your demo and my code propagate only a token or the root of tree. If in your demo `a` has two children named `b` and `c`, I would an ast like: `... ^(PLUS ^(a b c) 1) ^(PLUS ^(a b c) 2) ...` – marka.thore Jan 10 '13 at 14:35
  • @SalvatoreD., ah, okay. Then you'll need to do some extra work yourself, because, AFAIK, there's no deep-copy functionality in ANTLRv3. Also see this Q&A: http://stackoverflow.com/questions/6781019/antlr-duplicate-a-tree Instead of `{new CommonTree($lhs)}` do something like `{deepCopy($lhs)}` where `deepCopy(CommonTree)` is a method in your `@parser::members{ ... }` section (which returns a `CommonTree`, of course). – Bart Kiers Jan 11 '13 at 16:06
  • I've just implemented a solution like yours, I was hoping a simple way to do that, but maybe a deep clone is the only possible approach. Thank you – marka.thore Jan 11 '13 at 16:18