《编译原理答案陈意云高等教育出版社.pdf》由会员分享,可在线阅读,更多相关《编译原理答案陈意云高等教育出版社.pdf(144页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、编译原理习题课编译原理习题课编译原理习题课编译原理习题课(1)(1)2.32.3 叙述由下列正规式描述的语言0(0|1)*0(|0)1*)*(0|1)*0(0|1)(0|1)0*10*10*10*(00|11)*(01|10)(00|11)*(01|10)(00|11)*)*2.3(2.3(续续续续)一种表述(这里说的01串包括)0(0|1)*0 以0开头和结尾的长度至少是2的01串(|0)1*)*所有的01串(0|1)*0(0|1)(0|1)倒数第三位是0的01串0*10*10*10*含有3个1的01串(00|11)*(01|10)(00|11)*(01|10)(00|11)*)*含有偶数个
2、0和偶数个1的01串(习题集P1/1.1)2.42.4 为下列语言写正规定义包含5个元音的所有字母串,其中每个元音只出现一次 且按序排列按词典序排列的所有字母串C语言的注释相邻数字都不相同的所有数字串最多只有一处相邻数字相同的所有数字串由偶数个0和偶数个1组成的所有01串由偶数个0和奇数个1组成的所有01串不含字串011的01串2.4(2.4(续续续续)一种答案包含5个元音的所有字母串,其中每个元音只出现一次 且按序排列5个元音a,e,i,o,u 不含5个元音的任意字符:B-DF-HJ-NP-TV-Zb-df-hj-np-tv-z,记为*(a|A)*(e|E)*(i|I)*(o|O)*(u|U
3、)*按词典序排列的所有字母串A*a*B*b*Z*z*C语言的注释不含/,*的任意字符记为不含*/的任意字符串:(*+/*)*/*(*+/*)*/2.4(2.4(续续续续)一种答案(续)相邻数字都不相同的所有数字串123031357106678035 123 0 313571 0 6678 0 35 3 1 357 1 答案见习题集P2/1.32.4(2.4(续续续续)一种答案(续)最多只有一处相邻数字相同的所有数字串与上题类似 1230313571006678035 123 0 313571 00 6678 0 35 3 1 357 1 answer-double_0|double_1|dou
4、ble_9 其中double_i表示相邻的数字是idouble_0-0?(no_00)*no_000(no_00)*no_0?|00 no_0-2.4(2.4(续续续续)一种答案(续)最多只有一处相邻数字相同的所有数字串(续)double_i-i?(no_ii)*no_iii(no_ii)*no_i?|ii no_i-(0|no_0_i0)(no_0_i0)*(no_0_i?)|no_0_i no_0_i-no_0-(i-2)_i-no_0-(i+1)-比如i=5 double_5-5?(no_55)*no_555(no_55)*no_5?|55 no_5 -0|no_0_50)(no_0_5
5、0)*(no_0_5?)|no_0_5 no_0_5-1|no_0-1_51)(no_0-1_51)*(no_0-1_5?)|no_0-1_5 no_0-1_5-2|no_0-2_52)(no_0-2_52)*(no_0-2_5?)|no_0-2_5 no_0-2_5-3|no_0-3_53)(no_0-3_53)*(no_0-3_5?)|no_0-3_5 no_0-3_5-4|no_0-54)(no_0-54)*(no_0-5?)|no_0-5 no_0-5-2.4(2.4(续续续续)一种答案(续)由偶数个0和偶数个1组成的所有01串习题集P2/1.2由偶数个0和奇数个1组成的所有01串习题
6、集P2/1.2even_0_even_100|11*(01|10)(00|11)*(01|10)(00|11)*)*even_0_even_1=(00|11)*(01|10)(00|11)*(01|10)(00|11)*)*e v e n _ 0 _ o d d _ 1 1 e v e n _ 0 _ e v e n _ 1|0(0 0|1 1)*(0 1|1 0)e v e n _ 0 _ e v e n _ 1 对于偶数个0 和奇数个1 构成的串,其第一个字符可能是0 或1。(1)如果是1,那么剩下的部分一定是偶数个0 和偶数个1 (2)如果是0,那么经过若干个0 0 或1 1,一定会出现
7、一个0 1 或1 0,才能保证0 的个数是偶数,1 的个数是奇数.若串还没有结束,剩余部分一定是偶数个0 和偶数个1。这样,正确的正规定义是:e v e n _ 0 _ o d d _ 1 1 e v e n _ 0 _ e v e n _ 1|0(0 0|1 1)*(0 1|1 0)e v e n _ 0 _ e v e n _ 12.4(2.4(续续续续)一种答案(续)不含字串011的01串当出现0后,1只能单独出现1*(0+1)*0*2.72.7 用算法2.4为下列正规式构造NFA,并给出 处理ababbab的状态转换序列(a|b)*(a*|b*)*(|a)b*)*(a|b)*abb(a
8、|b)*2.7(2.7(续续续续)(|a)b*)*ababbab:s-4-0-1-5-6-7-8-4-0-1-5-6-7-6-7-8-4-0-1-5-6-7-8-f01a234567b58sfstart2.112.11 可以通过正规式的最简DFA同构来证明正 规式等价。证明下列正规式等价(a|b)*(a*|b*)*(|a)b*)*2.11(2.11(续续续续)NFA-DFA1)-closure(s)=s,4,f,0,2,3,5,6,8=A2)-closure(move(A,a)=-closure(1)=1,5,6,8,4,f,0,2,3=B3)-closure(move(A,b)=-closu
9、re(7)=7,6,8,4,f,0,2,3,5=C4)-closure(move(B,a)=-closure(1)=B5)-closure(move(B,b)=-closure(7)=C6)-closure(move(C,a)=-closure(1)=B7)-closure(move(C,b)=-closure(7)=Cbab abstartCBAa2.11(2.11(续续续续)DFA-最简DFA1)划分为接受状态集合F=A,B,C和非接受状态S-F=2)由于S-F为空集,只考虑F:对于A,输入a,转换为B,输入b,转换为C对于B,输入a,转换为B,输入b,转换为C对于C,输入a,转换为B,输
10、入b,转换为C因此F不需进一步划分sstartab2.132.13 构造表示0,1个数都是偶数的01字符串的 DFA习题集P3/1.42.142.14 能被5整除的二进制数习题集P4/1.5谢谢!谢谢!谢谢!谢谢!编译原理习题课编译原理习题课编译原理习题课编译原理习题课(2)(2)3.13.1 考虑文法 S-(L)|a L-L,S|S(a)建立句子(a,(a,a)和(a,(a,a),(a,a)的分 析树(b)为(a)的两个句子构造最左推导(c)为(a)的两个句子构造最右推导(d)这个文法产生的语言是什么3.1(3.1(续续续续)-(a,(a,aa,(a,a)S=(L)=(L,S)=(S,S)=
11、(a,S)=(a,(L)=(a,(L,S)=(a,(S,S)=(a,(a,S)=(a,(a,a)S(L )L ,SSa(L )L ,SSaaS=(L)=(L,S)=(L,(L)=(L,(L,S)=(L,(L,a)=(L,(S,a)=(L,(a,a)=(S,(a,a)=(a,(a,a)3.1(3.1(续续续续)-(a,(a,a),(a,aa,(a,a),(a,a)S(L )L ,SSaS=(L)=(L,S)=(S,S)=(a,S)=(a,(L)=(a,(L,S)=(a,(S,S)=(a,(L),S)=(a,(L,S),S)=(a,(S,S),S)=(a,(a,S),S)=(a,(a,a),S)=
12、(a,(a,a),(L)=(a,(a,a),(L,S)=(a,(a,a),(S,S)=(a,(a,a),(a,S)=(a,(a,a),(a,a)(L )L ,S(L )L ,SSaa(L )L ,SSaaSS=(L)=(L,S)=(L,(L)=(L,(L,S)=(L,(L,(L)=(L,(L,(L,S)=(L,(L,(L,a)=(L,(L,(S,a)=(L,(L,(a,a)=(L,(S,(a,a)=(L,(L),(a,a)=(L,(L,S),(a,a)=(L,(L,a),(a,a)=(L,(S,a),(a,a)=(L,(a,a),(a,a)=(S,(a,a),(a,a)=(a,(a,a),(a
13、,a)3.1(3.1(续续续续)描述的语言:括号匹配的串,串中的各项由”,”隔开,项可以是括号匹配的子串或a3.23.2 考虑文法 S-aSbS|bSaS|(a)为句子abab构造两个不同的最左推导,以说明此文法二义(b)为abab构造对应的最右推导(c)为abab构造对应的分析树(d)这个文法产生的语言是什么3.2(3.2(续续续续)(1)S=aSbS=abS=abaSbS=ababS=abab(2)S=aSbS=abSaSbS=abaSbS=ababS=abab S=aSbS=aSb=abSaSb=abSab=abab(2)Sa S b Sa S b SSa S b Sb S a S(1)
14、(2)描述的语言是a,b数目相等的串3.43.4 文法 R-R|R|RR|R*|(R)|a|b 产生字母表(a,b)上所有不含的正规式 该文法是二义的(a)证明该文法产生字母表a,b上的所有正 规式(b)为该文法写一个等价的非二义文法。(c)按照上面的两个文法构造ab|b*a的分析 树3.4(3.4(续续续续)证明该文法产生字母表a,b上的所有正规式 证明:1)该文法产生的串是字母表a,b上的正规式 R-a和R-b产生a,b,而a,b是a,b上的符号,因此是正规式。若R1,R2产生正规式,则:R-R1R2产生正规式 R-R1|R2产生正规式|R-R1*产生正规式*R-(R1)产生正规式()2)
15、字母表a,b上的所有正规式都可由此文法产生 字母表a,b上的任一正规式(其中,为正规式)必为以下形式之一:,可由R-RR产生|,可由R-R|R产生*,可由R-R*产生(),可由R-(R)产生 a,可由R-a产生 b,可由R-b产生 因而,该文法产生字母表a,b上的所有正规式3.4(3.4(续续续续)该文法没有体现运算符|、*、()、并置的优 先级,因而是二义的。R=R|R=a|R=a|R*=a|b*R=R*=R|R*=a|R*=a|b*E-E|T|T T-TF|F F-F*|(E)|a|bE=E|T=E|F=E|F*=E|b*=T|b*=F|b*=a|b*3.4(3.4(续续续续)-ab|ba
16、b|b*a*a 二义的 非二义的RR|RR RabR RaR *bRR RaR *R|RbR RbaEE|TT FTT FFabFF *ba3.53.5 下面的条件语句文法stmt-if expr then stmt|matched_stmtmatched_stmt-if expr then matched_stmt else stmt|other 试图消除悬空else的二义性。请证明此文法仍 是二义的。3.5(3.5(续续续续)由于matched_stmt不能保证then和else的配对,因而存在 二义性 句型if expr then if expr then matched_stmt el
17、se if expr then matched_stmt else stmt存在两个不同的最左推导 期望的是:if expr then if expr then matched_stmt else if expr then matched_stmt else stmt3.5(3.5(续续续续)一种推导,和期望的不一样 stmt=matched_stmt=if expr then matched_stmt else stmt=if expr then if expr then matched_stmt else stmt else stmt=if expr then if expr then m
18、atched_stmt else if expr then stmt else stmt=if expr then if expr then matched_stmt else if expr then matched_stmt else stmt if expr then if expr then matched_stmt else if expr then matched_stmt else stmt3.5(3.5(续续续续)另一种推导 stmt=if expr then stmt=if expr then matched_stmt=if expr then if expr then ma
19、tched_stmt else stmt=if expr then if expr then matched_stmt else matched_stmt=if expr then if expr then matched_stmt else if expr then matched_stmt else stmt if expr then if expr then matched_stmt else if expr then matched_stmt else stmt3.8(a)3.8(a)消除3.1的左递归3.8(a)(3.8(a)(续续续续)S-(L)|a L-L,S|S 只有直接左递归
20、 S-(L)|a L-SL L-,SL|3.103.10 构造下面文法的LL(1)分析表 D-TL T-int|real L-idR R-,idR|3.10(3.10(续续续续)先计算FIRST和FOLLOW FIRST(D)=FIRST(T)=int,real FIRST(L)=id FIRST(R)=,FOLLOW(D)=FOLLOW(L)=$FOLLOW(T)=id FOLLOW(R)=$3.10(3.10(续续续续)intrealid,$DD-TLD-TLTT-intT-realLL-idRRR-,idRR-3.113.11 下面文法是否LL(1)文法?说明理由 S-AB|PQx A-
21、xy B-bc P-dP|Q-aQ|3.11(3.11(续续续续)不是LL(1)文法 LL(1)文法:对于产生式A-|*(1)()()(2)()()FIRSTFIRSTFIRSTFOLLOW 若,那么 本题中,FIRST(AB)=x,FIRST(PQx)=d,a,x 不满足条件(1)3.153.15(a)用3.1的文法构造(a,(a,a)的最右推导,说出每个右句型的句柄(b)给出对应(a)的最右推导的移进-归约分 析器的步骤(c)对照(b)的移进-归约,给出自下而上构 造分析树的步骤。3.15(3.15(续续续续)(a)(b)(a)(b)S=(L)=(L,S)=(L,(L)=(L,(L,S)=
22、(L,(L,a)=(L,(S,a)=(L,(a,a)=(S,(a,a)=(a,(a,a)栈输入动作$(a,(a,a)$移进$(a,(a,a)$移进$(a,(a,a)$归约:S-a$(S(a,a)$归约:L-S$(L,(a,a)$移进$(L,(a,a)$移进$(L,(a,a)$移进$(L,(a,a)$归约:S-a3.15(3.15(续续续续)(a)(b)(a)(b)续上表续上表续上表续上表S=(L)=(L,S)=(L,(L)=(L,(L,S)=(L,(L,a)=(L,(S,a)=(L,(a,a)=(S,(a,a)=(a,(a,a)栈输入动作$(L,(S,a)$归约:L-S$(L,(L,a)$移进
23、$(L,(L,a)$移进$(L,(L,a)$归约:S-a$(L,(L,S)$归约:L-L,S$(L,(L)$移进$(L,(L)$归约:S-(L)$(L,S)$归约:L-L,S3.15(3.15(续续续续)(a)(b)(a)(b)续上表续上表续上表续上表S=(L)=(L,S)=(L,(L)=(L,(L,S)=(L,(L,a)=(L,(S,a)=(L,(a,a)=(S,(a,a)=(a,(a,a)栈输入动作$(L)$移进$(L)$归约:S-(L)$S$接受3.15(3.15(续续续续)(c)(c)栈输入动作$(a,(a,a)$移进$(a,(a,a)$移进$(a,(a,a)$归约:S-a$(S(a,
24、a)$归约:L-S$(L,(a,a)$移进$(L,(a,a)$移进$(L,(a,a)$移进$(L,(a,a)$归约:S-a(a ,(a ,a )$SLS3.15(3.15(续续续续)(c)(c)栈输入动作$(L,(S,a)$归约:L-S$(L,(L,a)$移进$(L,(L,a)$移进$(L,(L,a)$归约:S-a$(L,(L,S)$归约:L-L,S$(L,(L)$移进$(L,(L)$归约:S-(L)$(L,S)$归约:L-L,S(a ,(a ,a )$SLSLSLSL3.15(3.15(续续续续)(c)(c)(a ,(a ,a )$SLSLSLSL栈输入动作$(L)$移进$(L)$归约:S-
25、(L)$S$接受S谢谢!谢谢!谢谢!谢谢!编译原理习题课编译原理习题课编译原理习题课编译原理习题课(3)(3)3.8(a)3.8(a)(a)消除3.1的左递归(b)在(a)的基础上构造LL(1)分析表3.8(a)(3.8(a)(续续续续)S-(L)|a L-L,S|S 只有直接左递归 S-(L)|a L-SL L-,SL|3.8(b)(3.8(b)(续续续续)S-(L)|a L-SL L-,SL|FIRST(S)=(,a FIRST(L)=FIRST(S)=(,a FIRST(L)=,FOLLOW(S)=(FIRST(L)-)+FOLLOW(L)+FOLLOW(L)+$=,),$FOLLOW(
26、L)=)FOLLOW(L)=FOLLOW(L)=),$3.8(b)(3.8(b)(续续续续)(),a$SS-(L)S-aLL-SLL-SLLL-L-,SLL-3.163.16 给出接收文法 S-(L)|a L-L,S|S 的LR(0)活前缀的DFA;并且在此基础上构 造SLR(1)分析表.3.16(3.16(续续续续)拓展文法:(1)S-S(2)S-(L)(3)S-a(4)L-L,S(5)L-S 初态:I0=closureS-S=I0S-SS-(L)S-a3.16(3.16(续续续续)Goto(I0,S)=Goto(I0,()=Goto(I0,a)=I1S-S I3S-aI2S-(L)L-L,
27、S L-SS-(L)S-a3.16(3.16(续续续续)Goto(I2,L)=Goto(I2,S)=Goto(I2,()=I2 Goto(I2,a)=I3I4S-(L )L-L ,SI5L-S 3.16(3.16(续续续续)Goto(I4,)=Goto(I4,)=I7L-L,SS-(L)S-aI6S-(L)3.16(3.16(续续续续)Goto(I6,S)=Goto(I6,()=I2 Goto(I6,a)=I3I8L-L,S 3.16(3.16(续续续续)I8L-L,S I0S-SS-(L)S-aI1S-S I2S-(L)L-L,S L-SS-(L)S-aI3S-aI4S-(L )L-L ,S
28、I6S-(L)S(aLSa(,I7L-L,SS-(L)S-aS(aI5L-S 3.16(3.16(续续续续)SLR(1)分析表构造1)若AaI,且goto(I,a)=J,则 actionI,a=sJ2)若A I,则actionI,b=r A,bFollow(A)3)若SS I,则actionI,$=acc4)若goto(I,B)=K,则GOTOI,B=K5)其它为空白/error3.16(3.16(续续续续)状态actiongoto()a,$SL0s2s311s2s3acc2143r3r3r34s5s65r5r56r2r2r27s2s378r4r43.16(3.16(续续续续)S-(L)|a
29、L-L,S|S FOLLOW(S)=$+FOLLOW(L)=$,),FOLLOW(L)=),3.233.23 证明下面文法不是SLR(1)文法 S-X X-Ma|bMc|dc|bda M-d3.23(3.23(续续续续)S-X X-Ma|bMc|dc|bda M-d 存在移进-规约冲突 如句子dc,当d进栈后,面临c,此时项目 X-d c要求移进,而c在FOLLOW(M)中,因此项目M-d 要求规约3.263.26 一个非LR(1)的文法如下:L-MLb|a M-给出所有有移进-规约冲突的规范LR(1)项目 集3.26(3.26(续续续续)拓广文法:L-L L-MLb|a M-I0I0L-L,
30、$L-MLb,$L-a,$M-,$/a3.26(3.26(续续续续)I0L-L,$L-MLb,$L-a,$M-,aI1 L-L,$LI2L-M Lb,$L-MLb,bL-a,bM-,aMI3 L-a,$aI4L-M L b,$LI5L-M Lb,bL-MLb,bL-a,bM-,aMI6L-a,baI7L-M L b,$bI8L-ML b,baLMI9L-ML b,bb3.26(3.26(续续续续)I0,I2,I5 面临a时存在移进-规约冲突3.303.30 下面哪个不是LR(1)文法?对非LR(1)文法 给出所有冲突的LR(1)项目集S-aAc A-Abb|bS-aAc A-bAb|b3.30
31、(3.30(续续续续)第二个不是LR(1)文法 第二个文法在句子的正中心按A-b规约,而只向后看一位是无法判断是否到达句子 的中心位置的 存在冲突的项目集:S-aAc,$A-bAb,cA-b,cA-bAb,cA-bAb,bA-b,bAA-bAb,cA-b,cA-bAb,bA-b,bbA-bAb,bA-b,bA-bAb,bA-b,bbbb谢谢!谢谢!谢谢!谢谢!编译原理习题课编译原理习题课编译原理习题课编译原理习题课(4)(4)6.16.1 使用Pascal的作用域规则,确定下面程序中用于名字a,b 的每个出现的声明。程序输出整数1,2,3,4program a(input output);pr
32、ocedure b(u,v,x,y:integer);var a:record a,b:integer end;b:record b,a:integer end;begin with a do begin a:=u;b:=v end;with b do begin a:=x;b:=y end;writeln(a.a,a.b,b.a,b.b)end;begin b(1,2,3,4)end.6.1(6.1(续续续续)with a arecord a:=u aa.a b:=v ba.b with b brecord a:=x ab.a b:=y bb.b6.26.2 考虑下面的C程序 main()c
33、har*cp1,*cp2;cp1=“12345”;cp2=“abcdefghij”;strcpy(cp1,cp2);printf(“cp1=%s n cp2=%s n”,cp1,cp2);该程序经以前的某些C编译器编译后,运行结果为:cp1=abcdefghij cp2=ghij 试分析为什么cp2被修改6.2(6.2(续续续续)C语言中,字符串会添加0作为串的结束符,因此,串”12345”存储为”123450”,而串”123450abc0”打印出 来的只有12345 常量区连续分配 因而本题中”12345”和”abcdefghij”存储为 1 2 3 4 5 0 a b c d e f g
34、h i j 0 cp1 cp2 拷贝后结果为 a b c d e f g h i j 0 f g h i j 0 cp1 cp2 现代编译器编译通过,执行时会出错。(GCC:段错误/VC 非法访问)6.36.3 一个C程序如下:typedef struct _a char c1;long I;char c2;double f;a;typedef struct _b char c1;char c2;long l;double f;b;main()printf(“Size of double,long,char=%d,%d,%dn”,sizeof(double),sizeof(long),size
35、of(char);printf(“Size of a,b=%d,%dn”,sizeof(a),sizeof(b);该程序在SPARC/Solaris工作站上运行结果如下:Size of double,long,char=8,4,1 Size of a,b=24,16 试分析为什么6.3(6.3(续续续续)数据对齐:为了寻址方便 A:char OXXX long OOOO char OXXX XXXX double OOOO OOOO B:char O char OXX long OOOO double OOOO OOOO 可以用gcc S命令查看编译后的汇 编码 VC下可以在debug模式下,
36、菜单栏 View-Debug Windows中 Dissassenbly查看编译后的汇编码 GCC:(GNU)3.2.2(Red Hat Linux 3.2.2-5)结果为20,166.3(6.3(续续续续)#include static struct _a char c1;long i;char c2;double f;a =A,1,B,1.0;VC6下,Debug模式Memory窗口查看 GCC:(GNU)3.2.2 20030222(Red Hat Linux 3.2.2-5)|A|1|B|1.0|6.46.4 下面给出一个C程序及其在X86/Linux下的编译结 果,根据所生成的汇编程
37、序来解释程序中4个变量 的存储分配、作用域、生成期和置初始值方式的 区别 static long aa=10;short bb=20;func()static long cc=30;short dd=40;生成的汇编代码:6.4(6.4(续续续续).file static.c“.version“01.01”gcc2_compiled:.data.align 4.type aa,object.size aa,4aa:.long 10.globl bb.align 2.type bb,object.size bb,2bb:.value 20.align 4.type cc.2,object.siz
38、e cc.2,4cc.2:.long 30.text.align 4.globl func.type func,functionfunc:pushl%ebpmovl%esp,%ebpsubl$4,%espmovw$40,-2(%ebp).L1:leaveret.Lfe1:.size func,.Lfe1-func.ident GCC:(GNU)egcs-2.91.66 19990314/Linux(egcs-1.1.2 release)”6.4(6.4(续续续续).file static.c“.version“01.01”gcc2_compiled:.data.align 4.type aa,
39、object.size aa,4aa:-aa分配在静态数据区,作 用域为本文件,生存期为整个程序.long 10 aa静态置初值.globl bb -bb分配在静态数据区,作 用域为全局,可以被其他文件引用,生存期为整个程序.align 2.type bb,object.size bb,2bb:.value 20 bb静态置初值.align 4.type cc.2,object.size cc.2,4cc.2:-cc分配在静态数据区,作用域为本文件,生存期为整个程序。源程序中在函数内部,为防止 重名,需要重命名为cc.2.long 30 cc静态置初值.text.align 4.globl f
40、unc.type func,functionfunc:pushl%ebpmovl%esp,%ebpsubl$4,%espmovw$40,-2(%ebp)-dd分配在栈上,生存期为 func调用期,动态置初值.L1:leaveret.Lfe1:.size func,.Lfe1-func.ident GCC:(GNU)egcs-2.91.66 19990314/Linux(egcs-1.1.2 release)”6.56.5 假定使用:(a)值调用;(b)引用调用;(c)值-结果调用;(d)换名 调用。下面程序的结果分别是什么?program main(input,output);var a,b:
41、integer;procedure p(x,y,z:integer);begin y:=y+1;z:=z+x;end;begin a:=2;b:=3;p(a+b,a,a);print a;end.6.5(6.5(续续续续)值调用 x:=5;y:=2;z:=2;y:=y+1;z:=z+x;对形参的调用不改变实参的值,结果a 为2 引用调用 t:=a+b;a=a+1;a=a+t;结果a为8 值-结果调用 t:=a+b;x:=t;y:=a;z:=a y:=y+1;z:=z+x;t:=x;a:=y;a:=z;结果为7 换名调用 a:=a+1;a:=a+(a+b);结果为96.66.6 一个C程序如下:
42、func(i1,i2,i3)long i1,i2,i3;long j1,j2,j3;printf(“Address of i1 i2 i3=%o,%o,%on”,&i1,&i2,&i3);printf(“Address of j1 j2 j3=%o,%o,%on”,&j1,&j2,&j3);main()long i1,i2,i3;func(i1,i2,i3);该程序在X86/Linux上运行结果为:Address of i1,i2,i3=27777775460,27777775464,27777775470 Address of j1,j2,j3=27777775444,27777775440
43、,27777775434 从结果看func的3个形参地址逐渐升高,而3个局部变量地址逐渐降低。试说明为什么6.6(6.6(续续续续)C语言中,实参从右向左进栈,所以func(i1,i2,i3)按i3,i2,i1的顺序进栈 而j1,j2,j3按声明的顺序分配6.76.7 下面的C程序中,printf的调用仅含格式控制 串,运行时输出3个参数,分析之 main()printf(“%d%d%dn”);6.7(6.7(续续续续)C语言不做实参和形参个数类型是否一致的 检查 printf函数根据第一个参数格式控制列 表,到栈中取参数 本题中虽然只传了格式控制列表,但是 printf函数分析格式控制列表,
44、认为程序员 还传了3个整型数,因此继续去栈中取3个 参数,并输出之。所以得到了三个不可预知值得整数。6.86.8 下面给出一个C程序及其在X86/Linux下的编译结果。从结果看,func的四个局部变量 i1,j1,f1,e1的地址间隔和他们的类型一致,而形参i,j,f,e的地址间隔和他们的类 型不一致,试分析原因 func(i,j,f,e)short i,j;float f,e;short i1,j1;float f1,e1;printf(“Address of i,j,f,e=%o,%o,%o,%on”,&i,&j,&f,&e);printf(“Address of i1,j1,f1,e1
45、=%o,%o,%o,%on”,&i1,&j1,&f1,&e1);printf(“Address of short,int,long,float,double=%d,%d,%d,%d,%dn”,sizeof(short),sizeof(int),sizeof(long),sizeof(float),sizeof(double);main()short i,j;float f,e;func(i,j,f,e);运行结果:Address of i,j,f,e=35777772536,35777772542,35777772544,35777772554 Address of i1,j1,f1,e1=3
46、5777772426,35777772426,35777772424,35777772420,35777772414 Size of short,int,long,float,double=2,4,4,4,86.8(6.8(续续续续)C语言为了不保证实参和形参类型一致,因 此为了尽可能保证得到正确结果,编译器 在整型和实型做实参时,将他们提升为long 和double传递。但是函数内部取参数时,仍按照原来的类 型去取6.8(6.8(续续续续)main传参数时,提升数据类型func取参数时,按原来的数据类 型i:short-int4字节j:short-int4字节f:long-double8字节
47、e:long-double8字节i:short 2字节j:short 2字节f:long 4字节e:long 4字节6.96.9 一个C程序 func(c,l)char c;long l;func(c,l);在x86/Linux上编译生成的汇编代码如下,请说明char和long在参数传递和存储分配上 的区别6.9(6.9(续续续续).file parameter.c“.version“01.01”gcc2_compiled.:.text.align 4.globl func.type func,functionfunc:pushl%ebp-将老的基址 指针压栈movl%esp,%ebp-将当
48、前栈顶指针作为基址subl$4,%esp-分配空间movl 8(%ebp),%eaxmovb%al,-1(%ebp)movl 12(%ebp),%eaxpushl%eaxmovsbl-1(%ebp),%eax pushl%eaxcall funcaddl$8,%esp.L1:leave ret.Lfe1:.size func,.Lfe1-func.ident GCC:(GNU)egcs-2.91.66 19990314/Linux(egcs-1.1.2 release)”6.9(6.9(续续续续)Some AT&T ASM Syntax)Some AT&T ASM Syntax 寄存器:8个3
49、2-bit寄存器%eax,%ebx,%ecx,%edx,%edi,%esi,%ebp,%esp;操作符 源 目的-1(%ebp):基址:%ebp,偏移:-1 加在指令后的符号表示操作数的长度:b(byte,8-bit)w(word,16-bits)l(long,32-bits)movsbl:movs:符号扩展指令 movsbl意味着movs(from)byte(to)long;movbw意味着movs(from)byte(to)word;movswl意味着movs(from)word(to)long。More:plz google“AT&T ASM”6.9(6.9(续续续续)movl 8(%e
50、bp),%eax-取cmovb%al,-1(%ebp)-取其字节值,存入分配的 存储单元movl 12(%ebp),%eax-取lpushl%eax-l压栈movsbl-1(%ebp),%eax-取c,并转换成longpushl%eax-c压栈call func-调用funcaddl$8,%esp-恢复压栈前状态6.106.10 从例6.5可以看到,C程序执行时只用到了控 制链,不需要使用访问链.为什么Parscal程序 执行时需要使用访问链,而C程序不需要?6.10(6.10(续续续续)PASCAL允许过程嵌套,执行时,可以访问 非全局且非局部的变量,所以需要访问链 帮助确定数据所在活动记录