编译原理 第十章 目标程序运行时的存储组织
1 / 24 第十章 目标程序运行时的存储组织 课前索引
【课前思考】 ◇ 回顾一般的编译过程,能否找到本章所讲内容在哪个过程? ◇ 为什么编译程序要考虑目标程序运行时存储区的管理和组织? ◇ 请归纳C语言和PASCAL语言的程序结构和数据类型的不同点 【学习目标】 全面了解目标程序运行时存储区的整体布局;每种存储区的组织方式和管理方法;并通过实例着重掌握,对允许过程嵌套定义的情况,栈式动态存储分配的组织方式和运行时进栈退栈的活动实现方法。 【学习指南】 在代码生成前,编译程序必须进行目标程序运行环境的配置和数据空间的分配。一般来讲,假如编译程序从操作系统中得到一块存储区以使目标程序在其上运行,该存储区需容纳生成的目标代码和目标代码运行时的数据空间。我们这里所说的 运行时的存储区组织,是指目标程序运行时的数据空间的管理和组织。 【难重点】 ◇ 目标程序运行时,存储区域的整体布局,以及各区域的作用。 ◇ 各种不同类型的数据表示。 ◇ 允许过程嵌套定义的情况,栈式动态分配的组织管理。 ◇ 对过程的调用,进入和退出时,栈式动态分配的工作原理。 ◇ 过程活动纪录的各项内容和它们的作用,以及活动纪录的组织方式。 ◇ 过程参数传递的不同方式。 【知识结构】 2 / 24
从逻辑上看,在代码生成前,编译程序必须进行目标程序运行环境的配置和数据空间的分配。一般来讲,假如编译程序从操作系统中得到一块存储区以使目标程序在其上运行,该存储区需容纳生成的目标代码和目标代码运行时的数据空间。数据空间应包括:用户定义的各种类型的数据对象(变量和常数)所需的存储空间,作为保留中间结果和传递参数的临时工作单元,调用过程时所需的连接单元,以及组织输入/输出所需的缓冲区。目标代码所占用空间的大小在编译时能确定。有些数据对象所占用的空间也能在编译时确定,其地址可以编译进目标代码中。而有些数据对象具有可变体积和待分配性质,无法在编译时确定存储空间的位置。 因此运行时的存储区常常划分成:目标区、静态数据区、栈区和堆区,如图10.1就是一种典型划分,代码(code)区用以存放目标代码,这是固定长度的,即编译时能确定的;静态数据区(static data)用以存放编译时能确定所占用空间的数据;堆栈区(stack and heap)用于可变数据以及管理过程活动的控制信息。 图10.1 目标程序运行时存储区的典型划分 code static data stack ↓ ↑ heap
所谓数据空间的分配,本质上看,是将程序中的每个名字与一个存储位置关联起来,该存储位置用以容纳名字的值。编译程序分配目标程序运行时的数据空间的基本依据是程序语言设计时对程序运行中存储空间的使用和管理办法的规定。我们知道,即便有些名字在程序中只声明了一次,但该名字可能对应运行时不同的存储位置,比如,一个递归调用的过程,在执行时,其同一个局部名字应该对应不同的运行空间位置以容纳每次执行时的值。在程序设计语言语义学中,使用术语environment表示将一个名字映射到一个存储位置的函数,术语state表示存储位置到值的映射,使用术语 environment函数表示 env: N→S (N到S的映射) 如图10.2所示。 图10.2 名字 到存储、到值的映射
编译程序分配目标程序运行时的数据空间的基本依据是程序语言设计时对程序运行中存储空间的使用和管理办法的规定。决定存储管理复杂程度的因素--源语言本身,比如源语言允许的数据类型有多少?语言中允许的数据项是静态确定还是动态确定?程序结构有什么特点,是段结构还是分程序结构?过程定义是否允许嵌套?等等。 源语言的结构特点、源语言的数据类型、源语言中决定名字作用域的规则等因素影响存储空间的管理和组织的复杂程度,决定数据空间分配的基本策略。 本章将介绍存储空间的使用管理方法,重点针对栈式动态存储分配的实现进行讨论。 3 / 24
10.1 数据空间的三种不同使用方法和管理方法 数据空间的使用和管理方法分成三种:静态存储分配、栈式动态存储分配和堆式动态存储分配。 10.1.1 静态存储分配 这种存储分配非常简单,如果在编译时能确定目标程序运行中所需的全部数据空间的大小,编译时安排好目标程序运行时的全部数据空间,确定每个数据对象的存储位置,称这种分配策略为静态存储分配。如果一个名字的性质通过说明语句或隐式或显式规则而定义,则称这种性质是"静态"确定的。 像FORTRAN这样的语言,其程序是段结构的,即由主程序段和若干子程序段组成。各程序段中定义的名字一般是彼此独立的(除公共块和等价语句说明的名字以外),也即各段的数据对象名的作用域在各段中,同一个名字在不同的程序段表示不同的存储单元,不会在不同段间互相引用、赋值。另外它的每个数据名所需的存储空间大小都是常量(即不许含可变体积的数据,如可变数组),且所有数据名的性质是完全确定的。这样,整个程序所需数据空间的总量在编译时完全确定,从而每个数据名的地址就可静态进行分配。换句话说,一旦存储空间的某个位置分配给了某个数据名(关联起来)之后,在目标程序的整个运行过程中,此位置(地址)就属于该数据名了。 图10.4给出一个FORTRAN 77的程序例子。在图10.5中描述了该程序中局部变量的静态存储位置。 图10.4 一个FORTRAN 77的例子 (1) PROGRAM SUME (2) CHARACTER * 50 BUF //程序体所拥有的静态量BUF (3) INTEGER NEXT //程序体所拥有的静态量NEXT (4) CHARACTER C, PRDUCE //程序体所拥有的静态量C (5) DATA NEXT /1/, BUF / ' ' / (6) 6 C=PRDUCE() (7) BUF(NEXT:NEXT)=C (8) NEXT=NEXT+1 (9) IF(C .EN. ' ' )GOTO 6 (10) WRITE ( *,' (A)' )BUF (11) END (12) CHARACTER FUNCTION PRDUCE() (13) CHARACTER * 80 BUFFER (14) INTEGER NEXT (15) SAVE BUFFER, NEXT //PRDUCE函数体所拥有的静态量BUFFER, NEXT (16) DATA NEXT /81/ (17) IF (NEXT .GT.80)THEN (18) READ ( *,' (A)' )BUFFER (19) NEXT=1 (20) END IF (21) PRDUCE=BUFFER(NEXT:NEXT) (22) NEXT=NEXT+1 4 / 24
(23) END 图10.5 FORTRAN77的静态存储分配
10.1.2 动态存储分配 如果一个程序设计语言允许递归过程、可变数组或允许用户自由申请和释放空间,那么,就需要采用动态存储管理技术。因为对于这种程序在编译时无法知道它在运行时需要多大的存储空间,它所需要的数据空间的大小需待程序运行时动态地确定。 若一个数组所需的存储空间的大小在编译时就已知道,则称它为确定数组,否则称为可变数组。 例 : procedure A(m,n:integer); begin real z; array B[m:n]; begin · · · end; end; B[m:n] 为可变数组,B的上下界是过程A的实参,A被调用时才能确定。动态存储管理技术有两种方式:栈式(stack)和堆式(heap)。下面简述这两种方式的原则。 1.栈式动态存储分配 这种分配策略是将整个程序的数据空间设计为一个栈。在具有递归结构的语言程序中,每当调用一个过程时,它所需的数据空间就分配在栈顶,每当过程工作结束时就释放这部分空间。过程所需的数据空间包括两部分:一部分是生存期在本过程这次活动中的数据对象,如局部变量、参数单元、临时变量等等;另一部分则是用以管理过程活动的记录信息。即当一次过程调用出现时,调用该过程的那个过程的活动即被中断,当前机器的状态信息,诸如程序计数器(返回地址)、寄存器的值等等,也都必须保留在栈中。当控制从调用返回时,便根据栈中记录的信息恢复机器状态,使该过程的活动继续进行。至于在这种分配策略下,如何实现动态地分配和释放一个过程的数据空间,如何实现对非局部变量的引用、参数传递以及对可变数据结构(如可变数组)的空间分配办法等等,将在后面几节给予详细讨论。 栈式动态存储分配策略适用于PASCAL,C,ALGOL之类具有递归结构的语言的实现。 2.堆式动态存储分配 如果一个程序语言提供用户自由地申请数据空间和退还数据空间的机制(如C++中的5 / 24
new,delete,PASCAL的new,等机制),或者不仅有过程而且有进程的程序结构的情况下,空间的使用未必服?quot;先申请后释放,后申请先释放"的原则,那么栈式的动态分配方案就不适用了。通常使用一种称为堆式的动态存储分配方案。 Pascal语言中,标准过程new能够动态建立一个新记录,它实际上是从未使用的自由区(空闲空间)中找一个大小合适的存储空间并相应地置上指针。标准过程dispose是释放记录new与dispose不断改变着堆存储器的使用情况。 这种分配方式的存储管理技术甚为复杂,我们这里举出这种分配方法必须考虑的几个问题。 首先,当运行程序要求一块体积为N的空同时,我们应该分配哪一块给它呢?理论上说,应从比N稍大一点的一个空闲块中取出N个单元,以便使大的空闲块派更大的用场。但这种做法较麻烦。因此,常常仍采用"先碰上哪块比N大就从其中分出N个单元"的原则。但不论采用什么原则,整个大存区在一个定时间之后必然会变面零碎不堪。总有一个时候会出现变样的情形:运行程序要求一块体积为N的空间,但发现没有比N大的空闲块了,然而所有空闲块的总和却要比N大得多!出现这种情形时怎么办呢?这是一个比前面的问题难得多的问题。解决办法似乎很简单,这就是,把所有空闲块连接在一起,形成一片可分配的连续空间。这里主要问题是,我们必须调整运行程序对各占用块的全部引用点。 还有,如果运行程序要求一块体积为N的空间,但所有空闲块的总和也不够N,那又应怎么办呢?有的管理系统采用一种吊做废品回收的办法来对付这种局面。即寻找那些运行程序业己无用但尚未释放在占用块,或者那些行程序目前很少使用的点用块,把这此占用块收回来,重新分配。但是,我们如何知道哪些块运行时在使用或者目前很少使用呢?即便知道了,一经收回后运行程序在某个时候又要用它时又应该怎么办呢?要使用废品回收技术,除了在语言上要有明确的具体限制外,还需要有特别的硬件措施,否则回收几乎不能实现。 堆式动态储分配的实现通常有如下三种途径: 1 定长块管理 堆式动态储分配最简单的实现是按定长块进行。初始化时,将堆存储空间分成长度相等的若干块,每块中指定一个链域,按照邻块的顺序把所有块链成一个链表,用指针available指向链表中的第一块。 分配时每次都分配指针available所指的块,然后available指向相邻的下一块。归还时,把所归还的块插入链表。考虑插入方便,可以把所归还的块插在available所指的块之前,然后available指向新归还的块。 2 变长块管理 除了按定长块进行分配之外,还可以根据需要分配长度不同的存储块,可以随要求而变。按这种方法,初始化时存储空间是一个整块。按照用户的需要,分配时先是从一个整块里分割出满足需要的一小块,以后,归还时,如果新归还的块能和现有的空间能合并,则合并成一块;如果不能和任何空闲块合并,则可以把空闲块链成一个链表。再进行分配时,从空闲块链表中找出满足需要的一块,或者整块分配出去,或者从该块上分割一小块分配出去。若空闲块表中有若干个满足需要的空闲块时,该分配哪一块呢?通常有三种不同的分配策: ① 首次满足去:只要在空闲块链表中找到满足需要的一块,就进行分配。如果该块很大,则按申请的大小进行分割,剩余的块仍留在空闲块链表中;如果该块不很大,比如说,比申请的块大不了几个字节,则整块分配出去,以免使空闲链表中留下诈多无用的小碎块。 ② 最优满足法:将空闲块链表中一个不小于申请块且最接近于申请块的空闲块分配给用户,则系统在分配前首先要对空闲块链表从头至尾描一遍,然后从中找出一块不小于申
编译原理运行时存储空间的组织和管理课件
变量和数据的存储
• 静态存储:在编译时分配固定大小的内存空间。 • 动态存储:在运行时动态地分配和释放内存空间。 • 数据对齐:为了提高访问效率,对变量在内存中的位置进行调整。 • 在程序中,变量和数据的存储方式通常分为静态存储和动态存储两种。静态存
储是指在编译时就为变量分配固定大小的内存空间,这种方式适用于在程序执 行期间大小不变的变量。而动态存储是在运行时动态地为变量分配和释放内存 空间,它适用于大小在运行时才能确定或者在程序执行过程中会发生变化的数 据结构。为了提高内存访问效率,编译器通常还会进行数据对齐操作,即调整 变量在内存中的位置,使其按照特定的字节边界对齐,这样可以减少CPU访 问内存的次数,提高程序的执行速度。
04 数据段和代码段 的管理
数据段的组织和管理
静态存储分配:在编译时确定变量的 存储空间需求,并为其分配固定的存 储空间。这种分配方式适用于全局变 量和静态变量,其存储空间通常位于 数据段中。
动态存储分配:在运行时根据程序的 需要动态地分配存储空间。这种方式 适用于局部变量和临时变量,其存储 空间通常位于栈或堆中。动态存储分 配能够更有效地利用存储空间,并根 据需要动态调整。
03 堆区和栈区的管 理
堆区的组织和管理
动态内存分配
内存碎片问题
堆区是程序中用于动态内存分配的区 域,使用堆区可以实现在运行时根据 需要动态地分配和释放内存空间。在 堆区中,内存块的大小和数量是灵活 的,可以根据程序的需求进行调整。 常用的动态内存分配函数包括 malloc()和new()。
由于堆区的动态分配特性,频繁地分 配和释放内存块可能会导致内存碎片 问题。内存碎片指的是堆区中无法被 有效利用的小块内存空间。为了解决 这个问题,可以采用内存池技术,预 先分配一大块内存空间,并将其划分 为多个小块,每次需要分配内存时, 从内存池中获取一块合适的内存块。
教学日历-编译原理-2013-2014
5月12日
至
5月18日
4
2
2
第八章语法制导的翻译
语法制导翻译概论
自上而下翻译;
继承属性的自下而上计算;
递归计算;
重点:语法制导定义的分析
第十三周
5月19日
至
5月25日
6
4
2
第八章代码生成
代码生成器设计中的问题;
目标机器;
基本块和流图;
下次引用信息;
重点:中间代码的生成
第十四周
5月26日
至
6月1日
3.《编译技术》第2版.蒋立源编著.西安:西北工业大学出版社
4.《程序设计语言编译原理》第3版,陈火旺等编著.国防工业出版社
教研室主任(学科组长)签名:系(部)主任签名:
年月日 年月日
说明:
1.本教学日历由主讲教师负责填写,于每学期开学第一周内送交教师所在系(部)主任审定、签字。
2.此表一式二份,其中,任课教师自留一份,教师所在系(部)存档一份。
4
1
2
1
第九章符号表
符号表的主要属性及作用
符号表的组织
符号表的管理
第十五周
6月2日
至
6月8日
6
4
2
第十章目标程序运行时的存储组织
源语言问题:过程活动树控制栈声明的作用域名字的结合;
存储组织:运行是内存的划分、活动记录、编译时的局部数据安排;
存储分配策略:静态分配,栈式分配,堆式分配;
第十六周
6月9日
蚌埠学院教学日历
2013~2014学年度第二学期
授课教师姓名邹青青职称讲师
授课专业班级11计算机科学与技术(本1,2,3)
编译原理运行时存储空间组织
主程序P
TOP 4
3
2
1
SP 0
x a 0 返回地址
0
主程序P过程 S
TOP 10
9 8 7 6
SP 5
4 3 2 1 0
动态链
i c 0(形参个数) 0 返回地址
0 x a 0 返回地址
0
?第N层过程调用
第 N+1层过程,如何 确定被调用过程(第 N+1层)过程的静态链?
A:调用过程(第N层
每个过程的活动记录内容如图:
TOP
2 1 SP 0
临时单元 内情向量 局部变量 形式单元 参数个数 返回地址
老SP
对任何局部变量X的 引用可表示为变址访 问:
dx[SP] dx: 变量X相对于活 动记录起点的地址, 在编译时可确定。
9.5 嵌套过程语言的栈式实现
假定语言不仅允许过程的递归调用(和可变 数组),而且允许过程定义的嵌套,如 PASCAL,PL语言。
临时单元 内情向量 局部变量 形式单元
静态链 动态链 返回地址
连接数据
➢返回地址 ➢动态链:指向调用该 过程前的最新活动记 录地址的指针。
➢静态链:指向静态直 接外层最新活动记录 地址的指针,用来访 问非局部数据。
每个过程的活动记录内容
TOP
2 1 SP 0
临时单元 内情向量 局部变量 形式单元
静态链 动态链 返回地址
procedure quicksort(m, n:integer); var i:integer; begin if (n>m) then begin i:=partition(m, n ); quicksort(m, i-1 ); quicksort(i+1, n ) end; end;
目标程序运行时的存储组织
•主程序 •6
PPT文档演模板
目标程序运行时的存储组织
•2. 以过程为单位的存储分配方案的实现
•0层 •1层 •2层 •3层
•p •q •r •主
•t
•程序运行顺序:主程序→t→p→q→r
PPT文档演模板
目标程序运行时的存储组织
• 静态链:指向定义该过程的直接外 层过程(或主程序)运行时刻的数据区的 首(基)地址。
它所对应的动态地址addr(k ,off )可按
下式计算:
•addr(k ,off )=DISPLAY(k)+off
•
=CONTENT(sp+N+k)+off
•其中N是编译可确定的。当k为现役过
程的层数时,有:
•addr(k ,off )=sp•例1:设有:
lay
表
P过程 Display表
P过程活动记录首地址 主程序的SDPisplay表
函数值、形参单元
RA返回地址
先行Display表,存P过程Display表的首 地址SP
DL
PPT文档演模板
目标程序运行时的存储组织
•例2: 现有静态链和动态链相同的程 序 • 静态链 主程序— p — q • 动态链 主程序— p — q • 已知x的抽象地址为x( k, off )。当 •程分序析运:行到q时,求x的值。 • 1. 当x为q过程的变量,求x的值。 • 2 . 当x为p过程的变量,求x的值。 • 3. 当x为主程序的变量,求x的值。
• Display表如下图:
PPT文档演模板
目标程序运行时的存储组织
•top→
临时变量单元 局部变量单元
•N本层DSPLAY表
编译原理——运行时存储空间组织课件
优化程序性能
通过优化运行时存储空间的分配 和管理,可以提高程序的执行效 率,减少不必要的内存访问和数 据拷贝。
保障数据安全
合理地管理运行时存储空间可以 避免数据溢出、缓冲区溢出等安 全问题,提高程序的安全性。
02
栈式存储管理
栈的定义与特性
栈的定义
栈是一种特殊的线性表,只允许在表的一端进行插入和删除 操作。
运行时存储空间的分类
静态存储区
01
存储程序中的常量、字符串常量和全局变量等,在程序运行期
间始终占用固定的内存空间。
堆区
02
动态分配的内存区域,用于存储程序运行过程中动态分配的内
存。
栈区
03
பைடு நூலகம்
存储函数调用的局部变量和函数参数等,具有先进后出的特点
。
运行时存储空间的重要性
提高内存利用率
合理地组织和管理运行时存储空 间,可以提高内存的利用率,避 免内存浪费和冲突。
05
运行时存储空间的优化
内存使用分析
内存占用情况
分析程序在运行过程中占用的内存大小,包括 堆内存、栈内存等。
内存使用模式
研究程序在运行时的内存使用模式,如峰值内 存、平均内存等。
内存泄漏检测
通过工具和技术检测程序是否存在内存泄漏问题。
内存优化策略
内存管理策略
制定合理的内存管理策略,如内存分配、回收和再利用等。
堆内存碎片问题与解决方法
内存碎片问题
由于频繁的动态分配和回收操作,堆中的空闲单元可能会分散在整个存储空间中,导致 无法有效地利用这些空闲单元。
解决方法
为了解决内存碎片问题,可以采用各种策略来重新组织堆,例如合并空闲单元、移动元 素以形成连续的空闲区域等。此外,还可以使用内存池等数据结构来管理内存,以减少
编译原理10
运行时存储区的基本划分
运行时的存储区常常划分为目标区、静态 数据区、栈区和堆区,如下图
code Static data stack ↓ … ↑
heap
堆区是“正向生长”的一块区域
编译原理 计算机学院 李金厚
概念
静态:如果一个名字的性质通过说明语句 或隐或显规则而定义,则称这种性质是 “静态”确定的 动态:如果一个名字的性质只有在程序运 行的时候才能知道,则称这种性质为“动 态”确定的
静态存储分配栈式动态存储分配和堆式动态存储分配编译原理计算机学院静态存储分配策略如果编译时能确定目标程序运行中所需的全部数据空间大小并安排好每个数据对象的存储位置则称这种分配策略为静态存储分配它的每个数据名所需的存储空间大小都是常量因而不支持可变数组整个程序所需数据空间的总量在编译时完全确定编译原理计算机学院动态存储分配如果一个程序设计语言允许递归过程可变数组或允许用户自由申请和释放存储空间就需要采取此种存储管理技术algol语言等就包含这类存储策略的实现用以管理过程活动的记录信息编译原理计算机学院像c中的newdeletepascal中的new等等它假设程序运行时有一个大的存储空间每当需要的时候就从其中借用一块不同时再退还编译原理计算机学院服务于过程的栈式存储分配策略在栈顶为有关过程分配所需的数据空间当一个过程工作完毕返回时它在栈顶区域的数据空间也即释放大家可以结合汇编所学的子程序调用所涉编译原理计算机学院过程的活动记录activationrecord对应一段连续的存储区用以存放过程一次执行相关的信息可见下面的图表临时工作单元局部变量机器状态信息存取链控制链实参返回地址编译原理计算机学院临时工作单元计算表达式时需存放中间结果用的临时值单元局部变量一个过程的局部变量机器状态信息和有关过程执行前的机器状态信息包括程序计数器寄存器的值它们需要在该过程返回时恢复存取链用以存取非局部变量这些变量存放于其他过程活动记录中编译原理计算机学院控制链指向调用该过程的那个过程的活动记实参由调用过程提供相关的值也就是该过程实际运行所需要的参数值返回地址保存调用该过程的位置以保证调用过程结束正常返回编译原理计算机学院针对没有分程序结构过程定义不嵌套但允许过程递归调用的情况例对下面的程序主程序调用了过程qq又调用了r在r进入运行后的存储结构的图见下页programmain
运行时存储空间组织
运行时存储空间组织知识结构:存储器组织和分配概述基本概念语言中的参数形式参数传递方法运行时存储器的划分运行时存储器的划分活动记录运行时存储存储分配策略空间组织对语言的要求静态存储分配实现方法动态存储分配过程的活动记录DISPLAY表的作用和生成第一节目标程序运行时的活动编译程序最终目的是将源程序翻译成等价的目标代码。
了解目标代码在运行时,用户在源程序中定义各种信息(如变量)的存放和访问.存储组织和管理是一个复杂而又十分重要的问题,主要讨论:⑴活动记录的建立和管理;⑵存储组织和分配的策略;⑶全局信息的访问。
一、过程的活动在程序执行过程中,程序中数据的存取是通过与之对应的存储单元进行的。
数据地址、代码地址在编译时均安排为相对地址(以0为基地址)。
1、参数过程或函数,被调用时引用的变量或表达式。
2、形式参数被调用的过程或函数中引用的变量。
3、实在参数过程或函数调用时定义的变量或表达式(调用时替换过程或函数引用的形式参数)。
4、活动生存期过程的一次调用称为一个活动(或一个活动的生存期)。
5、递归过程的递归调用,当一个过程在没有退出当前的活动时,又开始其新的活动称递归调用:直接递归调用: procedure p beginP( )end间接递归调用: procedure pbeginQ( )endprocedure Qbeginp( )end6、作用域如果变量在一过程中定义并只在该过程中被引用,称之为局部变量,否则为全局变量。
二、参数的四种传递方法例 PROCEDURE P (X ,Y ,Z ) PROCEDURE q ()begin begin {调用段}Y:=y+1 A:=2;Z:=Z+X B:=3;end {p} P(A+B, A ,A)PRINT Aend1、传地址每个形参存放相应的实参的地址,对形参的任何访问都按间接地址访问(访问的对象是实参的地址)。
调用段实参单元 被调用段形参单元X YZA PRINT A 的值为8。
编译原理运行时的存储组织与分配课件
语法分析
语法分析器根据语言 的语法规则,将单词 列表转换成抽象语法 树(AST)。
语义分析
语义分析器对AST进 行语义检查,如类型 检查、变量声明等。
优化
优化器对AST进行优 化,以提高生成代码 的性能。
代码生成
代码生成器将AST转 换成目标机器代码。
03
运行时的存储组织
运行时存储空间的划分
代码段
学习高级的编译器设计技术,如自动并行化、向量化等, 以适应现代计算机体系结构和编程语言的发展。
学习与编译器相关的扩展语言和工具,如嵌入式语言、 形式化验证工具等,扩展自己的技能范围。
感谢您的观看
THANKS
编译原理涉及的领域广泛,包括程序设计语言、计算机体系结构、操作系统等, 是计算机科学领域的重要基石。
存储组织与分配的研究背景
存储组织与分配是编译原理中的一个重要问题,它涉及到如 何在内存中组织和分配程序的数据和代码,以最大限度地提 高内存的利用率和程序的执行效率。
随着计算机硬件技术的发展,存储组织与分配的研究也在不 断深入,它不仅涉及到编译原理,还涉及到操作系统的内存 管理、计算机体系结构的存储系统设计等多个领域。
分配策略
XX编译器使用静态分配策略,在编译时确定每个变量或数据结构的内存需求,并在运行时直接分配给 它们相应的内存空间。这种策略减少了运行时的开销,但无法处理动态内存需求。
XX解释器的存储组织与分配实例
存储组织
XX解释器将源代码的存储分为多个内存 块,包括代码块、数据块和堆栈块。代 码块存储解释器执行的机器码,数据块 存储全局变量和静态变量,堆栈块用于 存储函数调用和局部变量,以及动态分 配的内存。
堆的组织方式通常是非连续的, 由操作系统进行管理,通过指 针或引用进行访问。
编译原理运行时存储空间组织
(12) procedure quicksort(m, n:integer);
(13) var i:integer;
(14) begin
(15) if (n>m) then begin
(16) i:=partition(m, n );
(17) (18) (19)
quicksort(m, i-1 ); quicksort(i+1, n ) end;
对任何局部变量X 的引用可表示为变 址访问:
dx[SP] dx: 变量X相对于 活动记录起点的 地址,在编译时可 确定。
每个过程的活动记录内容(嵌套语言)
TOP→ 临时单元 内情向量 局部变量 形式单元
2 静态链 1 动态链 SP→ 0 返回地址
q 连接数据
Ø 返回地址 Ø 动 态 链 : 指 向 调 用 该过程前的最新活动 记录地址的指针。 Ø 静 态 链 : 指 向 静 态 直接外层最新活动记 录地址的指针,用来 访问非局部数据。
v 一个目标程序运行所需的存储空间包括:
l 存放目标代码的空间 l 存放数据项目的空间 l 存放程序运行的控制或连接数据所需单元(控制
栈)
v 运行时存储空间划分:
目标代码(Code) 静态数据
(Static Data) 栈(Stack) ↓ ↑ 堆(Heap)
9.2.2 活动记录
v 假定语言的特点为:允许过程递归调用、允许过程含 有可变数组,但过程定义不允许嵌套,如C语言。
l 过程是否允许递归? l 当控制从一个过程的活动返回时,对局部名
称的值如何处理? l 过程是否允许引用非局部名称? l 过程调用时如何传递参数;过程是否可以做
为参数被传递和做为结果被返回? l 存储空间可否在程序控制下进行动态分配? l 存储空间是否必须显式地释放?
