目标代码生成-基本块与流图.
目标代码生成

(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。
《编译原理》考试试题及答案

《编译原理》考试试题及答案(附录)一、判断题:1.一个上下文无关文法的开始符,可以是终结符或非终结符。
( X )2.一个句型的直接短语是唯一的。
( X )3.已经证明文法的二义性是可判定的。
( X )4.每个基本块可用一个DAG表示。
(√)5.每个过程的活动记录的体积在编译时可静态确定。
(√)6.2型文法一定是3型文法。
( x )7.一个句型一定句子。
( X )8.算符优先分析法每次都是对句柄进行归约。
(应是最左素短语) ( X )9.采用三元式实现三地址代码时,不利于对中间代码进行优化。
(√)10.编译过程中,语法分析器的任务是分析单词是怎样构成的。
( x )11.一个优先表一定存在相应的优先函数。
( x )12.目标代码生成时,应考虑如何充分利用计算机的寄存器的问题。
( )13.递归下降分析法是一种自下而上分析法。
( )14.并不是每个文法都能改写成LL(1)文法。
( )15.每个基本块只有一个入口和一个出口。
( )16.一个LL(1)文法一定是无二义的。
( )17.逆波兰法表示的表达试亦称前缀式。
( )18.目标代码生成时,应考虑如何充分利用计算机的寄存器的问题。
( )19.正规文法产生的语言都可以用上下文无关文法来描述。
( )20.一个优先表一定存在相应的优先函数。
( )21.3型文法一定是2型文法。
( )22.如果一个文法存在某个句子对应两棵不同的语法树,则文法是二义性的。
( )二、填空题:1.( 最右推导 )称为规范推导。
2.编译过程可分为(词法分析),(语法分析),(语义分析和中间代码生成),(代码优化)和(目标代码生成)五个阶段。
3.如果一个文法存在某个句子对应两棵不同的语法树,则称这个文法是()。
4.从功能上说,程序语言的语句大体可分为()语句和()语句两大类。
5.语法分析器的输入是(),其输出是()。
6.扫描器的任务是从()中识别出一个个()。
编译原理目标代码生成

中间代码生成
探讨中间代码的概念、作用和生成方法,包括抽象语法 树、三地址代码等中间表示形式。
代码优化
介绍代码优化的原理和常用技术,如常量折叠、复制传 播、死代码删除等,以提高目标代码的质量。
目标代码生成
详细讲解目标代码生成的过程和方法,包括指令选择、 寄存器分配、汇编语言输出等关键步骤,以及针对不同 目标平台的优化策略。
语义分析
介绍了语义分析的基本任务,如类型 检查、控制流分析、数据流分析等。
中间代码生成
阐述了中间代码的概念、作用及生 成方法,包括抽象语法树、三地址 代码等。
目标代码生成
详细讲解了目标代码生成的过程, 包括指令选择、寄存器分配、优化 等。
对未来编译技术的展望
智能化编译技术
随着人工智能技术的发展,未来编译器可能具备更强的自 主学习能力,能够自动优化代码性能、提高编译效率。
01
指令选择算法
根据目标计算机的指令集和程序语义, 选择最合适的指令来实现程序功能。
02
03
代码优化算法
通过对生成的机器相关代码进行各种 优化(如常量折叠、循环展开等), 提高其执行效率和资源利用率。
06
代码生成器的设计与实现
代码生成器的结构
中间代码生成器
将源程序转换为中间代码形式,便于后续优化和代码生成。
2
编译过程包括词法分析、语法分析、语义分析、 中间代码生成、代码优化和目标代码生成等阶段。
3
编译原理不仅关注如何生成高效的目标代码,还 关注如何提高编译器的可维护性、可移植性和可 扩展性。
目标代码生成的意义
提高程序执行效率
目标代码是计算机直接执行的指令,其执行效率远高于高级语言程序。通过优化目标代码 ,可以提高程序的执行速度。
第9章 目标代码生成

寄存器的使用准则
寄存器先行准则:尽可能把变量的值驻留到寄存器
中,尽可能用寄存器中的现行值,以减少访问内存
的次数。例:
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)
第七章 目标代码的生成

第二段代码较优(少用了寄存器)
基于树重写的代码生成
例
a [ i ] := b 的一个可能的中间表示树
基于树重写的代生成
树重写(Tree Rewriting)规则形如
其中 • replacement 代表树的单个节点 replacement template {cost} = {action}
这一点较难做到,因为执行效率往往与该语句的上下 文以及目标机体系结构(如流水线)有关
指令选择举例
为TAC 语句选择指令模板
假设一个目标机指令系统(一个简单汇编语言)
例 TAC 语句 a:=b+c 可转换为如下代码序列
MOV ADD MOV b, R0 c, R0 R 0, a
/* b 装入寄存器 R0 */ /* c 加到 R0 */ /* 存 R0 到 a */
两遍的通用寄存器分配算法
• 第一遍先假定可用的通用寄存器是无限数量的,完 成指令选择 例如:前面介绍的简单代码生成算法中的 getreg 函数返回一个伪寄存器(不管物理寄存器的个数) • 第二遍将物理寄存器分配到伪寄存器。 物理寄存器数量不足时,会将一些伪寄存器泄露到 (spilled into)内存,图着色算法的核心任务是使 得泄露的伪寄存器数目最少。
T4
T3
T1:=a+b T2:=c+d T3:=e-T2 T4:=T1-T3
T1
+ +
T2
T2:=c+d T3:=e-T2 T1:=a+b T4:=T1-T3
e0 a0 b0 c0 d0
由上述算法从 DAG 生成代码
将上述简单的代码生成算法应用于如下两个基本块
llvm编译流程

llvm编译流程LLVM(低级虚拟机)是一种开源的编译器基础设施,它由多个模块组成,提供了丰富的工具和框架,用于构建编译器前端、后端和优化器等各个部分。
LLVM的编译流程可以分为四个主要阶段:前端、优化器、后端和目标代码生成。
下面将详细介绍每个阶段的工作流程。
1. 前端(Frontend):前端主要负责将源代码转换为中间表示(Intermediate Representation,IR),通常是以 LLVM 的 IR 格式表示。
前端分为词法分析、语法分析和语义分析三个步骤。
- 词法分析将源代码分解为一个个的记号(Tokens),如变量名、关键字、符号等,使用词法分析器(Lexer)实现。
- 语法分析将记号序列转换为语法树(Syntax Tree),它是表示源代码结构的一种树形结构,使用语法分析器(Parser)实现。
-语义分析通过检查语法树的语义信息,如变量的类型、作用域等,进行语义合法性的验证,并进行类型推导、构建符号表等,是一个静态分析的过程。
2. 优化器(Optimizer):优化器对IR进行各种优化,以改进程序的性能和资源利用率。
优化器主要包括高层次优化和低层次优化。
-高层次优化包括数据流分析、控制流图优化和基本块优化等,从程序的整体结构出发,通过改变控制流和数据流的方式,来提高代码的效率。
-低层次优化包括寄存器分配、指令选择、调度和循环优化等,它们针对IR中的每个基本块和指令进行细粒度的分析和优化。
3. 后端(Backend):后端负责将优化后的IR转换为目标机器的汇编代码。
后端通常是针对特定的硬件平台进行优化,生成高效的机器码。
- 选择指令:通过指令选择器(Instruction Selector)将 IR 指令转换为目标机器的指令,同时进行寄存器分配和调度等操作。
-线性扫描寄存器分配:将虚拟寄存器分配给物理寄存器,同时进行寄存器的分配和调度。
-指令调度:对指令进行重排,以便利用指令级别的并行性。
编译原理目录

编译原理目录一、引言。
1.1 编译原理概述。
1.2 编译器的作用和原理。
二、词法分析。
2.1 词法分析的任务和原理。
2.2 正规表达式和有限自动机。
2.3 词法分析器的实现。
三、语法分析。
3.1 语法分析的任务和原理。
3.2 自顶向下分析和自底向上分析。
3.3 语法分析器的实现。
四、语义分析。
4.1 语义分析的任务和原理。
4.2 语义动作和语法制导翻译。
4.3 语义分析器的实现。
五、中间代码生成。
5.1 中间代码的作用和原理。
5.2 三地址码和四元式。
5.3 中间代码生成器的实现。
六、代码优化。
6.1 代码优化的目标和原理。
6.2 基本块和流图。
6.3 代码优化器的实现。
七、目标代码生成。
7.1 目标代码生成的任务和原理。
7.2 寄存器分配和指令选择。
7.3 目标代码生成器的实现。
八、汇编与链接。
8.1 汇编的作用和原理。
8.2 静态链接和动态链接。
8.3 汇编器和链接器的实现。
九、实践与应用。
9.1 编译原理在实际开发中的应用。
9.2 前端与后端的协同工作。
9.3 实践案例分析。
十、总结与展望。
10.1 编译原理的发展历程。
10.2 未来编译原理的发展趋势。
10.3 结语。
在编译原理的学习过程中,我们将深入了解编译器的工作原理和实现方法。
从词法分析到目标代码生成,每个环节都承担着特定的任务,而它们又相互协作,共同完成将源代码翻译成目标代码的过程。
通过本文档的学习,读者将能够全面了解编译原理的核心概念和具体实现,为日后的编译器开发和优化工作打下坚实的基础。
程序设计语言编译原理第三版第10章

§10.2 局部优化
举例:考察下面的三地址代码程序
(1)Read X
(2)Read Y
B1
(3)R:=X mod Y (4)if R=0 goto (8) B2
(5)X:=Y
(6)Y:=R
B3
(7)goto(3)
(8)write Y B4
(9)halt
B1
B2
B3
B4
§10.2 局部优化
3.流图及其生成
标识符(包括常数)-结点 NODE(A)-描述上述对应关系的函数,其值或者是一个结点的编号,
或者无定义
(2)中间代码的三种形式:A:=B A:=op B A:=B op C 或 A:=B[C]
(3)构造算法: ①开始,DAG为空 ②对基本块中每一条中间代码式,依次执行以下步骤:
§10.2 局部优化
步骤: 1.如果NODE(B)无定义,则构造一标记为B的叶结点并定义
NODE(B)为这个结点 如果当前代码是0型,则记NODE(B)的值为n,转4 如果当前代码是1型,则转2(1) 如果当前代码是2型,则(ⅰ)如果NODE(C)无定义,则构造一标 记
为C的叶结点并定义NODE(C)为这个结点;(ⅱ)转2(2)
(1)T0:=3.14 (2)T1:=2*T0 (3)T2:=R+r (4)A:=T1*T2 (5)B:=A (6)T3:=2*T0 (7)T4:=R+r (8)T5:=T3*T4 (9)T6:=R-r (10)B:=T5*T6
(4)代数变换
§10.2 局部优化
二、基本块的DAG表示及其应用
1.基本块的DAG:
一种结点带有下述标记或附加信息的DAG
(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 ))
目标代码的生成第8章

8.1.2 目标代码
本章采用汇编语言代码作为目标代码,但不针对某种特 定的目标机指令系统或汇编语言来生成目标代码,而是假设 有一台计算机,其指令系统等均按某种需要而设定,为教学 目的往往采取这种虚拟机目标代码形式。
2.按真转编写程序
8.2.2 虚拟机的汇编指令
3.按假转编写程序
8.3 从中间代码生成目标代码
8.3.1 从逆波兰表示生成目标代码 8.3.2 从四元式序列生成目标代码
8.3.1 从逆波兰表生成目标代码
从表达式的逆波兰表示生成相应的目标代码的算法可给出如下。 首先设立一个运算分量栈(栈),用来存放暂时不能处理的运算 分量的名(即工作单元地址)以及中间运算结果的名(即存放中间结 果的工作单元地址或累加器AC)。 其具体算法步骤如下。 从左到右扫描所给定的逆波兰表达式中的每个符号: 若扫描到运算分量,则将其下推入运算分量栈。 若扫描到运算符,按该运算符是几目运算,把运算分量栈 中相应个数的栈顶元素取出,生成该运算相应的目标代码,此后 栈上退去相应个数的运算分量,运算结果存放在“AC”中,把“AC” 标志入运算分量栈。 如此继续,直到整个逆波兰表达式处理完毕为止。
该虚拟机是一台地址单累加器的计算机,用“AC”表示该 累加器;设OP为操作码,d为地址,则指令: 0P d
表示 AC OP d=>AC
即累加器AC中的内容与d中的内容进行某种运算,结果送 到累加器AC中;其内存容量足够大;提供了21条符号汇 编指令。
8.2.2 虚拟机的汇编指令
虚拟机的汇编指令如表8.1所示。
精品文档-编译原理基础(第二版)(刘坚)-第6章

第6章 代 码 生 成
【例6.3】 图6.1(b)中有三个循环: (1) B3自身是一个循环。 (2) B6自身是一个循环。 (3) { B2,B3,B4}是一个循环。 前两个循环仅有一个节点和一条指向自身的边。例如 B3构成一个以B3为入口节点的循环。根据定义6.3的第(2) 条性质,循环中必须有一条非空的指向入口节点的路径, 此处是从B3到B3。因为,单一节点B2没有一条从B2到B2的 边,所以它不是循环,因为在{B2}中没有从B2到其自身的 非空路径。
பைடு நூலகம்
第6章 代 码 生 成
为每个基本块构造一个节点,并且若B是C的前驱(或 者说C是B的后继),则从B到C有一条边,最终得到流图如 图6.1(b)所示。
入口指向基本块B1,因为B1包含程序的第一条指令。 B1的唯一后继是B2,因为B1不以无条件跳转结束且B2的头 指令紧随B1的结束之后。
第6章 代 码 生 成
定义6.1 一段顺序执行的语句序列被称为一个基本块, 其中,第一条语句被称为基本块的入口,最后一条语句被称为基本 块的出口。
由于基本块中的语句是被顺序执行的,因此基本块的控制 流总是从入口进入,从出口退出。任何一个复杂的程序控制流,均 可以划分为若干个基本块;极端情况下,一条语句构成一个基本块。 因此可以将一段完整的程序表示为一个程序流图。
候被使用。如果一个变量的值当前在寄存器中并且以后再也 不被使用,则该寄存器就可以分配给其他变量。
第6章 代 码 生 成
定义6.4 在形如(i) x := y op z的三地址码中,出现在 “:=”左边和右边的变量分别被称为对变量的定值和引用,i 被称为变量的定值点或引用点。若变量的值在i之后的代码序 列中被引用,则称变量在i点是活跃的。若变量x在i点被定值, 在j点被引用,且从i到j没有x的其他定值,则称j是i中变量x 的下次引用信息,所有这样的下次引用信息jk(k = 1, 2, …) 构成一个下次引用链。
《编译原理》教学大纲

《编译原理》教学大纲一、课程概述编译原理是计算机科学与技术专业的一门重要课程,也是软件工程领域的基础课程之一、本课程通过对编译器的原理和实现技术的学习,使学生掌握编译器的设计和实现方法,培养学生独立解决实际问题的能力。
二、教学目标1.理解编译器的基本原理和工作流程;2.掌握常见编译器的构建方法和技术;3.能够设计和实现简单的编译器;4.培养分析和解决实际问题的能力。
三、教学内容和教学进度1.第一章:引论1.1编译器的定义和分类1.2编译器的基本工作流程2.第二章:词法分析2.1编译器的基本结构2.2词法单元的定义和识别方法2.3正则表达式和有限自动机3.第三章:语法分析3.1语法分析的基本概念3.2语法规则的定义和表示方法3.3自顶向下的语法分析方法3.4自底向上的语法分析方法4.第四章:语义分析4.1语义分析的基本概念4.2属性文法和语法制导翻译4.3语义动作和符号表管理5.第五章:中间代码生成5.1中间代码的定义和表示方法5.2基本块和控制流图5.3三地址码的生成方法6.第六章:优化6.1优化的基本概念和原则6.2常见的优化技术和方法6.3编译器的优化策略7.第七章:目标代码生成7.1目标代码生成的基本原理7.2目标代码的表示方法和存储管理7.3基本块的划分和目标代码生成算法8.第八章:附加主题8.1解释器和编译器的比较8.2面向对象语言的编译8.3并行编译和动态编译四、教学方法1.理论教学与实践相结合,注重教学案例的分析和实践;2.引导学生主动探索,注重培养学生的自主学习能力;3.激发学生的兴趣,鼓励学生提问和讨论。
五、考核方式1.平时成绩:包括课堂测验、作业和实验报告等;2.期末考试:闭卷笔试,主要考查学生对编译原理的理论知识和实践能力的掌握程度。
六、参考教材1.《编译原理与技术》(第2版),龙书,机械工业出版社,2024年2.《现代编译原理-C语言描述》(第2版),谢路云,电子工业出版社,2024年七、参考资源1. 实验环境:Dev-C++、gcc、llvm等2.相关网站:编译原理教学网站、编译器开源项目等八、教学团队本课程由计算机科学与技术学院的相关教师负责教学,具体安排详见教务处发布的教学计划。
目标代码生成(1)

U (^,^)→(4,y)→(3,y)→(^,^)
V (^,^)→(4,y)→(^,^)
W (^,y)→(^,^)
19
待用信息和活跃信息的表示
(x, x)表示变量的待用信息和活跃信息
第1元
i表示待用信息, ^表示非待用
(^,^)
右操作数
(^,^)
(^,^)
(4,y) (^,^)
2. 从基本块出口到入口由后向前依次处理各个四 元式。对每一个四元式i:A:=B op C,依次执行:
1) 把符号表中变量A的待用信息和活跃信息附加 到四元式i上
2) 把符号表中A的待用信息和活跃信息分别置为 “非待用”和“非活跃”
3) 把符号表中变量B和C的待用信息和活跃信息附 加到四元式i上
4
代码生成
代码生成
把语法分析后或优化后的中间代码变换成目标代码
目标代码的三种形式
绝对指令代码:能够立即执行的机器语言代码,所有地址 已经定位
可重新定位指令代码:待装配的机器语言模块,执行时, 由连接装配程序把它们和某些运行程序连接起来,转换成 能执行的机器语言代码
汇编指令代码:尚须经过汇编程序汇编,转换成可执行的 机器语言代码
4) 把符号表中B和C的待用信息均置为i,活跃信 息均置为“活跃”
23
例:基本块 1. T:=A-B 2. U:=A-C 3. V:=T+U 4. W:=V+U
设W是基本块出口之后的活跃变量。 建立待用信息链表与活跃变量信息链表如下:
24
附加在四元式上的待用/活跃信息表
序号 四元式 左值 左操作数 右操作数
第11章 目标代码生成

– 及时腾空:在离开基本块时,把存在寄存器 中的现行的值放到主存中。
19Байду номын сангаас
11.3.1 待用信息
• 如果在一个基本块内,四元式i对A定值, 四元式j要引用A值,而从i到j之间没有A 的其他定值,那么,我们称j是四元式i的 变量A的待用信息。(即下一个引用点) i: A:=B op C … j: D:=A op E • 假设在变量的符号表登记项中含有记录 待用信息和活跃信息的栏。
32
1 尽可能用B所在的寄存器 2 后尽可能用空闲寄存器 3 抢占用非空闲寄存器
3 从已分配的寄存器中选取一个Ri为所需要的寄 存器R。最好使得Ri满足一下条件: 占用Ri 的变量的值也同时存放在该变量的贮存 单元中,或者在基本块中要在最远的将来才会 引用到或不会引用到。 要不要为Ri中的变量生成存数指令?
31
• 寄存器分配:GETREG(i: A:=B op C) 返 回一个用来存放A的值的寄存器
1 尽可能用B独占的寄存器 2 后尽可能用空闲寄存器 3 抢占用非空闲寄存器 1 如 果 B 的 现 行 值 在 某 个 寄 存 器 Ri 中 , RVALUE[Ri]中只包含B,此外,或者B与A是 同一个标识符,或者B的现行值在执行四元式 A:=B op C之后不会再引用,则选取Ri为所需 要的寄存器R,并转4; 2 如果有尚未分配的寄存器,则从中选取一个Ri 为所需要的寄存器R,并转4;
1
源程序 表 词法分析器 单词符号 语法分析器 语法单位 出
格
错
管
中间代码生成器 四元式 优化段 四元式 目标代码生成器 目标代码
处
理
理
2
• 代码生成是把语法分析后或优化后的中间 代码变换成目标代码。
目标代码生成

编译程序最后一个阶段是目标代码生 成。它通常在语义分析后或者优化后的中 间代码上进行,并将中间代码转化为等价 的目标代码。
本章主要介绍
简单代码生成器的设计和构造方法
9.1 概述
我们知道,编译程序的最终目的是 将源程序翻译成等价的目标程序,为了 达到此目的,编译程序除了对源程序进 行词法分析、语法分析和语义分析外, 还必需将语义分析后或者优化后的中间 代码转换为等价的目标代码。
9.3
简单代码生成器
当翻译一个四元式如A=B op C时, 我们需要知道在基本块中还有哪些四元 式要对变量A、B、C进行引用。 2. 建立每个变量的待用信息和活跃信息 (1)待用信息
9.3
例
简单代码生成器
A在(i)定值 A在(j)引用
(i) A=T1 (j) T2 =A OP X
(j)为四元式(i)变量A的待用信息
9.3
简单代码生成器
(2) 活跃变量
基本块中所有的非临时变量均看 作基本块出口之后的活跃变量,临时 变量根据其在基本块出口之后是否被 引用来确定它是否为活跃变量。
9.3
简单代码生成器
(3) 计算变量待用信息和活跃信息 的算法:
输入:基本块及其入口语句号和 出口语句号 输出:附加待用信息和活跃信息 的基本块
依次把四元式变换成目标代码, 并在一个基本块内考虑如何充分利用 寄存器。 在设计代码生成器时,为考虑充分 利用寄存器,我们须要考虑下面两点:
9.3
简单代码生成器
1. 给出寄存器的分配原则
(1)把基本块内还要使用的变量的值 尽可能地保存在寄存器中; (2)在基本块内,把不再使用的变量 所占用的寄存器及时释放掉; (3)当到基本块出口时,将变量的值 存放在内存中。
根据代码自动生成流程图

根据代码自动生成流程图流程图作为一种图形化的工具,可以帮助开发人员更好地理解和分析程序的逻辑结构。
然而,手动绘制流程图不仅耗时耗力,而且容易出错。
为了解决这个问题,许多开发人员开始寻找自动生成流程图的方法。
本文将介绍一种根据代码自动生成流程图的方法。
1. 代码解析要自动生成流程图,首先需要对代码进行解析。
代码解析是将源代码转化为抽象语法树(Abstract Syntax Tree,简称AST)的过程。
AST是一种以树形结构表示源代码的方法,每个节点代表了代码中的一个语法结构。
代码解析可以使用各种工具和库来实现,例如Python中的ast模块。
将代码解析为AST后,我们就可以遍历AST树,获取代码中的各个语法结构。
2. 构建流程图模型获取到代码的AST后,我们需要根据AST构建一个流程图模型。
流程图模型由节点和边组成,节点代表代码中的每个语法结构,边代表语法结构之间的关系。
在构建流程图模型时,需要考虑代码中的条件语句、循环语句等控制流结构。
条件语句可以用条件节点表示,循环语句可以用循环节点表示。
条件节点和循环节点可以通过边连接起来,形成条件分支和循环结构。
3. 生成流程图有了流程图模型后,我们就可以根据模型生成流程图。
流程图可以使用各种绘图工具来实现,例如Graphviz等。
通过绘图工具,我们可以将流程图模型转化为可视化的流程图。
在生成流程图时,可以使用不同的图形元素来表示不同的语法结构,例如矩形框表示节点,箭头表示边。
通过调整图形元素的位置和连线的方式,可以使得流程图更加清晰和易于理解。
4. 实例演示下面我们以一个简单的Python程序为例,演示根据代码自动生成流程图的过程:def calculate_sum(n):sum =0for i in range(n):if i %2==0:sum += ireturn sumresult = calculate_sum(10)print(result)首先,我们将这段代码解析为AST。
目标代码生成

R1 …
R7
15
寄存器分配算法
• 一般在生成四元式A:=B OP C的代码中,通常把左操作 数B取到寄存器 R 中,再和C 操作( C可在内存中,也可 在寄存中),R中的结果就是A的值,或者说A占用了R. • 寄存器的分配可以用RGEREG(QUAD,R)实现,QUAD是 待分配寄存器的四元式: i: A:=B OP C , (OP,B,C,A) ; R是分配的寄存器。 (算法需查看附在四元式i上的活跃与引用信息及上表中 的结构)
Jrop P’;
7
§9.3 代码生成程序的雏形
• 为每个基本块的生成高质量代码:
– 总的指令条数要少; – 尽可能利用寄存器,少产生访问内存的指令,为 此需要充分合理的利用寄存器:
• 尽可能把后面还要引用的变量仍保存在寄存器中; • 应把不再使用的变量所占用的寄存器及时释放掉; • 为此需引入两个概念:基本块内变量的引用信息和 活跃信息。
end end;
13
四元式的附加信息
序 四元式 号 1 (-, A, B, T) 2 (+ , A, B, A) 3 (-, A, C, U) 4 (+, C, D, V) 5 (+, T, B, V) 6 (+, V, U, W) 结果 (5,Y) (3,Y) (6,Y) 左变 量 (2,Y) 右变 量 (2,Y)
符号表的变化情况
A (N, Y)→(3, Y)→(N, N)→(2, Y)→(1,Y)
B (N, Y)→(5, Y)→(2, Y)→ (1, Y) T (N, N)→(5, Y)→(N, N) C (N, Y)→(4, Y)→(3, Y) U (N, Y)→(6, Y)→(N, N)
编译原理 代码生成2(2)

case 2
movl $0,-4(%ebp) incl -4(%ebp) incl -4(%ebp) movl -4(%ebp),%eax movl -4(%ebp),%edx addl %edx,%eax incl -4(%ebp) addl -4(%ebp),%eax pushl %eax pushl $.LC0 call printf
+ t6
prod0
* t5
=[] t4 =[] t2
* t1,t3
ab
4
i0
•基本块DAG构造
(1) t1 := 4 * i (2) t2 := a [ t1 ] (3) t3 := 4 * i (4) t4 := b [ t3 ] (5) t5 := t2 * t4 (6) t6 := prod + t5 (7) prod := t6 (8) t7 := i + 1 (9) i := t7 (10) if i <= 20 goto (1)
y–x R
判别R非负(实施转移)
- 根据条件码转移
如 if x < y goto z :
cmp x, y
jg z // 若y > x则转z
AT&T汇编简介
•语法
INSTR Source, Dest e.g.
movl (%ecx), %eax
addl $1, %edx
•前缀与后缀
% -- 寄存器前缀,如 %eax, %ebp $ -- 立即数前缀,如 ,
•内存寻址方式
leal (%ebx, %ecx) , %eax %ebx + %ecx %eax
这里scale缺省为1。scale 和 disp 中的立即数不 加前缀$。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
(9) j:=j-1 (11) t5:=a[t4] (13) (14) (15) (16) (17) (18) (19) (20) (21) (22) t6:=4*i x:=a[t6] t7:=4*i t8:=4*j t9:=a[t8] a[t7]:=t9 t10:=4*j a[t10]:=x goto (5) B
3
例:给以下四元式序列划分基本块。
(1)read C (2)A=0 (3)B=1 (4)L1 : 1 (7)goto L1 (8)L2 : write A (9)halt
根据划分基本块的算法可以 确 定 四 元 式 (1)(4)(6)(8) 是 入 口语句; (3)(5)(7)(9)是出口语 (1)read C 句,因此分为四个基本块
(2)A=0 (3)B=1
(4)L1: A=A+B (5)if B≥C goto L2
(6) B=B+1 (7) goto L1
(8)L2: write A (9)halt
4
Pascal程序片断:
i:=1; while (i<=10) do begin a[i]:=a[i]+b[i]; i:=i+1 end
– 有一个条件/无条件转移语句从B1的最后一条语句转移 到B2的第一条语句; – B1 的最后一条语句不是转移语句,并且在程序的语句 序列中,B2紧跟在B1之后。
6
流图示例:
B1 (1) i:=1 B2 (2) if i<=10 goto B4 B3 (3) goto B5 B5 (17) ……
B4 (4) t1:=4*i (5) t2:=a-4 (6) t3:=4*i (7) t4:=a-4 (8) t5:=t4[t3] (9) t6:=4*i (10) t7:=b-4 (11) t8:=t7[t6] (12) t9:=t5+t8 (13) t2[t1]:=t9 (14) t10:=i+1 (15) i:=t10 (16) goto B2
B5
B6
8
流图:
(5) (7)
(1) (3)
i:=m-1 t1:=4*n
(2) j:=n (4) v:=a[t1]
B1
i:=i+1 t3:=a[t2]
(6) t2:=4*i (8) if t3<v goto (5) B2 (10) t4:=4*j (12) if t5>v goto (9) B3
B2
B1 B2 B3 B4
B5
5
流图
把控制信息加到基本块集合中,形成程序的有向 图,称为流图(控制流图) 流图的结点是基本块 如果一个结点基本块的入口语句是程序的第一条 语句,则称此基本块结点为首结点。 如果在某个执行序列中,基本块 B2 紧跟在基本块 B1 之后执行,则从 B1 到 B2 有一条有向边, B1 是 B2的前驱,B2是B1的后继。即如果:
第 9章
目标代码生成
知识点:基本块、程序流图 下次引用信息 代码生成算法
9.2 基本块与流图
基本块:是指程序中一组顺序执行的语句序列,其 中只有一个入口语句和一个出口语句。
– 具有原子性的一组连续语句序列。 – 控制从第一条语句流入,从最后一条语句流出,中途没 有停止或分支
如:
t1:=a*a t2:=b*b t3:=t1+t2
(1) i:=0 (2) if i<=10 goto (4) (3) goto (17) (4) t1:=4*i (5) t2:=a-4 (6) t3:=4*i (7) t4:=a-4 (8) t5:=t4[t3] /* t5=a[i] */ (9) t6:=4*i (10) t7:=b-4 (11) t8:=t7[t6] /* t8=b[i] */ (12) t9:=t5+t8 (13) t2[t1]:=t9 (14) t10:=i+1 (15) i:=t10 (16) goto (2) (17) …
B3
if i>=j goto (23) B6
B4 B6
(23) (24) (25) (26) (27) (28) (29) (30) t11:=4*i x:=a[t11] t12:=4*i t13:=4*n t14:=a[t13] a[t12]:=t14 t15:=4*n a[t15]:=x
B2
B3
B4
(14) (15) (16) (17) (18) (19) (20) (21) (22) (23) (24) (25) (26) (27) (28) (29) (30)
t6:=4*i x:=a[t6] t7:=4*i t8:=4*j t9:=a[t8] a[t7]:=t9 t10:=4*j a[t10]:=x goto (5) t11:=4*i x:=a[t11] t12:=4*i t13:=4*n t14:=a[t13] a[t12]:=t14 t15:=4*n a[t15]:=x
7
举例
基本块划分:
(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) i:=m-1 j:=n t1:=4*n v:=a[t1] i:=i+1 t2:=4*i t3:=a[t2] if t3<v goto (5) j:=j-1 t4:=4*j t5:=a[t4] if t5>v goto (9) if i>=j goto (23) B1
基本块:
t1:=a*a t2:=a*b t3:=2*t2 t4:=t1+t3 t5:=b*b t6:=t4+t5
2
基本块的划分方法
确定入口语句,下面的语句是入口语句:
– 三地址代码的第一条语句(若从四元式序列确定基本块的 入口语句,则四元式序列的第一个语句) 2. 确定基本块的出口语句: – goto语句转移到的语句 (1) 下一个入口语句的前导语句 – 紧跟在goto语句后面的语句 (2) 转移语句(包括转移语句本 身) 确定基本块,与每一个入口语句相应的基本块: (3) 停语句(包括停语句本身) – 从一个入口语句(含该语句)到下一个入口语句(不含) 入口语句和出口语句之间组成 之间的语句序列 一个基本块。 – 从一个入口语句(含该语句)到停止语句(含该语句)之 间的语句序列