Сообщение об ошибке, которое вы видели, указывает на то, что в вашем файле есть 73 конфликта сдвига / уменьшения, а не на конфликте сдвига / уменьшения в строке 73. (Конфликты сдвига / уменьшения соответствуют состояниям синтаксического анализатора, а не номерам строк.можно определить, где находятся конфликты, путем создания файла отчета с параметром командной строки -v
.
Из этих конфликтов 72 являются результатом простой опечатки.Ваша грамматика использует имена токенов NE
, GE
и LE
в производствах для Expr
, но ваши объявления приоритетов предназначены для токенов NEQ
, GEQ
и LEQ
.Это выдает предупреждение о неиспользованных токенах.(Также не используются STAR
и RESERVED
. Полагаю, вы случайно пропустили правило Expr
для умножения.)
Остальной конфликт находится в состоянии 45, элементы которого (из файла отчета):
State 45
7 VarDeclaration: ID . auxVarSpec Type
29 Statement: ID . ASSIGN Expr
43 ParseArgs: ID . COMMA BLANKID ASSIGN PARSEINT LPAR CMDARGS LSQ Expr RSQ RPAR
44 FuncInvocation: ID . LPAR opcFuncInvocation RPAR
(Номера, прикрепленные к каждому производству, являются номером производства, а не номером строки. Производственные номера находятся в верхней части файла отчета, но, поскольку производство также указано в списке, они не имеютЗдесь нет большой разницы. .
в каждом производстве указывает точку просмотра. Производства с точкой ожидания в начале не показаны, если вы не укажете --report=itemset
)
Конфликт сthe lookahead COMMA
:
COMMA shift, and go to state 68
COMMA [reduce using rule 9 (auxVarSpec)]
Таким образом, в этом состоянии запятая может быть либо сдвинута, чтобы продолжить производство 43. Или она может вызвать уменьшение, используя правило 9 (auxVarSpec: %empty
).Это сокращение возможно, потому что есть элемент с auxVarSpec
в качестве следующего нетерминала, и auxVarSpec
начинается с запятой, если она не пустая.
Чтобы быть более ясным, проблема в том, что всписок VarsAndStatements
, может быть VarDeclaration
(который является объявлением), но также может быть ParseArgs
(который является утверждением).Так что ParseArgs
и VarDeclaration
оба возможны, и оба они могут начинаться с ID COMMA
, но для одного из них необходимо уменьшить пустую правую часть между ID
и COMMA
.
Этот конфликт не может быть разрешен без дополнительного маркера упреждения: если за запятой следует еще один ID
, то синтаксический анализатор смотрит на VarDeclaration
, тогда как, если после запятой следует BLANKID
(независимо от того, чтоis), тогда это должно быть ParseArgs
.
Хотя конфликт не может быть разрешен в письменном виде, его можно избежать с помощью обычной техники отсрочки принятия решения о сдвиге / уменьшении.В частности, необходимо различать три случая:
ID Type /* VarDeclaration */
ID COMMA ID ... /* VarDeclaration */
ID COMMA BLANKID ... /* ParseArgs */
Один из способов сделать это - добавить явно избыточное производство:
VarDeclaration: VAR VarSpec
| ID Type
| ID COMMA ID auxVarSpec Type