??? 注意:雖然要求|β|>=|α|,但有一特例:α→ε也滿足1型文法。
??? 如有A->Ba則|β|=2,|α|=1符合1型文法要求。反之,如aA->a,則不符合1型文法。
??? 如Ab->Bab雖然符合1型文法要求,但不符合2型文法要求,因?yàn)槠洇?Ab,而Ab不是一個(gè)非終結(jié)符。
??? 如有:A->a,A->aB,B->a,B->cB,則符合3型文法的要求。但如果推導(dǎo)為:A->ab,A->aB,B->a,B->cB或推導(dǎo)為:A->a,A->Ba,B->a,B->cB則不符合3型方法的要求了。具體的說(shuō),例子A->ab,A->aB,B->a,B->cB中的A->ab不符合3型文法的定義,如果把后面的ab,改成“一個(gè)非終結(jié)符+一個(gè)終結(jié)符”的形式(即為aB)就對(duì)了。例子A->a,A->Ba,B->a,B->cB中如果把B->cB改為B->Bc的形式就對(duì)了,因?yàn)锳→α|αB(右線性)和A→α|Bα(左線性)兩套規(guī)則不能同時(shí)出現(xiàn)在一個(gè)語(yǔ)法中,只能完全滿足其中的一個(gè),才能算3型文法。
S -> a|b|(T)
T -> TdS|S
??????????? / | \??
?????????? (? T? )??
?????????? /? |? \??
????????? T?? d?? S??
??????? / | \???? |??
?????? T? d? S??? b??
?????? |??? /|\??
?????? S?? ( T )??
版權(quán)聲明:可以任意轉(zhuǎn)載,但轉(zhuǎn)載時(shí)必須標(biāo)明原作者charlee、原始鏈接 http://tech.idv2.com/2006/05/08/parse-regex-with-dfa/ 以及本聲明。
程序編譯的第一個(gè)階段是詞法分析,即把字節(jié)流識(shí)別為記號(hào)(token)流,提供給下一步的語(yǔ)法分析過(guò)程。而識(shí)別記號(hào)的方法就是正則表達(dá)式的分析。本文介紹利用有限自動(dòng)機(jī)分析表達(dá)式的方法。
概念
- 記號(hào)
- 有字母表中的符號(hào)組成的有限長(zhǎng)度的序列。記號(hào)s的長(zhǎng)度記為|s|。長(zhǎng)度為0的記號(hào)稱為空記號(hào),記為ε。
- 有限自動(dòng)機(jī)(Finite State Automaton)
- 為研究某種計(jì)算過(guò)程而抽象出的計(jì)算模型。擁有有限個(gè)狀態(tài),根據(jù)不同的輸入每個(gè)狀態(tài)可以遷移到其他的狀態(tài)。
- 非確定有限自動(dòng)機(jī)(Nondeterministic Finite Automaton)
- 簡(jiǎn)稱NFA,由以下元素組成:
- 1. 有限狀態(tài)集合S;
- 2. 有限輸入符號(hào)的字母表Σ;
- 3. 狀態(tài)轉(zhuǎn)移函數(shù)move;
- 4. 開始狀態(tài) sSUB{0};
- 5. 結(jié)束狀態(tài)集合F,F ∈ S。
- 自動(dòng)機(jī)初始狀態(tài)為sSUB{0},逐一讀入輸入字符串中的每一個(gè)字母,根據(jù)當(dāng)前狀態(tài)、讀入的字母,由狀態(tài)轉(zhuǎn)移函數(shù)move控制進(jìn)入下一個(gè)狀態(tài)。如果輸入字符串讀入結(jié)束時(shí)自動(dòng)機(jī)的狀態(tài)屬于結(jié)束狀態(tài)集合F,則說(shuō)明該自動(dòng)機(jī)接受該字符串,否則為不接受。
- 確定有限自動(dòng)機(jī)(Deterministic Finite Automaton)
- 簡(jiǎn)稱DFA,是NFA的一種特例,有以下兩條限制:
- 1. 對(duì)于空輸入ε,狀態(tài)不發(fā)生遷移;
- 2. 某個(gè)狀態(tài)對(duì)于每一種輸入最多只有一種狀態(tài)轉(zhuǎn)移。
將正則表達(dá)式轉(zhuǎn)換為NFA(Thompson構(gòu)造法)
算法
算法1 將正則表達(dá)式轉(zhuǎn)換為NFA(Thompson構(gòu)造法)
輸入 字母表Σ上的正則表達(dá)式r
輸出 能夠接受L(r)的NFA N
方法 首先將構(gòu)成r的各個(gè)元素分解,對(duì)于每一個(gè)元素,按照下述規(guī)則1和規(guī)則2生成NFA。 注意:如果r中記號(hào)a出現(xiàn)了多次,那么對(duì)于a的每次出現(xiàn)都需要生成一個(gè)單獨(dú)的NFA。
之后依照正則表達(dá)式r的文法規(guī)則,將生成的NFA按照下述規(guī)則3組合在一起。
規(guī)則1 對(duì)于空記號(hào)ε,生成下面的NFA。

規(guī)則2 對(duì)于Σ的字母表中的元素a,生成下面的NFA。

規(guī)則3 令正則表達(dá)式s和t的NFA分別為N(s)和N(t)。
a) 對(duì)于s|t,按照以下的方式生成NFA N(s|t)。

b) 對(duì)于st,按照以下的方式生成NFA N(st)。

c) 對(duì)于s*,按照以下的方式生成NFA N(s*)。

d) 對(duì)于(s),使用s本身的NFA N(s)。
性質(zhì)
算法1生成的NFA能夠正確地識(shí)別正則表達(dá)式,并且具有如下的性質(zhì):
- N(r)的狀態(tài)數(shù)最多為r中出現(xiàn)的記號(hào)和運(yùn)算符的個(gè)數(shù)的2倍。
- N(r)的開始狀態(tài)和結(jié)束狀態(tài)有且只有一個(gè)。
- N(r)的各個(gè)狀態(tài)對(duì)于Σ中的一個(gè)符號(hào),或者擁有一個(gè)狀態(tài)遷移,或者擁有最多兩個(gè)ε遷移。
示例
利用算法1,根據(jù)正則表達(dá)式 r=(a|b)*abb 可以生成以下的NFA。

將NFA轉(zhuǎn)化為DFA
算法
使用以下的算法可以將NFA轉(zhuǎn)換成等價(jià)的DFA。
算法2 將NFA轉(zhuǎn)化為DFA
輸入 NFA N
輸出 能夠接受與N相同語(yǔ)言的DFA D
方法 本算法生成D對(duì)應(yīng)的狀態(tài)遷移表Dtran。DFA的各個(gè)狀態(tài)為NFA的狀態(tài)集合,對(duì)于每一個(gè)輸入符號(hào),D模擬N中可能的狀態(tài)遷移。
定義以下的操作。
操作 | 說(shuō)明 |
ε-closure(s) | 從NFA的狀態(tài)s出發(fā),僅通過(guò)ε遷移能夠到達(dá)的NFA的狀態(tài)集合 |
ε-closure(T) | 從T中包含的某個(gè)NFA的狀態(tài)s出發(fā),僅通過(guò)ε遷移能夠到達(dá)的NFA的狀態(tài)集合 |
move(T, a) | 從T中包含的某個(gè)NFA的狀態(tài)s出發(fā),通過(guò)輸入符號(hào)a遷移能夠到達(dá)的NFA的狀態(tài)集合 |
令 Dstates 中僅包含ε-closure(s), 并設(shè)置狀態(tài)為未標(biāo)記;
while Dstates中包含未標(biāo)記的狀態(tài)T do
begin
? 標(biāo)記T;
? for 各輸入記號(hào)a do
? begin
??? U := ε-closure(move(T, a));
??? if U不在Dstates中 then
????? 將 U 追加到 Dstates 中,設(shè)置狀態(tài)為未標(biāo)記;
??? Dtrans[T, a] := U;
? end
end
ε-closure(T)的計(jì)算方法如下:
將T中的所有狀態(tài)入棧;
設(shè)置ε-closure(T)的初始值為T;
while 棧非空 do
begin
? 從棧頂取出元素t;
? for 從t出發(fā)以ε為邊能夠到達(dá)的各個(gè)狀態(tài)u do
??? if u不在ε-closure(T)中 then
??? begin
????? 將u追加到ε-closure(T)中;
????? 將u入棧;
??? end
end
示例
將上面生成的NFA轉(zhuǎn)化為DFA。
最初,Dstates內(nèi)僅有ε-closure(0) = A = {0, 1, 2, 4, 7}。然后對(duì)于狀態(tài)A,對(duì)于輸入記號(hào)a,計(jì)算 ε-closure(move(A, a)) = ε-closure(move({0, 1, 2, 4, 7}, a)) = ε-closure({3, 8}) = {1, 2, 3, 4, 6, 7, 8},即 B={1, 2, 3, 4, 6, 7, 8}, Dtran[A, a]=B。對(duì)于狀態(tài)A,由輸入記號(hào)b能夠到達(dá)的僅有4->5,因此 C = ε-closure({5}) = {1, 2, 4, 5, 6, 7},即 Dtran[A, b] = C。
以此類推,可得到以下的狀態(tài)和Dtran。
A = {0, 1, 2, 4, 7}????????? D = {1, 2, 4, 5, 6, 7, 9}
B = {1, 2, 3, 4, 6, 7, 8}??? E = {1, 2, 4, 5, 6, 7, 10}
C = {1, 2, 4, 5, 6, 7}
狀態(tài) | 輸入符號(hào) | |
a | b | |
A | B | C |
B | B | D |
C | B | C |
D | B | E |
E | B | C |
由此得出DFA如下圖所示。

NFA和DFA的效率
給定正則表達(dá)式r和輸入記號(hào)序列x,判斷r是否能夠接受x。
使用NFA的情況下,由正則表達(dá)式生成NFA的時(shí)間復(fù)雜度為O(|r|),另外由于NFA的狀態(tài)數(shù)最多為r的2倍,因此空間復(fù)雜度為O(|r|)。由NFA判斷是否接受x時(shí),時(shí)間復(fù)雜度為O(|r|×|x|)。因此,總體上處理時(shí)間與 r、x的長(zhǎng)度之積成比例。這種處理方法在x不是很長(zhǎng)時(shí)十分有效。
如果使用DFA,由于利用DFA判斷是否接受x與狀態(tài)數(shù)無(wú)關(guān),因此時(shí)間復(fù)雜度為O(|x|)。但是DFA的狀態(tài)數(shù)與正則表達(dá)式的長(zhǎng)度呈指數(shù)關(guān)系。例如,正則表達(dá)式 (a|b)*a(a|b)(a|b)...(a|b),尾部有 n-1 個(gè) (a-b)的話, DFA最小狀態(tài)數(shù)也會(huì)超過(guò) 2SUP{n}。