Antlr4 Visitor代码计算结果错误,求排查运算符判断问题
解决Antlr4 Visitor算术表达式计算错误问题
Antlr4 Visitor代码运行后输出错误结果,无法定位问题。以下是简单算术表达式语法:
grammar Arithmetics; expr : term (PLUS term | MINUS term)*; term : factor (MULT factor | DIV factor)*; factor : INT; PLUS : '+'; MINUS : '-'; MULT : '*'; DIV : '/'; INT : [0-9]+; WS : [ \t\r\n]+ -> skip;
C#代码实现:
class Program { static void Main(string[] args) { string input = "1 + 2 * 3 - 8 / 4"; var lexer = new ArithmeticsLexer(new AntlrInputStream(input)); var tokens = new CommonTokenStream(lexer); var parser = new ArithmeticsParser(tokens); var tree = parser.expr(); Console.WriteLine(tree.ToStringTree(parser)); var visitor = new MyArithmeticsVisitor(); int result = visitor.Visit(tree); Console.WriteLine($"Result: {result}"); } } public class MyArithmeticsVisitor : ArithmeticsBaseVisitor<int> { public override int VisitExpr(ArithmeticsParser.ExprContext context) { Console.WriteLine($"Expr:{context.GetText()}"); int result = VisitTerm(context.term(0)); for (int i = 1; i < context.term().Length; i++) { String s = context.term(i).GetText(); Console.WriteLine($"Visiting term {s}"); if (context.PLUS(i) != null) result += VisitTerm(context.term(i)); else if (context.MINUS(i) != null) result -= VisitTerm(context.term(i)); } return result; } public override int VisitTerm(ArithmeticsParser.TermContext context) { int result = VisitFactor(context.factor(0)); for (int i = 1; i < context.factor().Length; i++) { if (context.MULT(i - 1) != null) result *= VisitFactor(context.factor(i)); else if (context.DIV(i - 1) != null) result /= VisitFactor(context.factor(i)); } return result; } public override int VisitFactor(ArithmeticsParser.FactorContext context) { string strFactor = context.INT().GetText(); Console.WriteLine($"factor {strFactor}"); return int.Parse(strFactor); } }
运行输出:
(expr (term (factor 1)) + (term (factor 2) * (factor 3)) - (term (factor 8) / (factor 4))) Expr:1+2*3-8/4 factor 1 Visiting term 2*3 Visiting term 8/4 Result: 1
问题分析
VisitExpr方法中运算符判断逻辑错误:语法规则expr : term (PLUS term | MINUS term)*生成的上下文里,PLUS()和MINUS()的数组长度等于term()数组长度减1(第一个term没有前置运算符)。原代码中用循环变量i(从1开始)去访问context.PLUS(i)或context.MINUS(i),会导致索引越界,所有运算符判断都不成立,最终结果仅保留第一个term的值。
修正后的VisitExpr方法
public override int VisitExpr(ArithmeticsParser.ExprContext context) { Console.WriteLine($"Expr:{context.GetText()}"); int result = VisitTerm(context.term(0)); // 运算符数量等于term数量减1 int opCount = context.term().Length - 1; for (int i = 0; i < opCount; i++) { var currentTerm = context.term(i + 1); Console.WriteLine($"Visiting term {currentTerm.GetText()}"); // 用i作为运算符的索引,对应第i个PLUS或MINUS if (context.PLUS(i) != null) { result += VisitTerm(currentTerm); } else if (context.MINUS(i) != null) { result -= VisitTerm(currentTerm); } } return result; }
修正后运行结果
修正后重新运行,输出结果为Result: 5,符合算术表达式1 + 2*3 - 8/4 = 1+6-2=5的预期。
内容的提问来源于stack exchange,提问作者Michael EstrinOne
相关产品推荐
相关产品推荐

