我必须编写某种解析器,使用yacc和bison等工具非常容易。但我有以下问题:
NotRec: /*empty*/
| NotRec T_NOT
| NotRec T_MINUS
;
Expr:
| Term /*1*/
| NotRec Term /*2*/
;
规则1和2之间有什么区别?
在我看来,NotRec
可以为空(因为它有一个空分支),因此Term
应与NotRec Term
相同。但如果我删除第一条规则,我会得到不同的结果!
答案 0 :(得分:1)
如上所述,语法不明确,因为NotRec
将匹配0个或更多T_NOT
或T_MINUS
个令牌,因此如果您有Expr
没有此类令牌在Term
之前,它可以与规则1或规则2匹配。
如果删除NotRec: /*empty*/
规则,则NotRec
将变得无用,因为它与任何有限的令牌序列都不匹配。这会更改语言,删除T_NOT
/ T_MINUS
。
如果删除Expr: Term
规则,则可以在不更改语法的情况下消除歧义。
如果您将此语法与yacc或bison一起使用,则由于模糊性,您将获得转移/减少冲突。使用shift的默认冲突解决方案将在不改变语言的情况下解决歧义 - 只要在您遗漏的语法部分中没有其他冲突使用这些令牌。对于没有Expr
/ T_NOT
指令的任何T_MINUS
,它将使用规则1;对于具有一个或多个此类令牌的任何Expr
,它将使用规则2。这相当于将NotRec
规则更改为
NotRec: T_NOT
| T_MINUS
| NotRec T_NOT
| NotRec T_MINUS
;
这使NotRec
与一个或多个令牌匹配,而不是零或更多。