1、1、已知文法 G(S):SaS|bS|a(1)构造该文法的 LR(0)项目集规范族(2)构造识别该文法所产生的活前缀的 DFA。(3)构造其 SLR 分析表,并判断该文法是否是 SLR(1)文法。解题思路构造 LR(0)项目集规范族,有两种方法:一种是利用有限自动机来构造,另一种是利用函数 CLOSURE 和 GO 来构造。本题采取第 2 种方法,通过计算函数 CLOSURE 和 GO得到文法的 LR(0)项目集规范族,而 GO 函数则把 LR(0)项目集规范族连成一个识别该文法所产生的活前缀的 DFA。解答(1)将文法 G(S)拓广为 G(S):(0)SS(1)SaS(2)SbS(3)Sa构
2、造该文法的 LR(0)项目集规范族:I0=CLOSURE(S S)=S S, SaS, S bS, S aI1=GO( I0 , a)=CLOSURE(SaS , Sa)=SaS , Sa , S aS, SbS, Sa I2=GO(I0 , b)=CLOSURE(SbS )= SbS, SaS, SbS, Sa I3=GO(I0 , S)=CLOSURE(S S)= S SGO(I1, a)=CLOSURE(SaS , Sa)=I 1GO(I2, b)=CLOSURE(SbS)=I 2I4=GO(I1, S)=CLOSURE(SaS)=SaSGO(I2, a)= CLOSURE(SaS ,
3、Sa)=I 1GO(I2, b)= CLOSURE(SbS)=I 2I5=GO(I2, S)=CLOSURE(SbS)= SbS所以,项目集 I0,I 1,I 2,I 3,I 4 和 I5 构成了该文法的 LR(0)项目集规范族。(2)我们用 GO 函数把 LR(0)项目集规范族连成一个识别该文法所产生的活前缀的 DFA 如图 4.1 所示。(3)构造其 SLR 分析表。表 4.1 SLR 分析表ACTION GOTO状态 a b # S0 S1 S2 31 S1 S2 r3 42 S1 S2 53 acc4 r15 r2注意到状态 I1 存在“移进-归纳 ”冲突,计算 S 的 FOLLOW
4、集合:FOLLOW(S)=#可以采用 SLR 冲突消解法,得到表 4.1 所列的 SLR 分析表。从分析表可以看出,表中没有冲突项,所以该文法是 SLR(1)文法。2、证明 AdBd 是文法 G(S)的活前缀。说明活前缀在 LR 分析中的作用。给出串 dbdb#的LR 分析过程。G(S):(1) SAdB (2)Aa (3) A(4) Bb (5)BBdb (6)B解题思路所谓活前缀是指规范句型的一个前缀,这种前缀不句柄之后的任何符号。根据此定义,直接证明 AdBd 是文法 G(S)的活前缀。解答存在下面的规范推导:可见 AdBdb 是文法 G 的规范句型,AdBd 是该规范句型的前缀。另外,
5、在该规范句型中Bdb 是句柄,前缀是 AdBd 不含句柄 Bdb 之后的任何符号,所以 AdBd 是文法 G(S)的活前缀。在 LR 分析工作过程中的任何时候,栈里的方法符号(自栈底而上)X 1X2Xm 应该构成活前缀,把输入串的剩余部分配上之后即应成为规范句型(如果整个输入串确实构成一个句子)。因此,只要输入串的已扫描部分保持可归约成一个活前缀,那就意味着所扫描过的部分没有错误。构造文法 G 的 LR 分析表 4.2 所列。表 4.2 LR 分析表ACTION GOTOa d b # S A B0 s3 r3 1 21 acc2 s43 r24 r6 s5 r6 65 r4 r46 s7 r
6、17 s88 r5 r5串 dbdb#的 LR 分析过程如下:步骤 状态 符号 输入串0 0 # dbdb#1 02 #A dbdb#2 024 #Ad bdb#3 0245 #Adb db#4 0246 #AdB db#5 02467 #AdBd b#6 024678 #AdBdb #9 0246 #AdB #10 01 #S # acc3、根据程序设计语言的一般要求,为定义条件语句的二义文法 G(S)构造 SLR(1)分析表,要求 写出步骤和必要的说明。G(S): SiSeS|iS|a解答将文法 G(S)拓广为 G(S):(0) S S(1) SiSeS(2) SiS(3) Sa构造此文法
7、的 LR(0)项目集规范族,识别该文法所产生的活前缀的 DFA 如图 4.2 所示。注意到状态 I4 存在“移进归约”冲突,计算 FOLLOW 集合:FOLLOW(S)e,#当 LR 分析器处于状态 4 时,如果下一输入符号是 “” ,则按 SiS 归约;如果下一输入符号是“e ”,则既可以按 SiS 归约,也可以执行移入。根据程序设计语言的要求,条件语句的 else 子句应当和最近的没有 else 子句的 if 语句匹配,根据这一要求,我们规定:当 LR 分析器处于状态 4 时,如果下一输入符号是“” ,则按 SiS 归约;如果下一输入符号是“e”,则执行移入。构造 SLR(1)分析表如表
8、4.3 所列。表 4.3 SLR(1)分析表ACTION GOTOi e a # S0 s2 s3 11 acc2 s2 s3 43 r3 r34 s5 r25 s2 s3 66 r1 r14、设下列文法生成变量的类型说明:D id LL , id L | : TT integer | real构造一个翻译模式,把每个标识符的类型存入符号表。解题思路这是一个对说明语句进行语义分析的题目,不需要产生代码,但要求把每个标识符的类型填入符号表中。解答对 D,L,T 设置综合属性 type。过程 addtype(id,type)用来把标识符 id及其类型 type 填入到符号表中。翻译模式如下:D i
9、d L addtype(id.entry,L.type)L ,id L1 addtype(id.entry,L1.type);L.type:=L1.type;L : T L.type:=T.typeT integer T.type:=intergerT real T.type:=real5、文法 G 的产生式如下:S (L) | aL L , S | S(1)试写出一个语法制导定义,它输出配对括号个数;(2)写一个翻译方案,打印每个 a 的嵌套深度。如(a),a),打印 2,1。解题思路本题包括两部分,第 1 部分要求写语法制导定义,第 2 部分要求写翻译方案。语法制导定义(或属性文法)可以看
10、作是关于语言翻译的高级规范说明,其中隐去实现细节,使用户从明确说明翻译顺序的工作中解脱出来。翻译方案(也称翻译模式)给出了使用语义规则进行计算的次序,把某些实现细节表示出来。读者从下面解答中可体会两者的区别。解答(1) 为 S、L 引入属性 h,代表配对括号个数。语法制导定义如下:产生式 语义规则S (L) S.h:=L.h+1S a S.h:=0L L1 , S L.h:=L1.h+S.hL S L.h:=S.hSS print(S.h)(2)为 S、L 引入 d,代表 a 的嵌套深度。翻译方案如下:SS.d:=0;SS (L.d:=S.d+1;L)S aprint(S.d);L L1.d:
11、=L.d;L1S.d:=L.d;SL S.d:=L.dS6、下列文法对整型常数和实型常数施用 加法运算符“+”生成表达式;当两个整型数相加时,结果仍为整型数,否则,结果为实型数:E E+T | T T num.num | num(1)试给出确定每个子表达式结果类型的属性文法。(2)扩充(1)的属性文法,使之把表达式翻译成后缀形式,同时也能确定结果的类型。应该注意使用一元运算符 inttoreal 把整型数转换成实型数,以便使后缀形如加法运算符的两个操作数具有相同的类型。解题思路确定每个子表达式结果类型的属性文法是比较容易定义的。关键是如何扩充此属性文法,使之把表达式翻译成后缀形式。我们将不在
12、name 或 num.num向 T 归约的时候输出该运算对象,而是把运算对象的输出放在 T 或 ET 向 E 归约的时候。这是因为考虑输出类型转换算符 inttoreal 的动作可能在 ET 归约的时候进行,如果这时两个运算对象都在前面 name 或 num.num 向 T 归约的时候已输出,需要为第 1 个运算对象输出类型转换算符时就已经为时太晚。还要注意的是,在 ET 向 E 归约时,该加法运算的第 1 个运算对象已经输出。所以 EET 的语义规则不需要有输出 E 运算对象的动作。解答(1)为文法符号 E 和 T 配以综合属性 type,用来表示它们的类型。类型值分别用 int 和 rea
13、l 来表示。确定每个子表达式结果类型的属性文法如下:产生式 语义规则EE1T T.type:=if E1.type=int and T.type=int then int else realET E.type:=T.typeTnum.num T.type:=realTnum T.type:=int(2)下面属性文法将表达式的后缀表示打印输出,其中 lexeme 属性表示单词的拼写。产生式 语义规则EE1T if E1.type=real and T.type=int thenbeginE.type:=real;print(T.lexeme);print(inttoreal);endelse if E1.type=int and T.type=real thenbeginE.type:=real;print(inttoreal);print(T.lexeme);endelse beginE.type:=E1.type;print(T.lexeme);endprint(+);ET E.type:=T.type;print(T.lexeme);Tnum.num T.type:=real;T.lexeme:=num1.lexeme|“.”|num2.lexemeTnum T.type:=int;T.lexeme:=num.lexeme;