我的语法类似
%(var)
和
%var
和 (VAR)
我的规则类似于
optExpr:
| '%''('CommaLoop')'
| '%' CommaLoop
CommaLoop:
val | CommaLoop',' val
Expr:
MoreRules
| '(' val ')'
问题是它似乎无法判断是否属于%(CommaLoop)
或% (val)
,但它却在抱怨而不是(。哎呀?不应该抱怨(
1}}?我应该如何修复错误?我认为使%(
成为一个令牌是一个很好的解决方案,但我想确定为什么$(
在执行此操作之前不是错误。
答案 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运行它;它不会产生任何警告或错误。