我想用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树与我自己的树重复用于表达式逻辑?
您不应该复制或修改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.