C# 语法分析器(四)二义性文法

系列导航

  1. (一)语法分析介绍
  2. (二)LR(0) 语法分析
  3. (三)LALR 语法分析
  4. (四)二义性文法
  5. (五)错误恢复
  6. (六)构造语法分析器

二义性文法,指的是一个可以为某个句子生成多颗语法分析树。最常见的例子就是算式的例子:

0. EE
1. EE+E
2. EEE
3. Eid
4. E(E)

它可以为 id+idid 生成两个最左推导:

EE+EEEEid+EE+EEid+EEid+EEid+idEid+idEid+ididid+idid

二义性文法显然无法被 LR 语法分析器处理,那为什么要使用二义性文法?主要原因就是在表达式这样的语言构造中,二义性文法能够提供比任何等价的二义性文法更短、更自然的归约;同时,我们还可以通过一些消除二义性的规则,使得语言的归约在整体上是无二义性的,并构造出其 LR 语法分析器。

以上面的二义性文法为例,看一下二义性的来源,以下是 LR(0) 项集族:

I0:EEI3:EidI6:E(E)EE+EEE+EEEEI4:EE+EEEEEidEE+EE(E)EEEI7:EE+EEidEE+EI1:EEE(E)EEEEE+EEEEI5:EEEI8:EEEEE+EEE+EI2:E(E)EEEEEEEE+EEidEEEE(E)I9:E(E)EidE(E)

图 1 二义性算式文法的 LR(0) 项集族

再构造得到 LALR 语法分析表(包含冲突):

id+()$E0s3s211s4s5acc2s3s263r3r3r3r34s3s275s3s286s4s5s97s4/r1s5/r1r1r18s4/r2s5/r2r2r29r4r4r4r4

图 2 二义性算式文法的 LALR 语法分析表(包含冲突)

可以看到,由于 + 都在状态 7 和 8 的向前看符号中,因此 LALR 语法分析无法解决这里的冲突,不能确定这里应该移入还是归约。即使使用 LR(1),甚至更高的 LR(k) 都会产生这样的冲突。

消除二义性的一个实用方法就是优先级和结合性,如果我们设定 的优先级高于 +,那么在状态 7 需要选择“按照 EE+E 归约”和“移入 ” 时,就应当选择优先级更高的符号,即“移入 ”。其它情况由于移入的符号优先级不高于归约的符号,且符号是左结合的,应当选择归约动作。

这里还有一个细节,就是为什么 EE+E 的优先级是 +?这里使用一个简单的选择:产生式的优先级是它最右非终结符的优先级,或者也允许用户自行指定。

对于其它未指定的情况,可以选择使用通用策略:在遇到移入-归约冲突时优先选择移入,遇到归约-归约冲突时选择列在前面的产生式。或者可以报错要求开发者解决。

本系列相关代码都可以在这里找到。

posted @   CYJB  阅读(452)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
Fork me on GitHub
点击右上角即可分享
微信分享提示