Устранение ошибок сдвига / уменьшения для бинарных операций - PullRequest
1 голос
/ 23 ноября 2011

fsyacc испускает ошибки сдвига / уменьшения для всех двоичных операций.

У меня есть это рекурсивное производство:

scalar_expr:
    | scalar_expr binary_op scalar_expr { Binary($2, $1, $3) }

Изменение на

scalar_expr:
    | constant binary_op constant { Binary($2, Constant($1), Constant($3)) }

устраняет ошибки (но не то, что я хочу). Старшинство и ассоциативность определяются следующим образом:

%left BITAND BITOR BITXOR
%left ADD SUB
%left MUL DIV MOD

Вот выдержка из файла листинга, показывающая состояние, которое вызывает ошибки (одно другое состояние имеет такие же ошибки).

state 42:
  items:
    scalar_expr -> scalar_expr . binary_op scalar_expr
    scalar_expr -> scalar_expr binary_op scalar_expr . 

  actions:
    action 'EOF' (noprec):   reduce scalar_expr --> scalar_expr binary_op scalar_expr
    action 'MUL' (explicit left 9999):   shift 8
    action 'DIV' (explicit left 9999):   shift 9
    action 'MOD' (explicit left 9999):   shift 10
    action 'ADD' (explicit left 9998):   shift 6
    action 'SUB' (explicit left 9998):   shift 7
    action 'BITAND' (explicit left 9997):   shift 11
    action 'BITOR' (explicit left 9997):   shift 12
    action 'BITXOR' (explicit left 9997):   shift 13

Вы можете видеть сдвиги парсера во всех случаях, что, я думаю, правильно. Я не нашел случая, когда поведение, по крайней мере, некорректное.

Как я могу переформулировать грамматику, чтобы устранить эти ошибки?

Ответы [ 2 ]

1 голос
/ 16 ноября 2012

Как указал Стивен в своем ответе, правила приоритета для ваших операторов не будут применяться, если вы перенесете их в отдельное производство. Это странно, так как состояние, которое вы опубликовали, похоже, правильно их соблюдает.

Однако вы должны иметь возможность декларировать и применять явные правила приоритета, например, Вы можете определить их как:

%left ADD_SUB_OP
%left MUL_DIV_OP

и примените их следующим образом:

scalar_expr:
    | scalar_expr add_sub_ops scalar_expr %prec ADD_SUB_OP { Binary($2, $1, $3) }
    | scalar_expr mul_div_ops scalar_expr %prec MUL_DIV_OP { Binary($2, $1, $3) }

Таким образом, вам все еще нужно определить несколько правил, но вы можете сгруппировать все операторы с одинаковым приоритетом в группу (обратите внимание, что выбранные мной имена являются плохим примером; вы можете использовать имена, которые отражают приоритет или описывают операторы внутри так понятно что они указывают).

Полагаю, стоит ли это решение, зависит от количества операторов в группе, я полагаю.

1 голос
/ 23 ноября 2011

Является ли binary_op на самом деле производством, то есть у вас есть что-то вроде:

binary_op:
   | ADD { OpDU.Add }
   | SUB { OpDU.Sub }
   ...

Если это так, я думаю, что это проблема, поскольку я предполагаю, что определенные вами правила приоритета не будут соблюдаться в constant binary_op constant. Вам нужно явно перечислить каждый шаблон scalar_expr, например,

scalar_expr:
    | scalar_expr ADD scalar_expr { Binary(OpDU.Add, $1, $3) }
    | scalar_expr SUB scalar_expr { Binary(OpDU.Sub, $1, $3) }
    ...

(я не думаю, что есть какой-либо способ отвлечь эту повторяемость с помощью FsYacc)

...