如何解决优先级/关联性实现
我目前正在实现一个 LR(k) 解析器解释器,只是为了好玩。
我正在尝试实现优先级和关联性。
当谈到如何为“动作”部分指定关联性和优先级时,我有点困惑,即减少的优先级和关联性应该是什么。
如果我们有作品
E ->
| E + E { action1 }
| E * E { action2 }
| (E) { action3 }
| ID { action4 }
应该清楚,action1 应该具有与 + 相同的关联性和优先级 和 action2 应该与 * 相同。但总的来说,我们不能仅仅假设产生式中的规则只有一个具有优先级的符号。一个玩具示例
E -> E + E - E { action }
其中 - 和 + 是一些任意运算符,具有一些优先级和结合性。动作是否应该与 - 相关联,因为它在最后一个 E 之前?
我知道如何在 shift/reduce 之间进行选择的规则,这不是我所要求的。
解决方法
由 yacc(以及许多派生类)实现的经典优先级算法使用每个产生式中的最后一个非终结符来定义其默认优先级。这并不总是产生式所需的优先级,因此解析器生成器通常还会为其用户提供一种机制,用于显式指定产生式的优先级。
这种优先级模型已被证明是有用的,虽然它并非没有问题——见下文——它可能是简单解析器生成器的最佳实现,因为它的怪癖至少被记录在案。
>这个约定延续了优先级是非终结符(或“操作符”)的特征的想法。如果您正在构建运算符优先级解析器,则这是有效的,但它不对应于 LR(k) 解析。充其量只是一个粗略的近似值,可能会产生极大的误导。
如果底层语法确实是运算符优先语法——也就是说,没有产生式有两个连续的终结符,并且推算的优先关系是明确的——那么它可能是一个可接受的近似值,尽管值得注意的是,运算符优先关系是不可传递,因此它们通常不能总结为单调比较。但是 yacc 样式优先级的许多用途都超出了这个范围,甚至会导致严重的语法错误。
问题在于,将优先级建模为标记之间的简单传递比较会导致优先级声明被用来消除(从而隐藏)不相关的冲突。总之,在LR解析中使用优先级声明基本上是一种hack。这是一个有用的技巧,有时也是有益的——正如你所说,它可以减少状态数量和单位减少的频率——但需要谨慎对待。
确实,有人提出了一种基于语法重写的替代优先级模型。 (例如,参见 Ali Afroozeh 等人在 2013 年发表的论文“运算符优先规则的安全规范”)。这个模型要精确得多,但部分由于这种精确性,它不容易(误)用于其他目的,例如解决悬空冲突。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。