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

时间:2014-07-16 06:15:01

标签: node.js grammar peg pegjs

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

start  =  "A1" / "A123"

您可以尝试in the sandbox

我原本期望匹配" A1"以及" A123" (根据我的回溯如何运作的概念)。但情况并非如此:语法识别" A1"但不是" A123"。

注意:我不是在寻找建议"颠倒您的条款顺序"如相关问题How to transform a simple grammar into something which works in PEG.js (expected "a" but "a" found)。相反,我希望了解我所看到的行为,以及为什么Peg.js的回溯在这种情况下并不适用。有关为什么颠倒我的术语顺序没有帮助的解释,请参阅下面更实际的示例。


有关更实际的示例,请考虑单位解析。语法应该识别具有可选前缀的度量单位(例如" m"," mol"),例如" mm"," mmol",as以及非公制单位,如" yr","周"或" mo"。

以下Peg.js语法无法识别" mol"因为它被绊倒消耗了" mo"并且没有回溯。 (改变术语的顺序并没有帮助;或者更确切地说,会导致" mo"被认可,而且会损害" mol"或" mmol" 。)

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';

2 个答案:

答案 0 :(得分:9)

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

来自Wikipedia article

  

与上下文无关的语法和正则表达式不同,   这些操作符总是表现得很贪婪,消耗的输入也是如此   可能,永远不会回溯。

复杂案件中你要求的内容与this question中的要求相同。到目前为止的答案是:你必须调整PEG语法中的规则,以确保最长的选项始终首先匹配,即使结果是一个有点丑陋的语法。

调整PEG语法的一种方法是使用前瞻(这是为什么在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"

答案 1 :(得分:0)

这是设计的。您可以指定正确的订单或将用于匹配的规则。

原始white paper的引用:

  

当然,这些工具不会使语言语法设计变得容易。在   必须确定a中是否有两种可能的替代方案的地方   CFG含糊不清,PEG为类似的语言设计者提供了类似的东西   确定'/'表达式中是否有两个备选方案的挑战   可以在不影响语言的情况下重新排序。这个问题是   通常是显而易见的,但有时却不是,而且一般来说是不可判定的。   然而,正如发现CFG中的含糊不清一样,我们有希望   找到自动算法来识别订单敏感度或   在常见情况下保守的不敏感。

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