ANTLR пытается сопоставить выражение, которое не было указано в качестве параметра

#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] ;
  

Состоит из двух частей:

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

Когда я иду проверять грамматику, происходит вот что: сначала я пишу заголовок и в новой строке указываю символ для первого поля. Пока все хорошо. Дерево синтаксического анализа выглядит так, как я ожидал до этого момента.

Проблема возникает, когда я добавляю следующее поле. ANTLR решает переосмыслить строку как экземпляр STR вместо конкатенации полей, которую я ожидал.

Я не понимаю, почему ANTLR пытается принудительно использовать несвязанное терминальное выражение, когда оно не было указано в качестве опции грамматикой. Разве он не должен знать, что нужно искать только символы, соответствующие правилам поля, поскольку они происходят от fields узла в дереве синтаксического анализа? Что здесь происходит и как мне написать мои грамматики ANTLR, чтобы у них не было этой проблемы?

Я читал, что ANTLR жадно пытается сопоставить формат от верхней части грамматики до нижней, но это не объясняет, почему это происходит, потому что терминал STR является самой последней строкой в файле. Если ANTLR предоставляет особый приоритет соответствующим терминалам, как мне отформатировать грамматику, чтобы она интерпретировала ее должным образом? Насколько я понимаю, регулярные выражения не работают для нетерминалов, поэтому, похоже, нужно определить это так, как сейчас.

Пояснение: это всего лишь пример возможной грамматики, которую я пытаюсь заставить работать с текстовым форматом как есть, поэтому я не ищу ответы вроде добавления пробела между полями или изменения заголовка на заглавный.

Ответ №1:

Чего я раньше не понимал, так это того, что в создании синтаксического анализатора есть два этапа:

  1. Сканирование входных данных на предмет списка токенов с использованием правил лексера (операторы верхнего регистра), а затем…
  2. Построение дерева синтаксического анализа с использованием правил синтаксического анализа (операторов нижнего регистра) и сгенерированных токенов

Моя проблема заключалась в том, что у ANTLR не было возможности узнать, что я хотел, чтобы эта конкретная строка интерпретировалась по-другому, когда он генерировал токены. Чтобы устранить эту проблему, я написал новое правило лексера для строки fields, чтобы ее можно было идентифицировать как токен. Ключом было отображение FIELDS правила перед STR правилом, потому что ANTLR проверяет их в порядке их появления.

 root : title FIELDS EOF;
title : STR;

FIELDS : [a-c] [d-f];
STR : [a-z] ;
  

Примечание: мне пришлось стиснуть зубы и прочитать ANTLR Me&a Tutorial, чтобы разобраться в этом.