修改Antlr生成的表达式?

Dim*_*ims 1 java antlr antlr4

我想用Antlr4读取表达式并对它们执行一些修改.

例如,如果语法是算术,我会修改表达式,表示

2 * (3 + 1)
Run Code Online (Sandbox Code Playgroud)

2 * 4
Run Code Online (Sandbox Code Playgroud)

然后用

8
Run Code Online (Sandbox Code Playgroud)

这是"计算"或"简化".要执行此操作,我将创建一些树结构,第一个想法是使用由Antlr创建的完全相同的树.

不幸的是,我没有看到儿童的任何二传手.

怎么做?我是否真的应该将Antlr树与我自己的树重复用于表达式逻辑?

Que*_*pas 6

您不应该复制或修改ANTRL树.你应该利用树访客和听众模式来使用它们.

语法

首先,我们将为算术表达式准备简单的语法.

grammar expr;

WS : [ \t\r\n] -> skip;
INT : [0-9]+;

program
    : expr # baseExpr
    ;

expr
    : '(' expr ')'              # exprParentheses
    | left=expr '*' right=expr  # exprMul
    | left=expr '+' right=expr  # exprAdd
    | INT                       # exprINT
    ;
Run Code Online (Sandbox Code Playgroud)

评估表达

为了评估表达式,我们将遍历解析树以执行计算或收集结果.

public class EvaluateExpr extends exprBaseVisitor<Integer> {
    @Override
    public Integer visitExprINT(exprParser.ExprINTContext ctx) {
        return Integer.valueOf(ctx.INT().getText());
    }

    @Override
    public Integer visitExprMul(exprParser.ExprMulContext ctx) {
        Integer left = visit(ctx.left);
        Integer right = visit(ctx.right);
        return left * right;
    }

    @Override
    public Integer visitExprAdd(exprParser.ExprAddContext ctx) {
        Integer left = visit(ctx.left);
        Integer right = visit(ctx.right);
        return left + right;
    }

    @Override
    public Integer visitExprParentheses(exprParser.ExprParenthesesContext ctx) {
        return visit(ctx.expr());
    }
}
Run Code Online (Sandbox Code Playgroud)

替换表达式

为了用其评估形式替换表达式,我们将使用TokenStreamRewriter类.该工具允许轻松替换令牌.

public class ReplaceExpr extends exprBaseListener {
    private TokenStreamRewriter rewriter;

    public ReplaceExpr(CommonTokenStream tokens) {
        rewriter = new TokenStreamRewriter(tokens);
    }

    @Override
    public void enterBaseExpr(exprParser.BaseExprContext ctx) {
        rewriter.replace(ctx.start, ctx.stop, new EvaluateExpr().visit(ctx));
    }

    public String getReplacedCode() {
        return rewriter.getText();
    }
}
Run Code Online (Sandbox Code Playgroud)

运行示例

现在我们需要执行表达式的评估和替换.

exprLexer lexer = new exprLexer(new ANTLRInputStream("2 * (3 + 1)"));
CommonTokenStream tokens = new CommonTokenStream(lexer);
exprParser parser = new exprParser(tokens);
ReplaceExpr replaceExpr = new ReplaceExpr(tokens);
ParseTreeWalker.DEFAULT.walk(replaceExpr, parser.program());
System.out.println("Replaced code: " + replaceExpr.getReplacedCode());
Run Code Online (Sandbox Code Playgroud)

解析树或AST(抽象语法树)

如果您仍需要修改后的解析树,则可以再次解析更改后的代码.如果要修改树结构,请将解析树转换为AST(抽象语法树),并从头开始处理AST.