Применение ST к деревьям синтаксического анализа, сгенерированным Antlr4

Сгенерированные методы доступа узлов контекста дерева синтаксического анализа не соответствуют стандарту getProperty()/isProperty()/hasProperty(). В результате ST нельзя применить к дереву синтаксического анализа напрямую. Кажется, есть 3 альтернативы для применения ST к сгенерированным деревьям синтаксического анализа:

  1. Создайте классы адаптера модели ST для каждого созданного узла контекста. Затем ST можно применить непосредственно к сгенерированному дереву синтаксического анализа. Дублирование здесь заключается в создании адаптеров модели.
  2. Для каждого узла дерева синтаксического анализа создайте узел-оболочку, соответствующий стандарту getProperty()/isProperty()/hasProperty(). Затем ST можно применить к узлам-оболочкам. Здесь дублируется работа по созданию узлов-оболочек. (В этом случае дерево синтаксического анализа даже не требуется; построение автоматического дерева синтаксического анализа можно отключить, а узлы-оболочки (AST) можно создавать в действиях грамматики).
  3. Создайте посетителя. Каждое посещение*() создает экземпляр ЗБ, относящийся к посещаемому узлу контекста, устанавливает параметры (которые могут быть ЗБ, возвращаемыми при посещении дочерних узлов, или простыми строками) и возвращает ЗБ. Это вариант, который я сейчас использую. Дублирование здесь заключается в создании посетителя и назначении параметров шаблона в коде.

Существует ли опция Antlr4, которая генерирует средства доступа к узлам контекста дерева синтаксического анализа, соответствующие стандарту getProperty()/isProperty()/hasProperty()? Или есть опция ST4, позволяющая обращаться к property() вместо поиска getProperty()?

Было бы неплохо просто создать экземпляр шаблона ST с корневым узлом контекста в качестве параметра и позволить ST пройти по дереву.


person Y2i    schedule 04.04.2017    source источник


Ответы (1)


Просто хотел поделиться решением, которое почти позволяет избежать дублирования работы при использовании подхода № 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;
}
person Y2i    schedule 27.04.2017