将 ST 应用于 Antlr4 生成的解析树

Applying ST to Antlr4-generated parse trees

生成的解析树上下文节点访问器不符合 getProperty()/isProperty()/hasProperty() 标准。因此,ST 不能直接应用于解析树。似乎有 3 种替代方法可以将 ST 应用于生成的解析树:

  1. 为每个生成的上下文节点创建 ST 模型适配器 类。然后 ST 可以直接应用于生成的解析树。 这里的重复工作是创建模型适配器。
  2. 为每个解析树节点创建一个符合 getProperty()/isProperty()/hasProperty() 标准的包装器节点。然后 ST 可以应用于包装器节点。 这里的重复工作是创建包装器节点。(在这种情况下甚至不需要解析树;可以关闭自动解析树构造,并且可以在语法中创建包装器 (AST) 节点动作)。
  3. 创建访客。每个 visit*() 实例化一个特定于被访问的上下文节点的 ST,设置参数(可以是访问子节点或简单字符串返回的 ST)和 returns ST。这是我目前使用的选项。 这里的重复工作是在代码中创建访问者和分配模板参数。

是否有 Antlr4 选项生成符合 getProperty()/isProperty()/hasProperty() 标准的解析树上下文节点的访问器?或者是否有一个 ST4 选项允许它访问 属性() 而不是查找 getProperty()?

最好简单地实例化一个ST模板,以根上下文节点为参数,让ST遍历树。

只是想分享一个几乎可以避免重复工作的解决方案,同时使用我的问题中的方法 #1。

第1步:创建模型适配器,使用反射调用不符合getProperty()/isProperty()/hasProperty()标准的方法。

private static class MyModelAdaptor extends ObjectModelAdaptor {
    @Override
    public synchronized Object getProperty(Interpreter interp, ST self, Object o, Object property, String propertyName) throws STNoSuchPropertyException {
        try {
            return super.getProperty(interp, self, o, property, propertyName);
        } catch (STNoSuchPropertyException noProperty) {
            final Class<?> cls = o.getClass();
            try {
                return cls.getMethod(propertyName).invoke(o);
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                throw noProperty;
            }
        }
    }
}

第 2 步:注册模型适配器

public static STGroup registerAdaptors(STGroup stg) {
    final MyModelAdaptor adaptor = new MyModelAdaptor();
    for (final Class<?> cls : MyParser.class.getDeclaredClasses()) {
        if (isSubclassOf(cls, ParserRuleContext.class)) {
            stg.registerModelAdaptor(cls, adaptor);
        }
    }
    return stg;
}

第 3 步:实现 isSubclassOf() 方法以便 registerAdaptors() 编译:

private static boolean isSubclassOf(Class<?> cls, Class<?> superCls) {
    while (cls != null) {
        if (cls == superCls) {
            return true;
        }
        cls = cls.getSuperclass();
    }
    return false;
}