【问题标题】:Precedence/associativity implmentation优先级/关联性实现
【发布时间】:2021-01-12 14:17:15
【问题描述】:

我目前正在实现一个 LR(k) 解析器解释器,只是为了好玩。

我正在尝试实现优先级和关联性。

当谈到如何为“动作”部分分配关联性和优先级时,我有点卡住了,即减少的优先级和关联性应该是什么。

如果我们有作品

E -> 
  | E + E { action1 }
  | E * E { action2 } 
  | (E)   { action3 }
  | ID    { action4 }

应该很清楚,action1 应该与 + 具有相同的关联性和优先级 和 action2 应该与 * 相同。但总的来说,我们不能仅仅假设生产中的规则只有一个具有优先级的符号。一个玩具例子

E -> E + E - E { action }

其中 - 和 + 是一些任意运算符,具有一定的优先级和关联性。该动作是否应该与 - 相关联,因为它在最后一个 E 之前?

我知道如何在移位/减少之间进行选择的规则,这不是我要求的。

【问题讨论】:

    标签: parsing lr language-implementation


    【解决方案1】:

    由 yacc(和许多衍生产品)实现的经典优先算法使用每个产生式中的最后一个非终结符来定义其默认优先级。这并不总是产生式的期望优先级,因此解析器生成器通常还为其用户提供一种机制,用于明确指定产生式的优先级。

    这种优先级模型已被证明是有用的,虽然它并非没有问题 - 见下文 - 它可能是简单解析器生成器的最佳实现,如果只是因为它的怪癖至少被记录在案。

    这个约定延续了这样一种观点,即优先级是非终端(或“运算符”)的一个特征。如果您正在构建运算符优先级解析器,那么这是有效的,但它不对应于 LR(k) 解析。充其量,它只是一个粗略的近似值,可能会产生很大的误导性。

    如果底层语法确实是运算符优先语法——也就是说,没有产生式有两个连续的终结符,并且推定的优先关系是明确的——那么它可能是一个可以接受的近似值,尽管值得注意的是运算符优先关系是不传递,因此它们通常不能概括为单调比较。但是 yacc 样式优先级的许多用法都超出了这个范围,甚至会导致严重的语法错误。

    问题在于,将优先级建模为标记之间的简单传递比较可能会导致优先级声明被用于消除歧义(从而隐藏)不相关的冲突。简而言之,在 LR 解析中使用优先级声明基本上是一种 hack。这是一个有用的技巧,而且有时是有益的——正如你所说,它可以减少状态的数量和单位减少的频率——但需要谨慎对待。

    确实,有人提出了一种基于语法重写的替代优先模型。 (例如,参见 Ali Afroozeh 等人在 2013 年发表的论文,“运算符优先规则的安全规范”)。这个模型要精确得多,但部分由于这种精确性,它不适合(误)用于其他目的,例如解决悬空冲突。

    【讨论】:

    • 非常感谢。我知道这一点,但如果它应该被其他人使用,则由这些人负责采取适当的措施来处理它。 Me项目排在第一位,要做一个大代码项目。它已经包括缩进敏感解析的选项,并且仍然在线性时间内运行用户定义的前瞻数量的可能性,其中我使用压缩列表形式作为解释器部分中的表格来应对大 k 的表格大小的爆炸,以及一些聪明的非基于表格的代码生成器,让编译器找出更优化的形式。
    猜你喜欢
    • 2020-10-20
    • 1970-01-01
    • 2021-05-05
    • 2012-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多