自頂向下語法分析方法
-
什么叫確定:
兩個確定:①確定對最左的非終結符進行替換(最左推導)②對於同一個非終結符,確定一個產生式進行推導(SELECT集,無回溯)。
-
一個上下文無關文法是LL(1)文法的充分必要條件:
關於一個非終結符的各個產生式的可選集互不相交。
-
LL(1)文法的判定過程:
-
檢查產生式中是否有含有左遞歸或左公因子:
含有左遞歸或左公因子的文法一定不是LL(1)文法;
不含有左遞歸或左公因子的文法也不能確定是否為LL(1)文法;
-
標記能推導出ε的非終結符:
先找出能直接推出ε的非終結符,然后再查看其他產生式的右部,通過這些非終結符檢查還有沒有其他非終結符也可推出ε,直到沒有發現為止。
-
計算每個產生式的FIRST集:
①如果這個產生式右部第一個字符是終結符,那么這個終結符就屬於它的FIRST集。
②如果這個產生式右部第一個字符是非終結符,那么這個非終結符的FIRST集就屬於它的FIRST集。
如果這個非終結符的FIRST集中含ε,那么后面的字符如果是終結符......
③如果這個產生式右部可以推出ε,那么ε也屬於它的FIRST集。
-
計算每個非終結符的FOLLOW集:
首先向開始符號的FOLLOW集中添加
#
,然后對於所有非終結符,不斷的找含有它的產生式右部:①該非終結符后面的字符若是終結符,那么這個終結符就屬於它的FOLLOW集;
②該非終結符后面的字符若是非終結符,那么這個非終結符的FIRST()集中的所有元素就屬於它的FOLLOW集;
如果這個非終結符的FIRST()集中含ε,將ε刪去,同時將這個產生式左部FOLLOW集中的所有元素添加至它的FOLLOW集中;
注意:不需要考慮后面的字符了,因為已經包含在FIRST()集中了。
-
計算每個產生式的SELECT集:
①如果這個產生式可以推出ε,那么它的SELECT集是
{FIRST(該產生式右部)-ε}∪FOLLOW(該產生式左部的非終結符)
。②如果這個產生式不能推出ε,那么它的SELECT集是
{FIRST(該產生式右部)}
。 -
檢查相同左部產生式的SELECT集的交集:
檢查相同左部產生式的SELECT集的交集,如果全為空集說明該文法是LL(1)文法,反之則不是。
-
-
消除左公因式:
有顯式的左公因式和隱式的左公因式,對於隱式的左公因式要先化成顯式;
例:
顯式:
A→aB|aC
隱式:
A→ad|Bc
B→ae
解決方法:類似合並同類項,將左公因式提出,不同的部分用或連接,並用一個新的非終結符指向它。
注意:某些特殊的含左公因式的文法可能會出現循環替換的情況,此時無法解決左公因式問題。
-
消除左遞歸:
有直接左遞歸和間接左遞歸和一般左遞歸,對於間接左遞歸要先化成直接;
例子:
Ⅰ直接(模板):
P → P α | β
可改寫為:
P → βQ(因為P一定是β開頭)
Q → αQ | ε(Q就是α+)
其中Q為新增的非終結符Ⅱ間接:
S → PQ | a
P → QS | bⅢ一般:
S → PQ | a
P → QS | b
Q → SP | c
做以下變換:
①S → PQ | a
P → SPS|cS|b②S → SPSQ|cSQ|bQ|a
③按照直接左遞歸方法消除后:
S → cSQR|bQR|aR
R → PSQR | ε④結果:
S → cSQR|bQR|aR
P → SPS|cS|b
Q → SP | c
R → PSQR | ε -
遞歸下降分析法:
通過計算的SELECT集判斷編寫子程序:
例子:
遞歸下降分析法
ParseE'函數表示進入E'的產生式,通過switch函數分離相同左部的產生式,然后依次檢查產生式右部字符,如果是終結符,則通過MatchToken函數判斷符合,不符合則出錯;如果是非終結符,則繼續遞歸跳轉至它所對應的Parse函數。
遞歸下降分析法對應的是最左推導過程
優點:程序結構和層次清晰明了,易於手工實現;
對於語義加工,這種方法十分靈活;
缺點:遞歸調用可能帶來效率問題。 -
表驅動LL(1)分析方法(預測分析法 )
例子:
預測分析法
首先根據計算出的SELECT集繪制出預測分析表
預測分析表
然后新建一個分析棧,向空棧中依次壓入
#
和文法的開始符號E
,然后比較剩余輸入串的首字符和分析棧頂元素,如果不同,則先將分析棧頂元素出棧,然后將對應預測分析表中的產生式右部<u>從后向前</u>依次入棧;如果相同,則先將分析棧頂元素出棧,並將剩余輸入串的首字符刪去;然后重復以上過程直到棧為#
,剩余輸入串也為#
,則表示語法匹配成功。分析過程
-
LL(1)分析中的一種錯誤處理辦法 :
發現錯誤的情況:
(1) 棧頂的終結符與當前輸入符不匹配;
(2) 非終結符A於棧頂,面臨的輸入符為a,但分析表M的M[A,a]為空 (FIRST(A)中沒有a);應急”恢復策略:
對於錯誤(1) 跳過輸入串中的一些符號直至遇到和棧頂的終結符相同的字符為止。對於錯誤((2) 跳過輸入串中的一些符號直至遇到“同步符號”為止 。
同步符號的選擇
(1) 把FOLLOW(A)中的所有符號作為A的同步符號。跳過輸入串中的一些符號直至遇到這些“同步符號”,把A從棧中彈出,可使分析繼續。(跳過A)
(2) 把FIRST(A)中的符號加到A的同步符號集,當FIRST(A)中的符號在輸入中出現時,可根據A恢復分析。 (不跳過A)