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

问题描述

例如,我们有以下歧义语法:

expr -> expr OP expr

expr -> ( expr )

表达式 -> NUM

OP -> +

OP -> -

OP -> *

OP -> /

声明究竟是什么

%left + -

%left * /

在 yacc 中做什么?它们会帮助解析器在不改变语法的情况下解决歧义问题吗?

解决方法

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

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

优先规则的工作方式是提供一种解决这些 shift-reduce 冲突的编程方式——程序员可以为标记和规则以及每当发生 shift/reduce 冲突时提供“优先级”,如果标记和所涉及的规则具有优先级,冲突将有利于具有更高优先级的规则解决。

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

使用上面的语法,标记可以具有优先级,但 expr: expr OP expr 规则存在问题。由于它在 RHS 上没有标记(只是非终端),因此无法以这种方式获得优先级,因此您需要使用 %prec 提供优先级,但这也不起作用,因为没有单个优先考虑这条规则。

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