Предупреждение: "правило бесполезно в парсере из-за конфликтов" в Bison - PullRequest
0 голосов
/ 20 октября 2019

Я пытаюсь создать лексический анализатор C и у меня есть несколько предупреждений:

rule useless in parser due to conflicts: sentenceList: sentenceList sentence
rule useless in parser due to conflicts: sentSelection: IF '(' expression ')' sentence
rule useless in parser due to conflicts: sentSelection: IF '(' expression ')' sentence ELSE sentence
rule useless in parser due to conflicts: sentSelection: SWITCH '(' expression ')' sentence
rule useless in parser due to conflicts: sentIteration: WHILE '(' expression ')' sentence
rule useless in parser due to conflicts: sentIteration: FOR '(' expression ';' expression ';' expression ')' sentence

Это часть кода, откуда приходят предупреждения:

input:    /* nothing */
        | input line
;

line:     '\n'
        | sentence '\n' 
;
sentence :       sentComposed
                |sentSelection
                |sentExpression
                |sentIteration
;

sentComposed:     statementsList
                 |sentenceList
;

statementsList:      statement
                   | statementsList statement
;

sentenceList:    sentence
                |sentenceList sentence
;

sentExpression: expression ';'
              |';'
;

sentSelection: IF '(' expression ')' sentence
              |IF '(' expression ')' sentence ELSE sentence
              |SWITCH '(' expression ')' sentence
;

sentIteration: WHILE '(' expression ')' sentence
              |DO sentence WHILE '(' expression ')' ';' 
              |FOR '(' expression ';' expression ';' expression ')' sentence
;

statement: DATATYPE varList                
;

varList:     aVar
            |varList ',' aVar
;

aVar:     variable inicial                           
;

variable: IDENTIFIER                                 
;

initial: '=' NUM                                         
;

Iтолько что добавили еще немного информации Каждое слово в заглавных буквах - токены. Если вам нужна дополнительная информация, пожалуйста, скажите мне

1 Ответ

0 голосов
/ 20 октября 2019

Вот значительно упрощенная (но полная) выдержка из вашей грамматики. Я объявил 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.

Примечания:

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

    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. (Действительно, именно поэтому по умолчанию было выбрано «предпочитать смещение»).

...