編譯原理學習

編譯原理學習筆記----

Thompson算法由正規式構造NFA算法

例如:求正規式 1(0|1)*101 的NFA函數

首先將正規式r=1(0|1)*101分解成r=r1,r2r3學習

將r2,r3展開得:spa

 

 

不肯定有窮自動機(NFA)3d

一個不肯定的有窮自動機T是一個五元組,M={K,∑,f,S,Z}
⒈K是一個有窮集他的每個元素稱做一個狀態。
⒉∑是一個字母表,他的每個元素稱爲一個輸入符號。
⒊f是一個從Kx∑*到K的子集映射即K*∑*->2^K,其中2^K表示K的冪集。
⒋S包含於K集,是一個非空初態集合。
⒌Z包含於K是一個非空的終態集合。

 

肯定有窮自動機(DFA)blog

一個肯定的有窮自動機M是一個五元組:M=(K, ∑,f,S,Z)其中,遞歸

1)K是一個有窮集,他的每一個元素稱爲一種狀態。編譯

2) ∑是一個有窮字母表,他的每一個元素稱爲一個輸入符號,因此∑稱爲輸入符號表。class

3)f是轉換函數,是KX∑-->K 上的映像,例如f(ki,a)=kj這就意味着,當前狀態爲k,輸入字符a後,將轉換到下一狀態kj,咱們把kj稱爲ki的一個後繼狀態;編譯原理

4)S屬於K,是惟一的一個出態。

5)Z屬於K,是一個終態,終態也稱爲可接受狀態或結束狀態。

例如:

這個DFA能夠表示一個狀態圖:

也能夠用狀態矩陣顯示,行表示狀態,列表示輸入符號,終態在表的右端標1,非終態在表的右邊標0。

 

NFA相對於DFA的2點區別:

NFA的不肯定性)
1.當前狀態下,對同一字符可能有多於一個的下一狀態。
2.可能存在ε狀態轉移。

 

NFA轉DFA

例如:給出NFA的圖

求其最小DFA,求法以下:

(ps:由於集合C和D接收一個輸入字符a或b時都獲得同一個集合(即同一狀態),因此C和D不可區分,能夠去掉D這一行)。

 

由正規式的NFA構造CFG(上下文無關文法)

例如:從正規式r=(a|b)*abb的NFA構造CFG

正規式對應的NFA爲:

通常方法:

  A → HT

  H →ε| aH | bH

  T → abb

因此,能夠改寫爲:

  A0 → aA0|bA0|aA1

  A1 → bA2

  A2 → bA3

  A3 → ε

將每個狀態看作一個非終結符,至關於照圖寫出狀態經一步能達到的狀態轉移。

 

文法類型

若文法G=(N,T,P,S)的每一個產生式α→β中,均有α∈(N∪T)*,且至少含有一個非終結符,β∈(N∪T)*,則稱G爲0型文法。

 

對0型文法施加如下第i條限制,即獲得i型文法。

1.G的任何產生式α→β(S→ε除外)知足|α|≤|β|;

2.G的任何產生式形如A→β,其中A∈N,β∈(N∪T)*;

3.G的任何產生式形如A→a或者A→aB(或者A→Ba),其中 A和B∈N,a∈T。

 

 

LL(1)文法:一種自上而下的分析方法

對文法G的句子進行肯定的自頂向下語法分析的充分必要條件是,G的任意兩個具備相同左部的
產生式A—>α|β 知足下列條件:
   (1)若是α、β均不能推導出ε,則 FIRST(α) ∩ FIRST(β) = Φ。
  (2)α 和 β 至多有一個能推導出 ε。
  (3)若是 β *═> ε,則 FIRST(α) ∩ FOLLOW(A) = Φ。
將知足上述條件的文法稱爲LL(1)文法。
通俗的來講,所謂LL(1)分析法,就是指從左到右掃描輸入串,同時採用最左推導,且對每次直接推導只需向前看一個輸入符號,即可肯定當前所應當選擇的規則。
這個文法應該知足:無二義性,無左遞歸,無左公因子。

 

構造LL(1)文法:

第一步:計算first集合

算法:每次選取右部第一個符號,推導直至右部第一個符號是終結符,把其加入First集合中。

例如:計算如下文法的First集合

  L →E;L|ε

  E →TE'

  E'→+TE'|-TE'|ε

  T →FT'

  T'→*FT'|/FT'|mod FT'|ε

  F →(E)|id|num

計算First集合要自下而上分析。

由於(E)第一個符號爲終結符,因此將直接加入First集合,同理id,num也加入First集合。

再如:T->FT',右部第一個符號是非終結符F,將其推導至F->(E)|id|num,發現3個推導式中第一個符號都爲終結符,因此將他們都加入First集合。

須要注意的是,若產生式中包含ε也要加入First集合。

由以上的分析方法可計算出:

FIRST(F/T/E)= {( id num}

FIRST(T') = {* / mod ε}

FIRST(E') = {+ - ε}

FIRST(L) = {ε ( id num}

 

第二步:計算Follow集合(Folow集合的算法稍微複雜一些,教科書上的解釋很複雜,我本身總結了一下,通俗的描述出來)

算法:4條規則(  求Follow(U)  )

1.U是文法開始符號,則直接加入 

2.形如 ...Ua... ,加入 

3.形如 S->...UP... ,加入First(P),而且,若是First(P)中包含 ε 符號時,要去掉 ε 並加入Follow(S)。

4.形如  P->...U ,加入Follow(P)。

例如:計算如下文法的Follow集合

  L →E;L|ε

  E →TE'

  E'→+TE'|-TE'|ε

  T →FT'

  T'→*FT'|/FT'|mod FT'|ε

  F →(E)|id|num

計算Follow集合要自上而下分析。

由於L是開始符號,因此Follow(L)={#}

求E的Follow集合時,先將跟E有關的式子列出

L →E;L|ε

F →(E)|id|num

形如...Ua...,因此將加入Follow(E)集合。

由以上分析方法便可求出:

FOLLOW(L) = {#}

FOLL0W(E/E')= {) ;}

FOLLOW(T/T')= {+ - ; )}

FOLLOW(F) = {+ - * / mod ) ;}

 

第三步:構造預測分析表

首先觀察一下預測分析表和我們求出的First和Follow集合:

FIRST(F/T/E)= {( id num}

FIRST(T') = {* / mod ε}

FIRST(E') = {+ - ε}

FIRST(L) = {ε ( id num}

 

FOLLOW(L) = {#}

FOLL0W(E/E')= {) ;}

FOLLOW(T/T')= {+ - ; )}

FOLLOW(F) = {+ - * / mod ) ;}

好比,求L這行,發現First(L)集合中有ε ( id num這幾個符號,所以在這行的這幾個符號中填入L的產生式(ε產生式能夠忽略,而且若是有多個產生式,就填相關的產生式),又由於First(L)中包含ε,所以將這行存在於Follow(L)集合中全部的終結符填入ε

 

第四步:根據預測分析表以格局的形式寫出對某輸入序列的分析過程。

例如:

匹配過程就是匹配到棧內容中的非終結符時,根據當前輸入中匹配的終結符查預測分析表,選取相應的產生式,將產生式倒過來寫,替換棧中匹配的非終結符。

 

LL(1)文法的判別:

簡單判斷:看看文法有無左因子,有無左遞歸,有就不是。

定義判斷:

假設文法中有A->B|C

1.若First(B)∩First(C)有終結符,則不是LL(1)文法。

2.若B=>*ε 並且 C=>*ε,則不是LL(1)文法。

3.若B=>*ε 且First(C)∩Follow(A)有終結符,則不是LL(1)文法。

 

LR(0)文法:

LR(0)項目集:產生式右部用.分隔。例如:E->T*F 的LR(0)項目有

E->.T*F

E->T.*F

E->T*.F

E->T*F.

識別活前綴的DFA

例如:文法爲

E→E*T|T

T→T+F|F

F→id

給出它的識別活前綴的DFA。

解答:

就是將LR(0)項目集進行推導,直至產生式推導完畢。可是,要注意的是,若是推導出的產生式的 . 後面有非終結符,要將非終結符的活前綴一塊兒寫出來。例如,I5狀態中的 E->E.*T 通過 推導出 E->E*.T , 是非終結符,因此,下一個狀態中要加入

T->.T+F   

T->.F   

F->.id 

 

項目集存在移進/歸約衝突:某一狀態便可歸約(.在產生式最後,推導完畢)又能夠通過某字符到達下一狀態。

例如:某文法活前綴的DFA

分析可知:I2 , I11存在移進/歸約衝突。

 

LR(0)文法判斷:存在移進/歸約或者歸約/歸約衝突衝突就不是LR(0),若是衝突可解決就是SLR(1)。

 

SLR(1)文法判斷

當LR(0)文法存在移進/歸約衝突時即狀態集中同時存在

A→β1.β2B→β.

若是FIRST(β2)∩FOLLOW(B)=Φ,則衝突可解決,是SLR(1)文法。

存在歸約/歸約衝突時即同時存在

A→α. 和 B→β.

若是FOLLOW(A)∩FOLLOW(B)=Φ,則衝突可解決,是SLR(1)文法。

 

句型、短語、直接短語、句柄

短語:以非終結符爲根子樹中全部從左到右的葉子。

直接短語:子樹中只有父子兩代的子樹的葉子節點。

句柄:子樹中最左邊的那棵只有父子兩代的子樹的全部葉子結點自左至右排列起來,就是該句型的句柄。

例如:有文法

E→E+T|T

T→T*F|F

F→id

和句型:id1+id2*id3。

畫出其分析樹:

 

句柄:由於最左部有子樹F1-id1只有父子兩代關係,因此句柄爲id1。

 

後綴式、三地址碼、三元式、四元式

後綴式計算方法:將最後計算的計算符號放到最後,把它的左操做數放到開始(ps:左操做數若是是一個表示達也要重複以前操做並將結果放到中間),右操做數若是是一個表達式,則重複以前的操做將結果放到中間。

例如:求 3+5*2/7 的後綴式

分析:最後運算的符號是+,左操做數是3,右操做數是表達式5*2/7,將3放到最前面,+放到最後面,接着計算5*2/7的後綴式,一樣5放到最前面,*放到最後並加入到以前的後綴式中間,計算2/7的後綴式,2放到最前面,/放到最後面,右操做數7放到中間,並將其總體加入到以前的後綴式中間。

所以,獲得

3 5 2 * 7 / +

 

三元式、四元式

例如:計算 x:=(a+b)*(a+b) 的三元式和四元式。

首先畫出它的註釋語法樹:

由註釋語法樹從葉子節點寫到根結點很容易可得三元式:

(1)(+, a, b )

(2)(+, a, b )

(3)(*,(1),(2))

(4)(:=,x, (3))

和四元式:

(1)(+, a, b, T1)

(2)(+, a, b, T2)

(3)(*, T1,T2,T3)

(4)(:=,x, T3,T4)

其實四元式也就是給三元式每一步生成的式子用一個變量表示。

 

三地址碼計算方法

例如,求 x := a + b * c 的三地址碼序列: 

(*,b,c,T1) 

(+,a,T1,T2)

(:=,x,T2,T3)

將最早運算的表達式用一個變量T1表示,依次用T2,T3...表示其餘運算,三地址碼序列就是將表達式樹用四元式組表示。

相關文章
相關標籤/搜索