youtube :詞法規則
文章較長,是4節視頻的合集,大家看的時候多思考吧。
4.1| Lexical Specification – 詞法規則
回顧:
如何識別任意字符串是否屬於某一語言?
步驟:
- 寫出所有
token class
的正則表達式
比如:
Number = ‘digit'
Keyword = 'if'+'else'+...
identifier = letter (letter+digit)*
OpenPar = '('
Lexical Speicification
R = 所有token class
的並
R = Keyword + identifier + Number + ...
= r1 + r2 + r3 + ...
- 輸入字符串
x1...xn
,針對字符串的某個前綴(即子串),判斷其是否屬於L(R)
for 1 <= i <= n 檢查
x1...xi 屬於 L(R)
- 如果3成立,那麼
x1...xi
就屬於L(R)
,否則x1...xi
不屬於L(R)
x1...xi 屬於 L(Rj) 成立對於一些j
- 將
x1...xi
從x1...xn
中刪除,轉入3繼續判斷,直到x爲空(哦,原來如此,有點神奇呀!)
避免以上流程中的二義性:
- 總是選擇最大的前綴
x1...xi
(maximal match
)
比如: ’==‘
不會看成兩個’=‘
- 對給定前綴
x1...xi
,匹配其對應的token class
中優先級最大的那個(正想問呢)
比如:'if'
可能屬於identifier
或者keyword
,此時優先識別爲keyword
- 設定
error
集合,表示不屬於該語言的字符串。若輸入此類字符串,則報錯。(定義的規則好像很嚴謹耶,都是大神 /w\ )
將Error
放到最後(優先級最低),因爲可能我們定義的Error
太草率,和前面的正確的正則表達式有重合。
4.2| Finite Automata – 有窮自動機
本節主要講了:如何用有窮自動機實現正則表達式
-
Finite Automata
用於等價地實現正則表達式 -
Finite Automata
組成:
An input alphabet
– 字母表E
A finite set of states
– 有限的狀態集合S
A start states
– 開始狀態n
A set of accepting states
– 終止狀態
A set of transitions
– 狀態轉換
- 有窮自動機的圖示:
language of a FA
=set of accepted strings
– 有窮自動機對應的語言:其接受(終止狀態)的字符串組成的集合
比如輸入爲字符串'110'
,經過有窮自動機後,Accepts(接受):
epsilon move
空轉換,不用輸入就可以從狀態A轉換到狀態B
- DFA 確定型的有窮自動機
-
一個輸入對應一個確定的狀態轉換(即一個確定的輸入不會轉換到兩個狀態)
-
沒有空轉換
- NFA 非確定型的有窮自動機
-
一個輸入可以同時對應多個狀態轉換
-
可以有空轉換
4.3| Regular Expressions into NFAs – 正則表達式轉換爲NFAs
Lexical specification --> Regular Expression --> NFA --> DFA --> Table-driven Implementation of DFA
(詞法規範 --> 正則表達式 --> 不確定的有窮自動機 --> 確定的有窮自動機 --> 一組查詢表和一些遍歷表的代碼)
前面的部分完成了前兩步,定義了NFA、DFA。(瞬間明朗了haha…)
對於每一個正則表達式,定義NFA、以及空字符和字符a如下:
那麼(好秀呀!),這樣的話正則表達式可以直接按照模板套,變成NFA:
4.4| NFA to DFA – NFA to DFA
(上課是真滴沒聽懂這一塊QAQ)
-
定義:
epsilon closure
– 從某狀態通過空轉換可達到的所有狀態的集合 -
定義:NFA
起始狀態:A
轉換得到的狀態:a(X)=從X出發由輸入a能達到的所有狀態
終止狀態:F
- 那麼:從NFA轉換到DFA
起始狀態:epsilon closure(A)
轉換得到的狀態:X-a->Y if Y = epsilon closure(a(X)) (意思就是從X轉換到一個狀態集,包含所有從X出發,經過空轉換或或其他轉換能到達的狀態)
終止狀態:只要當前狀態集中包含F,就是終止狀態
- 簡單來說:NFA一個輸入可以轉換到不同狀態,DFA一個輸入轉換到一個唯一的狀態集(包含不同狀態)
比如 (1+0)*1
NFA表示如下:
步驟:
-
從A(起始狀態)開始,找出epsilon closure(A) = ABCDHI,作爲DFA的起始狀態。(如下圖,紫色圈出)
-
可能的轉換是’1’或者’0’,從’0’開始可以到達F,那麼求epsilon closure(F) = FGHIABCD。(如下圖,深藍色圈出)
-
從’0’開始可以到達E或者J,那麼求epsilon closure(E) + epsilon closure(F) = ABCDEGHIJ,因爲包含J,所以說終止狀態。(如下圖,紅色圈出)
-
對紅圈、深藍圈繼續上面的步驟。
練習(字母我自己標的,不一定正確,結果是正確的):
4.4| Implementing Finite Automata – 實現有窮自動機
一個DFA可以用一個2維數組T
實現
一個維度表示狀態
一個維度表示輸入符號
對於每一個轉換 Si --a--> Sk
, 定義T[i,a] = k
根據轉換表A處理輸入字符串(pretty cool)
i = 0; // 初始化指向開始狀態
state = 0; // 表示當前狀態
while(input[i]) { // 對於輸入,更新state
state = A[state][input[i++]];
}
因爲N個狀態的NFA可能對應2^N-1個DFA狀態,所以可以用指針壓縮表,也可以直接將NFA轉換爲表格。
DFA
– 更快、不太緊湊
NFA
– 慢,簡潔