slide1 n.
Download
Skip this Video
Loading SlideShow in 5 Seconds..
指导教师 : 杨建国 PowerPoint Presentation
Download Presentation
指导教师 : 杨建国

Loading in 2 Seconds...

play fullscreen
1 / 90

指导教师 : 杨建国 - PowerPoint PPT Presentation


  • 117 Views
  • Uploaded on

编 译 原 理. 指导教师 : 杨建国. 二零一零年三月. 第十章 目标程序运行时的存储组织. 第一节 数据空间的三种不同使用方法和管理方法. 第二节 栈式存储分配的实现. 第三节 参数传递. 第四节 过程调用、过程进入和过程返回. 知识结构. 第十章 目标程序运行时的存储组织. 10.1  数据空间的三种不同使用方法和管理方法. 从逻辑上看,代码生成前,编译程序必须进行目标程序 运行环境的设计 和 数据空间的分配 数据空间包括:用户定义的各种类型的数据对象(变量  和常量)所需的 存储空间 ,作为保留中间结果和传递参

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about '指导教师 : 杨建国' - lucius


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
slide1

编 译 原 理

指导教师:杨建国

二零一零年三月

slide2

第十章 目标程序运行时的存储组织

  • 第一节 数据空间的三种不同使用方法和管理方法
  • 第二节 栈式存储分配的实现
  • 第三节 参数传递
  • 第四节 过程调用、过程进入和过程返回
slide4

第十章 目标程序运行时的存储组织

  • 10.1 数据空间的三种不同使用方法和管理方法
  • 从逻辑上看,代码生成前,编译程序必须进行目标程序

运行环境的设计和数据空间的分配

  • 数据空间包括:用户定义的各种类型的数据对象(变量

 和常量)所需的存储空间,作为保留中间结果和传递参

 数的临时工作单元,调用过程时所需的连接单元,组织

 输入输出所需的缓冲区

slide5

存储区划分成:代码区、静态数据区、栈区、堆区:存储区划分成:代码区、静态数据区、栈区、堆区:

slide6

代码区:用以存放目标代码,这是固定长度的,即编译时代码区:用以存放目标代码,这是固定长度的,即编译时

 能确定的

  • 静态数据区:用以存放编译时能确定所占用空间的数据
  • 堆栈区:用于可变数据以及管理过程活动的控制信息
slide7

编译程序分配目标程序运行时的数据空间的基本依据是编译程序分配目标程序运行时的数据空间的基本依据是

 程序语言设计时对程序运行中存储空间的使用和管理办

 法的规定

  • 在程序设计语言语义学中,使用environment表示将一个

名字映射到一个存储位置的函数,state表示存储位置到

值的映射,如图10.2所示:

slide8

数据空间的使用和管理方法分成三种:

  • 静态存储分配
  • 栈式动态存储分配
  • 堆式动态存储分配
slide9

一.静态存储分配

  • 静态存储分配:在编译时能确定目标程序运行中所需的

 全部数据空间的大小,编译时安排好目标程序运行时的

 全部数据空间,确定每个数据对象的存储位置

  • 如像FORTRAN程序是段结构的,如图10.3所示:
slide10

图10.4给出一个FORTRAN77的程序例子:

  • PROGRAM CNSUME
  • CHARACTER * 50 BUF //程序体所拥有的静态量BUF
  • INTEGER NEXT //程序体所拥有的静态量NEXT
  • CHARACTER C, PRDUCE //程序体所拥有的静态量C
  • DATA NEXT /1/, BUF / ' ' /
  • C=PRDUCE()
  • BUF(NEXT:NEXT)=C
  • NEXT=NEXT+1
  • IF(C .EN. ' ' )GOTO 6
  • WRITE ( *,' (A)' )BUF

(11) END

slide11

(12) CHARACTER FUNCTION PRDUCE()

CHARACTER * 80 BUFFER

INTEGER NEXT

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

(23)END

slide12

图10.5中描述了该程序中局部变量的静态存储位置:图10.5中描述了该程序中局部变量的静态存储位置:

slide13

二.动态存储分配

  • 如果一个程序设计语言允许递归过程、可变数组或允许

用户自由申请和释放空间,那么,就需要采用动态存储

 管理技术

slide14

三.栈式动态存储分配

  • 这种分配策略是将整个程序的数据空间设计为一个栈
slide15

四.堆式动态存储分配

  • 假设程序运行时有一个大的存储空间,每当需要时就从

 这片空间中借用一块,不用时再退还,由于借还的时间

 先后不一,经一段运行之后,程序运行空间将被划分成

 许多块,有些占用,有些空闲。那么当运行程序要求一

 块体积为N的空间时,需要决定应该从哪个空闲块得到这

 个空间

  • 理论上讲,应该从比N稍大一些的空闲块中取出N个单元,

 以便使大的空闲块派更大的用场,但实现难度很大

slide16

实际中常常采用的办法:先遇到哪块比N大就从其中取出实际中常常采用的办法:先遇到哪块比N大就从其中取出

N个单元

  • 即使这样,也会发生找不到一块比N大的空闲块,但所有

 空闲块总和比N大得多,这时,有的分配管理系统采用废

 品回收的办法来应付

slide17

10.2 栈式存储分配的实现

  • 过程的活动记录AR(Activation Record):是一段连续的存

 储区,用以存放过程的一次执行所需要的信息,这些信

 息如图10.6所示:

slide18

临时工作单元:如计算表达式过程存放的中间结果临时工作单元:如计算表达式过程存放的中间结果

  • 局部变量:一个过程的局部变量
  • 机器状态信息:如程序计数器、寄存器的值
  • 存取链:用以存取非局部变量
  • 控制链:指向调用该过程的那个过程的活动记录
  • 实参:由调用过程向该被调过程提供实参的值(或地址)
  • 返回地址:保存该被调过程返回后的地址
slide19

一.简单的栈式存储分配的实现

  • 最简单的程序设计语言结构如图10.7所示:

program main; //主程序头

全局变量或数组的说明;

proc R; //过程R的头

…//过程R的体

end (R);//过程R的尾

proc Q;//过程Q的头

…//过程Q的体

end (Q);//过程Q的尾

主程序执行语句 //主程序体

end.(main)//主程序尾

slide20

例如,图10.7的程序结构中,若主程序调用了过程Q,Q例如,图10.7的程序结构中,若主程序调用了过程Q,Q

 又调用了R,在R进入运行后的存储结构如图10.8(a)所示:

  • 若主程序调用了过程Q,Q递归调用自己,在Q过程第2次

 进入运行后的存储结构如图10.8(b)所示:

  • 若主程序先调用过程Q,然后主程序接着调用R,且Q过

 程没有调用Q和R,这时Q和R进入运行后的存储结构分

 别如图10.8(c)和10.8(d)所示:

slide21

TOP

  • TOP:始终指向已占用的栈顶单元
  • SP:总是指向现行过程活动记录的起点
slide22

TOP

  • 这种语言若含有可变数组,则其过程活动记录的内容如

 图10.9所示:

slide23

TOP

  • 图10.10表明分配数组区之后的运行栈情况,可以与图

10.8(a)对照:

slide24

二.嵌套过程语言的栈式实现

  • Pascal语言程序结构的特点是允许过程嵌套定义,如图

10.11所示:

slide26

图10.11的Pascal程序中过程定义的嵌套情况如下:图10.11的Pascal程序中过程定义的嵌套情况如下:

  • sort
  • readarray
  • exchange
  • quicksort
  • partition
slide27

假如过程sort激活(调用)了过程quicksort,这时存储栈假如过程sort激活(调用)了过程quicksort,这时存储栈

 中的情形如图10.12所示,其中在quicksort过程活动记录

 中有一存储单元(用斜线描绘)用以记录过程quicksort

 可以引用sort中定义的变量a和x。也就是说,为了解决对

 非局部变量的存取问题,必须设法跟踪每个外层过程的

 最新活动记录的位置

slide29

一种跟踪方法是:在过程活动记录中增设存取链,指向包一种跟踪方法是:在过程活动记录中增设存取链,指向包

 含该过程的直接外层过程的最新活动记录的起始位置。

 过程活动记录的内容如图10.13(a)所示。图10.12所提

 到的情况可用图10.13(b)所示:

slide30

TOP

静态链

  • 因为PL/O的过程是无参过程,PL/O也无动态数组,所以

 它的过程活动记录的内容如图10.14所示:

slide31

再回到图10.11例子,如果该程序的某次执行顺序为:再回到图10.11例子,如果该程序的某次执行顺序为:

  • sortquicksortquicksortpartition

exchange…

  • 图10.15给出了进入过程exchange之后运行栈的示意,仅

 标明存取链和控制链的值

slide33

另一种跟踪方法是:每进入一个过程后,在建立它的活另一种跟踪方法是:每进入一个过程后,在建立它的活

 动记录的同时建立一张嵌套层次显示表display

  • 嵌套层次:指过程定义的层数,始终假定主程序的层数

 为0,因此主程序称为0层过程

slide34

计数过程的层数用一个计数器Level,初值为0,每遇到过计数过程的层数用一个计数器Level,初值为0,每遇到过

 程说明则增1,过程说明结束则减1

  • display是一个指针数组d,也可看做是一个小栈,自顶向

 下每个单元依次存放着现行层,直接外层,……直至最

 外层(0层,主程序层)等每一层过程的最新活动记录的

 地址

slide35

图10.11的程序,假定有如下四种调用情况:

  • (a)sortquicksort…
  • (b)sortquicksortquicksort…
  • (c) sortquicksortquicksortpartition…
  • (d) sortquicksortquicksortpartition

exchange…

  • 图10.16(a)-(d)分别说明上述四种情形的运行栈和display
slide36

quicksort

quicksort

quicksort

quicksort

quicksort

quicksort

quicksort

slide37

display本身的体积在编译时可确定,它作为单独的表分配display本身的体积在编译时可确定,它作为单独的表分配

 存储还是作为活动记录的一部分,比如置于实参的上端(

 如图10.17所示),则取决于编译程序的设计者

slide38

当过程P1调用过程P2而进入P2后,P2应如何建立起自己的当过程P1调用过程P2而进入P2后,P2应如何建立起自己的

display?

  • 当P1调用P2时必须把P0的display地址作为连接数据之一传

 给P2

slide39

如果P2是一个真实过程,那么P0或者就是P1自身或者既是如果P2是一个真实过程,那么P0或者就是P1自身或者既是

P1又是P2的直接外层(图10.18的(a)(b)两种情形),不

 论哪一种情形,只要在进入P2后能够知道P1的display就

 能知道P0的display,从而可直接构造出P2的display。也

 就是说,在这种情况下,只需所P1的display地址作为连

 接数据之一传送给P2就能够建立P2的display

slide41

如果P2是形式参数,那么调用P2意味着调用P2当前相应的如果P2是形式参数,那么调用P2意味着调用P2当前相应的

 实在过程

  • 此时的P0应是这个实在过程的直接外层过程
  • 假定P0的display地址可从形式单元P2所指示的地方获得
  • 为了能在P2中获得P0的display地址,必须在P1调用P2时设

 法把P1的display地址作为连接数据之一传送给P2

slide42

于是连接数据变为三项:

(1)老SP值;

(2)返回地址;

(3)全局display地址

  • 这样,整个活动记录的组织就如图10.17所示
slide43

三.分程序结构的存储管理

  • 一个分程序是一个含有它自己的局部数据(变量)声明

 的语句

  • 在C语言中,一个分程序的语法形式是:{ 声明 语句}
  • 例如图10.19的C程序中的分程序B0,B1,B2和B3,分程

 序的特征是它们的嵌套结构,使用界符标明分程序的开

 始和结束,C语言用{ }

slide45

分程序结构可以用栈式存储分配实现

  • 一种办法是把分程序看成一个“无参过程”,只不过是在

 该分程序入口处调用,分程序出口处返回。分程序在哪

 里定义就在哪里被调用

  • 另一种办法是每次为一个完整的过程体分配存储,即把

 一个过程体中的所有分程序所需的存储一次分配好,如

 图10.19的C程序,可以为这里所有声明的名字分配一块存

 储,如图10.20所示:

slide47

ALGOL的结构特点是除了允许过程嵌套定义还含有分程ALGOL的结构特点是除了允许过程嵌套定义还含有分程

 序的结构,如图10.21的一个ALGOL过程:

slide48

如采用将分程序看成“无参过程”,则效率很低,因为:如采用将分程序看成“无参过程”,则效率很低,因为:

  • 第一,分程序不存在被调用的问题,不必要在进入一个

 分程序时,将连接数据和display都放进活动记录中

  • 第二,当从内层分程序向外转移时可能同时要结束若干

 个分程序,那么怎样恢复所要到达的那个分程序的数据

 区呢?

slide49

克服上述缺点的办法是:

  • 首先,代替原来的那个统一的栈顶指示器,让每个过程

 和分程序都有自己的栈顶指示器TOP,它的值保存在各

 自的活动记录中

  • 其次,不把分程序看作“无参过程”,而让每个分程序享

 用包围它的那个最小过程的display

slide50

每个过程的活动记录所含的内容有:

1.过程的TOP单元,指向活动记录的栈顶位置

2.连接数据:

(1)老SP值

(2)返回地址

(3)全局display地址

(4)调用时的栈顶单元地址,称作老TOP

3.参数个数和形式单元

4.display表

slide51

5.过程所管辖的各分程序的局部数据单元对每个分程序来说,5.过程所管辖的各分程序的局部数据单元对每个分程序来说,

 它们包括:

(1)一个名为TOP的单元,当进入时它含现行栈顶地址,以后

 用来存放栈的新高度

(2)分程序的局部变量、数组内情向量和临时工作单元

slide52

图10.22给出了过程A(见图10.21)的活动记录的结构:图10.22给出了过程A(见图10.21)的活动记录的结构:

slide53

下面用一个例子说明进出分程序时数据区的变化过程:下面用一个例子说明进出分程序时数据区的变化过程:

  • 图10.23(a)表示已调用了图10.21的过程A,控制已转入

A中,但尚未开始执行过程体时栈的内容

  • 图10.23(b)反映了已进入过程体分程序(B1),但尚未

 分配数组空间时栈的内容。分程序B1的TOP值直接抄自

 外层分程序的TOP单元

  • 图10.23(c)反映了分配数组B后的情形,此时B1的TOP

 值上升到指示新栈顶,但过程A的TOP值不动

  • 图10.23(d)反映了进入分程序B2之后的情形
slide54

进入分程序B4时又抄写B1的TOP,并对数组C进行分配,进入分程序B4时又抄写B1的TOP,并对数组C进行分配,

 于是得到图10.23(e)

  • 当进入分程序B5时,再次抄写直接外层的TOP值,得到

 图10.23(f)

slide56

10.3 参数传递

  • 当一个过程调用其他过程时,调用过程和被调过程之间的

 通信经由非局部量或者经由参数传递

slide57

如图10.24的过程exchange1既使用了非局部量数组a,又使如图10.24的过程exchange1既使用了非局部量数组a,又使

 用了形式参数i和j,将a[i]和a[j]的值进行交换

(1)procedure exchange1(i , j:integer);

(2) var x:integer;

(3) begin;

(4) x:=a[i];a[i]:=a[j];a[j]:=x;

(5) end;

  图10.24 带有非局部变量和形参的Pascal过程

slide58

把实在参数传递给相应的形式参数方法:

  • 传值、传地址、传名、宏扩展等
  • 观察图10.25的Pascal程序,程序的输出是a=2,b=1,如果将

 第3行的关键字var 去掉,则该程序的输入是a=1,b=2

slide60

一.传值call-by-value(值调用)

  • 将实参计算出它的值,然后把它传给被调过程:

1.形式参数当作过程的局部变量处理

2.调用过程计算实参的值,并将它们的右值放在为形式单元

 开辟的空间中

slide61

3.被调用过程执行时,就像使用局部变量一样使用这些形式3.被调用过程执行时,就像使用局部变量一样使用这些形式

 单元

  • 传值的重要特点是对形式参数的任何运算不影响调用过

 程的活动记录中实参的值

  • 通过值调用的过程可以由非局部量或由指针而对调用过

 程发生影响

slide62

比如图10.26的C程序中,x和y声明为整型指针,第8行调用比如图10.26的C程序中,x和y声明为整型指针,第8行调用

swap(&a,&b)中的&操作符导致将指向a和b的指针传给过

 程swap。该程序的输出为:a is now 2, b is now 1

slide63

二.传地址

  • 当参数通过引用传递时,也称作传地址,或引用调用
  • 调用过程传给被调过程的是指针,指向实参存储位置的

 指针

1.如实参是一个名字或是具有左值的表达式,则左值本身传

 递过去

2.如实参是一个表达式,比如a+b或2,而没有左值,则表

 达式先求值,并存入某一位置,然后该位置的地址传递

 过去

3.被调过程中对形式参数的任何引用和赋值都通过传递到被

 调过程的指针被处理成间接访问

slide64

例如,在图10.25的程序中,若用实参i和a[i]对过程swap进例如,在图10.25的程序中,若用实参i和a[i]对过程swap进

 行调用,即swap(i,a[i]),其效果如下步骤所述:

1.将i和a[i]的地址(左值)拷贝到被调过程的活动记录中,比

 如说分别对应形参x和y的单元arg1和arg2

2.将局部变量temp设为由arg1所指单元的内容(即令temp等

 于I0,其中I0是i的初值),这一步对应于swap定义中的第

6行语句:temp:=x

3.将arg1所指单元的内容设为等于temp的值,即设a[I0]=i ,这

 一步对应swap中第7行的x:=y

4.将arg2所指单元的内容设为等于temp的值,即设a[I0]=i,

 这一步对应y:=temp

slide65

三.过程参数

  • 一个嵌套过程(函数)可以作为参数传递,比如图10.27

 的PASCAL程序中,过程c把f作为参数传递给b,而b通

 过引用形参h调用f

slide67

图10.28说明了这点,当过程c传递f时,c可以决定f的存取图10.28说明了这点,当过程c传递f时,c可以决定f的存取

 链,或者说f的存取链或display可以根据c的存取链或

display来建立:

slide68

例题:一个PASCAL程序中的嵌套过程定义情况见下面的例题:一个PASCAL程序中的嵌套过程定义情况见下面的

 程序。若程序运行时的存储空间采用栈式动态分配的方

 案,请给出调用序列sort→quicksort→partition→exchange

 时,exchange激活后的运行栈布局,指出exchange过程活

 动记录的DISPLAY表的内容。

program sort(input,output);

var a:array[0…10] of integer;

x:integer;

procedure exchange(i,j:integer);

begin

x:=a[i];a[i]:=a[j];a[j]:=x

end{exchange};

slide69

procedure quicksort(m,n:integer);

var k,v:integer;

function partition(y,z:integer):integer;

var i,j:integer;

begin

…a…

…v…

…exchange(i,j);

end{partition};

begin

end{quicksort};

begin

end{sort}.

slide70

答案一:exchange过程运行时的运行栈及DISPLAY表的内容:答案一:exchange过程运行时的运行栈及DISPLAY表的内容:

exchange的DISPLAY

exchange的活动记录

e_SP→

partition的DISPLAY

partition的活动记录

p_SP→

quicksort的DISPLAY

quicksort的活动记录

q_SP→

sort的活动记录

sort的DISPLAY

s_SP→

slide71

答案二:exchange过程运行时的运行栈及DISPLAY表的内容:答案二:exchange过程运行时的运行栈及DISPLAY表的内容:

exchange的DISPLAY

exchange的活动记录

e_SP→

partition的DISPLAY

partition的活动记录

p_SP→

quicksort的DISPLAY

quicksort的活动记录

q_SP→

sort的活动记录

sort的DISPLAY

s_SP→

slide72

例题:某语言允许过程嵌套定义和递归调用(如PASCL语例题:某语言允许过程嵌套定义和递归调用(如PASCL语

 言),若在栈式动态存储分配中采用嵌套层次显示表

DISPLAY解决对非局部变量的引用问题,试给出下列程序

 执行到语句“b:=10;”时运行栈及DISPLAY表的示意图。

program main;

var x,y;

procedure p;

var a;

procedure q;

var b;

begin{q}

b:=10;

end{q};

slide73

procedure s;

var c;

procedure r;

var d;

begin {r}

call q;

end {r};

begin {s}

call r;

end {s};

begin {p}

call s;

end {p};

begin {main}

call p;

end {main}.

slide74

答案:运行栈及DISPLAY表的内容:

q的活动记录

q的DISPLAY

q_SP→

r的DISPLAY

r的活动记录

r_SP→

s的DISPLAY

s的活动记录

s_SP→

p的DISPLAY

p的活动记录

p_SP→

main的DISPLAY

main的活动记录

main_SP→

slide75

例题:对于如下的程序:

procedure p(x,y,z);

begin y:=y+1;

z:=z+x;

end;

begin a:=2;

b:=3;

p(a+b,a,a);

print a;

end.

  若参数的传递方法分别为:(1)传名;(2)传地址;(3)传结果;(4)传值。试问程序执行所输出的a分别是什么?

slide76

答案:

(1)传名(换名):用实参对过程体中任一出现的对应形参进行文字替换。

执行对p(a+b,a,a)的调用,实施了对过程p的如下变换procedure p(a+b,a,a);

begin a:=a+1;

a:=a+a+b;

end;

调用传入的数据为:a=2和b=3;

执行a:=a+1;结果为:a=3和b=3;

执行a:=a+a+b;结果为:a=9和b=3;

所以,这种情况下程序输出为:9

slide77

被调过程数据区

主调数据区

x:

T

adda:

2

主调数据区

adda

被调过程数据区

y:

addb:

3

adda:

3

x:

adda

T

z:

T:

5

3

addb:

adda

y:

主调数据区

T:

5

adda

z:

adda:

8

被调过程数据区

x:

addb:

3

T

T:

5

adda

y:

adda

z:

  • 答案:(2)传地址(引用调用):

过程调用时,是将实参的地址传递给被调用的过程p中的

形式参数:形参和实参有如下的对应(设a的地址为adda,b的

地址为addb,临时单元T放a+b的值):

执行y:=y+1后,有:

执行z:=z+x后,有:

所以这种情况下程序输出为:8

slide78

主调数据区

被调过程数据区

adda:

2

x_add:

T

主调数据区

被调过程数据区

addb:

3

x_val:

5

adda:

2

x_add:

T

T:

5

adda

y_add:

addb:

3

x_val:

5

y_val:

2

5

T:

adda

y_add:

adda

z_add:

y_val:

3

被调过程数据区

2

z_val:

adda

z_add:

x_add:

T

2

z_val:

x_val:

5

主调数据区

adda

y_add:

主调数据区

adda:

2

y_val:

3

adda:

7

addb:

3

adda

z_add:

addb:

3

5

T:

7

z_val:

T:

5

  • 答案:

(3)传结果:将实参的值和地址都传递给被调用的过程p(设a的地址为adda,b的地址为addb,临时单元T放a+b的值):

执行y:=y+1后,有:

执行z:=z+x后,有:

子程序调用完成后,各值按其地址依次回送到主调数据区:

所以这种情况下程序输出为:7

有的书是3

slide79

主调数据区

被调过程数据区

adda:

2

x:

5

主调数据区

被调过程数据区

addb:

3

2

y:

adda:

2

x:

5

5

T:

2

z:

addb:

3

3

y:

T:

5

2

主调数据区

z:

被调过程数据区

adda:

2

x:

5

addb:

3

3

y:

T:

5

7

z:

  • 答案: (4)传值:

  过程调用时,是将实参的值传递给被调用的过程p中的形式参数(设a的地址为adda,b的地址为addb,临时单元T放a+b的值):

执行y:=y+1后,有:

有的书是2

执行z:=z+x后,有:

  由于实参和形参间的关系是单方向的一次性的传值,被调过程的形参的任何一个值均不回传到对应的实参,因此,返回主调程序后不改变主调程序的任何值

所以这种情况下程序输出为:2

slide80

例题:对于如下的程序:

begin

integer I;

integer array B[1..2];

procedure Q(X); integer X;

begin

I:=1;X:=X+2;B[I]:=10;

I:=2;X:=X+2;

end;

B[1]:=1;B[2]:=2;I:=1;Q(B[I]);

end.

  若参数的传递方法分别为:(1)传名;(2)传地址;(3)传结果;(4)传值。程序执行所输出的B[1]和B[2]分别是什么?

slide81

主调数据区

主调数据区

主调数据区

主调数据区

I:

I:

I:

I:

1

1

1

1

B[1]:

B[1]:

B[1]:

B[1]:

3

10

10

1

B[2]:

B[2]:

B[2]:

B[2]:

2

2

4

2

  • 答案:

(1)传名(换名):过程被调用时,等价于被调用者被替换成如下形式:procedure Q(B[I]);integer B[I];

begin I:=1;B[I]:=B[I]+2;B[I]:=10;

I:=2;B[I]:=B[I]+2;

end;

执行“I:=1;B[I]:=B[I]+2;”后:

执行“B[I]:=10;”后:

执行“I:=2;B[I]:=B[I]+2;”后:

所以这种情况下程序输出为:B[1]=10,B[2]=4

slide82

被调数据区

被调数据区

被调数据区

被调数据区

X:

X:

X:

X:

B[1]

B[1]

B[1]

B[1]

主调数据区

主调数据区

主调数据区

主调数据区

I:

I:

I:

I:

2

1

1

1

B[1]:

B[1]:

B[1]:

B[1]:

3

10

12

1

B[2]:

B[2]:

B[2]:

B[2]:

2

2

2

2

  • 答案:(2)传地址(引用调用):

过程调用实际上是把实参的地址传给被调过程Q的形参X:

执行“I:=1;X:=X+2;”后:

执行“B[I]:=10;”后:

执行“I:=2;X:=X+2;”后:

所以这种情况下程序输出为:

B[1]=12,B[2]=2

slide83

被调数据区

被调数据区

被调数据区

被调数据区

X_add:

X_add:

X_add:

X_add:

B[1]

B[1]

B[1]

B[1]

X_val:

X_val:

X_val:

X_val:

3

3

5

1

主调数据区

主调数据区

主调数据区

主调数据区

主调数据区

I:

I:

I:

I:

I:

1

1

2

2

1

B[1]:

B[1]:

B[1]:

B[1]:

B[1]:

10

10

3

1

5

B[2]:

B[2]:

B[2]:

B[2]:

B[2]:

2

2

2

2

2

  • 答案:

(3)传结果:实参的值和地址都传递给被调过程Q

执行“I:=1;X:=X+2;”后:

执行“B[I]:=10;”后:

执行“I:=2;X:=X+2;”后:

子程序返回后:

程序输出为:B[1]=5,B[2]=2

slide84

被调数据区

被调数据区

被调数据区

被调数据区

X:

X:

X:

X:

1

3

5

3

主调数据区

主调数据区

主调数据区

主调数据区

I:

I:

I:

I:

1

1

2

1

B[1]:

B[1]:

B[1]:

B[1]:

10

10

1

1

B[2]:

B[2]:

B[2]:

B[2]:

2

2

2

2

  • 答案: (4)传值:

 过程调用实际上是把实参的地址传给被调过程Q的形参X

执行“I:=1;X:=X+2;”后:

执行“B[I]:=10;”后:

执行“I:=2;X:=X+2;”后:

所以这种情况下程序输出为:

B[1]=10,B[2]=2

slide85

10.4 过程调用、过程进入和过程返回

  • 对于过程调用的四元式序列:
  • par T1
  • par T2
  • par Tn
  • call P,n
slide86

在运行时是如何执行的?//par和call产生什么相应的目标在运行时是如何执行的?//par和call产生什么相应的目标

代码

  • 对于par Ti(i=1,2,…,n)的处理是:根据par Ti

(i=1,2,…,n)中Ti的种别而生成传送指令,或将参数的值

或将参数的地址传送至新的过程的活动记录的形式单元中

slide87

对于call p,n则应生成传送参数个数n的指令;保护现行SP

 至新过程的活动记录(老SP);转子,转向P的第一条指

 令;定义新SP;保护返回地址;定义新值;填写display或

 存取链内容等指令

  • 如果过程含动态数组(局部),则应生成对数组进行存储

 分配的指令,即生成运行时动态地建立内情向量和分配数

 组空间的目标指令

  • 在过程执行语句的工作过程中,凡引用形参、局部变量或

 数组元素都可根据过程活动记录起点的相对位置访问

slide88

当过程P工作完毕要返回到调用段时,若语言有形如return当过程P工作完毕要返回到调用段时,若语言有形如return

 (E)的返回语句,或P是个函数过程时,则可把已算好的

 值传送至某个特定的寄存器中,调用段将从这个特定的寄

 存器中获得被调过程的结果值。然后所生成的目标指令则

 应完成的工作是:恢复SP;恢复TOP,按保存的返回地址

 实行无条件转移

slide89

【本章小结】

  • 目标代码运行时,存储区域的整体布局,以及各区域的作用
  • 各种不同数据变量区的不同分配组织方式
  • 允许过程嵌套定义的语言,栈式动态分配的组织管理
  • 过程活动纪录的各项内容和它们的作用,以及活动纪录的

 组织方式

  • 参数传递的不同方式及其实现
  • 过程调用和返回时,相应目标代码以及栈式动态分配区的

 管理