Удалить сдвиг / уменьшить конфликты с помощью точечного выражения и массивов - PullRequest
0 голосов
/ 27 сентября 2018

Извините, я новичок в зубрах.Я не понимаю проблему и как ее исправить.Я признателен, если вы сможете «научить меня ловить рыбу», указав на проблему и решение:

%left '.' '+'
%right '(' '['

%%
 OptionalExpressions
  : { $$ = nullptr; }
  | Expressions
  ;

Expressions
  : Expression
  | Expressions ',' Expression
  ;

Expression
  : Expression '+' Expression
  | ExpressionDot
  | TOKEN_ADDROF Expression
  | ExpressionIndexable
  | ExpressionFunctionCall
  | TOKEN_INTEGER
  | TOKEN_IDENTIFIER
  | '(' Expression ')'
  ;

ExpressionDot
  : Expression '.' Expression
  ;

ExpressionIndexable
  : Expression '[' Expression ']'
  ;

ExpressionFunctionCall
  : Expression '(' OptionalExpressions ')'
  ;
%%

Спасибо.

1 Ответ

0 голосов
/ 28 сентября 2018

Перед вашей следующей промысловой экспедицией вам следует внимательно прочитать раздел в руководстве по зубрам на , используя декларации предшествующих действий и, возможно, некоторые из связанных ответов SO .В руководстве Bison также есть очень полезная информация о понимании конфликтов и инструментах, которые Bison предоставляет вам.Здесь я в основном следую процедуре, описанной в последней ссылке.

Первый шаг - попросить Bison сгенерировать отчет о состояниях синтаксического анализатора, для чего просто нужно указать параметр -v (или --report=all, если вы хотите больше информации, что иногда полезно).Первая строка в результирующем файле .output сообщает вам, в каких состояниях есть конфликты сдвига / уменьшения:

State 12 conflicts: 4 shift/reduce

Итак, следующий шаг - взглянуть на состояние 12. Конфликты указываются действиями парсера вскобки;Я выделил их, чтобы сделать их более заметными.(Действия, заключенные в квадратные скобки, - это те, которые устранены зубрами с использованием алгоритма разрешения по умолчанию, также описанного в руководстве.)


    State 12

        5 Expression: Expression . '+' Expression
        7           | TOKEN_ADDROF Expression .
       13 ExpressionDot: Expression . '.' Expression
       14 ExpressionIndexable: Expression . '[' Expression ']'
       15 ExpressionFunctionCall: Expression . '(' OptionalExpressions ')'

        '.'  shift, and go to state 15
        '+'  shift, and go to state 16
        '('  shift, and go to state 17
        '['  shift, and go to state 18

<b>        '.'       [reduce using rule 7 (Expression)]</b>
<b>        '+'       [reduce using rule 7 (Expression)]</b>
<b>        '('       [reduce using rule 7 (Expression)]</b>
<b>        '['       [reduce using rule 7 (Expression)]</b>
        $default  reduce using rule 7 (Expression)

Таким образом, в этом состоянии зубр не смог применить какое-либо правило приоритета, чтобы решитьв случае, если применяется правило 7.Правило 7 удобно воспроизводится в отчете:

    7           | TOKEN_ADDROF Expression .

Приоритетом этого правила будет приоритет терминала TOKEN_ADDROF.Но этот приоритет не определен, потому что TOKEN_ADDROF не появляется ни на одном уровне приоритета.

Мы можем попытаться добавить его:

%left '.' '+'
%precedence TOKEN_ADDROF
%precedence '(' '['

И, эй presto!

Было бы справедливо спросить, почему я положил его туда, куда я его положил, и почему я использовал %precedence вместо %left или %right, как для него, так и для других унарных операторов.

Для началасо вторым вопросом %precedence означает «этот уровень приоритета включает в себя операторы, для которых конфликт не может быть разрешен с помощью ассоциативности, поэтому я не буду объявлять какую-либо конкретную ассоциативность».

И это верно в этом случае: унарные операторы не имеют ассоциативности. - в 3-4-7 может ассоциироваться слева ((3-4)-7)) или справа (3-(4-7)).Разрешение будет принято на основе Expression продукции с приоритетом - (Expression: Expression '-' Expression) и маркера предварительного просмотра с приоритетом - ( - ).Это, очевидно, может случиться.В качестве ограничения рассмотрим оператор TOKEN_ADDROF (кстати, это не & ? Если так, просто запишите его как символьный токен.) Здесь соответствующая продукция, как мы уже видели,равно

Expression: TOKEN_ADDROF Expression

Теперь, что, если жетон предвкушения равен TOKEN_ADDROF?Ответ: это синтаксическая ошибка, потому что TOKEN_ADDROF не является двоичным оператором, поэтому он не может следовать за выражением.(Может случиться так, что у вас есть бинарный оператор с таким же написанием. Но в этом случае вы бы положили %prec UNOP на вышеупомянутую продукцию, и тогда не было бы никакой возможности, чтобы маркер предпросмотра мог быть UNOP, потому что этотокен никогда не создается лексическим сканером.) Таким образом, не существует производства, которое допускает сдвиг и, следовательно, никакого конфликта.

Аналогичная аргументация применима к постфиксным операторам, таким как приложение функций и подписка.(И после увеличения и после уменьшения, если применимо.) В этих случаях возможен следующий постфиксный оператор, но он не может быть сдвинут до тех пор, пока производство Expression POSTFIX не будет уменьшено.Опять же, никакого возможного конфликта нет.

Так что в случае постфиксных операторов единственное сравнение приоритетов будет между уровнями, а не с уровнем, и ассоциативность не применяется.Если вы не укажете ассоциативность, бизон выдаст предупреждение о конфликте, если вы случайно ошибочно наберете грамматику таким образом, чтобы разрешить ассоциативность (например, не вставив объявление %prec UNOP там, где это необходимо), вместо того, чтобы молча игнорировать ошибку.

В этой конкретной грамматике указание '[' и '(' на уровне приоритета не требуется, так как эти токены не используются напрямую в любом Expression производстве.Это означает, что грамматика обеспечивает явный приоритет для этих операторов.Использование как деклараций предшествования, так и явного приоритета в одной и той же грамматике часто является признаком того, что различные части грамматики были скопированы и вставлены из разных источников.(Просто говорю.) Обычно это не считается хорошим стилем, хотя иногда это оправдано.В этом случае я бы предложил использовать явный или объявленный приоритет явно.

Итак, давайте предположим, что уровни приоритета должны быть объявлены.В таком случае, почему я поставил постфиксные операторы в конце?Ответ: потому что это общее правило (хотя и не абсолютное правило), что постфиксные операции связываются более тесно, чем префиксные операции.Например, -arr[i] означает , а не означает (-arr)[i].Это так очевидно, что большинство людей не думают об этом, хотя иногда им не удастся применить правило к *arr[i] и *arr++, которые имеют точно такие же отношения предшествования.

Надеюсь, это поможет.

...