0%

编译原理——第4章(2)

题型总结

1. LL(1)文法分析

该类题型主要包括左递归消除、回溯消除、构建预测分析表、还原递归分析过程、还原预测分析过程等。

例-1(课后习题4-3改)设文法G[S]G[S]
SAS\rightarrow A
ABAiBA\rightarrow B|AiB
BCB+CB\rightarrow C|B+C
C)A(C\rightarrow )A*|(

(1) 将文法G[S]G[S]改写为LL(1)文法。

分析:改写LL(1)文法第一步——消除左递归。

首先发现AAiBA\rightarrow AiB存在左递归,于是将第2条规则改写为:
ABAA\rightarrow BA'
AiBAεA'\rightarrow iBA'|\varepsilon(注意这里不能没有ε\varepsilon!)

然后第3条规则显然也有左递归,继续改写:
BCBB\rightarrow CB'
B+CBεB'\rightarrow +CB'|\varepsilon

至此左递归消除完成。文法变为:
SAS\rightarrow A
ABAA\rightarrow BA'
AiBAεA'\rightarrow iBA'|\varepsilon
BCBB\rightarrow CB'
B+CBεB'\rightarrow +CB'|\varepsilon
C)A(C\rightarrow )A*|(

下面查看这其中是否有回溯。对于左部相同的两条规则:

  • AiBAεA'\rightarrow iBA'|\varepsilon,其SELECT\operatorname{SELECT}集分别为{i}\{i\}{,\{*, $ }\},无交集(注意这里的$是由FOLLOW\operatorname{FOLLOW}集产生的,如果一个非终结符后面可以不跟任何终结符,那么就需要将符号串的结束符$包含到SELECT\operatorname{SELECT}集中。)
  • B+CBεB'\rightarrow +CB'|\varepsilon,其SELECT\operatorname{SELECT}集分别为{+}\{+\}{i,,\{i,*, $ }\},无交集。
  • C)A(C\rightarrow )A*|(,其SELECT\operatorname{SELECT}集分别为{)}\{)\}{(}\{(\},无交集。

注意这里的FOLLOW\operatorname{FOLLOW}集计算过程。盲目去找很容易漏掉几个。找FOLLOW\operatorname{FOLLOW}集不应该只是去找某一个非终结符的FOLLOW\operatorname{FOLLOW}集,而是应该从头到尾将所有非终结符的FOLLOW\operatorname{FOLLOW}集全部找到,因为一些非终结符的FOLLOW\operatorname{FOLLOW}集可以直接加载其他非终结符的FOLLOW\operatorname{FOLLOW}集之中。
对于上例中的文法。我们来使用规范化的方式寻找FOLLOW\operatorname{FOLLOW}集:

  • 对于SS,其为开始符号,后面本来就可以不跟什么符号,因此$ FOLLOW(S)\in\operatorname{FOLLOW}(S)。又有SAS\rightarrow A,因此AAFOLLOW\operatorname{FOLLOW}集中一定包含SSFOLLOW\operatorname{FOLLOW}集中的所有元素。注意此时我们并不确定SSFOLLOW\operatorname{FOLLOW}集中是否只有一个$。
FOLLOW集
SS {\{ $ }\}
AA {\{ $ }\}
  • 对于文法ABAA\rightarrow BA',有FOLLOW(A)FOLLOW(A)\operatorname{FOLLOW}(A)\subseteq\operatorname{FOLLOW}(A')FIRST(A)FOLLOW(B)\operatorname{FIRST}(A')\subseteq\operatorname{FOLLOW}(B),其中FIRST(A)={i,ε}\operatorname{FIRST}(A')=\{i,\varepsilon\}
FOLLOW集
SS {\{ $ }\}
AA {\{ $ }\}
AA' {\{ $ }\}
BB {i,\{i, $ }\}
  • 对于文法BCBB\rightarrow CB',有FIRST(B)FOLLOW(C)\operatorname{FIRST}(B')\subseteq\operatorname{FOLLOW}(C),其中FIRST(B)={+,ε}\operatorname{FIRST}(B')=\{+,\varepsilon\},且有FOLLOW(B)FOLLOW(B)\operatorname{FOLLOW}(B)\subseteq\operatorname{FOLLOW}(B')FOLLOW(B)FOLLOW(C)\operatorname{FOLLOW}(B')\in\operatorname{FOLLOW}(C)
FOLLOW集
SS {\{ $ }\}
AA {\{ $ }\}
AA' {\{ $ }\}
BB {i,\{i, $ }\}
BB' {i,\{i, $ }\}
CC {+,\{+, $ }\}
  • 对于文法C)A(C\rightarrow )A*|(,有FOLLOW(A)*\in\operatorname{FOLLOW}(A)
FOLLOW集
SS {\{ $ }\}
AA {,\{*, $ }\}
AA' {\{ $ }\}
BB {i,\{i, $ }\}
BB' {i,\{i, $ }\}
CC {+,\{+, $ }\}
  • 扩充被AA影响的FOLLOW\operatorname{FOLLOW}集:
FOLLOW集
SS {\{ $ }\}
AA {,\{*, $ }\}
AA' {,\{*, $ }\}
BB {i,\{i, $ }\}
BB' {i,\{i, $ }\}
CC {+,\{+, $ }\}
  • 对于文法AiBAεA'\rightarrow iBA'|\varepsilon,有FOLLOW(A)FOLLOW(B)\operatorname{FOLLOW}(A')\in\operatorname{FOLLOW}(B)
FOLLOW集
SS {\{ $ }\}
AA {,\{*, $ }\}
AA' {,\{*, $ }\}
BB {i,,\{i,*, $ }\}
BB' {i,,\{i,*, $ }\}
CC {i,,+,\{i,*,+, $ }\}

故不存在回溯问题。

最终修改完成的文法为:
SAS\rightarrow A
ABAA\rightarrow BA'
AiBAεA'\rightarrow iBA'|\varepsilon
BCBB\rightarrow CB'
B+CBεB'\rightarrow +CB'|\varepsilon
C)A(C\rightarrow )A*|(

(2) 求经过改写后的每个非终结符的FIRST\operatorname{FIRST}集和FOLLOW\operatorname{FOLLOW}集,以及每一条规则的SELECT\operatorname{SELECT}集。

解:FIRST\operatorname{FIRST}集和FOLLOW\operatorname{FOLLOW}集如下:

FIRST集 FOLLOW集
SS {),(}\{),(\} {\{ $ }\}
AA {),(}\{),(\} {,\{*, $ }\}
AA' {i,ε}\{i,\varepsilon\} {,\{*, $ }\}
BB {),(}\{),(\} {i,,\{i,*, $ }\}
BB' {+,ε}\{+,\varepsilon\} {i,,\{i,*, $ }\}
CC {),(}\{),(\} {i,,+,\{i,*,+, $ }\}

SELECT\operatorname{SELECT}集如下:

SELECT集
SAS\rightarrow A {),(}\{),(\}
ABAA\rightarrow BA' {),(}\{),(\}
AiBAA'\rightarrow iBA' {i}\{i\}
AεA'\rightarrow\varepsilon {,\{*, $ }\}
BCBB\rightarrow CB' {),(}\{),(\}
B+CBB'\rightarrow +CB' {+}\{+\}
BεB'\rightarrow \varepsilon {i,,\{i,*, $ }\}
C)AC\rightarrow )A* {)}\{)\}
C(C\rightarrow ( {(}\{(\}

(3) 写出该文法的递归下降分析程序的AA'函数、BB'函数和CC函数:

解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
A'(){
if(sym == 'i'){
scanner(); // 输入符号串读位置前移一位
B();
A'();
}else if(sym != '*' && sym != '$')
error();
else
scanner();
}

B'(){
if(sym == '+'){
C();
B'();
}else if(sym != 'i' && sym != '*' && sym != '$')
error();
}

C(){
if(sym == '('){
scanner();
A();
scanner();
if(sym != '*')
error();
}else if(sym != ')')
error();
scanner();
}

递归下降分析函数需要保证:在任何一个非终结符识别函数刚刚开始执行时,读位置始终指向该非终结符应该识别的第一个字符。因此调整指针的操作应该在上一级函数中实现,这也是AA函数和CC函数最后一句scanner()的含义。

(4) 画出预测分析图。

解:可以根据SELECT\operatorname{SELECT}集直接画出预测分析图:

( ) * + i $
SS SAS\rightarrow A SAS\rightarrow A
AA ABAA\rightarrow BA' ABAA\rightarrow BA'
AA' AεA'\rightarrow\varepsilon AiBAA'\rightarrow iBA' AεA'\rightarrow\varepsilon
BB BCBB\rightarrow CB' BCBB\rightarrow CB'
BB' BεB'\rightarrow \varepsilon B+CBB'\rightarrow +CB' BεB'\rightarrow \varepsilon BεB'\rightarrow \varepsilon
CC C(C\rightarrow ( C)AC\rightarrow )A*

(5) 使用上面的预测分析图分析输入串)(i(+(*

解:画图——

分析栈 输入串 所用规则
$ )(i(+(*$
$A )(i(+(*$ SAS\rightarrow A
$A'B )(i(+(*$ ABAA\rightarrow BA'
$A'B'C )(i(+(*$ BCBB\rightarrow CB'
$A'B'*A) )(i(+(*$ C)AC\rightarrow )A*
$A'B'*A'B (i(+(*$ ABAA\rightarrow BA'
$A'B'*A'B'C (i(+(*$ BCBB\rightarrow CB'
$A'B'*A'B'( (i(+(*$ C(C\rightarrow (
$A'B'*A'B' i(+(*$
$A'B'*A' i(+(*$ BεB'\rightarrow \varepsilon
$A'B'*A'Bi i(+(*$ AiBAA'\rightarrow iBA'
$A'B'*A'B (+(*$
$A'B'*A'B'C (+(*$ BCBB\rightarrow CB'
$A'B'*A'B'( (+(*$ C(C\rightarrow (
$A'B'*A'B' +(*$
$A'B'*A'B'C+ +(*$ B+CBB'\rightarrow +CB'
$A'B'*A'B'C (*$
$A'B'*A'B'( (*$ C(C\rightarrow (
$A'B'*A'B' *$
$A'B'*A' *$ BεB'\rightarrow \varepsilon
$A'B'* *$ AεA'\rightarrow\varepsilon
$A'B' $
$A' $ BεB'\rightarrow \varepsilon
$ $ AεA'\rightarrow\varepsilon

成功。

上面的分析流程:如果栈中最上面一个是非终结符,下一步就要根据输入串最前面的字符选择候选式。如果栈中最上面一个是终结符,就和输入串最前面的字符比较,如果相等就相消,如果不等就输出错误。

2. OG文法分析

OG文法没有讲完,后面的素短语等内容没有要求,因此只需要掌握两个集合的求解以及算符优先表的构建即可。

例-2:对于例-1中的文法,求所有非终结符的FIRSTVT\operatorname{FIRSTVT}集和LASTVT\operatorname{LASTVT}集,并画出算符优先表。

SAS\rightarrow A
ABAiBA\rightarrow B|AiB
BCB+CB\rightarrow C|B+C
C)A(C\rightarrow )A*|(

分析:按照构建两个集合的方法求出所有非终结符的FIRSTVT\operatorname{FIRSTVT}集和LASTVT\operatorname{LASTVT}集:

FIRSTVT LASTVT
SS {i,(,),+}\{i,(,),+\} {i,,(,+}\{i,*,(,+\}
AA {i,(,),+}\{i,(,),+\} {i,,(,+}\{i,*,(,+\}
BB {(,),+}\{(,),+\} {,(,+}\{*,(,+\}
CC {(,)}\{(,)\} {,(}\{*,(\}

构建算符优先表:

i ( ) + * $
i \gtrdot \lessdot \lessdot \lessdot \gtrdot \gtrdot
( \gtrdot \gtrdot \gtrdot \gtrdot
) ,\gtrdot,\lessdot \lessdot \lessdot \lessdot \eqcirc
+ \gtrdot \lessdot \lessdot \gtrdot \gtrdot \gtrdot
* \gtrdot \gtrdot \gtrdot
$ \lessdot \lessdot \lessdot \lessdot \eqcirc

3. LR(0)文法

该部分包含LR(0)文法的分析表、活前缀DFA的构建。

例-3:画出例-1中文法的规范句型活前缀DFA以及LR(0)分析表,如果有冲突说明冲突来源,没有冲突说明理由。

SAS\rightarrow A
ABAiBA\rightarrow B|AiB
BCB+CB\rightarrow C|B+C
C)A(C\rightarrow )A*|(

分析:首先拓广,加一条规则:
SSS'\rightarrow S
SAS\rightarrow A
ABAiBA\rightarrow B|AiB
BCB+CB\rightarrow C|B+C
C)A(C\rightarrow )A*|(

然后递归地构建DFA:

  • 求出CLOSURE(SS)={SS,SA,AB,AAiB,BC,BB+C,C)A,C(}\operatorname{CLOSURE}(S'\rightarrow\cdot S)=\{S'\rightarrow\cdot S,S\rightarrow\cdot A,A\rightarrow\cdot B,A\rightarrow\cdot AiB,B\rightarrow\cdot C,B\rightarrow\cdot B+C,C\rightarrow\cdot)A*,C\rightarrow\cdot(\},作为项目集I0I_0
  • 求出GOTO(I0,S)=CLOSURE({SS})={SS}\operatorname{GOTO}(I_0,S)=\operatorname{CLOSURE}(\{S'\rightarrow S\cdot\})=\{S'\rightarrow S\cdot\},作为项目集I1I_1,其没有GOTO\operatorname{GOTO}函数。
  • 求出GOTO(I0,A)=CLOSURE({SA,AAiB})={SA,AAiB}\operatorname{GOTO}(I_0,A)=\operatorname{CLOSURE}(\{S\rightarrow A\cdot,A\rightarrow A\cdot iB\})=\{S\rightarrow A\cdot,A\rightarrow A\cdot iB\},作为项目集I2I_2
  • 求出GOTO(I0,B)=CLOSURE{AB,BB+C}={AB,BB+C}\operatorname{GOTO}(I_0,B)=\operatorname{CLOSURE}\{A\rightarrow B\cdot,B\rightarrow B\cdot +C\}=\{A\rightarrow B\cdot,B\rightarrow B\cdot +C\},作为项目集I3I_3
  • 求出GOTO(I0,C)=CLOSURE{BC}={BC}\operatorname{GOTO}(I_0,C)=\operatorname{CLOSURE}\{B\rightarrow C\cdot\}=\{B\rightarrow C\cdot\},作为项目集I4I_4,其没有GOTO\operatorname{GOTO}函数。
  • 求出GOTO(I0,")")=CLOSURE{C)A}={C)A,AB,AAiB,BC,BB+C,C)A,C(}\operatorname{GOTO}(I_0,")")=\operatorname{CLOSURE}\{C\rightarrow )\cdot A*\}=\{C\rightarrow )\cdot A*,A\rightarrow\cdot B,A\rightarrow\cdot AiB,B\rightarrow\cdot C,B\rightarrow\cdot B+C,C\rightarrow\cdot)A*,C\rightarrow\cdot(\},作为项目集I5I_5
  • 求出GOTO(I0,"(")=CLOSURE{C(}={C(}\operatorname{GOTO}(I_0,"(")=\operatorname{CLOSURE}\{C\rightarrow (\cdot\}=\{C\rightarrow (\cdot\},作为项目集I6I_6,其没有GOTO\operatorname{GOTO}函数。
  • 求出GOTO(I2,i)=CLOSURE({AAiB})={AAiB}\operatorname{GOTO}(I_2,i)=\operatorname{CLOSURE}(\{A\rightarrow Ai\cdot B\})=\{A\rightarrow Ai\cdot B\},作为项目集I7I_7
  • 求出GOTO(I3,+)=CLOSURE({BB+C})={BB+C,C)A,C(}\operatorname{GOTO}(I_3,+)=\operatorname{CLOSURE}(\{B\rightarrow B+\cdot C\})=\{B\rightarrow B+\cdot C,C\rightarrow\cdot)A*,C\rightarrow\cdot(\},作为项目集I8I_8
  • 求出GOTO(I5,A)=CLOSURE({C)A,AAiB})={C)A,AAiB}\operatorname{GOTO}(I_5, A)=\operatorname{CLOSURE}(\{C\rightarrow)A\cdot*,A\rightarrow A\cdot iB\})=\{C\rightarrow)A\cdot*,A\rightarrow A\cdot iB\},作为项目集I9I_9
  • 求出GOTO(I5,B)=CLOSURE({AB,BB+C})=I3\operatorname{GOTO}(I_5, B)=\operatorname{CLOSURE}(\{A\rightarrow B\cdot, B\rightarrow B\cdot+C\})=I_3
  • 求出GOTO(I5,C)=CLOSURE{BC}=I4\operatorname{GOTO}(I_5, C)=\operatorname{CLOSURE}\{B\rightarrow C\cdot\}=I_4
  • 求出GOTO(I5,"(")=CLOSURE({C(})=I6\operatorname{GOTO}(I_5, "(")=\operatorname{CLOSURE}(\{C\rightarrow (\cdot\})=I_6
  • 求出GOTO(I5,")")=CLOSURE({C)A})=I5\operatorname{GOTO}(I_5,")")=\operatorname{CLOSURE}(\{C\rightarrow )\cdot A*\})=I_5
  • 求出GOTO(I7,B)=CLOSURE({AAiB})={AAiB}\operatorname{GOTO}(I_7, B)=\operatorname{CLOSURE}(\{A\rightarrow AiB\cdot\})=\{A\rightarrow AiB\cdot\},作为项目集I10I_{10},其没有GOTO\operatorname{GOTO}函数。
  • 求出GOTO(I8,C)=CLOSURE({BB+C})={BB+C}\operatorname{GOTO}(I_8, C)=\operatorname{CLOSURE}(\{B\rightarrow B+C\cdot\})=\{B\rightarrow B+C\cdot\},作为项目集I11I_{11},其没有GOTO\operatorname{GOTO}函数。
  • 求出GOTO(I8,")")=CLOSURE({C)A})=I5\operatorname{GOTO}(I_8, ")")=\operatorname{CLOSURE}(\{C\rightarrow)\cdot A*\})=I_5
  • 求出GOTO(I8,"(")=CLOSURE{C(}=I6\operatorname{GOTO}(I_8,"(")=\operatorname{CLOSURE}\{C\rightarrow (\cdot\}=I_6
  • 求出GOTO(I9,i)=CLOSURE({AAiB})={AAiB,BC,BB+C,C)A,C(}\operatorname{GOTO}(I_9, i)=\operatorname{CLOSURE}(\{A\rightarrow Ai\cdot B\})=\{A\rightarrow Ai\cdot B,B\rightarrow\cdot C,B\rightarrow\cdot B+C,C\rightarrow\cdot)A*,C\rightarrow\cdot(\},作为项目集I12I_{12}
  • 求出GOTO(I9,)=CLOSURE({C)A})={C)A}\operatorname{GOTO}(I_9, *)=\operatorname{CLOSURE}(\{C\rightarrow)A*\cdot\})=\{C\rightarrow)A*\cdot\},作为项目集I13I_{13},其没有GOTO\operatorname{GOTO}函数。
  • 求出GOTO(I12,B)={AAiB,BB+C}\operatorname{GOTO}(I_{12},B)=\{A\rightarrow AiB\cdot,B\rightarrow B\cdot+C\},作为项目集I14I_{14},有GOTO(I14,+)=I8\operatorname{GOTO}(I_{14},+)=I_8
  • 求出GOTO(I12,C)={BC}=I4\operatorname{GOTO}(I_{12},C)=\{B\rightarrow C\cdot\}=I_4
  • 求出GOTO(I12,")")=I5\operatorname{GOTO}(I_{12},")")=I_5
  • 求出GOTO(I12,"(")=I6\operatorname{GOTO}(I_{12},"(")=I_6

由上面的推导画出DFA(图略,太复杂)
根据上面的推导画出分析表如下:

可以看见其中有多处移进-归约冲突。

4. SLR(1)文法

例-4:使用SLR(1)文法尝试改写上一题的分析表,说明改写后是否存在冲突。如果不存在,试分析符号串)(i(+(*

分析:上图中一共有3处移进-规约冲突,下面逐一进行处理:

  • 对于状态2移入符号ii,状态2的两个LR(0)项目中只有{AAiB}\{A\rightarrow A\cdot iB\}可以接受符号ii,而另一个状态{SA}\{S\rightarrow A\cdot\}无法接收符号iiFOLLOW\operatorname{FOLLOW}集中不包含ii)。因此此处冲突可以解决。
  • 对于状态3移入符号++,状态3的两个LR(0)项目中只有{BB+C}\{B\rightarrow B\cdot +C\}可以接受,而另一个无法接受。因此此处状态可以解决。
  • 对于状态14移入符号++,状态14的两个LR(0)项目中只有{BB+C}\{B\rightarrow B\cdot +C\}可以接受,而另一个无法接受。因此此处状态可以解决。

至此冲突已经完全解决,可以进行分析了。分析过程如下: