资源预览内容
第1页 / 共86页
第2页 / 共86页
第3页 / 共86页
第4页 / 共86页
第5页 / 共86页
第6页 / 共86页
第7页 / 共86页
第8页 / 共86页
第9页 / 共86页
第10页 / 共86页
亲,该文档总共86页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
第六章运行时刻环境序6.1源语言中的一些问题6.2存储组织6.3运行时刻存储分配策略6.5参数传递6.6符号表1序计算环境运行时的环境计算目标代码源程序中的名字(常量,变量)目标机存储空间。它受命于源程序的执行语义。源程序由一组过程按某种规则组成。过程的一次执行称作一次活动,在过程的语句序列执行之前,过程中访问的对象构成此过程的运行环境,由运行支持程序组织好。编译程序根据如何组织运行环境而生成目标代码。映射源程序26.16.1有关源程序中的一些问题有关源程序中的一些问题目的:构造运行程序的策略和方法6.1.1过程6.1.2活动树6.1.3控制栈6.1.4说明的作用域6.1.5名字的绑定6.1.6构造运行程序和源程序有关的一些问题36.1.1过程源程序由一组过程组成,不同的程序设计语言,由过程构成源程序的方法不同。构成源程序的两个过程行文,要么是嵌套的,要么是不相交的。4programsort(input,output);vara:array0.10ofinteger;procedurereadarray;vari:integer;beginend;functionpartition(y,z:integer):integer;vari,j,x,v:integer;beginend;procedurequicksort(m,n:integer);vari:integer;beginendend;beginend.56.1.26.1.2活动树活动树 程序执行期间的控制流:1程序执行的控制是顺序的;2过程的每一次执行都是从过程体的开头开始,并最终把控制返回到紧接着该过程被调用点的后面。过程的一次活动:过程体的每一次执行。一个过程p的一次活动的生存期:在该过程体的执行中的第一步和最后一步之间的一序列步骤的执行时间,其中包括执行过程p所调用的过程的执行时间,以及这些过程所调用的过程的执行时间,如此等等。6特点:每当控制流从过程p的活动进入到过程q的活动中后,它将返回到过程p的同一次活动中。如果a和b是两个过程活动,那么它们的生存期要么是不重叠的,要么是嵌套的。这种活动生存期的嵌套性质可以通过在每一个过程中插入两个打印语句来加以说明。7执行开始enterreadarrayleavereadarrayenterquicksort(1,9)enterpartition(1,9)leavepartition(l,9)enterquicksort(1,3).leavequicksort(1,3)enterquicksort(5,9).leavequicksort(5,9)leavequicksort(1,9)执行结束8一个过程是递归的,如果同一过程的一次新的活动可以在前面活动结束以前开始。用一颗树来描绘控制进入和离开活动的途径。这祥的树称作活动树。在一棵活动树中:1.b的左边当且仅当a的生存期发生在b的生存期之前。用活动树来讨论正在这个结点上的控制。9srq(1,9)p(1,9)q(1,3)p(1,3)q(1,0)q(2,3)p(2,3)q(2,1)q(3,3)q(5,9)p(5,9)q(5,5)q(7,9)p(7,9)q(7,7)图6.3一棵活动树10结论:一个结点代表一个唯一的活动,且每一个活动只有一个结点表示,当控制进入某一个活动时,可以直接说,控制在这个结点上。6.1.3控制栈程序执行的控制流对应于从根开始,按先根次序遍历活动树。因此,用一个栈保存过程活动的生存踪迹。把它称作控制栈。当一个活动开始执行时,把代表这个活动的结点推进栈;当这个活动结束时,把代表这个活动的结点从栈中弹出。11例6.2栈和活动树的变化栈ssrSrq(1,9)Sq(1.9)p(1,9)Sq(1.9)p(1,9)q(1,3)Sq(1.9)q(1,3)p(1,3)Sq(1.9)q(1,3)p(1,3)q(1,0)Sq(1.9)q(1,3)q(1,0)q(2,3)Sq(1.9)q(1,3)q(2,3)图6.412控制栈中的活动都是活跃的,当前控制进入的活动在栈顶,从栈顶活动到栈底活动的活动序列是从活动树上当前结点通向根的路径上的结点序列:s,q(1,9),q(l,3),q(2,3)从栈底活动到栈顶活动的活动序列表示了活动的生存期的嵌套关系。结论结论:扩充控制栈可用来实现如Pascal语言的栈式存储分配,进入一个活动,在栈顶建立这个活动所使用的存储空间;这个活动结束,从栈顶弹出其使用的存储空间。136.1.46.1.4说明的作用域说明的作用域1. .说明明把名字与名字的属性信息绑定在一起。2.说明的作用域是一个说明起作用的范围(源程序行文)。一个名字在源程序行文中可能有几处说明,语言的作用域规则规定:在语句序列中引用的一个名字是在何处说明的名字。3.编译时,处理说明把名字及其属性信息填写进符号表(add(id.entry,id.vul);处理引用名字时,查找这个名字的属性信息(lookup(id),符号表管理程序根据语言的作用域规则,使lookup(id)返回id的作作用域中绑定的属性信息。146.1.56.1.5名字与存储的绑定名字与存储的绑定名字与存储单元的绑定是指把源程序中的数据名字映射到目标机存储单元的过程。引进两个函数,environment和state。environment把名字映射到一个存储单元上;state把存储单元映射到那里所存放的值上。可以说,函数environment把一个名字映射为一个l-value(左-值),而函数state把一个l-value(左-值)映射为一个r-value(右-值)。如图6.5所示。15名字存储单元值存储分配程序运行environmentstatel-valuer-value图6.5从名字到值的两个阶段映射16静态概念动态对应过程定义过程活动名字说明名字的绑定说明的作用域活动的生存期176.1.66.1.6提出的问题提出的问题编译程序组织存储分配所采用策略和方法主要取决于对源程序中下面的问题的回答。1过程可以是递归的吗?2当控制从过程的一次活动返回时,局部名的值将发生什么变化?3一个过程可以访问非局部名吗?4当调用过程时参数是怎样传递的?5过程可以作为参数被传递吗?6过程可以作为结果被返回吗?7.可以在程序控制下进行动态存储分配吗?8.显式的存储重新分配(指撤除分配后的分配)是必须的吗?18例:函数的返回值是函数。Funtimesxy=x*yvaltimes=fn:int(intint)twice=times2funcompose(f,g)=f(g(x)compose=fn:()()valfourtimes=compose(twice,twice)196.26.2存储组织存储组织6.2.1运行时刻内存的划分运行时刻内存的划分运行时刻的存储空间必须划分以用来存放:1.生成的目标代码;2.数据目标;3.用于保存过程活动踪迹的一个控制栈。存储空间划分的各部分:20目标代码静态数据栈堆1.编译后知道目标代码的大小。2.pascal主程序中的数据,c,FORTRAN3.栈:Pascal,c4.堆:Pascal,c216.2.26.2.2活动记录活动记录把过程的一个活动所需要的信息组织成一块连续的存储单元,称为活动记录。一个活动所需要的信息的每个数据项有相同的生存期,因此,组织成一个活动记录是很自然的。对于pascal语言来说,运行过程中,当调用一个过程时,在栈顶构筑它的活动记录;当这个过程的活动执行完后,把它从栈顶弹出。源语言不同,实现方法不同,组成活动记录的域不同。实现pascal语言的活动记录如图6.7所示。22返回值实在参数控制链访问链保存机器状态局部数据临时变量控制链:指向调用过程活动的活动记录。访问链:指向本活动要访问的非局部数据所在的活动记录。保存机器状态:调用过程活动在调用点的机器状态,包括计数器,各种寄存器的值。局部数据:过程中定义的局部量。临时变量:编译产生。236.2.36.2.3编译时刻的局部数据的设计编译时刻的局部数据的设计局部数据域是编译时刻在分析过程中的说明时设计的。例如:PROCEDUREsub(x,y:real);VARi,j:integer;a:ARRAY1.5OFreal;e,f:real;BEGINf:=e+i*j;END;24符号表名字形类型偏移量活动记录布局返回值(top-sp,0)x形real1(top-sp,1)y形real2(top-sp,2)(top-sp,3)(top-sp,20)iint20(top-sp,21)jint21(top-sp,22)aarray22(top-sp,27)ereal27(top-sp,28)freal2825中间代码*ijt1*(top-sp,20)(top-sp,21)(top-sp,29)+et1t2+(top-sp,27)(top-sp,29)(top-sp,30)itort2t3itor(top-sp,30)(top-sp,31):=t3f:=(top-sp,31)(top-sp,28)编译结束,知道每个过程的活动记录的长度,将其填写到相应的过程表中,运行时,调用哪个过程,就在运行栈顶,推进那个过程的活动记录(栈箭头加上活动记录长度)。266.36.3运行时刻存储分配策略运行时刻存储分配策略分配策略是:1静态分配;2栈式分配,或称栈式动态分配;3堆式分配,或称堆式动态分配。6.36.3.1静态存储分配6.36.3.2栈式存储分配6.36.3.3堆式存储分配采用哪种分配策略是由源语言的语义决定的。276.36.3.1静态存储分配在编译时刻为每个数据项目确定出在运行时刻的存储空间中的位置,且这种绑定在运行时刻不再发生变化。局部名字的值在过程活动停止后仍保留下来。限制:1.在编译时刻知道数据目标的大小和它们在内存位置上约束;2.不能递归调用过程(一个过程的两个活动的生存期不相交,一个过程的所有活动可以使用同一个活动记录);3.不能动态地建立数据结构。28(1)PROGRAMCNSUME(2)CHARACTER*50BUF(3)INTEGERNEXT(4CHARACTERC,PRDUCE(5)DATANEXT1,BUF/(6)CPRDUCE()。(7)BUF(NEXT:NEXT)C(8NEXTNEXT1(9)IF(C.NE.)GOTO6(10)WRITE(*,(A))BUF(11)END29(12)CHARACTERFUNCTIONPRDUCE()(13)CHARACTER*80BUFFER(14)INTEGERNEXT(15)SAVEBUFFER,NEXT(16)DATANEXT81(17)IF(NEXT.GT.80 )THEN(18)READ(*,(A)BUFFER(19)NEXT1(20)ENDIF(21)PRDUCEBUFFER(NEXT:NEXT)(22)NEXTNEXT1(23)END图图6.86.8一个一个Fortran 77程序程序30CNSUME目标代码PRDUCE目标代码Char*50bufintnextcharcChar*80bufferintnextCnsume活动记录prduce活动记录目标代码静态数据316.3.26.3.2栈式存储分配栈式存储分配基于控制栈的原理:存储空间被组织成栈,活动记录的推入和弹出分别对应于活动的开始和结束。与静态分配不同的是,在每次活动中把局部名字和新的存储单元绑定,在活动结束时,活动记录从栈中弹出,因而局部名字的存储空间也随之消失。例6.5图6.11表明当控制流通过图6.3的活动树时活动记录被推人或弹出运行时刻的栈中的情况,设寄存器top标记栈顶。32sSa:arraytoprri:integertoptopq(1,9)q(1,9)i:integertopp(1,9)p(1,9)i:integertoptopq(1,3)q(1,3)i:integertop图6.11栈式分配活动记录在栈中的变化33确定活动记录中局部数据的地址:假设top-sp标记一个活动记录的开始的位置,dx表示x的地址相对于top-sp的偏移量。那么,x在过程的目标代码中的地址可写成dx(top-sp)在运行时刻,当把x的活动记录筑于栈顶时,寄存器top-sp被赋于实际的地址,top-sp可以是一个寄存器。调用序列和返回序列调用序列和返回序列通过在目标代码中生成调用序列和返回序列实现过程的调用。激活一个过程的活动是执行34过程语句的结果。过程语句p(e1,e2,en)的目标代码(调用序列)完成任务:1.调用者对实在参数求值,并把它们传送给被调用过程的活动记录的参数域。2调用者在被调用者的活动记录中存放返回地址和老top-sp之值。之后调用者把top一sp之值增加到图6.12所示的位置。3被调用者存放寄存器值和其它状态信息。4被调用者初始化其局部数据并开始执行。35返回序列,return目标代码完成的任务是:1被调用者在自己的活动记录的返回值域中放一个返回值。2利用状态域中的信息,被调用者恢复top-sp和其它寄存器,并且按返回地址转移到调用者的代码之中。3调用者复制返回值到自己的活动记录中。任务的划分,根据源语言、目标机器和操作系统等具体情况而定。上述任务,由运行支持子程序完成,可视为虚机指令。36可变长度的数据可变长度的数据源程序的例子PROCEDUREexam(l,m,n:integer);VARa:array1.lofreal;b:array1.mofreal;c:array1.nofreal;BEGINEND;编译时,不知a,b,c的大小,仅对每个数组设置一个指针。37ControllinkabcTop-sptopArrayaArraybArrayctopP的活动记录P的动态数组图6.13动态分配的数组38活动记录的进栈和推栈栈顶活动记录用两个指针top和top-sp指示。top-sp指向栈顶活动记录保存机器状态域的末端,用于访问局部数据。top指向栈顶。P调用q:栈top+h:=top-sp;top-sp:=top+h;top:=top+q的活动记录长度从q的活动返回:top:=top-spq(h)top-sp:=栈top-sp39pqtop-sptop-sptoptoph406.3.36.3.3堆式存储分配堆式存储分配1局部名的值在活动结束时必须被保存。2.被调用者的活动生存期超过调用者。用活动树不能够正确描绘这种语言的过程之间的控制流。new(p);dispose(p);416.46.4对非局部名字的访问对非局部名字的访问讨论基于活动记录的栈式分配。一个语言所规定的作用域规则决定了如何处理对非局部名字的引用。有静态和动态两种作用域规则。静态静态:考查程序正文来决定引用的名字是哪一个名字说明,如Pascal,C和Ada是众多语言中使用带有“最近嵌套”规定的词法作用域规则的语言;动态动态:在运行时刻考查最近的活动来决定应用到一个名字上的说明,如LISP和APL。426.4.16.4.1块块一个块(Block)是一个含有局部数据说明的语句。declarationsstatements一个块与另一个块要么是独立的,要么一个块完全嵌入在另一个块之中,这种嵌套的性质有时称作块结构。在块结构语言中,说明的作用域由最近嵌套规则给出:1在块B中的一个说明的作用域包括B。2如果名字x在块B中没有说明,那么,43x在B中的出现是在一个外围块B中的x的说明的作用域之内,并且使得:(a)B中有x的说明,(b)B是包围B的,相对于其它任何具有名字x的说明且包围B的块而言,B是离B最近的。对于pascal语言来说,一个过程是一个块,一个程序是一个块结构。而对于c语言来说,每个函数是一个块结构,而函数之间是不嵌套的。44main()inta=0;/*B0-B2*/intb=0;/*B0-B1*/intb=1;/*B1-B3*/inta=2;printf(“%d%d/n”,a,b);intb=3;printf(“%d%d/n”,a,b);printf(“%d%d/n”,a,b);printf(“%d%d/n”,a,b);B0B1B2B345a0b0b1a2,b3图6.16函数main局部数据在活动记录中的按排块结构语言可以采用栈式分配。函数main的每个块可看成一个无参过程,块中的块可被看成一个语句。控制从块开始进入,遇块结束退出。B2和B3的生存期不相交,它们的局部数据可占用同一块存储空间。466.4.26.4.2不含嵌套过程的词法作用域不含嵌套过程的词法作用域C中过程定义不能嵌套(l)inta11;(2)readarray()a(3)intpartition(y,z)inty,z;a(4)quicksort(m,n)intm,n;.(5)main().a.图6.17带有a的非局部出现的C程序47目标代码inta11栈堆1.函数外的数据和函数内的静态数据,静态分配于静态数据域。2.函数内的数据(out)栈式分配,运行进入任一函数,使用的数据,要么在当前的活动记录中;要么在静态数据域中。486.4.36.4.3含有嵌套过程的词法作用域含有嵌套过程的词法作用域图6.18带有嵌套过程的一个Pascal程序程序的静态嵌套结构:sortreadarrayexchangequicksortpartition49(1)programsort(input,output);(2)vara:array0.10ofinteger;(3)x:integer;(4)procedurereadarray;(5)vari:integer;(6)beginaendreadarray;(7)procedureexchange(i,j:integer);(8)begin(9)x:=ai;ai:=aj;aj:x(10)endexchange;50(11)procedurequicksort(m,n:integer);(12)vark,v:integer;(13)functionpartition(y,z:integer):integer;(14)vari,j:integer;(15)begina(16)V(17)exchange(i,j);(18)endpartition;(19)beginendquicksort;(20)beginend.sort51程序的静态嵌套结构决定程序中每个过程中访问哪些外围过程中的数据。每个过程静态嵌套在哪些过程中,可用静态链static(p)表示:static(sort)=sortstatic(readarray)=sortreadarraystatic(exchange)=sortexchangestatic(quichsort)=sortquichsortstatic(partition)=sortquichsortpartition运行时,过程的数据被组织成活动记录,为了实现非局部访问,过程的活动记录之间必须维持静态链反映程序的静态嵌套结构。526.4.3.16.4.3.1嵌套深度嵌套深度用过程的嵌套深度过程的嵌套深度来表达一个过程在程序中的嵌套层次。令主程序的嵌套深度为1;从一个过程进入到一个被包围过程时嵌套深度加1。如图6.18中的位于(11)行上的过程quicksort的嵌套深度为2,而(13)行上的partition的嵌套深度为3。过程表示除过程名字之外的过程定义正文。一个名字的嵌套深度名字的嵌套深度等于说明它的过程的嵌套深度,是名字的重要属性。在(15)(17)行上的partition中的a,v和i的嵌套深度分别是1,2和3。536.4.3.2存取链(accesslink)栈中的活动记录应反映源程序正文中过程之间的嵌套关系,或静态结构。为每一个活动记录增设一个称为存取链(或存取链路)的指针,如果在源程序正文中过程p直接嵌入在过程q中,那么p的一个活动记录中的存取链指向q的最近的活动记录中的存取链。从当前活动记录开始,沿着这条链,能找到访问的非局部名字。它是静态链在存储空间上的实现,也称作静态链。程序运行过程中应维持这条链。54SSnila,xtop-sptoprritoptop-sptop-sptopq(1,9)q(1,9)k,vtoptop-spp(1,9)p(1,9)i,jtoptop-sptop-sptopq(1,3)q(1,3)k,vtoptop-spp(1,3)p(1,3)i,jtoptop-spe(1,3)e(1,3)i,jtoptop-sp图6.1955非局部访问非局部访问在嵌套深度为np的过程p中引用一个嵌套深度为nanp的非局部名字a,a的存储位置可按下面的步骤找到:1从栈顶活动记录出发沿存取链前进npna步,到达a所在的活动记录。npna的值可在编译时刻计算出来。2a的地址=a所在活动记录的始址+a的偏移量。编译生成过程p的目标代码中非局部名字a的地址表示为:(npna,a在其活动记录中的偏移量)56运行时存取链的维护运行时存取链的维护维护存取链的代码是调用序列的一部分。假设嵌套深度为np的过程p调用嵌套深度为nx的过程x。存取链的维护依赖于过程p和过程x之间的嵌套关系。1.npnx,nx=np+1,x在p中定义。被调用过程的活动记录的存取链必须指向栈中刚好在其前面的(地址码较低的)调用过程的活动记录的存取链。57pxcallxptop-sptopxtop-sptop栈top+h:=top-sp;top-sp:=top+h;top:=top+x的活动记录长度;582.npnxxPcallxnp=nxpx59callxxpxpcallxpxnpnx60过程p和x的嵌套深度为1,2,,nx-1的外围过程是相同的。从p的活动记录开始沿存取链前进np-nx+1步,可到达包围着p和x且离它们最近的过程的当前的活动记录。这个活动记录的存取链位置即是x的当前活动记录存取链应指向的位置。np-nx+1在编译时能计算出来。61过程作为参数传递的实现PROGRAMparam(input,output);PROCEDUREb(FUNh(n:integer):integer);BEGINwriteln(h(2)END;PROCEDUREc;VARm:integer;FUNCTIONf(n:integer):integer;BEGINf:=m+nEND;BEGINm:=0;b(f)END;BEGINcEND.62paramcm:=0b(f)存取链存取链f(2)如何建立存取链?过程要在定义它的环境中运行。过程作为实参数传递时,必须把它的存取链作为实参数的一部分传递。在传递f时,确定f的存取链,好象在c中调用f一样。在b中激活f的活动时,它作为f的活动记录的存取链。636.4.3.36.4.3.3Display表Display表是一个指针数组d,在运行过程中,若当前活动的过程的嵌套深度为i,则di中存放当前的活动记录地址,di-1,di-2,d1中依次存放着当前活动的过程的直接外层,,直至最外层(主程序)等每一层过程的最新活动地址。这样,嵌套深度为j的变量a存放在由dj所指出的活动记录中。在运行过程中维持一个Display表实现非局部访问比存取链效率要高。64Display表的维护表的维护(过程不作为参数传递)当嵌套深度为i的过程的活动记录筑在栈顶时:(1)在新的活动记录中保存di的值;(2)置di指向新的活动记录。在一个活动结束前,di置成保存的旧值。用Display表如何访问非局部量?1.Display表是一个数组,开始地址用通用寄存器指出;2.Display表由一组寄存器实现。65sSa,xdisplayrrq(1,9)q(1,9)k,vp(1,9)p(1,9)e(1,9)e(1,9)saved2q(1,3)q(1,3)saved2k,vp(1,3)p(1,3)saved3i,j图6.1966设p(嵌套深度为j)调用q(嵌套深度为i)1.jiqd1d2di-1diPqpcallqSavediPcallqqdjSavedj696.4.46.4.4动态作用域动态作用域程序运行时,一个名字a实施其影响,直到含a的声明的一个过程开始执行时暂停,此过程停止时,该影响恢复。设有下面的的调用序列:ABCP过程P中有对x的非局部引用,沿动态链(红链)查找,最先找到的便是。70programdynamic(input,output);varr:real;procudureshow;beginwtite(r:5:3)end;procedutesmall;varr:real;beginr:0.125;showend;beginr:0.25;show;small;write1n;show;small;writelnend.71在词法作用域之下,程序的输出为:0.2500.2500.2500.250在动态作用域之下,输出为:0.2500.1250.2500.125实现动态作用域的方法实现动态作用域的方法:1.深访问深访问。使用控制链在栈中搜索,以寻找包含所需非局部名字的存储单元的第一个活动记录(控制链又称动态链)。722浅访问浅访问。这种方法的思想是在静态分配的存储空间中存放每一个名字的现行值。当过程p开始一次新的活动时,p中的非局部名n占用对于n静态分配的存储空间。先前的n值可以存放在p的活动记录中并且当p的活动记录结束时必须给以恢复。两种方法进行比较。736.56.5参数传递参数传递实在参数和形式参数结合的方法:传值调用(call-by-value)引用调用(call-by-reference)复制恢复(copy-restore)传名调用(call-by-name)ai:=aj其中表达式aj代表一个值,而ai则表示一个存储地址。参数传递方法之间的区别主要基于实在参数是代表右-值(r-值)、左-值(l-值)、或者实在参数的正文本身。746.5.16.5.1传值调用传值调用programreference(input,output);vara,b:integer;procedureswap(x,y:integer);vartemp:integer;begintemp:x;x:y;y:tempend;begina:1;b:2;swap(a,b);writeln(a=,a, b=,b)end.75传值调用可以实现如下:调用过程计算实在参数,并把它们的右-值放入到形式参数的存储空间中。使用传值的方法,调用swap(a,b)等价于下面几步:x:=ay:=btemp:=xx:=yy:=temp766.5.26.5.2引用调用引用调用把实在参数的地址传递给相应的形式参数,在目标代码中,在被调用过程中对形式参数的一次引用就成为对传递给被调用过程的指针的一个间接引用。Referenceabxy12swapabtemp77Temp:=x;temp:=a;x:=y;a:=b;y:=temp;b:=temp;6.5.36.5.3复制恢复复制恢复实现:实现:1.当控制流入到被调用过程之前,把实在参数的右-值和左-值传递到被调用过程中;2.当控制返回时,把形式参数的现行右-值复制回到相应的实在参数的左-值中。78programcopyout(input,output);vara:integer;procedureunsafe(varx:integer);beginx:2;a:=0end;begina:=1;unsafe(a);writeln(a)end.79Copyoutunsafea11ax202Copy-incopy-out806.5.46.5.4传名调用传名调用传名调用(call-by-name)由Algol中的复制规则(copy一rule)定义为:1.过程被当作宏对待。过程调用的作用相当于把被调用过程的过程体宏扩展(macroexpansion)到调用出现的地方。2重新命名被调用过程中的局部名字。例如,对于例6.6中的调用swap(i,ai),采用传名调用方式传递参数,则可实现如下:temp:=i;i:ai;(注意此处i值得以改变)ai:temp;(此ai不是原来的ai)81当i的值改变时,ai的值也改变。因此,不能一开始就算出实在参数的地址,以后就用这个地址;而是每当被调用过程内引用该形式参数时,就必须重新计算它的地址。而且,必须在定义它的环境中进行计算,即,必须在调用过程中进行计算。实现方法:在调用过程的目标程序中,对应每一个这样的形式参数都设置一个单独的过程,称为实形替换程序(thunk)。每当被调用过程内引用某个形式参数时,就调用相应的实形替换程序(thunk)。82目标程序结构:gotoL;A1:计算i的地址(thunk);A2:计算ai的地址(thunk);L:带着下边的表调用swap;RET:RET(返回地址)A1(第一个thunk过程的地址)A2(第二个thunk过程的地址)83总结:程序结构活动生存期活动树控制栈栈式存储分配程序结构静态作用域活动记录非局部访问存取链display表846.6.56.6.5练习练习6.16.26.3对于(b)(1)画出激活f后的运行栈和存取链;(2)画出激活f后的运行栈和display表。6.4补:对以下的pascal程序,画出过程c第二次被激活时的运行栈,控制链和存取链,说明在c中如何访问变量x。85PROGRAMevn;PROCEDUREa;VARx:integer;PROCEDUREb;PROCEDUREc;BEGINx:=2;bEND;BEGINprocedurebcEND;BEGINbEND;procedureaBEGINaEND.main86
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号