【问题标题】:Left-recursive Grammar Identification左递归语法识别
【发布时间】:2013-10-22 22:31:43
【问题描述】:
我们经常想重构上下文无关文法来移除左递归。有许多算法可以实现这种转换。例如here 或here。
无论是否存在左递归,此类算法都会重构语法。这具有负面影响,例如从原始语法生成不同的解析树,可能具有不同的关联性。理想情况下,只有在绝对必要时才会转换语法。
是否有一种算法或工具可以识别语法中是否存在左递归?理想情况下,这也可能对包含左递归的生产规则子集进行分类。
【问题讨论】:
标签:
algorithm
parsing
recursion
grammar
【解决方案1】:
有一个标准算法用于识别可为空的非终结符,该算法在时间上与语法大小成线性关系(见下文)。完成此操作后,您可以在所有非终端 A、B 上构建关系 A potentially-starts-with B。 (事实上,在所有语法符号上构建这种关系更为正常,因为它也用于构建 FIRST 集合,但在这种情况下,我们只需要投影到非终结符上。)
这样做后,左递归非终结符都是A,因此A potentially-starts-with<sup>+</sup> A,其中potentially-starts-with<sup>+</sup> 是:
potentially-starts-with ∘ potentially-starts-with<sup>*</sup>
您可以使用任何传递闭包算法来计算该关系。
作为参考,检测可空的非终结符。
- 删除所有无用符号。
- 将指针附加到每个产生式,最初位于第一个位置。
- 将所有产生式放入一个工作队列中。
- 如果可能,请找出符合以下条件之一的产品:
- 如果产生式的左侧已被标记为 ε 非终结符,则丢弃产生式。
- 如果指针右侧的标记是终结符,则丢弃该产生式。
- 如果指针右侧没有标记(即指针位于末尾),则将产生式的左侧标记为 ε 非终结符并丢弃产生式。
- 如果紧挨着指针右侧的记号是一个已被标记为 ε 非终结符的非终结符,则将指针向右推进一个记号并将产生式返回到工作队列。
一旦无法从工作队列中选择生产,所有 ε-非终结符都已被识别。
只是为了好玩,对上述算法稍加修改即可完成步骤 1。我将其留作练习(这也是龙书的练习)。还留作练习的是确保上述算法在线性时间内执行的方法。