为什么我对')'的转换减少/冲突而不是'('?

时间:2009-12-02 04:40:59

标签: yacc bison shift-reduce-conflict

我的语法类似

%(var)

%var

和     (VAR)

我的规则类似于

optExpr:
    | '%''('CommaLoop')'
    | '%' CommaLoop

CommaLoop:
    val | CommaLoop',' val

Expr:
    MoreRules
    | '(' val ')'

问题是它似乎无法判断是否属于%(CommaLoop)% (val),但它却在抱怨而不是(。哎呀?不应该抱怨( 1}}?我应该如何修复错误?我认为使%(成为一个令牌是一个很好的解决方案,但我想确定为什么$(在执行此操作之前不是错误。

2 个答案:

答案 0 :(得分:3)

这是由于LR解析的工作方式。 LR解析实际上是自下而上的,根据语法规则的RHS将令牌组合在一起,并用LHS替换它们。当解析器“移位”时,它会在堆栈上放置一个令牌,但实际上并没有匹配规则。相反,它通过当前状态跟踪部分匹配的规则。当它到达对应于规则末尾的状态时,它可以减少,从堆栈弹出RHS的符号并推回表示LHS的单个符号。因此,如果存在冲突,则在解析器到达某个规则的末尾之前它们不会出现,并且无法决定是否减少(或减少什么)。

在您的示例中,在看到 val 之后,这将是堆栈上的内容( top在这里右侧。)当前瞻是时,它无法决定是否应该弹出val并通过规则 CommaLoop:val 减少,或者如果它应该移动,那么它就可以弹出3个东西并减少规则 Expr:'('val')'

我假设你有一些额外的规则,例如 CommaLoop:Expr ,否则你的语法实际上并不匹配任何东西,bison / yacc会抱怨未使用的非终端。

答案 1 :(得分:0)

现在,你的解释和你的语法似乎不匹配。在你的解释中,你将所有三个短语显示为'var',但是你的语法显示以'%'开头的那些短语允许以逗号分隔的列表,而不允许使用逗号分隔列表的那个短语。

目前,我假设所有三个都应该允许以逗号分隔的列表。在这种情况下,我将语法分解为更多:

optExpr: '%' aList

aList: CommaLoop
    | parenList

parenList: '(' CommaLoop ')'

CommaLoop: 
    | val 
    | CommaLoop ',' val

Expr: MoreRules
    | parenList

我已经改变了optExpr和Expr,所以两者都不能匹配一个空序列 - 我的猜测是你可能不打算开始。我已经充实了它,足以通过byacc运行它;它不会产生任何警告或错误。