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