Я новичок в парсинге и ANTLR, поэтому заранее извиняюсь, если это глупый вопрос. Я пытаюсь использовать ANTLR для анализа логических формул (включая AND, OR, NOT). У меня следующая грамматика

grammar LTL;

ltl: ltl_or | ltl_and | ltl_not | Atom;

ltl_and: OPEN_CURLY ltl CLOSE_CURLY And OPEN_CURLY ltl CLOSE_CURLY;
ltl_or: OPEN_CURLY ltl CLOSE_CURLY Or OPEN_CURLY ltl CLOSE_CURLY;
ltl_not: Not OPEN_CURLY ltl CLOSE_CURLY;

Or: 'Or' | 'or';
Atom: (~('{' | '}'))+;
And: 'And' | 'and';
Not: 'Not' | 'not';
OPEN_CURLY: '{';
CLOSE_CURLY: '}';

Мой тестовый пример - {ABCD()}Or{AB CD()}, который, как я ожидаю, должен быть проанализирован как действительная формула Or с двумя атомами. И это действительно происходит с грамматикой выше. Однако, если я поменяю местами правила Or и Atom, как показано ниже:

Atom: (~('{' | '}'))+;
Or: 'Or' | 'or';

Я получаю ошибку

line 1:8 no viable alternative at input '{ABCD()}Or'

Может ли кто-нибудь указать несколько указателей?

0
SPMP 11 Окт 2021 в 14:46

2 ответа

Лучший ответ

Вот отредактированная версия вашей грамматики, которая правильно обрабатывает введенные вами данные и использует преимущества других идиом ANTLR, которые (надеюсь) облегчают чтение и поддержку. (С комментариями, указывающими, какие были внесены изменения.)

grammar LTL
    ;

// *almost* always a good idea to have a start rule that 
// consumes everything up to EOF to prevent
// premature termination of parsing input
ltl_start: ltl EOF;

// *IF* you really want to allow a "naked" ATOM 

// ltl_start: (ltl | ATOM) EOF;

// since it seems ltls are always wrapped in curlies, 
// I've refactored them a bit to simplify also
// used labelled alternatives that are generally easier to read 
// Note, you can use literals in your rules that match token rules 
// and ANTLR will match them up I find this frequently makes the
// grammar easier to read.
ltl
    : ltl OR ltl   # ltl_or
    | ltl AND ltl  # ltl_and
    | NOT ltl      # ltl_not
    | '{' ATOM '}' # ltl_atom
    ;

// Symbols
OPEN_CURLY:  '{';
CLOSE_CURLY: '}';

// keywords
OR:  'Or' | 'or';
AND: 'And' | 'and';
NOT: 'Not' | 'not';

// place ATOM *after* keywords to prevent keywords being misidentified as ATOMs
ATOM: ~[{}]+; // Another way of saying "Atom: (~('{' | '}'))+;"

Хотя это и не обязательно, я предпочитаю называть правила Lexer заглавными буквами, чтобы они действительно выделялись из правил синтаксического анализатора (индивидуальный вкус).

Для правил лексера очень часто используется несколько правил лексера, которые могут соответствовать определенной последовательности символов (т. Е. Неоднозначности). Полностью избежать их было бы ОЧЕНЬ болезненно, поэтому ANTLR допускает их и разрешает неоднозначности с помощью этих двух правил:

  • Если более одного правила лексера соответствует вводу, то используется то, которое соответствует самой длинной последовательности символов.
  • Если несколько правил соответствуют последовательности символов одинаковой длины, то используется правило лексера, которое появляется первым в грамматике.
1
Mike Cargal 11 Окт 2021 в 14:43

Ошибка "line 1:8 no viable alternative at input '{ABCD()}Or'" не могла быть вызвана грамматикой, которую вы опубликовали (может быть, вы разместили только небольшую часть вашей фактической грамматики)?

Опубликованная вами грамматика создаст следующее дерево синтаксического анализа для входных данных {ABCD()}Or{AB CD()}:

enter image description here

Обратите внимание, что он не будет правильно анализировать входные данные {ABCD()}And{AB CD()}, потому что правило лексера And помещается под правилом лексера Atom, и когда два правила лексического анализатора соответствуют одним и тем же символам, первое определено первым " побеждает ».

Таким образом, ошибка предполагает, что существует какое-то правило лексера, которое соответствует вводу {ABCD()}Or.

1
Bart Kiers 11 Окт 2021 в 13:45