在明确的 PEG 语法中消除左递归

问题描述

我已经在 StackOverflow 上阅读了一堆现有的问题,但我无法弄清楚我的语法。

statement "Statement" =
    assignment / primitive / reference / operation
operation "Operation" =
    statement operator:operator statement
operator "Operator" =
    "+"

* 请注意,稍后我可能会向运算符规则添加更多运算符模式(即“==”、“**”、“/”)。因此,它可能会变得更加复杂。

我实际上在这里使用 PEG.js 而不是普通的 PEG,因此使用了非常规的语法。

编译器向我抱怨 statement 访问了 operation ,而后者又访问了 statement 等等,这会导致可能的无限循环。这通常称为左递归。

对于这种特殊情况,我无法理解如何解决此问题。我不太明白这个场景的头尾模式。


注意:我想尽可能方便地在其他规则中重复使用 statement 规则。因此,将其分成十几个单独的规则作为解决方法可能是一个解决方案,但作为答案并不能真正帮助我。

解决方法

在一些朋友的帮助下,顺便在10分钟内了解了整个PEG解析架构,我能够解决这个场景的问题。

让我们问这个:

left+right 形式的操作中,我们是否会在 {{1} 上进行赋值(形式为 a=b)或其他操作(形式为 a+b) }}一面?

答案很可能是否定的。

因此,此语法有效:

left

如您所见,我只是将 statement "Statement" = assignment / operation / primitive / reference operation "Operation" = (primitive / reference) operator statement operator "Operator" = "+" 规则替换为 statement 规则中的 primitive / reference 部分,省略了 statement 和 { {1}} 部分,因为我们不需要它们在左侧。

这就是解决方案。一切正常。

然而,如果您想知道为什么解析像 assignment 这样的输入有效,尽管我们显然不允许 operation 左侧的递归 1+2+3+4+5 s,请注意我们仍然允许他们在右侧。并且右递归在 PEG 中是完全有效的。