yacc 中的关联和优先级声明是否解决了语法歧义的问题?

Does association and precedence declarations in yacc solve the issues of an ambiguous grammar?

举例来说,我们有以下不明确的语法:

expr -> expr OP expr

表达式 -> ( 表达式 )

表达式 -> NUM

OP -> +

OP -> -

OP -> *

OP -> /

声明到底是什么

%left + -

%left * /

在 yacc 中做什么?它们会帮助解析器解决歧义问题而无需更改语法吗?

yacc 优先指令允许程序员以有限的方式指定如何解决语法中的 shift/reduce 冲突。准确了解它们的工作原理(以及它们如何实现“正常”优先级规则)需要对 shift/reduce 解析的工作原理有相当好的了解。

在高层次上,shift/reduce 解析通过识别与输入中规则的 RHS 相对应的模式并将这些模式“替换”为表示规则的 LHS 的符号来工作。目标是最终用与语法的顶级符号匹配的单个符号替换整个输入。更详细地说,当它看到输入的每个符号时,它要么移动该符号(读取它并将其压入堆栈),要么减少规则——从堆栈中取出与规则的 RHS 匹配的符号并将它们替换为LHS 的单个符号。在此过程中的任何一步,如果堆栈顶部的符号与任何规则的 RHS 匹配,则解析器可以移动或减少——决定要做什么基本上是 yacc 所做的解析器构造的全部工作。当它无法决定(从语法)时,它会报告 shift/reduce 冲突。 (当堆栈顶部与两个不同规则的 RHS 匹配时,也会发生 reduce/reduce 冲突)。

优先规则的工作方式是提供一种解决这些移位减少冲突的编程方式——程序员可以为令牌和规则提供“优先级别”,并且每当 shift/reduce 冲突发生时,如果两者所涉及的令牌和规则具有优先级,冲突将以优先级更高的规则解决。

当您使用 %left/%right 指令时,它会设置标记的优先级别。规则的优先级来自规则 RHS 中的第一个标记或来自显式 %prec 指令。

根据你上面的语法,标记可以有一个很好的优先级,但是 expr: expr OP expr 规则有问题。由于它在 RHS 上没有标记(只是非终端),因此无法获得优先级,因此您需要使用 %prec 给出优先级,但这也不起作用,因为没有单个优先考虑此规则。

如果您将规则拆分为多个规则(摆脱 OP 并为每个运算符设置一个单独的规则)那么事情就可以了,因为每个规则可以有不同的优先级。