我已经实现了解析器组合器,它可以解析可能包含歧义的语法。当语法不明确时会出现错误,但事实证明朝另一个方向前进会更加困难。问题是如何用最少的括号将抽象语法树漂亮地打印成可能不明确的语法。使用运算符优先级会有所帮助,但不是万能的。在相同的优先级内,问题仍然存在。
确切的运算符直到运行时才知道,并且在用户引入新运算符时可以在执行期间更改。我支持前缀、后缀和中缀(左、右和非关联)运算符。中缀左和后缀运算符同时在优先级上混合。这同样适用于中缀右和前缀运算符。运算符还可以嵌入完整的表达式,因此 if-then-else 和 if-then 都可以实现为前缀运算符。(尽管这可能不是明智之举。)
这是一个使用提到的 if-then-else 和 if-then 运算符的示例,这里假定它们处于相同的优先级。显然,该表达式if a then if b then c else d
是模棱两可的,因为它可以解释为if a then (if b then c) else d
or if a then (if b then c else d)
。在漂亮打印期间,即使两个运算符处于相同的优先级并且具有兼容的关联性(右侧),算法也应该知道使用括号。
一个警示性示例:添加另一个前缀运算符 say inc,其优先级与 if-then-else 和 if-then 相同。现在假设一个任意集合P ⊂ H x O
,其中H
是算子孔O
集,是算子集。该集合是一种关系,它告诉何时需要添加括号。检查表达式if a then inc b else c
和if a then (inc if b then c) else d
。第一个要求(if-then-else.2, inc)
不参加P
,第二个要求相反。这与问题可以通过某种关系或顺序解决的假设相矛盾。可以尝试(inc.1, if-then)
在P
做后一个表达式时说 let is if a then inc (if b then c) else d
,但随后inc if a then b
变成inc (if a then b)
了有太多括号的。
据我所知,语法是上下文无关的。不过,我对定义有点摇摆不定。
解析器松散地基于此处的一篇论文。我正在使用 Haskell。
更新:正如 NieDzejkob 所证明的,这个问题通常是无法解决的。我愿意接受可能失败的算法。如果这还不足以使事情变得实用,那么一个好的启发式方法就可以了。