解决yacc中的减少/减少冲突

时间:2014-04-08 18:06:13

标签: compiler-construction yacc reduce

我想知道如何在不制作数百行的情况下解决减少/减少冲突的问题。此规则在rvalue ...“rvalue token rvalue”之间的每个令牌上都会发生冲突。

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

感谢您的帮助......

1 个答案:

答案 0 :(得分:1)

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

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

我怀疑你也有像rvalues: rvalue | rvalues rvalue ;这样的规则,当与上面的规则相结合时,会导致大量的减少/减少冲突。这些冲突也是优先模糊,但由于rvalues规则中没有令牌(它只是一个或多个rvalues顺序,没有中间令牌),它不能通过yacc优先级规则解决,但可以解决将规则划分为优先级。

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

修改

避免从中缀/前缀运算符之间的歧义中获得的减少/减少冲突以及允许没有中间令牌的连续表达式的一般方法是将表达式规则拆分为两个版本 - 一个以有问题的前缀运算符开头(s)和没有的。然后,在表达式紧跟另一个表达式而没有中间令牌的上下文中,您只使用第二个规则而不是一般规则。在你的情况下,这会给你类似的东西:

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_prefix匹配所有以rvalue&前缀运算符开头的-表达式,而rvalue_nonprefix匹配所有rvalues其他表达。然后,当您有一个连续rvalue的上下文时,您将所有以下rvalue_nonprefix更改为-,因为任何看起来像&或{该上下文中的{1}}应与前面的rvalue结合使用作为中缀运算符。

这是语法大小的显着增长(所有中缀运算符都已重复),但绝不是&#34;数百个附加规则&#34;。特别是,无论您有多少不同的前缀/中缀运算符,您只需要一次拆分。如果你也有不明确的后缀/中缀操作符,你需要一个额外的拆分(再次复制所有内容),但你的例子似乎没有那个问题。