如何在peg.js中回溯工作(例如)?

我定义了以下最小的Peg.js语法:

start = "A1" / "A123" 

您可以在沙箱中尝试。

我预料会匹配“A1”和“A123”(根据我的回溯工作原理)。 但事实并非如此:语法识别“A1”而不识别“A123”。

:我不是在寻找“相反的术语顺序”的build议,如相关的问题如何将一个简单的语法转换成在PEG.js(预期“一个”,但“一个”find)工作的东西 。 相反,我期待了解我所看到的行为,以及为什么Peg.js的回溯不适用于这种情况。 有关解释为什么颠倒我的术语顺序不起作用的信息,请参阅下面的更实际的示例。


对于一个更现实的例子,考虑单位parsing。 一个语法应该识别带有可选前缀(如“mm”,“mmol”)以及非“公制”单位(如“年”,“星期”或“mo”)的公制单位(如“m”,“mol”)。

下面的Peg.js语法不会识别“mol”,因为它被绊倒消耗“mo”,并且不会回溯。 (改变术语顺序没有帮助;或者说,会导致以“mol”或“mmol”为代价来识别“mo”)。

 start = nonmetric / metric / prefix metric metric = "mol" / "l" / "m" / "g" nonmetric = "yr" / "mo" / "week" / "day" / "hour" prefix = "m" / "k" / "c" 

我可以在Antlr中做类似的事情,取得很好的成绩:

 grammar units; start : nonmetric | metric | prefix metric; metric : 'mol' | 'l' | 'm' | 'g'; nonmetric : 'yr' | 'mo' | 'week' | 'day' | 'hour'; prefix : 'm' | 'k' | 'c'; 

问题在于回溯的概念。 PEGparsing器不像其他recursion下降parsing器或Prolog那样回溯。 相反,当遇到一个select时,一个PEGparsing器会尝试每一个选项,直到一个成功。 一旦成功,无论规则如何被调用,它都会承诺。

从维基百科的文章 :

然而,与上下文无关的语法和正则expression式不同的是,这些操作符总是performance得贪婪,消耗尽可能多的input而不回溯。

你在复杂的情况下所要求的与在这个问题中所要求的是一样的。 到目前为止的答案是肯定的 :你必须调整PEG语法中的规则,以确保最长的选项总是首先匹配,即使结果是有些丑陋的语法。

调整PEG语法的一种方法是使用lookahead(这是为什么lookahead在PEG中具有特征的主要原因之一):

 start = nonmetric / metric / prefix metric metric = "mol" / "l" / !"mo" "m" / "g" nonmetric = "yr" / !"mol" "mo" / "week" / "day" / "hour" prefix = !("mol"/"mo") "m" / "k" / "c" 

这是devise。 您需要指定将用于匹配的正确顺序或规则。

原白皮书的引用:

这些工具当然不会使语言的语法devise变得简单。 为了确定CFG中两种可能的替代scheme是否含糊不清,PEG为语言devise者提供了类似的挑战,即确定“/”expression式中的两个替代scheme是否可以在不影响语言的情况下进行重新sorting。 这个问题通常是显而易见的,但有时并不普遍,而且是不可判定的。 然而,就像在CFG中发现模糊一样,我们希望find自动algorithm来在常见情况下保守地识别顺序敏感性或不敏感性。

在这个简单的例子中,PEG.js可能会更聪明一些,并且认识到你指定的规则是不明确的。 可能值得问一下作者。