如何解析ANTLR语法中atom ((PLUS | MINUS) atom)*模式?
解析ANTLR语法中
atom ((PLUS | MINUS) atom)*模式的示例 先看你提供的原语法文件:
grammar calculator; expression: atom ((PLUS | MINUS) atom)*; atom: '1'; PLUS: '+'; MINUS: '-'; WS: [ \r\n\t]+ -> skip;
针对你提到的atom ((PLUS | MINUS) atom)*模式,下面分别用Visitor和Listener两种模型给出具体解析实现,解决操作符与对应atom匹配的问题:
Visitor 实现(Java示例)
ANTLR生成的Visitor类中,ExpressionContext会包含所有atom的实例,以及对应的操作符节点。我们可以通过索引定位操作符,或者遍历子节点来匹配每一组操作符+atom:
import org.antlr.v4.runtime.Token; public class CalculatorVisitorImpl extends CalculatorBaseVisitor<Integer> { @Override public Integer visitExpression(CalculatorParser.ExpressionContext ctx) { // 先获取第一个atom的计算值 int result = visitAtom(ctx.atom(0)); // 遍历后续所有的atom和对应的操作符 for (int i = 1; i < ctx.atom().size(); i++) { // 操作符的位置:每组(op atom)占2个节点,所以第i个atom对应的操作符索引是 2*(i-1)+1 Token opToken = ctx.getChild(2*(i-1)+1).getSymbol(); int nextValue = visitAtom(ctx.atom(i)); // 根据操作符类型计算结果 if (opToken.getType() == CalculatorParser.PLUS) { result += nextValue; } else if (opToken.getType() == CalculatorParser.MINUS) { result -= nextValue; } } return result; } @Override public Integer visitAtom(CalculatorParser.AtomContext ctx) { // atom规则只有'1',直接返回1即可 return 1; } }
关键说明
ctx.atom()返回所有atom节点的列表,第一个元素是表达式开头的atom,后续元素是每个操作符后的atom。- 操作符节点的索引规律:因为表达式结构是
atom (op atom)*,所以第一个操作符在子节点索引1的位置,第二个在3,以此类推,对应公式2*(i-1)+1(i从1开始,对应第i个后续atom)。
Listener 实现(Java示例)
Listener基于事件回调,需要维护当前计算结果和最近匹配到的操作符,通过监听操作符和atom的回调事件来完成计算:
import org.antlr.v4.runtime.Token; public class CalculatorListenerImpl extends CalculatorBaseListener { private int calculationResult; private Token currentOperator; @Override public void enterExpression(CalculatorParser.ExpressionContext ctx) { // 初始化结果为第一个atom的值 calculationResult = 1; } @Override public void exitPLUS(CalculatorParser.PLUSContext ctx) { // 匹配到加号时记录操作符 currentOperator = ctx.getSymbol(); } @Override public void exitMINUS(CalculatorParser.MINUSContext ctx) { // 匹配到减号时记录操作符 currentOperator = ctx.getSymbol(); } @Override public void exitAtom(CalculatorParser.AtomContext ctx) { // 跳过第一个atom(已经在enterExpression中初始化) if (ctx.getParent() instanceof CalculatorParser.ExpressionContext) { CalculatorParser.ExpressionContext parentCtx = (CalculatorParser.ExpressionContext) ctx.getParent(); if (ctx != parentCtx.atom(0)) { int value = 1; // atom规则只有'1' if (currentOperator.getType() == CalculatorParser.PLUS) { calculationResult += value; } else if (currentOperator.getType() == CalculatorParser.MINUS) { calculationResult -= value; } } } } // 对外提供获取计算结果的方法 public int getResult() { return calculationResult; } }
关键说明
- 进入
expression时先初始化结果为第一个atom的值。 - 监听
PLUS和MINUS的exit事件,记录当前匹配到的操作符。 - 每个后续
atom的exit事件触发时,使用记录的操作符更新计算结果。
内容的提问来源于stack exchange,提问作者sion
相关产品推荐
相关产品推荐

