ANTLR语法的迁移工具



假设我有以下简单语法(查询DSL):

grammar TestGrammar;
term : textTerm ;
textTerm : 'Text' '(' T_VALUE '=' STRING+ ')' ;
T_VALUE : 'value' ;
STRING : '"' .+? '"' ;
WS : [ trn]+ -> skip ;

然后在某个时候我决定需要更改文本术语格式,例如:

Text(value = "123") -> MyText(val = "123")

我应该如何迁移用户使用以前版本的语法生成的现有数据?

假设

让我们通过为'Text'字符串引入标记TEXT来简化您的语法。

grammar TestGrammar;
WS : [ trn]+ -> channel(HIDDEN);  // preserve the whitespaces characters!
T_VALUE : 'value';
STRING : '"' .+? '"';
TEXT : 'Text';
term
    : textTerm;
textTerm
    : TEXT '(' T_VALUE '=' STRING+ ')';

解决方案

现在我们将利用ANTLRv4工具构建的AST侦听器。这允许我们遍历AST并使用Lucas Trzesniewski在注释中已经提到的TokenStreamRewriter类执行令牌替换。

import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.TokenStreamRewriter;
public class MigrationTask extends TestGrammarBaseListener {
    private TokenStreamRewriter rewriter;
    public MigrationTask(CommonTokenStream stream) {
        this.rewriter = new TokenStreamRewriter(stream);
    }
    @Override
    public void enterTextTerm(TestGrammarParser.TextTermContext ctx) {
        rewriter.replace(ctx.TEXT().getSymbol(), "MyText");
        rewriter.replace(ctx.T_VALUE().getSymbol(), "val");
    }
    public String getMigrationResult() {
        return rewriter.getText();
    }
}

因此,每当在AST遍历过程中遇到该令牌时,我们就用它的替代品替换给定的令牌。

使用

现在我们可以在给定的ParseTree上执行MigrationTask并检索迁移结果:

(...)
CommonTokenStream tokens = new CommonTokenStream(lexer);
TestGrammarParser parser = new TestGrammarParser(tokens);
ParseTree tree = parser.term();
ParseTreeWalker walker = new ParseTreeWalker();
MigrationTask migrationTask = new MigrationTask(tokens);
walker.walk(migrationTask, tree);
String result = migrationTask.getMigrationResult(); // Here we retrive migration result !
(...)

最新更新