#parsin& #antlr #&rammar
#Синтаксический анализ #antlr #грамматика
Вопрос:
Я пытаюсь понять, как работают грамматики ANTLR, и я столкнулся с ситуацией, когда оно ведет себя неожиданно, и я не могу объяснить почему или выяснить, как это исправить.
Вот пример:
root : title 'n' fields EOF;
title : STR;
fields : field_1 field_2;
field_1 : 'a' | 'b' | 'c';
field_2 : 'd' | 'e' | 'f';
STR : [a-z] ;
Состоит из двух частей:
- Заголовок, представляющий собой строку в нижнем регистре без специальных символов
- Двухсимвольная строка, представляющая набор возможных конфигураций
Когда я иду проверять грамматику, происходит вот что: сначала я пишу заголовок и в новой строке указываю символ для первого поля. Пока все хорошо. Дерево синтаксического анализа выглядит так, как я ожидал до этого момента.
Проблема возникает, когда я добавляю следующее поле. ANTLR решает переосмыслить строку как экземпляр STR
вместо конкатенации полей, которую я ожидал.
Я не понимаю, почему ANTLR пытается принудительно использовать несвязанное терминальное выражение, когда оно не было указано в качестве опции грамматикой. Разве он не должен знать, что нужно искать только символы, соответствующие правилам поля, поскольку они происходят от fields
узла в дереве синтаксического анализа? Что здесь происходит и как мне написать мои грамматики ANTLR, чтобы у них не было этой проблемы?
Я читал, что ANTLR жадно пытается сопоставить формат от верхней части грамматики до нижней, но это не объясняет, почему это происходит, потому что терминал STR является самой последней строкой в файле. Если ANTLR предоставляет особый приоритет соответствующим терминалам, как мне отформатировать грамматику, чтобы она интерпретировала ее должным образом? Насколько я понимаю, регулярные выражения не работают для нетерминалов, поэтому, похоже, нужно определить это так, как сейчас.
Пояснение: это всего лишь пример возможной грамматики, которую я пытаюсь заставить работать с текстовым форматом как есть, поэтому я не ищу ответы вроде добавления пробела между полями или изменения заголовка на заглавный.
Ответ №1:
Чего я раньше не понимал, так это того, что в создании синтаксического анализатора есть два этапа:
- Сканирование входных данных на предмет списка токенов с использованием правил лексера (операторы верхнего регистра), а затем…
- Построение дерева синтаксического анализа с использованием правил синтаксического анализа (операторов нижнего регистра) и сгенерированных токенов
Моя проблема заключалась в том, что у ANTLR не было возможности узнать, что я хотел, чтобы эта конкретная строка интерпретировалась по-другому, когда он генерировал токены. Чтобы устранить эту проблему, я написал новое правило лексера для строки fields, чтобы ее можно было идентифицировать как токен. Ключом было отображение FIELDS
правила перед STR
правилом, потому что ANTLR проверяет их в порядке их появления.
root : title FIELDS EOF;
title : STR;
FIELDS : [a-c] [d-f];
STR : [a-z] ;
Примечание: мне пришлось стиснуть зубы и прочитать ANTLR Me&a Tutorial, чтобы разобраться в этом.