276翁泽原理及实我 China-pub.com 下载 ④将返回地址存放在新的活动记录中(如果需要)。 ⑤完成到被调用的过程的代码一个转移。 当存在着一个过程时,则 ①将p复制到sp中。 ②将控制链装载到中中。 ③完成到返回地址的一个转移。 ④改变s即以弹出自变量。 例7.5考虑在前面图7-3b中的对g的最后一个调用的情况: (栈的其余部分) m:2 控制链 词用g时的活动记录 返园地址 y:1 8 当进行对g新的调用时,首先将参数的值压入到运行时栈中: (楼的其余部分) m:2 一控制鼓 返回地址 调用g时的活动记录 y:1 m:1 接着将印压入到栈中: (校的其余部分) m:2 一控制链 调用。时的活动记录 返回地址 yi 1 m:1 控制链
④ 将返回地址存放在新的活动记录中(如果需要)。 ⑤ 完成到被调用的过程的代码一个转移。 当存在着一个过程时,则 ① 将f p复制到s p中。 ② 将控制链装载到f p中。 ③ 完成到返回地址的一个转移。 ④ 改变s p以弹出自变量。 例7.5 考虑在前面图7-3b 中的对g的最后一个调用的情况: 当进行对g新的调用时,首先将参数m的值压入到运行时栈中: 接着将f p压入到栈中: 2 7 6 编译原理及实践 下载 (栈的其余部分) 控制链 调用g时的活动记录 返回地址 (栈的其余部分) 控制链 调用g时的活动记录 返回地址 (栈的其余部分) 控制链 控制链 调用g时的活动记录 返回地址 自由空间 自由空间 自由空间
China-pub.com 第7章运行时环境 277 下载 现在将sp复制到p中,并将返回的地址压入到栈中,就得出了到g的新的调用了 (栈的其余部分) :2 控制链 调用g时的活动记录 返国地址 y:1 a:1 控制链 p 返同地址 调用g时新的活动记录 自由空铜 最后,g在栈上分配和初始化新的y以完成对新的活动记录的构造: (钱的其余部分) n:2 。控制链 返回地址 调用g时的活动记录 y:1 m:1 控制链 调用g时新的活动记录 返国地址 y:0 3)处理可变长度数据到这里我们已经描述了一种情况,所有的数据,无论是局部的还是 全局的,都可在一个固定的地方,或由编译程序计算出的到印的固定偏移处找到。有时编译程 序必须处理数据变化的可能性,表现在数据对象的数量和每个对象的大小上。发生在支持基于 栈的环境的语言中的两个示例如下:①调用中的自变量的数量可根据调用的不同而不同。② 数组参数或局部数组变量的大小可根据调用的不同而不同。 情况(I)的典型例子是C中的printf函数,其中的自变量的个数由作为第一个自变量传递 的格式串决定。因此: printf("",n,prompt,ch)i 就有4个自变量(包括格式串"号dsc"),但是 printf("Hello,world\n"): 却只有一个自变量。通常,C编译程序一般通过把调用的自变量按相反顺序(in reverse order) 压入到运行时栈p来处理这一点。那么,在上面描述的实现中第1个参数(它告知pr1ntf的代码
现在将s p复制到f p中,并将返回的地址压入到栈中,就得出了到g的新的调用了: 最后,g在栈上分配和初始化新的y以完成对新的活动记录的构造: 3) 处理可变长度数据 到这里我们已经描述了一种情况,所有的数据,无论是局部的还是 全局的,都可在一个固定的地方,或由编译程序计算出的到 f p的固定偏移处找到。有时编译程 序必须处理数据变化的可能性,表现在数据对象的数量和每个对象的大小上。发生在支持基于 栈的环境的语言中的两个示例如下:① 调用中的自变量的数量可根据调用的不同而不同。② 数组参数或局部数组变量的大小可根据调用的不同而不同。 情况( 1 )的典型例子是C中的p r i n t f函数,其中的自变量的个数由作为第一个自变量传递 的格式串决定。因此: printf("%d%s%c", n, prompt, ch); 就有4个自变量(包括格式串" % d % s % c "),但是 printf("Hello, world\n"); 却只有一个自变量。通常, C编译程序一般通过把调用的自变量按相反顺序 (in reverse order) 压入到运行时栈p来处理这一点。那么,在上面描述的实现中第 1个参数(它告知p r i n t f的代码 第 7章 运行时环境 2 7 7 下载 (栈的其余部分) 控制链 控制链 调用g时的活动记录 调用g时新的活动记录 返回地址 返回地址 自由空间 (栈的其余部分) 控制链 控制链 调用g时的活动记录 调用g时新的活动记录 返回地址 返回地址 自由空间
278 翁译原理及实践 China-pub.com 下载 共有多少参数)通常是位于到印的固定偏移的位置(使用上一个示例的假设得出实际上是+4)。另 一个选择是使用一个在VX体系结构中的诸如即(自变量指针)的处理器机制。还会对这以及 其他的可能情况在练习中再进一步讨论。 Ada非约束数组(unconstrained array)是情况(2)的一个示例: type Int vector is array(INTEGER range <>of INTEGER; procedure Sum (low,high:INTEGER; A:Int_vector)return INTEGER is tomp:Int_Array (low..high); begin end sum: (请注意局部变量t©p,其大小不可预测)。处理这种情况的典型办法是:为变量长度数据使用 间接的额外层,并将指针存放到一个在编译时可预测的地址中的实际数据里,同时执行期间用 s即可管理的方法在运行栈的顶部进行真正的分配。 例76给定前面定义的Ada Sumi过程,假定环境的组织也同上面一样⊙,那么可以如下所示实 现sum的活动记录(这个图示具体地显示了一个当数组大小为I0时对sum的调用): (栈的其余部分) 1ow high… A: 调用m时的活动记 A的大小:10 控制链 Ep 返同地址 A[9] 可变长度数据区拔 A[O] 自由空向 现在,对A【1]的访问就可由计算 6(Ep)+2*1 得到。其中®意味着间接,且此时仍假设整型两个字节,地址4个字节。 注意,在上例所描述的实现中,调用程序必须知道Sum的任何活动记录的大小。而且编译 。这在Ada中实际是不够的,它将会导致嵌套过程。参见本节后面的讨论
共有多少参数)通常是位于到f p的固定偏移的位置(使用上一个示例的假设得出实际上是 + 4 )。另 一个选择是使用一个在 VA X体系结构中的诸如ap (自变量指针) 的处理器机制。还会对这以及 其他的可能情况在练习中再进一步讨论。 A d a非约束数组 (unconstrained array)是情况( 2 )的一个示例: type Int_Vector is array(INTEGER range <>) of INTEGER; procedure Sum (low, high: INTEGER; A: Int_Vector) return INTEGER i s temp: Int_Array (low..high); b e g i n . . . end Sum; (请注意局部变量t e m p,其大小不可预测)。处理这种情况的典型办法是:为变量长度数据使用 间接的额外层,并将指针存放到一个在编译时可预测的地址中的实际数据里,同时执行期间用 s p可管理的方法在运行栈的顶部进行真正的分配。 例7.6 给定前面定义的Ada S u m过程,假定环境的组织也同上面一样 ,那么可以如下所示实 现S u m的活动记录 ( 这个图示具体地显示了一个当数组大小为1 0时对S u m的调用): 现在,对A [ i ]的访问就可由计算 @6 (fp) +2*i 得到。其中@意味着间接,且此时仍假设整型两个字节,地址 4个字节。 注意,在上例所描述的实现中,调用程序必须知道 S u m的任何活动记录的大小。而且编译 (栈的其余部分) 调用Sum时的活动记录 可变长度数据区域 控制链 A的大小:10 返回地址 自由空间 这在A d a中实际是不够的,它将会导致嵌套过程。参见本节后面的讨论。 2 7 8 编译原理及实践 下载