You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为两个相似的ANTLR4语法实现共享Visitor以避免重复代码

解决方案

以下是几种可落地的复用方案,你可以根据项目约束选择:

方案1:抽取公共逻辑到静态工具类(改造成本最低)

将数字、加法的核心转换逻辑抽为无状态的静态工具方法,两个Converter各自从自己的Context中取出参数调用工具类即可,仅保留极薄的适配层代码:

// 公共工具类,核心逻辑仅写一次
public class ExpressionConvertUtils {
    // 数字节点转换逻辑
    public static Expression buildNumberExpr(String numberStr) {
        return new NumberExpression(Integer.parseInt(numberStr));
    }
    // 加法节点转换逻辑
    public static Expression buildAddExpr(Expression left, Expression right) {
        return new AddExpression(left, right);
    }
}

两个Converter的对应方法直接调用:

// Grammar1Converter 中的实现
@Override
public Expression visitNumber(Grammar1Parser.NumberContext ctx) {
    return ExpressionConvertUtils.buildNumberExpr(ctx.NUMBER().getText());
}
@Override
public Expression visitAddition(Grammar1Parser.AdditionContext ctx) {
    return ExpressionConvertUtils.buildAddExpr(visit(ctx.expr(0)), visit(ctx.expr(1)));
}

// Grammar2Converter 中的实现
@Override
public Expression visitNumber(Grammar2Parser.NumberContext ctx) {
    return ExpressionConvertUtils.buildNumberExpr(ctx.NUMBER().getText());
}
@Override
public Expression visitAddition(Grammar2Parser.AdditionContext ctx) {
    return ExpressionConvertUtils.buildAddExpr(visit(ctx.expr(0)), visit(ctx.expr(1)));
}

方案2:接口默认方法适配(适配层代码也可复用)

如果希望进一步减少重复的适配代码,可以通过泛型接口+默认方法实现公共逻辑封装:

public interface CommonConvertCapability<NumberCtx, AddCtx> {
    // 子类实现各自Context的取值逻辑
    String getNumberText(NumberCtx ctx);
    Expression visitLeftExpr(AddCtx ctx);
    Expression visitRightExpr(AddCtx ctx);

    // 默认实现公共转换逻辑
    default Expression convertNumber(NumberCtx ctx) {
        return new NumberExpression(Integer.parseInt(getNumberText(ctx)));
    }
    default Expression convertAdd(AddCtx ctx) {
        return new AddExpression(visitLeftExpr(ctx), visitRightExpr(ctx));
    }
}

Converter实现接口即可直接使用公共逻辑:

public class Grammar1Converter extends Grammar1BaseVisitor<Expression> 
    implements CommonConvertCapability<Grammar1Parser.NumberContext, Grammar1Parser.AdditionContext> {

    @Override
    public String getNumberText(Grammar1Parser.NumberContext ctx) {
        return ctx.NUMBER().getText();
    }
    @Override
    public Expression visitLeftExpr(Grammar1Parser.AdditionContext ctx) {
        return visit(ctx.expr(0));
    }
    @Override
    public Expression visitRightExpr(Grammar1Parser.AdditionContext ctx) {
        return visit(ctx.expr(1));
    }

    @Override
    public Expression visitNumber(Grammar1Parser.NumberContext ctx) {
        return convertNumber(ctx);
    }
    @Override
    public Expression visitAddition(Grammar1Parser.AdditionContext ctx) {
        return convertAdd(ctx);
    }
    // 其他独有规则的实现...
}

方案3:ANTLR语法层抽公共规则(复用程度最高)

如果允许调整原始语法定义,可以直接用ANTLR的import语法复用公共规则,从根源上避免重复逻辑:

  1. 先定义公共语法文件CommonExpr.g4:
grammar CommonExpr;

NUMBER : [0-9]+ ;
WS : [ \r\n\t]+ -> skip ;

expr : expr '+' expr    # Addition
     | NUMBER           # Number
     ;
  1. 两个业务语法导入公共语法,扩展独有规则:
// Grammar1.g4
grammar Grammar1;
import CommonExpr;

root : expr EOF;
expr : '*' expr expr # Multiplication; // 扩展乘法规则
// Grammar2.g4
grammar Grammar2;
import CommonExpr;

root : expr EOF;
expr : NUMBER '!' # Factorial | NUMBER '^' NUMBER # Exponentiation; // 扩展阶乘、幂运算规则

这种方式生成的公共规则Context会继承自统一父类,你可以直接编写公共Visitor基类处理公共规则,完全不需要重复代码。


内容的提问来源于stack exchange,提问作者tomashauser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 22:36:07