第9章 目标代码生成
目标代码生成

(1 2 ) h a lt B 5
图7–1 程序流图
[解答] (1) 考虑变量a的情况:基本块B2中没有对a进行 定值,且引用的次数为1(e=a−b);基本块B3没有对a进 行定值,也没有引用a;基本块B4对a进行了定值,并 且定值前引用的次数为1(a=a−f)。根据执行代价节省数 的计算公式得到:
③ 删除RVALUE [Ri]中的M; (4) 给出R,返回。
例7.2 对例7.1,假设只有AX和BX是可用寄存器,用代码 生成算法生成目标代码和相应的RVALUE和AVALUE。
表7.2 例7.2的目标代码
四元式
目标代码
RVALUE
AVALUE
T=A−B U=A−C V=T+U
MOV AX, A SUB AX, B
和A是同一标识符,或者B在该四元式之后不再被引用,则选取Ri为所
需寄存器并转(4)。
不行则选用空闲寄存器
(2) 如有尚未分配的寄存器,则从中选取一个Ri为所需寄存器并转(4)。 再不行则选用待用位置最远的变量占用的寄存器
(3) 从已分配的寄存器中选取一个Ri为所需寄存器R。选取原则为:占用 Ri的变量的值也同时放在内存中,或者该值在基本块中要在最远的位置 才会引用到。这样,对寄存器Ri所含的变量和变量在内存中的情况必须 先做如下调整:
(1) 在原代码生成算法中,仅当变量在基本块中被定值时,其值才 存放在寄存器中。现在把寄存器固定分配给某变量使用,当该变量 在基本块中被定值前,每引用它一次就可以少访问一次内存,则执 行代价节省1。
(2) 在原代码生成算法中,如果某变量在基本块中被定值且在基本 块出口之后是活跃的,则出基本块时要把它在寄存器中的值存放到 内存单元中。现在把寄存器固定分配给某变量使用,出基本块时就 无需把它的值存放到其内存单元中,则执行代价节省2。
变量名符号表

ENTER过程完成。
说明部分的分析与处理(程序)
• 说明类型的定义: • object= (constant, variable,procedur) • (定义纯量/枚举类型) • 名字表的定义 table:array[0..txmax] of
record name:alfa; • case kind:object of
表也是一个栈,栈顶指针为level。当进入一个新过程时,level增加1;每当退 出一个过程时,level减1。DISPLAY(level)总是指向当前正在处理的最内层的 过程的子符号表在栈符号表中的起始位置。
.在符号表的信息栏中引入一个指针域(previous)用以链接它在同一过程内 的前一域名字在表中的下标(相对位置)。每一层的最后一个域名字,其 previous之值为0。这样,每当需要查找一个新名字时,就能通过
地址ble表的下标指针tx补充说
明:
tx 6 (9)
LE 1
V BLOCK
tx ...
0
(6)
LE 0 V BLOCK
主程
序
tx是BLOCK的 实际值参
BLOCK(LEV+1,TX, …) (递归进入分程序)
第1次调用block BLOCK(0, 0, …)
编译程序按名字的不同种属分别使用许多符号 表,如常数表、变量名表、过程名表等等。
SUBROUTINE INCWAP(M,N)
10 K=M+1
M=M+4 N=K RETURN END
经编译头三阶段后所产生的主要表格有: 符号 名表SNT、常数表CT、入口名表ENT、标号 表LT和四元式表QT
符号名表SNT
几种通常都是需要的。 1 符号名 2 符号的类型 3 符号的存储类别 4 符号的作用域及可视性 5 符号变量的存储分配信息 6 符号的其它属性(1) 数组内情向量 (2) 记录结构型的成员信息(3) 函数及过程
编译原理课后习题答案-清华大学-第二版

if〈条件〉then〈语句〉[else〈语句〉] (2) 扩充 repeat 语句为:
repeat〈语句〉{;〈语句〉}until〈条件〉
答案: 对 PL/0 语言作如下功能扩充时的语法图和 EBNF 的语法描述如下:
(1) 扩充条件语句的语法图为:
EBNF 的语法描述为: 〈条件语句〉::= if〈条件〉then〈语句〉[else〈语句〉]
地址,用以过程执行结束后返回调用过程时的下一条指令继续执行。 在每个过程被调用时在栈顶分配 3 个联系单元,用以存放 SL,DL, RA。
第5题
PL/0 编译程序所产生的目标代码是一种假想栈式计算机的汇编语言,请说明该汇编语 言中下列指令各自的功能和所完成的操作。 (1) INT 0 A (2) OPR 0 0 (3) CAL L A
第2题
一个典型的编译程序通常由哪些部分组成?各部分的主要功能是什么?并画出编译程 序的总体结构图。
答案: 一个典型的编译程序通常包含 8 个组成部分,它们是词法分析程序、语法分析程序、语
义分析程序、中间代码生成程序、中间代码优化程序、目标代码生成程序、表格管理程序和 错误处理程序。其各部分的主要功能简述如下。
优化和目标代码生成(PPT课件)

• 代码优化在整个编译过程的位置
源程序 编译前端 中间代码 中间代码生成 中间代码 目标代码生成 目标程序 中间代码 中间代码优化 目标代码优化
程序员和编译器可能改上程序的位置
源程序 编译前端 中间代码 目标代码生成 目标程序
程序员可以改进 算法,改变循环
编译器可以改进过程调 用、循环和地址计算
编译器可以利用寄存器, 选择指令和窥孔优转换
3
7.1.1 数据类型
类型的合法性检查是判断数据类型是否与上下文的要求一致 数据类型是对该类型数据(变量或常量)的取值是否合法以 及对该类型数据的运算是否合法的一种说明。
4
7.1.2 数据结构
一个程序设计语言如允许使用的数组、记录、字符串、 表、栈等形式的数据结构,在编译程序中应为它们提供相 应的翻译。 为了能对数据结构中的元素进行引用,必须完成从逻辑结 构到能够访问这些数据元素的物理结构的映射。应考虑: 1映射算法相对简单,根据逻辑结构容易计算出物理地址 2从逻辑结构投影到物理结构时,不至于超界或存储溢出 3使用的数据结构承担这种程序设计语言的主要功能 4在这些数据结构定义相关的运算
25
• 指令选择
– 一个编译程序可以看成是一个转换系统,它把源程序转换成 等价的目标代码,也就是说,对源语言种各种语言结构,依 据语义确定相应的目标代码结构,即确定源语言于目标语言 之间的对应关系,确保正确实现语义。显然,能否建立这样 的关系直接影响到编译程序的质量。 – 目标机器指令系统的性质决定了指令选择的难以程度,指令 系统的一致性和完备性直接影响到这种对应关系的建立。如 果目标机器能一致地支持各种数据类型和寻址方式,不需特 别处理例外,这种对应关系的建立就容易得多。 – 指令执行速度和机器特点对产生目标代码的质量也十分重要。 显然,如果指令集合丰富的目标机器对于某种操作可提供集 中处理的时候,应该选择效率高、执行速度快的一种。
编译原理第三版课后习题答案

编译原理第三版课后习题答案编译原理是计算机科学中的一门重要课程,它研究的是如何将高级程序语言转换为机器语言的过程。
而《编译原理》第三版是目前被广泛采用的教材之一。
在学习过程中,课后习题是巩固知识、提高能力的重要环节。
本文将为读者提供《编译原理》第三版课后习题的答案,希望能够帮助读者更好地理解和掌握这门课程。
第一章:引论习题1.1:编译器和解释器有什么区别?答案:编译器将整个源程序转换为目标代码,然后一次性执行目标代码;而解释器则逐行解释源程序,并即时执行。
习题1.2:编译器的主要任务是什么?答案:编译器的主要任务是将高级程序语言转换为目标代码,包括词法分析、语法分析、语义分析、中间代码生成、代码优化和目标代码生成等过程。
第二章:词法分析习题2.1:什么是词法分析?答案:词法分析是将源程序中的字符序列划分为有意义的词素(token)序列的过程。
习题2.2:请给出识别下列词素的正则表达式:(1)整数:[0-9]+(2)浮点数:[0-9]+\.[0-9]+(3)标识符:[a-zA-Z_][a-zA-Z_0-9]*第三章:语法分析习题3.1:什么是语法分析?答案:语法分析是将词法分析得到的词素序列转换为语法树的过程。
习题3.2:请给出下列文法的FIRST集和FOLLOW集:S -> aAbA -> cA | ε答案:FIRST(S) = {a}FIRST(A) = {c, ε}FOLLOW(S) = {$}FOLLOW(A) = {b}第四章:语义分析习题4.1:什么是语义分析?答案:语义分析是对源程序进行静态和动态语义检查的过程。
习题4.2:请给出下列文法的语义动作:S -> if E then S1 else S2答案:1. 计算E的值2. 如果E的值为真,则执行S1;否则执行S2。
第五章:中间代码生成习题5.1:什么是中间代码?答案:中间代码是一种介于源代码和目标代码之间的表示形式,它将源代码转换为一种更容易进行优化和转换的形式。
第九章 目标代码生成(1)

SYMBL[X( L )]
…L
a
yyy
b
yy
c
yy
d
yy
t1 n y y n
t2 n y n
t3 n y n
t4
nyn
t5
nyn
x
yn
9.1.3 寄存器的分配问题
寄存器操作快且指令短,如何充分利用它?
⒈ 设置描述表: RDL(R0,R1,…, Rn):
用以记录寄存器的当前状态:如 RDL.R1=x 如何为
此外还有下述 操作码 op :
逻辑 运算
LT(<),GT(>),EQ(==),LE(<=),GE(>=),NE(!=) AND(&&),OR(||),NO(!)
※ 四元式目标代码翻译示例:
【例9.1】
⑴( + a b t1 ) ⑵( - t1 d t2 )
①LD R0,a ②ADD R0,b ③SUB R0,d
※ 附有活跃信息的四元式:
⑴(+ a(y) b(y) t1(y ) ) ⑵(* a(y) t1(y) t3(y) ) ⑶(/ t1(y) t3(n ) x(y) ) ⑷(= t1(n) _ i(y ) )
Ⅲ. 基本块内活跃信息求解算法
• 支持: ⑴ 在符号表上增设一个信息项( L )
name … L
⑴(+ a( y ) b( y ) t1( y )) ⑵(- c( y ) d( y ) t2( y )) ⑶(* t1( y )t2( n )t3( y ))
⑷(- a( y ) t3( n )t4( y )) ⑸(/ t1( n ) 2 t5( y )) ⑹(+ t4( n )t5( n ) x( y ))
(完整word版)期末复习——判断题

判断题第一章1.源语言是编写被编译的程序使用的语言。
(√)2. 解释执行与编译执行的根本区别在于解释程序对源程序没有真正进行翻译。
(╳)3. “遍”是指对源程序从头到尾扫描一遍,并做相应的加工处理。
( ╳ )4. 编译程序是将源程序翻译成等价的目标程序的程序。
(√)5. 宿主语言是目标机的目标语言(╳)6. 编译程序是应用软件(╳)第二章1.NFA和DFA的区别之一是映射函数是否唯一。
(√)2.FA的初始状态可以是多个。
(√)3. 若一个文法是递归的,则它所产生语言的句子个数必定是无穷的。
(√)4. 存在这样的语言,它能被确定的有穷自动机识别,但不能用正规表达式表示。
(╳)5. 设有字母表V,则V T ∩V N=Φ。
( √ )6. 有文法G1=G2,则L(G1)=L(G2)。
( ╳ )7.文法等价是指所描述的语言是完全相同的。
(√)8.一个确定有限状态自动机中,有且仅有一个唯一的终态。
(╳)9.设R和S分别是字母表∑上的正规式,则有L(R|S)=L(R)∪L(S)。
(√)10.自动机M1和M2的状态数不同,则二者必不等价。
(╳)11.确定有限自动机以及非确定有限自动机都能正确地识别正规集。
(√)12.对任意一个右线性正规文法G,都存在一个NFA M,满足L(G)=L(M)。
(√)13.对任何正规式e,都存在一个NFA M,满足L(M)=L(e)。
(√)14.从一个句型到另一个句型的推导过程是唯一的。
(╳)15、最右推导是最右规约的逆过程,最左推导是最左规约的逆过程。
(× )16.一张转换图只包含有限个状态,其中有一个被认为是初态,最多只有一个终态。
(╳)17.二义文法不是上下文无关文法。
(╳)18、对能用有限自动机描述的一个语言,该语言的一子集所构成的语言也一定能用有限自动机来描述。
(×)19、对任意文法G,都存在相应的正规式与之等价。
(× )20、对文法G中的一个句子,如果能够找到两种以上的推导,则该句子是二义性的。
编译原理及编译程序构造答案

编译原理及编译程序构造答案【篇一:编译原理课后习题答案】译程序在逻辑功能上由哪几部分组成?答:编译程序主要由以下几个部分组成:词法分析、语法分析、语义分析、中间代码生成、中间代码优化、目标代码生成、错误处理、表格管理。
2. 实现编译程序的主要方法有哪些?答:主要有:转换法、移植法、自展法、自动生成法。
3. 将用户使用高级语言编写的程序翻译为可直接执行的机器语言程序有哪几种主要的方式?答:编译法、解释法。
4. 编译方式和解释方式的根本区别是什么?答:编译方式:是将源程序经编译得到可执行文件后,就可脱离源程序和编译程序单独执行,所以编译方式的效率高,执行速度快;解释方式:在执行时,必须源程序和解释程序同时参与才能运行,其不产生可执行程序文件,效率低,执行速度慢。
1第二章1. 乔姆斯基文法体系中将文法分为哪几类?文法的分类同程序设计语言的设计与实现关系如何?答:1)0型文法、1型文法、2型文法、3型文法。
2)2. 写一个文法,使其语言是偶整数的集合,每个偶整数不以0为前导。
答:z?sme | bs?1|2|3|4|5|6|7|8|9 m?? | d | md d?0|s b?2|4|6|8 e?0|b n? d|ndd? 0|1|2|3|4|5|6|7|8|9请给出句子123、301和75431的最右推导和最左推导。
答:n?nd?n3?nd3?n23?d23?123n?nd?ndd?ddd?1dd?12d?123 n?nd?n1?nd1?n01?d01?301n?nd?ndd?ddd?3dd?30d?301n?nd?n1?nd1?n31?nd31?n431?nd431?n5431?d5431?75431n?nd?ndd?nddd?ndddd?ddddd?7dddd?75ddd?754dd?7543d? 754313. 设文法g为:4. 证明文法 s?ises|is| i是二义性文法。
答:对于句型iises存在两个不同的最左推导:s?ises?iises s?is?iises所以该文法是二义性文法。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
寄存器的使用准则
寄存器先行准则:尽可能把变量的值驻留到寄存器
中,尽可能用寄存器中的现行值,以减少访问内存
的次数。例:
1. (:=, 10, X) 2. (×, X, X, t1) 3. (-, X, t1, t2) 4. (:=, t2, X)
执行 1 后,把10装入到某寄存器
RX中,而不送到X的内存单元, 这样,2、3、4就可以直接从RX 中取值,而不用访问内存单元了
end GetReg
例:中间代码(三地址码): (1) t1 := z * 6 (2) x := -4 (3) if x >= 76 goto (7) (4) x := x + 4 (5) y := t1 + x (6) goto (3)
指令种类
• 赋值 MOV • 比较 CMP • ≥转移 JLE • 转移 JMP • 累加 ADD • 相乘 MUL
寄存器的分配原则是选择代价最小的寄存器,这就涉 及到代价如何计算的问题。如果申请的是空闲寄存器,则 代价自然为0,否则属于剥夺性质。当一个寄存器R被剥夺 时,R的一些占有变量的现行值可能不在内存中,而且以后 可能引用,因此要产生一些回送现行值的Store指令(ST) 和重新装入寄存器的Load指令(LD)。则R的分配代价包括:
DL:取D(Dead)或 L(Live)。如果从K+1中间
代码开始,到A重新被赋值或基本块结束都没有引
用A,则A的DL值为D;否则为L。DL值在中间代码
步骤确定。例如:
1. (+,a,b,t1) 2. (-,t1,c,t2) 3. (×,t2,b,t3) 4. (:=,t3,x)
(+,D,L,L) (-ቤተ መጻሕፍቲ ባይዱD,D,L) (×,D,D,L) (:=,D,D)
生成实际的目标机代码需结合目标机进行。 例如:有无间接寻址、寄存器是否够、有无较好 的特殊指令等。
9.2、临时变量
(1)临时变量的特点
最大的特点是寿命短。因此,可采取与源变 量不同的空间分配和释放方法,即:不等到作用 域结束,而是用完立即释放,这样就可以实现存 储单元的共享。
(2)临时变量的存储空间
9 静态分配:给每个临时变量一律分配一个AR 单元(按共享法静态分配)
9 动态分配:只当需要保存于内存中时才分配 ,其余时候仅使用寄存器。
考虑静态分配情况下,临时变量的存储分配问题:
定值点:如果 i 中间代码给临时变量T定值,则称 i 为 T 的定值点;
引用点:如果 j 中间代码使用临时变量T,则称 j 为 T 的引用点。
(2)寄存器的状态描述
如果系统有取之不尽的寄存器,问题就简单得多,因 为不用剥夺正被占用的寄存器。但使问题复杂化的原因正 是寄存器不够。为了正确且有效地使用可分配的寄存器, 需要记录寄存器的状态。
寄存器的状态表
为实现以上准则,需要对寄存器的状态表进行有效的管 理和分配,我们将考虑基本块上的寄存器分配。对于某 个基本块中的中间代码 K: (Op, A, B, C) ,假设寄存器 中存放了变量A,则用二元组(DL, SNS)表示变量A的状态:
用R0实 现累加
(8) MOV R0, R3
(9) ADD R0, R2
(10) ST R0, Y
(11) J (5) (12) … …
每次循环都送 回内存,因为 循环可能终止
寄存器活跃准则:至少有一个下次引用时,才分配 寄存器。又假设有(+,A,B,T),且B有下次引 用,则产生指令:
LD RT, A LD RB, B ADD RT, RB
寄存器多载准则:在一个寄存器里存放多个变量的 值。例如赋值语句 Y:=X,那么可让Y和X占同一寄 存器。
(3)寄存器的分配
• 输入: – 中间代码序列:后缀式、三地址代码、树 – 符号表中的信息
• 输出:目标代码 – 绝对机器代码:所有地址均已定位,可立即执行 – 可再定位机器指令代码:连接定位后可立即执行 – 汇编指令代码:经汇编程序生成可执行的代码
• 目标机: – 包含多通用寄存器、控制栈、堆 – 指令的选择:例如代码 a:=a+1的实现 – 寄存器的分配:选择哪些变量驻留在寄存器中及具体 寄存器的选择
代码生成阶段必须指定各变量应占存储中的 哪个单元,因此它也必须计算临时变量所需的存 储空间大小,才能分配存储单元。(注:源变量 的空间在生成符号表时已计算出)
我们在学习“运行时的存储空间”一章时知道,在一 个过程内被声明的变量都要占栈区的AR单元,且不 能共享。但对于临时变量来说则不同,应尽量共享 。这时可有两种处理方法:
例2:
1
2
t1
t2 i (i>2)
i+1
i+2 t3 i+3
j (j>i+3)
t4
j+1
t5 k (k>j+1)
k+1
t1:[1, i+2] t2:[2, i]
Offset = m Offset = m+1
t3:[i+1, j]
Offset = m+1
t4:[i+3, k+1] Offset = m
1: ( +, a, b, t1 ) 2: ( -, t1, c, t2 ) 3: (×, t2, d, t3 )
t1: [1,2] t2: [2,3] t3: [3,4]
则它们的活动区间 彼此不严格相交, 可共享
4: ( :=, t3, x )
临时变量的作用域如同配对的括号序列所管辖的区域 一样是层次嵌套的。因此,可以设想用一个栈来存放这类 临时变量的值。为简单起见,假定所有临时变量值只需要 一种同一长度的栈单元。
把寄存器中的现行值送回内存的Store指令的总代价 把新变量的值装入寄存器的Load指令的总代价
关于代价的定义:
访问寄存器的代价视为0 访问内存的代价视为1 操作的执行代价视为1
例如:
1. LD A,Reg
{Cost = 2}
2. ST Reg,Memory {Cost = 2}
• 计算顺序的选择: – 有些顺序用到较少寄存器,从而能提高效率。
9.1、目标代码的种类
(1)虚拟目标代码
产生虚拟目标代码(针对并不存在的机器编 写)的好处是便于编译器的移植。
(2)实际目标代码
与虚拟目标代码不同,实际目标代码是针对 实际存在的机器设计的,因此需要有将虚拟代码 转换成实际目标机代码的代码生成器。
寄存器分配
一般寄存器 – R0 R1
专用寄存器 – R2 (循环变量) – R3 (存放t1)
目标代码:
(1) LD R0, Z
(2) MUL R0, 6
(3) MOV R3, R0
(4) MOV R2, -4
(5) CMP R2, 76
(6) JLE (12)
t1值下 次还用
(7) ADD R2, 4
SNS:取S(Store)或 NS。如果存放A的寄存器
要被剥夺,且A当前值要进行保存,则A的SNS值要
取S,否则取NS。SNS值要在目标代码步骤确定。
既然DL值可从中间代码精确求到,那么关键的是SNS值的 确定问题。即:什么时候要把寄存器的值送回内存呢?我们 有如下结论:
如果现行值已在内存中,则不需要回送 现行值不在内存,但该现行值再没有下次的引用,则
活动区间:如果 i 是T的定值点,j 是T的最后引用点,称[i,j]为T的活动 区间。
活动区间不严格相交:有活动区间[i,j]和[m,n],如果j≤m或n≤i,则 称它们不严格相交。
静态分配的基本思想:如果两个临时变量的活动区间不严格相交,则可 以共享单元。
例1:有x := d× (a+b-c),其中间代码为:
C := 2;
while true do begin
Rset := {R’ | FreeRegCost(R’) = C}
if Rset ≠ Φ then begin R := Distant(Rset); Exit end;
C := C + 2;
//代价是2的倍数
end
end
FreeReg(R)
//产生Store指令,将占有R的变量送回内存
第九章 代码生成
代码生成部分属于编译器的后端,它与 目标机器和操作系统相关,目标代码生成的 好坏直接影响编译器的性能。
代码生成器的设计主要考虑如何生成高 质量的目标代码。衡量目标代码的质量主要 从占用空间和执行效率上考虑,这就跟寄存 器的使用方法密切相关,其中最难处理和开 销最大的问题就是寄存器的分配问题。
3. Mult Reg1,Reg2 {Cost = 1}
下面给出一个基于代价的寄存器分配算法。设Rset为可用的寄 存器集合,Distant(Rset)表示Rset中内容被下次引用最远的 寄存器。则:
Procedure GetReg( R:RegAddr );
begin
if (存在R0使得FreeRegCost(R0) = 0) then R := R0 else begin
t5:[j+1, k]
Offset = m+1
9.3、代码生成概要
步骤:
• 为中间代码中的各变量(包括源变量和临时变量)分配 寄存器
• 对于每条中间代码,参照目标机允许的代码形式,进行 翻译
目标机器模型:
• 指令形式:
• 某些指令的意义
LD Ri , B ST Ri , B JX CMP A, B
把B单元内容取到寄存器Ri中 把寄存器Ri 的内容存到B单元 无条件转向X单元(JLE为>=跳转)
也不需要回送。
其中第一条容易实现;而第二条中则如何确定一个基本块 内变量值没有下次引用则是一个很复杂的问题。