Конструкция дерева: распространение поддерева на дочернее

Предположим, что у меня есть эта простая и бессмысленная грамматика:

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

Я пробовал следующим образом:

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

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

он работает, если что это единственный токен, но что, если это дерево? Это правильный подход?

3
nl ja de

1 ответы

Вот как:

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 может не отображать правильный АСТ: создать небольшой класс драйвера самостоятельно:

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);
  }
}

Чтобы запустить его, выполните:

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

который приведет к DOT-файлу, представляющему собой следующий AST:

enter image description here

3
добавлено
если a является деревом (с дочерними элементами), он, по-видимому, распространяет только корень дерева (только a без детей), можете ли вы его проверить? Может быть, это зависит от конструктора CommonTree ?
добавлено автор marka.thore, источник
мой вопрос в том, что если я хочу распространять целое дерево со своими дочерними элементами вместо одного узла. Ваша демонстрация и мой код распространяют только токен или корень дерева. Если в вашем демо a есть два дочерних элемента с именем b и c , мне бы понравилось: ... ^ (PLUS ^ (abc) 1) ^ (PLUS ^ (abc) 2) ...
добавлено автор marka.thore, источник
Я только что реализовал такое решение, как ваше, я надеялся на простой способ сделать это, но, возможно, глубокий клон - единственный возможный подход. спасибо
добавлено автор marka.thore, источник
@SalvatoreD., Ну, разве это не то, что вы спросили? Ваш пример и моя демо делают то же самое. Возможно, отредактируйте свой вопрос и перефразируйте его, или добавьте больше примеров.
добавлено автор Bart Kiers, источник
@SalvatoreD., Ах, ладно. Тогда вам нужно будет сделать дополнительную работу самостоятельно, потому что, AFAIK, в ANTLRv3 нет функции глубокой копии. Также см. Этот вопрос: stackoverflow.com/questions/6781019/antlr-duplicate -a-tree Вместо {new CommonTree ($ lhs)} выполните что-то вроде {deepCopy ($ lhs)} , где deepCopy (CommonTree) - это метод в разделе @parser :: members {...} (который, конечно же, возвращает CommonTree ).
добавлено автор Bart Kiers, источник