自頂向下分析法就是從文法的開始符號出發,不斷建立直接推導,試圖構造一個最左推導序列,最終由它推導出與輸入符號串完全匹配(相同)的句子。
從語法樹的角度看,自頂向下分析法就是以開始符號爲根節點,試圖向下構造一棵語法樹,其端末結符號串與輸入符號串相同。
能使用自頂向下分析技術的文法正是LL(1)文法.
LL(1)文法
LL(1)的含義:第1個L表明自頂向下分析是從左向右掃描輸入串,第2個L表明分析過程中將用最左到推倒,1表明只需向右看一個符號便可決定如何推倒即選擇哪個產生式(規則)進行推導,類似也可以有LL(k)文法,也就是需要向前查看k個符號才能確定選用哪個產生式。
若文法G[S]爲
S->AB
S->bC
A->ε
A->b
B->ε
B->aD
C->AD
C->b
D->aS
D->c
判斷別步驟
1.求出能推出ε的非終結符
非終結符 | S | A | B | C | D |
---|---|---|---|---|---|
初值 | - | - | - | - | - |
第一次掃描 | - | y | y | - | n |
第二次掃描 | y | y | y | n | n |
2.求first集,非終結符第一個的終結符集合
非終結符 | 中間集 | 最終集 |
---|---|---|
S | first(A)-{ε} U first(B) -{ε} U {b} U {ε} | {ε, b,a} |
A | {ε, b} | {ε, b} |
B | {ε, a} | {ε, a} |
C | first(A)-{ε} U first(D) U {b} | {a, b,c} |
D | {a,c} | {a,c} |
3.求follow集,非終結符跟着的第一個的終結符集合
(1) 對於文法的開始符號 S,置 # 到 FOLLOW(S) 中;
(2)若 A -> αBaβ 是一個產生式,a 爲終結符,則把 a加至 FOLLOW(B) 中;
(3)若 A -> αBβ 是一個產生式,則把 FIRST(β) - {ε} 加至 FOLLOW(B) 中;
(4)若 A -> αB 是一個產生式,或 A -> αBβ 是一個產生式,而 β =*> ε, 則把 FOLLOW(A) 加至FOLLOW(B) 中
非終結符 | 規則 | 中間集 | 最終集 |
---|---|---|---|
S | (1),(4 D->aS) | {#} U follow(D) | {#} |
A | (3,4 S->AB), (3 C->AD) | first(B)-{ε} U follow(S) U first(D) | {a,#,c} |
B | (4 S->AB) | follow(S) | {#} |
C | (4 S->bC) | follow(S) | {#} |
D | (4 B->aD),(4 C->AD) | follow(B) U follow© | {#} |
4.求select集,每個式子對應的終結符
產生式 | 中間集 | 最終集 |
---|---|---|
S->AB | fisrt(AB) - {ε} U follow(S) | {a,b,#} |
S-bC | first(bC) | {b} |
A->ε | fisrt(ε) - {ε} U follow(A) | {a,#,c} |
A->b | fisrt(b) | {b} |
B->ε | fisrt(ε) - {ε} U follow(B) | {#} |
B->aD | fisrt(aD) | {a} |
C->AD | fisrt(AD) - {ε} | {a,b,c} |
C->b | fisrt(b) | {b} |
D->aS | fisrt(aS) | {a} |
D->c | fisrt© | {c} |
LL(1)文法的判別,從上表格最終集中得出
select(S->AB) ∩ select(S->bC) = {b} 不爲空,當終結符爲S時,講入符號爲b時,不知道選用哪個式子
select(A->ε) ∩ select(A->b) = {}爲空
select(B->ε) ∩ select(B->aD)= {}爲空
select(C->AD) ∩ select(C->b)= {b}不爲空,同上
select(D->aS) ∩ select(D->c)= {}爲空
從非LL(1)文法到LL(1)文法的等價轉換
由LL(1)文法定義可知,若方法中有直接或間接左遞歸或者有左公共因子則肯定不是LL(1)文法,因而我們高潮消除文法中的左遞歸,撮左公共因子進行等價轉換。
問題1:左遞歸問題
若採用自頂向下的語法分析,應消除文法中存在的左遞歸。
因爲左遞歸的存在,有可能使推導不能結束,分析陷入循環狀態。 例如:
A → Aβ (A∈VN , β∈VT*) 直接左遞歸
A → Bβ B->Aα (A,B∈VN , α,β∈VT*) 間接左遞歸
左遞歸還比較好理解,例如:我需要匹配的字符串是 bsd 就需要從左端 b 開始是被,推導時,先用 A -> Aa 推導 AAa,此時不符合條件,但因爲還有非終結符,不能結束,而是繼續推導。此時就會陷入死循環。
- 消除直接左遞歸
P→Pα1 / Pα2 /…/ Pαn / β1 / β2 /…/βm
其中,αi(I=1,2,…,n)都不爲ε,而每個βj(j=1,2,…,m)都不以P開頭,將上述規則改寫爲如下形式即可消除P的直接左遞歸:
P→β1 P’ / β2 P’ /…/βm P’
P’→α1P’ / α2 P’ /…/ αn P’ /ε
例:
S->Sa
S->b
可以改寫爲
S->bS’
S’->aS’|ε
- 消除間接左遞歸
消除間接左遞歸的方法是,把間接左遞歸文法改寫爲直接左遞歸文法,然後用消除直接左遞歸的方法改寫文法。
消除左遞歸算法:
(1) 把文法G的所有非終結符按任一順序排列,例如,A1,A2,…,An。
(2) for (i=1;i<=n;i++){
for (j=1;j<=i-1;j++){
把形如Ai→Ajγ的產生式改寫成Ai→δ1γ /δ2γ /…/δkγ
其中Aj→δ1 /δ2 /…/δk是關於的Aj全部規則;
消除Ai規則中的直接左遞歸;
}
(3) 化簡由(2)所得到的文法,即去掉多餘的規則。
例:
A->Ba
A->aB
B->Ac
B->d
首先,令非終結符的排序爲A,B。對於A,不存在直接左遞歸。把A代入到B中的相關規則中得
B->Bbc
B->d|aBc
B存在直接左遞歸。在消除了B的直接左遞歸後,得到整個文法爲:
B->(aBc|d)B’
B->bcB’|ε
最終得:
A->Ba
A->aB
B->(aBc|d)B’
B->bcB’|ε
問題2:左公共因子問題
若採用自頂向下的語法分析,應消除文法中存在的左公因子。
因爲左公因子的存在,使式子select存在不爲空集的情況如
A → αβ | αγ
select(A → αβ) ∩ select(A → αγ) 不爲空
提取公因式
A→αβ1 |αβ2|αβ3|…|αβn,提取左公因子後變爲
A->α(β1|β2|β3|…|βn),再引出非終結符A’
A->αA’
A’->β1|β2|β3|…|βn
例:
S->aSb
S->aS
S->ε
提取左公因式
S->aS(b|ε)
S->ε
進一步變換
S->aSA
A->b|ε
S->ε