1. 程式人生 > >編譯原理 詞法分析 二

編譯原理 詞法分析 二

上一篇文章我們介紹了在詞法分析中涉及到的詞法單元、模式和詞素的概念,並給出了正則表示式的遞迴定義,以及如何把一個正則表示式轉換成一個狀態轉換圖。本篇文章將接著上一篇文章的內容,繼續介紹詞法分析的一個重要內容——有窮自動機。

有窮自動機
一個有窮自動機可以把一個描述詞素的模式變成一個詞法分析器,從本質上來講,有窮自動機是與狀態轉換圖相類似的圖,它有以下特點:

有窮自動機是一個識別器,它只能對每個輸入符號串簡單的輸出“yes”或“no”,表示是否能夠識別此符號串;
有窮自動機和狀態轉換圖類似,它具有有限個數的結點,每個結點表示一個狀態,並且這些狀態中有一個初始狀態和若干個終止狀態。從一個狀態s開始,經過被某個符號a(可能包括ε)標記的有向邊,可以到達另一個狀態t或者回到狀態s(成環);
有窮自動機分為不確定的有窮自動機和確定的有窮自動機,不確定的和確定的有窮自動機能識別的語言集合是相同的。
不確定的有窮自動機
一個不確定的有窮自動機(Nondeterministic Finite Automate,下文簡稱NFA)由以下部分組成:

結點集合:一個有窮的狀態集合S;
標記集合:一個輸入符號集合∑,以及空串ε;
轉換函式:它為每個狀態和∑∪{ε}中的每個符號都給出了相應的後繼狀態的集合。即轉換函式的輸入是某個狀態s和∑∪{ε}中的某個符號a,輸出是從狀態s出發,經過標記為a的邊,能夠到達的所有狀態的集合;
初始狀態:S的一個狀態被指定為初始狀態;
終止狀態:S的一個子集被指定為終止狀態的集合。
從NFA的組成部分可以看出,它和狀態轉換圖的不同之處在於:

同一個符號可以標記從同一個狀態出發到達多個目標狀態的多條邊,即轉換函式是一對多關係的;
一條邊的標號不僅可以是輸入符號集合中的符號,也可以是空串ε。
另外,我們也可以把一個NFA用一張轉換表來表示,表的每行對應狀態,表的每列對應輸入符號和ε(實際上就是在資料結構中學過的圖的鄰接表)。下面是一個NFA及其對應的轉換表:

確定的有窮自動機
確定的有窮自動機(Deterministic Finite Automate,下文簡稱DFA)是NFA的一個特例,其中:

標記集合:一個輸入符號集合∑,但不包含空串ε;
轉換函式:對每個狀態s和每個輸入符號a,有且僅有一條標號為a的邊離開s,即轉換函式的對應關係從一對多變為了一對一。
同樣的,一個DFA也能用一個轉換表來表示。由於此時每個表項中只有一個狀態,因此可以省去括號,下面是和在NFA中同一個正則表示式對應的DFA及其轉換表:

從NFA到DFA的轉換
NFA抽象地表示了用來識別某個語言中的串的演算法,而相應的DFA則是一個簡單具體的識別串的演算法。在構造詞法分析器時,真正實現或模擬的是DFA。本節先不論如何從一個正則表示式構建一個有窮自動機,而是討論如何從一個NFA轉換得到相應的DFA。

從NFA轉換得到一個DFA通常使用子集構造法(subset construction)。子集構造法的基本思想是讓構造得到的DFA的每個狀態對應於NFA的一個狀態集合,下面對其進行說明。

由NFA構建DFA的子集構造演算法,輸入一個NFA N,輸出一個接受同樣語言的DFA D。在此期間會為D構造一個轉換表Dtran,D的每個狀態是N的狀態的一個子集,也就是說,D的一個狀態,是在N中從狀態s開始經過標號為a或者ε的邊能夠到達的所有狀態的集合,為此,我們需要認識在NFA狀態集上的操作:

其中,ε-closure(T)操作的詳細過程如下:

我們必須找出當N讀入了某個輸入串之後可能位於的所有狀態集合。首先,在讀入第一個輸入符號之前,N可以位於集合ε-closure(s0)中的任何狀態上(s0是N的初始狀態);接著,假定N在讀入串x之後位於集合T中的狀態上,如果下一個輸入符號為a,那麼N可以移動到集合move(T, a)中的任何狀態上,又因為N可以在讀入a後再執行幾個ε轉換,所以N在讀入串xa後可以位於ε-closure(move(T, a))中的任何狀態上。這個過程可以用下面的偽程式碼表示:

下面我們來實際操作一下。對正則表示式(a|b)*abb,它的一個NFA如下圖:

下面我們使用子集構造法構造一個等價的DFA:

DFA的初始狀態A是ε-closure(0),即A={ 0, 1, 2, 4, 7 },A中的狀態就是從狀態0出發,只經過標號為ε的邊到達的所有狀態;
由於輸入符號只有a和b,下面我們計算ε-closure(move(A, a))和ε-closure(move(A, b)),得到Dtran[A, a]=ε-closure(move(A, a))={ 1, 2, 3, 4, 6, 7, 8 }和Dtran[A, b]=ε-closure(move(A, b))={ 1, 2, 4, 5, 6, 7 },令狀態B為Dtran[A, a],狀態C為Dtran[A, b];
類似第2步,現在我們需要計算ε-closure(move(B, a))、ε-closure(move(B, b))、ε-closure(move(C, a))和ε-closure(move(C, b)),如果出現新的集合,則按照大寫字母順序標記,直到沒有新狀態產生為止;
把包含NFA終止狀態的DFA狀態標記為DFA的終止狀態。
這樣我們就得到了一個等價的DFA,下面是這個DFA及其轉換表:

 
歡迎關注微信公眾號fightingZhヾ(◍°∇°◍)ノ゙
--------------------- 
作者:jzyhywxz 
來源:CSDN 
原文:https://blog.csdn.net/jzyhywxz/article/details/78300350 
版權宣告:本文為博主原創文章,轉載請附上博文連結!