【编译原理】1-5章课后习题答案精心整理版,可直接缩印
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第一章
1.2 计算机执行用高级语言编写的程序有哪些途径?它们之间的主要区别是什么? 【解答】计算机执行用高级语言编写的程序主要有两种途径:解释和编译。
这两种途径的主要区别在于:解释方式下不生成目标代码程序,而编译方式下生成目标代码程序。
从执行速度上看,编译型的高级语言比解释型的高级语言要快,但解释方式下的人机界面比编译型好,便于程序调试。
(在解释方式下,翻译程序事先并不采用将高级语言程序全部翻译成机器代码程序,然后执行这个机器代码程序的方法,而是每读入一条源程序的语句,就将其解释(翻译)成对应其功能的机器代码语句串并执行,而所翻译的机器代码语句串在该语句执行后并不保留,最后再读入下一条源程序语句,并解释执行。
这种方法是按源程序中语句的动态执行顺序逐句解释(翻译)执行的,如果一语句处于一循环体中,则每次循环执行到该语句时,都要将其翻译成机器代码后再执行。
在编译方式下,高级语言程序的执行是分两步进行的:第一步首先将高级语言程序全部翻译成机器代码程序,第二步才是执行这个机器代码程序。
因此,编译对源程序的处理是先翻译,后执行。
)
1.3 请画出编译程序的总框图。
如果你是一个编译程序的总设计师,设计编译程序时应当考虑哪些问题? 【解答】编译程序总框图如图1-1所示。
作为一个编译程序的总设计师,首先要深刻理解被编译的源语言其语法及语义;其次,要充分掌握目标指令的功能及特点,如果目标语言是机器指令,还要搞清楚机器的硬件结构以及操作系统的功能;第三,对编译的方法及使用的软件工具也必须准确化。
总之,总设计师在设计编译程序时必须估量系统功能要求、硬件设备及软件工具等诸因素对编译程序构造的影响等。
第二章
2.1 正规式M1和M2等价是指:M1和M2所识别的语言集相等。
2.2 什么是扫描器?扫描器的功能是什么?
【解答】扫描器就是词法分析器,它接受输入的源程序,对源程序进行词法分析并识别出一个个单词符号,其输出结果是单词符号,供语法分析器使用。
通常是把词法分析器作为一个子程序,每当词法分析器需要一个单词符号时就调用这个子程序。
每次调用时,词法分析器就从输入串中识别出一个单词符号交给语法分析器。
2.3 设M=({x,y}, {a,b}, f, x, {y})为一非确定的有限自动机,其中f 定义如下: f(x,a)={x,y} f{x,b}={y} f(y,a)=Φ f{y,b}={x,y} 试构造相应的确定有限自动机M ′。
【解答】对照自动机的定义M=(S,Σ,f,So,Z),由f 的定义可知f(x,a)、f(y,b)均为多值函数,因此M 是一非确定有限自动机。
先画出NFA M 相应的状态图,如图2-2所示。
用子集法构造状态转换矩阵,如表2-1所示。
程序子程序或分程序语句表达式算符数据引用函数调用
b
将转换矩阵中的所有子集重新命名,形成表2-2所示的状态转换矩阵。
即得:M ′=({0,1,2},{a,b},f,0,{1,2}),其状态转换图如图2-3所示。
将图2-3所示的DFA M ′最小化。
首先,将M ′的状态分成终态组{1,2}与非终态组{0}。
其次,考察{1,2},由于{1,2}a={1,2}b={2}⊂{1,2},所以不再将其划分了,也即整个划分只有两组:{0}和{1,2}。
令状态1代表{1,2},即把原来到达2的弧都导向1,并删除状态2。
最后,得到如图2-4所示的化简了的DFA M ′。
2.4 正规式(ab)*a 与正规式a(ba)*是否等价?请说明理由。
【解答】正规式(ab)*a 对应的NFA 如图2-5所示,正规式a(ba)*对应的NFA 如图2-6所示。
这两个正规式最终都可得到最简DFA ,如图2-7所示。
因此,这两个正规式等价。
2.5 设有L(G)={a2n+1b2ma2p+1| n ≥0,p ≥0,m ≥1}。
(1) 给出描述该语言的正规表达式;(2) 构造识别该语言的确定有限自动机(可直接用状态图形式给出)。
【解答】该语言对应的正规表达式为a(aa)*bb(bb)*a(aa)*,正规表达式对应的NFA 如图2-8所示。
重新命名后的状态转换矩阵可化简为(也可由最小化方法得到) {0,2} {1} {3,5} {4,6} {7}按顺序重新命名为0、1、2、3、4后得到最简的DFA ,如图2-10所示。
a, b
a
a, b
a
重新命名
2.6 有语言L={w|w ∈(0,1)+,并且w 中至少有两个1,又在任何两个1之间有偶数个0},试构造接受该语言的确定有限状态自动机(DFA)。
【解答】对于语言L ,w 中至少有两个1,且任意两个1之间必须有偶数个0;也即在第一个1之前和最后一个1之后,对0的个数没有要求。
据此我们求出L 的正规式为0*1(00(00)*1)*00(00)*10*,画出与正规式对应的NFA ,
如图2-11
由图2-12可看出非终态2和4的下一状态相同,终态6和8的下一状态相同,即得到最简状态为 {0}、{1}、{2,4}、{3}、{5}、{6,8}、{7} 按顺序重新命名为0、1、2、3、4、5、6,则得到最简DFA ,如图2-13所示。
2.7
(1) 试用有限自动机的等价性证明这两个正规式是等价的;(2) 给出相应的正规文法。
【解答】(1) 正规式((a|b)*|aa)*b 对应的NFA 如图2-14所示。
用子集法将图2-14所示的NFA 确定化为DFA ,如图2-15所示。
由于对非终态的状态1、2来说,它们输入a 、b 的下一状态是一样的,故状态1和状态2可以合并,将合并后
的终态3命名为2,则得到表2-3 由此得到最简DFA ,如图2-16所示。
正规式(a|b)*b 对应的NFA 如图2-17所示。
重新命名b
用子集法将图2-17所示的NFA 确定化为如图2-18所示的状态转换矩阵。
比较图2-18与图2-15,重新命名后的转换矩阵是完全一样的,也即正规式(a|b)*b 可以同样得到化简后的DFA 如图2-16所示。
因此,两个自动机完全一样,即两个正规文法等价。
(2) 对图2-16,令A 对应状态1,B 对应状态2,则相应的正规文法G[A]为
G[A]:A →aA|bB|b
B →aA|bB|b G[A]可进一步化简为G[S]:S →aS|bS|b(非终结符B 对应的产生式与A 对应的产生式相同,故两非终结符等价,即可合并为一个产生式)。
2.8 下列程序段以B 表示循环体,A 表示初始化,I 表示增量,T 表示测试:请用正规表达式表示这个程序段可能的执行序列。
【解答】用正规表达式表示程序段可能的执行序列为A(TBI)*。
2.9 将图2-19所示的非确定有限自动机(NFA)变换成等价的确定有限自动机(DFA)。
其中,X 为初态,Y 为终态。
【解答】 用子集法将NFA 确定化,如图2-20所示。
图2-20所对应的DFA 如图2-21所示。
对图2-21的DFA 进行最小化。
首先将状态分为非终态集和终态集两部分:{0,1,2,5}和{3,4,6,7}。
由终态集可知,对于状态3、6、7,无论输入字符是a 还是b 的下一状态均为终态集,而状态4在输入字符b 的下一状态落入非终态集,故将其化为分
{0,1,2,5}, {4}, {3,6,7}
对于非终态集,在输入字符a 、b 后按其下一状态落入的状态集不同而最终划分为 {0}, {1}, {2}, {5}, {4}, {3,6,7}
按顺序重新命名为0、1、2、3、4、5,得到最简DFA 如图2-22所示。
重新命名
重新命名
2.10 有一台自动售货机,接收1分和2分硬币,出售3分钱一块的硬糖。
顾客每次向机器中投放≥3分的硬币,便可得到一块糖(只给一块并且不找钱)。
(1) 写出售货机售糖的正规表达式;(2) 构造识别上述正规式的最简DFA 。
【解答】(1) 设a=1,b=2,则售货机售糖的正规表达式为a (b|a(a|b))|b(a|b)。
(2) 画出与正规表达式a(b|a(a|b))|b(a|b)对应的NFA ,如图2-23所示。
用子集法将图2-23的NFA 确定化,如图2-24所示。
由图2-24可看出,非终态2和非终态3面对输入符号a 或b 的下一状态相同,故合并为一个状态,即最简状态{0}、{1}、{2,3}、{4}。
按顺序重新命名为0、1、2、3,则得到最简DFA ,如图2-25所示。
第三章
3.1 (1) 文法G :S →xSx|y 所识别的语言: xnyxn(n ≥0)
(2) 如果文法G 是无二义的,则它的任何句子α:最左推导和最右推导对应的语法树必定相同。
(3) 采用自上而下分析,必须 消除回溯 。
(4) 设a 、b 、c 是文法的终结符,且满足优先关系ab 和bc ,则 a ~c 都不一定成立 。
(5) 在规范归约中,用 句柄 来刻画可归约串。
(6) 若a 为终结符,则A →α·a β为 移进 项目。
(7) 若项目集Ik 含有A →α· ,则在状态k 时,仅当面临的输入符号a ∈FOLLOW(A)时,才采取“A →α· ”动作的一定是 SLR(1)文法 。
(8) 同心集合并有可能产生新的 “归约”/“归约” 冲突。
3.2 令文法G[N]为:G[N]: N →D|ND ,D →0|1|2|3|4|5|6|7|8|
(1) G[N]的语言L(G[N])是什么? (2) 给出句子0127、34和568的最左推导和最右推导。
【解答】(1) G[N]的语言L(G[N])是非负整数。
(2) 最左推导:NNDNDDNDDDDDDD0DDD01DD012D0127 NNDDD3D34
NNDNDDDDD5DD56D568 最右推导:NNDN7ND7N27ND27N127D1270127 NNDN4D434
NNDN8ND8N68D68568
3.3 已知文法G[S]为S →aSb|Sb|b ,试证明文法G[S]
为二义文法。
【解答】由文法G[S]:S →aSb|Sb|b ,对句子aabbbb 可对应如图3-1所示的两棵语法树。
因此,文法G[S]为
二义文法(对句子abbb 也可画出两棵不同语法树)。
S a S b a S b S b b a S b S b S
a S
b b
重新命名
3.4已知文法G[S]为S→SaS|ε,试证明文法G[S]为二
义文法。
【解答】由文法G[S]:S→SaS|ε,句子aa的语法树如图3-2所示。
由图3-2可知,文法G[S]为二义文法。
S
S S
a
S S
a
εεε
S
S
S a
S
S a
ε
ε
ε
(a)(b)
3.5 按指定类型,给出语言的文法。
(1) L={aibj|j>i≥0}的上下文无关文法;
(2) 字母表Σ={a,b}上的同时只有奇数个a和奇数个b的所有串的集合的正规文法;
(3) 由相同个数a和b组成句子的无二义文法。
【解答】(1) 由L={aibj|j>i≥0}知,所求该语言对应的上下文无关文法首先应有S→aSb型产生式,以保证b的个数不少于a的个数;其次,还需有S→Sb或S→b 型的产生式,用以保证b的个数多于a的个数。
因此,所求上下文无关文法G[S]为G[S]:S→aSb|Sb|b
(2) 为了构造字母表Σ={a,b}上同时只有奇数个a和奇数个b的所有串集合的正规式,画出如图3-3所示的DFA。
由图3-3可直接得到正规文法G[S]如下:
G[S]:S→aA|bB
A→aS|bC|b
B→bS|aC|a
C→bA|aB|ε
(3) 用一个非终结符A代表一个a(即有A→a),用一个非终结符B代表一个b(即有B→b);为了保证a和b的个数相同,则在出现一个a时应相应地出现一个B,出现一个b时则相应出现一个A。
假定已推导出bA,如果下一步要推导出连续两个b时,则应有bAbbAA。
也即为了保证b和A的个数一致,应有A→bAA;同理有B→aBB。
此外,为了保证递归地推出所要求的ab串,应有S→aBS和S→bAS。
由此得到无二义文法G[S]为G[S]:S→aBS|bAS|ε
A→bAA|a
B→aBB|b
3.6 有文法G[S]: S→aAcB|Bd,A→AaB|c,→bScA|b
(1) 试求句型aAaBcbbdcc和aAcbBdcc的句柄;
(2) 写出句子acabcbbdcc的最左推导过程。
【解答】(1) 分别画出对应句型aAaBcbbdcc和aAcbBdcc的语法树如图3-4的(a)、(b)所示。
A a
B b S c A
B
A c
a
S
B d
b
b S
c A
B
A c
a
S
B d c
(a)(b)
c
对树(a),直接短语有3个:AaB、b和c,而AaB 为最左直接短语(即为句柄)。
对树(b),直接短语有两个:Bd和c,而Bd为最左直接短语。
(2) 句子acabcbbdcc的最左推导如下:
SaAcBaAaBcBacaBcBacabcBacabcbScAacabcbBdcA acabcbbdcAacabcbbdcc
3.7 对于文法G[S]: S→(L)|aS|a,L→L,S|S
(1) 画出句型(S,(a))的语法树;
(2) 写出上述句型的所有短语、直接短语、句柄、素短语和最左素短语。
【解答】(1) 句型(S, (a))的语法树如图3-5所示。
(L)
S
L,S
S(L)
S
a
(2) 由图3-5可知:
短语:S、a、(a)、S,(a)、(S,(a));
直接短语:a、S;
句柄:S;
素短语:素短语可由图3-5中相邻终结符之间的优先关系求得,即:
#⋖(⋖,⋖(⋖a⋗)⋗)⋗#
因此,素短语为a 。
3.8 下述文法描述了C 语言整数变量的声明语句: G[D]: D →TL ,T →int|long|short ,L →id|L,id (1) 改造上述文法,使其接受相同的输入序列,但文法是右递归的;
(2) (2) 分别用上述文法G[D]和改造后的文法G[D ′]为输入序列int a,b,c 构造分析树。
【解答】 (1) 消除左递归后,文法G[D ′]如下: D →TL
T →int|long|short L →idL
(2)
3.9 考虑文法G[S]: S →(T) | a+S | a ,T →T,S | S
消除文法的左递归及提取公共左因子,然后对每个非终结符写出不带回溯的递归子程序。
【解答】消除文法G[S]的左递归: S →(T) | a+S | a T →ST ′
T ′→,ST ′| ε
提取公共左因子: S →(T) | aS ′ S ′→+S | ε T →ST ′
T ′→,ST ′| ε
改造后的文法已经是LL(1)文法,不带回溯的递归子程序如下:
void match (token t) {
if ( lookahead==t) lookahead=nexttoken; else error ( ); }
void S ( ) {
if ( lookahead==′a ′) match (′a ′);
else if ( lookahead==′(′) {
match (′(′); T ( );
void S ′( ) {
if ( lookahead==′+′) {
match (′+′); S ( ); } }
void T ( ) { S ( ); T ′( ); }
void T ′ ( ) {
if ( lookahead==′, ′) {
match (′, ′); S ( ); T ′ ( ); } }
3.10 已知文法G[A]: A →aABl|a ,B →Bb|d (1) 试给出与G[A]等价的LL(1)文法G[A ′]; (2) 构造G[A ′]的LL(1)分析表; (3) 给出输入串aadl#的分析过程。
【解答】 (1) 文法G[A]存在左递归和回溯,故其不是LL(1)文法。
要将G[A]改造为LL(1)文法,首先要消除文法的左递归,即将形如P →P α | β的产生式改造为 P →βP ′ P →αP ′| ε 来消除左递归。
由此,将产生式B →Bb|d 改造为 B →dB ′
B ′→bB ′| ε 其次,应通过提取公共左因子的方法来消除G[A]中的回溯,即将产生式A →aABl|a 改造为 A →aA ′
A ′→ABl | ε 最后得到改造后的文法为 G[A ′]:A →aA ′ A ′→ABl | ε
B →dB ′
B ′→bB ′| ε 求得:
FIRST(A)={a} FIRST(A ′)={a, ε}
L ,c L D T int L ,b a ,b L D
T int a L′L′,c L′ (a)(b )
FIRST(B)={d} FIRST(B′)={b, ε}
对文法开始符号A,有FOLLOW(A)={#}。
由A′→ABl得FIRST(B)\{ ε}⊂FOLLOW(A),即FOLLOW(A)={#,d};
由A′→ABl得FIRST(′l′) ⊂FOLLOW(B),即FOLLOW(B)={l};
由A→aA′得FOLLOW(A) ⊂FOLLOW(A′),即FOLLOW(A′)={#,d};
由B→dB′得FOLLOW(B) ⊂FOLLOW(B′),即FOLLOW(B′)={l}。
对A′→ABl来说,FIRST(A)∩FOLLOW(A′)={a}∩{#,d}=Φ,所以文法G′[A]为所求等价的LL(1)文法。
(2) 构造预测分析表的方法如下:
①对文法G[A′]的每个产生式A→α执行②、③步。
②对每个终结符a∈FIRST(A),把A→α加入到M[A,a]中,其中α为含有首字符a的候选式或为唯一的候选式。
③若ε∈FIRST(A),则对任何属于FOLLOW(A)的终结符b,将A→ε加入到M[A,b]中。
把所有无定义的M[A,a]标记上“出错”。
由此得到G[A′]的预测分析表,见表3-1。
(3)输入串aadl的分析过程见表3-2。
3.11 将下述文法改造为LL(1)文法:G[V]: V→N | N[E],E→V | V+E,N→i
【解答】LL(1)文法的基本条件是不含左递归和回溯(公共左因子),而文法G[V]中含有回溯,所以先消除回溯,得到文法G[V′]:G [V′]:V→NV′
V′→ε| [E]
E→VE′
E′→ε| +E
N→i
一个LL(1)文法的充要条件是:对每一个终结符A的任何两个不同产生式A→α|β有下面的条件成立:
(1) FIRST(α)∩FIRST(β)=Φ;(2) 假若βε,则有FIRST(α)∩FOLLOW(A)= Φ。
即求出G[V′]的FIRSTVT和LASTVT集如下:
FIRST(N)=FIRST(V)=FIRST(E)={i}
FIRST(V′)={[, ε}
FIRST(E′)={+, ε}
FOLLOW(V)={#}
由V′→…E]得FIRST(′)′)⊂FOLLOW(E),即FOLLOW(E)={ ]};
由V→NV′得FIRST(V′)\{ ε}⊂FOLLOW(N),即FOLLOW(N)={ [};
由E→VE′得FIRST(E′)\{ ε}⊂FOLLOW(V),即FOLLOW(V)={#,+};
由V→NV′得FOLLOW(V)⊂FOLLOW(V′),即FOLLOW(V′)={#,+};
由V→NV′,且V′→ε得FOLLOW(V)⊂FOLLOW(N),即FOLLOW(N)={[,#,+];
由E→VE′得FOLLOW(E)⊂FOLLOW(E′),即FOLLOW(E′)={ ]};
则,对V′→ε|[E]有:FIRST(ε)∩FIRST(′[′]= Φ;
对E′→ε| +E有:FIRST(ε)∩FIRST(′+′)= Φ;
对V′→ε| [E]有:FIRST(′[′)∩FOLLOW(V′)={[]∩{#,+}=Φ;
对E′→ε| +E有:FIRST(′+′)∩FOLLOW(E′)={+}∩{}}=Φ。
故文法G[V′]为LL(1)文法。
3.12 对文法G[E]: E→E+T|T,T→T*P|P,P→i
(1)构造该文法的优先关系表(不考虑语句括号#),并指出此文法是否为算符优先文法;
【解答】FIRSTVT集构造方法:
①由P→a…或P→Qa…,则a∈FIRSTVT(P)。
②若a∈FIRSTVT(Q),且P→Q…,则a∈FIRSTVT(P),也即FIRSTVT(Q)⊂FIRSTVT(P)。
由①得:由E→E+…得FIRSTVT(E)={+};
由T→T*…得FIRSTVT(T)={*};
由P→i得FIRSTVT(P)={i}。
由②得:由T→P得FIRSTVT(P)⊂FIRSTVT(T),即FIRSTVT(T)={*,i};
由E→T得FIRSTVT(T)⊂FIRSTVT(E),即FIRSTVT(T)={+,*,i}。
LASTVT集构造方法:
①由P→…a或P→…aQ, 则a∈LASTVT(P)。
②若a∈LASTVT(Q),且P→…Q,则a∈LASTVT(P),也即LASTVT(Q)⊂LASTVT(P)。
由①得:E→…+T,得LASTVT(E)={+};
T→…*P,得LASTVT(T)={*};
P→i,得LASTVT(P)={i}。
由②得:由T→P得LASTVT(P)⊂LASTVT(T),即LASTVT(T)={*,i};
由E→T得LASTVT(T)⊂LASTVT(E),即LASTVT(E)={+,*,i}。
优先关系表构造方法:
①对P→…ab…或P→…aQb…,有ab;
②对P→…aR…而b∈FIRSTVT(R),有a⋖b;
③对P→…Rb…而a∈LASTVT(R),有a⋗b。
解之无①。
由②得:E→…+T,即+⋖FIRSTVT(T),有+⋖*,+⋖i;
T→…*P,即*⋖FIRSTVT(P),有*i。
由③得:E→E+…,即LASTVT(E)⋗+,有+⋗+,*⋗+,i⋗+;
T→T*…,即LASTVT(T)⋗*,有*⋗*,i⋗*。
得到优先关系表见表3-3。
由于该文法的任何产生式的右部都不含两个相继并列的非终结符,故属算符文法,且该文法中的任何终结符对(见优先关系表)至多满足、⋖和⋗三种关系之一,因而是算符优先文法。
3.13 设有文法G[S]: S →a|b|(A),A →SdA|S
(1) 构造算符优先关系表;(2) 给出句型(SdSdS)的短语、简单短语、句柄、素短语和最左素短语; (3) 给出输入串(adb)#的分析过程。
【解答】(1) 先求文法G[S]的FIRSTVT 集和LASTVT 集: 由S →a|b|(A)得FIRSTVT(S)={a,b,(}; 由A →Sd …得FIRSTVT(A)={d},又由A →S …得FIRSTVT(S) ⊂FIRSTVT(A),即FIRSTVT(A)={d,a,b, ( }; 由S →a|b|(A)得LASTVT(S) ={a,b,)}; 由A →…dA 得LASTVT(A)={d},又由A →S 得LASTVT(S) ⊂LASTVT(A),即LASTVT(A)={d,a,b,)}。
构造优先关系表方法如下: ① 对P →…ab …或P →…aQb …,有ab ; ② 对P →…aR …而b ∈FIRSTVT(R),有a ⋖b ; ③ 对P →…Rb …而a ∈FIRSTVT(R),有a ⋗b 。
由此得到:
① 由S →(A)得();
② 由S →(A …得(⋖FIRSTVT(A),即(⋖d,(⋖a,(⋖b,(⋖(;
由A →…dA 得d ⋖FIRSTVT(A),即d ⋖d,d ⋖a,d ⋖b,d ⋖ (;
③ 由S →…A)得LASTVT(A)⋗),即d ⋗),a ⋗),b ⋗),)⋗);
由A →Sd …得LASTVT(S)⋗d ,即a ⋗d,b ⋗d,)⋗d ; 此外: 由#S#得##; 由#⋖FIRSTVT(S)得 #⋖a,# ⋖b, # ⋖ (;
由LASTVT(S)⋗#得a ⋗#, b ⋗#, )⋗#。
最后得到算符优先关系表,见表3-6。
由表3-6可以看出,任何两个终结符之间至多只满足、⋖、⋗三种优先关系之一,故G[S]为算符优先文法。
(2) 为求出句型(SdSdS)的短语、简单短语、句柄,我们先画出该句型对应的语法树,如图3-8所示。
由图3-8得到: 短语:S ,SdS ,SdSdS ,(SdSdS)
简单短语(即直接短语):S 句柄(即最左直接短语):S
由图3-9得到:
素短语:SdS
最左素短语:SdS
(3) 输入串(adb)#的分析过程见表3-7。
同时给出了(adb)#的语法树,如图3-10所示。
(A
)S S d A
S d A
S
(A )
S S d A
S d A S #<(<d <d >)>#.....
(A )S S d A S b
a
3.14 在算符优先分析法中,为什么要在找到最左素短语的尾时才返回来确定其对应的头,能否按扫描顺序先找到头后再找到对应的尾,为什么?
【解答】设句型的一般形式为N1a1N2a2…NnanNn+1。
其中,每个ai都是终结符,而Ni则是可有可无的非终结符。
对上述句型可以找出该句型中的所有素短语,每个素短语都具有如下形式:…aj-1⋖ajaj+1…ai⋗ai+1…
如果某句型得到的优先关系如下:…⋖…⋖……⋗…⋗
则当从左至右扫描到第一个“⋗”时,再由此从右至左扫描到第一个“⋖”时,它们之间(当然不包含第一个“⋖”前一个终结符和第二个“⋗”后一个终结符)即为最左素短语。
如果由左至右扫描到第一个“⋖”,可以看出这并不一定是最左素短语的开头,因为由它开始并不一定是素短语(在其内部还可能包含其他更小的素短语),所以,在算符优先分析算法中,只有先找到最左素短语的尾(即“⋗”),才返回来确定与其对应的头(即“⋖”);而不能按扫描顺序先找到头然后再找到对应的尾。
3.15 试证明在算符文法中,任何句型都不包含两个相邻的非终结符。
【解答】设文法G=(VT,VN,S, ξ),其中VT是终结符集;VN是非终结符集;ξ为产生式集合;S是开始符号。
对句型的推导长度n作如下归纳:
(1) 当n=1时,S⇒α,则存在一条产生式S→α属于ε,其中a∈(VT∪VN) *。
由于文法是算符文法,所以α中没有两个相邻非终结符,故归纳初始成立。
(2) 设n=k时结论成立,则对任何k+1步推导所产生的句型必为:Sα∪β⇒α∨β
其中,α、β∈(VT∪VN) *,U∈VN,而U→V是一条产生式。
由归纳假设,U是非终结符,设α=α1α2…αn,β=β1β2…βm,其中αi、βj ∈(VT∪VN) (1≤i≤n-1,2≤j≤m) ;但αn和βm必为位于U两侧的终结符。
设V=V1V2…Vr,由于它是算符文法的一个产生式右部候选式,因此V1V2…Vr中不会有相邻的非终结符出现。
又因为αnV1和Vrβ1中的αn、β1为终结符,也即在推导长度为k+1时所产生的句型
α1α2…αnV1V2…Vrβ1β2…βm
不会出现相邻的非终结符,故n=k+1时结论成立。
显然,在α或β为空时结论也成立。
3.16 给出文法G[S]: S→aSb∣P,P→bPc∣bQc,Q→Qa∣a
【解答】(1) 根据Chomsky的定义,对任何形如A→β的产生式,有A∈VN,β∈(VT∪VN)*时为2型文法。
而文法G[S]恰好满足这一要求,故为Chomsky 2型文法。
(2) 由文法G[S]可以看出:S推出串的形式是ai P bi(i≥0),P推出串的形式是bjQcj(j≥1),Q推出串的形式是ak(k≥1)。
因此,文法G[S]生成的语言是L={aibjakcjbi|i≥0, j≥1, k≥1}。
(3) 求出文法G[S]的FIRSTVT集和LASTVT集:
FIRSTVT(S)={a,b} FIRSTVT(P)={b} FIRSTVT(Q)={a}
LASTVT(S)={b,c} LASTVT(P)={c} LASTVT(Q)={a}
构造优先关系表如表3-8所示。
由于在优先关系中同时出现了a⋖a和a⋗a以及b⋖b和b⋗b,故文法G[S]不是算符优先文法。
(4) 消除文法G[S]的左递归:S→aSb | P
P→bPc | bQc
Q→aQ′
Q′→aQ′| ε提取公共左因子后得到文法G′[S]: S→aSb | P
P→bP′
P′→Pc | Qc
Q→aQ′
Q′→aQ′| ε
求每个非终结符的FIRST集和FOLLOW集如下:
FIRST(S)={a,b} FIRST(P)={b} FIRST(P′)={a,b} FIRST(Q)={a} FIRST(Q′)={a, ε} FOLLOW(S)={b,#} FOLLOW(P)={b,c,#} FOLLOW(P′)={b,c,#} FOLLOW(Q)={c} FOLLOW(Q′)={c} 通过检查G′[S]可以得到:
①每一个非终结符的所有候选式首符集两两不相交;
②存在形如A→ε的产生式Q′→aQ′| ε,但有:FIRST(aQ′)∩FOLLOW(Q′)={a}∩{c}=Φ
所以文法G′[S]是LL(1)文法。
3.17 LR分析器与优先关系分析器在识别句柄时的主要异同是什么?
【解答】如果S⇒aAδ且有A⇒β,则称β是句型αβδ相对于非终结符A的短语。
特别的,如果有A⇒β,则称β是句型αβδ相对于规则A→β的直接短语。
一个句型的最左直接短语称为该句型的句柄。
规范归约是关于α的一个最右推导的逆过程,因此,规范归约也称最左归约。
请注意句柄的“最左”特征。
LR分析器用规范归约的方法寻找句柄,其基本思想是:在规范归约的过程中,一方面记住已经归约的字符串,即记住“历史”;另一方面根据所用的产生式推测未来可能碰到的输入字符串,即对未来进行“展望”。
当一串貌似句柄的符号串呈现于栈顶时,则可根据历史、展望以及现实的输入符号等三方面的材料,来确定栈顶的符号串是否构成相对某一产生式的句柄。
事实上,规范归约的中心问题恰恰是如何寻找或确定一个句型的句柄。
给出了寻找句柄的不同算法也就给出了不同的规范归约方法,如LR(0)、SLR(1)、LR(1)以及LALR就是在归约方法上进行区别的。
算符优先分析不是规范归约,因为它只考虑了终结符之间的优先关系,而没有考虑非终结符之间的优先关系。
此外,算符优先分析比规范归约要快得多,因为算符优先分析跳过了所有单非产生式所对应的归约步骤。
这既是算符优先分析的优点,同时也是它的缺点,因为忽略非终结符在归约过程中的作用存在某种危险性,可能导致把本来不成句子的输入串误认为是句子,但这种缺陷容易从技术上加以弥补。
为了区别于规范归约,算符优先分析中的“句柄”被称为最左素短语。
3.18 见作业 3.19 见作业 3.20 无 3.21 见作业
3.22 请指出图3-12中的LR分析表(a)、(b)、(c)分属LR(0)、SLR(1)和LR(1)中的哪一种,并说明理由。
【解答】我们知道,LR(0)、SLR(1)和LR(1)分析表构造的主要差别是构造算法(2)。
其区别如下:
(1) 对LR(0)分析表来说,若项目A→α·属于Ik(状态),则对任何终结符a(或结束符#),置ACTION[k,a]为“用产生式A→α进行归约(A→α为第j个产生式)”,简记为“rj”。
表现在ACTION子表中,则是每个归约状态所在的行全部填满“rj”;并且,同一行的“rj”其下标j相同,而不同行的“rj”其下标j是不一样的。
(2) 对SLR(1)分析表来说,若项目A→α·属于Ik,则对任何输入符号a,仅当a∈FOLLOW(A)时置ACTION[k,a]为“用产生式A→α进行归约(A→α为第j个产生式)”,简记为“rj”。
表现在ACTION子表中,则存在某个归约状态所在的行并不全部填满rj,并且不同行的“rj”其下标j不同。
(3) 对LR(1)来说,若项目[A→α·,a]属于Ik(状态),则置ACTION[k,a]为“用产生式A→α进行归约”,简记为“rj”。
LR(1)是在SLR(1)状态(项目集)的基础上,通过状态分裂的办法(即分裂成更多的项目集),使得LR分析器的每个状态能够确切地指出当α后跟哪些终结符时才容许把α归约为A。
例如,假定[A→α·,a]属于Ik(状态),则置ACTION[k,a]栏目为rj(A→α为第j个产生式);而[A→α·,b]属于Im(状态),则同样置ACTION[m,b]栏目为rj。
表现在ACTION子表中,则在不同的行(即不同的状态)里有相同的rj存在。
因此,图3-12(a)的分析表为LR(1)分析表(在不同行有相同的r2存在);图3-12(b)为LR(0)分析表(有rj的行是每行都填满了rj且同一行rj的j相同,不同行rj的j不同);而图3-12(c)为LR(0)分析表(存在并不全部填满rj的行,且不同行rj的j不同)。
3.23 文法G(S)的产生式集为
S→(EtSeS) | (EtS) | i =E
E→+EF | F
F→*Fi | i
构造文法G的SLR(1)分析表,要求先画出相应的DFA。
【解答】将文法G拓广为文法G[S′]:(0)S′→S
(1) S→(EtSeS)
(2) S→(EtS)
(3) S→i=E
(4) E→+EF
(5) E→F
(6) F→*Fi
(7) F→i
用ε_CLOSURE 方法构造文法G[S ′]的LR(0)项目集规范族:
I0: S ′→·S I5: S → (EtS ·eS) I13: E →+·EF
S →·(EtSeS) S → (EtS ·) E →·+EF
S →·(EtS) I6: S → (EtSe ·S) E →·F
S →·i=E S →·(EtSeS) I14: E →+E ·F
I1: S ′→S · S →·(EtS) F →·*Fi
I2: S → (·EtSeS) S →·i=E F →·i
S → (·EtS) I7: S → (EtSeS ·) I 15: E →+EF ·
E →·+E
F I8: S → (EtSeS)· I16: E →F ·
E →·
F I9: S → (EtS)· I17: F →*·Fi
I3: S →(E ·tSeS) I10: S →i ·=E F →·*Fi
S →(E ·tS) I11: S →i=·E F →·i
I4: S → (Et ·SeS) E →·+EF I18: F →*F ·i
S → (Et ·S) E →·F I19: F →*Fi ·
S →·(EtSeS) I12: S →i=E · I20: F →i ·
S →·(EtS)
S →·i=E
文法G[S ′]的DFA 如图3-13所示。
构造SLR(1)分析表必须先求出所有形如“A →α·”的FOLLOW(A),即由FOLLOW 集的构造方法求得G[S ′]的FOLLOW 集如下:
(1) FOLLOW(S ′)={#};
(2) 由S →(EtSeS)得FIRST(′t ′) FOLLOW(E),即FOLLOW(E)={t};
FIRST(′e ′) FOLLOW(S),即FOLLOW(S)={e};
FIRST(′) ′) FOLLOW(S),即FOLLOW(S)={e,)};
由F →*Fi 得FIRST(′i ′) FOLLOW(F),即FOLLOW(F)={i};
由E →+EF 得FIRST(′F ′)/{ε} FOLLOW(E),即 FOLLOW(E)={t,i};
(3) 由S ′→S 得FOLLOW(S ′) FOLLOW(S),即FOLLOW(S)={e,),#};
由S →i=E 得FOLLOW(S) FOLLOW(E),即FOLLOW(E)={t,i,e,),#};
由E →F 得FOLLOW(E) FOLLOW(F),即FOLLOW(F)={t,i,e,),#}。
最后得到SLR(1)分析表,见表3-10。
)S (i i F *F i e i S *(t +E E +
E F +F F =i (S I 1:S′→S· I 0: S′→·S S→·(EtSeS) S→·(EtS) S→·i =E I 2: S→(·EtSeS) S→(·EtS) E→·+EF E→·F I 10:S→i·=E I 11: S→i =·E E→·+EF E→·F I 12:S→i =E· I 3: S→(E·tSeS) S→(E·tS) I 16:E→F· I 13: E→+·EF E→·+EF E→·F I 14: E→+E·F F→·*Fi F→·i I 17: F→*·Fi F→·*Fi F→·i I 15:E→+EF· I 20:F→i· I 18:F→*F·i I 19:F→*Fi· I 4: S→(Et·SeS) S→(Et·S) S→·(EtSeS) S→·(EtS) S→·i =E I 5: S→(EtS·eS) S→(EtS·) I 6: S→(EtSe·S) S→·(EtSeS) S→·(EtS) S→·i =E I 7:S→(EtSeS·) I 8:S→(EtSeS)·
I 9:S→(EtS)·)E
3.24 为二义文法G[T]构造一个LR分析表(详细说明构造方法)。
其中终结符“,”满足右结合性,终结符“;”满足左结合性,且“,”的优先级高于“;”的优先级。
【解答】首先将文法G[T]拓广为文法G[S]:(0) S→T
(1) T→TAT (2) T→bTe (3) T→a (4) A→,(5) A→;
下面列出LR(0)的所有项目:
1.S→·T 5.T→TA·T 9.T→bT·e 13.A→·,
2.S→T·6.T→TAT·10.T→bTe·14.A→,·
3.T→·TAT 7.T→·bTe 11.T→·a 15.A→·;
4.T→T·AT 8.T→b·Te 12.T→a·16.A→; ·
用ε_CLOSURE方法构造文法G[S]的LR(0)项目集规范族,并根据转换函数GO构造出文法G[S]的DFA,如图3-14。
已知文法G[S]为二义文法,故必然存在冲突。
逐一检查各状态,得知I8存在“移进”/“归约”冲突(因为T →TA T ·要求归约,而T →T ·AT 却要求移进)。
在此,LR(0)已不能满足要求,因为LR(0)分析表中的ACTION 子表在某归约状态下(即某一行)的所有栏目全被“rj ”占满,但由于存在“移进”/“归约”冲突,即在此状态下,有些栏目应填为“Sj ”(即归约)。
为了减少冲突,最好采用SLR(1)、LR(1)或LALR 分析表。
这里采用SLR(1)分析表。
下面,构造文法G[S]中非终结符的FIRST 集和FOLLOW 集如下: FIRST(S)=FIRST(T)={a,b}; FIRST(A)={“,”,“;”} FOLLOW(S)={#};FOLLOW(T)={“,”,“;”,e,#}; FOLLOW(A)={a,b} 因为T →TA T ·要求归约,而T →T ·AT 要求移进,即对T 要求归约而对A 要求移进,则有: FOLLOW(T)∩FIRST(A)={“,”,“;”,e,#}∩{“,”,“;”}={“,”,“;”}≠Φ 也即冲突字符为“,”和“;”。
下面分析“,”与“;”的具体情况。
因为“,”的优先级高且有右结合,故不论是“,”还是“;”,遇见“,”其后的“,”一定移进;类似地,“;”优先级低且有左结合,则无论是“,”还是“;”,遇见其后的“;”一定归约。
由此可得到SLR(1)分析表,见表3-11。
从分析表中可以看到,本应该对在状态8对应ACTION 子表中的字符集{e,“,”,“,”,#}都执行用r1归约,但“,”和“;”存在“移进”/“归约”冲突,由于“,”的优先级高且有右结合,故对应ACTOIN[8, “,”]栏改为s5,即移进;由于“;”满足左结合性,即应归约,所以ACTION[8,“,”]栏仍为r1。
注意,如果将条件改为“,”的优先级高且满足左结合,则将无法构造分析表。
这是因为“,”在遇见其后的“,”时要求归约;而“;”在遇见其后的“,”时则要求移进;这时ACTION[8,“,”]栏就无法确定是放“r1”还是放“s5”了。
3.25 文法G[T]及其SLR(1)分析表(见表3-12)如下,给出串bibi 的分析过程。
【解答】 对句子bibi ,先构造它的语法树,如图3-15所示。
bibi 的分析过程参考该语法树进行,见表3-13。
T i H b i E H
b
3.27 一个非LR(1)的文法如下:
L→MLb | a
M→ε
请给出所有“移进”/“归约”冲突的LR(1)项目集,以说明该文法确实不是LR(1)的。
【解答】
先将文法G[L]拓广为G[L′]:(0) L′→L
(1) L→MLb
(2) L→a
(3) M→ε
如果按LR(1)方法构造分析表时出现“移进”/“归约”冲突,则项目集规范族中一定包含如下形式的项目:[A→α·bβ,a] 和[A→α·,b]
即移进符号与向前搜索符号相同。
在构造LR(1)项目集族之前,我们先求出G[L′]中所有非终结符的FIRST集和
FOLLOW集:
FIRST(L′)=FIRST(L)={a, ε}
FIRST(M)={ ε}
由FOLLOW集构造方法知FOLLOW(L′)={#};
由L→…Lb 得FIRST(′b′) FOLLOW(L),即FOLLOW(L)={b};
由L→ML…得FIRST(L)\{ ε}FOLLOW(M),即FOLLOW(M)={a};
由L′→L得FOLLOW(L′) FOLLOW(L),即FOLLOW(L)={#,b}。
LR(1)闭包CLOSURE(I)构造方法如下:
(1) I的任何项目都属于CLOSURE(I)。
(2) 若项目[A→α·Bβ,a]属于CLOSURE(I),B→γ是一个产生式,对FIRST(βa)中的每个终结符b,如果[B→·γ,b]原来不在CLOSURE(I)中,则把它加进去。
(3) 重复执行步骤(2),直至CLOSURE(I)不再增大为止。
注意,b可能是从β推出的第一个符号,若β推出ε,则b就是a。
令[L′→·L,#]∈CLOSURE(I0),求得项目集如下:
I0:L′→·L,# I2:L→M·Lb,# I4:L→M·Lb,b
L→·MLb,# L→·MLb,b L→·MLb,b
L→·a,# L→·a,b L→·a,b
M→·, a M→·, a M→·, a
I1:L′→L·,# I3:L→ML·b,# I5:L→MLb·,#
如果一个项目中含有m个移进项目:
A1→α·a1β1, A2→α·a2β2, …,Am→α·amβm
同时I中含有n个归约项目:
B1→α·, B2→α·, …, Bn→α·
如果集合{a1, …,am},FOLLOW(B1), …,FOLLOW(Bn)两两相交,则必然存在“移进”/“归约”冲突。
由I0中L→·a, #和M→·,a 可知{a}∩FOLLOW(M)={a}∩{a}≠Φ(在此α=ε);
由I2中L→·a,b和M→·,a 可知{a}∩FOLLOW(M)≠Φ;
由I4中L→·a,b和M→·,a 可知{a}∩FOLLOW(M)≠Φ;
也即,I0 、I2 、I4三个项目集存在“移进”/“归约”冲突。