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

时间:2017-04-04 13:51:59

标签: antlr4 stringtemplate-4

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

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

    简单地使用根上下文节点作为参数实例化ST模板并让ST遍历树是很好的。

1 个答案:

答案 0 :(得分:0)

只是想分享一个解决方案,几乎可以避免重复工作,同时使用我的问题中的方法#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;
}