龙书第六章参考答案.docx

上传人:b****8 文档编号:28932881 上传时间:2023-07-20 格式:DOCX 页数:20 大小:22.18KB
下载 相关 举报
龙书第六章参考答案.docx_第1页
第1页 / 共20页
龙书第六章参考答案.docx_第2页
第2页 / 共20页
龙书第六章参考答案.docx_第3页
第3页 / 共20页
龙书第六章参考答案.docx_第4页
第4页 / 共20页
龙书第六章参考答案.docx_第5页
第5页 / 共20页
点击查看更多>>
下载资源
资源描述

龙书第六章参考答案.docx

《龙书第六章参考答案.docx》由会员分享,可在线阅读,更多相关《龙书第六章参考答案.docx(20页珍藏版)》请在冰豆网上搜索。

龙书第六章参考答案.docx

龙书第六章参考答案

6.1节的练习

为下面的表达式构造DAG

((x+y)-((x+y)*(x-y)))+((x+y)*(x-y))

解答

为下列表达式构造DAG,且指出他们每个子表达式的值编码。

假定+是左结合的。

1a+b+(a+b)

2a+b+a+b

3a+a+(a+a+a+(a+a+a+a))

解答

a+b+(a+b)

1

id

a

2

id

b

3

+

1

2

4

+

3

3

a+b+a+b

1

id

a

2

id

b

3

+

1

2

4

+

3

1

5

+

4

2

a+a+(a+a+a+(a+a+a+a))

1

id

a

2

+

1

1

3

+

2

1

4

+

3

1

5

+

3

4

6

+

2

5

6.2节的练习

6.2.1

将算数表达式a+-(b+c)翻译成

4抽象语法树

5四元式序列

6三元式序列

7间接三元式序列

解答

抽象语法树

四元式序列

op

arg1

arg2

result

0

+

b

c

t1

1

minus

t1

t2

2

+

a

t2

t3

三元式序列

op

arg1

arg2

0

+

b

c

1

minus

(0)

2

+

a

(1)

间接三元式序列

op

arg1

arg2

0

+

b

c

1

minus

(0)

2

+

a

(1)

instruction

0

(0)

1

(1)

2

(2)

参考

∙间接三元式更详细的讲解

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)=[]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)

间接三元式

0)+y1

1)param(0)

2)callf1

3)+

(2)2

4)=x(3)

0)

1)

2)

3)

4)

参考

∙数组元素的取值和赋值

6.2.3!

说明如何对一个三地址代码序列进行转换,使得每个被定值的变量都有唯一的变量名。

6.3节的练习

6.3.1

确定下列声明序列中各个标识符的类型和相对地址。

floatx;

record{floatx;floaty;}p;

record{inttag;floatx;floaty;}q;

解答

SDT

S->{top=newEvn();offset=0;}

D

D->Tid;{top.put(id.lexeme,T.type,offset);

offset+=T.width}

D1

D->ε

T->int{T.type=interget;T.width=4;}

T->float{T.type=float;T.width=8;}

T->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

解答

产生式语义规则

E->E1*E2{E.addr=newTemp();

gen(E.addr'='E1.addr'*'E2.addr;}

|+E1{E.addr=E1.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

!

x=a[b[i][j]][c[k]]

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;}

A->A1,E{A.array=A1.array;

A.type=A1.type.elem;

t=newTemp();

A.addr=newTemp();

gen(t'='E.addr'*'A.type.length);

gen(A.addr'='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

)*w

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

t1=(int)s

t2=(int)c

i=t1+t2

x=(s+c)*(t+d)

t1=(int)s

t2=(int)c

t3=t1+t2

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

S->repeatS1whileBS1.next=newlabel()

B.true=newlabel()

B.false=S.next

S.code=label(B.true)||S1.code

||label(S1.next)||B.code

S->for(S1;B;S2)S3S1.next=newlabel()

B.true=newlabel()

B.false=S.next

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循环语句的规则。

解答

ProductionSyntaxRule

S->if(B){B.true=newlabel()

repeatS1B.false=S.next

until!

(B)S1.next=newlabel()

}S.code=B.code

||label(B.true)||S1.code

||label(S1.next)||B.code

6.6.3!

假设C中存在一个异或运算。

按照图6-37的风格写出这个运算符的代码生成规则。

解答

B1^B2等价于!

B1&&B2||B1&&!

B2(运算符优先级!

>&&>||)

ProductionSyntaxRule

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&&c==d||e==f)x==1

ifFalsea==bgotoL3

ifc==dgotoL2

L3:

ifFalsee==fgotoL1

L2:

x==1

L1:

if(a==b||c==d||e==f)x==1

ifa==bgotoL2

ifc==dgotoL2

ifFalsee==fgotoL1

L2:

x==1

L1:

if(a==b||c==d&&e==f)x==1

ifa==bgotoL2

ifFalsec==dgotoL1

ifFalsee==fgotoL1

L2:

x==1

L1:

6.6.5

基于图6-36和图6-37中给出的语法制导定义,给出一个翻译方案。

6.6.6

使用类似于图6-39和图6-40中的规则,修改图6-36和图6-37的语义规则,使之允许控制流穿越。

解答

仅补充完毕书中未解答部分

ProductionSyntaxRule

S->if(B)S1elseS2B.true=fall

B.false=newlabel()

S1.next=S.next

S2.next=S.next

S.code=B.code

||S1.code

||gen('goto'S1.next)

||label(B.false)||S2.code

S->while(B)S1begin=newlabel()

B.true=fall

B.false=S.next

S1.next=begin

S.code=label(begin)||B.code

||S1.code

||gen('goto'begin)

S->S1S2S1.next=fall

S2.next=S.next

S.code=S1.code||S2.code

B->B1&&B2B1.true=fall

B1.false=ifB.false==fall

thennewlabel()

elseB.false

B2.true=B.true

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=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&&(c==d||e==f)

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:

整个程序

对于这些结构语句,我们可以通过一个规则用其他的

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 幼儿教育 > 育儿知识

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1