编译原理LL(1)分析法学习总结
刚上完编译原理,下午1,2节都有点打瞌睡,重新学习整理一下
学习内容
1、first集
2、follow集
3、 LL(1)文法
内容
找first集
1:这是书上first集合的定义:
很显然这么定义是看不懂的也不知道 这句话在干什么
那就直接来看FIRST集的分析方法 :
对于文法中的符号X∈VN∪VT,其FIRST(X)集合可反复应用下列规则计算,直到其FIRST(X)集合不再增大为止:
1)若 X∈VT,则FIRST(X)={X}。
2)若X∈VN,且具有形如X→aα的产生式(a∈VT),或具有形如X→ε的产生式,则把a或ε加进FIRST(X)。//把X能推出的第一个终结符加入FIRST(X)。
-
设G中有形如X→Y1…Yk的产生式,其中X,Y1…Yk∈VN,且Y1…Yi-1均能=>*ε(1≤i≤k),则FIRST(Y1)-{ε},…, FIRST(Yi-1)-{ε},FIRST(Yi)都包含在FIRST(X)中。// Yi推导不出ε,所以Yi+1不在FIRST(X)中。
-
若对一切1≤i≤k,均有ε∈FIRST(Yi),则将ε符号加进FIRST(X)。//若X=>*ε,则将ε加入FIRST(X)。
看完是不是觉得还是思路还是不是很会:
那我们就举个例子
例子
首先先说一下默认规则 :
起始符E,其余大写字母为非终结符;
小写字母为终结符,#为ε;
产生式: E->TE, 其中这个是关于A的产生式,A为左部(左边部分),BC为右部 (右边部分)
Vt是终结符
Vn是非终结符
题目
随便找个文法G[S]:
S-> B|bC
A->#|b
B->aB|#
其实first集就是该符号的所有产生式右部第一个是终结符
求解
S的产生式有两个:S->AB,S->bC
1、S->bC,明显右部第一个终结符是b, 那关于这个产生式的终结符就是b 了
这个时候把b放进来 first(S)={b}
2、然后是S->AB,这时右部的第一个是A,非终结符,所以不成立。这时你就要再把A的产生式引进来(因为A有关于他的产生式)。
关于A的产生式为:A->#,A->b,分别代入S->AB的产生式得:S->B(应该是S->#B,但是#可以省略) 和S->bB.
看第二个S->bB ,马上就可以知道遇到的第一个终结符是b,
这个时候first(S)={b}
3、然后看第一个S->B,这个时候B不是终结符,所以不成立,这时就要把B的产生式导进来。
变成S->aB ,S->#,
然后上面两个式子,分别第一个终结符为a,和 #
则这个时候first(S)={b, a , #}
然后按照这种方式把所有非终结字符first集全求出来
找follow集
就是该符号后面跟着的第一个终结符
follow集定义:
follow(A)={a | S=*>…Aa…,a∈Vt}…
若 S=*>…AB…,则follow(A)=first(B)…
若S=*>…A ,因为这个时候A属于S,因此这个时候应该看得是S后面的东西也就是follow(S)∈follow(A)…
若S=*>…AB,这个时候first(B)存在空的情况,而这个时候first的空集不能出现在follow集中,因此还应该看S后面的东西,因此这个等于follow(A)=(first(B)-{#})∪follow(S)…
follow集的分析方法
-
对于文法的开始符号S,置#于FOLLOW(S) 中;
-
若A→αBβ是一个产生式,则把FIRST(β)-{e}加至FOLLOW(B)中;若β=>*e (即eÎFIRST(β)),则把FOLLOW(A)加至FOLLOW(B)中。//若B有可能是最后一个符号,则把
FOLLOW(A)加至FOLLOW(B)中,否则把FIRST(β)- {e}加至FOLLOW(B)中。
反复使用上述规则,直到所求FOLLOW集不再增大为止。
例子
题目
注意:FIRST集从产生式左侧推导,而FOLLOW集从产生式右侧推导。例如求A的FIRST集,要先从产生式左侧找到A,然后根据产生式右侧的信息求出A的FIRST集;求A的FOLLOW集时,要先从产生式右侧找到A,然后根据A右侧的符号信息求出A的FOLLOW集。
S->xAy
A->aBb
求解
FOLLOW(A):
因为要找A后面的跟着的第一个终结符,所以应该直接看谁能产生A,得
S->xAy,
此时A后面跟着的终结符是y,因此follow(A)={y}
求FOLLOW(B)
则先找谁能产生B:
B的产生式:
A->aBb,此时,要把first(b)(因为是B后面遇到第一个终结符,也就是first(b),也就是b的first集合)
但是如果这个时候b等于#,那么B的follow集应该取得是b(假设b可能为空的情况)后面的东西,那么问题来了,b后面的东西怎么来呢?
S->xAy,先看下A的产生式,(因为永远是从S出发,因此当产生式出现B的时候一定是这样的流程)
然后代入A的产生
S->xaBby
可以看到出现B的时候是这样的,所以这个时候就应该是把b忽视,直接看y,那么这个时候是不是很熟悉?没错就是跟上面求FOLLOW(A)的一样做法,也就是follow(A)∈follow(B)
这个时候可以总结一个规律
当b为#的时候,follow(B) 就应该看谁产生生它的那个非终结符的follow(),在这里就是因为A->xBy,因此看follow(A)