编译原理教程课后习题答案--第六章

第六章 运行时存储空间组织 6.1 完成下列选择题: (1) 过程的DISPLAY表中记录了 a. 过程的连接数据 b. 过程的嵌套层次 c. 过程的返回地址 d. 过程的入口地址 (2) 过程P1调用P2时,连接数据不包含 a. 嵌套层次显示表 b. 老SP c. 返回地址 d. 全局DISPLAY地址 (3) 堆式动态分配申请和释放存储空间遵守原则。 a. 先请先放 b. 先请后放 c. 后请先放 d. 任意 (4) 栈式动态分配与管理在过程返回时应做的工作有 a. 保护SP b. 恢复SP c. 保护TOP d. 恢复TOP

(5) 如果活动记录中没有DISPLAY表,则说明。 a. 程序中不允许有递归定义的过程 b. 程序中不允许有嵌套定义的过程 c. 程序中既不允许有嵌套定义的过程,也不允许有递归定义的过程 d. 程序中允许有递归定义的过程,也允许有嵌套定义的过程 【解答】 (1) b (2) a (3) d (4) b (5) b

6.2 何谓嵌套过程语言运行时的DISPLAY表?它的作用是什么? 【解答】 当过程定义允许嵌套时,一个过程在运行中应能够引用在静态定义时包围它的任一外层过程所定义的变量或数组。也就是说,在栈式动态存储分配方式下的运行中,一个过程Q可能引用它的任一外层过程P的最新活动记录中的某些数据。因此,过程Q运行时必须知道它的所有(静态)外层过程的最新活动记录的地址。由于允许递归和可变数组,这些外层过程的活动记录的位置也往往是变迁的。因此,必须设法跟踪每个(静态)外层的最新活动记录的位置,而完成这一功能的就是DISPLAY嵌套层次显示表。

也即,每当进入一个过程后,在建立它的活动记录区的同时也建立一张DISPLAY表,它自顶而下每个单元依次存放着现行层、直接外层等,直至最外层(主程序层)等每一层过程的最新活动记录的起始地址。 6.3 (1) 写出实现一般递归过程的活动记录结构以及过程调用、过程进入与过程返回的指令; (2) 对以return(表达式)形式(这个表达式本身是一个递归调用)返回函数值的特殊函数过程,给出不增加时间开销但能节省存储空间的实现方法。假定语言中过程参数只有传值和传地址两种形式,为便于理解,举下例说明这种特殊的函数调用: int gcd (int p,int q) { if (p % q ==0) return q; else return gcd (q, p % q) } 【解答】 (1) 一般递归过程的活动记录如图6-1所示。

图6-1 递归过程的活动记录

过程调用指令为

(i+4)[TOP]=Ti 或 (i+4)[TOP]=addr [Ti] 1[TOP]=SP 3[TOP]=SP+d 4[TOP]=n JSR P 过程进入指令为 SP=TOP+1 1[SP]=返回地址 TOP=TOP+L 建立DISPLAY P; /*执行P过程*/ 返回指令为 TOP=SP-1 SP=0[SP] X=2[TOP] UJ 0[X]

(2) 对于return后的直接递归情况,可简化为 (i+3)[SP]=Ti 或 (i+3)[SP]=addr [Ti] UJ P 6.4 有一程序如下: program ex; a: integer; procedure PP(x: integer); begin:

x:=5; x:=a+1 end;

begin a:= 2; PP(a); write(a) end. 试用图表示ex调用PP(a)前后活动记录的过程。 【解答】 按照嵌套过程语言栈式实现方法,ex调用PP(a)前后活动记录的过程如图6-2所示。

PP的活动记录 (调用PP(a)之后)

ex的活动记录 (调用PP(a)之前)

图6-2 ex调用PP(a)前后的活动记录

6.5 类PASCAL结构(嵌套过程)的程序如下,该语言的编译器采用栈式动态存储分配策略管理目标程序数据空间。 program Demo procedure A; procedure B; begin(*B*) … if d then B else A; …

end;(*B*) begin(*A*) B end;(*A*)

begin(*Demo*) A end.

(1) 若过程调用序列为

① Demo→A;② Demo→A→B;③ Demo→A→B→B;④ Demo→A→B→B→A 请分别给出这四个时刻运行栈的布局和使用的DISPLAY表; (2) 若该语言允许动态数组,编译程序应如何处置?如过程B有动态局部数组R[m:n],请给出B第一次激活时相应的数据空间的情况。 【解答】 (1) 运行栈及使用的DISPLAY表如图6-3所示。

B的活动记录

A的活动记录

A的活动记录

Demo的活动记录

Demo的活动记录

(1) Demo→A(2) Demo→A→B

A 2的活动记录 A2B2的活动记录

B2_sp

B2的活动记录

B2 B1的活动记录 B1的活动记录B1_sp

B1 A的活动记录DISPLAY DISPLAY表A1的活动记录A_sp

1Demo的活动记录A Demo的活动记录

Demo_sp

(4) Demo→A(3) Demo→A→B1→B1→B2→A21→B2

图6-3 运行栈及DISPLAY表示意图

(2) 由于一个过程在运行时所需的实际数据空间的大小,除可变数据结构(可变数组)那些部分外,其余部分在编译时是完全可以知道的。编译程序处理时将过程运行时所需的数据空间分为两部分:一部分在编译时可确定其体积,称为该过程的活动记录;另一部分(动态数组)

的体积需在运行时动态确定,称为该过程的可变辅助空间。当一个过程开始工作时,首先在运行栈顶部建立它的活动记录,然后再在这个记录之顶确定它所需的辅助空间。含有动态数组R的过程B在第一次激活时,相应的数据空间情况如图6-4所示。 B的可变辅助空间

B的活动记录

B的活动记录

A的活动记录 A的活动记录

A_sp

Demo的活动记录

的活动记录

(b)(a)

图6-4 带动态数组的运行栈示意

(a) 动态数组R空间分配之前;(b) 动态数组R空间分配之后

6.6 下面程序的结果是120。但是如果把第5行的abs(1)改成1的话,则程序结果为1。试分析为什么会有这种不同的结果。 int fact( ) { static int i=5; if (i==0){ return(1); } else { i=i-1; return((i+abs(1))*fact( ));} } main( ) { printf ("factor or 5=%d\n",fact( )); } 解答】 i是静态变量,所有对i的操作实际上都是对i所对应的存储单元进行操作,每次递归进入下一层fact函数后,上一层对i的赋值仍然有效。需要注意的是,每次递归调用时,(i + abs(1))*fact( )中的(i + abs(1))的值都先于fact算出。因此,第一次递归调用所求得的值为5*fact,第二次递归调用所求得的值为4*fact,…,一直到第五次递归调用所求得的值为1*fact,而此时fact为1。也即实际上是求一个5*4*3*2*1的阶乘,由此得到结果

为120。

将abs(1)改为1后,输出结果为1而不是120,这主要是与编译的代码生成策略有关。对表达式(i + abs(1))* fact( ),因为两个子表达式(i+abs(1))和fact( )都有函数调用,而编译器的编译则是先产生左子表达式的代码,后产生右子表达式的代码。也即,每次递归调用时,(i + abs(1))* fact( )中的(i+abs(1))的值都先于fact算出。但是,当abs(1)改为1后,左子表达式就没有函数调用了,于是编译器就先产生右子表达式的代码。每次递归调用时, (i+1)* fact( )中的(i+1)值都后于fact计算。也即,第一次递归调用得到(i+1)* fact,第二次递归调用得到(i+1)*fact,第三次递归调用仍得到(i+1)*fact,…,直到第五次递归调用还是得到(i+1)* fact,而此时fact为1,i为0。因此,每次递归所求实际上都是1 * fact,最终得到输出结果为1。

第六章 运行时存储空间组织 6.1 完成下列选择题: (1) 过程的DISPLAY表中记录了 a. 过程的连接数据 b. 过程的嵌套层次 c. 过程的返回地址 d. 过程的入口地址 (2) 过程P1调用P2时,连接数据不包含 a. 嵌套层次显示表 b. 老SP c. 返回地址 d. 全局DISPLAY地址 (3) 堆式动态分配申请和释放存储空间遵守原则。 a. 先请先放 b. 先请后放 c. 后请先放 d. 任意 (4) 栈式动态分配与管理在过程返回时应做的工作有 a. 保护SP b. 恢复SP c. 保护TOP d. 恢复TOP

(5) 如果活动记录中没有DISPLAY表,则说明。 a. 程序中不允许有递归定义的过程 b. 程序中不允许有嵌套定义的过程 c. 程序中既不允许有嵌套定义的过程,也不允许有递归定义的过程 d. 程序中允许有递归定义的过程,也允许有嵌套定义的过程 【解答】 (1) b (2) a (3) d (4) b (5) b

6.2 何谓嵌套过程语言运行时的DISPLAY表?它的作用是什么? 【解答】 当过程定义允许嵌套时,一个过程在运行中应能够引用在静态定义时包围它的任一外层过程所定义的变量或数组。也就是说,在栈式动态存储分配方式下的运行中,一个过程Q可能引用它的任一外层过程P的最新活动记录中的某些数据。因此,过程Q运行时必须知道它的所有(静态)外层过程的最新活动记录的地址。由于允许递归和可变数组,这些外层过程的活动记录的位置也往往是变迁的。因此,必须设法跟踪每个(静态)外层的最新活动记录的位置,而完成这一功能的就是DISPLAY嵌套层次显示表。

也即,每当进入一个过程后,在建立它的活动记录区的同时也建立一张DISPLAY表,它自顶而下每个单元依次存放着现行层、直接外层等,直至最外层(主程序层)等每一层过程的最新活动记录的起始地址。 6.3 (1) 写出实现一般递归过程的活动记录结构以及过程调用、过程进入与过程返回的指令; (2) 对以return(表达式)形式(这个表达式本身是一个递归调用)返回函数值的特殊函数过程,给出不增加时间开销但能节省存储空间的实现方法。假定语言中过程参数只有传值和传地址两种形式,为便于理解,举下例说明这种特殊的函数调用: int gcd (int p,int q) { if (p % q ==0) return q; else return gcd (q, p % q) } 【解答】 (1) 一般递归过程的活动记录如图6-1所示。

图6-1 递归过程的活动记录

过程调用指令为

(i+4)[TOP]=Ti 或 (i+4)[TOP]=addr [Ti] 1[TOP]=SP 3[TOP]=SP+d 4[TOP]=n JSR P 过程进入指令为 SP=TOP+1 1[SP]=返回地址 TOP=TOP+L 建立DISPLAY P; /*执行P过程*/ 返回指令为 TOP=SP-1 SP=0[SP] X=2[TOP] UJ 0[X]

(2) 对于return后的直接递归情况,可简化为 (i+3)[SP]=Ti 或 (i+3)[SP]=addr [Ti] UJ P 6.4 有一程序如下: program ex; a: integer; procedure PP(x: integer); begin:

x:=5; x:=a+1 end;

begin a:= 2; PP(a); write(a) end. 试用图表示ex调用PP(a)前后活动记录的过程。 【解答】 按照嵌套过程语言栈式实现方法,ex调用PP(a)前后活动记录的过程如图6-2所示。

PP的活动记录 (调用PP(a)之后)

ex的活动记录 (调用PP(a)之前)

图6-2 ex调用PP(a)前后的活动记录

6.5 类PASCAL结构(嵌套过程)的程序如下,该语言的编译器采用栈式动态存储分配策略管理目标程序数据空间。 program Demo procedure A; procedure B; begin(*B*) … if d then B else A; …

end;(*B*) begin(*A*) B end;(*A*)

begin(*Demo*) A end.

(1) 若过程调用序列为

① Demo→A;② Demo→A→B;③ Demo→A→B→B;④ Demo→A→B→B→A 请分别给出这四个时刻运行栈的布局和使用的DISPLAY表; (2) 若该语言允许动态数组,编译程序应如何处置?如过程B有动态局部数组R[m:n],请给出B第一次激活时相应的数据空间的情况。 【解答】 (1) 运行栈及使用的DISPLAY表如图6-3所示。

B的活动记录

A的活动记录

A的活动记录

Demo的活动记录

Demo的活动记录

(1) Demo→A(2) Demo→A→B

A 2的活动记录 A2B2的活动记录

B2_sp

B2的活动记录

B2 B1的活动记录 B1的活动记录B1_sp

B1 A的活动记录DISPLAY DISPLAY表A1的活动记录A_sp

1Demo的活动记录A Demo的活动记录

Demo_sp

(4) Demo→A(3) Demo→A→B1→B1→B2→A21→B2

图6-3 运行栈及DISPLAY表示意图

(2) 由于一个过程在运行时所需的实际数据空间的大小,除可变数据结构(可变数组)那些部分外,其余部分在编译时是完全可以知道的。编译程序处理时将过程运行时所需的数据空间分为两部分:一部分在编译时可确定其体积,称为该过程的活动记录;另一部分(动态数组)

的体积需在运行时动态确定,称为该过程的可变辅助空间。当一个过程开始工作时,首先在运行栈顶部建立它的活动记录,然后再在这个记录之顶确定它所需的辅助空间。含有动态数组R的过程B在第一次激活时,相应的数据空间情况如图6-4所示。 B的可变辅助空间

B的活动记录

B的活动记录

A的活动记录 A的活动记录

A_sp

Demo的活动记录

的活动记录

(b)(a)

图6-4 带动态数组的运行栈示意

(a) 动态数组R空间分配之前;(b) 动态数组R空间分配之后

6.6 下面程序的结果是120。但是如果把第5行的abs(1)改成1的话,则程序结果为1。试分析为什么会有这种不同的结果。 int fact( ) { static int i=5; if (i==0){ return(1); } else { i=i-1; return((i+abs(1))*fact( ));} } main( ) { printf ("factor or 5=%d\n",fact( )); } 解答】 i是静态变量,所有对i的操作实际上都是对i所对应的存储单元进行操作,每次递归进入下一层fact函数后,上一层对i的赋值仍然有效。需要注意的是,每次递归调用时,(i + abs(1))*fact( )中的(i + abs(1))的值都先于fact算出。因此,第一次递归调用所求得的值为5*fact,第二次递归调用所求得的值为4*fact,…,一直到第五次递归调用所求得的值为1*fact,而此时fact为1。也即实际上是求一个5*4*3*2*1的阶乘,由此得到结果

为120。

将abs(1)改为1后,输出结果为1而不是120,这主要是与编译的代码生成策略有关。对表达式(i + abs(1))* fact( ),因为两个子表达式(i+abs(1))和fact( )都有函数调用,而编译器的编译则是先产生左子表达式的代码,后产生右子表达式的代码。也即,每次递归调用时,(i + abs(1))* fact( )中的(i+abs(1))的值都先于fact算出。但是,当abs(1)改为1后,左子表达式就没有函数调用了,于是编译器就先产生右子表达式的代码。每次递归调用时, (i+1)* fact( )中的(i+1)值都后于fact计算。也即,第一次递归调用得到(i+1)* fact,第二次递归调用得到(i+1)*fact,第三次递归调用仍得到(i+1)*fact,…,直到第五次递归调用还是得到(i+1)* fact,而此时fact为1,i为0。因此,每次递归所求实际上都是1 * fact,最终得到输出结果为1。


相关文章

  • 大学几乎所有学科的课本答案[2]
  • 大学几乎所有学科的课本答案! 来源: 任明嘉的日志 经济金融 [PDF格式]<会计学原理>同步练习题答案 [Word格式]<成本会计>习题及答案(自学推荐,23页) [Word格式]<成本会计>配套习题集 ...查看


  • 编译原理教程课后习题答案--第七章
  • 第七章 目标代码生成 7.1 对下列四元式序列生成目标代码: T=A-B S=C+D W=E-F U=W/T V=U*S 其中,V 是基本块出口的活跃变量,R0和R1是可用寄存器. [解答] 简单代码生成算法依次对四元式进行翻译.我们以四元 ...查看


  • 在大学里寻找课后答案的必去之处
  • 3500份课后答案,很值得收藏,这里只介绍了一部分. 还有很多,可以去课后答案网(http://www.khdaw.com/bbs)查找. ##################[公共基础课-答案]#################### 新 ...查看


  • 大学课后题答案
  • 不用买参考书了!大学课本答案大全!--爱死你了!( 为什么大四才发现啊) 2008-12-18 16:50 | (分类:) 注册可用 公共课程 http://www.10xiao.com/forum-6-1.html 新视野大学英语读写教程 ...查看


  • 大学课本答案大全
  • 不用买参考书了!大学课本答案大全! 公共课程 http://www.10xiao.com/forum-6-1.html 新视野大学英语读写教程第四册答案 http://www.10xiao.com/thread-7-1-1.html 新视野 ...查看


  • 数据库原理及应用教程第3版课后题答案
  • 第一章习题参考答案 一.选择题 1. C 2. B 3. D 4. C 5. D 6. A 7. A 8. B 9. D 10. B 11. C 12. D 13. A 14. D 15. B 16. C 17. D 18. A 19. D ...查看


  • 新英汉翻译教程第十四章语态转换译法课堂互动及课后习题答案
  • 1 课堂互动1: 翻译下列句子, 顺译成被动句(参考译文) 8.He was beaten black and blue. 9.His father was killed before liberation. [译文]他爹在解放前给杀害了. ...查看


  • [多媒体技术应用教程]的课后习题答案
  • 习题参考答案 第一章 参考答案 一.单项选择题 1.B 2.A 3.B 4.A 5.D 6.A 二. 多项选择题 1.CG 2.BCEGHI 3.ABCEF 第2章 参考答案 一.选择题 1.A 2.C 3.A 4. BD 5. ABCD ...查看


  • 数学专业参考书推荐
  • 数学专业参考书整理推荐 从数学分析开始讲起: 数学分析是数学系最重要的一门课,经常一个点就会引申出今后的一门课,并且是今后数学系大部分课程的基础.也是初学时比较难的一门课,这里的难主要是对数学分析思想和方法的不适应,其实随着课程的深入会一点 ...查看


热门内容