C# 语法分析器(三)LALR 语法分析
系列导航
- (一)语法分析介绍
- (二)LR(0) 语法分析
- (三)LALR 语法分析
- (四)二义性文法
- (五)错误恢复
- (六)构造语法分析器
上一章构造了 LR(0) 自动机,现在就可以来构造 LALR 语法分析表了。
这里先介绍一个新函数:
- 显然,如果
是一个终结符,那么 - 如果
是一个非终结符,且 是一个产生式,那么将 加入到 中。 - 如果
是一个产生式,那么如果对于某个 , 在 中且 在所有的 、 、...、 中,那么就把 加入到 中。
构造
前面提到过,LR(0) 语法分析缺少后续输入信息,在算式文法中会出现移入-归约冲突,那我们就尝试向前看一个符号,引入更多信息来解决冲突。
LR(1) 项集
LR(1) 语法分析中需要用到下一个输入的信息,因此需要对项进行精化,使其包含第二个分量。LR(1) 的项一般形如
在形如
构造 LR(1) 项集的方法与前一章中构造 LR(0) 项集的方法相同,只需要对
构造 LR(1) 项集
- 初始项集只有
,这里很好理解,只需要在输入结束时才会归约到起始符号。 - 如果
在 中,且 是一个产生式,那么对于 中的每个终结符 ,将 加入 。不断应用这个规则,直到没有新项可以添加到 中为止。
为什么这里
构造 LR(1) 项集
由于 LR(1) 项集族包含了向前看符号,显然会比 LR(0) 项集族包含更多状态,不太利于实际的词法分析中。如果我们尝试合并一些 LR(1) 项集,以可能产生归约-归约冲突为代价,是可以将状态数减少到与 LR(0) 项集族同样水平的。这就是 LALR 语法分析,在实际使用中往往是更优的选择。
LALR 项集
前面提到,LALR 项集是可以直接根据 LR(1) 项集合并而来的,但构造 LR(1) 项集族的时间和空间成本都比较高,更实用的是根据 LR(0) 项集族,通过一个“传播和自发生成”过程直接生成向前看符号,高效计算 LALR 项的内核。
- 假设项集
包含项 ,且 。无论 为何值,在 时得到的结果中总是包含 。那么对于 来说,向前看符号 就是自发生成的。 - 其它条件与 1 相同,但有
,且结果中包含 的原因是项 有一个向前看符号 ,那我们就说向前看符号 从 的项 传播到了 的项 中。需要注意的是,这里的传播关系与特定向前看符号无关,要么所有向前看符号都从一个项传播到另一个项,要么都不传播。
找到每个 LR(0) 项集中自发生成的向前看符号,和向前看符号的传播过程,就可以为 LR(0) 项添加上正确的向前看符号了。
首先需要选择一个不在当前文法中的符号
- 为当前项集
中的每个项 计算 - 如果
在 中,且 ,那么 中的项 的向前看符号 是自发生成的。 - 如果
在 中,那么向前看符号会从 中的项 传播到 中的项 上。
确定了向前看符号的自发生和传播过程,就可以不断在项集间传播向前看符号直到停止。
- 首先,每个项集只包含其自发生成的向前看符号。
- 不断扫描每个项集,确定当前项集
可以将向前看符号传播到哪些项集,并将 的向前看符号添加到被传播到的项集中。 - 不断重复步骤 2,直到每个项集的向前看符号都不再增加。
还是继续使用算式文法作为示例:
先来计算
在闭包中,6 个项都有自发生成的向前看符号。例如其中
闭包中所有项都有
中的
中的
中的
中的
中的
中的
中的
下面列出所有传播过程:
自 | 到 |
---|---|
向前看符号的计算过程如下:
项集 | 初始值 | 第一趟 |
---|---|---|
这一过程的实现可以参见这里。
现在就已经基于 LR(0) 项集族得到了 LALR 项集族的内核,只要再为每个项集计算 LR(1) 的闭包,就可以当作 LR(1) 项集族来计算语法分析表了。
LALR 语法分析表
LALR 语法分析表的构造与 LR(1) 是一样的。假设已构造 LRLR 的项集族
- 根据
构造得到状态 ,状态 的 根据以下方法决定:- 如果
在 中,且 ,那么将 设置为“移入 ”。这里的 必须是一个终结符。 - 如果
在 中且 ,那么将 设置为“归约 ” - 如果
在 中,那么将 设置为“接受”。
- 如果
- 状态
的 根据以下方法决定:设 是一个非终结符,如果 ,那么 。 - 规则 1 和 2 未定义的所有条目都设置为“报错”。
- 语法分析器的初始状态就是根据
所在项集构造得到的状态。
同样的,如果上述规则产生了任何冲突动作,就说明文法不是 LALR 的。
上面算式文法生成的 LALR 语法分析表如下所示:
可以看到与 LR(0) 语法分析表相比,少了一些动作,也不再存在移入-归约冲突。
现在就可以得到一个“可执行”的语法分析器了,但为了让语法分析真正可用,还缺少一个重要的组成部分:解决冲突和错误恢复。
本系列相关代码都可以在这里找到。
作者:CYJB
出处:http://www.cnblogs.com/cyjb/
GitHub:https://github.com/CYJB/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)