使用LALR解析器解决语法中的歧义

时间:2014-03-05 17:15:01

标签: grammar bnf ambiguity lalr disambiguation

我使用whittle来解析语法,但我遇到了经典的LALR ambiguity problem。我的语法看起来像这样(简化):

<comment> ::= '{' <string> '}'           # string enclosed in braces
<tag> ::= '[' <name> <quoted-string> ']' # [tagname "tag value"]
<name> ::= /[A-Za-z_]+/                  # subset of all printable chars
<quoted-string> ::= '"' <string> '"'     # string enclosed in quotes
<string> ::= /[:print:]/                 # regex for all printable chars

问题当然是<string>。它包含所有可打印的字符,因此非常贪婪。由于它是一个LALR解析器,它会尝试将<name>解析为<string>并且一切都会中断。语法使事情变得复杂,因为它为不同的事物使用不同的字符串分隔符,这就是为什么我首先尝试制定<string>规则。

是否存在规范化该语法以使其符合LALR的规范方法,如果它甚至可能的话?

1 个答案:

答案 0 :(得分:1)

这不是“经典的LALR歧义问题”,无论可能是什么。这只是语言词汇规范中的一个错误。

我快速浏览了Whittle自述文件,但它与OP中的语法没有任何相似之处。所以我假设OP中的文本是概念性的而不是字面式的,并且它包含明显不正确的事实

<string> ::= /[:print:]/                 # regex for all printable chars

只是一个错字。

更好的是/[:print:]*/,假设Ruby允许你使用[:print:]而不是Posix标准[[:print:]]

但这也不正确,因为lexing(通常)匹配最长的字符串,因此会吞噬结束语和任何后续文本。

因此quoted-string的正确解决方案是正确写出来:

<quoted-string> ::= /"[^"]*"/

甚至

<quoted-string> :: /"([^\\"]|\\.)*"/
# any number of characters other than quote or escape, or escaped pairs

您可能对如何逃避内部双引号有其他想法;这只是例子。在这两种情况下,您都需要对令牌进行后处理,以便(至少)去除双引号和可能的解释转义序列。这就是它的方式。

您的评论序列提出了一个更难的问题,假设您的意图是评论可能包含嵌套大括号(例如。{This comment {with this} ends here}),因为嵌套大括号语法不规则,因此无法与正则表达式匹配。当然,现在很少有“正则表达式”库是常规的,我不知道Ruby是否包含某种支撑计数扩展,例如Lua的模式语法。嵌套的大括号语法肯定是无上下文的,但要实际解析它,你需要以与程序其余部分不同的方式对词外{...}的内容进行词法分析。

这是后一种观察,而不是LALR算法中的任何弱点,这会导致你的痛苦,而且我会说这是一个弱点((大多数是无证件的afaics)词汇分析部分。例如,在flex生成的词法分析器中,使用开始条件来分离词汇环境(程序/引用字符串/支撑注释)是正常的,然后解析器就没有歧义。

希望有所帮助。