返回不同类型的对象时,将 Visitor 或 Listener 与 ANTLR4 结合使用

vas*_*ily 7 java antlr antlr4

我使用 ANTLR4 将一种语言翻译成另一种语言。例如,当我读取数字文字时,我可以返回Integeror Double

@Override
public Integer visitIntegerValue(Parser.IntegerValueContext ctx) {
    return Integer.valueOf(ctx.getText());
}

@Override
public Double visitDoubleValue(Parser.DoubleValueContext ctx) {
    return Double.valueOf(ctx.getText());
}
Run Code Online (Sandbox Code Playgroud)

最终,如果您进一步扩展此方法并引入其他构造(例如字符串和条件),则对于访问者来说唯一合理的类型是class Visitor extends BaseVisitor<Object>,但它会导致代码大量添加instanceof. 例如

@Override
public CollectionQuery visitCondition(Parser.ConditionContext ctx) {
    Property property = (Property) visit(ctx.property());
    String operator = (String) visit(ctx.operator());
    Object value = visit(ctx.amount());
    Object condition;
    if (value instanceof String && operator.equals("$regex")) {
        condition = Pattern.compile((String) value, Pattern.CASE_INSENSITIVE);
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

虽然我不介意这种“动态性”,但我想知道这是否是一种可维护的继续方式,或者是否应该使用其他技术,例如创建目标语言结构的适当层次结构。

Mat*_*hew 4

一个建议是每种返回类型都有一个访问者:

public class IntegerVisitor extends BaseListener<Integer> {
  @Override
  public Integer visitIntegerValue(Parser.IntegerValueContext ctx) {
    return Integer.valueOf(ctx.getText());
  }
}

public class DoubleVisitor extends BaseListener<Double> {
  @Override
  public Double visitDoubleValue(Parser.DoubleValueContext ctx) {
    return Integer.valueOf(ctx.getText());
  }
}
Run Code Online (Sandbox Code Playgroud)

当您访问截然不同的事物时,这更有意义(例如,如果您使用 java 语法进行解析,则可能有 aMethodVisitor和 aClassVisitor等。请参阅此处的示例:请参阅此处的示例