Проблема разрешения конфликта shift-reduce в моей грамматике

Я пытаюсь написать небольшой парсер с Ирония. К сожалению, я получаю "shift-reduce conflict". Грамматика не моя сильная сторона,и мне нужно только сделать эту маленькую вещь. Вот сокращенная грамматика, которая вызывает ошибку:

ExpressionTerm := "asd"
LogicalExpression :=
    ExpressionTerm |
    LogicalExpression "AND" LogicalExpression |
    LogicalExpression "OR" LogicalExpression

что означает "конфликт сдвига-уменьшения" и как я могу его решить? Я понимаю, что это означает, что моя грамматика неоднозначна, но я не могу достаточно исказить свою логику, чтобы увидеть как.

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

asd
asd AND asd
asd AND asd OR asd
asd OR asd AND asd OR asd

добавлена 2: забыл сказать, корень грамматика LogicalExpression.

добавлены 3: Ах, я понял! Двусмысленность заключается в том, что такое выражение, как

asd AND asd OR asd

можно интерпретировать двумя разными способами:

(asd AND asd) OR asd
asd AND (asd OR asd)

но как могу я это решить? Хорошо, я могу поставить один из И ИЛИ или быть сильнее другого (я все равно собирался). Но теперь я вижу, что ошибка появляется даже если есть только один оператор. Другими словами, это также приводит к той же ошибке:

LogicalExpression := "asd" | LogicalExpression "OR" LogicalExpression

в этом случае я хочу этого:

asd OR asd OR asd

разбираться на это:

(asd OR asd) OR asd

каков недвусмысленный способ сделать это?

добавлено 4: понял!

LogicalExpression1 := LogicalExpression1 "OR" LogicalExpression2 | LogicalExpression2
LogicalExpression2 := LogicalExpression2 "AND" LogicalExpression3 | LogicalExpression3
LogicalExpression3 := "NOT" LogicalExpression4 | LogicalExpression4
LogicalExpression4 := "asd" | "(" LogicalExpression1 ")"

этот анализирует все логические выражения с приоритетом оператора как не->и - >или. "asd" можно заменить выражением, предназначенным для ваших терминов.

4 ответов


ваша грамматика неоднозначна, если вы используете только один впередсмотрящим. Чтобы проиллюстрировать, что такое "АСД"? Это ExpressionTerm или более длительный срок. Это смещение-уменьшение конфликта. Я подозреваю, что и здесь конфликт сокращается.

большинство генераторов LL(1) / LALR(1) обеспечат некоторый способ борьбы с конфликтом сдвига через операторы приоритета. Большинство также по умолчанию будет иметь самую длинную последовательность при наличии конфликта shift-reduce, поэтому чаще всего их можно игнорировать (после некоторых изучение.) (В этом случае, возможно, вам нужно переместить один член вниз, чтобы он вел себя правильно).


Shift-уменьшить конфликт означает, что ваша грамматика неоднозначна. С вашим рекурсивным правилом токен " asd " может быть интерпретирован как часть любого ExpressionTerm или LogicalExpression и парсер не может решить, какой. Нужно дополнительное правило, чтобы разорвать связь.


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

if (a) then
   if (b) then
     printf('a + b');
   else
     print('this could be a + !b or !a');

оператор else может привязываться к первому или второму if. В случае неоднозначных грамматик вы обычно определяете значение, указывающее количество ожидаемых предупреждений shift-reduce в вашей грамматике.

кроме того, вы можете использовать парсер LL(k) или ll (*). Эти типы парсеров у вас нет сдвига/уменьшения двусмысленности. В зависимости от вашего приложения они могут быть проще или сложнее, чем парсер LALR(1).


грамматика неоднозначна в LL(1) или LALR(1) так как токен asd может быть заменен в ExpressionTerm и LogicalExpression сгладить правила грамматики для разрешения конфликтов shift / reduce