编译原理完整学习笔记(四):语法分析
前言
如果你对这篇文章可感兴趣,可以点击「【访客必读 - 指引页】一文囊括主页内所有高质量博客」,查看完整博客分类与对应链接。
文章目录
- 前言
- 语法分析
- 一、自上而下分析
- 1.1 左递归 & 回溯
- 1.1.1 面临的问题
- 1.1.2 消除左递归
- 1.1.3 消除回溯
- 1.2 LL(1) 文法
- 1.2.1 LL(1)定义
- 1.2.2 FIRST
- 1.2.3 FOLLOW
- 1.2.4 习题练习
- 1.3 递归下降分析器
- 1.3.1 概述
- 1.3.2 程序示例
- 1.4 扩充的巴克斯范式
- 1.4.1 定义
- 1.4.2 示例
- 1.5 预测分析程序
- 1.5.1 预测分析程序组成
- 1.5.2 构造预测分析表
- 1.5.3 预测分析示例
- 1.5.4 二义性文法
- 二、自下而上分析
- 2.1 基础概念
- 2.1.1 短语
- 2.1.2 素短语
- 2.2 算符优先文法
- 2.2.1 优先关系
- 2.2.2 算符文法
- 2.2.3 FIRSTVT、LASTVT
- 2.2.4 最左素短语定理
- 2.2.5 算符优先分析算法
- 2.3 LR 分析法
- 2.3.1 LR 文法
- 2.3.2 概念说明
- 2.3.3 LR 分析过程
- 2.3.4 LR 分析示例
- 2.4 LR(0) 文法
- 2.4.1 活前缀
- 2.4.2 文法拓广
- 2.4.3 LR(0) 项目
- 2.4.4 识别活前缀的 DFA 构造法1
- 2.4.5 识别活前缀的 DFA 构造法2
- 2.4.6 LR(0)分析表构造
- 2.5 SLR(1) 文法
- 2.5.1 引入原因
- 2.5.2 SLR(1) 解决冲突
- 2.5.3 SLR(1) 分析表
- 2.6 LR(1) 文法
- 2.6.1 引入原因
- 2.6.2 LR(k) 项目
- 2.6.3 DFA 构造
- 2.6.4 LR(1) 分析表
- 2.7 LALR(1) 文法
- 2.8 LR 文法总结
语法分析
- 语法分析方法
- 自下而上:算符优先分析法、LR分析法
- 自上而下:递归下降分析法、预测分析程序
一、自上而下分析
1.1 左递归 & 回溯
1.1.1 面临的问题
回溯问题
- 分析过程中,当一个非终结符用某一个候选匹配成功时,这种匹配可能是暂时的
- 因此如果在后续匹配中出错的话,不得不“回溯”
文法左递归问题
- P→PαP \rightarrow P\alphaP→Pα,匹配过程会无限循环下去
1.1.2 消除左递归
「消除直接左递归」
核心思想:左递归变右递归
例题
「消除间接左递归」
要求
核心思想
- 消除回路中的节点
算法
例题
S -> Qc | c
Q -> Rb | b
R -> Sa | a顺序 1:R、Q、S
答案:
S -> abcS' | bcS' | cS'
S' -> abcS' | 空字顺序 2:S、Q、R
答案:
S -> Qc | c
Q -> Rb | b
R -> bcaR' | caR' | aR'
R' -> bcaR' | 空字
1.1.3 消除回溯
消除回溯的核心在于能确定非终结符 A 所有候选可能推出的第一个符号,因此引入 FIRST 集
提取左公共因子 —— 令非终结符的所有候选首符集两两不相交
由于有一些非终结符会推出空字,因此我们需要定义 FOLLOW 集
1.2 LL(1) 文法
1.2.1 LL(1)定义
文法定义
- 第一个 L 表示 “从左到右扫描串”
- 第二个 L 表示 “最左推导”
- 第三个 1 表示 “每一步只需向前查看一个符号”
LL(1) 分析法
- LL(1) 文法可以对输入串进行有效的无回溯的自上而下分析
- LL(1) 文法可以对输入串进行有效的无回溯的自上而下分析
1.2.2 FIRST
定义
求解算法
- 核心思想:用 “对有限产生式的反复扫描” 代替 “穷尽所有推导”
构造每个文法符号的 FIREST 集
构造任何符号串的 FIRST 集
1.2.3 FOLLOW
定义
构造每个非终结符的 FOLLOW 集
1.2.4 习题练习
求解步骤
- 消除左递归
- 提取左公共因子
- 求出每个非终结符的 FIRST 集、FOLLOW 集
- 判定是否符合 LL(1) 文法
练习题
根据LL(1)文法要求,可以判定该文法符合LL(1)。
1.3 递归下降分析器
1.3.1 概述
- 总体思想
- 分析程序由一组子程序组成,对每一语法单位(非终结符)构造一个相应的子程序,识别对应的语法单位
- 定义全局过程、变量
- ADVANCE:把输入串指示器 IP 指向下一个输入符号,即读入一个单词符号
- SYM:IP 当前所指的输入符号
- ERROR:出错处理子程序
- 代码实现概述
- 依据 FIRST、FOLLOW 集进行匹配
- 依据 FIRST、FOLLOW 集进行匹配
1.3.2 程序示例
文法
Procedure F
PROCEDURE F;IF SYM = 'i' THEN ADVANCEELSEIF SYM = ')' THENBEGINADVANCE;E;IF SYM=')' THEN ADVANCEELSE ERRORENDELSE ERROR;
- PROCEDURE E
PROCEDURE E;
BEGINT; E';
END:
- PROCEDURE E’
- 此处可以检查 FOLLOW 集,也可以不检查,对程序正确性没有影响
PROCEDURE E';
IF SYM = '+' THEN
BEGINADVANCE;T; E';
END
- PROCEDURE T
PROCEDURE T;
BEGINF; T';
END
- PROCEDURE T’
PROCEDURE T';
IF SYM='*' THEN
BEGINADVANCE;F; T';
END
1.4 扩充的巴克斯范式
1.4.1 定义
- 举例
用扩充的巴克斯范式来描述语法,直观易懂,便于表示左递归消除和左公共因子提取。
1.4.2 示例
1.5 预测分析程序
1.5.1 预测分析程序组成
- 总控程序
- 分析表
- 分析栈
1.5.2 构造预测分析表
分析产生式语句的FIRST集
如果非终结符可以推空,则加入 FOLLOW 集
练习例子
1.5.3 预测分析示例
1.5.4 二义性文法
并不是所有文法在消除左递归、提取左公共因子后都符合 LL(1) 文法要求,因此我们可以根据具体情况来修改预测分析表。
文法举例
二义文法对应的预测分析表
此处出现冲突的格子其实代表的是 if…then if…then…else… 语句中,else 匹配的是第一个 if,还是第二个 if 的问题,因此我们可以根据程序的实际要求进行选择,并删除另一个,使该文法满足 LL(1) 的特性。
二、自下而上分析
自下而上分析采用 “移进-归约” 思想。
- 基本思想
- 用一个寄存符号的先进后出栈,把输入符号一个一个地移进到栈里,当栈顶形成某个产生式的候选式时,即把栈顶的这一部分替换成(归约为)该产生式的左部符号。
- 核心方法
- 算符优先分析法
- 按照算符的优先关系和结合性质进行语法分析
- 适合分析表达式
- LR 分析法
- 规范规约:句柄作为可归约串
- 算符优先分析法
2.1 基础概念
2.1.1 短语
定义(短语、直接短语)
语法树的角度
- 两代以上子树的叶子结点构成的序列为短语
- 子树只有两代,则为直接短语
2.1.2 素短语
定义(素短语、最左素短语)
- 属于短语
- 至少有一个终结符
- 除自身外不再包含更小的素短语
示例
2.2 算符优先文法
2.2.1 优先关系
2.2.2 算符文法
算符文法定义
算符优先文法定义
- 引入终结符的优先级
- 引入终结符的优先级
2.2.3 FIRSTVT、LASTVT
FIRSTVT
LASTVT
具体实现方式
- 利用栈不断遍历所有产生式
- 若栈 STACK 不空,就将栈顶项弹出,记此项为 (Q, a)。对于每个形如 P→Q...P\rightarrow Q...P→Q... 的产生式,若 F[P, a] 为假,则变其值为真且将 (P, a) 推进 STACK 栈。
- 上述过程一直重复,直至栈 STACK 为空为止。
FIRSTVT、LASTVT 具体作用
示例
- 求解时还需要考虑 KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲E# 式子
- 求解时还需要考虑 KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲E# 式子
2.2.4 最左素短语定理
- 具体定理
- 出现了一个山峰式的句型
- 出现了一个山峰式的句型
2.2.5 算符优先分析算法
具体算法过程
具体归约过程
- 从左至右,终结符对终结符,非终结符对非终结符,且只要求终结符对应匹配
- 从左至右,终结符对终结符,非终结符对非终结符,且只要求终结符对应匹配
算符分析树 v.s. 语法树
- 二者不同,分析树可能会更简便
- 二者不同,分析树可能会更简便
2.3 LR 分析法
2.3.1 LR 文法
- LR 文法定义
- 对于一个文法,如果能够构造一张分析表,使得它的每个入口均是唯一确定的,则这个文法就称为 LR 文法。
- LR(k) 文法定义
- 一个文法,如果能用一个每步顶多向前检查 k 个输入符号的 LR 分析器进行分析,则这个文法就称为 LR(k) 文法。
- LR 文法与二义文法
- LR 文法不是二义的,二义文法肯定不会是 LR 的
- LR 文法是二义文法的真子集,因此是二义文法的充分条件
- 实际应用
- 虽然 LR 文法不能涵盖所有二义文法,但程序设计语言仍然使用 LR 分析法,如果分析表中有冲突,则人工手动去除
2.3.2 概念说明
LR 分析法
- 关键在于生成分析表,再根据分析表进行语法分析
- 关键在于生成分析表,再根据分析表进行语法分析
句柄
- 一个句型的最左直接短语就是该句型的句柄
- 一个句型的最左直接短语就是该句型的句柄
规范归约
- 规范归约即每次对句柄进行归约
- 规范归约 = 最左归约 = 最右推导的逆过程
- 最右推导 = 规范推导
- 由规范推导推出的句型称为规范句型
2.3.3 LR 分析过程
规范规约的关键在于寻找句柄
- 历史:已移入符号栈的内容
- 展望:根据产生式推测未来可能遇到的输入符号
- 现实:当前的输入符号
LR 分析表
- ACTION[s, a]: 当状态 s 面临输入符号 a 时,应采取什么动作
- GOTO[s, X]: 状态 s 面对文法符号 X 时,下一状态是什么
- 分析表中 s 表示移进(shift),r 表示归约(reduce)
其中归约的具体步骤如下所示:
- LR分析过程性质
- 在任何时候,分析栈里面的内容和扫描串剩下的内容拼接起来,总是一个规范句型。
- 一旦栈顶出现了当时栈内内容和栈外输入串拼接出来的那个句型的句柄,马上就会归约。
2.3.4 LR 分析示例
图 1
图 2
图 3
2.4 LR(0) 文法
2.4.1 活前缀
概念引入原因
- 为了定义在规范规约时,不会出现 D 这种情况,引入活前缀概念
- 为了定义在规范规约时,不会出现 D 这种情况,引入活前缀概念
活前缀定义
- 规范句型的一个前缀,且该前缀不含句柄之后的任何符号
- 活前缀后续符号均为入栈,因此为终结符
2.4.2 文法拓广
- 文法拓广目的
- 与构造 DFA 时引入初态、终态节点目的一致
- 使得文法的 DFA 中只有一个初态、一个终态
2.4.3 LR(0) 项目
2.4.4 识别活前缀的 DFA 构造法1
总体思想
- 先构造 NFA,再将 NFA 通过构造的方式转换成 DFA
NFA 构造方法
DFA 构造举例
NFA => DFA
- DFA 的项目集为文法的LR(0)项目集规范族
- 族 = 元素是集合的集合
2.4.5 识别活前缀的 DFA 构造法2
总体思想
- 通过引入有效项目的概念,直接构造出 DFA
有效项目概念
LR(0)项目集规范族构造
拓广文法
构造闭包
状态转移
2.4.6 LR(0)分析表构造
通过 DFA 构造分析表
举例
根据分析表进行句子识别的部分与 “2.3.4 LR分析示例” 的内容一致,此处不再赘述。
2.5 SLR(1) 文法
2.5.1 引入原因
- LR(0) 出错原因
- LR(0) 方法不够强,容易出现 “移进-归约” 冲突与 “归约-归约” 冲突
- 即 LR(0) 分析表构造中,出现冲突
2.5.2 SLR(1) 解决冲突
- 引入 SLR(1) 文法进行冲突解决
- 简单说,就是加入对 FOLLOW 集的考虑,减少冲突
- 简单说,就是加入对 FOLLOW 集的考虑,减少冲突
2.5.3 SLR(1) 分析表
- 构造算法
- SLR(1) 在分析表构造时只需将 FOLLOW 集考虑进去
- SLR(1) 在分析表构造时只需将 FOLLOW 集考虑进去
按上述方法构造出的 ACTION 和 GOTO 表如果不含多重入口,则称该文法为 SLR(1) 文法。
- 构造示例
2.6 LR(1) 文法
2.6.1 引入原因
- 根本原因
- FOLLOW 集提供的信息太泛,其中有些字符其实并不会出现
- 因此我们需要更加精确的文法来构造分析表
2.6.2 LR(k) 项目
- 扩展 LR(0) 项目,引入展望串
2.6.3 DFA 构造
项目集的闭包
项目集的转换函数
2.6.4 LR(1) 分析表
构造算法
构造示例
2.7 LALR(1) 文法
文法性质
- 项目集个数 = SLR(1)
- 通过合并 LR(1) 中的同心集得到,如果 LR(1) 中原本就没有 “移进-归约” 冲突,则 LALR 中也不会有,但可能会出现 “归约-归约” 冲突
- 文法目的:识别能力比 SLR(1) 更强,但项目集个数一致
同心集合并
- 同心集定义
- 两个集合忽略展望串时,完全相同
- 同心集合并举例
- I5 与 I9 同心,合并后为 I59
- 同心集定义
I5: A -> d·, aB -> d·, cI9: A -> d·, cB -> d·, aI59: A -> d·, a/cB -> d·, a/c
2.8 LR 文法总结
文法能力
- LR(0)、SLR(1)、LALR(1)、LR(1) 文法,前者为后者的真子集
- LR(0)、SLR(1)、LALR(1)、LR(1) 文法,前者为后者的真子集
LR(1) 文法
- 具有规范的 LR(1) 分析表的文法称为 LR(1) 文法
- 使用 LR(1) 分析表的分析器叫做一个规范的 LR 分析器
编译原理完整学习笔记(四):语法分析相关推荐
- HTML4基本编译原理,Stanford公开课《编译原理》学习笔记(1~4课)
课程里涉及到的内容讲的还是很清楚的,但个别地方有点脱节,任何看不懂卡住的地方,请自行查阅经典著作<Compilers--priciples, Techniques and Tools>(也 ...
- Stanford公开课《编译原理》学习笔记(2)递归下降法
[摘要] javascript实现递归下降语法解析 示例代码托管在:http://www.github.com/dashnowords/blogs B站地址:[编译原理] Stanford公开课:[S ...
- Stanford公开课《编译原理》学习笔记(1~4课)
[摘要] 编译原理基础 示例代码托管在:http://www.github.com/dashnowords/blogs B站地址:[编译原理] Stanford公开课:[Stanford大学公开课官网 ...
- 【编译原理】学习笔记以及课程设计
编译原理 教材用的是<编译原理>(第三版)陈火旺著,电子版戳这里密码:x4ut 课后习题答案戳这里密码:nkv9 教学PPT戳这里密码:0tfz PPT习题答案戳这里密码:v9ct (侵删 ...
- 《编译原理》学习笔记 ·002【第二章:文法和语言(形式语言理论)-1】
注:前言.目录见 https://blog.csdn.net/qq_44220418/article/details/108428971 文章目录 零.引言 一.符号串与符号串集合 1.字母表 2.符 ...
- 《编译原理》学习笔记 ·003【第二章:文法和语言(形式语言理论)-2】
注:前言.目录见 https://blog.csdn.net/qq_44220418/article/details/108428971 文章目录 三.文法和语言的分类 1.Chomsky语言分类法 ...
- 《编译原理》学习笔记 ·001【第一章:总论】
注:前言.目录见 https://blog.csdn.net/qq_44220418/article/details/108428971 文章目录 一.编译程序 1.编译程序 2.编译基础设施 3.编 ...
- 【编译原理】学习笔记1 词法分析
进行词法分析,打印分析结果. 编译器是一个程序:输入字符串,输出目标代码. 词法分析: 读入源码字节,将其组成有意义的TOKEN流. 语法分析: 根据TOKEN流构建树形的中间表示. 语义分析: 检查 ...
- 【编译原理】编译原理系统学习与实践系列文章汇总目录(持续更新中)
本文属于「编译原理」系列文章的汇总目录,这一系列正式开始于2021/10/22,着重于「编译原理的学习与实践」.众所周知,编译原理难学难精,因此本系列将至少持续到作者本人「精通编译原理」为止(笑).由 ...
- 【一文弄懂】张正友标定法-完整学习笔记-从原理到实战
张正友标定法-完整学习笔记-从原理到实战 文章目录 张正友标定法-完整学习笔记-从原理到实战 (零)前言: 1 为什么需要标定? 2 相机标定的已知条件和待求解是什么? 标定前的已知条件: 待求信息: ...
最新文章
- initramfs 文件系统
- 查看Oracle中存储过程长时间被卡住的原因
- AMAZING AUCTION (第三届省赛)
- linux——用脚本实现全自动安装虚拟机
- Python描述性统计示例
- 十招搞定SQL2K安全
- 谷歌控制面板中的NetWrok
- gitlab git clone 输入密码_gitlab1:部署gitlab
- php 电梯程序设计,教你写出京东电梯式轮播
- fmc接口定义_STM32接口FSMC/FMC难点详解
- 关于面试时碰到的几个多线程手撕代码题
- 神舟刷蓝天w650dbios_神舟Z7-CT7NA刷入蓝天BIOS破除40W功耗墙
- 【oracle】varchar和varchar2区别
- php网页设计课程设计dreamweaver8_Dreamweaver 8.0 多媒体网页制作教程
- could not find function 函数名
- 洛谷P1510 精卫填海(简单的dp)
- Android 显示软键盘输入法和强制隐藏软键盘输入法
- Elasticsearch应用案例1:百度
- 《淘宝店铺营销推广一册通》一2.2 选择店铺行业
- 【编程语言】Scala下载及安装教程 CentOS 7
热门文章
- 学习之路二十七:三种序列化方式的一些注意点
- WARN No appenders could be found for logger的解决方法
- mysql把字段拆成两个_MySQL数据库中,将一个字段的值分割成多条数据显示
- dbcc checkdb 200g 要多久_东丽区无人驾驶学多久,放心省心_石家庄北方汽修学校
- 初学者C语言输入输出挖坑填补处须知
- Requests 高级用法 —2.18.1 文档
- net core mysql开源框架_.net core 基于Dapper 的分库分表开源框架(core-data)
- elementui表格复制_vue+element-ui做表格的导出功能(一)。
- 15拆分成3个不同的自然数_素数大概有多少个?15岁的高斯翻过素数表之后给出了答案...
- 黄色叹号_平行进口车有质量问题?许多新车都有的黄色感叹号故障灯是什么?...