Как исправить yacc shift / уменьшить конфликты от оператора post-increment?
Я пишу грамматику в YACC (на самом деле Bison), и у меня проблема сдвига/уменьшения. Это происходит из-за включения постфиксных операторов инкремента и декремента. Вот сокращенная версия грамматики:
%token NUMBER ID INC DEC
%left '+' '-'
%left '*' '/'
%right PREINC
%left POSTINC
%%
expr: NUMBER
| ID
| expr '+' expr
| expr '-' expr
| expr '*' expr
| expr '/' expr
| INC expr %prec PREINC
| DEC expr %prec PREINC
| expr INC %prec POSTINC
| expr DEC %prec POSTINC
| '(' expr ')'
;
%%
Зубр говорит мне, что есть 12 конфликтов shift/reduce, но если я комментирую строки для постфиксного приращения и уменьшения, он работает нормально. Кто-нибудь знает, как исправить этот конфликт? На данный момент я рассматриваю возможность перехода к генератору парсера LL(k, что делает это намного проще, но грамматики LALR всегда казались гораздо более естественными для написания. Я также рассматриваю GLR, но я не знаю никаких хороших генераторов синтаксического анализатора C/C++ GLR.
5 ответов
попробуйте это:
%token NUMBER ID INC DEC
%left '+' '-'
%left '*' '/'
%nonassoc '++' '--'
%left '('
%%
expr: NUMBER
| ID
| expr '+' expr
| expr '-' expr
| expr '*' expr
| expr '/' expr
| '++' expr
| '--' expr
| expr '++'
| expr '--'
| '(' expr ')'
;
%%
ключ должен объявить операторы postfix как номера ассоциативные. В противном случае вы смогли бы
++var++--
скобки также должны иметь приоритет, чтобы минимизировать смещение / уменьшить предупреждения
Мне нравится определять больше элементов. Вам не нужен материал %left, %right, %prec.
simple_expr: NUMBER
| INC simple_expr
| DEC simple_expr
| '(' expr ')'
;
term: simple_expr
| term '*' simple_expr
| term '/' simple_expr
;
expr: term
| expr '+' term
| expr '-' term
;
поиграйте с этим подходом.
эта основная проблема заключается в том, что у вас нет приоритета для INC
и DEC
токены, поэтому он не знает, как разрешить двусмысленности, связанные с lookahead INC
или DEC
. Если добавить
%right INC DEC
в конце списка приоритетов (вы хотите, чтобы унарные были выше приоритета и постфикс выше префикса), он исправит это, и вы даже можете избавиться от всех PREINC
/POSTINC
вещи, как это не имеет значения.
операторы preincrement и postincrement имеют nonassoc, поэтому определите, что в разделе приоритета и в правилах сделайте приоритет этих операторов высоким, используя %prec