Копировать узлы деревьев, используя грамматики дерева ANTLR

Мне нужно руководство по решению проблемы, с которой я столкнулся, используя древовидную грамматику. По сути, я хочу иметь возможность заменять / копировать операторы, которые можно найти в дереве. Это, вероятно, лучше всего объяснить на примере.

Вот пример ввода:

int a = 10;
new function A;

function A {
    int x;
    int y;
    new function B;
}

function B {
    float b = 20;
}

Требуемый вывод (позже):

int a = 10;
int x;
int y;
float b = 20;

Это простой поиск и замена операторов внутри функциональных блоков. Моя проблема в том, предоставляет ли ANTLR способ сделать это посредством древовидных грамматик?

Вот грамматика, которая должна анализировать вышеуказанный ввод:

Test.g

grammar Test;
options {
  language = Java;
  output = AST;
}
tokens {
    VARDECL;
    FUNDEF;
    FUNCALL;
    BLOCK;
    ASSIGN;

    Assign = '=';
    EqT    = '==';  
    NEq    = '!=';
    LT     = '<';
    LTEq   = '<=';
    GT     = '>';
    GTEq   = '>=';
    NOT    = '!';
    PLUS   = '+';
    MINUS  = '-';
    MULT   = '*';
    DIV    = '/';
}

parse: statements+
     ;

statements : varDeclare
           | funcDefinition
           | funcCall
           ;

funcDefinition : 'function' id '{' funcBlock* '}' -> ^(FUNDEF id ^(BLOCK funcBlock*))
               ;

funcBlock : varDeclare
          | funcCall
          ;

funcCall : 'new' 'function' id ';' -> ^(FUNCALL id)
         ;

varDeclare : type id equalExp? ';' -> ^(VARDECL type id equalExp?)
           ;

equalExp : (Assign^ (expression | '...' )) 
         ;

expression : binaryExpression
           ;

binaryExpression : addingExpression ((EqT|NEq|LTEq|GTEq|LT|GT)^ addingExpression)*
                 ;

addingExpression : multiplyingExpression ((PLUS|MINUS)^ multiplyingExpression)*
                 ;

multiplyingExpression : unaryExpression 
                        ((MULT|DIV)^ unaryExpression)*
                      ;

unaryExpression: ((NOT|MINUS))^ primitiveElement
               | primitiveElement
               ;   

primitiveElement : literalExpression
                 | id
                 | '(' expression ')' -> expression
                 ;  

literalExpression : INT
                  ;              

id : IDENTIFIER
   ;

type : 'int'    
     | 'float'
     ; 

// L E X I C A L   R U L E S      

INT : DIGITS ;   

IDENTIFIER : LETTER (LETTER | DIGIT)*;

WS  :   ( ' '
        | '\t'
        | '\r'
        | '\n'
        ) {$channel=HIDDEN;}
    ;

fragment LETTER : ('a'..'z' | 'A'..'Z' | '_') ;
fragment DIGITS: DIGIT+;
fragment DIGIT : '0'..'9';

Test.java

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RuleReturnScope;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.DOTTreeGenerator;
import org.antlr.stringtemplate.StringTemplate;

public class Test {
    public static void main(String[] args) throws Exception {
        String src = "int a = 10;\r\n" + 
                "new function A;\r\n" + 
                "\r\n" + 
                "function A {\r\n" + 
                "   int x;\r\n" + 
                "   int y;\r\n" + 
                "   new function B;\r\n" + 
                "}\r\n" + 
                "\r\n" + 
                "function B{\r\n" + 
                "   float b = 20;\r\n" + 
                "}";
        TestLexer lexer = new TestLexer(new ANTLRStringStream(src));
        CommonTokenStream tokenStream = new CommonTokenStream(lexer);
        TestParser parser = new TestParser(tokenStream);
        RuleReturnScope r = parser.parse();
        System.out.println("Tree:" + ((CommonTree) r.getTree()).toStringTree() + "\n");


        CommonTree t = (CommonTree)r.getTree();
        generateGraph(t, "Tree.dot");   
    }

    private static void generateGraph(CommonTree t, String file) throws IOException {
        DOTTreeGenerator gen = new DOTTreeGenerator();
        StringTemplate st = gen.toDOT(t);
        String output = file;
        PrintWriter out = new PrintWriter(new FileWriter(output));
        out.println(st);
        out.close();
    }
}

Tree.dotГрафик AST

Как я могу выполнить поиск для каждого FUNCALL и заменить его содержимым BLOCK внутри с помощью Tree Grammar?

Заранее спасибо!

1 ответ

Решение

В вашей грамматике вы составите таблицу blockMap из ваших FUNDEF БЛОКОВ с идентификатором в качестве ключа.

Тогда в вашей древовидной грамматике что-то вроде этого, хотя, вероятно, потребуется некоторая настройка. Вы сделаете правило для funcCall:

funcCall : ^(FUNCALL id) -> {input.getTreeAdaptor().dupTree(blockMap.get(id)}
     ;

Вот что делает копию БЛОКА с карты: input.getTreeAdaptor(). DupTree(...)

Вам нужно сделать копию, потому что узлы отслеживают своих родителей, поэтому вы можете использовать их только в одном месте дерева.

Другие вопросы по тегам