龙书第六章参考答案Word文档格式.docx
- 文档编号:19125950
- 上传时间:2023-01-04
- 格式:DOCX
- 页数:17
- 大小:20.48KB
龙书第六章参考答案Word文档格式.docx
《龙书第六章参考答案Word文档格式.docx》由会员分享,可在线阅读,更多相关《龙书第六章参考答案Word文档格式.docx(17页珍藏版)》请在冰豆网上搜索。
∙间接三元式更详细的讲解
6.2.2
对下列赋值语句重复练习6.2.1
8a=b[i]+c[j]
9a[i]=b*c-b*d
10x=f(y+1)+2
11x=*p+&
y
a=b[i]+c[j]
四元式
0)=[]bit1
1)=[]cjt2
2)+t1t2t3
3)=t3a
三元式
0)=[]bi
1)=[]cj
2)+(0)
(1)
3)=a
(2)
间接三元式
0)
1)
2)
3)
a[i]=b*c-b*d
0)*bct1
1)*bdt2
2)-t1t2t3
3)[]=ait4
4)=t3t4
0)*bc
1)*bd
2)-(0)
(1)
3)[]=ai
4)=(3)
(2)
0)*bc1)*bd2)-(0)
(1)3)[]=ai4)=(3)
(2)
0)1)2)3)4)
x=f(y+1)+2
0)+y1t1
1)paramt1
2)callf1t2
3)+t22t3
4)=t3x
0)+y1
1)param(0)
2)callf1
3)+
(2)2
4)=x(3)
4)
∙数组元素的取值和赋值
6.2.3!
说明如何对一个三地址代码序列进行转换,使得每个被定值的变量都有唯一的变量名。
6.3节的练习
6.3.1
确定下列声明序列中各个标识符的类型和相对地址。
floatx;
record{floatx;
floaty;
}p;
record{inttag;
floatx;
}q;
SDT
S->
{top=newEvn();
offset=0;
}
D
D->
Tid;
{top.put(id.lexeme,T.type,offset);
offset+=T.width}
D1
ε
T->
int{T.type=interget;
T.width=4;
float{T.type=float;
T.width=8;
record'
{'
{Evn.push(top),top=newEvn();
Stack.push(offset),offset=0;
D'
}'
{T.type=record(top);
T.width=offset;
top=Evn.top();
offset=Stack.pop();
标识符类型和相对地址
lineidtypeoffsetEvn
1)xfloat01
2)xfloat02
2)yfloat82
2)precord()81
3)tagint03
3)xfloat43
3)yfloat123
3)qrecord()241
6.3.2!
将图6-18对字段名的处理方法扩展到类和单继承的层次结构。
12给出类Evn的一个实现。
该实现支持符号表链,使得子类可以重定义一个字段名,也可以直接引用某个超类中的字段名。
13给出一个翻译方案,该方案能够为类中的字段分配连续的数据区域,这些字段中包含继承而来的域。
继承而来的字段必须保持在对超类进行存储分配时获得的相对地址。
6.4节的练习
6.4.1
向图6-19的翻译方案中加入对应于下列产生式的规则:
14E->
E1*E2
15E->
+E1
产生式语义规则
E->
E1*E2{E.addr=newTemp();
E.code=E1.code||E2.code||
gen(E.addr'
='
E1.addr'
*'
E2.addr);
}
|+E1{E.addr=E1.addr;
E.code=E1.code;
6.4.2
使用图6-20的增量式翻译方案重复练习6.4.1
E2.addr;
6.4.3
使用图6-22的翻译方案来翻译下列赋值语句:
16x=a[i]+b[j]
17x=a[i][j]+b[i][j]
18!
x=a[b[i][j]][c[k]]
x=a[i]+b[j]
语法分析树:
三地址代码
t_1=i*awidth
t_2=a[t_1]
t_3=j*bwidth
t_4=b[t_3]
t_5=t_2+t_4
x=t_5
x=a[i][j]+b[i][j]
语法分析树:
三地址代码:
t_1=i*ai_width
t_2=j*aj_width
t_3=t_1+t_2
t_4=a[t_3]
t_5=i*bi_width
t_6=j*bj_width
t_7=t_5+t_6
t_8=b[t_7]
t_9=t_4+t_8
x=t_9
!
6.4.4!
修改图6-22的翻译方案,使之适合Fortran风格的数据引用,也就是说n维数组的引用为id[E1,E2,…,En]
仅需修改L产生式(同图6-22一样,未考虑消除左递归)
L->
id[A]{L.addr=A.addr;
global.array=top.get(id.lexeme);
A->
E{A.array=global.array;
A.type=A.array.type.elem;
A.addr=newTemp();
gen(A.addr'
E.addr'
A.type.width;
A1,E{A.array=A1.array;
A.type=A1.type.elem;
t=newTemp();
gen(t'
A.type.length);
A1.addr'
+'
t);
注意
令a表示一个i*j的数组,单个元素宽度为w
a.type=array(i,array(j,w))
a.type.length=i
a.type.elem=array(j,w)
6.4.5
将公式6.7推广到多维数据上,并指出哪些值可以被存放到符号表中并用来计算偏移量。
考虑下列情况:
19一个二维数组A,按行存放。
第一维的下标从l_1到h_1,第二维的下标从l_2到h_2。
单个数组元素的宽度为w。
20其他条件和1相同,但是采用按列存放方式。
21!
一个k维数组A,按行存放,元素宽度为w,第j维的下标从l_j到h_j。
22!
其他条件和3相同,但是采用按列存放方式。
令n_i为第i维数组的元素个数,计算公式:
n_i=h_i-l_i+1
3.A[i_1]]…[i_k]=base+
(
(i_1-l_1)*n_2*…*n_k+
…+
(i_k-1-l_k-1)*n_k+
(i_k-l_k)
)*w
4.A[i_1]]…[i_k]=base+
(i_1-l_1)+
(i_2-l_2)*n_1+
…+
(i_k-l_k)*n_k-1*n_k-2*…*n_1
6.4.6
一个按行存放的整数数组A[i,j]的下标i的范围为1~10,下标j的范围为1~20。
每个整数占4个字节。
假设数组A从0字节开始存放,请给出下列元素的位置:
23A[4,5]
24A[10,8]
25A[3,17]
计算公式:
((i-1)*20+(j-1))*4
26(3*20+4)*4=256
27(9*20+7)*4=748
28(2*20+16)*4=224
6.4.7
假定A是按列存放的,重复练习6.4.6
((j-1)*10+(j-1))*4
29(4*10+3)*4=172
30(7*10+9)*4=316
31(16*10+2)*4=648
6.4.8
一个按行存放的实数型数组A[i,j,k]的下标i的范围为1~4,下标j的范围为0~4,且下标k的范围为5~10。
每个实数占8个字节。
假设数组A从0字节开始存放,计算下列元素的位置:
32A[3,4,5]
33A[1,2,7]
34A[4,3,9]
((i-1)*5*6+j*6+(k-5))*8
35((3-1)*5*6+4*6+(5-5))*8=672
36((1-1)*5*6+2*6+(7-5))*8=112
37((4-1)*5*6+3*6+(9-5))*8=896
6.4.9
假定A是按列存放的,重复练习6.4.8
((i-1)+j*4+(k-5)*5*4)*8
38((3-1)+4*4+(5-5)*5*4)*8=144
39((1-1)+2*4+(7-5)*5*4)*8=384
40((4-1)+3*4+(9-5)*5*4)*8=760
6.5节的练习
6.5.1
假定图6-26中的函数widen可以处理图6-25a的层次结构中的所有类型,翻译下列表达式。
假定c和d是字符类型,s和t是短整型,i和j为整型,x是浮点型。
41x=s+c
42i=s+c
43x=(s+c)*(t+d)
x=s+c
t1=(int)s
t2=(int)c
t3=t1+t2
x=(float)t3
i=s+c
i=t1+t2
x=(s+c)*(t+d)
t4=(int)t
t5=(int)d
t6=t4+t5
t7=t3+t6
x=(float)t7
6.5.2
像Ada中那样,我们假设每个表达式必须具有唯一的类型,但是我们根据一个子表达式本身只能推导出一个可能类型的集合。
也就是说,将函数E1应用于参数E2(文法产生式为E->
E1(E2))有如下规则:
E.type={t|对E2.type中的某个s,s->
t在E1.type中}
描述一个可以确定每个字表达式的唯一类型的SDD。
它首先使用属性type,按照自底向上的方式综合得到一个可能类型的集合。
在确定了整个表达式的唯一类型之后,自顶向下地确定属性unique的值,整个属性表示各子表达式的类型。
6.6节的练习
6.6.1
在图6-36的语法制导定义中添加处理下列控制流构造的规则:
44一个repeat语句:
repeatSwhileB
45!
一个for循环语句:
for(S1;
B;
S2)S3
ProductionSyntaxRule
repeatS1whileBS1.next=newlabel()
B.true=newlabel()
B.false=S.next
S.code=label(B.true)||S1.code
||label(S1.next)||B.code
for(S1;
S2)S3S1.next=newlabel()
S2.next=S1.next
S3.next=newlabel()
S.code=S1.code
||lable(S1.next)||B.code
||lable(B.true)||S3.code
||label(S3.next)||S2.code
||gen('
goto'
S1.next)
6.6.2
现代计算机试图在同一个时刻执行多条指令,其中包括各种分支指令。
因此,当计算机投机性地预先执行某个分支,但实际控制流却进入另一个分支时,付出的代价是很大的。
因此我们希望尽可能地减少分支数量。
请注意,在图6-35c中while循环语句的实现中,每个迭代有两个分支:
一个是从条件B进入到循环体中,另一个分支跳转回B的代码。
基于尽量减少分支的考虑,我们通常更倾向于将while(B)S当作if(B){repeatSuntil!
(B)}来实现。
给出这种翻译方法的代码布局,并修改图6-36中while循环语句的规则。
if(B){B.true=newlabel()
repeatS1B.false=S.next
until!
(B)S1.next=newlabel()
}S.code=B.code
||label(B.true)||S1.code
6.6.3!
假设C中存在一个异或运算。
按照图6-37的风格写出这个运算符的代码生成规则。
B1^B2等价于!
B1&
&
B2||B1&
!
B2(运算符优先级!
>
&
||)
B->
B1^B2B1.true=newlabel()
B1.false=newlabel()
B2.true=B.true
B2.false=B1.true
b3=newboolean()
b3.code=B1.code
b3.true=newlabel()
b3.false=B.false
b4=newboolean()
b4.code=B2.code
b4.true=B.false
b4.false=B.true
S.code=B1.code
||label(B1.false)||B2.code
||label(B1.true)||b3.code
||label(b3.true)||b4.code
6.6.4
使用6.6.5节中介绍的避免goto语句的翻译方案,翻译下列表达式:
46if(a==b&
c==d||e==f)x==1
47if(a==b||c==d||e==f)x==1
48if(a==b||c==d&
e==f)x==1
if(a==b&
ifFalsea==bgotoL3
ifc==dgotoL2
L3:
ifFalsee==fgotoL1
L2:
x==1
L1:
if(a==b||c==d||e==f)x==1
ifa==bgotoL2
x==1
if(a==b||c==d&
ifFalsec==dgotoL1
6.6.5
基于图6-36和图6-37中给出的语法制导定义,给出一个翻译方案。
6.6.6
使用类似于图6-39和图6-40中的规则,修改图6-36和图6-37的语义规则,使之允许控制流穿越。
仅补充完毕书中未解答部分
if(B)S1elseS2B.true=fall
B.false=newlabel()
S1.next=S.next
S2.next=S.next
S.code=B.code
||S1.code
S1.next)
||label(B.false)||S2.code
while(B)S1begin=newlabel()
B.true=fall
S1.next=begin
S.code=label(begin)||B.code
begin)
S1S2S1.next=fall
S.code=S1.code||S2.code
B1&
B2B1.true=fall
B1.false=ifB.false==fall
thennewlabel()
elseB.false
B2.false=B.false
B.code=ifB.false==fall
thenB1.code||B2.code||label(B1.false)
elseB1.code||B2.code
6.6.7!
练习6.6.6中的语义规则产生了一些不必要的标号。
修改图6-36中语句的规则,使之只创建必要的标号。
你可以使用特殊符号deferred来表示还没有创建的一个标号。
你的语义规则必须能生成类似于例6.21的代码。
6.6.8!
!
6.6.5节中讨论了如何使用穿越代码来尽可能减少生成的中间代码中跳转指令的数据。
然而,它并没有充分考虑将一个条件替换为它的补的方法,例如将ifa<
bgotoL1;
gotoL2替换成ifFalsea>
=bgotoL2;
gotoL1。
给出语法制导定义,它在需要时可以利用这种替换方法。
6.7节的练习
6.7.1
使用图6-43中的翻译方案翻译下列表达式。
给出每个子表达式的truelist和falselist。
你可以假设第一条被生成的指令的地址是100.
49a==b&
(c==d||e==f)
50(a==b||c==d)||e==f
51(a==b&
c==d)&
e==f
a==b&
6.7.2
52E3.false=i1
53S2.next=i7
54E4.false=i7
55S1.next=i3
56E2.true=i3
6.7.3
当使用图6-46中的翻译方案对图6-47进行翻译时,我们为每条语句创建S.next列表。
一开始是赋值语句S1,S2,S3,然后逐步处理越来越大的if语句,if-else语句,while语句和语句块。
在图6-47中有5个这种类型的结构语句:
∙S4:
while(E3)S1
∙S5:
if(E4)S2
∙S6:
包含S5和S3的语句块
∙S7:
if(E2)S4elseS6
∙S8:
整个程序
对于这些结构语句,我们可以通过一个规则用其他的Sj.next列表以及程序中
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第六 参考答案