本文PDF下载
本文章中有些图片可能由于图床的防盗链问题导致加载不出来。本文的PDF下载见下方地址,整理不易,麻烦点个小小的赞😘😘😘
https://download.csdn.net/download/m0_50906780/85413560
一.绪论
1.1 什么是编译
将高级语言翻译成汇编语言或机器语言的过程
1.2 编译系统的结构
词法分析:
从左向右逐行扫描源程序的字符,识别出各个单词,确定单词的类型。
将识别出的单词转换成统一的机内表示——词法单元(token)形式
token:< 种别码,属性值 >
语法分析:
语法分析器(parser)从词法分析器输出的token序列中识别出各类短语,并构造语法分析树(parse tree)
语义分析:
- 收集标识符的属性信息
- 语义检查
中间代码生成器:
- 三地址码:类似于汇编语言的指令序列组成,每个指令最多有三个操作数(operand)
- 语法结构树/语法书
三地址指令的表示:
- 四元式 :(op, arg1, arg2, result)
- 三元式: (op, arg1, agr2)
- 间接三元式:
目标代码生成器:
目标代码生成以源程序的中间表示形式作为输入,并把它映射到目标语言;(中间形式 ==> 目标语言)
目标代码生成的一个重要任务是为程序中使用的变量合理分配寄存器;
代码优化
1.3 编译程序的生成
不用画T形图
1.4 为什么要学习编译原理
1.5 编译技术的应用
二、语言及其文法
2.1 基本概念
串:有穷符号(symbol) 序列
串的连接:xy
串的n次幂:将n个s连接起来
字母表:有穷符号集合
字母表的乘积:笛卡尔积
字母表的n次幂:长度为n的符号串构成的集合
字母表的正闭包:长度正数的符号串构成的集合
字母表的克林闭包:任意符号串(长度可以为零)构成的集合
2.2 文法的定义
G = (VT , VN , P , S )
VT = { apple, boy, eat, little }
VN = { 句子, 名词短语, 动词短语, 名词, … }
P : 产生式集合
S:开始符号
2.3语言的定义
推导:用产生式的右部替换产生式的左部 (生成语言)
规约:(识别语言)
由文法G的开始符号S推导出的所有句子构成的集合称为文法G生成的语言,记为L(G )。
2.4 文法分类
2.5 CFG的分析树
二义性文法:如果一个文法可以为某个句子生成多棵分析树,则称这个文法是二义性的
三、词法分析
3.1 单词的描述
- 正则表达式:描述正则语言
3.2 单词的识别
-
有穷自动机:➢这类系统具有一系列离散的输入输出信息和有穷数目的
内部状态(状态:概括了对过去输入信息处理的状况),系统只需要根据当前所处的状态和当前面临的输入信息就可以决定系统的后继行为。每当系统处理了当前的输入后,系统的内部状态也将发生改变
DFA(确定的有穷自动机)
输入+ 状态 ==> 一个状态
NFA(非确定的有穷自动机)
输入 + 状态 ==> 多个状态
DFA和NFA可以识别相同的语言
正则文法 <=> 正则表达式 <=> FA
带有 ε-边 的NFA
把DFA的状态改成一个NFA可以到达的状态集合就可以了
子集构造法
3.3 词法分析阶段的错误处理
➢词法错误检测
➢如果当前状态与当前输入符号在转换表对应项中的信息为空,而当前状态又不是终止状态,则调用错误处理程序
错误处理: 查找已扫描字符串中最后一个对应于某终态的字符 ➢如果找到了,将该字符与其前面的字符识别成一个单词。 然后将输入指针退回到该字符,扫描器重新回到初始状态,继续识别下一个单词,如果没找到就采用错误恢复
**错误恢复:**采用==“恐慌模式”==,从剩余的输入中不断删除字符,直到词法分析器能够在剩余输入的开头发现一个正确的字符为止
四、语法分析
语法分析的主要任务是根据给定的文法,识别输入句子的各个成分,从而构造出句子的分析树
大部分程序设计语言的语法构造可以用CFG(上下文无关文法)来描述,CFG以token作为终结符
自顶向下的分析(推导)自底向上分分析(归约)这两个方法只能给出某些文法子类,但其表达能力足以描述现代大多语言的语法构造
4.1 自顶向下的分析
可以看成是从开始的S推导出串w的过程
-
最左推导:总是选择每个句型的最左非终结符进行替换
-
-
-
最右推导:总是选择每个句型的最右非终结符进行替换
-
在自底向上的分析中,最左归约成为规范归约,最右推导称为规范推导(自底向上,右导左归)
自顶向下的语法分析采用最左推导的方式
➢总是选择每个句型的最左非终结符进行替换 ➢根据输入流中的下一个终结符,选择最左非终结符的一个候选式
自顶向下语法分析(递归下降分析)
同一非终结符的多个候选式存在共同前缀,会出现回溯现象,左递归文法(A->Aa)会使递归下降分析器陷入无限循环
消除直接左递归(引入一些非终结符和空产生式),把左递归转换成右递归
预测分析是递归下降分析技术的一个特例,通过在输入中向前看固定个数符号来选择正确的A-产生式,向前看K个输入符号的预测分析器——LL(k)文法类,预测分析不需要回溯,是一种确定的自顶向下分析方法
4.2 预测分析法
LL(1) 文法
从文法开始符号出发,在每一步推导过程中根据当前句型 的最左非终结符A和当前输入符号a,选择正确的A-产生 式。为保证分析的确定性,选出的候选式必须是唯一的。
-
S_文法(每个产生式的右部都以终结符开始,同一非终结符的各个候选式的首终结符都不同,S文法不含ε产生式)
-
q_文法 (每个产生式的右部或为ε ,或以终结符开始 ➢具有相同左部的产生式有不相交的可选集 。)
-
LL(1)文法:当且仅当G的任意两个具有相同左部的产生式A -> a|b 满足不存在终结符a使得a和b都能推导出以a开头的串,a和b至多有一个可推导出空。(同一非终结符的各个产生式的SELECT集互不相交)
-
FOLLOW集:FOLLOW(A)(在某个句型中紧跟在A后边的终结符a的集合)
-
SELECT集:SELECT(A->b)(产生式A→β的可选集是指可以选用该产生式进行推导时对应的输入符号的集合,SELECT( A→aβ ) = { a },SELECT( A→ε )=FOLLOW( A ))
-
FIRST集:FIRST(α)(➢给定一个文法符号串α, α的串首终结符集FIRST(α)被定义为可以从α推导出的所有串首终结符构成的集合。如果α => ε, 那么ε也在FIRST(α)中。如果X是一个终结符,那么FIRST(X) = {X},非终结符就递归着看,如果 X→ε∈P,那么将ε加入到FIRST( X )中)
-
计算串X1X2 …Xn的FIRST 集合:先加入X1的FIRST集中的非空符号,如果有空,则依次加入下一个Xi的的所有非空符号,直到没有空为止
-
-
计算SELECT可选集:如果包含空集,select集等于first集;如果不包含,select集等于first集并上它的follow集
-
计算非终结符的FOLLOW集: 把$放入到FOLLOW(S)中;如果有A->aBb,FIRST(b)中除ε之外的所有符号都在FOLLOW(B)中,如果存在一个产生式A→αB,或存在产生式A→αBβ且 FIRST ( β ) 包含ε,那么 FOLLOW( A )中的所有符号都在 FOLLOW( B )中
-
下面是求各个集的例子
-
只有FIRST集中会有空串!!!!
只有FIRST集中会有空串!!!!
只有FIRST集中会有空串!!!!
只有FIRST集中会有空串!!!!
求follow集的讲解:
对于每个非终结符号,我们都可以求出其follow集:
根据(1),首先将 加 入 到 f o l l o w ( E ) 中 , 即 f o l l o w ( E ) = { 加入到follow(E)中,即follow(E)={ 加入到follow(E)中,即follow(E)={},由⑤可知,)也应该在follow(E)中,即follow(E)={$,)};
对于E’,根据规则(3)以及产生式①,应该将follow(E)加入到follow(E‘)中,即follow(E’)={$,)};
对于T,根据规则(2)以及产生式①,应该将first(E’)加入到follow(T)中,即follow(T)={+},根据规则(3),由于first(E’)包含ε,所以应该将follow(E’)加入到follow(T)中,即follow(T)={+,$,)};
对于T’,根据规则(3)以及产生式③,应该将follow(T)加入到follow(T‘)中,即follow(T’)={+,$,)};
对于F,根据规则(2)以及产生式③,应该将first(T’)加入到follow(F)中,即follow(F)={},根据规则(3),由于first(T’)包含ε,所以应该将follow(T’)加入到follow(F)中,即follow(F)={,+,$,)};
select集有终结符号直接加进去,有空串的情况就直接加follow集
LL(1)的分析方法
递归的预测分析法:在递归下降分析中,根据预测分析表进行产生式的选择(根据式子写对应的过程代码)
procedure PROGRAM(TOKEN);
begin
if TOKEN ≠ ‘xxx’ then ERROR;
GETNEXT(TOKEN);
左部名(TOKEN);
end
非递归的预测分析法:维护一个栈结构来模拟最左推导过程
预测分析表是根据相应符号的产生式的SELECT集采取并运算构建的
如果栈顶符号和剩余输入是相同的终结符,则把它们弹栈删除
输出相应结果和把相应结果压入栈中是同时进行的(在同一行上)
预测分析法实现步骤:
1)构造文法
2)改造文法:消除二义性、消除左递归、消除回溯
3)求每个变量的FIRST集和FOLLOW集,从而求得每个候选式的SELECT集
4)检查是不是 LL(1) 文法(同一非终结符的各个产生式的SELECT集互不相交)。若是,构造预测分析表
5)对于递归的预测分析,根据预测分析表为每一个非终结符编写一个过程;对于非递归的预测分析,实现表驱动的预测分析算法
预测分析中的错误检测:
➢两种情况下可以检测到错误
➢栈顶的终结符和当前输入符号不匹配
➢栈顶非终结符与当前输入符号在预测分析表对应项中的信息为空
预测分析中的错误恢复
➢恐慌模式
➢忽略输入中的一些符号,直到输入中出现由设计者选定的同步词法单元(synchronizing token)集合中的某个词法单元
➢其效果依赖于同步集合的选取。集合的选取应该使得语法分析器 能从实际遇到的错误中快速恢复
➢例如可以把FOLLOW(A)中的所有终结符放入非终结符A的同步 记号集合
➢如果终结符在栈顶而不能匹配,一个简单的办法就是弹出此终结符
如果是空,忽略输入的a,如果是synch,弹出栈顶的非终结符A
如果栈顶的终结符和输入符号不匹配,则弹出栈顶的终结符(想想它俩如果相同的话,会同时把他们俩都删除掉)
4.3 自底向上的分析
将输入串w归约为文法开始符号S
自顶向下采用最左推导;自底向上采用最左规约
➢移入-归约分析(Shift-Reduce Parsing)
栈内符号串 + 剩余输入 = 规范句型
每次规约的符号串被称为句柄
移入规约的工作过程
➢在对输入串的一次从左到右扫描过程中,语法分析器将零个或多个输入符号移入到栈的顶端,直到它可以对栈顶的一个文法符号串β进行归约为止 ➢然后,它将β归约为某个产生式的左部 ➢语法分析器不断地重复这个循环,直到它检测到一 个语法错误,或者栈中包含了开始符号且输入缓冲区为空(当进入这样的格局时,语法分析器停止运行, 并宣称成功完成了语法分析)为止
移入规约分析器课采取的四种动作(移入、规约、接收、报错)
每次规约的符号串被称为句柄
存在的问题:错误的识别了句柄
4.4 LR分析法(无二义性)
LR文法(Knuth, 1963) 是最大的、可以构造出相应 移入-归约语法分析器 的文法类
L:对输入进行从左到右的扫描
R:反向构造出一个最右推导序列
LR(k)分析:需要向前查看k个输入符号的LR分析,k = 0 和 k = 1 这两种情况具有实践意义,当省略(k)时,表示k =1
关键就是要正确地识别句柄
sa:将符号a、状态n压入栈
rn:用第n个产生式进行规约
一开始是只有 0 和 $ ,0遇到b把 4和b给压入,之后再输入进来a,4号状态遇到a使用③进行规约,规约成B,之后0号遇到B,看GOTO表会把2号状态压进来。
(个人总结:看状态号和输入的符号进行相应的压栈操作,如果遇到规约操作,把右部的终结符换成非终结符,把原来状态号删掉,再去看GOTO,压入新的状态号)
**LR(k)分析**:需要**向前查看k个输入符号**的LR分析,k = 0 和 k = 1 这两种情况具有实践意义,当省略(k)时,表示k =1
构造给定文法的LR分析表:
➢LR(0)分析
* 在左边,移进项目
* 在中间,待约项目
* 在右边,规约项目
错误!!!
还要去看是终结符还是非终结符
- ➢ 后继项目(Successive Item):同属于一个产生式的项目,但圆点的位置只相差一个符号, 则称后者是前者的后继项目, 比如 A→α· Xβ的后继项目是A→αX·β
增广文法为了使文法开始符号仅出现在一个产生式的左边,从而使得分析器只有一个接受状态
每个项目集闭包对应着自动机的一个状态,从初始状态到某一状态的路径对应的符号序列 代表着某一时刻分析栈中的内容
状态图画法总结:初始状态,各个表达式在左部加上·,之后根据 · 后面的符号进行状态的前进,前进后如果 · 后面是非终结符,则要加上非终结符对应的移进项目产生式。ACTION中是终结符和$;GOTO中是非终结符
不是所有CFG都能用LR(0)方法进行分析,CFG不总是LR(0)文法,其中会产生移进/规约冲突还有规约/规约冲突
➢SLR分析
出现了冲突
SLR分析会根据下一个输入符号的归属,来判断是规约还是移进。
如果是目前可移进的下一个符号,就采用移进
如果是FOLLOW(B)里面的,就采用规约
如果给定的SLR分析表不存在有冲突的动作,就称为SLR文法
➢LR(1)分析
因为SLR中存在着冲突
SLR只是简单地考察下一个输入符号b是否属于与归纳项目A->a相关联的FOLLOW(A)
但是: b∈FOLLOW(A) <== 规约a (可推出)
b∈FOLLOW(A) !=> 规约a (不可推出)
在不同的位置,A会要求不同的后继符号,A的后继符集合是FOLLOW(A)的子集
LR(1)多了一个展望符,表示在当前状态下A后面必须要紧跟的终结符
[A --> αβ,a] 当β等于空的时候会用到展望符a
直到写到·后面是终结符为止
如果除展望符外,两个LR(1)项目集是相同的,则称这两个项目是同心的
如果LR(1)分析表中没有语法分析动作冲突, 那么给定的文法就称为LR(1)文法
➢LALR分析
【同心:如果除展望符外,两个LR(1)项目集是相同的,则称这两个LR(1)项目集是同心的】
合并同心项集不会产生移进-归约冲突,但会产生归约-归约冲突
合并同心项集的时候会产生归约-归约的冲突
LALR分析法可能会作多余的规约动作,但绝不会作错误的的移进操作
LALR(1)的特点
形式上与LR(1)相同
大小上与LR(O)/SLR相当
分析能力介于SLR和LR(1)二者之间
SLR<LALR(1)<LR(1)
合并后的展望符集合仍为FOLLOW集的子集
每个二义性文法都不是LR的!!!!
每个二义性文法都不是LR的!!!!
每个二义性文法都不是LR的!!!!
但是某些类型的二义性文法在语言的描述和实现中很有用,更简短,更自然
遇到错误应该采用恐慌模式或者短语层次的错误恢复
4.5总结:
-
SLR文法:
-
LR(1)文法
-
LALR(1)文法
五、语法制导翻译
语法制导翻译使用CFG来引导对语言的翻译, 是一种面向文法的翻译技术
语法制导翻译【语法分析、语义翻译(语义翻译、中间代码生成)】
为CFG中的文法符号设置语义属性,用来表示语法成分对应的语义信息
需要使用与文法符号所在产生式(语法规则)相关联的语义规则来计算分析树中各个结点对应的语义属性值
将语义规则和语法规则联系起来有两个概念:
- 语法制导定义(SDD)
- 语法制导翻译方案(SDT)
语法制导定义SDD
-
文法符号 <==> 一个语义属性集合
-
产生式 <==> 一组语义规则(用于计算各个文法符号的属性值)
语法制导翻译方案SDT
-
在产生式右部嵌入了语义动作的CFG
-
-
SDD
➢是关于语言翻译的高层次规格说明
➢隐蔽了许多具体实现细节,使用户不必显式地说明翻译发生的顺序
-
SDT
➢可以看作是对SDD的一种补充,是SDD的具体实施方案
➢显式地指明了语义规则的计算顺序,以便说明某些实现细节
5.1 语法制导定义SDD
文法符号——语义属性集合
产生式——一组语义规则
-
综合属性(子节点或结点本身)(向下)
- 通过子节点或结点本身的属性值来定义
- 终结符可以具有综合属性。终结符的综合属性值是由词法分析器提供的词法值,因此在SDD中没有计算终结符属性值的语义规则
-
继承属性(父节点、兄弟节点或结点本身)(向上)
- 只能通过父节点、兄弟节点或结点本身的属性值来定义
- 终结符没有继承属性。终结符从词法分析器处获得的属性值被归为综合属性值
属性文法
一个没有副作用的SDD有时也称为属性文法
属性文法的规则仅仅通过其他属性值和常量来定义一个属性值
SDD为CFG中的文法符号设置语义属性。对于给定的输入串x,应用语义规则计算分析树中各结点对应的属性值,语义规则建立了属性之间的依赖关系(依赖图),在对语法分析树节点的一个属性求值之前,必须首先求出这个属性值所依赖的所有属性值
➢对于只具有综合属性的SDD ,可以按照任何自底向上的顺序计算它们的值
➢对于同时具有继承属性和综合属性的SDD,不能保证存在一个顺序来对各个节点上的属性进行求值
5.2 S-属性定义与L-属性定义
给定一个SDD,很难确定是否存在某棵语法分析树,使得SDD的属性之间存在循环依赖关系
但是存在S-SDD和L-SDD,它们能够保证对每棵语法分析树都存在一个求值顺序,因为它们不允许 产生带有环的依赖图,它们还可以和自顶向下及自底向上的语法分析过程一起高效地实现
S-SDD:仅仅使用综合属性的SDD,其可以按照语法分析树节点的任何自底向上顺序来计算它的各个属性值
L-SDD:在一个产生式所关联的各属性之间, 依赖图的边可以从左到右,但不能从右到左 (因此称为L属性的,L是Left的首字母)。一个SDD是L-SDD,当且仅当它的每个属性要么是一个综合属性,要么是满足如下条件的继承属性:
假设存在一个产生式 A->X1X2...Xn, Xi的继承属性仅依赖于下列属性:
* A的继承属性
* 产生式中Xi左边的符号 X1 , X2 , … , Xi-1 的属性
* Xi本身的属性,但Xi的全部属性不能在依赖图中形成环路
每个S-SDD都是L-SDD
5.3 语法制导翻译方案SDT
语法制导翻译方案(SDT)是在产生式右部嵌入了程序片段(语义动作)的CFG
SDT可以看作是SDD的具体实施方案
SDT可在语法分析过程中实现S-SDD和L-SDD
-
基本文法可以使用LR分析技术,且SDD是S属性的
-
基本文法可以使用LL分析技术,且SDD是L属性的
将S-SDD转换为SDT:将每个语义动作都放在产生式的最后
如果一个S-SDD的基本文法可以使用LR分析技术, 那么它的SDT可以在LR语法分析过程中实现,当归约发生时执行相应的语义动作
将L-SDD转换为SDT:
- 将计算某个非终结符A的继承属性的动作插入到产生式右部中紧靠在A的本次出现之前的位置上
- 将计算一个产生式左部符号的综合属性的动作放置在这个产生式右部的最右端
如果一个L-SDD的基本文法可以使用LL分析技术, 那么它的SDT可以在LL或LR语法分析过程中实现
➢在非递归的预测分析过程中进行语义翻译
➢在递归的预测分析过程中进行语义翻译
➢在LR分析过程中进行语义翻译
5.4 L-属性定义的自顶向下翻译
➢在非递归的预测分析过程中进行语义翻译
注意向栈中加入的时候是这样子加的
T-》M{a3}N{a4}
在栈中先弹出T,再把M,Msyn,{a3},N,Nsyn,{a4}加进去,之后可以根据栈中指针及相对位置来进行相关代码的书写和计算。
如果栈顶(最左边)是非终结符,就按展开式一直展开直到匹配上终结符,都有综合属性,有继承属性的写在本身的下面。
如果栈顶是综合属性的属性值Fsyn(综合记录出栈),也是要弹出,但要看看后面是否会用到它;如果栈顶是继承属性的属性值F.inh(式子为F.inh = T.inh * F.inh),也是要弹出,会用到它的时候把它放到对应的语义动作下面
如果栈顶是动作,就执行该动作
执行代码:
属性:是对应符号里面存储的属性
执行代码:如果是对应的符号则为弹出符号或展开符号时对其继承属性要执行的动作代码;如果是对应的动作则为执行动作时要执行的动作代码(弹出属性时,如果属性在后面还要使用,则把它复制到对应的动作下面)
top的变换:弹出栈(比如属性或者动作)top = top - 1;弹出栈(比如展开一个非终结符)top = top - 1 + 展开后的top增加量
➢在递归的预测分析过程中进行语义翻译
5.5 L-属性定义的自底向上翻译
➢在LR分析过程中进行语义翻译
(修改LL文法为基础的L-SDD,在LR分析中可以用)
给定一个以LL文法为基础的L-SDD,可以修改这个文法,并在LR语法分析过程中计算这个新文法之上的SDD
把语义动作都换成产生空终结符的产生式,语义动作执行和原来相同的任务。这样所有语义动作就都可以移动到式子最右边,转化成类似于S-SDT的形式。
这样修改后的SDT,所有语义动作都位于产生式的末尾了
六、中间代码生成
6.1 声明语句的翻译
收集标识符的类型等属性信息,并为每一个名字分配一个相对地址
名字的类型和相对地址保存在相应的符号表记录中
➢指针构造符pointer
➢ 若T 是类型表达式,则 pointer ( T ) 是类型表达式,它表示一个指针类型
➢笛卡尔乘积构造符
➢ 若T1 和T2是类型表达式,则笛卡尔乘积T1 X T2 是类型表达式
➢函数构造符→
➢ 若T1、T2、…、Tn和R是类型表达式,则T1XT2 X…XTn → R是类型表达式
➢记录构造符record
➢ 若有标识符N1、N2、…、Nn与类型表达式T1 、T2、…、Tn, 则 record ( ( N1 X T1 ) ( N2 X T2 )X …X ( Nn X Tn )) 是一个类型表达式
- 对于声明语句,语义分析主要就是收集标识符的类型等属性信息,并为每一个名字分配一个相对地址
- 从类型表达式可以知道该类型在运行时刻所需的存储单元数量,称为类型的宽度
- 在编译时刻,可以使用类型的宽度,为每一个名字分配一个相对地址
- 名字的类型和相对地址信息保存在相应的符号表记录中
这是一个L属性定义的SDT,如果L-SDD其基础文法是LL(1)文法(具有相同左部的产生式的SELECT可选集是否相同),那么可以在自顶向下的过程中实现这个SDT
6.2 赋值语句的翻译
6.2.1 简单赋值语句的翻译
赋值语句的SDT的主要任务就是生成对表达式求值的三地址码
||是连接的意思,观察到非终结符的code都是后面的code按顺序连接起来,化简,化简成了增量翻译,在增量方法中,gen不仅要构造出一个新的三地址指令,还要把它添加到至今为止已生成的指令序列之后
new temp 会产生一个临时变量
6.2.2 数组引用的翻译
数组引用 ==> 三地址码
关键:数组元素的寻址
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s9yv5XkW-1652919086756)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220514091048573.png)]
6.3 控制语句的翻译
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dnSQ4M0h-1652919086757)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220514091645600.png)]
newlabel():生成一个用于存放标号的新的临时变量L,返回变量地址(只是确定了S的后继指令标号的存放地址,但这个标号的具体值要等S分析完毕之后的语义动作中填入,先预定一个房间)
label(L):将下一条三地址指令的标号存放到地址L中,(完成继承属性的填写)
继承属性B.true和B.false放在B之前,要用newlabel函数生成两个用于存放标号的临时变量,并将函数的返回地址分别赋值给B.true和B.false
&& || !被翻译成跳转指令,运算符本身不出现在代码中,布尔表达式的值是通过代码序列中的位置来表示的
控制流翻译的例子:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FQE2Zura-1652919086759)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220514095227186.png)]
6.4 回填
➢基本思想
➢生成一个跳转指令时,暂时不指定该跳转指令的目标标号。这样的指令都被放入由跳转指令组成的列表中。同 一个列表中的所有跳转指令具有相同的目标标号。等到能够确定正确的目标标号时,才去填充这些指令的目标标号
➢makelist( i )
➢创建一个只包含i的列表,i是跳转指令的标号,函数 返回指向新创建的列表的指针
➢merge( p1 , p2 )
➢将 p1 和 p2 指向的列表进行合并,返回指向合并后的 列表的指针
**➢backpatch( p, i )**
➢将 i 作为目标标号插入到 p所指列表中的各指令中
nextquad是即将生成的下一条指令的标号
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E8cKuMcm-1652919086759)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220514100922490.png)]
M就是为了记录下B2的第一条指令的标号
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lViJNlJk-1652919086760)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220514101521709.png)]
控制流语句的回填
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZR29Rg65-1652919086760)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220514103619680.png)]
➢S.nextlist:指向一个包含跳转指令的列表,这些指令最终获得的目标标号就是按照运行顺序紧跟在S代码之后的指令的标号
根据示意图,我们要用S1的第一条指令来回填B.truelist,要用S2的第一条指令来回填B.falselist,需要记录下 S1、S2的第一条指令的标号。在S1之后要生成跳转指令,因此我们在S1之后设置一个标记非终结符n,用于生成这条跳转指令
6.5 switch语句的翻译
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZfxoCIIH-1652919086763)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220514110244502.png)]
6.6 过程调用语句的翻译
call + 过程的名字id + (Elist即过程的参数表达式列表)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cni5PzTr-1652919086764)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220514111828921.png)]
七、运行存储分配
7.1存储组织
一个目标程序(代码区+数据区)
静态存储分配(编译时刻)
动态存储分配(运行时刻,栈式和堆式)
活动记录:每运行一次所需要管理的信息的存放区域
7.2 静态存储分配(编译)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zv7hWORH-1652919086765)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220514225416328.png)]
常用的静态存储分配方法:
-
顺序分配法
➢按照过程出现的先后顺序逐段分配存储空间
➢各过程的活动记录占用互不相交的存储空间
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-42exf8wm-1652919086765)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220514225543235.png)]
-
层次分配法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iUNDSZUg-1652919086766)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220514225822457.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AcK7rABE-1652919086766)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220514225934490.png)]
7.3 栈式存储分配(运行)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5NRtTCcX-1652919086766)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220514230159894.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CFIQhPfq-1652919086767)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220514230325374.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q9dsPSpB-1652919086767)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220514231333133.png)]
调用序列和返回序列
➢ 调用序列
➢实现过程调用的代码段。为一个活动记录在栈中分配空间, 并在此记录的字段中填写信息
➢ 返回序列
➢恢复机器状态,使得调用过程能够在调用结束之后继续执行
➢ 一个调用代码序列中的代码通常被分割到调用过程(调用者) 和被调用过程(被调用者)中。返回序列也是如此
编译时刻不能确定大小的对象——>堆区
但如果是过程的局部对象——>运行时刻栈中(可以避免对它们的空间进行垃圾回收,也就减少 了相应的开销)
只有一个数据对象局部于某个过程,且当此过程结束时它 变得不可访问,才可以使用栈为这个对象分配空间
7.4 非局部数据的访问
- 访问链:
-
display表
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4s35JC1P-1652919086772)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515092018480.png)]
例子
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w1R3Z2Sh-1652919086773)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515092038688.png)]
7.5 参数传递
-
形式参数
在过程定义中使用的参数
-
实际参数
在调用过程时使用的参数
-
形参和实参相关联的几种方法
➢ 传值(Call- by-Value)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ECatkq8a-1652919086773)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515092450695.png)]
➢ 传地址(Call- by-Reference)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oQizzHVO-1652919086773)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515092600030.png)]
➢ 传值结果(Call- by-Value-Result)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rh8fd8eQ-1652919086774)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515092708155.png)]
➢ 传名(Call- by-Name)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vvXtW2A0-1652919086774)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515092829377.png)]
7.6 符号表
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ndbmKsA9-1652919086774)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515092917057.png)]
符号表上的主要操作:
➢声明语句的翻译(定义性出现)
➢填、查
➢可执行语句的翻译(使用性出现)
➢查
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xYyEgRbL-1652919086774)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515093524890.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yvs5TGDr-1652919086778)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515095210132.png)]
八、代码优化
8.1 流图
- 第一个三地址指令
- 转移指令的目标指令(要跳到的地方的第一个指令,不是goto语句,是要goto的地方)
- 紧跟在转移指令之后的指令
从第一条指令开始,先找goto要到的地方,再加上紧跟在goto后面的指令
以基本块为单位,根据每个基本块的最后一条语句进行分析,可以画出流图
8.2 优化的分类
➢机器无关优化 ➢针对中间代码
➢机器相关优化 ➢针对目标代码
➢局部代码优化 ➢单个基本块范围内的优化
➢全局代码优化 ➢面向多个基本块的优化
常见的优化方法:
-
➢删除公共子表达式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cqNMuUof-1652919086783)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515103101204.png)]
- ➢删除无用代码
➢ 无用代码(死代码Dead-Code ) :其计算结果永远不会被使用的语句
- ➢常量合并
- ➢代码移动
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LErCLiyi-1652919086786)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515105058755.png)]
- ➢强度削弱
➢归纳变量
➢对于一个变量x ,如果存在一个正的或负的常数c使得每次x被赋值时它的值总增加c ,那么x就称为归纳变量(Induction Variable) 归纳变量可以通过在每次循环迭代中进行一次简单的增量运算(加法或减法)来计算
- ➢删除归纳变量
8.3 基本块的优化
➢很多重要的局部优化技术首先把一个基本块转换成为 一个无环有向图(directed acyclic graph,DAG)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HumxUx7M-1652919086789)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515110213907.png)]
首先删除没有附加活跃变量的根节点:G
当一个定值变量表中存在多个定值变量时,我们只需生成一条三地址指令,并将计算结果赋给其中的一条变量,我们倾向于赋给一个活跃变量,删除:M,J,IH
再根据DAG重新编写基本块,删除掉的变量语句不用写,一直是常量的值用常量区代替,处理后的如蓝色小方块所示
8.4 数据流的分析
➢一组用来获取程序执行路径上的数据流信息的技术
➢数据流分析应用
➢到达-定值分析 (Reaching-Definition Analysis)
➢活跃变量分析 (Live-Variable Analysis)
➢可用表达式分析 (Available-Expression Analysis)
到达定值分析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wLNxFSjY-1652919086792)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515113721649.png)]
看di到Bj的过程中,di中的变量是否有被重新定值,如果重新定值,则被杀死
迭代到不发生改变为止,最后可以根据各个基本块的IN值来得到各个入口块的到达定值信息,可以完成上面的√×表
ud链,引用-定值链
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f9tQkuzz-1652919086797)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515114833270.png)]
活跃变量分析(逆向数据流问题)
➢活跃变量(会引用x在p的值)
➢对于变量x和程序点p,如果在流图中沿着从p开始的某条路径会引用变量x在p点的值,则称变量x在点p是活跃(live)的,否则称变量x在点p不活跃(dead)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iGzD5Twi-1652919086797)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515145927458.png)]
在程序中的各个基本块中都没有引用变量a的值,因此a在各个基本块的出口处都不是活跃的
i从B1出来到下一次改变的路径上在B2处被引用,所以i在b1的接口处是活跃的;i从B2出来到下一次改变的路径上在没有被引用,所以是不活跃的,同理可以分析出来B3和B4
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GtERSkIe-1652919086798)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515151717293.png)]
对于B2:i和j的首次出现是以引用形式出现的,所以把它们加入到useB2中去
对于use(在该语句块中首次出现是以引用形式出现)
对于def(在该语句块中首次出现是以定义形式初始)
OUT[B] = 后继所有结点的IN值的并集
IN[B] = useB 加上 (OUT[B] - def[B])
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DfEGMZFr-1652919086801)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515153829754.png)]
可用表达式分析
e_genB:添加表达式的右部,删除与表达式左部相关的式子
e_killB:添加表达式的左部相关的式子,删除表达式的右部
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n4XWJ7Fp-1652919086804)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515154258497.png)]
IN[B] = 所有前驱的OUT集的交集
OUT[B] = genB 加上 (IN[B] - killB)
8.5 流图中的循环
主要算IN[B],OUT[B]就是IN[B]再并上自己本身,IN[B]是其所有前驱结点OUT的交,因为是每条路径,所以要取
回边:有一条被支配结点到支配结点的边(被支配 ==> 支配)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZAA7k8Dl-1652919086806)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515162149880.png)]
自然循环:先把回边的那两个结点加入,再去找可以到被支配结点的结点,从被支配结点的其余前驱按照结点的前驱一个个递归去找即可
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SA9Q8EoK-1652919086806)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515162739823.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SekiPPxy-1652919086807)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515162748154.png)]
8.6 全局优化
➢删除全局公共子表达式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DHRcFnB5-1652919086807)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515163312475.png)]
➢删除复制语句
➢代码移动 (循环不变的检测 + 代码外提)
即想要外提的话:所在块要支配所有出口节点;对X的赋值和引用必须为一对一的关系
➢作用于归纳变量的强度削弱
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v8mUMfMu-1652919086810)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220515170353565.png)]
➢删除归纳变量
九、代码生成
9.1 代码生成器的主要任务
9.2 一个简单的目标机模型
寻址模式
9.3 指令选择
9.4 寄存器的选择
① 先根据指令,先更新寄存器的内容,再更新标识符的内容
② 再根据寄存器的变化删除右部存储在该寄存器的内容(该寄存器有了新的占领者,之前的都不是了)
③ 注意如果是复制语句(x = y)要把两个变量都更新下
④ 结束时,a,d都没有存在对应的地址符下面,说明它们是活跃变量,要加上收尾工作exit,把它们放到对应的地址符下面(ST a,R2)(ST d,R1)
9.5 寄存器选择函数getReg的设计
例子:
➢冗余指令删除
➢控制流优化
➢代数优化
➢机器特有指令的使用
MOOC错题
编译原理之LL(1) 、LR(0)、SLR、LR(1)、LALR文法的对比
(1条消息) 编译原理之LL(1) 、LR(0)、SLR、LR(1)、LALR文法的对比_棉花糖灬的博客-CSDN博客_lr(0)
第一讲、绪论
第二讲、程序设计语言及其文法
三型文法是正则文法
第三讲、词法分析
第四章:语法分析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CqviwpQP-1652919086832)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220519072700423.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JoEHqExK-1652919086832)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220519072618579.png)]
含有公共左因子的文法肯定不是LL1文法,但不含公共左因子的也不一定就是LL1文法。LL1文法可以推出不含公共左因子,但是不含公共左因子推不出LL1文法
把空串加进去还要接着往后看
第五讲:语法制导翻译
返回的永远都是综合属性,继承属性都是作为函数的参数传入进去的。
第六讲:中间代码生成
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3MLaPeRm-1652919086841)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220518234042172.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D2Rolhmt-1652919086841)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/8452/image-20220514112330154.png)]
既不是仅为定义性,也不是仅为使用性
第七章:运行存储分配
局部变量地址在被调用者的数据区
两个临时变量的作用域不相交,分配在统一单元中
第八章:代码优化
没有办法引用B1中的i,因为i在B2中已经被改变了
下面的例子中,没有被改变,相当于u2 u3是隐含存在的没改变的值,没有写到代码中,但是之后被引用了
第九章:代码生成
窥孔优化不是在中间代码层次进行的优化工作!!!
窥孔优化不是在中间代码层次进行的优化工作!!!
窥孔优化不是在中间代码层次进行的优化工作!!!