Compiler construction 解决yacc中的reduce/reduce冲突

Compiler construction 解决yacc中的reduce/reduce冲突,compiler-construction,yacc,reduce,Compiler Construction,Yacc,Reduce,我想知道如何解决reduce/reduce冲突,而不必排成百行。这条规则在右值和右值之间的每个标记上都有冲突。。。“右值令牌右值” r值 :“('rvalue')” |左值 |文字的 |左值赋值右值 |左值公司 |左值公司 |“-”右值 | '!' 右值 |“~”右值 |“&”左值 |右值“|”右值 |右值“^”右值 |右值“&”右值 |右值右移 |右值左移位右值 |右值比较右值 |右值分流右值 |右值“”右值 |右值 |右值'-'右值 |右值'+'右值 |右值“%”右值 |右值'*'右值 |右

我想知道如何解决reduce/reduce冲突,而不必排成百行。这条规则在右值和右值之间的每个标记上都有冲突。。。“右值令牌右值”

r值
:“('rvalue')”
|左值
|文字的
|左值赋值右值
|左值公司
|左值公司
|“-”右值
| '!' 右值
|“~”右值
|“&”左值
|右值“|”右值
|右值“^”右值
|右值“&”右值
|右值右移
|右值左移位右值
|右值比较右值
|右值分流右值
|右值“”右值
|右值
|右值'-'右值
|右值'+'右值
|右值“%”右值
|右值'*'右值
|右值“/”右值
|右值“?”右值“:”右值
|右值'('')'
|右值'('rvalue rvalues')'
;

感谢您的帮助…

首先,使用yacc的
-v
选项生成一个y.output,显示语法的所有状态和冲突。这将向您显示在您看到的移位/减少和减少/减少冲突中涉及哪些规则

其次,您的语法片段不完整,因为它缺少除
rvalue
之外的所有非终结符的规则。您发布的片段本身没有任何reduce/reduce冲突(尽管它确实有大量的shift/reduce冲突,这是由于左/右/过程冲突)。可以通过为令牌添加适当的优先级规则(%left/%right声明)或将规则拆分为多个优先级规则来解决这些问题

我怀疑你也有一个规则,比如
rvalues:rvalue | rvalues rvalue当与上述规则结合使用时,会导致大量reduce/reduce冲突。这些冲突也是优先级歧义,但由于
rvalues
规则中没有标记(其顺序中只有一个或多个rvalues,没有中间标记),因此无法通过yacc优先级规则解决,但可以通过将规则拆分为优先级级别来解决

如果您需要更具体的帮助,您需要发布更多语法(至少是
rvalues
规则)

编辑

要避免中缀/前缀运算符之间的歧义导致的reduce/reduce冲突,并允许连续表达式没有中间标记,通常的方法是将表达式规则分为两个版本——一个以有问题的前缀运算符开头,另一个不以有问题的前缀运算符开头。然后,在一个表达式紧跟在另一个表达式后面且没有中间标记的上下文中,只使用第二条规则而不是一般规则。在你的情况下,这会给你一些类似的东西:

rvalue_noprefix
    : '(' rvalue ')'
    | lvalue
    | literal
    | lvalue assign rvalue
    | inc_dec lvalue
    | lvalue inc_dec
    | '!' rvalue
    | '~' rvalue
    | rvalue_noprefix '|' rvalue
    | rvalue_noprefix '^' rvalue
    | rvalue_noprefix '&' rvalue
    | rvalue_noprefix RIGHT_SHIFT rvalue
    | rvalue_noprefix LEFT_SHIFT rvalue
    | rvalue_noprefix COMPARE rvalue
    | rvalue_noprefix DIFF rvalue
    | rvalue_noprefix '<' rvalue
    | rvalue_noprefix LE rvalue
    | rvalue_noprefix '>' rvalue
    | rvalue_noprefix GE rvalue
    | rvalue_noprefix '-' rvalue
    | rvalue_noprefix '+' rvalue
    | rvalue_noprefix '%' rvalue
    | rvalue_noprefix '*' rvalue
    | rvalue_noprefix '/' rvalue
    | rvalue_noprefix '?' rvalue ':' rvalue
    | rvalue_noprefix '(' ')'
    | rvalue_noprefix '(' rvalue rvalues ')'
;

rvalue_prefix
    : '-' rvalue
    | '&' lvalue
    | rvalue_prefix '|' rvalue
    | rvalue_prefix '^' rvalue
    | rvalue_prefix '&' rvalue
    | rvalue_prefix RIGHT_SHIFT rvalue
    | rvalue_prefix LEFT_SHIFT rvalue
    | rvalue_prefix COMPARE rvalue
    | rvalue_prefix DIFF rvalue
    | rvalue_prefix '<' rvalue
    | rvalue_prefix LE rvalue
    | rvalue_prefix '>' rvalue
    | rvalue_prefix GE rvalue
    | rvalue_prefix '-' rvalue
    | rvalue_prefix '+' rvalue
    | rvalue_prefix '%' rvalue
    | rvalue_prefix '*' rvalue
    | rvalue_prefix '/' rvalue
    | rvalue_prefix '?' rvalue ':' rvalue
    | rvalue_prefix '(' ')'
    | rvalue_prefix '(' rvalue rvalues ')'
;

rvalue: rvalue_prefix | rvalue_noprefix ;
rvalue\u noprefix
:“('rvalue')”
|左值
|文字的
|左值赋值右值
|左值公司
|左值公司
| '!' 右值
|“~”右值
|右值
|右值
|右值
|右值\u非右移位\u右值
|右值\u非左移\u右值
|右值\u noprefix比较右值
|右值
|右值\u noprefix“”右值
|右值
|右值\u noprefix'-'右值
|右值\u noprefix'+'右值
|右值\u noprefix“%”右值
|右值\u noprefix'*'右值
|右值\u noprefix'/'右值
|右值“?“右值”:“右值”
|右值“('')”
|右值“(“右值右值”)”
;
右值前缀
:“-”右值
|“&”左值
|右值前缀“|”右值
|右值\前缀“^”右值
|右值前缀“&”右值
|右值前缀右移右值
|右值前缀左移右值
|右值\前缀比较右值
|右值前缀DIFF右值
|右值前缀“”右值
|右值前缀GE右值
|右值前缀'-'右值
|右值前缀“+”右值
|右值\前缀“%”右值
|右值\前缀'*'右值
|右值前缀“/”右值
|右值前缀“?”右值“:”右值
|右值前缀'('')
|右值前缀“(“右值右值”)”
;
rvalue:rvalue_前缀| rvalue_noprefix;
您可以理解为
rvalue\u prefix
匹配以前缀
&
-
运算符开头的所有不同
rvalue
表达式,而
rvalue\u nonrefix
匹配所有其他表达式。然后,当您有一个连续
rvalue
的上下文时,您将以下所有
rvalue
s更改为
rvalue\u nonprefix
,因为在该上下文中,任何看起来像是以
-
&
开头的内容都应该与前面的
rvalue
作为中缀运算符组合

这是语法规模的大幅增长(所有中缀运算符都被复制),但这绝不是“数百条附加规则”。特别是,无论有多少不同的不明确前缀/中缀运算符,您只需要一次拆分。如果您还有不明确的后缀/中缀运算符,则需要添加拆分(再次复制所有内容),但您的示例似乎没有该问题。

68:减少/减少冲突(减少75,减少76)在'?'68:减少/减少冲突(减少75,减少76)在':'68:减少/减少冲突(减少75,减少76)关于“|”68:减少/减少冲突(减少75,减少76)关于“^”68:减少/重新
rvalue_noprefix
    : '(' rvalue ')'
    | lvalue
    | literal
    | lvalue assign rvalue
    | inc_dec lvalue
    | lvalue inc_dec
    | '!' rvalue
    | '~' rvalue
    | rvalue_noprefix '|' rvalue
    | rvalue_noprefix '^' rvalue
    | rvalue_noprefix '&' rvalue
    | rvalue_noprefix RIGHT_SHIFT rvalue
    | rvalue_noprefix LEFT_SHIFT rvalue
    | rvalue_noprefix COMPARE rvalue
    | rvalue_noprefix DIFF rvalue
    | rvalue_noprefix '<' rvalue
    | rvalue_noprefix LE rvalue
    | rvalue_noprefix '>' rvalue
    | rvalue_noprefix GE rvalue
    | rvalue_noprefix '-' rvalue
    | rvalue_noprefix '+' rvalue
    | rvalue_noprefix '%' rvalue
    | rvalue_noprefix '*' rvalue
    | rvalue_noprefix '/' rvalue
    | rvalue_noprefix '?' rvalue ':' rvalue
    | rvalue_noprefix '(' ')'
    | rvalue_noprefix '(' rvalue rvalues ')'
;

rvalue_prefix
    : '-' rvalue
    | '&' lvalue
    | rvalue_prefix '|' rvalue
    | rvalue_prefix '^' rvalue
    | rvalue_prefix '&' rvalue
    | rvalue_prefix RIGHT_SHIFT rvalue
    | rvalue_prefix LEFT_SHIFT rvalue
    | rvalue_prefix COMPARE rvalue
    | rvalue_prefix DIFF rvalue
    | rvalue_prefix '<' rvalue
    | rvalue_prefix LE rvalue
    | rvalue_prefix '>' rvalue
    | rvalue_prefix GE rvalue
    | rvalue_prefix '-' rvalue
    | rvalue_prefix '+' rvalue
    | rvalue_prefix '%' rvalue
    | rvalue_prefix '*' rvalue
    | rvalue_prefix '/' rvalue
    | rvalue_prefix '?' rvalue ':' rvalue
    | rvalue_prefix '(' ')'
    | rvalue_prefix '(' rvalue rvalues ')'
;

rvalue: rvalue_prefix | rvalue_noprefix ;