第8章 存储空间的分配

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

printd(int n) { int i; if(n<0) {putchar(‘-’); n=-n; } if((i=n/10)!=0) printd(i); L:putchar(n%10+’0’); }
top
简单变量:i=1
形参:n=12
参数个数:1 sp top
返回地址 老sp:k1
简单变量:i=12
临时变量 数组 简单变量

新的Байду номын сангаас动记录
数组 临时变量
数组内情向量
变,则不能确 定活动记录的 大小,但要求 在编译时一定 要能确定活动 记录的长度, 为此,将活动 记录改为:
简单变量

活 动 记 录
30
对数组建立内情向量,记录已知信息。 如:
数组起始地址a 维数n 数组常量C d1 d2 … dn 数组起始地址a 维数n 数组常量C L1 N1 d1 L2 N2 d2 … … Ln Nn dn 这样便于计算数组越界
k1
27
top
printd(int n) { int i; if(n<0) {putchar(‘-’); n=-n; } if((i=n/10)!=0) printd(i); L:putchar(n%10+’0’); }
简单变量:i=0
形参:n=1
参数个数:1
返回地址
sp 老sp:k2 简单变量:i=1
动态数据区
由动态存储分配产生的数据区。 这种数据区不是固定不变的。随着相应 程序单位的调用和返回,它也会进入和退 出。
8
静态存储分配对程序设计语言的要求:
不允许有递归调用;
不允许有嵌套的子程序;
不允许有可变数组。
FORTRAN语言满足这些要求。
9
变量地址= 相对地址 + 起始地址
top
简单变量:i=12 形参 形参 :n=-125 :n=125
进入子过程体内,填简单变量i 参数:n=-125<0,先打印’-’,n=125; sp i=125/10=12!=0 : printd(12) top
sp
参数个数:1
返回地址 老sp:K
k1

25
①进入子过程体前: (1+3)[top]=Ti=n=12 1[top]=sp=k1 3[top]=参数个数=1 ②转入子过程体 sp=top+1 1[sp]=返回地址 top=top+L
k3
top
形参:n=12
参数个数:1 sp
返回到第2次调用处(包括返回数 据区): n=12,打印:12%10+‘0’=‘2’
返回地址 老sp:k1
简单变量:i=12
k2
形参:n=125 参数个数:1 返回地址 老sp:k …
k1
28
printd(int n) { int i; if(n<0) {putchar(‘-’); n=-n; } if((i=n/10)!=0) printd(i); L:putchar(n%10+’0’); }
31
Void p(…) { … int A[1..m]; int B[1..n]; … }
top
数组B 数组A P的活动记录 …
sp
32
计算各维的长度(或上、下限)
调用数组空间分配子程序,其参数为
各维的长度(或上、下限)及内情向 量的起始地址。
33
填写内情向量中的信息
(数组起址:=top+1 )
17
top sp top sp
Q的数据区 R的数据区
Q的数据区
全局变量
当 Q 退出后, SP 应指到什 么地方不知道(因为 R 的 长度不知),因此在每个 数据区设一老 SP 记下上一 过程的SP值。
18
设a为数据区中的相对地址, 则a[sp]为相对地址a+sp的地址;

20
简单变量

则20[sp]:将20单元 的简单变量取出来。
调整top:top:=top+v v为数组体积
top top
数组 P的活动记录 …
sp
34
例:
procedure P procedure Q procedure R
这种过程嵌套结构所附 带的语义检查: ①过程调用的合理性 ②变量使用的合法性
end end
end
35
由于过程定义是嵌套的,任一个过程都 可以引用其外层过程中定义的变量。 因此,子过程必须要知道其全部外层过 程的最新活动记录的地址。 由于允许递归调用和包含可变数组,因 此过程的活动记录位置往往是变化的, 因此应跟踪每个外层过程的最新活动记 录的位置。
12
栈式存储分配适合于:
层次嵌套结构
允许过程递归调用
含可变数组
的程序设计语言。
13
数据区内容
临时变量 数组 简单变量 形式单元 参数个数 返回地址
将这样一个数据区称为 一个活动记录。 活动记录的大小在编译 时可以静态地确定。
14
活动数据区的内容与静态存储分配的数 据区相同, 所不同的是要允许递归,则每调用一次 过程都要生成一个数据区,每次操作都 是在新的数据区上进行, 递归调用多少次就生成多少个数据区 由于只有在运行时才知道调用多少次, 因此只能在运行时确定分配多少空间。
top sp
老sp

进入P后,首先应定义新的活动记录的 sp,然后保存返回地址并定义新的top值

20
对应的目标动作:②进入P后的动作:
sp:=top+1; //定义新sp
top Add(T3)
1[sp]:=返回地址;//保存返回地址 top:=top+L; //定义新的top
过程P的活动记录长 度,在编译时可静 态计算出来。
活动记录内容 运行时,每当进入一个过程就 top 临时变量 将此过程的数据区(活动记录 数组 )置于栈顶。 简单变量 当过程执行完毕后,该过程所 形式单元 对应的数据区也不复存在,进 参数个数 入到下一个将要执行的过程的 数据区中。 返回地址 因此,有必要用两个寄存器来 sp 老sp(控制链) 记下数据区的大小。 现行过程活动记录起点
top
简单变量:i=1
形参:n=12
参数个数:1 sp top
返回地址 老sp:k1
简单变量:i=12
k2
返回到第1次调用处(包括返回数 据区): n=125, 打印:125%10+‘0’=‘5’ 总的打印结果为:-125
sp
形参:n=125 参数个数:1 返回地址 老sp:k …
k1
29
原来的活动记录 若数组长度可
Add(T2) Add(T1)
参数个数:3 返回地址 sp top sp
老sp


21
对应的目标动作: ③从P返回时的动作:
top:=sp-1; sp:=0[sp]; //老sp 无条件转2[top] //返回地址
top
Add(T3)
Add(T2) Add(T1)
参数个数:3
返回地址
sp top sp
简单变量:i=0
形参:n=1
参数个数:1
返回地址
sp 老sp:k2 简单变量:i=1
k3
形参:n=12
参数个数:1
进入过程体内: 参数n=1 i=1/10=0; putchar打印:1%10+‘0’=‘1’;
返回地址 老sp:k1
简单变量:i=12
k2
形参:n=125 参数个数:1 返回地址 老sp:K …
3
编译程序必须分配目标程序运行时的 存储空间。这些存储空间包括:
用户定义的各类变量和常量所需存储单 元; 作为保留中间结果的参数传递用的临时 工作单元; 调用过程或函数时需要的形式单元; 返回地址以及组织输入 / 输出所需的缓冲 区。
4
从本质上看,数据对象的空间分配是将 程序中的每个对象名字与一个存储位置 进行绑定。 目标程序运行时的数据空间组织的基本 依据是程序设计语言对程序运行中存储 空间的使用和管理办法的规定。
临时变量 数组 简单变量 形式单元 寄存器保护区 返回地址
10
很多高级语言都支持嵌套分程序、嵌 套或递归过程结构及动态数组, 这些需要运行时存储空间管理机制。 栈式存储分配方法是适合于这类语言 的一种存储管理方法。 栈式存储分配方法是把整个程序的存 储空间都安排在一个栈内。
11
进入主程序时,将主程序定义的各类全程 量所需存储空间分配于栈顶; 每当调用一个子程序(过程 /函数)时,就 将其所需的存储空间分配于栈的当前栈顶; 每当从子程序运行结束时,就从栈中释放 其所占空间; 整个程序执行完后,释放它所占用的全部 空间。
如:递归调用的过程,在运行时,其同一 个局部名字应对应不同的运行空间位置。
5
过程是否允许递归? 当控制从一个过程的活动返回时,对局部 如何处理? 过程是否允许引用非局部名? 过程调用时如何传递参数;过程是否可以 作为参数被传递和作为结果被返回? 存储空间可否在程序控制下进行动态分配? 存储空间是否必须显式地释放?
老sp


22
动态存储分配比静态存储分配省空间。
因为当某一过程执行完后就可以释放它
所占的空间,只有当都不释放空间时才
与静态分配所用空间相同。
但动态分配省空间所付出的代价是运行
时分配,降低了执行效率。
23
某含递归调用的C语言程序: printd(int n) { int i; if(n<0) { putchar(‘-’); n=-n; } if((i=n/10)!=0) printd(i); L:putchar(n%10 +‘0’); } //打印余数 在主程序中调用:printd(-125)
36
静态链
指向其直接外层过程的最新活动记录的 基地址。
Display表
每当进入一个子过程时,在建立它的活 动记录区的同时建立一张嵌套的层次显 示表——display。
37
层次
0
Program P; Var a,x: integer; 1 Procedure Q(b:int ) Var i:integer; 2 Procedure R( u:int; Var v:int); Var c,d: integer begin if u=1 then R(u+1,v)
sp
老sp(控制链)
19
过程调用四元式: 对应的目标动作: (par,_,_,T1) (par,_,_,T2) (par,_,_,T3) (call,_,_,p)
①进入P前的动作:
Add(T3) Add(T2)
Add(T1)
参数个数:3
//地址调用 (i+3)[top]:=add(Ti) //值调用 (i+3)[top]:=Ti 1[top]:=sp;//保存老sp 3[top]:=参数个数
24
①进入子过程体前: (1+3)[top]=Ti=n=-125 1[top]=sp=k //保留老sp 3[top]=参数个数=1 ②转入子过程体 sp=top+1 1[sp]=返回地址 top=top+L
printd(int n) { int i; if(n<0) {putchar(‘-’); n=-n; } if((i=n/10)!=0) printd(i); L:putchar(n%10+’0’); }
6
静态存储分配
在编译阶段进行的存储分配。 对程序中的简单变量和常量数组,由于它们 所需的存储单元数在编译时就可以确定,因 此在编译时就可以给它们分配存储单元。
动态存储分配
在运行阶段才能确定数据的位置及大小的分 配方法。
7
静态数据区
由静态存储分配产生的数据区。 这种数据区在整个程序运行过程中是固 定不变的。
第八章 运行时的存储空间组织
8.1 概述 8.2 静态存储分配 8.3 动态存储分配
2
编译程序的最终目的是将源程序翻译 成等价的目标程序。 因此,除了进行词法、语法、语义分 析外,在生成目标代码前,需要把程序 静态的正文与程序运行时的活动联系起 来,弄清楚在代码运行时刻,程序中的 各种变量、常量等是如何存放的,如何 去访问它们。
15
Program main; 全局变量 procedure R; … end;(R) procedure Q; … call R; end;(Q) … 主程序; call Q; … end.(main)
设在主程序中调用Q, Q又调用了R,则栈式 分配为:
R的数据区 Q的数据区 主程序的数据区
每调用一个过程就开辟一 个数据区。当某个过程执 行完后,退出此过程的数 据区,进入下一个过程的 数据区。 16
k2
进入子过程体内,填简单变量i i=12/10=1!=0 : printd(1)
sp
形参:n=125 参数个数:1 返回地址 老sp:K …
k1
26
top
printd(int n) { int i; if(n<0) {putchar(‘-’); n=-n; } if((i=n/10)!=0) printd(i); L:putchar(n%10+’0’); }
相关文档
最新文档