编译原理第10章目标程序运行时的组织
编译原理模拟试卷和答案
![编译原理模拟试卷和答案](https://img.taocdn.com/s3/m/8fcefad39ec3d5bbfd0a74e5.png)
北京语言大学网络教育学院《编译原理》模拟试卷一注意:1.试卷保密,考生不得将试卷带出考场或撕页,否则成绩作废。
请监考老师负责监督。
2.请各位考生注意考试纪律,考试作弊全部成绩以零分计算。
3.本试卷满分100分,答题时间为90分钟。
4.本试卷分为试题卷和答题卷,所有答案必须答在答题卷上,答在试题卷上不给分。
一、【单项选择题】(本大题共10小题,每小题2分,共20分)在每小题列出的四个选项中只有一个选项是符合题目要求的,请将正确选项前的字母填在答题卷相应题号处。
1、一个编译程序中,包含词法分析、()、中间代码生成、代码优化、目标代码生成等五个部分。
[A] 语法分析[B] 文法分析[C] 语言分析[D] 解释分析2、词法分析器用于识别()。
[A] 字符串[B] 语句[C] 单词[D] 标识符3、语法分析器则可以发现源程序中的()。
[A] 语义错误[B] 语法和语义错误[C] 错误并校正[D] 语法错误4、下面关于解释程序的描述正确的是()。
(1) 解释程序的特点是处理程序时不产生目标代码。
(2) 解释程序适用于COBOL 和FORTRAN 语言。
(3) 解释程序是为打开编译程序技术的僵局而开发的。
[A] (1)(2)[B] (1)[C] (1)(2)(3)[D] (2)(3)5、解释程序处理语言时, 大多数采用的是()方法。
[A] 源程序命令被逐个直接解释执行[B] 先将源程序转化为中间代码, 再解释执行[C] 先将源程序解释转化为目标程序, 再执行[D] 以上方法都可以6、编译过程中, 语法分析器的任务就是()。
(1) 分析单词是怎样构成的(2) 分析单词串是如何构成语句和说明的(3) 分析语句和说明是如何构成程序的(4) 分析程序的结构[A] (2)(3)[B] (2)(3)(4)[C] (1)(2)(3)[D] (1)(2)(3)(4)7、编译程序是一种()。
[A] 汇编程序[B] 翻译程序[C] 解释程序[D] 目标程序8、文法G 所描述的语言是()的集合。
编译原理第10章运行时的存储组织与分配
![编译原理第10章运行时的存储组织与分配](https://img.taocdn.com/s3/m/cb99c66af12d2af90242e6c9.png)
10.2 静态存储分配
在编译阶段由编译程序实现对存储空间的管理,为 源程序中的变量分配存储单元。
条件
➢在编译时能够确定变量在运行时的数据空间大小 ➢运行时不改变
编译原理第10章运行时的存储组织与 分配
FORTRAN程序的静态分配
编译原理第10章运行时的存储组织与 分配
动态存储分配 在目标程序运行阶段由目标程序实现对存
再见,see you again
2020/12/13
编译原理第10章运行时的存储组织与 分配
编译原理第10章运行时的存储组织与 分配
练习 下面程序的运行结果是什么?如果把第6行的(i+1)*fact( )改 成fact( )*(i+1)的话,则程序的运行结果是有什么变化?试分析 为什么会有这两种不同的结果。 int fact( ) { static int i=5; if(i==0) return 1; else { i--; return((i+1)*fact( )); //第6行 }} main( ) { printf("factor of 5!=%d\n",fact());}
为运行阶段实现存储奠定基础
编译原理第10章运行时的存储组织与 分配
教学内容
• 10.1 存储组织概述 • 10.2 静态存储分配 • 10.3 栈式动态存储分配 • 10.4 堆式动态存储分配
编译原理第10章运行时的存储组织与 分配
10.1 存储组织概述
运行时存储空间的划分
代码空间
目标代码空间 静态数据空间
储空间的组织与管理,为源程序中的变量分 配存储单元 特点 • 在目标程序运行时进行分配 • 编译时为运行阶段设计好存储组织形式,即为每个 数据项安排好它在数据区中的相对位置
编译原理目标程序运行时的存储组织
![编译原理目标程序运行时的存储组织](https://img.taocdn.com/s3/m/3ee4e5201fb91a37f111f18583d049649b660ea2.png)
编译原理目标程序运行时的存储组织引言在编译原理中,目标程序是指通过编译器将高级源代码转换为机器可执行的程序。
在目标程序运行时,需要一定的存储空间来存储程序的指令和数据。
本文将介绍编译原理中目标程序运行时的存储组织的基本概念和原理。
程序的内存模型目标程序在运行时的存储组织是通过内存模型来描述的。
内存模型定义了目标程序在内存中的存储方式和访问机制。
常见的内存模型有栈式模型、堆式模型和段式模型等。
栈式模型栈式模型将程序的内存划分为栈和堆两部分。
栈用于存储程序的局部变量、函数调用和返回地址等信息,而堆用于动态存储分配,如动态创建的对象以及通过malloc等函数分配的内存。
栈式模型的存储空间是连续分配的,栈的大小是固定的,而堆的大小可以根据需要进行动态调整。
堆式模型堆式模型将程序的内存划分为堆和栈两部分。
堆是动态分配的内存空间,用于存储程序运行时动态创建的对象和变量。
栈则用于存储函数调用的临时变量、函数参数和返回地址等信息。
堆式模型的存储空间可以动态调整,但需要手动管理内存的分配和释放,以避免内存泄漏和内存碎片的产生。
段式模型段式模型将程序的内存划分为若干个段,每个段用于存储特定类型的数据。
常见的段包括代码段、数据段、堆段和栈段等。
代码段用于存储程序的指令,数据段用于存储常量、全局变量和静态变量等数据,堆段和栈段与堆式模型和栈式模型类似。
段式模型可以更灵活地管理不同类型的数据,提高了内存的利用率。
存储器分配在目标程序运行时,编译器负责将程序的指令和数据分配到合适的存储器中。
存储器分配的主要目标是提高程序的执行效率和优化存储空间的利用率。
静态存储器分配静态存储器分配是在编译时确定存储器的分配方式。
静态存储器分配将程序的指令和数据分配到固定的内存地址上,程序运行时不会改变存储器分配。
静态存储器分配适用于程序结构稳定、数据量较小的场景,但难以适应动态创建和销毁对象的情况。
栈式存储器分配栈式存储器分配将程序的局部变量、函数调用和返回地址等信息存储在栈中。
编译原理目标程序运行时的组织
![编译原理目标程序运行时的组织](https://img.taocdn.com/s3/m/06f16826571252d380eb6294dd88d0d233d43c34.png)
编译原理目标程序运行时的组织简介在编译原理中,目标程序是由程序设计语言的源代码通过编译器转换而成的可执行文件。
目标程序的运行是通过操作系统的支持以及相关的硬件来完成的。
在目标程序运行时,需要对内存的组织进行有效的管理,以保证程序能够正确地执行。
程序的存储结构目标程序在运行时的组织首先涉及到程序的存储结构。
一般来说,目标程序在存储器中被组织为多个段或者区块。
这些段或者区块包括代码段、数据段、堆栈段等。
每个段都有不同的权限,比如代码段通常是只读的,数据段和堆栈段都是读写的。
代码段代码段是存储目标程序的机器指令的区域。
代码段在目标程序运行时是只读的,因为在运行时不能更改源代码。
代码段通常是按照顺序组织的,每条指令都有一个地址。
当程序执行时,计算机会从代码段中读取指令并逐条执行。
数据段数据段是存储目标程序的静态数据、全局变量以及常量的区域。
数据段在目标程序运行时是读写的,因为数据段中的数据可能会发生变化。
数据段通常是按照数据的类型和大小进行组织的,每个数据都有一个地址。
堆栈段堆栈段是存储目标程序的局部变量、函数的参数和返回值等临时数据的区域。
堆栈段在目标程序运行时是读写的,因为堆栈中的数据会被不断压入和弹出。
堆栈段通过栈的数据结构进行组织,数据的压入和弹出都是通过栈指针来实现的。
内存管理目标程序在运行时需要使用内存进行存储和计算。
内存管理是指程序如何分配、使用和释放内存资源的过程。
在目标程序运行时,操作系统负责管理内存的分配和释放,并对内存进行保护,以防止程序的错误操作导致系统崩溃或安全风险。
内存管理的主要任务包括内存分配、内存回收和内存保护。
内存分配是指为程序分配所需的内存空间。
常见的内存分配方式有静态分配和动态分配。
静态分配是在程序加载到内存时预先分配一定的内存空间,而动态分配是根据程序的需要,在运行时临时分配内存空间。
内存回收是指当某个内存空间不再被程序使用时,将其释放回系统。
常见的内存回收方式有手动回收和自动回收。
程序设计语言编译原理第三版第10章
![程序设计语言编译原理第三版第10章](https://img.taocdn.com/s3/m/c26323ccd0d233d4b04e6939.png)
§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)图的叶结点以一标识符(变量名)或常数作为标记,表示该 结点代表该变量或常数的值。
第10章目标程序运行时的组织
![第10章目标程序运行时的组织](https://img.taocdn.com/s3/m/10839d0226fff705cd170a71.png)
2、堆式动态存储分配 如果一个程序语言提供用户自由地申请数据空间和
退还数据空间的机制,通常使用一种称为堆式的动态存 储分配方案。
术语: 过程活动记录: AR
为说明方便,假定程序是由过程组成,过程运行时称作过 程的激活。
一个过程的一次执行所需要的信息使用一个连续的存储区来 管理,这个区 (块)叫做一个活动记录
1、栈式动态存储分配 这种分配策略是将整个程序的数据空间设计为一个栈。 例:在具有递归结构的语言程序中,每当调用一个过程时, 它所需的数据空间就分配在栈顶,每当过程工作结束时就释 放这部分空间。
过程所需的数据空间包括两部分: 一部分是生存期在本过程这次活动中的数据对象,如局部变 量、参数单元、临时变量等等; 另一部分则是用以管理过程活动的记录信息(连接数据)。即 当一次过程调用出现时,调用该过程的那个过程的活动即被 中断,当前机器的状态信息,诸如返回地址、寄存器的值等 等,也都必须保留在栈中。当控制从调用返回时,便根据栈 中记录的信息恢复机器状态,使该过程的活动继续进n 中的数据说明
} Void R( ) { R 中的数据说明 } Void Q
{Q中的数据说明
这种情况可以直接采用栈式 存储分配策略。
在运行时,每个过程开始时 就把它的活动记录压入栈, 直到该活动结束,它的活动 记录弹出栈。
}
Main
QR
嵌套过程语言的栈式分配方案
前面我们讲的过程不允许语言嵌套定义,现在 我们取消这个限制,即允许过程嵌套定义,一 个过程可以引用包围它的任一外层过程所定义 的标识(如变量,数组或过程等)。如:我们 所熟悉的PASCAL语言程序结构就是这样一种 语言。
编译原理程序运行时的存储组织
![编译原理程序运行时的存储组织](https://img.taocdn.com/s3/m/1f46cb850408763231126edb6f1aff00bfd5706d.png)
编译原理程序运行时的存储组织一、程序的应该存储区域1.代码区:也称为文本区或者只读区,用于存放程序的目标代码。
代码区是只读的,不允许修改。
在程序运行过程中,代码区的内容不会发生变化。
2.全局数据区:用于存放全局变量和静态数据。
全局数据区在程序开始运行时就被分配好空间,在程序的整个运行过程中都存在,直到程序结束。
3.堆区:用于存放动态分配的内存空间,也称为动态内存分配区。
堆区的内存空间是在程序运行时动态分配和释放的,可以根据程序的需要进行扩大或者缩小。
4.栈区:用于存放函数的局部变量和函数调用信息。
栈区的空间是在程序运行时自动分配和释放的,由编译器负责管理。
在函数调用时,会为函数分配一块栈区空间,函数返回后,该空间被自动释放。
二、内存管理方式1.静态内存管理:静态内存管理是指在程序编译阶段,由编译器根据程序的静态内存需求,在编译过程中为程序分配好固定大小的内存空间,静态内存管理的特点是内存空间的分配和释放都是在编译时确定的,程序运行时不需要进行内存管理。
2.动态内存管理:动态内存管理是指在程序运行时根据需要动态地分配和释放内存空间,动态内存管理的特点是内存空间的分配和释放是在程序运行过程中动态确定的。
动态内存管理可以通过堆区进行。
三、内存分配和释放编译原理程序在运行时的存储组织中,对于静态内存区域的分配和释放是由编译器在编译时确定的,程序在运行时无法进行修改。
对于动态内存区域的分配和释放,可以通过堆区进行,可以使用以下几个函数进行动态内存的分配和释放:1. 分配内存:程序可以使用malloc函数、calloc函数或者realloc函数来分配内存空间。
malloc函数用于分配指定字节数的内存空间,calloc函数用于分配指定数量和大小的内存空间,realloc函数用于调整已经分配的内存空间的大小。
2. 释放内存:程序在使用完动态分配的内存空间后,需要使用free函数来释放内存空间。
free函数会将之前分配的内存空间标记为可用状态,可以供其他程序使用。
编译原理课件第十章目标程序运行时的存储组织
![编译原理课件第十章目标程序运行时的存储组织](https://img.taocdn.com/s3/m/12e1e595ac51f01dc281e53a580216fc700a5382.png)
PART 01
目标程序运行时的存储器 组织
存储器分类
主存储器
用于存储程序运行时所需的数 据和指令,具有较快的访问速
度。
辅助存储器
如硬盘、光盘等,用于存储大 量数据和程序,访问速度较慢 。
高速缓存存储器
位于CPU和主存储器之间,用 于缓存常用数据和指令,提高 访问速度。
寄存器
位于CPU内部,用于临时存储 数据和指令,访问速度最快。
01
数据段用于存储程序中定义的全 局变量、静态变量等数据。
03
数据段的大小在编译时确定,并 在程序运行时被加载到内存中。
02
数据段分为初始化数据段和未初 始化数据段,分别用于存储初始
化和未初始化的数据。
201 4
04
数据段的保护机制可以防止其他 程序或用户随意修改其中的数据。Fra bibliotek堆栈段
01
堆栈段用于存储函数调用的参数、局部变量以及函数调用的返回地址 等信息。
02
堆栈段的特点是后进先出(LIFO),即最后进入堆栈的元素最先被弹 出。
03
当函数被调用时,其参数和局部变量等信息被压入堆栈中;当函数返 回时,这些信息被从堆栈中弹出。
04
堆栈段的增长和缩小是通过堆栈指针来实现的,堆栈指针指向堆栈的 顶部元素。
PART 02
程序的内存布局
静态内存分配
全局变量存储
代码段
01
代码段用于存储程序的指令代码 ,是程序运行时必须加载到内存 中的部分。
02
代码段通常被划分为多个区段, 每个区段对应程序中的一个模块
或函数。
在程序运行时,代码段中的指令 被加载到CPU的指令寄存器中, 并由CPU执行。
编译原理 第十章 目标程序运行时的存储组织
![编译原理 第十章 目标程序运行时的存储组织](https://img.taocdn.com/s3/m/51efbf4aa21614791611282c.png)
(21) PRDUCE=BUFFER(NEXT:NEXT)
(22) NEXT=NEXT+1
(23) END
图 FORTRAN77的静态存储分配
10.1.2动态存储分配
如果一个程序设计语言允许递归过程、可变数组或允许用户自由申请和释放空间,那么,就需要采用动态存储管理技术。因为对于这种程序在编译时无法知道它在运行时需要多大的存储空间,它所需要的数据空间的大小需待程序运行时动态地确定。
首先,当运行程序要求一块体积为N的空同时,我们应该分配哪一块给它呢理论上说,应从比N稍大一点的一个空闲块中取出N个单元,以便使大的空闲块派更大的用场。但这种做法较麻烦。因此,常常仍采用"先碰上哪块比N大就从其中分出N个单元"的原则。但不论采用什么原则,整个大存区在一个定时间之后必然会变面零碎不堪。总有一个时候会出现变样的情形:运行程序要求一块体积为N的空间,但发现没有比N大的空闲块了,然而所有空闲块的总和却要比N大得多!出现这种情形时怎么办呢这是一个比前面的问题难得多的问题。解决办法似乎很简单,这就是,把所有空闲块连接在一起,形成一片可分配的连续空间。这里主要问题是,我们必须调整运行程序对各占用块的全部引用点。
编译原理-第十章--代码优化
![编译原理-第十章--代码优化](https://img.taocdn.com/s3/m/beffb5f0b52acfc788ebc92d.png)
第十章代码优化某些编译程序在中间代码或目标代码生成之后要对生成的代码进行优化。
所谓优化,实质上是对代码进行等价变换,使得变换后的代码运行结果与变换前代码运行结果相同,而运行速度加大或占用存储空间少,或两者都有。
优化可在编译的不同阶段进行,对同一阶段,涉及的程序范围也不同,在同一范围内,可进行多种优化。
一般,优化工作阶段可在中间代码生成之后和(或)目标代码生成之后进行。
中间代码的优化是对中间代码进行等价变换。
目标代码的优化是在目标代码生成之后进行的,因为生成的目标代码对应于具体的计算机,因此,这一类优化在很大程度上依赖于具体的机器,我们不做详细讨论。
另外依据优化所涉及的程序范围,又可分为局部优化、循环优化和全局优化三个不同的级别。
局部优化指的是在只有一个入口、一个出口的基本程序块上进行的优化。
循环优化对循环中的代码进行的优化。
全局优化是在整个程序范围内进行的优化。
本章重点:局部优化基本块的DAG表示第一节优化技术简介为了说明问题,我们来看下面这个例子,源程序是:P :=0For I :=1 to 20 doP :=P+A[I]*B[I];经过编译得到的中间代码如图10-1-1所示,这个程序段由B1和B2两个部分组成,B2是一个循环,假定机器按字节编址。
那么,对于这个中间代码段,可进行如下这些优化。
1、删除多余运算(删除公共子表达式)优化的目的在于使目标代码执行速度较快。
图10-1-1中间代码(3)和(6)中都有4*I的运算,而从(3)到(6)没有对I赋值,显然,两次计算机的值是相等的。
所以,(6)的运算是多余的。
我们可以把(6)变换成:T4 :=T1。
这种优化称为删除多余运算或称为删除公共子表达式。
2、代码外提减少循环中代码总数的一个重要办法是代码外提。
这种变换把循环不变运算,即其结果独立于循环执行次数的表达式,提到循环的前面。
使之只在循环外计算一次,上例中,我们可以把(4)和(7)提到循环外。
经过删除多余运算和代码外提后,代码变成图10-1-2。
编译原理-第十章习题答案
![编译原理-第十章习题答案](https://img.taocdn.com/s3/m/bd05a6290912a2161479297d.png)
上一页
下一页
12
P:=0 for I:=1 to 20 do P:=P+A[I]*B[I]
(1)P:=0 (2)I:=1 (1)P:=0 (2)I:=1 (4)T2:=addr(A)-4 (7)T5:=addr(B)-4
(3)T1:=4*I (4)T2:=addr(A)-4 (5)T3:=T2[T1] (6)T4:=4*I (7)T5:=addr(B)-4 (8)T6:=T5[T4] (9)T7:=T3*T6 (10)P:=P+T7 (11)I:=I+1 (12)if I<=20 goto(3)
例: L1: if a<b goto L2 goto Lnext L2: if c<d goto L3 goto L4 L3: t1 =y+z x =t1 goto L1 L4:t2 = y-z x =t2 goto L1 L1:if a<b goto L2 L2:if c<d goto L3 goto L4 L3:t1 = y + z x = t1 goto L1
编译原理电子教案 第十章 优化
本章的主要内容
基本块的划分和流图的构建 基本块的DAG表示及基于DAG的局部优化 循环优化
上一页
下一页
2
本章要求
知识点:优化的基本概念及方法、基本块及程序流图、 DAG及基于DAG的优化、循环优化 熟练掌握: (1)局部优化:基本块,流图,DAG优化。 (2)循环优化:代码外提,强度削弱,删除归纳变量。
优化后: _tmp0 = 56 ; _tmp1 = _tmp0 – b ; a = _tmp1 ;
上一页 下一页
8
常数传播
_tmp4 = 0 ; f0 = _tmp4 ; _tmp5 = 1 ; f1 = _tmp5 ; _tmp6 = 2 ; i = _tmp6 ;
编译原理-清华大学-第10章1-代码优化
![编译原理-清华大学-第10章1-代码优化](https://img.taocdn.com/s3/m/6843d654ce2f0066f53322c8.png)
(1)P:=0 (2)I:=0 (4)T2:=addr(A) (7)T5:=addr(B) (3)T1:=0
(5)T3:=T2[T1] (6)T4:=T1 (8)T6:=T5[T4] (9)T7:=T3*T6 (10)P:=P+T7 (11)I:=I+1 (3‘)T1:=T1+4 (12)if I<=20 goto(5)
2、代码外提
目的:减少循环中代码总数。 方法:把循环不变运算,即其结果独立
于循环执行次数的表达式提到循环的前 面,使之只在循环外计算一次。
(1)P:=0 (2)I:=0
(3)T1:=4*I (4)T2:=addr(A) (5)T3:=T2[T1] (6)T4:=T1 (7)T5:=addr(B) (8)T6:=T5[T4] (9)T7:=T3*T6 (10)P:=P+T7 (11)I:=I+1 (12)if I&l经过变换循环的控制条件后,有些变 量不被引用,可以从循环中删除。
(1)P:=0 (2)I:=0 (4)T2:=addr(A) (7)T5:=addr(B) (3)T1:=4*I
(5)T3:=T2[T1] (6)T4:=T1 (8)T6:=T5[T4] (9)T7:=T3*T6 (10)P:=P+T7 (11)I:=I+1 (3’)T1:=T1+4 (12)if I<=20
2)在运行基本块时,只能从其入口进入, 从出口退出。
2、划分基本块算法
(1)求出各基本块的入口语句 1)程序的第一个语句 ; 2)能由条件转移语句和无条件转移语句转
移到达的语句; 3)紧跟在条件转移语句后面的语句。
(2) 对以上求出的每个入口语句,确定其所 属的基本块。它是由该入口语句到下一入 口语句(不包括该入口语句) 之间的语句序 列组成的。
编译原理 第10章 目标程序运行时的存储组织
![编译原理 第10章 目标程序运行时的存储组织](https://img.taocdn.com/s3/m/ce361f11cc7931b765ce154a.png)
var c:char; begin
...(1)... end; {B} procedure C; var t:real; begin
...(2)... end;{C} begin ..... B; C; ..... end;{A} begin{main} ... A(d); ... end.
《编译原理》课后习题答案第十章
第 10 章 目标程序运行时的存储组织
第 5 题:
过程参数的传递方式有几种?简述“传地址”和“传值”的实现原理。
答案:
参数的传递方式有下述几种: “传值” -- Call by Value。 “传地址”-- Call by Address。 “换名” -- Call by Name。 “得结果”-- Value-result。
答案:
盛威网()专业的计算机学习网站
3
《编译原理》课后习题答案第十章
问题 2:
对如下的 Pascal 程序,画出程序执行到(1)和(2)点时的运行栈。 program Tr(input,output);
var i:integer; d:integer; procedure A(k:real);
附加题
问题 1:
下面是一个 Pascal 程序 program PP(input,output)
var K:integer; function F(N:integer):integer begin
if N< =0 then F:=1 else F:=N * F(N-1); end; begin K:=F(10); ... end; 当第二次(递归地)进入 F 后,DISPLAY 的内容是什么?当时整个运行栈的内容是什么?
编译原理考试知识点复习
![编译原理考试知识点复习](https://img.taocdn.com/s3/m/99ac7e2ada38376bae1faeb6.png)
第一章:编译过程的六个阶段:词法分析,语法分析,语义分析,中间代码生成,代码优化,目标代码生成解释程序:把某种语言的源程序转换成等价的另一种语言程序——目标语言程序,然后再执行目标程序。
解释方式是接受某高级语言的一个语句输入,进行解释并控制计算机执行,马上得到这句的执行结果,然后再接受下一句。
编译程序:就是指这样一种程序,通过它能够将用高级语言编写的源程序转换成与之在逻辑上等价的低级语言形式的目标程序(机器语言程序或汇编语言程序)。
解释程序和编译程序的根本区别:是否生成目标代码第三章:Chomsky对文法中的规则施加不同限制,将文法和语言分为四大类:0型文法(PSG)◊ 0型语言或短语结构语言文法G的每个产生式α→β中:若α∈V*VNV*, β∈(VN∪VT)* ,则G是0型文法,即短语结构文法。
1型文法(CSG)◊ 1型语言或上下文有关语言在0型文法的基础上:若产生式集合中所有|α|≤|β|,除S→ε(空串)外,则G是1型文法,即:上下文有关文法另一种定义:文法G的每一个产生式具有下列形式:αAδ→αβδ,其中α、δ∈V*,A∈VN,β∈V+;2型文法(CFG)◊ 2型语言或上下文无关语言文法G的每个产生式A→α,若A∈VN ,α∈(VN∪VT)*,则G是2型法,即:上下文无关文法。
3型文法(RG)◊ 3型语言或正则(正规)语言若A、B∈VN,a∈VT或ε,右线性文法:若产生式为A→aB或A→a左线性文法:若产生式为A→Ba或A→a都是3型文法(即:正规文法)最左(最右)推导在推导的任何一步α⇒β,其中α、β是句型,都是对α中的最左(右)非终结符进行替换规范推导:即最右推导。
规范句型:由规范推导所得的句型。
句子的二义性(这里的二义性是指语法结构上的。
)文法G[S]的一个句子如果能找到两种不同的最左推导(或最右推导),或者存在两棵不同的语法树,则称这个句子是二义性的。
文法的二义性一个文法如果包含二义性的句子,则这个文法是二义文法,否则是无二义文法。
编译原理 第十章 目标程序运行时的存储组织
![编译原理 第十章 目标程序运行时的存储组织](https://img.taocdn.com/s3/m/db68bcda10a6f524cdbf8540.png)
第十章目标程序运行时的存储组织课前索引【课前思考】◇回顾一般的编译过程,能否找到本章所讲内容在哪个过程?◇为什么编译程序要考虑目标程序运行时存储区的管理和组织?◇请归纳C语言和PASCAL语言的程序结构和数据类型的不同点【学习目标】全面了解目标程序运行时存储区的整体布局;每种存储区的组织方式和管理方法;并通过实例着重掌握,对允许过程嵌套定义的情况,栈式动态存储分配的组织方式和运行时进栈退栈的活动实现方法。
【学习指南】在代码生成前,编译程序必须进行目标程序运行环境的配置和数据空间的分配。
一般来讲,假如编译程序从操作系统中得到一块存储区以使目标程序在其上运行,该存储区需容纳生成的目标代码和目标代码运行时的数据空间。
我们这里所说的运行时的存储区组织,是指目标程序运行时的数据空间的管理和组织。
【难重点】◇目标程序运行时,存储区域的整体布局,以及各区域的作用。
◇各种不同类型的数据表示。
◇允许过程嵌套定义的情况,栈式动态分配的组织管理。
◇对过程的调用,进入和退出时,栈式动态分配的工作原理。
◇过程活动纪录的各项内容和它们的作用,以及活动纪录的组织方式。
◇过程参数传递的不同方式。
【知识结构】从逻辑上看,在代码生成前,编译程序必须进行目标程序运行环境的配置和数据空间的分配。
一般来讲,假如编译程序从操作系统中得到一块存储区以使目标程序在其上运行,该存储区需容纳生成的目标代码和目标代码运行时的数据空间。
数据空间应包括:用户定义的各种类型的数据对象(变量和常数)所需的存储空间,作为保留中间结果和传递参数的临时工作单元,调用过程时所需的连接单元,以及组织输入/输出所需的缓冲区。
目标代码所占用空间的大小在编译时能确定。
有些数据对象所占用的空间也能在编译时确定,其地址可以编译进目标代码中。
而有些数据对象具有可变体积和待分配性质,无法在编译时确定存储空间的位置。
因此运行时的存储区常常划分成:目标区、静态数据区、栈区和堆区,如图10.1就是一种典型划分,代码(code)区用以存放目标代码,这是固定长度的,即编译时能确定的;静态数据区(static data)用以存放编译时能确定所占用空间的数据;堆栈区(stack and heap)用于可变数据以及管理过程活动的控制信息。
编译原理课件-目标程序运行时的组织
![编译原理课件-目标程序运行时的组织](https://img.taocdn.com/s3/m/9f3ca081d5d8d15abe23482fb4daa58da0111c6e.png)
一則,每逢進入 一個分程式,就照樣建立 連接數據和DISPLAY表,這是不必要的。 二則 ,當從內層分程式向外層轉移時,可 能同時要結束若干個分程式。
簡單的棧式分配方案
• 程式結構特點:過程定義不嵌套,過程可 遞歸調用,含可變數組;
• 例: main • 全局變數的說明
• proc R • …… • end R; • proc Q • …… • end Q; • 主程序執行語句
• end main
Main---->Q---->R
Main--->Q---->Q
棧式存儲組織review
數據空間的存儲管理:棧式存儲分配
– 過程(函數)的活動記錄:是一段連續的存儲區,存放過 程(函數)的一次執行所需要的資訊。
– 過程(函數)活動記錄的內容:聯繫單元(靜態鏈,動態鏈 和返回地址)、局部變數和臨時變數
棧式存儲分配的實現:
• 設置兩個指針:棧頂指針Top和當前活動記錄指針SP; • 調用一個過程(函數)前,先把過程(函數)的參數壓入數據棧; • 在數據棧中為過程(函數)的活動記錄分配空間; • 填寫聯繫單元內容; • 執行過程(函數)代碼; • 過程(函數)返回前,根據當前SP恢復Top指針,根據動態鏈恢
按照過程處理辦法,意味著必須一層 一層地通過“返回” 來恢復所要到達的 那個分程式的數據區,但不能直接到達。
例如:如果有一個從第5層分程式轉出到達 第1層分程式的標號L,雖然在第5層分程 式工作時知道L所屬的層數,我們極易從 DISPLAY中獲得第1層分程式的活動記 錄基址(SP),但是怎麼知道第1層分程 式進入時的TOP呢?唯一的辦法是從 5,4,3和2各層順序退出。但這種辦法是很 浪費時間的。
编译原理 第20讲(第十章)
![编译原理 第20讲(第十章)](https://img.taocdn.com/s3/m/c619aa66783e0912a2162a37.png)
10.3.3分程序结构的存储分配方案
处理分程序结构存储分配方案的一种简单办法是, 把分程序看成 “无名无参过程”,它在哪里定义就在 哪里被调用。因此,可以把处理过程的存储办法应用到 处理分程序中,但这种做法是极为低效的。 一则,每逢进入一个分程序,就照样建立连接数据 和DISPLAY表,这是不必要的。 二则,当从内层分程序向外层转移时,可能同时要 结束若干个分程序。 按照过程处理办法,意味着必须一层一层地通过 “返回” 来恢复所要到达的那个分程序的数据区,但 不能直接到达。
10.4.1 传值的实现(Call
by value)
1.形式参数当作过程的局部变量处理,
即在被调过程的活动记录中开辟了形参 的存储空间,这些存储位置即是我们所 说的形式单元(用以存放实参)。 2.调用过程计算实参的值,并将其放在 对应形式单元开辟的空间中。(传右值) 3.被调用过程执行时,就像使用局部变 量一样使用这些形式单元。
10.5 堆式动态存储分配
需求: – 一个程序语言允许用户自由地申请数据空间和退还 数据空间,或者不仅有过程而且有进程(process) 的程序结构, 操作: – 堆提供两个操作,分配操作和释放操作 情况: – 经一段运行时间之后,这个大空间就必定被分划成 许多块块,有些占用,有些无用(空闲)--碎片问 题
例子(Pascal)
int i; //全局变量 int a [10]; //全局变量 void p (int x) { 为什么不换名字? ++i; ++x; } main () { i=1; –1把被调用的程序中与调用过程中同名的 a[1]=1; 局部变量换名 a[2]=2; –2把被调用程序抄到调用处,其中形参用 p(a[i]); 实参文字形式替换 return 0; }
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
编译原理第10章目标程序运行时的组 织
编译原理第10章目标程序运行时的组 织
用Display表的方案
(1)主程序--->(2)P--->(3)Q--->(4)R
top
P的
display sp 活动记录
d[1]
主程序的
d[0]
活动记录
编译原理第10章目标程序运行时的组 织
概述
代码生成前如何安排目标机资源 运行时组织的几个问题 • 数据表示-如何在目标机中表示每个源语言类型的值 • 表达式求值-如何组织表达式的计算 • 存储分配-如何组织不同作用域变量的存储 • 过程实现-如何以例程实现过程,函数,参数传递
编译原理第10章目标程序运行时的组 织
• 关键技术:解决对非局部量的引用(存 取)。
• 设法跟踪每个外层过程的最新活动记录 AR的位置。
• 跟踪办法: 1. 用静态链(如PL/0的SL)。 2. 用DISPLAY表。
编译原理第10章目标程序运行时的组 织
const a=10; var b,c; procedure p; begin c:=b+a; end; begin read(b); while b#0 do begin call p; write(2*c); read(b); end end.
数组内情向量:编译将数组的有关信息记录在一些单元中,称为数 组的“内情向量”。
A[l 1:u 1,l 2:u 2, … ,ln : un]
l1
u1
l2
u2
: :
type
a(首地址)
n
C
编译原理第10章目标程序运行时的组
织
目标程序运行时的存储组织
存储分配策略:
静态存储分配 动态存储分配——栈式
堆式
简单的栈式分配方案 嵌套过程的栈式分配方案 分程序结构的存储分配方案
. . . d DISPLAY . 简单变量 . 数组内情向量 . 临时变量
• 当过程的层次为n, 它的 display为n+1个 值。 • 一个过程被调用时, 从调用过程的 DISPLAY表中自下向 上抄录n个SP值,再加 上本层的SP值。 •全局DISPLAY地址
编译原理第10章目标程序运行时的组 织
在语义学中,使用术语environment函数表示
env: N→S
(N到S的映射) 编译原理第10章目标程序运行时的组
织
编译原理第10章目标程序运行时的组 织
决定运行管理复杂程度的因素——源语言本身 1. 允许的数据类型的多少 2.语言中允许的数据项是 静态确定
动态确定 3.程序结构 决定名字的作用域的规则和结构 A.段结构 B.过程定义不嵌套,只允许过程递归调用 C.分程序结构
编译原理第10章目标程序运行时的组 织
为了解决上述问题,可采取两种措施。第 一,对每个过程或分程序都建立有自己 的栈顶指示器TOP,代替原来仅有过程 的栈顶指示器, 每个TOP的值保存在各自 活动记录中。这样,上述的第二个问题 便可解决。第二,不把分程序看作“无 参过程”,每个分程序享用包围它的那 个最近过程的DISPLAY。每个分程序都 隶属于某个确定的过程,分程序的层次 是相对于它所属的那个过程进行编号的。
但方法(成员函数)不存在该对象里 指令:
编译原理第10章目标程序运行时的组 织
编译原理第10章目标程序运行时的组 织
编译原理第10章目标程序运行时的组 织
编译原理第10章目标程序运行时的组 织
可变 (动态)数组: 若一个数组所需的存储空间的大小在
编译时就已知道,则称它为确定数组,否则称为可变(动态)数组。
分程序嵌套 过程定义嵌套
4存储类别的多少
Global Static Local dynamic
编译原理第10章目标程序运行时的组 织
术语
• 静态:如果一个名字的性质通过说明语句 或隐或显规则而定义,则称这种性质是 “静态”确定的。
• 动态:如果名字的性质只有在程序运行时 才能知道,则称这种性质为“动态”确定 的。
局部变量 中间结果
编译原理第10章目标程序运行时的组 织
目标代码的解释执行 运行栈
S
• M调用过程P t.
.
RA DL
b SL t
b
P
M
编译原理第10章目标程序运行时的组 织
解决对非局部量的引用(存取) 用Display表
Display表---嵌套层次显示表 当前激活过程的层次为K,它的Display表含有K+1个单元,依次存
分程序结构
Procedure A(m,n); integer m,n;
B1:begin real z; array B[m:n];
B2:begin real d, e;
L3:
2
end;
B4:begin array C[1:m];
1
B5:begin real e;
L6:
54
end;
end;
L8:end;
编译原理第10章目标程序运行时的组
织
目标代码解释执行时数据栈的布 局(运行栈的存储分配)
每个过程的AR有 3个联系单元:
–SL: 静态链,指向定义该过程的直接外过程 (或主程序)运行时最新数据段的基地址。
–DL: 动态链,指向调用该过程前正在运行过 程的数据段基地址。
–RA: 返回地址,记录调用该过程时目标程序 的断点,即调用过程指令的下一条指令的地址。
编译原理第10章目标程序运行时的组 织
每个过程被当作是0层分程序。而过程体 分程序(假定是一个分程序)当作是它 所管辖的第1层分程:序。
这样,每个过程的活动记录所含的内容有:
1.过程的TOP值,它指向过程活动记录的 栈顶位置。
2.连接数据,共四项:
(1)老SP值;
(18) opr 0 4 次栈顶与栈顶相乘(2*c)
(19) opr 0 14 栈顶值输出至屏幕 (20) opr 0 15 换行 (21) opr 0 16 从命令行读取值到栈顶 (22) sto 0 3 栈顶值送变量b中 (23) jmp 0 11 无条件转到循环入口(11) (24) opr 0 0 结束退栈
编译原理第10章目标程序运行时的组 织
分程序结构的存储 分配方案
处理分程序结构存储分配方案的一种 简单办法是,把分程序看成 “无名无参过 程”,它在哪里定义就在哪里被调用。因 此,可以把处理过程的存储办法应用到处 理分程序中。但这种做法是极为低效的。
一则,每逢进入 一个分程序,就照样建立 连接数据和DISPLAY表,这是不必要的。 二则 ,当从内层分程序向外层转移时,可 能同时要结束若干个分程序。
编译原理第10章目标程序运行时的组 织
简单的栈式分配方案
• 程序结构特点:过程定义不嵌套,过程可 递归调用,含可变数组;
• 例: main
• 全局变量的说明
• proc R
• ……
• end R;
• proc Q
• ……
• end Q; • 主程序执行语句
• end main
编译原理第10章目标程序运行时的组 织
编译原理第时的组 织
嵌套过程语言的栈式 分配方案
l 主要特点:
• (语言)一个过程可以引用包围它的任 一外层过程所定义的标识符(如变量, 数组或过程等)。
• (实现)一个过程可以引用它的任一外 层过程的最新活动记录中的某些数据。
编译原理第10章目标程序运行时的组 织
编译原理第10章目标程序运行时的组 织
按照过程处理办法,意味着必须一层 一层地通过“返回” 来恢复所要到达的 那个分程序的数据区,但不能直接到达。
例如:如果有一个从第5层分程序转出到达 第1层分程序的标号L,虽然在第5层分程 序工作时知道L所属的层数,我们极易从 DISPLAY中获得第1层分程序的活动记 录基址(SP),但是怎么知道第1层分程 序进入时的TOP呢?唯一的办法是从 5,4,3和2各层顺序退出。但这种办法是很 浪费时间的。
编译原理第10章目标程 序运行时的组织
2020/12/13
编译原理第10章目标程序运行时的组 织
概述-代码生成解决语义gap
高级语言支持的概念 Type value expression Variable procedure Function parameters
目标机支持的概念 bits bytes words Registers Stack address Routine(sub routine)
top display
主程序的
d[0]
sp 活动记录
(2)
(1) 编译原理第10章目标程序运行时的组 织
用Display表的方案
• 主程序--->P--->Q--->R
d[2]displatyopsp
Q的 活动记录
d[1]
P的
d[0]
活动记录
主程序的
活动记录
(3)
top R 的 display sp 活动记录
( 0) jmp 0 8 转向主程序入口 ( 1) jmp 0 2 转向过程p入口 ( 2) int 0 3 过程p入口,为过程p开辟空间 ( 3) lod 1 3 取变量b的值到栈顶 ( 4) lit 0 10 取常数10到栈顶 ( 5) opr 0 2 次栈顶与栈顶相加 ( 6) sto 1 4 栈顶值送变量c中 ( 7) opr 0 0 退栈并返回调用点(16) ( 8) int 0 5 主程序入口开辟5个栈空间 ( 9) opr 0 16 从命令行读入值置于栈顶 (10) sto 0 3 将栈顶值存入变量b中 (11) lod 0 3 将变量b的值取至栈顶 (12) lit 0 0 将常数值0进栈 (13) opr 0 9 次栈顶与栈顶是否不等 (14) jpc 0 24 等时转(24)(条件不满足转) (15) cal 0 2 调用过程p (16) lit 0 2 常数值2进栈 (17) lod 0 4 将变量c的值取至栈顶