Вот значительно упрощенная (но полная) выдержка из вашей грамматики. Я объявил expression
терминалом, чтобы избежать его определения:
%token expression IF
%%
sentence : sentComposed
|sentSelection
|sentExpression
sentComposed: sentenceList
sentenceList: sentence
|sentenceList sentence
sentExpression: expression ';'
|';'
sentSelection: IF '(' expression ')' sentence
Когда я запускаю его через бизона, он сообщает:
ez.y: warning: 4 shift/reduce conflicts [-Wconflicts-sr]
ez.y: warning: 8 reduce/reduce conflicts [-Wconflicts-rr]
Эти конфликтыявляются реальной проблемой, о чем свидетельствуют следующие предупреждения («из-за конфликтов»):
ez.y:8.18-38: warning: rule useless in parser due to conflicts [-Wother]
|sentenceList sentence
^^^^^^^^^^^^^^^^^^^^^
ez.y:11.18-47: warning: rule useless in parser due to conflicts [-Wother]
sentSelection: IF '(' expression ')' sentence
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Когда бизон обнаруживает конфликт в грамматике, он разрешает его в соответствии с простой процедурой:
- конфликты уменьшения-уменьшения разрешаются в пользу сдвига
- конфликты уменьшения-уменьшения разрешаются в пользу производства, которое происходит раньше в грамматике.
Один разэто делает это, может оказаться, что какое-то производство больше не может быть использовано, потому что оно было исключено из каждого контекста, в котором оно могло быть сокращено. Это явный признак того, что грамматика проблематична. [Примечание 1]
Основная проблема здесь заключается в том, что sentComposed
означает, что операторы можно просто соединить вместе, чтобы сделать более длинный оператор. Итак, что произойдет, если вы напишите:
IF (e) statement1 statement2
Может случиться так, что statement1 statement2
предназначен для сокращения в один sentComposed
, который является целью IF
, поэтому два оператора выполняются толькоесли e
верно. Или может быть, что sentComposed
состоит из оператора IF
с целью statement1
, за которой следует statement2
. В терминах C разница между:
if (e) { statement1; statement2; }
и
{ if (e) { statement1; } statement2; }
Так что это реальная двусмысленность, и вам, вероятно, нужно переосмыслить отсутствие скобок, чтобы исправить это.
Но это не единственная проблема;у вас также есть куча уменьшающих-уменьшающих конфликтов. Это происходит гораздо проще, потому что часть вышеуказанной грамматики представляет собой следующий цикл:
sentence: sentComposed
sentComposed: sentenceList
sentenceList: sentence
Этот цикл означает, что ваша грамматика позволяет обернуть одну sentence
в произвольное число единицсокращения. Вы, конечно, не хотели этого;Я уверен, что вы намеревались использовать sentComposed
только в случае необходимости. Но бизон не знает твоих намерений;он знает только то, что вы говорите.
Опять же, вы, вероятно, решите эту проблему, когда выясните, как на самом деле вы хотите определить границы sentComposed
.
Примечания:
В некоторых случаях конфликты на самом деле не являются проблемой. Например, существует конфликт сдвига-уменьшения между этими двумя производствами;так называемая неопределенность «висящего другого»:
sentSelection: IF '(' expression ')' sentence
|IF '(' expression ')' sentence ELSE sentence
В вложенном выражении IF
:
IF (e) IF (f) s1 ELSE s2
неясно, должно ли ELSE
применяться к внутреннемуили внешний IF
. Если это относится к внутреннему IF
, его необходимо сместить, чтобы разрешить второе производство для sentSelection
. Если это относится к внешнему IF
, сначала необходимо выполнить сокращение, чтобы завершить внутреннее (иначе говоря) IF
, прежде чем перевести ELSE
во внешнее IF
. Действие Бизона по умолчанию («предпочесть смещение») в этом случае делает совершенно правильно, то есть немедленно сдвигает ELSE
. (Действительно, именно поэтому по умолчанию было выбрано «предпочитать смещение»).