Нерелевантное правило нарушает грамматику ANTLR4

Я строю грамматику ANTLR4 для синтаксического анализа строк из источника данных - похоже, если не во многом так же, как StringTemplate, за исключением того, что мне не нравится этот синтаксис, поэтому я пишу свой собственный (также просто для удовольствия и обучения, так как это мой первый опыт с ANTLR). Моя грамматика в настоящее время выглядит следующим образом (это упрощено от того, что у меня есть на самом деле, но я убедился, что это "хороший пример" и демонстрирует ту же проблему, о которой я спрашиваю):

grammar Combined1;

file: 
    .*? (repToken .*?)+
    | .*?
    ;

foreach: '@foreach' WS* '(' WS* repvar WS* ')' WS* '{' content=file '}' ;
with: '@with' WS* '(' WS* repvar WS* ')' WS* '{' content=file '}' ;
// withx: '@withx' WS* '(' WS* repvar WS* ')' WS* '{' content=file '}' ;

repvar: '@' (
    '$'
    | '(' nestedIdentifier ')'
    | nestedIdentifier 
    ) ;

repToken:
    foreach
    | with
    // | withx
    | repvar
    ;

nestedIdentifier: Identifier ('.' Identifier)* ;
Identifier: [A-Za-z_] [A-Za-z0-9_]* ;
WS: [ \t\r\n] ;
Other: ( . ) ;

Эта грамматика прекрасно работает, что позволяет мне выполнять замены, такие как:

string template = "Test: @foreach(@list){@$}";
Process(template, new { list = new [] { "A", "B", "C" } });

и результат будет:

Test: ABC

(Механика обработки дерева для получения этого результата относительно проста, но не имеет отношения к вопросу, поэтому я не предоставляю этот код.)

У меня такой вопрос... если я добавлю (раскомментирую) правило "withx" прямо под with: правило, и я забыл включить (раскомментировать) withx к альтернативам в repToken тогда мой пример выше ломается, хотя это не имеет ничего общего с withx, Как только я добавлю withx в качестве альтернативы repToken тогда мой пример снова работает. Зачем??

Вот что я знаю:

  • Несмотря на погоду withx включен или нет, мой лексер правильно возвращает 12 токенов: Test, :, ' ', @foreach, (, @, list, ), {, @, item, Это неудивительно, поскольку я только добавил правило синтаксического анализатора и не коснулся токенов лексера (кроме добавления неявного токена '@withx').
  • Прежде чем я добавлю withx Как правило, мой синтаксический анализатор правильно группирует все токены после @foreach как дочерние элементы ForeachContext, в результате чего получается FileContext с 4 дочерними элементами (3 TerminalNodeImpl и RepTokenContext).
  • После того как я добавлю withx Как правило, мой синтаксический анализатор по какой-то причине не распознает остальные токены как принадлежащие ForeachContext, что приводит к FileContext с 10 дочерними элементами, ни один из которых не является ForeachContext, но который имеет все TerminalNodeImpl с 2 RepTokenContext, соответствующими @list и @$.

Я совершенно сбит с толку, почему добавление правила парсера, которое не имеет ничего общего с моим вводом, может привести к сбою парсера. Помогите!?

РЕДАКТИРОВАНИЕ 17.03.2014 : JavaMan запросил дерево разбора в каждом сценарии, чтобы пояснить описание выше. Я не знаю, как сгенерировать графическое представление дерева разбора, которое он сделал, но вот два скриншота из отладчика Visual Studio, иллюстрирующие разницу... Обратите внимание, что в этих изображениях я использую более длинные имена - в частности, ReplacementTokenContext для repToken.

Первый, когда я включаю withx в альтернативном списке (обратите внимание, что дерево по сути FileContext -> ReplacementTokenContext (индекс узла 3) -> ForeachContext): Visual Studio Смотреть, когда я включаю с

И второе, когда я не включаю withx в альтернативном списке (обратите внимание, что дерево по сути FileContext -> TerminalNodeImpl "@foreach" (индекс узла 3): Visual Studio Смотреть, когда я не включаю с

1 ответ

Со всей вашей грамматикой плюс withx Правило и 2 строки ввода, я могу получить этот узел дерева разбора repToken группировка входного текста @foreach под foreach узел:

Это выглядит как правильный разбор для меня. Это то, что вы хотите? Может ли быть проблема с вашим кодом посетителя? Вы получили то же самое дерево разбора? Было бы лучше, если бы вы могли опубликовать свое дерево разбора здесь.

Кстати, как насчет отправки всех пробелов в скрытый канал и удаления всех токенов WS из правил парсера?

РЕДАКТИРОВАТЬ:

Я использую ANTLR4 V4.1 только с целью Java, поэтому я не могу быть уверен, что это ошибка с целью C# или v4.2. Но обе грамматики дают мне одно и то же дерево разбора в Java. Существует инструмент под названием TestRig (по крайней мере, в Java target), который может генерировать дерево разбора в форме GUI или ASCII:

java org.antlr.v4.runtime.misc.TestRig Combine1 file -tree in.cpp > treeres.txt

Запустив указанную выше команду с использованием двух упомянутых вами версий грамматики и одного и того же входного файла, я получил такое же ASCII-представление дерева разбора:

(file string   template   =   " Test :   (repToken (foreach @foreach ( (repvar @ (nestedIdentifier list)) ) { (file (repToken (repvar @ $))) })) " ; \r \n Process ( template ,   new   {   list   =   new   [ ]   {   " A " ,   " B " ,   " C "   }   } ) ;)

Графический вывод слишком большой, поэтому я не включаю их здесь. Так что, по крайней мере, в Java одно и то же дерево разбора генерируется с или без withx править.

Я предлагаю вам дважды проверить с помощью инструмента TestRig или попробовать проверить с помощью цели Java.

Другие вопросы по тегам