我曾与一些解析器(Yacc,Bison和Menhir)合作过。如果我没记错的话,所有这些都允许规则为空。这是我使用Menhir的一个例子,它是我最常用的一个。
some_list:
| {[]}
| some_non_empty_list { $1 }
some_non_empty_list:
| SEMICOLON some_list { $2 }
| element { [$1] }
| element some_non_empty_list { $1 :: $2 }
重要的部分是some_list可以减少虚无。
我目前对构建解析表(构建NFA,从NFA构建DFA,最小化)的算法的理解使我认为这会导致整个地方的移位/减少冲突。但它显然没有,因为我的代码当时有效。
那么如何构建一个可以接受这些空规则的解析表?
答案 0 :(得分:1)
为什么您认为空规则比带有一个右侧令牌的规则难处理?
过于简化,语法规则L = R1 R2 R3;表示“如果看到R1 R2 R3,则降为L”。不简化,如果我们有X = A L B;那么我们的L规则意味着“如果您的左上下文是A,您已经看过R1 R2 R3,并且下一个标记是first(B),则减少到L。
如果L = R1 R2,则此想法相同;并且L = R1;。
甚至对于(空规则)的极限情况:L =;
除非您已经看到L的左上下文,其内容以及随后内容的开头,否则您不能简化为L。因此,您无法在“任何时候”简化为空规则。
您需要做的是通过学习如何在建立分析状态时跟踪项目集来了解LR解析器的工作方式。一次在纸上做一个小语法(痛苦的是,值得的),LR解析器将变得很清晰。您可以在有关LR解析的任何书籍(包括Aho等人的经典Compilers)中找到描述的过程。