我使用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的规范方法,如果它甚至可能的话?
答案 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生成的词法分析器中,使用开始条件来分离词汇环境(程序/引用字符串/支撑注释)是正常的,然后解析器就没有歧义。
希望有所帮助。