2009-10-03 5 views
3

Первоначально в примере была этазубр сдвиг/свертка проблему перемещения добавить цит в subexpr

expr: 
     INTEGER 
     | expr '+' expr   { $$ = $1 + $3; } 
     | expr '-' expr   { $$ = $1 - $3; } 
     ; 

Я хотел, чтобы быть «более простой», так что я написал это (я понимаю, что это будет делать «+» как для добавления, так и для вычитания. Но это пример)

expr: 
     INTEGER 
     | expr addOp expr   { $$ = $1 + $3; } 
     ; 

addOp: 
      '+' { $$ = $1; } 
     | '-' { $$ = $1; } 
     ; 

Теперь я получаю ошибку сдвига/уменьшения. Это должно быть то же самое -_- (для меня). Что мне нужно сделать, чтобы исправить это?

Редактировать: Чтобы все было ясно. В первом случае нет предупреждений/ошибок. Я использую% left, чтобы установить приоритет (и я буду использовать% right for = и другие права ops). Однако, похоже, это не применяется при переходе в подвыражения.

+0

Shift/уменьшить конфликты являются нормальными, но это правило, которое является одновременно левым и правым рекурсивным не соответствует Yacc парсеру конструкцию скважины и является излишне сложным.Если вы оставите его рекурсивным, он будет работать лучше и не будет конфликтов. См. 'Q4.y' ниже. – DigitalRoss

+0

Как вторая заметка, ваша вторая версия не делает то, что вы думаете. Он вернет «4» для «2 - 2». –

+0

Кроме того, '{$$ = $ 1; } 'rule неявно - вам нужно только выписать правила, если это что-то другое. –

ответ

1

Вы уверены, что конфликты связаны только с этими двумя правилами? Первый должен иметь больше конфликтов, чем второй. По крайней мере, с одним символом взгляда на будущее решение перейти в состояние с addOp на стек легче во второй раз.

Update (я считаю, что могу доказать свою теорию ... :-):

$ cat q2.y 
%% expr: '1' | expr '+' expr | expr '-' expr; 
$ cat q3.y 
%% expr: '1' | expr addOp expr; 
    addOp: '+' | '-'; 
$ yacc q2.y 
conflicts: 4 shift/reduce 
$ yacc q3.y 
conflicts: 2 shift/reduce 

Сказав все, что, это нормально для Yacc грамматик иметь неясностей, и любой вещественно у системы жизнеобеспечения, вероятно, будет не только несколько, но и буквально десятков конфликтов смены/уменьшения. По определению этот конфликт возникает, когда имеется совершенно допустимый сдвиг, поэтому, если вы не против, чтобы парсер принимал этот сдвиг, тогда не беспокойтесь об этом.

Теперь, в yacc, вы должны предпочесть леворекурсивные правила. Вы можете добиться того, что и не избавиться от грамматической неоднозначности с:

$ cat q4.y 
%% expr: expr addOp '1' | '1'; 
    addOp: '+' | '-'; 
$ yacc q4.y 
$ 

Примечание: никаких конфликтов в приведенном выше примере. Если вам нравится ваша грамматика, как она есть, просто сделать:

%expect 2 
%% expr: '1' | expr addOp expr; 
    addOp: '+' | '-'; 
+0

Я использовал% left '-' '+', чтобы у первого не было правила сдвига/уменьшения. Во-вторых, он, похоже, не применяется, какой тип отстой, и я понятия не имею, как сделать его применимым (% left addOp не работает, поскольку он не является токеном) – 2009-10-03 20:14:53

+0

Думаю, я рекомендовал бы вам изменить свою грамматику, q4.y'. – DigitalRoss

1

Проблема заключается в том, что правило

expr: expr addOp expr { ..action.. } 

не имеет приоритета. Обычно правила получают приоритет первого токена в RHS, но это правило не имеет токенов на его RHS. Вам необходимо добавить директиву% prec:

expr: expr addOp expr %prec '+' { ..action.. } 

, чтобы явно дать правилу преимущество.

Обратите внимание, что это не избавляет от конфликта shift/reduce, который присутствовал в вашей оригинальной грамматике. Он просто решает его в соответствии с указанными вами правилами приоритета, а это значит, что бизон не даст вам сообщение об этом. В общем случае использование приоритета для разрешения конфликтов может быть сложным, поскольку оно может скрывать конфликты, которые вы, возможно, хотели бы решить по-другому или могли бы быть неразрешимы в вашей грамматике, как написано.

Также см моего ответа на вопрос this

+0

Я бы зашел так далеко, чтобы группировать '+' и '-' под тем же токеном в lexer, но это может быть не предпочтительнее некоторых. Он работает в любом случае. –