編譯原理 - 語法分析(1): 自上而下的語法分析


為什么我們不用詞法分析那一套方式(正則文法、有限狀態機等)來解決語法分析?

正則文法通常什么樣?

對於文法G=(V, T, S, P),如果產生式的形式如下:

A -> xB
A -> x

其中A, B屬於V,x屬於T*,則稱為右線性文法;相似的,如果產生式的形式如下:

A -> Bx
A -> x

則稱為左線性文法。右線性文法和左線性文法統稱為正則文法

例子:

 

G(S):

  S->aS|bS

  S->aA
  A->aB|bB
  B->a|b

 

上下文無關文法通常什么樣?

 對於文法G=(V, T, S, P),如果產生式的形式如下:

 

對於任何

0型文法:
    α -> β :α∈(VN∪VT)* , β∈(VN∪VT)* (可以是符號也可以是字)

1. 在0型文法的基礎上,約束滿足|β|>=|α|,即1型文法(上下文有關文法)。

2. 在上下文有關文法的基礎上,約束滿足所有的產生式左邊只有一個非終結符。

例子:

    G(S):
        S -> aSa|bSbA
        A -> bA

很顯然的上下文無關文法包括了正則文法,是一個更大的范圍。

所以由於正則文法的表達能力,它的表述能力有限,而高級語言的語法結構合適用上下文無關文法描述。所以我們需要一套全新的算法來進行語法分析。

 

自上而下的語法分析

什么是自上而下的語法分析?

對於任何一個上下文無關文法,我們可以構建一個類似於下圖的語法樹。

該語法樹(將無線遞歸下去)可以用來表示文法:

G(s):

S→aAS | a
A→SbA |SS |ba
 
對於這棵樹的樹根(S),他一定是開始符號。對於它的樹葉(a,b),它一定是終止符號。
而自上而下的語法分析,從樹根開始尋找出這樣一個 推導出的句子恰為輸入符號串的導出序列的過程。

 

自上而下分析所面臨的問題

回溯

假設有文法:

S -> xAy

A -> **|*

對於輸入串 x**y 匹配過程如下:

1.讀第1個字符x,展開S樹,發現S有唯一產生式S->xAy。且對於產生式的右邊確實有第一個節點是葉結點(終結符),且為x。所以x得到匹配。

2.讀第2個字符*,因為S的第一個節點已經處理完畢,於是嘗試第二個節點A。發現第二個節點A並不是葉結點。

3.因為A不是葉節點,於是展開A,發現產生式右邊有兩個項:*和**,他們都滿足第一個字符是*,故可能存在兩個選擇。當第一個選擇是錯誤的時候,就需要回溯。

回溯會帶來很多麻煩事:

1.因為語義和語法處理一般同時工作,所以當回頭的時候,語義部分的工作都白費了。

2.如果存在了虛假匹配(如題用A->*處理了**的第一個*,后面出錯)使得需要復雜的回溯處理。

3.如果分析不成功,我們難於知道輸入串出錯的確切位置。

左遞歸

如果存在左遞歸的產生式(如A->Abc),那么因為是處理過程的本質是樹的深度遍歷,會導致會無窮無盡的遞歸下去。

 

左遞歸的消除

直接左遞歸

P->Pα|β

這意味着 β(α)*

改寫成:

P->βP'

P'->αP'|ε

更通用的:

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->Qc|c

Q->Rb|b

R->Sa|a

把S->Qc|c中的Q替換成S的表達式,就變成了直接左遞歸,再按照上述方法處理。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM