编译原理课后答案——第六章_运行时存储空间组织
编译原理第6章习题答案
1)抽象语法树:
2)四元式序列:
3)三元式序列:
4)间接三元式序列:
6.4.1 向图6-19的翻译方案中加入对应于下列产生式的规则: 1) E E1 * E2 2) E E1 (单目加)
E.addr = E1.addr E.code = E1.code
例如:+3
6.4.2 使用图6-20中的增量式翻译方案重复练习6.4.1
{E.addr = E1.addr}
在增量方式中,gen不仅要构造出一个新的三地址指令,还 要将它添加到至今为止已生成的指令序列之后。
6.4.3 使用使用图6-22所示的翻译方案来翻译下 列赋值语句: 2) x = a[i][j] + b[i][j] 假设w1为数组a的第一维的宽度,w2为数组b 的第一维的宽度,整数宽度为w。第6章习题答案
作业: 6.1.1 6.2.1 6.4.1 6.4.2 6.4.3 6.6.1
6.7.1 (1) 补充习题1
第6章 中间代码生成
6.1.1 为下面的表达式构造DAG ((x+y)-((x+y)*(x-y)))+((x+y)*(x-y))
6.2.1 将算术表达式 a+-(b+c) 翻译成
补充习题1:用本节所给的翻译模式(采用回填)翻译语句: if (a<b || c<d && e<f ) A1 else A2; while (a<b) A3 ; 假定语句序号从100起算,又假定A1、A2、A3语句各生成10条指令。
100 if a<b goto 106 101 goto 102 102 if c<d goto 104 103 goto 117 104 if e<f goto 106 105 goto 117 106 107 . A1 . 115 116 goto 127 117 118 A2 . . 126 127 if a<b goto 129 128 goto 140 129 130 A3 . . 138 139 goto 127 140 141 142 143 144 145
编译原理课后习题答案
(a) 0 ( 0 | 1)* 0
由0和1组成且以0开始和结束的符号串全体. (b) ( ( | 0 ) 1* ) * 由0和1组成的符号串全体.
(c) ( 0 | 1 )* 0 ( 0 | 1) ( 0 | 1) 由0和1组成且以000,001,010或011结束的符号串全体. 长度大于等于3且倒数第3个字符为0的01符号串全体.
R R ‘|’ S | S S ST | T T U* | U U (R) | a | b
a
a
a
28
4.5 dangling-else文法: stmt if expr then stmt | matched-stmt matched-stmt if expr then matched-stmt else stmt | other 试说明此文法是二义性的。 句子 if e1 then if e2 then s1 else if e3 then s2 else s3 if e1 then if e2 then s1 else if e3 then s2 else s3
0|1 B 1 D E 0 ABDE ABDE ABCDE ABDE 1 ABCDE ABCDE
start
A
1
C
NFA 0
start A' 1
0
B'
0
1
start
A'
1
最小化DFA
24
DFA
3.8 给定右线性文法G: S 0S | 1S | 1A | 0B A 1C |1 B 0C | 1 C 0C | 1C | 0 | 1 试求一个等价的左线性文法G’.
20
3.6 给出接受下列在字母表{0,1}上的DFA。 (a)所有以00结束的符号串的集合; (1|0)*00
编译原理运行时存储空间组织
主程序P
TOP 4
3
2
1
SP 0
x a 0 返回地址
0
主程序P过程 S
TOP 10
9 8 7 6
SP 5
4 3 2 1 0
动态链
i c 0(形参个数) 0 返回地址
0 x a 0 返回地址
0
?第N层过程调用
第 N+1层过程,如何 确定被调用过程(第 N+1层)过程的静态链?
A:调用过程(第N层
每个过程的活动记录内容如图:
TOP
2 1 SP 0
临时单元 内情向量 局部变量 形式单元 参数个数 返回地址
老SP
对任何局部变量X的 引用可表示为变址访 问:
dx[SP] dx: 变量X相对于活 动记录起点的地址, 在编译时可确定。
9.5 嵌套过程语言的栈式实现
假定语言不仅允许过程的递归调用(和可变 数组),而且允许过程定义的嵌套,如 PASCAL,PL语言。
临时单元 内情向量 局部变量 形式单元
静态链 动态链 返回地址
连接数据
➢返回地址 ➢动态链:指向调用该 过程前的最新活动记 录地址的指针。
➢静态链:指向静态直 接外层最新活动记录 地址的指针,用来访 问非局部数据。
每个过程的活动记录内容
TOP
2 1 SP 0
临时单元 内情向量 局部变量 形式单元
静态链 动态链 返回地址
procedure quicksort(m, n:integer); var i:integer; begin if (n>m) then begin i:=partition(m, n ); quicksort(m, i-1 ); quicksort(i+1, n ) end; end;
编译原理第六章习题解答
第六章习题答案4.文法G:S→S;G|GG→G(T)|HH→a|(S)T→T+S|S(1)该文法是算符文法,且不包含ε产生式。
计算每个非终结符的FIRSTVT集合:FIRSTVT(S) = FIRSTVT(S)∪{;}∪FIRSTVT(G) = {;, a, (}FIRSTVT(G) = FIRSTVT(G)∪{(}∪FIRSTVT(H) = {a, (}FIRSTVT(H) = {a, (} = {a, (}FIRSTVT(T) = FIRSTVT(T)∪{+}∪FIRSTVT(S) = {+, ;, a, (}计算每个非终结符的LASTVT集合:LASTVT(S) = {;}∪LASTVT(G) = {;, a, )}LASTVT(G) = {)}∪LASTVT(H) = {a, )}LASTVT(H) = {a, )} = {a, )}LASTVT(T) = {+}∪LASTVT(S) = {+, ;, a, )}①关系由#S#可知:##由G→G(T)|H可知:()②关系S# LASTVT(S)#→{;, a, )}#S; LASTVT(S);→{;, a, )};G( LASTVT(G)( →{a, )}(T) LASTVT(T)) →{+, ;, a, )})S) LASTVT(S)) →{;, a, )})T+ LASTVT(T)+ →{+, ;, a, )}+③关系#S #FISRTVT(S)→ #{;, a, (};G ;FISRTVT(G)→ ;{a, (}(T (FISRTVT(T)→ ({+, ;, a, (}(S (FISRTVT(S)→ ({;, a, (}+S +FISRTVT(S)→ +{;, a, (}构造算符优先关系表如下:+ ; a ( ) # +;a()#由该文法的算符优先关系表可知,该文法是算符优先文法。
(2)句型a(T+S);H;(S)的语法树如右图所示:短语:a(T+S);H;(S),a(T+S);H ,a(T+S),a ,T+S ,H ,(S)句柄:a素短语:a ,T+S ,(S)最左素短语:a(3)对a;(a+a)进行算符优先分析步骤如下:对采用算符优先分析方法进行分析,可知:a;(a+a)和(a+a)均应为该文法的句子。
编译原理(第2版)课后习题答案详解
第1 章引论第1 题解释下列术语:(1)编译程序(2)源程序(3)目标程序(4)编译程序的前端(5)后端(6)遍答案:(1)编译程序:如果源语言为高级语言,目标语言为某台计算机上的汇编语言或机器语言,则此翻译程序称为编译程序。
(2)源程序:源语言编写的程序称为源程序。
(3)目标程序:目标语言书写的程序称为目标程序。
(4)编译程序的前端:它由这样一些阶段组成:这些阶段的工作主要依赖于源语言而与目标机无关。
通常前端包括词法分析、语法分析、语义分析和中间代码生成这些阶段,某些优化工作也可在前端做,也包括与前端每个阶段相关的出错处理工作和符号表管理等工作。
(5)后端:指那些依赖于目标机而一般不依赖源语言,只与中间代码有关的那些阶段,即目标代码生成,以及相关出错处理和符号表操作。
(6)遍:是对源程序或其等价的中间语言程序从头到尾扫视并完成规定任务的过程。
第2 题一个典型的编译程序通常由哪些部分组成?各部分的主要功能是什么?并画出编译程序的总体结构图。
答案:一个典型的编译程序通常包含8 个组成部分,它们是词法分析程序、语法分析程序、语义分析程序、中间代码生成程序、中间代码优化程序、目标代码生成程序、表格管理程序和错误处理程序。
其各部分的主要功能简述如下。
词法分析程序:输人源程序,拼单词、检查单词和分析单词,输出单词的机内表达形式。
语法分析程序:检查源程序中存在的形式语法错误,输出错误处理信息。
语义分析程序:进行语义检查和分析语义信息,并把分析的结果保存到各类语义信息表中。
中间代码生成程序:按照语义规则,将语法分析程序分析出的语法单位转换成一定形式的中间语言代码,如三元式或四元式。
中间代码优化程序:为了产生高质量的目标代码,对中间代码进行等价变换处理。
目标代码生成程序:将优化后的中间代码程序转换成目标代码程序。
表格管理程序:负责建立、填写和查找等一系列表格工作。
表格的作用是记录源程序的各类信息和编译各阶段的进展情况,编译的每个阶段所需信息多数都从表格中读取,产生的中间结果都记录在相应的表格中。
编译原理第6章 运行时存储空间组织和符号表
运行时存储空间组织和符号表
3
当前活动记录一般包含如下内容: 连接数据: ①返回地址 ②动态链:指向调用该过程前的运行活动记录地 址的指针。运行时,使运行栈上各数据区按动态 建立的次序连成链。链头为栈顶起始位置。 ③静态链:指向静态直接外层最新活动记录地址 的指针,用来访问非局部数据。 形式单元:存放相应实在参数的地址或值。 局部数据区:局部数据、内情向量、临时单元。 ( P164 图6.7 )
2013-6-28
运行时存储空间组织和符号表
35
1
14
例:n=13 32
2013-6-28
运行时存储空间组织和符号表
36
三、 名字的作用范围 1、Fortran的符号表组织
2013-6-28
运行时存储空间组织和符号表
37
2、Pascal符号表组织
最近嵌套作用域原则:一个名字的作用 域是那个包含了这个名字的说明的最小 函数。 设计符号表: ①采用栈符号表:新的名字从栈顶填入, 每当进入一个过程时建立一张子符号表, 退出时释放。 ②引入过程的嵌套层次表(DISPLAY)
2013-6-28
运行时存储空间组织和符号表
14
§2 静态存储分配
FORTRAN77采用的是静态存储分配,它 的程序是段结构,整个程序由主程序段和若 干个子程序段组成,它的每个数据名所需的 存储空间大小都是常量,并且不允许递归调 用,这样,整个程序所需存储空间的总量在 编译时就能完全确定,所以,可以采用静态 存储分配方式。
2013-6-28
运行时存储空间组织和符号表
42
2013-6-28
运行时存储空间组织和符号表
43
2013-6-28
运行时存储空间组织和符号表
《编译原理》(陈火旺版)课后作业参考答案ch6-10
第6章 属性文法和语法制导翻译7. 下列文法由开始符号S 产生一个二进制数,令综合属性v al 给出该数的值:试设计求S.val 的属性文法,其中,已知B 的综合属性c, 给出由B 产生的二进位的结果值。
例如,输入101.101时,S.val=5.625,其中第一个二进位的值是4,最后一个二进位的值是0.125。
【答案】11. 设下列文法生成变量的类型说明:(1)构造一下翻译模式,把每个标识符的类型存入符号表;参考例6.2。
【答案】第7章 语义分析和中间代码产生1. 给出下面表达式的逆波兰表示(后缀式):3. 请将表达式-(a+b)*(c+d)-(a+b+c)分别表示成三元式、间接三元式和四元式序列。
【答案】间接码表:(1)→(2)→(3)→(4)→(1)→(5)→(6)4. 按7.3节所说的办法,写出下面赋值句A:=B*(-C+D ) 的自下而上语法制导翻译过程。
给出所产生的三地址代码。
【答案】5. 按照7.3.2节所给的翻译模式,把下列赋值句翻译为三地址代码: A[i, j]:=B [i, j] + C[A [k, l]] + d [ i+j] 【答案】6. 按7.4.1和7.4.2节的翻译办法,分别写出布尔式A or ( B and not (C or D) )的四元式序列。
【答案】用作数值计算时产生的四元式: 用作条件控制时产生的四元式:其中:右图中(1)和(8)为真出口,(4)(5)(7)为假出口。
7. 用7.5.1节的办法,把下面的语句翻译成四元式序列: While A<C and B<D do if A=1 then C:=C+1else while A ≦D do A:=A+2; 【答案】第9章 运行时存储空间组织4. 下面是一个Pascal 程序:当第二次( 递归地) 进入F 后,DISPLAY 的内容是什么?当时整个运行栈的内容是什么? 【答案】第1次进入F 后,运行栈的内容: 第2次进入F 后,运行栈的内容:第2次进入F 后,Display 内容为:5. 对如下的Pascal 程序,画出程序执行到(1)和(2)点时的运行栈。
编译原理部分课后答案,仅供参考
第一章编译程序概述1.1什么是编译程序编译程序是现代计算机系统的基本组成部分之一,而且多 数计算机系统都含有不止一个高级语言的编译程序。
对有些高 级语言甚至配置了几个不同性能的编译程序。
1.2编译过程概述和编译程序的结构编译程序完成从源程序到目标程序的翻译工作,是一个复 杂的整体的过程。
从概念上来讲,一个编译程序的整个工作过 程是划分成阶段进行的,每个阶段将源程序的一种表示形式转 换成另一种表示形式,各个阶段进行的操作在逻辑上是紧密连 接在一起的。
一般一个编译过程划分成词法分析、语法分析、 语义分析、中间代码生成,代码优化和目标代码生成六个阶段,这是一种典型的划分方法。
事实上,某些阶段可能组合在一起, 这些阶段间的源程序的中间表示形式就没必要构造岀来了。
我 们将分别介绍各阶段的任务。
另外两个重要的工作:表格管理 和岀错处理与上述六个阶段都有联系。
编译过程中源程序的各 种信息被保留在种种不同的表格里,编译各阶段的工作都涉及 到构造、查找或更新有关的表格,因此需要有表格管理的工作; 如果编译过程中发现源程序有错误,编译程序应报告错误的性 质和错误发生的地点,并且将错误所造成的影响限制在尽可能 小的范围内,使得源程序的其余部分能继续被编译下去,有些 编译程序还能自动校正错误, 这些工作称之为岀错处理。
图1.3表示了编译的各个阶段。
图1.3编译的各个阶段它不生成目标代码,它每遇到一个语句,就要对这个语句进行 分析以决定语句的含义,执行相应的动作。
右面的图示意了它 的工作机理第二章:PL/O 编译程序问答第1题 PL/0语言允许过程嵌套定义和递归调用,试问 它的编译程序如何解决运行时的存储管理。
答:PL/0语言允许过程嵌套定义和递归调用,它的编译程序在运行时采用了栈式动态存储管理。
(数组CODE 存放的只读目 标程序,它在运行时不改变。
)运行时的数据区S 是由解释程序 定义的一维整型数组,解释执行时对数据空间S 的管理遵循后进先岀规则,当每个过程(包括主程序)被调用时,才分配数据 空间,退出过程时,则所分配的数据空间被释放。
编译原理第6章运行时存储空间组织和符号表
堆栈和堆的区别与应用
1 堆栈的特点
堆栈的先进后出特性和其在函数调用和维护程序状态中的应用。
2 堆的特点
堆的动态分配特性和其在动态存储分配和数据结构中的应用。
3 实际应用
探索堆栈和堆在实际程序开发中的应用场景。
动态存储分配
动态内存分配原理
学习动态内存分配的原理和 算法,了解如何有效地利用 内存资源。
编译原理第6章运行时存 储空间组织和符号表
在编译原理的第6章中,我们将探讨程序运行时的存储空间组织和符号表。了 解这些概念将有助于我们更好地理解程序的内部运行机制。
运行时存储空间组织
堆栈和堆
学习堆栈和堆的区别和应用, 深入了解程序中不同存储空 间的作用和用法。
动态存储分配
了解动态存储分配的原理和 方法,掌握动态内存管理的 技巧。
全局变量和静态变量的存储方式
1
全局变量
全局变量的存储方式及其作用域规则。
静态变量
2
静态变量的存储方式及其在程序运行过
程中的特点。
3
示例和实践
通过实例和实际代码演示学习全局变量 和静态变量的使用方法。
局部变量和动态变量的存储方式
局部变量
局部变量在函数执行时的存储方式和作用范围。
动态变量
动态变量的存储方式及其在程序运行过程中的特点 和用途。
内存泄漏与回收
掌握如何避免内存泄漏,并 了解内存回收的方法和策略。
内存管理的最佳实践
分享内存管理的最佳实践, 帮助提高程序的效率和稳定 性。
算法实现与性能评估
算法实现
利用合适的数据结构和编程技巧 实现高效的算法。
性能评估
通过实际测试和分析,评估算法 的时间和空间复杂度。
编译原理 第6章习题解答
第六章习题解答6.1根据语法树,得到下述优先关系:E′*(E T′>+ F>* i>*+<T +<F +<i *<(6.2由文法各条产生式,有然后构造<:FIRST={(Z,b),(M,(),(M,a),(L,M)}FIRST+={(Z,b),(M,(),(M,a),(L,M),(L,(),(L,a)}FIRST*=FIRST+∪{(a,a),(b,b),((,(),( ),)),(Z,Z),(M,M),(L,L)}所以<={(b,(),(b,a),((,M),((,(),((,a))再构造>:LAST={(Z,b),(M,L),(M,a),(L,))}LAST+={(Z,b),(M,L),(M,a),(M,))(L,))}(LAST+)T={(b,Z),(L,M),(a,M),( ),M},( ),L}}(LAST+)T所以>={(L,b),(L,a),(a,b),(a,a),( ),b),(),a)}将这三种关系合并得到表6.1。
利用此算法分析符号串b((aa)a)b是否是文法G[Z]的句子,过程如表6.2所示。
分析成功,符号串b((aa)a)b是文法G[Z]的句子。
表6.1 G[Z]的简单优先关系矩阵表6.2 简单优先分析过程6.3由优先关系矩阵中所示的优先关系:a>c a<b b>b b以及优先函数的定义,应该有f(a)>g(c),f(a)<g(b),f(b)>g(b),f(b)=g(c)则有f(a)>g(c)=f(b)>g(b)>f(a)矛盾。
所以该文法不存在优先函数。
6.4①定义集合∑=N,R={(x,y)∣x,y∈∑,x是y的因子}②定义集合∑=N,R={(x,y)|x,y∈∑,x和y均能被3整除}③定义集合∑=N-{1},R={(x,y)|x,y∈∑,x和y有大于1的公约数}④定义集合∑=N,R为关系“=”6.5关系可以用集合定义,也可以用布尔矩阵表示。
最新编译原理(课后习题答案ppt课件
10
(b) 试对于句子 not ( true or false) 构造一棵分析树.
bexpr bterm bfactor not bfactor
a S b S
(d) 此文法产生的语言是什么?
由相同个数的a和b组成的字符串.
9
1.3 考虑文法 bexpr bexpr or bterm | bterm bterm bterm and bfactor | bfactor bfactor not bfactor | ( bfactor ) | true | false
(a) 0 ( 0 | 1)* 0 由0和1组成且以0开始和结束的符号串全体.
(b) ( ( | 0 ) 1* ) * 由0和1组成的符号串全体.
(c) ( 0 | 1 )* 0 ( 0 | 1) ( 0 | 1) 由0和1组成且以000,001,010或011结束的符号串全体. 长度大于等于3且倒数第3个字符为0的01符号串全体.
16
3.4 对于下列语言分别写出它们的正规表达式:
(a) 英文字母组成的所有符号串, 要求符号串中顺序包含 五个元音字母. 令letter={非元音的英文字母} letter* (a|A) letter* (e|E) letter* (i|I) letter* (o|O) letter* (u|U) letter*
18
(e) 带有偶数个0和奇数个1的由0和1组成的符号串全体. E为带有偶数个0和1的由0和1组成的符号串全体. 即 ( 00 | 11)* ( ( 01 | 10 ) ( 00 | 11)* ( 01 | 10 ) ( 00 | 11)* )* E1E|E0E1E0E
编译原理部分课后答案,仅供参考
第一章编译程序概述1.1 什么是编译程序编译程序是现代计算机系统的基本组成部分之一,而且多数计算机系统都含有不止一个高级语言的编译程序。
对有些高级语言甚至配置了几个不同性能的编译程序。
1.2编译过程概述和编译程序的结构编译程序完成从源程序到目标程序的翻译工作,是一个复杂的整体的过程。
从概念上来讲,一个编译程序的整个工作过程是划分成阶段进行的,每个阶段将源程序的一种表示形式转换成另一种表示形式,各个阶段进行的操作在逻辑上是紧密连接在一起的。
一般一个编译过程划分成词法分析、语法分析、语义分析、中间代码生成,代码优化和目标代码生成六个阶段,这是一种典型的划分方法。
事实上,某些阶段可能组合在一起,这些阶段间的源程序的中间表示形式就没必要构造出来了。
我们将分别介绍各阶段的任务。
另外两个重要的工作:表格管理和出错处理与上述六个阶段都有联系。
编译过程中源程序的各种信息被保留在种种不同的表格里,编译各阶段的工作都涉及到构造、查找或更新有关的表格,因此需要有表格管理的工作;如果编译过程中发现源程序有错误,编译程序应报告错误的性质和错误发生的地点,并且将错误所造成的影响限制在尽可能小的范围内,使得源程序的其余部分能继续被编译下去,有些编译程序还能自动校正错误,这些工作称之为出错处理。
图1.3表示了编译的各个阶段。
图1.3 编译的各个阶段1.3 高级语言解释系统为了实现在一个计算机上运行高级语言的程序,主要有两个途径:第一个途径是把该程序翻译为这个计算机的指令代码序列,这就是我们已经描述的编译过程。
第二个途径是编写一个程序,它解释所遇到的高级语言程序中的语句并且完成这些语句的动作,这样的程序就叫解释程序。
从功能上说,一个解释程序能让计算机执行高级语言。
它与编译程序的主要不同是它不生成目标代码,它每遇到一个语句,就要对这个语句进行分析以决定语句的含义,执行相应的动作。
右面的图示意了它的工作机理第二章:PL/0编译程序问答第1题PL/0语言允许过程嵌套定义和递归调用,试问它的编译程序如何解决运行时的存储管理。
编译原理运行时存储空间的组织和管理 6(1)
存储单元
状态
值
环境
6.1 局部存储分配
静态概念和动态概念的对应
静 态 概 念
动 态 对 应
过程的定义
过程的活动
6.1 局部存储分配
静态概念和动态概念的对应
静 态 概 念
动 态 对 应
过程的定义
过程的活动
名字的声明
名字的绑定
6.1 局部存储分配
静态概念和动态概念的对应
6.1 局部存储分配
在SPARC/Solaris工作站上下面两个结构的size分别是24和16,为什么不一样? typedef struct _a{ typedef struct _b{ char c1; char c1; long i; char c2; char c2; long i; double f; double f; }a; }b;
6.1 局部存储分配
6.1.5 程序块 本身含有局部变量声明的语句 可以嵌套 最接近的嵌套作用域规则 并列程序块不会同时活跃 并列程序块的变量可以重叠分配
6.1 局部存储分配
main() { / begin of B0 / int a = 0; int b = 0; { / begin of B1 / int b = 1; {/ begin of B2 / int a = 2; }/ end of B2 / {/ begin of B3 / int b = 3; }/ end of B3 / }/ end of B1 / }/ end of B0 /
6.1 局部存储分配
在X86/Linux机器的结果和SPARC/Solaris工作站不一样,是20和16。 typedef struct _a{ typedef struct _b{ char c1; 0 char c1; 0 long i; 4 char c2; 1 char c2; 8 long i; 4 double f; 12 double f; 8 }a; }b;
编译原理课后答案——第六章_运行时存储空间组织
DISPLAY表 B_sp
A_sp Demo_sp
… …
…
B的活动记录
DISPLAY表 A_sp Demo_sp
A_sp Demo_sp
… …
A的活动记录
DISPLAY表 Demo的活动记录 A_sp
A_sp Demo_sp
… …
A的活动记录
Demo_sp (1) Demo→A
Demo的活动记录
(2) Demo→A→B
示表。
第六章 运行时存储空间组织
也即,每当进入一个过程后,在建立它的活动记录区的同时 也建立一张DISPLAY表,它自顶而下每个单元依次存放着现行层、
直接外层等,直至最外层(主程序层)等每一层过程的最新活动记
录的起始地址。 6.3 (1) 写出实现一般递归过程的活动记录结构以及过程 调用、过程进入与过程返回的指令; (2) 对以return(表达式)形式(这个表达式本身是一个递归 调用)返回函数值的特殊函数过程,给出不增加时间开销但能节省 存储空间的实现方法。假定语言中过程参数只有传值和传地址两
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。
编译原理第6章习题答案
P164–7
方法一: S L1.L2 SL L L1B LB B0 B1 {S.val:=L1.val+(L2.val/2 {S.val:=L.val} {L.val:=2*L1.val + B.c; L.length:=L1.length+1} {L.val:=B.c; L.length :=1} {B.c:=0} {B.c:=1}
End Else begin E.type := real; E.code:=E1.code || T.code || inttoreal || + end ET E.type := T.type; E.code:= T.code
T num.num T.type := real E.code:= num.num T num T.type := int E.code:= num
L1.length
L 2.length
)}
;
L.length:=L1.length+1} LB B0 B1 {L.val:=B.val; L.length :=1} {B.val:=0} {B.val:=1}
P165–11
答: D→id L L→, id L1 L→ : T T→integer T→ real {D.type:= L.type;addtype(id.type,L.type)} {L.type:= L1.type;addtype(id.type,L1.type)} {L.type:= T.type} { T.type := integer} { T.type := real}
L 2.length
)}
方法二: 为了用上 B 的综合属性 c, 就要将左递归产生式 L LB 转化为 L BL, 所以设计的求 S.val 的属性文法为: S L1.L2 SL L B L1 {S.val:=L1.val+(L2.val/2 {S.val:=L.val} {L.val:=B.c+L1.val; B.c:=B.val*2
编译原理第二版第六章课后答案
第六章第6章自底向上优先分析P122 练习1、已知文法G[S]为:S a|^|(T)T T,S|S(1)计算G[S]的FIRSTVT和LASTVT。
(2)构造G[S]的算符优先关系表并说明G[S]是否为算符优先文法。
(4)给出输入串(a,a)#和(a,(a,a))#的算符优先分析过程。
【解】(1)FIRSTVT LASTVTS a、^、(a、^、)T ,、a、^、(,、a、^、)(2)a ( ) , ^ #a ≯≯≯( ≮≮=≮≮) ≯≯≯, ≮≮≯≯≮^ ≯≯≯# ≮≮≮步骤栈优先关系当前符号剩余输入串移进或归约1 # #≮( ( a,a)# 移进4S->S;G|GG->G(T)|HH->a|(S)T->T+S|S(1)构造G[S]的算符优先关系表,并判断G[S]是否为算符优先文法。
(2)给出句型a(T+S);H;(S)的短语、句柄、素短语和最左素短语。
【解】(1)FIRSTVT(S)={; ( a }FIRSTVT(G)={ ( a }FIRSTVT(T)={+ ; ( a}LASTVT(S)={; a ) }LASTVT(G)={ a ) }LASTVT(T)={+ ; a ) }>关系:LASTVT(S) >;LASTVT(G)>(LASTVT(T)>)LASTVT(S)>)LASTVT(T)> +< 关系;<FIRSTVT< SPAN>(G)(<FIRSTVT(T)(<FIRSTVT(S)< SPAN>+< FIRSTVT(S)= 关系( = );()a+# ;<..><..>.> (<.<.<..> ).>.>.>a .>.>.>+<.<..><..>.> #<.<.<.<.<.(2)建立句型的语法子树如下:短语为:a, T+S, H, (S), a(T+S),a(T+S);H , a(T+S);H;(S)句柄:a素短语:a, T+S, (S)最左素短语:a如有侵权请联系告知删除,感谢你们的配合!如有侵权请联系告知删除,感谢你们的配合!。
编译原理(第四版)第6章运行时存储空间组织
于是,对当前正在执行(即活动)的过程,其任何局部变量或形 参X的引用均可表示为变址访问X[SP]。此处X代表X相对于活 动记录基址的偏移量,这个偏移量(即相对数)在编译时可完全 确定下来。过程的局部数组的内情向量的相对地址在编译时也 同样可完全确定下来,一旦数据空间在过程里获得分配,对数 组元素的引用也就容易用变址的方式进行访问。
图6-8 活动记录在栈中的示意
由图6-8可知,过程c访问过程a定义的变量x时,都要根据每层活动 记录所保存的老SP值逐层返回(见图6-8箭头所示)方可找到。 这种做法过于麻烦,能否采取一种更为简单有效的方法呢?一种
常用的跟踪每个外层过程最新活动记录位置的有效办法是,每进 入一个过程后,在建立它的活动记录区的同时建立一张嵌套层次 DISPLAY表,将记录它所有外层过程最新活动记录起始位置的 SP值都放在这张嵌套层次DISPLAY表中;这样,就可直接在本 层查到它的任何一个外层过程最新活动记录起始位置。假定现在 进入的过程层数为i,则它的DISPLAY表含有i+1个单元。此表 本身是一个小栈,自顶而下每个单元依次存放着现行层、直接外 层、……直至最外层(第0层,即主程序层)的每一层的最新活 动记录的起始地址。例如,令过程R的外层为Q,Q的外层为主程 序P,则过程R运行时的DISPLAY表内容如表6.1所示。
我们首先考虑一种简单程序语言的实现,这种语言没有分程 序结构,过程定义不允许嵌套,但允许过程的递归调用,允许过 程含有可变数组。例如,C语言除不允许含有可变数组外,就是 这样一种语言。C语言的程序结构如下: 全局数据说明
void main( ) {
main中的数据说明
}
void R( ) {
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
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)前后活动记录的过程。
Demo的活动记录
(4) Demo→A 1→B→A 1→B 2 2
图6-3 运行栈及DISPLAY表示意图
第六章 运行时存储空间组织 (2) 由于一个过程在运行时所需的实际数据空间 的大小,除可变数据结构(可变数组)那些部分外,其 余部分在编译时是完全可以知道的。编译程序处理时 将过程运行时所需的数据空间分为两部分:一部分在 编译时可确定其体积,称为该过程的活动记录;另一
示表。
第六章 运行时存储空间组织
也即,每当进入一个过程后,在建立它的活动记录区的同时 也建立一张DISPLAY表,它自顶而下每个单元依次存放着现行层、
直接外层等,直至最外层(主程序层)等每一层过程的最新活动记
录的起始地址。 6.3 (1) 写出实现一般递归过程的活动记录结构以及过程 调用、过程进入与过程返回的指令; (2) 对以return(表达式)形式(这个表达式本身是一个递归 调用)返回函数值的特殊函数过程,给出不增加时间开销但能节省 存储空间的实现方法。假定语言中过程参数只有传值和传地址两
3[TOP]=SP+d 4[TOP]=n JSR P
第六章 运行时存储空间组织 过程进入指令为 SP=TOP+1 1[SP]=返回地址 TOP=TOP+L 建立DISPLAY
P;
返回指令为 TOP=SP-1 SP=0[SP] X=2[TOP] UJ 0[X]
/*执行P过程*/
第六章 运行时存储空间组织 (2) 对于return后的直接递归情况,可简化为 (i+3)[SP]=Ti 或 (i+3)[SP]=addr [Ti]
种形式,为便于理解,举下例说明这种特殊的函数调用:
第六章 运行时存储空间组织 int gcd (int p,int q) {
if (p % q ==0) return q;
else return gcd (q, p % q) } 【解答】 (1) 一般递归过程的活动记录如图6-1 所示。
第六章 运行时存储空间组织
请分别给出这四个时刻运行栈的布局和使用的 DISPLAY表; (2) 若该语言允许动态数组,编译程序应如何处 置?如过程B有动态局部数组R[m:n],请给出B第一次 激活时相应的数据空间的情况。 【解答】 (1) 运行栈及使用的DISPLAY表如图6-3 所示。
第六章 运行时存储空间组织
B_sp
…
DISPLAY表 B_sp
A_sp Demo_sp
… …
…
B的活动记录
DISPLAY表 A_sp Demo_sp
A_sp Demo_sp
… …
A的活动记录
DISPLAY表 Demo的活动记录 A_sp
A_sp Demo_sp
… …
A的活动记录
Demo_sp (1) Demo→A
Demo的活动记录
(2) Demo→A→B
(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。
TOP 临时单元 内情向量 局部变量 DISPLAY表 形式单元 参数个数 全局DISPLAY地址 返回地址 SP TOP 老SP d个单元 L
图6-1 递归过程的活动记录
第六章 运行时存储空间组织 过程调用指令为 (i+4)[TOP]=Ti 或 (i+4)[TOP]=addr [Ti]
1[TOP]=SP
【解答】
按照嵌套过程语言栈式实现方法,ex
调用PP(a)前后活动记录的过程如图6-2所示。
第六章 运行时存储空间组织
PP_TOP PP_SP ex_SP PP的活动记录 (调用PP(a)之后)
DISPLAY表 形式参数X
参数个数:1 全局DISPLAY地址 返回地址 PP_SP ex_TOP ex_SP a DISPLAY表 ex_SP 参数个数:0 全局DISPLAY地址 返回地址 ex_SP ex_SP
第六章 运行时存储空间组织 (3) 堆 式 动 态 分 配 申 请 和 释 放 存 储 空 间 遵 守 原则。
a. 先请先放
c. 后请先放 作有 。
b. 先请后放
d. 任意
(4) 栈式动态分配与管理在过程返回时应做的工 a. 保护SP b. 恢复SP
c. 保护TOP
d. 恢复TOP
第六章 运行时存储空间组织 (5) 如果活动记录中没有DISPLAY表,则说明 a. 程序中不允许有递归定义的过程 。
部分(动态数组)的体积需在运行时动态确定,称为该
过程的可变辅助空间。当一个过程开始工作时,首先 在运行栈顶部建立它的活动记录,然后再在这个记录
之顶确定它所需的辅助空间。含有动态数组R的过程B
在第一次激活时,相应的数据空间情况如图6-4所示。
第六章 运行时存储空间组织
数组 R
…
B的可变辅助空间
运行中,一个过程Q可能引用它的任一外层过程P的最新活
动记录中的某些数据。因此,过程Q运行时必须知道它的 所有(静态)外层过程的最新活动记录的地址。由于允许递
归和可变数组,这些外层过程的活动记录的位置也往往是
变迁的。因此,必须设法跟踪每个(静态)外层的最新活动 记录的位置,而完成这一功能的就是DISPLAY嵌套层次显
b. 程序中不允许有嵌套定义的过程
c. 程序中既不允许有嵌套定义的过程,也不允许有递 归定义的过程 d. 程序中允许有递归定义的过程,也允许有嵌套定义 的过程 【解答】 (1) b (3) d (2) a (4) b (5) b
第六章 运行时存储空间组织 6.2 何谓嵌套过程语言运行时的DISPLAY表?它的作 当过程定义允许嵌套时,一个过程在运行 用是什么? 【解答】 中应能够引用在静态定义时包围它的任一外层过程所定义 的变量或数组。也就是说,在栈式动态存储分配方式下的
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。
第六章 运行时存储空间组织
第六章 运行时存储空间组织
6.1 完成下列选择题: (1) 过程的DISPLAY表中记录了 a. 过程的连接数据 。
b. 过程的嵌套层次
c. 过过程P1调用P2时,连接数据不包含 a. 嵌套层次显示表 c. 返回地址 b. 老SP d. 全局DISPLAY地址
第六章 运行时存储空间组织
将abs(1)改为1后,输出结果为1而不是120,这主要是与 编译的代码生成策略有关。对表达式(i + abs(1))* fact( ), 因为两个子表达式(i+abs(1))和fact( )都有函数调用,而编 译器的编译则是先产生左子表达式的代码,后产生右子表达 式的代码。也即,每次递归调用时,(i + abs(1))* fact( ) 中的(i+abs(1))的值都先于fact算出。但是,当abs(1)改为1 后,左子表达式就没有函数调用了,于是编译器就先产生右 子表达式的代码。每次递归调用时,
……
B2的活动记录
B1_sp DISPLAY表 A_sp Demo_sp B1_sp
… …
B1_sp A1_sp Demo_sp
……
B1的活动记录
DISPLAY表 A_sp Demo_sp
A_sp Demo_sp
…
A1_sp Demo_sp
…
A1的活动记录
Demo_sp (3) Demo→A→B 2 1→B
A_sp Demo_sp
…
A_sp Demo_sp
…
A的活动记录
Demo的活动记录
(a)
图6-4 带动态数组的运行栈示意 (a) 动态数组R空间分配之前;(b) 动态数组R空间分配之后
第六章 运行时存储空间组织 6.6 下 面 程 序 的 结 果 是 120 。 但 是 如 果 把 第 5 行 的 abs(1)改成1的话,则程序结果为1。试分析为什么会有这 种不同的结果。 int fact( ) {
数组R的 内情向量
…
数组 R 的 内情向量 B的活动记录 DISPLAY表 B_sp A的活动记录 DISPLAY表 Demo的活动记录 A_sp Demo_sp (b)