修改Antlr生成的表达式?

时间:2016-12-16 08:48:10

标签: java antlr antlr4

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

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

2 * (3 + 1)

2 * 4

然后用

8

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

不幸的是,我没有看到任何针对孩子的人。

如何完成?我是否应该将Antlr树与我自己的树重复用于表达式逻辑?

1 个答案:

答案 0 :(得分: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
    ;

评估表达式

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

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

替换表达式

为了用其评估形式替换表达式,我们将使用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();
    }
}

运行示例

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

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

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

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