我有以下yacc / bison / happy语法:
%token
if TokenIf
then TokenThen
else TokenElse
true TokenTrue
false TokenFalse
%left APP
%right IF
%%
Hungry
: NoHungry
| Hungry NoHungry %prec APP
| if Hungry then Hungry else Hungry %prec IF
NoHungry
: true
| false
bison -v
告诉我在以下情况下有两个冲突:
State 12
2 Hungry: Hungry . NoHungry
3 | if Hungry then Hungry else Hungry .
true shift, and go to state 2
false shift, and go to state 3
true [reduce using rule 3 (Hungry)]
false [reduce using rule 3 (Hungry)]
$default reduce using rule 3 (Hungry)
NoHungry go to state 8
我尝试通过 %prec
给出明确的优先声明来解决冲突,但无济于事 . 鉴于野牛解决了所谓的冲突(例如转移而不是减少),这并不是那么糟糕,但我想知道如何在不改变公认语言的情况下摆脱冲突 .
1 回答
从野牛报告中可以看出,冲突与终端
true
和false
有冲突,这些终端未在优先关系中列出 . 因此,优先规则不适用于这些冲突 .回想一下,在 生产环境 和终端之间定义了优先关系 . 它不涉及两个终端或两个产品(因此不能用于解决减少 - 减少冲突) . 可以减少的 生产环境 优先级与先行终端之间的比较确定是否会发生减少或转移 . 为方便起见,制作由终端名称表示,通常是制作中唯一的终端;这对应于一个常见的用例,但有时令人困惑 . 特别是,
%prec
声明仅用于为规则提供在优先声明中使用的名称,并且最好以这种方式而不是"explicit"声明来考虑它 .简而言之,通过在优先关系中明确添加适当的终端,可以解决问题中简化语法的冲突:
摘自
-v
输出:通过使用
-r solved
而不是-v
,您可以更明确地看到分辨率:我本可以使用
"else"
作为if
生产环境 的名称,如果没有%prec
声明,它将是默认值,但"if"
似乎更直观 .%precedence
声明(最近的野牛版本中提供)并不意味着左右相关性;在这种情况下,关联性不适用,因为不存在冲突涉及具有相同优先级的 生产环境 和终端的情况 . 如果Happy没有实现它,可以使用%left
或%right
出于同样的原因(关联性无关紧要)但我认为%precedence
更好地记录了这种情况 .由于这无疑是一个简化的例子,值得注意的是更完整的语法需要一些语法分析 . 特别是,优先级大于
"if"
的终端列表必须包含FIRST(NoHungry)
中的所有终端,并且bison不提供执行该计算的自动工具,尽管您通常可以从shift-reduce冲突报告中提取列表 . (甚至可能是"if"
是集合的一部分,在这种情况下,关联性很重要 . )