形式語言與自動機 Part.5 上下文無關語言與下推自動機(PDA)

課程名:形式語言與自動機

作者:Lupinus_Linn

許可證:CC-BY-NC-SA 3.0 創作共用-署名-非商業性-相同方式共享

  • 署名(英語:Attribution,BY):您(用戶)可以複製、發行、展覽、表演、放映、廣播或通過信息網絡傳播本作品;您必須按照作者或者許可人指定的方式對作品進行署名。
  • 非商業性使用(英語:Noncommercial,NC):您可以自由複製、散佈、展示及演出本作品;您不得爲商業目的而使用本作品。
  • 相同方式共享(英語:Sharealike,SA):您可以自由複製、散佈、展示及演出本作品;若您改變、轉變或更改本作品,僅在遵守與本作品相同的許可條款下,您才能散佈由本作品產生的派生作品。(參見copyleft。)

引用:

  • 本文中部分文字與圖片引用自北京郵電大學計算機學院王柏教授的《形式語言與自動機》課程課件。
  • 緒論中的證明方法部分引自清華大學王生原老師課件。
  • 部分題目插圖引用自北京郵電大學出版社《形式語言與自動機 第二版》教材。

在此一併表示感謝,並不做商業用途。

本筆記所有內容的傳送門

Part.1緒論, Part.2 語言與文法
Part 3.有限自動機
Part.4 正則語言,2DFA,Mealy&Moore機
Part.5 上下文無關語言與下推自動機(PDA)
Part.6 圖靈機

Part 5. 上下文無關文法和下推自動機

5.1 上下文無關文法

  • 回顧Chomsky文法體系,上下文無關文法是2型文法。
  • 產生式形如Aα,AN,α(NT)A\rarr \alpha ,A\in N,\alpha\in(N\cup T)^*的語言是上下文無關語言。(左側是單個非終結符)
  • 2型文法對應的識別器是下推自動機PDA,其比普通的自動機多了一個棧,稱爲下推棧。

5.2 推導與歸約

  • 推導和歸約都是用來判定字符串是否屬於文法所定義的語言的。

  • 推導:自上而下,從文法推出句型(句子也是句型)。
    推導過程:將產生式的左部(head)替換爲產生式的右部( body).
    例子:

在這裏插入圖片描述

  • 最右推導:若推導過程的每一步總是替換出現在最右邊的非終結符, 則這樣的推導稱爲最右推導(rm,rightmost).

  • 最左推導:反之。

  • 推導樹:文法的起始符爲根,樹的枝結點標記是非終結符, 葉結點標記爲終結符或ε。
    若枝結點AA有直接子孫x1,x2,,xkx_1, x_2,…, x_k,則文法中有生成式Ax1x2xkA→x_1x_2…x_k.

    例子:
    在這裏插入圖片描述

  • 推導樹邊緣:葉子從左向右組成的字符串稱爲推導樹的邊緣。
    在這裏插入圖片描述

  • 歸約:又稱遞歸推理。自下而上,從句型還原出使用的文法。
    歸約過程:將產生式的右部(body)替換爲產生式 的左部( head).

    在這裏插入圖片描述

  • 推導和歸約分別是從上到下/從下到上建樹。

  • 以下幾個描述是一回事

    1. 字符串ωT\omega \in T^*可以歸約到非終結符AA.
    2. 存在一棵根節點爲A的推導樹,其邊緣爲ω\omega.
    3. 非終結符AA可以推導出串ω\omega.
    4. 非終結符AA可以最左推導出串ω\omega.
    5. 非終結符AA可以最右推導出串ω\omega.

5.3 二義性

  • 二義性是針對文法而言的。
  • 上下文無關文法GG是二義的\leftrightarrow存在兩棵不同的推導樹,但是它們的邊緣是同一個串ωL(G)\omega\in L(G)
  • 如果文法是二義的,那麼它產生的某個句子可以從不同的最左/右推導推出。
  • 例子:
    在這裏插入圖片描述
  • 對於同一語言,可能存在有二義性和沒有二義性的不同文法。但是沒有一般方法可以通過變換消除二義性。

5.4 CFG的Chomsky範式(CNF)

  • 要求:每個非終結符要麼推出兩個非終結符,要麼推出一個終結符。即:生成式形式爲ABC,Aa,A,B,CN,aTA→BC, A→a, A, B, C∈N , a∈T
  • 本質特徵:推導樹是二叉樹。
  • 每個CFG都可以化成CNF.

5.5 CFG的Grebach範式(GNF)

  • 要求:每個產生式右端都以終結符開始,且只有該一個終結符(但推導樹未必是二叉樹)。即:生成式形式爲Aaβ,aT,βNA→aβ, a∈T , β∈N^*
  • 本質特徵:消除左遞歸。

5.6 消去CFG的無用符號

  • 有用符號:包含生成符號和可達符號。即:XNTX\in N \cup T是有用的\LeftrightarrowSαXβω,ωTS\Rightarrow^* \alpha X \beta\Rightarrow^*\omega ,\omega\in T^*
    • 生成符號:可以推出非終結符串的符號。即:ωT\exists \omega \in T^*XX推出ω\omega.
    • 可達符號:可以被起始符號到達的符號,即:SS推出αXβ\alpha X \beta.
  • 無用符號:非生成符號和不可達符號。
    • 消去無用符號:將無用符號從NN中移除,並移除其在PP中的所有產生式。
  • 必須先刪除非生成符號,再刪除不可達符號。 如果反着來會出現:某個符號原先是可達的,但是和其一起的某個符號因爲不是生成符號被刪除了,就不可達了。導致該符號沒有被正常刪除。

5.6.1 找出生成符號集

精髓:從終結符倒着推,能推出終結符串的就是生成符號。

方法

  • 基礎 任何終結符 aTa\in T都是生成符號。
  • 歸納 如果有產生式 AαA\to \alpha,其中 α(NT)\alpha \in (N\cup T)^*的每一個符號都是生成符號,則 A 也是生成符號。

5.6.2 找出可達符號集

精髓:起始符號是可達符號,可達符號產生式右側都是可達符號。

5.7 消去CFG的ϵ\epsilon產生式(不是消符號)

  • 意義:消去ϵ\epsilon產生式外,除了文法不能產生空串外,沒有影響。
  • 可致空符號:可以經過一步或多步推出空串的符號。即:對於CFG G=(N,T,P,S)CFG\ G = (N, T, P, S ),稱符號 ANA \in N是可致空的,當且僅當AA可以經過一步或多步推出ϵ\epsilon.

5.7.1 找出可致空符號集

精髓:能直接推出ϵ\epsilon的符號肯定是可致空符號,能推出可致空符號串的也是可致空符號。

方法

  • 基礎 對於所有產生式 AϵA \to \epsilonAA 是一個可致空符號
  • 歸納 如果有產生式 BC1C2CkB\to C_1C_2…C_k,其中每一個 CiNC_i \in N 是可致空符號,則 BB 是一個可致空符號。

5.7.2 消去空產生式

  • 所有直接推出ϵ\epsilon的產生式被刪除。

  • 推出可致空符號串的產生式,由於需要表現出原來推出空串的可能性,需要將其所有爲空的可能性枚舉出來,但是不能是空串。

    比如A->C1C2C3,其中C1C2C3都是可空符號
    就有以下的可能
    A->C1C2C3
    A->C1C2
    A->C1C3
    A->C2C3
    A->C1
    A->C2
    A->C3
    當C1,C2,C3不可空之後,就要將這些產生式全部加到A裏
    

    最後還要處理起始符號,如果能產生空串,就讓新起始符號直接產生空串。

  • 步驟

    1. 找出能推導出ϵ\epsilon的所有非終結符AA的集合NN'.
    2. 按如下兩步組成新的P1P_1
      ① 如果生成式Aβ0C0β1C1CnβnP,n0A\to \beta_0C_0\beta_1C_1\dots C_n\beta_n\in P,n\ge 0CkN(1kn),βjNC_k \in N'(1\le k\le n),\beta_j \notin N'(即可空符號裏插了一些不可空符號),則P1P_1應加入Aβ0Y0β1Y1YnβnA\to \beta_0Y_0\beta_1Y_1\dots Y_n\beta_n,其中YkY_kCkC_k或者ϵ\epsilon。(即保持不可空符號),枚舉所有的情況,但不包括AϵA\to \epsilon.
    3. 如果SNS\in N'(即S可空),則P1P_1中增加S1ϵSS_1\to \epsilon|SS1S_1是新的起始符,N1=N{S1}N_1=N\cup \{S_1\}。(即把起始符推出空串單獨寫出來)。
      如果SNS\notin N'(即S不可空),則繼承起始符即可。
    4. 得到的無ϵ\epsilon文法G1=(N1,T,P1,S1)G_1=(N_1,T,P_1,S_1).
  • 例子

在這裏插入圖片描述

5.8 消去CFG的單產生式(不是消符號)

  • 單產生式:一個非終結符推出一個非終結符的產生式,說了一句廢話。

  • 單元偶對:一個非終結符如果能全部使用單產生式推出另一個非終結符,則這兩個非終結符是一個單元偶對。

    比如A->B B->C
    則實際上有A->B->C
    則(A,B),(A,C),(B,C)都是單元偶對
    

5.8.1 找出所有的單元偶對

精髓:從S開始BFS,根據單產生式的關係畫出樹即可。

方法:這裏從某一個不特定的非終結符A爲起點。

  1. 設A的單元偶對的非終結符的集合是NAN_A,設N={A}N=\{A\}開始迭代。
  2. 遍歷NN內的非終結符(迭代變量BB),遍歷BB的產生式,如果BCB\to C,則NN增加非終結符CC.
  3. 重複2.,直到NN內的非終結符不再增加。

5.8.2 消去單產生式

精髓:兒子的產生式全部交給爸爸。

如果A->B B->α
則去掉A->B,增加A->α

步驟:如果BαPB\to \alpha \in P,則BB的所有爸爸,即滿足BNAB\in N_A的所有AA,把AαA\to \alpha加入到P1P_1.
最終得到G1=(N1,T1,P1,S)G_1=(N_1,T_1,P_1,S).

注意:有可能有成環的情況,此時要一直推到只包含自己到自己這一條單產生式,不能再含有其他的單產生式。

A->B|α	B->C|β	C->A|γ
A->B|α
A->C|β|α
A->A|γ|β|α
A->A是一句正確的廢話,刪掉
A->γ|β|α

B同理,推到A的時候可以用A最後的結果
B->C|β
B->A|γ|β
B->γ|β|α|β
刪掉重複的
B->γ|β|α

5.9 化簡順序:消空→消單→消無用

  • 如果消空前的符號比較多可以先消一次無用。消無用什麼時候都可以做,但是消無用內部需要先消非生成符號再消不可達符號

5.10 消除遞歸

  • 遞歸文法:如果某個非終結符能推出含有自己的句型(倒不是有自己到自己的產生式),則稱這個文法是遞歸文法。即:A推出αAβ,AN\alpha A\beta,A\in N,則該文法是遞歸文法。

  • 左遞歸文法:能經過若干步後推出含有自己的句型,並且自己在左邊,即:A推出AβA\beta,則文法是左遞歸文法。

  • 右遞歸文法:能經過若干步後推出含有自己的句型,並且自己在右邊。

  • 循環文法:能經過若干步後推出自己。即:A推出A。

  • 生成式:CFG中,所有AαA\to \alpha的生成式稱爲AA生成式。

  • 遞歸在推導樹上的表現就是子樹
    下圖中推導n次會得到anSbna^nSb^n

    S
    a
    S
    b
    a
    S
    b

5.10.1 消除直接左遞歸

  • 假設AA產生式是AAαβA\to A\alpha | \beta
    按照下列推導樹得到βα2\beta \alpha^2

    A
    A
    α
    A
    α
    β

    可以看出,每次使用AAαA\to A\alpha產生式會在右邊生成一個α\alpha,並且越早產生的α\alpha在最後的句子中越靠右。
    最後一定有一個β\beta在最左邊。
    所以不妨先至少推出一個β\beta,然後用右線性文法產生α\alpha^*,這樣就消除了左遞歸。
    改寫爲
    AββAAααA A\to \beta|\beta A'\\ A'\to \alpha|\alpha A'

  • 當產生式有多個直接左遞歸時,每次可以選擇的產生式是不定的,所以在文法中將所有的可能列出來。
    AAα1Aα2Aαmβ1β2βn A\to A\alpha_1|A\alpha_2|\dots |A\alpha_m|\beta_1|\beta_2|\dots|\beta_n
    可以改寫爲
    Aβ1β2βnβ1Aβ2AβnAAα1α2αmα1Aα2AαmA A\to \beta_1|\beta_2|\dots|\beta_n|\beta_1A'|\beta_2A'|\dots|\beta_nA'\\ A'\to \alpha_1|\alpha_2|\dots|\alpha_m|\alpha_1A'|\alpha_2A'|\dots|\alpha_mA'
    即,產生且僅產生{βn}\{\beta_n\}中的一個,在產生{αm}\{\alpha_m\}^*時,每一次的選擇是獨立的,可以選擇不同的α\alpha.
    最後得到的正則式是
    (β1+β2++βn)(α1++αm) (\beta_1+\beta_2+\dots+\beta_n)(\alpha_1+\dots+\alpha_m)^*

  • 例子:
    這裏的*是一個字符。

在這裏插入圖片描述

5.10.2 消除全部左遞歸

5.10.2.1 理解
  • 還有一些左遞歸不是直接的,比如
    A1A2α1β1A2A1α2β2 A_1\to A_2\alpha_1|\beta_1\\ A_2\to A_1\alpha_2|\beta_2
    顯然A1A2α1A1α2α1A_1\Rightarrow A_2\alpha_1\Rightarrow A_1\alpha_2\alpha_1,仍然會產生左遞歸。
    甚至這個套娃鏈可以更長
    A1A2α1β1A2A3α2β2A3A4α3β3A4A1α4β4 A_1\to A_2\alpha_1|\beta_1\\ A_2\to A_3\alpha_2|\beta_2\\ A_3\to A_4\alpha_3|\beta_3\\ A_4\to A_1\alpha_4|\beta_4

  • 回到只有兩個非終結符A1,A2A_1,A_2的例子,生成式的形式有點像二元一次方程(注意只是類比,有不同點)
    x1=x2α1+β1x2=x1α2+β2 x_1=x_2\alpha_1+\beta_1\\ x_2=x_1\alpha_2+\beta_2
    解這種方程的方法是:
    ① 代入x2x_2
    x1=(x1α2+β2)α1+β1x1=x1α2α1+β2α1+β1 x_1=(x_1\alpha_2+\beta_2)\alpha_1+\beta_1\\ x_1=x_1\alpha_2\alpha_1+\beta_2\alpha_1+\beta_1
    ② 解一元一次方程:x1=x1α2α1+β2α1+β1x_1=x_1\alpha_2\alpha_1+\beta_2\alpha_1+\beta_1
    ③ 將解出的x˙1\dot x_1帶回到其他方程,得x˙2=x˙1α2+β2\dot x_2=\dot x_1\alpha_2+\beta_2

  • 結合線性文法的特點,可以有如下解法
    對於
    A1A2α1β1A2A1α2β2 A_1\to A_2\alpha_1|\beta_1\\ A_2\to A_1\alpha_2|\beta_2
    ① 將A1A_1A2A_2在最左邊的產生式,做一次推導,將其作爲一個新產生式(有個定理說的是推導可以作爲產生式,我沒寫)
    A1A1α2α1β1A1A1α2α1β1 \because A_1\Rightarrow A_1\alpha_2\alpha_1|\beta_1\\ \therefore A_1\to A_1\alpha_2\alpha_1|\beta_1
    ② 根據消去直接左遞歸的方法,消去A1A_1的左遞歸
    A1β1β1A1A1α2α1α2α1A1 A_1\to \beta_1|\beta_1A'_1\\ A'_1\to \alpha_2\alpha_1|\alpha_2\alpha_1A'_1
    ③ 將解出的非左遞歸A1A_1帶回A2A_2
    A2β1β1A1β2 A_2\to \beta_1|\beta_1A'_1|\beta_2
    此時A2A_2也沒有了左遞歸。
    ④ 得出結果
    A1β1β1A1A2β1β1A1β2A1α2α1α2α1A1 A_1\to \beta_1|\beta_1A'_1\\ A_2\to \beta_1|\beta_1A'_1|\beta_2\\ A'_1\to \alpha_2\alpha_1|\alpha_2\alpha_1A'_1

  • 推廣到一般時,需要注意

    1. 間接左遞歸是一個圈,即對於一組含有間接左遞歸的產生式,以任何一個非終結符作爲左部都可以推出直接左遞歸。所以需要對非終結符排序。
    2. 排序不一定是按左遞歸鏈條的,比如明明鏈條是A1A2A3A_1\Rightarrow A_2\dots\Rightarrow A_3\dots,執行算法時也可以排成A2,A1,A3A_2,A_1,A_3的順序。
5.10.2.2 算法
  1. 將全部非終結符排序,即將NN映射到A1,A2,,AmA_1,A_2,\dots,A_m.

  2. 消除{Am}\{A_m\}中所有的直接左遞歸。

  3. A1A_1開始,到AmA_m結束
    假設現在執行的是AiA_i,找出類似左遞歸形式的AiAjA_i\to A_j\dots,如果j<ij\lt i,則將AjA_j代換。

    迭代保證了AjAkA_j\to A_k\dots中一定滿足k>jk\gt j,因爲比jj小的已經在之前迭代的時候換過了,而直接左遞歸已經在第二步被消掉了。

  • 實際在操作的時候可以把第2、3步結合做,即一遍消直接左遞歸,一遍代入比自己小的。

  • 例子:
    A1A2A3aA2A3A1A1bA3A1A2A3A3a A_1\to A_2A_3|a\\ A_2\to A_3A_1|A_1b\\ A_3\to A_1A_2|A_3A_3|a
    排序:{A1,A2,A3}\{A_1,A_2,A_3\}
    採用一遍消直接左遞歸一遍代入比自己小的的策略。
    A1A_1:
    沒有直接左遞歸,沒有比自己小的A1AjA_1\to A_j\dots
    A2A_2:
    沒有直接左遞歸,有比自己小的A2A1bA_2\to A_1 b
    所以代入一次A2(A2A3+a)bA3A1A2A3bA3A1abA_2\to (A_2A_3+a)b|A_3A_1\to A_2A_3b|A_3A_1|ab
    是直接左遞歸,消掉,其中β1=A3A1,β2=ab,α=A3b\beta_1 = A_3A_1,\beta_2 = ab,\alpha = A_3b
    A2β1β2β1A2β2A2aka.A2A3A1abA3A1A2abA2A2ααA2aka.A2A3bA3bA2 A_2 \to \beta_1| \beta_2 | \beta_1 A'_2 | \beta_2 A'_2\\ aka.A_2\to A_3A_1|ab|A_3A_1A'_2|abA'_2\\ A'_2\to \alpha | \alpha A'_2\\ aka.A'_2 \to A_3b | A_3bA'_2
    A3A_3太多了我懶得寫了

5.11 轉Chomsky範式

  • 這裏的前提是已經是無空產生式、無單產生式、無循環、無無用符號的文法了。(前兩者對CNF範式很重要)

精髓:因爲CNF範式只允許ABC,AaA\to BC,A\to a,所以產生式右部長度大於2時,就把最左符號單拎出來,其他符號用臨時符號代替。而且因爲不允許AaBA\to aB,所以非終結符出現在非葉節點需要添加非終結符,改寫成ACaB,CaaA\to C_aB,C_a\to a.

方法:對於產生式AD1D2Dn,n2A\to D_1D_2\dots D_n,n\ge 2,假設引入的非終結符形如BiB_i
如果DiTD_i\in T,則引入BiDiB_i\to D_i
如果DiND_i \in N,則令BiDiB_i\to D_i.(形式化描述用,實際不用)
經過上面兩種情況,原來的生成式變成了AB1B2Bn,n2A\to B_1B_2\dots B_n,n\ge 2
如果n>2n\gt 2,則引入CiC_i,兩兩分組。
AB1C1C1B2C2Cn1Bn1Bn A\to B_1C_1\\ C_1\to B_2 C_2\\ \dots\\ C_{n-1}\to B_{n-1}B_n
例子G=({A,B,S},{a,b},P,S)G=(\{A,B,S\},\{a,b\},P,S),求等效CNF G1CNF\ G_1.
P:SaABBAABBBaBASb P: S\to aAB|BA\\ A\to BBB|a\\ B\to AS|b
解:化成無空、無單、無循環、無無用符號的文法。這裏已經是了。
已經符合CNF範式的,不變
SBA,Aa,BASb S\to BA,A\to a,B\to AS|b
保留。
對於SaABS\to aAB,變爲
SCaABSCaC1,C1AB S\to C_aAB\\ S\to C_aC_1,C_1\to AB
對於ABBBA\to BBB,變爲ABC2,C2BBA\to BC_2,C_2\to BB.

5.12 轉Greibach範式

  • 需要先轉成CNF.
  • 複習:GNF範式的特點是生成式右部最左一定是終結符,但是不一定是二叉樹。

精髓:消直接左遞歸的步驟可以將生成式右部最左引入終結符,符合GNF的要求。所以消掉全部的左遞歸,其他非左遞歸成分的不斷代入,直到出現最左是終結符的爲止。

例子:已有CNF如下(其他略去不表)
P:ABCBCAbCABa P:A\to BC\\ B\to CA|b\\ C\to AB|a

  1. 將非終結符排序:A,B,C

  2. 執行消全部左遞歸算法:
    A,BA,B的產生式不需要調整。
    CABC\to AB的最左A<CA\lt C,需要代入CBCBC\to BCB,仍然不行,再代入CCACBbCBC\to CACB|bCB。不要忘了CaC\to a,代換後得到的CC產生式是
    CCACBbCBa C\to CACB|bCB|a
    對於CCACBC\to CACB,消左遞歸
    α=ACB,β1=bCB,β2=aCβ1β2β1Cβ2CbCBabCBCaCCααCACBACBC \alpha = ACB,\beta_1 = bCB,\beta_2 = a\\ C\to \beta_1|\beta_2|\beta_1C'|\beta_2C'\to bCB|a|bCBC'|aC'\\ C'\to \alpha|\alpha C'\to ACB| ACBC'

  3. 倒序遍歷所有非終結符,將不符合GNF要求的(右部最左爲非終結符)不斷代換,直到符合要求。
    然後倒序新引入的用於消左遞歸的符號XX',同樣操作。
    CC的產生式都符合要求。
    BB的產生式BCAB\to CA不符合要求,代入
    BCAbCBAaAbCBCAaCA B\to CA\to bCBA|aA|bCBC'A|aC'A
    AA的產生式ABCA\to BC不符合要求,代入
    ABCbCBACaACbCBCACaCAC A\to BC\to bCBAC|aAC|bCBC'AC|aC'AC
    原有非終結符處理完畢,處理新引入的符號。
    CC'的產生式CACBACBCC'\to ACB| ACBC'不符合要求,代入AA
    CbCBACCBaACCBbCBCACCBaCACCBbCBACCBCaACCBCbCBCACCBCaCACCBC C' \to bCBACCB|aACCB|bCBC'ACCB|aC'ACCB| bCBACCBC'|aACCBC'|bCBC'ACCBC'|aC'ACCBC'
    其實CC'只是我寫出來嚇唬人的,用來說明GNF範式可能很長。

5.13 下推自動機

  • 下推自動機(PDA)比有限自動機多了一個下推棧,所以可以記憶一個變量。其實如果把有限自動機改成無限也可以,可惜改不得。

組成:一個有限狀態控制器,一個輸入帶,一個無限容量的下推棧。

定義:七元組M=(Q,T,Γ,δ,q0,z0,F)M=(Q,T,\Gamma,\delta,q_0,z_0,F)
和有限自動機相比,多了一個Γ\Gamma:有限下推棧字母表
多了一個棧底符號z0z_0,通常其不包含在TT中,只是在PDA中用於表示棧底。

δ\delta變成了Q×(Tϵ)×ΓQ×ΓQ\times (T\cup \epsilon) \times \Gamma \to Q\times \Gamma^*,即根據當前狀態、帶上的輸入字符、棧頂符號或空(只有一個,不能是串)三者決定下一個狀態和棧頂的字符串(壓入時可以壓入多個字符)
δ(q,a,Z)={p,α}\delta(q,a,Z)=\{p,\alpha\}表示,當自動機狀態爲qq,輸入符號爲aa,棧頂爲ZZ時,將狀態轉換爲pp,在棧頂壓入α\alpha串。

格局:用三元組(q,ω,α)(q,\omega,\alpha)描述。
qq當前狀態。
ω\omega待輸入串,ω=ϵ\omega=\epsilon時表示輸入字符讀完。
α\alpha下推棧的內容,α\alpha從左到右是棧頂到棧底,α=ϵ\alpha=\epsilon表示棧空。

接受方式

  1. 終態接受:輸入結束時狀態處於接受狀態。即推導過程是(q0,ω,z0)(q,ϵ,α),qF(q_0,\omega,z_0)├^*(q,\epsilon,\alpha),q\in F
  2. 空棧接受:輸入結束時下推棧爲空。即推導過程是(q0,ω,z0)(q,ϵ,ϵ)(q_0,\omega,z_0)├^*(q,\epsilon,\epsilon)。爲了標識空棧接受,一般把FF標記成\empty.

DPDA:確定的下推自動機,即每一次轉移都只有一個選擇。
具體來說, 每次轉移必須符合下列的一種情況

  1. δ(q,a,z)=1δ(q,ϵ,Z)=|\delta(q,a,z)|=1∧ \delta(q,\epsilon,Z)=\empty
  2. δ(q,a,z)=δ(q,ϵ,z)1\delta(q,a,z)=\empty∧ |\delta(q,\epsilon,z)|\le 1

這樣可以防止在轉移時搞不清楚是用字符轉移還是用空轉移導致的不同結果。

NDPA:不確定的下推自動機。

5.14 PDA的設計

5.14.1 L(M)={anbnn0}L(M)=\{a^nb^n|n\ge 0\}

思路:把輸入的字符 a 入棧,當開始輸入 b 時,從棧中彈出 a ,若 a 、 b 個數相同,則到達終態,且棧中空。

在這裏插入圖片描述

5.15 終態接受\leftrightarrow空棧接受

5.15.1 終態接受👉空棧接受

精髓:既然終態不在接受了,就把原來的終態空轉移到同一個狀態,然後把棧彈空。

方法Mf(Q,T,Γ,δ,q0,z0,F)M_f(Q,T,\Gamma,\delta,q_0,z_0,F),構造M=(Q{qe,q1},T,Γ{z1},δ1,q1,z1,)M_\empty=(Q\cup\{q_e,q_1\},T,\Gamma\cup \{z_1\},\delta_1,q_1,z_1,\empty)
即增加一個起始狀態q1q_1,一個放空用狀態qeq_e,同時把棧底符號換成z1z_1(因爲z0z_0也要被彈掉)。

  1. δ1(q1,ϵ,z1)={(q0,z0z1)}\delta_1(q_1,\epsilon,z_1)=\{(q_0,z_0z_1)\},即從空棧PDA的起始狀態無條件進入原終態PDA。
  2. δ1(q,a,z)=δ(q,a,z)\delta_1(q,a,z)=\delta(q,a,z),即空棧PDA繼承原終態PDA的所有轉移(含空轉移)。
  3. qfF,δ1(qf,ϵ,z)={(qe,ϵ)}\forall q_f\in F,\delta_1(q_f,\epsilon,z)=\{(q_e,\epsilon)\},將終態無條件跳轉到放空用終態。
  4. δ(qe,ϵ,z)={(qe,ϵ)}\delta(q_e,\epsilon,z)=\{(q_e,\epsilon)\}即自己把棧彈空。

5.15.2 空棧接受👉終態接受

精髓:更簡單,把所有的狀態都在空棧時轉移到同一個可接受狀態即可。

方法M(Q,T,Γ,δ,q0,z0,)M_\empty(Q,T,\Gamma,\delta_\empty,q_0,z_0,\empty),構造Mf=(Q{q1,qf},T,Γ{z1},δf,q1,z1,{qf})M_f=(Q\cup\{q_1,q_f\},T,\Gamma\cup\{z_1\},\delta_f,q_1,z_1,\{q_f\})

  1. δ(q1,ϵ,z1)={(q0,z0z1)}\delta(q_1,\epsilon,z_1)=\{(q_0,z_0z_1)\},即把空棧PDA的棧底符號壓進去,然後轉移到其開始狀態。
  2. δf(q,a,z)=δ(q,a,z)\delta_f(q,a,z)=\delta_\empty (q,a,z),即終態PDA繼承原空棧PDA的所有轉移(含空轉移)。
  3. δf(q,ϵ,z1)={(qf,ϵ)}\delta_f(q,\epsilon,z_1)=\{(q_f,\epsilon)\},即當任何一個狀態處出現空棧(z0z_0沒了。露出了z1z_1),就跳轉到一個公共的接受狀態。

5.16 上下文無關文法\leftrightarrow下推自動機

5.16.1 上下文無關文法👉下推自動機

精髓:挺無聊的,總共只有一個狀態。把文法的符號作爲棧符號,開始壓入S,如果棧頂是非終結符就做最左推導,如果棧頂是終結符就等輸入來把它喫掉,最後棧空了就接受了。

方法:對於CFG G=(N,T,P,S)CFG\ G=(N,T,P,S),構造PDA M=(Q,T,Γ,δ,q0,z0,F)PDA\ M=(Q,T,\Gamma,\delta,q_0,z_0,F)
其中QQ只需要一個狀態,Q={q}Q=\{q\}
TT是可以輸入的非終結符
Γ=NT\Gamma=N\cup T,即棧內的符號可以是非終結符和終結符。
q0=qq_0=q,反正只有一個狀態。
z0=Sz_0=S,從起始符開始推導。
F=F=\empty空棧接受
δ\delta如下

  1. 對於ANA\in N,增加δ(q,ϵ,A)={(q,β)if AβP}\delta(q,\epsilon,A)=\{(q,\beta)|if\ A\to \beta\in P\},即PDA在棧頂遇到非終結符就無條件做推導。
  2. 對於aT,δ(q,a,a)={(q,ϵ)}a\in T,\delta(q,a,a)=\{(q,\epsilon)\},即PDA遇到棧頂遇到終結符就等待輸入相同的字符後把它喫掉。
    這個很重要,容易忘

在這裏插入圖片描述

5.16.2 下推自動機👉上下文無關文法

  • 挺抽象一個定理,但是本屆不考。
  • 略去不表。

5.17 CFL的泵引理

  • 和正則語言的泵引理類似,都是說明,如果語言的句子長於一個常數時,總是有子串在重複。不過正則語言是一個子串重複,CFL是兩個。

定理CFL LCFL\ L一定存在常數NN,對於ωLωN\omega \in L ∧ |\omega|\ge N,則存在分解ω=ω1ω2ω0ω3ω4\omega=\omega_1\omega_2\omega_0\omega_3\omega_4,並且ω2ω3ϵ,ω2ω0ω3N\omega_2\omega_3\neq \epsilon,|\omega_2\omega_0\omega_3|\le N(這很重要),對於i0,ω1ω2iω0ω3iω4L\forall i\ge0,\omega_1\omega_2^i\omega_0\omega_3^i\omega_4\in L.(L=ϵL={\epsilon}除外)

原因:通俗一點解釋,證明不考。對於語言LL,設ϵL\epsilon \notin L,其Chomsky文法爲GG.設某個句子ωL\omega\in L,其使用文法GG的推導樹是一顆二叉樹,設該二叉樹的路徑長度(從根節點到葉節點的最大長度)爲nn,則邊緣長度ω2n1|\omega|\le 2^{n-1}(滿二叉樹時取等)。
如果說文法GG內有nn個非終結符,那麼,當ω2n=N|\omega|\ge 2^n=N時,根據Pigeonhole定理,一定有兩個節點(途徑非終結符)相同,那麼,這兩個節點,除了重複自己外還會重複另一個分支。
舉個例子,有三個終結符{A,B,C}\{A,B,C\}

A
α
C
B
trivial
A
α
C

然後A->C->B又會推出A,不斷重複,此時A的另一個分支α\alpha不斷重複,產生了ω3i\omega_3^i
如果把C和α\alpha左右子樹的位置對調一下

A
C
α
B
trivial
A
C
α

此時產生的是ω2i\omega_2^i.
由於我們不能確定α\alpha在左子樹還是右子樹,或者兩邊都有遞歸。不妨兩邊都用,大不了ω2=ϵ\omega_2=\epsilon或者ω3=ϵ\omega_3=\epsilon,但是兩者不能同時爲空。

5.17.1 L={anbncnn1} is not CFL.L=\{a^nb^nc^n|n\ge 1\}\ is\ not\ CFL.

  1. 假設LLCFLCFL,則知存在NN,對於任意ωN\omega\ge N滿足泵引理。
  2. 不妨取ω=aNbNcN=ω1ω2ω0ω3ω4\omega =a^Nb^Nc^N=\omega_1\omega_2\omega_0\omega_3\omega_4,考慮ω2ω0ω3\omega_2\omega_0\omega_3的位置,無非有兩種情況:
    • aω2cω3a\in \omega_2∧ c\in \omega_3,則因爲要跨過全bbω2ω0ω31+N+1=N+2|\omega_2\omega_0\omega_3|\ge 1+N+1=N+2,但是泵引理要求ω2ω0ω3N|\omega_2\omega_0\omega_3|\le N,所以不成立。
    • 因爲ω2ω0ω3N|\omega_2\omega_0\omega_3|\le N,所以在滑動時,ω2\omega_2ω3\omega_3可能會含有相同字符。這裏以aa爲例。
      ω2=am,ω0=al,ω3=ajbk\omega_2=a^m,\omega_0=a^l,\omega_3=a^jb^k,由於ω0\omega_0不可以重複而ω2,ω3\omega_2,\omega_3可以重複,取ω=ω1ω22ω0ω32ω4\omega'=\omega_1\omega_2^2\omega_0\omega_3^2\omega_4,則此時aa的數量多於bbcc,不屬於LL
    • ω2\omega_2ω3\omega_3不含有相同字符,這個更離譜。
  3. 綜上,所有可能給的情況下都與LLCFLCFL的假設矛盾,所以LL不是CFLCFL.

5.18 CFL的封閉性

  • 對加法、乘法、閉包封閉,對交、補、置換不封閉。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章