Применение ST к деревьям разбора, генерируемым Antlr4

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

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

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

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

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;
}
Другие вопросы по тегам