资源描述
,武汉理工大学计算机科学与技术系,Compile,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,目标程序运行时的组织,从逻辑上看,在代码生成前,编译程序必须进行目标程序运行环境的配置和数据空间的分配。,数据空间应包括:,用户定义的各种类型的数据对象(变量和常数)所需的存储空间;,作为保留中间结果和传递参数的临时工作单元;,调用过程时所需的连接单元;,组织输入,/,输出所需的缓冲区。,目标代码所占用空间的大小在编译时能确定。有些数据对象所占用的空间也能在编译时确定,其地址可以编译进目标代码中。而有些数据对象具有可变体积和待分配性质,无法在编译时确定存储空间的位置。,因此运行时的存储区常常划分成:目标代码区、静态数据区、栈区和堆区,如图,。,目标代码区,code,静态数据区,static,栈,Stack,堆,heap,图,10.1,目标程序运行时存储区的典型划分,所谓数据空间的分配,本质上看,是将程序中的每个名字与一个存储位置关联起来,该存储位置用以容纳名字的值。,编译程序分配目标程序运行时的数据空间的基本依据是程序语言设计时对程序运行中存储空间的使用和管理办法的规定。,在程序设计语言语义学中,使用术语,environment,表示将一个名字映射到一个存储位置的函数,术语,state,表示存储位置到值的映射,如图所示。,图,10.2,名字到存储位置、到值的映射,编译程序分配目标程序运行时的数据空间的基本依据是程序语言设计时对程序运行中存储空间的使用和管理办法的规定。,决定存储管理复杂程度的因素,-,源语言本身,比如源语言允许的数据类型有多少?语言中允许的数据项是静态确定还是动态确定?程序结构有什么特点,是段结构还是分程序结构?过程定义是否允许嵌套?等等。,源语言的结构特点、源语言的数据类型、源语言中决定名字作用域的规则等因素影响存储空间的管理和组织的复杂程度,决定数据空间分配的基本策略。,10.1,数据空间的三种不同使用方法和管理方法,数据空间的使用和管理方法,:,简单的栈式分配方案,嵌套过程的栈式分配方案,分程序结构的存储分配方案,静态存储分配、,动态存储分配,栈式,堆式,10.1.1,静态存储分配,如果在编译时能确定目标程序运行中所需的全部的数据空间的大小,编译时安排好目标程序运行时的全部数据空间,确定每个数据对象的存储位置,称这种分配策略为静态存储分配。,如,C,中的静态变量,外部变量等。,10.1.2,动态存储分配,如果一个程序设计语言允许递归过程、允许动态的申请建立和撤消存储空间、可变数组或允许用户自由申请和释放空间,那么,就需要采用动态存储管理技术。,因为对于这种程序在编译时无法知道它在运行时需要多大的存储空间,它所需要的数据空间的大小需待程序运行时动态地确定。,若一个数组所需的存储空间的大小在编译时就已知道,则称它为确定(静态)数组,否则称为可变(动态)数组。,10.1.2.1,栈式动态存储分配,这种分配策略是将整个程序的数据空间设计为一个栈。,在具有递归结构的语言程序中,每当调用一个过程时,它所需的数据空间就分配在栈顶,每当过程工作结束时就释放这部分空间。,过程所需的数据空间包括两部分:,生存期在本过程这次活动中的数据对象;,用以管理过程活动的记录信息。,栈式动态存储分配策略适用于,PASCAL,,,C,,,ALGOL,之类具有递归结构的语言的实现。,10.1.2.2,堆式动态存储分配,如果一个程序语言提供用户自由地申请数据空间和退还数据空间的机制,或者不仅有过程而且有进程的程序结构,一般用堆式的动态存储分配方案。,如,+,中的,new,,,delete,,,PASCAL,的,new,,等机制。,此时,空间的使用未必服从“先申请后释放,后申请先释放”的原则,那么栈式的动态分配方案就不适用了。通常使用一种称为堆式的动态存储分配方案。,这种分配方式的存储管理技术甚为复杂,我们这里举出这种分配方法必须考虑的几个问题。,堆式的动态存储分配策略,:,当运行程序要求一块体积为,N,的空同时,我们应该分配哪一块给它呢?,理论上说,应从比,N,稍大一点的一个空闲块中取出,N,个单元,以便使大的空闲块派更大的用场。但这种做法较麻烦。,因此,常常仍采用“先碰上哪块比,N,大就从其中分出,N,个单元”的原则。但不论采用什么原则,整个大存区在一定时间之后必然会变成零碎不堪。,总有一个时候会出现异样的情形:运行程序要求一块体积为,N,的空间,但发现没有比,N,大的空闲块了,然而所有空闲块的总和却要比,N,大得多!出现这种情形时怎么办呢?这是一个比前面的问题难得多的问题。,解决办法似乎很简单,这就是,把所有空闲块连接在一起,形成一片可分配的连续空间。,这里主要问题是,我们必须调整运行程序对各占用块的全部引用点。,堆式的动态存储分配策略,:,另外,如果运行程序要求一块体积为,N,的空间,但所有空闲块的总和也不够,N,,那又应怎么办呢?,有的管理系统采用一种叫做垃圾回收的办法来对付这种局面。即寻找那些运行程序业己无用但尚未释放在占用块,或者那些行程序目前很少使用的占用块,把这此占用块收回来,重新分配。,但是,我们如何知道哪些块运行时在使用或者目前很少使用呢?即便知道了,一经收回后运行程序在某个时候又要用它时又应该怎么办呢?,要使用垃圾回收技术,除了在语言上要有明确的具体限制外,还需要有特别的硬件措施,否则回收几乎不能实现。,堆式动态储分配的实现通常有如下两种途径:,1,)定长块管理,堆式动态储分配最简单的实现是按定长块进行。初始化时,将堆存储空间分成长度相等的若干块,每块中指定一个链域,按照邻块的顺序把所有块链成一个链表,用指针,available,指向链表中的第一块。,分配时每次都分配指针,available,所指的块,然后,available,指向相邻的下一块。归还时,把所归还的块插入链表。考虑插入方便,可以把所归还的块插在,available,所指的块之前,然后,available,指向新归还的块。,堆式动态储分配最简单的实现是按定长块进行。,D I S P L A Y,4 过程调用、过程进入和过程返回,这种分配策略是将整个程序的数据空间设计为一个栈。,因此,可以把处理过程的存储办法应用到处理分程序中。,Display表-嵌套层次显示表,即每进入一个过程后,在建立它的活动记录的同时建立一张Display表。,用以存取非局部变量,这些变量存放于其他过程的活动记录中。,当然在实际编译程序中,也常常使用机器寄存器传递实参。,调用swap(i,ai)其结果等价于执行下列运算:,这种分配策略是将整个程序的数据空间设计为一个栈。,这样,每个过程的活动记录所含的内容有:,决定存储管理复杂程度的因素-源语言本身,比如源语言允许的数据类型有多少?语言中允许的数据项是静态确定还是动态确定?程序结构有什么特点,是段结构还是分程序结构?过程定义是否允许嵌套?等等。,占用,占用,占用,空闲,空闲,空闲,available,(a),占用,占用,空闲,空闲,空闲,(b),空闲,available,图,10.3,定长块管理,2,)变长块管理,除了按定长块进行分配之外,还可以根据需要分配长度不同的存储块,可以随要求而变。按这种方法,初始化时存储空间是一个整块。按照用户的需要,分配时先是从一个整块里分割出满足需要的一小块,以后,归还时,如果新归还的块能和现有的空间能合并,则合并成一块;如果不能和任何空闲块合并,则可以把空闲块链成一个链表。再进行分配时,从空闲块链表中找出满足需要的一块,或者整块分配出去,或者从该块上分割一小块分配出去。若空闲块表中有若干个满足需要的空闲块时,该分配哪一块呢,?,通常有三种不同的分配策略:,变长块管理通常有三种不同的分配策略:,首次满足法(时间优先),;,最优满足法(空间优先),;,最差满足法(时间优先)。,上述三种分配策略各有所长。,10.2,栈式存储分配的实现,前面提到,使用栈式存储分配策略意味着,运行时每当进入一个过程,就在栈顶为该过程的临时工作单元,局部变量,机器状态及返回地址等信息分配所需的数据空间,当一个过程工作完毕返回时,它在栈顶的数据空间也即释放。,为讨论方便,首先引入一个术语,-,过程的活动记录,AR(Activation Record),。过程的活动记录是一段连续的存储区,用以存放过程的一次执行所需要的动态信息,这些信息可以如图所示。,图,10.6,过程的活动记录,返回地址,实参,控制链,存取链,机器状态信息,局部变量,临时工作单元,临时工作单元,:比如计算表达式过程中需存放中间结果用的临时值单元。,局部变量,:一个过程的局部变量。,机器状态信息:,保存该过程执行前关于机器状态的信息,诸如程序计数器、寄存器的值,这些值都需要在控制从该过程返回时给予恢复。,存取链,:用以存取非局部变量,这些变量存放于其它过程的活动记录中。并不是所有语言需要该信息。,控制链,:指向调用该过程的那个过程的活动记录,这也不是所有语言都需要的。,实参,:也称形式单元,由调用过程向该被调过程提供实参的值(或地址)。当然在实际编译程序中,也常常使用机器寄存器传递实参。,返回地址,:保存该被调过程返回后的地址。,图,10.6,过程的活动记录,返回地址,实参,控制链,存取链,机器状态信息,局部变量,临时工作单元,静态链,指向静态直接外层最新活动记录的起始地址,,即指向,定义,本过程的,直接外层过程,(或主程序)运行时,最新,活动记录的基地址,。,动态链,,指向,调用,该过程前正在运行过程的数据段基地址。,10.2.1,简单的栈式分配的实现,程序结构特点,:,过程定义不嵌套,过程可递归调用,含可变数组;例:,program,main,全局变量的说明,proc R,end R;,proc Q,end Q;,主程序执行语句,end main,图,10.7,过程定义不嵌套的程序结构,这种情况下,采用栈式动态分配策略,即,运行时,每当进入一个过程,则为该过程分配一段存储区,当一个过程工作完毕返回时,它所占用的存储区可释放。程序运行时的存储空间,(,栈,),中在某一时刻可能会包含某个过程的几个活动记录(某个过程递归调用的情况);另外,同样的一个存储位置,在不同运行时刻可能分配给不同的数据对象。,例如图的程序结构中,若主程序调用了过程,Q,,,Q,又调用了,R,,在,R,进入运行后的存储结构如图(,a,)所示。,若主程序调用了过程,Q,,,Q,递归调用自己,在,Q,过程第二次进入运行后的存储结构如图(,b,)所示。若主程序先调用过程,Q,,然后主程序接着调用,R,,且,Q,过程不调用,Q,和,R,,这时,Q,和,R,进入运行后的存储结构,先后分别如图(,c,)和(,d,)所示。,TOP,临时工作单元,局部简单变量,局部数组的内情向量,保存运,行过程前的状态,(返回地址,寄存器值,),实参,(形式单元)和参数个数,SP,存取链(,静态链,),控制链,(,动态链,,老,SP,),图,10.6,过程的活动记录,Main,Q,R,TOP,R,的活动记录,SP,主程序全局,数据区,Q,的活动记录,Main,Q,Q,Q,的活动记录,主程序全局,数据区,Q,的活动记录,图,10.8,栈式存储分配,静态链,指向静态直接外层最新活动记录的起始地址,,即指向,定义,本过程的,直接外层过程,(或主程序)运行时,最新,活动记录的基地址,。,动态链,,指向,调用,该过程前正在运行过程的数据段基地址。,指向调用该过程的那个过程的最新活动记录的起始地址,用以存取非局部变量,这些变量存放于其他过程的活动记录中。,TOP,R,的数组区,SP,R,的活动记录,Q,的活动记录,主程序全局,数据区,图,10.10,分配了数组区之后的运行栈,TOP,临时工作单元,局部简单变量,局部数组的内情向量,返回地址,实参,(形式单元),SP,参数个数,控制链,(老,SP,),图,10.9,无嵌套定义,的过程活动记录内容,10.2.2,嵌套过程语言的栈式实现,主要特点:,(语言)一个过程可以引用包围它的任一外层过程所定义的标识符(如变量,数组或过程等)。,(实现)一个过程可以引用它的任一外层过程的最新活动记录中的某些数据。,(1)program,sort,(input,output);/sort,的过程头,(2),var a:array 0.10 of integer;(3),x:integer;(4),procedure,readarray,;/sort,内嵌套定义的,readarray,的过程头,(5),var i:integer;(6),beginaendreadarray;/readarray,的过程体,(7),procedure,exchange,(i,j:integer);,/sort,内嵌套定义的,exchange,的过程头,(8),begin(9),x=ai;ai=aj;aj=x;/exchange,的过程体,(10),endexchange;(11),procedure,quicksort,(m,n:integer);,/sort,内嵌套定义的,quicksort,的过程头,(12),var k,v:integer;(13),function,partition,(y,z:integer):integer;,/quicksort,内嵌套定义的,partition,的函数头,(14),var i.j:integer;(15),begin a/partition,的函数体,(16),v(17),exchange,(i,j);(18),endpartition;(19),beginendquicksort;/quicksort,的过程体,(20)beginendsort./sort,的例程体,图,10.11,具有嵌套过程的,PASCAL,程序,图的,PASCAL,程序中过程定义的嵌套情况如下:,sort,readarray,exchange,quicksort,partition,局部变量,a,x,局部变量,k,v,过程,quicksort,的活动记录,过程,sort,的活动记录,图,10.12,存储栈布局,记录下列信息:,可以引用过程,sort,的局部变量,关键技术:解决对非局部量的引用(存取)。,设法跟踪每个外层过程的最新活动记录,AR,的位置。,跟踪办法:,1.,用静态链(如,PL/0,的,SL,)。,2.,用,DISPLAY,表。,跟踪的办法很多,我们介绍两种,一种是在过程活动记录中增设存取链,指向包含该过程的直接外层过程的最新活动记录的起始位置。过程活动记录的内容如图(,a,)所示。图所提到的情况可用图(,b,)说明。,图,10.13,嵌套定义过程的活动记录和存储栈,(a),局部变量,存取链,控制链,TOP,SP,存取链,控制链,(,老,SP),TOP,SP,(b),quicksort,的,AR,sort,的,AR,再回到图的例子。如果该程序的某次执行顺序为:,sortquicksortquicksortpartitionexchange,即主程序,(,最外层过程,)sort,开始执行,继而进入过程,quicksort,,而又一次进入过程,quicksort,,接着进入过程,partition,,进入过程,exchange,。图给出了进入过程,exchange,之后运行栈的示意,我们仅把存取链和控制链的值标明。,可以看出,过程,exchange,由过程(函数),partition,调用,但,exchange,的直接外层过程是,sort,,所以过程,exchange,的活动记录的存取链指向,sort,的活动记录的始址。,图,10.15,运行栈,静态链,指向静态直接外层最新活动记录的起始地址,,动态链,,指向,调用,该过程前正在运行过程的数据段基地址。,exchange,的活动记录,partition,的活动记录,quicksort,的活动记录,quicksort,的活动记录,sort,的活动记录,解决对非局部量的引用(存取)的确有效办法是用,Display,表。,Display,表,-,嵌套层次显示表,,即每进入一个过程后,在建立它的活动记录的同时建立一张,Display,表。,当前激活过程的层次为,K,,它的,Display,表含有,K+1,个单元,依次存放着现行层,直接外层,直至最外层的每一过程的最新活动记录的基地址。,例:,program main(i,0);,程序结构图,proc R(,c,d);,R,end /*,R*/,proc P (a);,主,proc Q(b);,P,Q,call,R,R(,x,y);,end /*,Q*/call Q,Q(z);call P,end /*,P*/,call R,P,(,W,);,R,(,U,,,V,);,end /*,main*/,用,Display,表的方案,(1),主程序,-(2)P-(3)Q-(4)R,主程序的,活动记录,d0,sp,display,top,(,1,),d1,d0,P,的,活动记录,主程序的,活动记录,display,sp,top,(,2,),用,Display,表的方案,主程序,-P-Q-R,d2,d1,d0,Q,的,活动记录,P,的,活动记录,主程序的,活动记录,display,sp,top,(,3,),R,的,活动记录,Q,的,活动记录,P,的,活动记录,主程序的,活动记录,d1,d0,display,top,sp,(,4,),DISPLAY,表的维护和建立,DISPLAY,表,d,运行栈,0,主程活动记录地址,1 R,活动记录地址,.,当过程的层次为,n,,它的,display,为,n+1,个值。,一个过程被调用时,从调用过程的,DISPLAY,表中自下向上抄录,n,个,SP,值,再加上本层的,SP,值。,全局,DISPLAY,地址,0,老,SP,1,返回地址,2,全局,DISPLAY,地址,3,参数个数,4,形式单元,.,.,.,d,DISPLAY,.,.,.,简单变量,数组内情向量,临时变量,分程序结构,Procedure A(m,n);integer m,n;,B,1,:begin real z;array Bm:n;,B,2,:begin real d,e;,L,3,:2,end;,B,4,:begin array C1:m;1,B,5,:begin real e;,L,6,:5 4,end;,end;,L,8,:end;,分程序结构的存储分配方案,处理分程序结构存储分配方案的一种简单办法是,把分程序看成“无名无参过 程”,它在哪里定义就在哪里被调用。因此,可以把处理过程的存储办法应用到处理分程序中。但这种做法是极为低效的。,一则,每逢进入 一个分程序,就照样建立连接数据和,DISPLAY,表,这是不必要的。,二则,当从内层分程序向外层转移时,可能同时要结束若干个分程序。,按照过程处理办法,意味着必须一层一层地通过“返回”来恢复所要到达的那个分程序的数据区,但不能直接到达。,例如:如果有一个从第,5,层分程序转出到达第,1,层分程序的标号,L,,虽然在第,5,层分程序工作时知道,L,所属的层数,我们极易从,DISPLAY,中获得第,1,层分程序的活动记录基址(,SP,),但是怎么知道第,1,层分程序进入时的,TOP,呢?唯一的办法是从,5,4,3,和,2,各层顺序退出。但这种办法是很浪费时间的。,为了解决上述问题,可采取两种措施。第一,对每个过程或分程序都建立有自己的栈顶指示器,TOP,,代替原来仅有过程的栈顶指示器,每个,TOP,的值保存在各自活动记录中。这样,上述的第二个问题便可解决。第二,不把分程序看作“无参过程”,每个分程序享用包围它的那个最近过程的,DISPLAY,。每个分程序都隶属于某个确定的过程,分程序的层次是相对于它所属的那个过程进行编号的。,:,每个过程被当作是,0,层分程序。而过程体分程序(假定是一个分程序)当作是它所管辖的第,1,层分程序。,这样,每个过程的活动记录所含的内容有:,1.,过程的,TOP,值,它指向过程活动记录的栈顶位置。,2.,连接数据,共四项:,(1),老,SP,值;,(2),返回地址;,(3),全局,DISPAY,地址;,(4),调用时的栈顶单元地址,老,TOP,。,3.,参数个数和形式单元,4.DISPAY,表。,5.,过程所辖的各分程序的局部数据单元。对于每个分程序来说,它们包括:,(,1),分程序的,TOP,值。当进入分程序时它含现行栈顶地址,以后,用来定义栈的新高度(分程序的,TOP,值);,(,2),分程序的局部变量,数组内情向量和临时工作单元。,过程的活动记录,B,的,数,组,B,的内情向量,变量,z,k,d,D I S P L A Y,6,形式单元,m,n,5,参数个数:,4,调用时的栈顶地址(老),3,全局,D I S P L A Y,地址,2,返回地址,1,老,S P,0,过程的,指向活动记录之顶,SP,数,组的内情向量,B,的,B,的,B,的,变量,e,变量,d,和,e,B,B,1,T,O,B,的,信,息,向,量,Z,B,1,的,P,D I S P L A Y,形式单元,m,n,2,连,接,数,据,A,的,T O P,(b),进,入,分,程,序,B,1,D I S P L A Y,形式单元,m,n,2,连,接,数,据,(a),到,达,标,号,B,1,处,A,的,T O P,(,d,)进入分程序,B2,数,组,B,e,d,B2,2,的,T O P,B,的,信,息,向,量,z,B,1,的,T O P,D I S P L A Y,形式单元,m,n,2,连接,数,据,A,的,T O P,数,组,B,B,的,信,息,向,量,z,B1,的,T O P,D I S P L A Y,形式单元,m,n,2,连,接,数,据,A,的,T O P,(,c,)数组分配之后,(e),进入分程序,B,4,分配数组,C,之后,数,组,C,数,组,B,C,的,向,量,内,情,B4,的,T O P,B,的,内,情,向,量,Z,B,1,的,T O P,D I S P L A Y,形式单元,m,n,2,连,接,数,据,A,的,T O P,(f),进入分程序,B,5,数,组,C,数,组,B,e,B,5,的,T O P,C,的,内,情,向,量,B,4,的,T O P,B,的,内,情,向,量,z,B,1,的,T O P,D I S P L A Y,形式单元,m,n,2,连接数据,A,的,T O P,10.3,参数传递,(1)procedure exchangel(i,j:integer);,(2)var x:integer;,(3)begin;,(4)x:=ai;ai:=aj;aj:=x,(5)end;,带有非局部变量和形参的,PASCAL,过程,非局变量,ai,和,aj,的值进行交换,,i,j,为形参(在这里是传值),(,1)program reference(input,output);,(2)var a,b:integer;,(3)procedure swap(var x,y:integer);,(4)var temp:integer;,(5)begin,(6)temp:=x;,(7)x:=y;,(8)y:=temp,(9)end;,(10)begin,(11)a:=1;b:=2;,(12)swap(a,b);,(13)writeln(a=,a);writeln(b=,b),(14)end.,带有过程,swap,的,PASCAL,程序,10.3.1,传值(值调用,call-by-value,),特点是对形式参数的任何运算不影响实参的值。,例如:过程,swap(x,y:integer);,swap(a,b,);,其结果:,a,b,调用前的值不改变。,传值的实现,(,1,)形式参数当作过程的局部变量处理,即在被调过程的活动记录中开辟了形参的存储空间,这些存储位置即是我们所说的形式单元(用以存放实参)。,(,2,)调用过程计算实参的值,并将其放在对应形式单元开辟的空间中。,(,3,)被调用过程执行时,就像使用局部变量一样使用这些形式单元。,procedure swap(x,y:integer);,var temp:integer;,begin temp:=x;x:=y,;,y:=temp,end,;,调用,swap(a,b),过程将不会影响,a,和,b,的值。其结果等价于执行下列运算:,x:=a,;,y:=b,;,temp:=x,;,x:=y,;,y:=temp,10.3.2,传地址(变量参数,call-by-address,、,call-by-location,、,call-by-reference,),例如:过程,swap(var x,y:integer);,swap(a,b,);,(,a,b,为调用时的实参),调用结果,a,b,的值被改变。,传地址的实现,把实在参数的地址传递给相应的形参,即,调用过程把一个指向实参的存储地址的指针传递给被调用过程相应的形参:,(,1,)实在参数是一个名字,或具有左值的表达式,-,传递左值,(,2,)实在参数是无左值的表达式,-,计算值,放入一存储单元,传此存储单元地址,(,3,)目标代码中,被调用过程对形参的引用变成对传递给被调用过程的指针的间接引用,procedure swap(x,y:integer);,var temp:integer;,begin temp:=x;x:=y,;,y:=temp,end,;,调用,swap(i,ai),其结果等价于执行下列运算:,1把,i,和,ai,的地址分别放到,x,和,y,相应的单元,a1,a2,2(temp:=x,;,)temp,的内容置为,a1,所指单元中存的内容,3(x:=y;)a1,所指单元的内容置为,a2,所指单元值,4(y:=temp)a2,所指单元的内容置为,temp,的值,(1)swap(x,y),(2)int *x,*y;,(3)int temp;,(4)temp=*x;*x=*y;*y=temp;,(5),(6)main(),(7)int a=1,b=2;,(8)swap(,(9)printf(“a is now%d,b is now%dn”,a,b);,(10),在一个值调用过程中使用指针的,C,程序,在,C,程序中无传地址所以用指针实现。,10.3.3,过程参数,一个嵌套过程(函数)可以作为参数传递。,除了实参是过程的情况外,还有实参为数组的情况,实参为标号的情况以及实参为形式参数的情况。,过程作为参数传递,三种环境:词法环境,传递环境,活动环境,(1)program param(input,output);,(2)procedure b(function h(n:integer):integer);,(3)begin writeln(h(2)endb;,(4)procedure c;,(5)var,m:,integer;,(6)function f(n:integer):integr;,(7)begin f:=,m,+n endf;,(8)begin,m,:=0;b(f)end c;,(9)begin,(10)c,(11)end,图,10-27,嵌套过程作为参数传递,例如:过程 swap(x,y:integer);,生存期在本过程这次活动中的数据对象;,通常有三种不同的分配策略:,end;,首次满足法(时间优先);,(3)目标代码中,被调用过程对形参的引用变成对传递给被调用过程的指针的间接引用,调用时的栈顶地址(老),(8)swap(,考虑插入方便,可以把所归还的块插在available所指的块之前,然后available指向新归还的块。,但不论采用什么原则,整个大存区在一定时间之后必然会变成零碎不堪。,按照用户的需要,分配时先是从一个整块里分割出满足需要的一小块,以后,归还时,如果新归还的块能和现有的空间能合并,则合并成一块;,这里主要问题是,我们必须调整运行程序对各占用块的全部引用点。,图10-27 嵌套过程作为参数传递,全局D I S P L A Y 地址,按这种方法,初始化时存储空间是一个整块。,(7)int a=1,b=2;,param,c,存取链,m,b,存取链,图,10-28,连同存取链一起,传递过程实参,10.4,过程调用、过程进入和过程返回,过程调用的四元式序列,S,call id(),E,E,par T,1,par T,2,par T,n,call id,n,过程调用的四元式序列,(1)S,call id()for,队列,.q,的每一项,P do gen(par,-,-,p);n:=n+1;,gen(call,-,-,entry(id),(2),1,E,把排在,.q,的末端;,(3),E,谢谢观看,谢谢观看,
展开阅读全文