STInterpreter条件判断时变量取值为null的原因分析
基于ANTLR4的STInterpreter条件判断时变量值为null的问题
我们实现了基于ANTLR4的STInterpreter解释器类,测试代码中完成了变量x、y的赋值,随后进行x < y的条件判断。执行后输出显示赋值成功,但条件判断时出现Left: null, Right: null, Operator: <的结果,未正确执行运算。
相关代码
STInterpreter类代码
package com.jdcs.st; import org.antlr.v4.runtime.*; import org.antlr.v4.runtime.tree.*; import java.util.HashMap; import java.util.Map; import com.jdcs.st.generated.*; public class STInterpreter { private final Map<String, Object> symbolTable = new HashMap<>(); public void execute(String code) { STLexer lexer = new STLexer(CharStreams.fromString(code)); STParser parser = new STParser(new CommonTokenStream(lexer)); ParseTree tree = parser.program(); new STVisitor().visit(tree); } private class STVisitor extends STBaseVisitor<Object> { @Override public Object visitAssignment(STParser.AssignmentContext ctx) { String variable = ctx.IDENTIFIER().getText(); Object value = visit(ctx.expression()); System.out.println("Assigning " + value + " to " + variable); // 调试信息 symbolTable.put(variable, value); // 打印当前符号表状态 System.out.println("Symbol Table: " + symbolTable); return null; } @Override public Object visitLiteral(STParser.LiteralContext ctx) { if (ctx.INT() != null) return Integer.parseInt(ctx.INT().getText()); if (ctx.BOOL() != null) return Boolean.parseBoolean(ctx.BOOL().getText()); return null; } @Override public Object visitExpression(STParser.ExpressionContext ctx) { if (ctx.operator() == null) { return visit(ctx.literal() != null ? ctx.literal() : ctx.IDENTIFIER()); } Object left = visit(ctx.expression(0)); Object right = visit(ctx.expression(1)); String operator = ctx.operator().getText(); System.out.println("Left: " + left + ", Right: " + right + ", Operator: " + operator); return evaluate(left, right, operator); } private Object evaluate(Object left, Object right, String operator) { switch (operator) { case "+": -> { return (int) left + (int) right; } case "-": -> { return (int) left - (int) right; } case "*": -> { return (int) left * (int) right; } case "/": -> { return (int) left / (int) right; } case "=": -> { return left.equals(right); } case "<": -> { return (int) left < (int) right; } case ">": -> { return (int) left > (int) right; } } throw new RuntimeException("Unsupported operator: " + operator); } @Override public Object visitCondition(STParser.ConditionContext ctx) { return visit(ctx.expression()); } @Override public Object visitIfStatement(STParser.IfStatementContext ctx) { boolean condition = (boolean) visit(ctx.condition()); if (condition) { ctx.statement().forEach(this::visit); } else if (ctx.statement().size() > 1) { visit(ctx.statement(1)); } return null; } } }
测试代码
STInterpreter interpreter = new STInterpreter(); String code = """ x := 10; y := 20; IF x < y THEN z := x + y; END_IF; """; interpreter.execute(code);
执行输出
Assigning 10 to x Assigning 20 to y Left: null, Right: null, Operator: <
问题原因
核心问题是访问变量标识符时,没有从符号表中读取已赋值的变量值。
在visitExpression方法中,当表达式是单个标识符(比如x或y)时,代码调用visit(ctx.IDENTIFIER()),但STVisitor类并没有重写visitIDENTIFIER方法。而ANTLR4的STBaseVisitor默认实现中,未重写的访问方法会返回null,导致变量值无法被正确获取,最终条件判断时left和right都为null。
解决方案
在STVisitor类中添加visitIDENTIFIER方法,从符号表中读取对应变量的值:
@Override public Object visitIDENTIFIER(STParser.IDENTIFIERContext ctx) { String varName = ctx.getText(); Object value = symbolTable.get(varName); if (value == null) { throw new RuntimeException("未定义的变量: " + varName); } return value; }
添加该方法后,当解释器访问到变量标识符节点时,会从之前赋值的symbolTable中取出对应的值,条件判断就能正确获取x=10和y=20,执行10 < 20的比较运算,进而进入IF分支执行z := x + y的赋值操作。
内容的提问来源于stack exchange,提问作者Eljah
相关产品推荐
相关产品推荐

