我一直试图解决一个看似简单的转变/减少冲突,但无济于事。当然,如果我忽略冲突,解析器工作正常,但如果我重新组织我的规则,我会觉得更安全。在这里,我简化了一个相对复杂的语法到单一冲突:
statement_list
: statement_list statement
|
;
statement
: lvalue '=' expression
| function
;
lvalue
: IDENTIFIER
| '(' expression ')'
;
expression
: lvalue
| function
;
function
: IDENTIFIER '(' ')'
;
使用yacc中的verbose选项,我得到的输出文件描述了上述冲突的状态:
state 2
lvalue -> IDENTIFIER . (rule 5)
function -> IDENTIFIER . '(' ')' (rule 9)
'(' shift, and go to state 7
'(' [reduce using rule 5 (lvalue)]
$default reduce using rule 5 (lvalue)
感谢您的帮助。
答案 0 :(得分:5)
问题是,这需要2个令牌前瞻才能知道它何时到达语句的结尾。如果您输入了以下表格:
ID = ID ( ID ) = ID
解析器移动第二个ID(前瞻为(
)之后,它不知道这是否是第一个语句的结尾((
是第二个语句的开头),或者这个是一个功能。所以它转移(继续解析函数),这与上面的示例输入有关。
如果扩展function
以允许括号内的参数和expression
允许实际表达式,事情会变得更糟,因为前瞻性要求是无限的 - 解析器需要一直到达第二个=
确定这不是函数调用。
这里的基本问题是没有帮助标点符号来帮助解析器找到语句的结尾。由于作为有效语句开头的文本也可以出现在有效语句的中间,因此查找语句边界很难。