第10章目标程序运行时的组织

决定运行管理复杂程度的因素——源语言本身

  • •静态:如果一个名字的性质通过说明语句或隐式规则而定义,则称这种性质是“静态”确定的。
  • •动态:如果名字的性质只有在程序运行时才能知道,则称这种性质为“动态”确定的。

10.1 数据空间的三种不同使用和管理方法

10.1.1 静态存储分配

Fortran特例 p232

 

10.1.2 动态分配

原因:过程递归调用、可变数组、动态申请空间。

10.1.3 栈式动态分配

10.1.4堆式动态存储分配

10.2 栈式存储分配的实现

  • •含义:过程调用时…..

过程执行结束时…..

  • •过程活动记录(AR):一个过程的一次执行所需要的信息使用一个连续的存储区来管理,这个区(块)叫做一个活动记录
  • •过程活动记录的内容

临时值,如计算表达式时的中间工作单元。

局部变量(数据)

保存运行过程前的状态

存取链(可选)对于非局部量的引用。

控制链(可选)指向调用者的活动记录,释放栈数据区。

实参(形式单元)

返回地址

10.2.1简单的栈式分配的实现

程序结构特点:无分程序结构,过程定义不嵌套,过程可递归调用,不访问外层变量; 

  • •例:  main

全局变量的说明

  • • proc     R
  • •  ……
  • •end  R;
  • •proc   Q
  • •…… 
  • • end  Q;
  • •主程序执行语句

         end  main

 

 

若语言允许可变数组,则其活动记录内容如下。

 

10.2.2 嵌套过程语言的栈式实现

一.特点

  • l 如果允许过程嵌套定义,是否可以采用栈式分配方案?(Pascal)
  • l主要特点:
  • •(语言)一个过程可以引用包围它的任一外层过程所定义的标识符(如变量,数组或过程等)。
  • • (实现)一个过程可以引用它的任一外层过程的最新活动记录中的某些数据。
  • •关键技术:解决对非局部量的引用(存取)。
  • •设法跟踪每个外层过程的最新活动记录AR的位置。
  • •跟踪办法:

    1. 用控制链(如PL/0的SL)。

 

2. 用DISPLAY表。

 

二.控制链

 

 Program sort (input,output);

 

    var a:array[0..10] of integer;       x:integer;

 

    procedure readarray;

 

    var i :integer;

 

    begin  …a…    end;

 

    procedure exchange(i,j:integer)

 

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

 

   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;

 

   begin  ….  End {quicksort}

 

Begin  …..  End.{sort}

 

 

程序结构:

Sort                                   0层

 

      readarray                    1层

 

      exchange

 

      quicksort

 

             partition                2层

 

 

如何访问外层变量?

存取链---指向直接外层的活动记录

控制链---指向调用过程的活动记录

存取链与控制链是否指向同一个位置? (见p237)

例如:Sort—quicksort----quicksort----partition----exchange

 

三. Display表---嵌套层次显示表

    (解决问题,访问外层变量)

 

  • •办法:

设当前激活过程的层次为K,它的Display表含有K+1个单元,依次存放着现行层,直接外层…直至最外层的每一过程的最新活动记录的基地址

过程层次:过程定义层次,0层、1层、、、

 

用Display表的方案

(1)主程序--->(2)P--->(3)Q--->(4)R

如何组织display表?和活动记录放在一起。

  • • 当过程的层次为n,它的   display为n+1个值。
  • • 一个过程被调用时,从调用过程的DISPLAY表中自下向上抄录n个SP值,再加上本层的SP值。
  • •  过程调用时需传递:

老SP、返回地址、全局DISPLAY地址

  • •P239例

 

 

10.2.3 分程序结构

一.分程序结构举例       C程序 p240        Algol程序:

Procedure   A(m,n);  integer  m,n;

 B1:begin   real   z; array B[m:n];                                     

 

             B2:begin     real   d,  e;                       

 

    L3:                                                           2

 

                   end;

 

             B4:begin     array C[1:m];                   1      

 

                   B5:begin     real    e;           

                         L6:                               5    4

 

                         end;

 

                   end;

 

    L8:end;

 

二.分程序的特点

  • •          变量作用域
  • •          内外层同名变量的引用

怎样实现存储管理? 将每一个分程序作为无参过程?

  • •          分程序不存在被调用问题,不需保存连接数据

三.分程序结构的存储分配方案

1.分程序结构存储分配方案的一种简单办法是,把分程序看成 “无名无参过 程”,它在哪里定义就在哪里被调用。但这种做法是极为低效的

 

一.每逢进入 一个分程序,就照样建立连接数据和DISPLAY表,这是不必要的。

二. 当从内层分程序向外层转移时,可能同时要结束若干个分程序。按照过程处理办法,意味着必须一层一层地通过“返回” 来恢复所要到达的那个分程序的数据区,但不能直接到达。

2.可采取的两种措施。

 

  • •          第一,对每个过程或分程序都建立有自己的栈顶指示器TOP,代替原来仅有过程的栈顶指示器, 每个TOP的值保存在各自活动记录中。这样,上述的第二个问题便可解决。
  • •          第二,不把分程序看作“无参过程”,每个分程序共享包围它的那个最近过程的DISPLAY。每个分程序都隶属于某个确定的过程,分程序的层次是相对于它所属的那个过程进行编号的。

每个过程被当作是0层分程序。而过程体分程序(假定是一个分程序)当作是它所管辖的第1层分程序。

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

1.过程的TOP值,它指向过程活动记录的栈顶位置。

 

2.连接数据,共四项:

 

(1)老SP值;

(2)返回地址;

  (3)全局DISPAY地址;

 

(4)调用过程调用时的栈顶单元地址,老TOP。

3. 参数个数和形式单元

 

4.  DISPAY表。

 

5.  过程所辖的各分程序的局部数据单元。对于每个分程序来说,它们包括:

 

(1)分程序的TOP值。

当进入分程序时它含现行栈顶地址,以后,用来定义栈的新高度(分程序的TOP值);

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

Procedure   A(m,n);  integer  m,n;

 B1:begin   real   z; array B[m:n];                                    

             B2:begin     real   d,  e;                       

 

    L3:                                                          

 

                   end;

 

             B4:begin     array C[1:m];                         

 

                   B5:begin     real    e;           

 

                         L6:                               

 

                         end;

 

                   end;

 

    L8:end;

 

过程A的活等记录结构为:

 

 

 

 

 

10.3  参数传递

参数传递举例:

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

 

(2)      var x:integer;

 

(3)      begin;

 

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

 

(5)      end;

 

 

带有非局部变量和形参的PASCAL过程

非局变量a[i]和a[j]的值进行交换,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程序

  • •          传地址(变量参数)

例如:过程  swap(var x,y:integer);

    swap(a,b);( a,b为调用时的实参 )

 

调用结果a,b的值被改变。

  • •          传值(值调用)

特点是对形式参数的任何运算不影响实参的值。

例如:过程  swap(x,y:integer);

    swap(a,b);其结果: a,b调用前的值不改变。

 

10.3.1  传值的实现

  • •          1.形式参数当作过程的局部变量处理,即在被调过程的活动记录中开辟了形参的存储空间,这些存储位置即是我们所说的形式单元(用以存放实参)。
  • •          2.调用过程计算实参的值,并将其放在对应形式单元开辟的空间中。
  • •          3.被调用过程执行时,就像使用局部变量一样使用这些形式单元。
  • •          1.形式参数当作过程的局部变量处理,即在被调过程的活动记录中开辟了形参的存储空间,这些存储位置即是我们所说的形式单元(用以存放实参)。
  • •          2.调用过程计算实参的值,并将其放在对应形式单元开辟的空间中。
  • •          3.被调用过程执行时,就像使用局部变量一样使用这些形式单元。

10.3.2   传地址的实现

(call- by- reference )(call-by-address)(call-by-location)

把实在参数的地址传递给相应的形参,即

调用过程把一个指向实参的存储地址的指针传递给被调用过程相应的形参:

1.实在参数是一个变量名,或具有左值的表达式----传递左值

 

2.实在参数是无左值的表达式----计算值,放入一存储单元,传此存储单元地址

 

3.目标代码中,被调用过程对形参的引用变成对传递给被调用过程的指针的间接引用

 

procedure  swap(  var x,y:integer);

 

         var  temp:integer;

 

         begin    temp:=x;    x:=y;     y:=temp

 

         end;

 

调用swap(i,a[i])   其结果等价于执行下列运算:

 1把 i和a[i]的地址分别放到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(&a,&b);

 

(9)         printf(“a is now %d,b is now %d\n”,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))  end{b};
  • •          (4)procedure  c;
  • •          (5)         var m:integer;
  • •          (6)         function  f(n:integer):integr;
  • •          (7)              begin  f:=m+n    end{f};
  • •          (8)    begin m := 0; b(f)  end {c};
  • •          (9)begin
  • •          (10) c
  • •          (11)end

图10-27   嵌套过程作为参数传递

 

  • •          调用过程可决定参数过程的存储链
  • •          C必须将C的存储链和f的入口传给过程b.
  • •          p247

 

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

posted @ 2017-05-30 16:42  天涯海角路  阅读(199)  评论(0)    收藏  举报