我想用Antlr4读取表达式并对它们执行一些修改。
例如,如果语法是算术,我会修改表达式,代表
2 * (3 + 1)
与
2 * 4
然后用
8
这是"计算"或&& 34;简化"。要执行此操作,我将创建一些树结构,第一个想法是使用由Antlr创建的完全相同的树。
不幸的是,我没有看到任何针对孩子的人。
如何完成?我是否应该将Antlr树与我自己的树重复用于表达式逻辑?
答案 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。