ANTLR 4 и StringTemplate 4 - использование обходчика деревьев с шаблонами

Отказ от ответственности: я никогда не использовал Java до прошлого месяца, и я никогда раньше не слышал об ANTLR или StringTemplate. На стажировку этим летом мне дали проект с использованием инструментов, которые никто в компании никогда не использовал. Все «верят в меня», что я «разберусь». Отсюда огромные пробелы в моем понимании. Мне нравится этот проект, и я многому научился, так что не воспринимайте это как жалобы. Я просто хочу, чтобы это работало.

Прямо сейчас я работаю над хорошим подтверждением концепции для старого предметно-ориентированного языка. Моя грамматика ANTLR создает красивые деревья синтаксического анализа, и я могу выводить простые примеры StringTemplate, подобные тем, которые были во введении.

Скажем, в моем .stg файле есть простой шаблон:

module(type, name, content) ::= "<type> MODULE <name>; <content>; END MODULE."

В Java я могу использовать add() для установки значений для каждого из аргументов шаблона:

STGroup g = new STGroupFile("example.stg");
ST st = g.getInstanceOf("module");
st.add("type", "MAIN");
st.add("name", "test");
st.add("content", "abc");
System.out.println(st.render()); 
// prints "MAIN MODULE test; abc; END MODULE."

Как мне заставить ANTLR и ST читать текстовый файл и производить красиво распечатанный вывод?

MAIN MODULE test;
abc;
END MODULE.

Должен стать

MAIN MODULE test; abc; END MODULE.

Например. (Я не планирую форматировать весь вывод, не волнуйтесь. Он будет печатать намного красивее, чем это.)

В этом ответе я узнал, что ANTLR 4 автоматически генерирует ходунки. Если моя грамматика ANTLR правильная / хорошо написана, как мне сопоставить правила / токены ANTLR с аргументами моего шаблона для генерации вывода из входного текстового файла?

Если я пропустил это где-нибудь в документации, дайте мне знать. Примеров ANTLR 4 и ST 4 гораздо меньше, чем в предыдущих версиях.


person Shelby S.    schedule 23.07.2015    source источник


Ответы (1)


Учитывая правило парсера

r : a b c ;

сгенерированное дерево синтаксического анализа будет содержать узел rContext с дочерними узлами aContext, bContext, cContex, каждый из которых потенциально имеет дополнительные дочерние узлы, для каждого экземпляра во входном потоке, где выполняется правило.

Прогулка вызовет серию звонков слушателя (или посетителя).

enterR
enterA
....
exitA
enterB
....
exitB
enterC
....
exitC
exitR

Каждый вызов содержит ссылку на контекст экземпляра в дереве синтаксического анализа, предоставляя доступ к фактическим значениям, которые могут быть переданы в ST в порядке префикса / суффикса относительно промежуточных дочерних узлов.

Если простого упорядочивания доступа по префиксу / суффиксу недостаточно (или нежелательно сложно), используйте один или несколько предыдущих обходов дерева синтаксического анализа для анализа более сложных узлов и аннотирования экземпляров узлов с помощью продуктов анализа. На последнем обходе выходных данных укажите в продуктах анализа значения, которые нужно передать в ST.

В зависимости от реальных обстоятельств, для анализа узла нет ничего необычного в том, чтобы собирать значения от его дочерних узлов, передавать партию в шаблон для раскрытия деталей, форматирования и т. Д. И сохранять результат в виде строки аннотации узла, ожидающей вывода в заключительный выходной обход.

Обновить

Чтобы аннотировать узлы дерева синтаксического анализа, вы можете использовать ParseTreeProperty.

Когда набор аннотаций становится более чем «тривиальным», типичный вариант - связать экземпляр класса «декоратор», специфичный для конкретного типа узла, с экземпляром узла / контекста дерева синтаксического анализа в основном как лучший контейнер данных. Конечно, методы, относящиеся к конкретным типам узлов, затем могут быть встроены в соответствующие классы-декораторы, чтобы обеспечить четкое разделение задач.

Методы слушателя становятся примерно такими:

public void exitNodeB(NodeBContext ctx) {
    super.exitNodeB(ctx);
    NodeBDescriptor descriptor = (NodeBDescriptor) getDescriptor(ctx);
    if (analysisPhase) {
        descriptor.process(); // node-type specific analysis
    } else {
        descriptor.output();  // node-type specific output generation
    }
}

Особенности того, когда анализировать (при входе, выходе или и том и другом) и когда выводить, будут зависеть от конкретного приложения. Реализуйте в соответствии с вашими целями.

person GRosenberg    schedule 23.07.2015
comment
Итак, я обновляю методы входа и выхода из файла MyGrammarListener.java? Используете параметр ctx? Или я ссылаюсь на ctx за пределами файла прослушивателя для подключения к StringTemplate? - person Shelby S.; 24.07.2015
comment
Спасибо, это действительно полезно. Это что-то, что я должен был получить, прочитав Справочник по ANTLR 4? Можно ли мне еще где-нибудь узнать, как это сделать? Я изучил ООП, когда использовал C ++ в своих классах, но Java выводит его на новый уровень. - person Shelby S.; 24.07.2015
comment
Я в основном не понимаю, где вы берете analysisPhase и как вы знаете, как создать descriptor. Я немного покопался в API-интерфейсах ANTLR и ST, но я понятия не имею, что иногда нужно делать. - person Shelby S.; 24.07.2015
comment
Взгляните на GenProjectModel в качестве образца. GenPackage Wizard можно использовать для (повторного) создания пакета, адаптированного к вашей грамматике. - person GRosenberg; 24.07.2015
comment
Привет, GRose, я пытался настроить GenPackage Wizard, но у меня возникли проблемы. Я клонировал репо и создал новый проект Java в Eclipse, чтобы проверить его, но я не уверен, как на самом деле сгенерировать пакет. Нужно ли мне писать свою главную? - person Shelby S.; 06.08.2015
comment
Следуйте инструкциям в файле использования. Если у вас есть проблема, откройте ее там. - person GRosenberg; 07.08.2015