第一章——编译原理概述
词法分析:确定单词的词性
语法分析:识别语句中的短语,获得句子结构
语义分析:根据句子结构,识别各个短语在句子总充当什么成分
词法分析
任务:从左到右,逐行扫描源程序的字符,识别出各个单词,确定单词的类型,将识别出的单词转换成统一的机内表示------token形式
token< 种别码 , 属性值 >
例子
语法分析
任务:从词法分析器输出的token序列中识别出各类短语,并构造语法分析树
语义分析
任务:
- 收集标识符的属性信息
- 种属
- 类型
- 存储位置,长度
- 值
- 作用域
- 参数和返回值信息
- 语义检查
中间代码
中间表示形式
- 三地址码
- 有三个操作数的指令
- 指令表示
- 四元式
- 三元式
- 简介三元式
- 四元式
- 语法结构树/语法树
第二章——语言及文法
字母表与串
字母表:是一个有穷符号集合
字母表的运算:
- 字母表的乘积
- 字母表的幂运算
- 字母表的正闭包
-
字母表的克林闭包
串
串上的运算
- 连接
- 幂运算
文法定义
- 终结符:不可再分,最基本符号,也被称为token
- 非终结符:还能推出其他语法成分(终结符和非终结符统称为文法符号)
- 产生式:组合成串的方式。
- 开始符号:该文法中最大的语法成分
语言的定义
推导与规约
用产生式的右部推导出左部
判断某一词串是否是该语言的句子
句型和句子
文法的分类
0型文法(产生式左部有非终结符)
1型文法(右部比左部长)
2型文法(左部为非终结符)
3型文法(有部的左或右开始为终结符)
四种文法的关系
上下文无关文法的分析树
分析树是推导的图形化表示
句型的短语
二义性文法
如果一个文法可以为某个句子生成多颗分析树,则称这个文法是二义的
正则表达式
描述正则语言的更紧凑的表示方法
正则定义
有穷自动机(FA)
词法分析
FA模型
最长字串匹配原则
有穷自动机的分类
确定的有穷自动机(DFA)
一个状态出度只有一个,很确定
非确定的有穷自动机(NFA)
不确定,到哪,有很多出度
DFA和NFA的等价性
从正则表达式到有穷自动机
过程
RE->NFA->DFA
例子
NFA->DFA
dfa的每个状态都是一个由nfa中的状态构成的集合,即nfa的状态集合的一个子集
转换表中,新的集合的任何子集也作为状态变化条件
构建转换表过程,把一个条件能到达的所有状态组成一个集合
第四章-语法分析
按照分析树的构造方向分为
自顶向下分析
自底向上分析
自顶向下分析
从分析树的顶部(根节点)向底部方向构造分析树。
最左推导(自定向下)
最右推导(自底向上)
文法转换(并不是所有文法都适合自顶向下,这时需要进行文法改造)
问题
左递归文法
消除直接左递归
两步(
引入新的非终结符A`(用来产生无数字符)
用新非终结符构建原来非终结符)
消除直接左递归的一般形式
消除间接左递归
LL(1)文法
递归下降分析当分析错误的时候会回溯,为避免回溯,预测正确的步骤被称为预测分析,
LL(1)文法可以使用预测分析。
非终结符的后继符号集(FOLLOW)
(跟在后边的终结符集合)
aBC
B的FOLLOW集,看C的值
产生式可选集(SELECT)
(遇到这个输入符号就可以使用这个产生式)
输入那些字符串可以使用这些可选集
串首终结符集(FIRST)
(一个文法符号(例如非终结符)能推出来的所有句子的首终结符)
(1)如果FIRST(a)推不出来空,那么只有当输入的字符是a的首非终结符才能用,A->a
也就是SELECT(A->a)=FIRSR(a)
(2)如果能推出空,那么就把空串踢出去,然后结合A->空的情况,也就是FOLLOW(A),
SELECT(A->a)=((FIRST(a)-空)U FOLLOW(A) )
LL(1)文法
一切的本质是保证select集不相交
(1)a,b不能推导出空,也就是说SELECT(A->a|b)=FIRST(a|b),此时为保证不用回溯所以要每一个推导式得出的FIRST()不相同,也就是FIRST(a)n FIRST(b)=空
(2)若都推出空串,那么他们的select集都会有FOLLOW(A),会相交因此不能都推出空串
(3)如果b推导出空,那么他的select集中有FOLLOW(A),因此
FIRST(a) n FOLLOW(A)=空
a同理
FIRST集和FOLLOW集的计算
FIRST集
· 步骤
- 若x是终结符,则FIRST为其本身
- 若其为非终结符,看图,若推出空串,则层层加入FIRST集
- 记得空串
多个串联合的FIRST集
计算非终结符A的FOLLOW(A)
重复 三步
- 将$放入follow(s)中,s是开始符号
- 正常推:看后边文法字符串的FIRST集
- A->aB,那么FOLLOW(B)=FOLLOW(A)
递归的预测分析法
(消消乐,从起始语句开始)
- 依次检测输入的字符串
- 根据检测的字符串,和当前栈顶的文法字符串判定使用哪一个文法(依据表)
- 直至栈顶与检测中的字符串相同,两方都出栈
- 继续下一次
预测分析中的错误处理
错误恢复(遇见错误,输出错误,栈中弹出当前文法串)
例子
自底向上的语法分析
移入-归约分析
每次归约的符号串被称为句柄
直接短语中的最左直接短语为该句型的句柄。
- 非归约是
- 依次检测输入的字符串
- 根据检测的字符串,和当前栈顶的文法字符串判定使用哪一个文法(依据表)
- 直至栈顶与检测中的字符串相同,两方都出栈
- 继续下一次
- 移入归约分析
- 将输入字符串依次移入栈中,直至符合某一条文法(移入)
- 根据文法,改变栈中的文法串(归约)
LR分析法
LR的基本原理
LR分析表结构
具体操作
有两个动作:sn移入,rn归约
- 初始状态0
- 输入一个字符串,判断动作
- 若为sn(移进),则进栈,改变状态
- 若为rn(归约),则归约为新的字符,新字符与GOTO中的状态跳转比较,改变状态
LR(0)分析法(右边合成左边)
LR(0)中的项目
增广文法 (使得产生式左部只有一个开始符号,使分析器只有一个接收状态)
例子
当原点后面存在非终结符时,他就有等价项目
LR(0)自动机
规约状态进行操作,没有跳转
构建自动机
- 找出等价项目,化为闭包
- 闭包中每一项都有一个状态改变过程(识别过程 )
构建
- 从状态0开始,一个个列出识别到的字符后进入的状态
- 若为终结符,则移入栈,改变状态,sn
- 若为非终结符,在GOTO表中添加跳转状态,跳转到归约状态
- 若为规约状态,看对应的产生式,rn
冲突
LR(0)会产生移入归约冲突,证明并不是所有文法都适合LR(0)
SLR
基本思想(引入FOLLOW集,解决一定的冲突)
让新进来的字符清晰的分为归约,移入两个阵营
LR(1)分析
进一步缩小SLR的范围,考虑特定位置的厚后继符
S->L=R.,$:只有S后边跟的是$时才能归约
等价项目
主要看的是展望符
例子
- 从初始生成式开始,找出所有的等价项目,形成第一个闭包,
- 遍历闭包中所有项目(每一种状态)
- 在遍历生成的碧波的项目
- 直至生成归约状态
除展望符外,两个LR(1)项目集是相同的,则称这两个LR(1)项目集是同心的
LALR文法
基本思想(合并同心项目集)
合并了展望符
展望符与移入无关,因此其不影响移入
合并同心项目集时产生归约-归约冲突
会推迟错误的发现
二义性文法的特点
LR分析中的错误处理
恐慌模式错误恢复
短语层次错误恢复
第五章-语法制导翻译
什么是语法制导翻译
语法分析就是把人能看懂的,变成机器能看懂的
语法制导翻译的基本思想
文法符号设置与之对应的语义属性 表示语义信息
语法规则设置与之对应的语义规则 来计算语义属性
SDD与SDT是一个连接桥梁
语法制导定义 (SDD)
文法符号-----语义属性
例子
语法制导翻译方案(SDT)
SDT可以看作是SDD的具体实现方案
SDD
规则对应
文法符号对应
综合属性
通过子节点或本身
继承属性
父节点和兄弟节点(把兄弟当父亲?)
例子
每个节点都有属性的分析树成为注释分析树
属性文法
SDD求值顺序
求自己前,先求出依赖
依赖图
例子
继承属性节点左边,综合属性节点右边
addtype()为副属性
属性值的计算顺序
拓扑排序例子
大的都可以通过小的来计算出来lianliang
综合属性与继承属性的计算顺序
两类SDD(俩属性定义)
S-属性定义
只有综合属性,可以按照自底向上完成属性计算
L-属性定义 (对继承属性进行限制)
在一个产生式所关联的各个属性之间,依赖图可的边可以从左到右,但不能从右到左
子节点的继承属性只能依赖父节点的继承属性(父节点的综合属性,可以依赖子节点,防止形成环)
子节点只能依赖左边兄弟的属性
例子
左部的都是综合属性,右部的都是 继承属性,值判断继承属性就可以知道是不是L类型
SDT
再产生式右部嵌入程序片段
S—SDD转换为SDT
L-SDD转换为SDT
分别定义了继承属性和综合属性的动作放在哪
L属性定义的SDT实现
分为三中实现方法,非递归,递归,LR分析过程中
在非递归的预测分析过程中进行翻译(自顶向下)
1、扩展语法分析栈
2、将语义动作转化为动作符号
第六章-中间代码的生成
学习各种语句的翻译(声明语句,赋值语句,控制语句,过程调用语句)
类型表达式
例子
声明语句的翻译
主要任务:收集类型信息,分配地址
具体操作
把语义动作作为同等与文法符号的存在,构造语法树,
当栈顶是 语义动作时,执行语义动作,
是文法符号时正常翻译(与输入指针的内容匹配,选择生成式,直到生成式生成的内容与输入指针相同,ll(1)).
赋值语句的翻译
任务生成对表达式求值得三地址码
数组引用的翻译
控制流语句及其SDT
(选择,循环)
第七章-运行存储分配
存储空间分配
工作过程中,必须为程序出现的对象分配运行时得存储空间,
- 可以定大小的称为:静态存储分配
- 不能定大小得称为:动态存储分配
- 栈式存储分配
- 堆式存储分配
活动记录(过程-程序,活动-函数)
静态存储分配
分配方法
- 顺序分配法
- 层次分配法(分析调用关系,其中无相互调用的,尽量使其共享存储空间)
- 从底向上分配空间
- 层次分配算法(实现层次分配,主要是关系矩阵得建立)
动态存储分配
栈式调用
活动树(描述程序进入离开各个活动的情况,兄弟节点按顺序执行)
调用序列和返回序列
非局部数据的访问
嵌套深度(类似作用域链)
访问链
访问链的建立
符号表
源程序中各个名字的属性信息,存放在符号表中
通常为每一个作用域创建一个独特的符号表