前前後後大概用了半個月,從構思到實現,試過語法分析樹和抽象語法樹,寫起來不是特別順利,然後換了思路,以一種直觀的方式進行詞法分析(可能時間複雜度較高,沒計算過)。
在實現的過程中也發掘到幾篇不錯的blog
表達式 | 匹配 | 例子 |
---|---|---|
c | 單個非運算字符c | a, b, z |
\c | 字符c的字面值 | \\ |
「s」 | 串s的字面值 | ".\「 |
. | 除換行符以外的所有字符 | *.out |
[s] | 字符串s中的任意一個字符 | [abc], [a-z], [0-9] |
[ |
||
r1r2 | r1後加上r2 | abc |
(r) | 與r相同 | (ab) |
r{m, n} | 最少m個,最多n個r重複出現 | r{1, 5} |
r1 | r2 | r1或r2 | a | b |
r* | 和r匹配的零個或多個串連接的串 | a*, [abc]* |
r+ | 和r匹配的一個或多個串連接的串 | a+, [0-9]+ |
r? | 零個或一個r | a?, (ab)? |
註解1:c匹配的是非元標識字符, 即除(\ " . ^ …) 代表特定意義的字符。 \c 匹配的是元標識字符的字面值, 即 ‘.’ 匹配除換行符以外的字符, 加上 ‘\.’ 表示匹配一個小數點 ‘.’ 。
註解2: r*口語爲kleene閉包(克林閉包),r+口語爲正閉包,r?口語爲???(我也不知道)。
註解3:在上個版本中支持[^s],但由於在當前版本改動了規則的繼承層次,導致無法直接實現此功能(或許有方法,笑)。
註解4:構建 ‘.’ 元標識符時,會有bug(繪製出NFA就明白了)。
註解5:在當前版本中,沒有構建符號表,因爲算是測試版本,返回的Token的實例也很‘直接’。
註解6:在當前版本中,有正則表達式到不確定有窮自動機的轉換;不確定的有窮自動機 轉 確定的有窮自動機沒辦法實現,需要一點小改動纔可。子集構造法的三個函數有,轉換類也有(註解了),在正文部分會提及如何。
語法分析樹,抽象語法樹 ,規則與定式
什麼是有限狀態自動機?
|
有限狀態自動機是一個五元組
狀態的非空有窮集合, , 稱爲 的一個狀態
輸入字母表
狀態轉移函數,有時又叫作狀態轉換函數,
的開始狀態,也可叫作初始狀態或啓動狀態,
的終止狀態集合, 被 包含,任給 , 稱爲 的終止狀態
簡要提及:
正則表達式(Regular Expression, RE)
不確定的有限狀態自動機(Nondeterministic Finite Automata,NFA)
確定的有限狀態自動機(Deterministic Finite Automata,DFA)
每個規則類都包含輸入字母表中的一個子集,即
;
每個狀態通過匹配規則到達新的狀態,即
;
說起來比較抽象,其實很容易理解:
例如圖一
,0號狀態可以通過單字符規則(CharacterRule)到達1號狀態
在圖二
中,0號狀態可以通過或規則(OrRule),即0~9中任意一個字符可以到達1號狀態。
圖二
是圖三
的簡化版(防止狀態數過多),雖然狀態數減少,但是在某些時候就不是特別適用了,例如需要轉換爲確定的有窮自動機時,我們知道子集構造法中move函數接受的是單字符(詳情見代碼 SubsetConstruction類),而簡化版本用的是ConjunctionSymRule(連詞符規則),導致不能夠精確匹配,也就不能轉換爲確定的有窮自動機。
爲了生成有限狀態自動機的方便,每個規則可以生成一個模板有限狀態自動機,稱之爲定式。像 , , 這三種閉包都有固定的NFA模板,得到r直接生成即可,即:RE -> NFA
圖四
的正則式爲:
,構建一個單定式有限狀態自動機,0號狀態即Start State,1號狀態即Accept State。
爲圖四
構建一個Kleene閉包,即 r * 。
由規則生成的有限狀態自動機,此自動機包含一個開始狀態和一個接受狀態,不用考慮在開始狀態和接受狀態之間有多少轉換。
講完了在項目中最主要的兩項-規則與定式,其他不是那麼重要,包括輸入文件,雙緩衝區方案等等。
輸入文件: 正則定義文件 和 識別源文件
上面是此次正則定義中的一部分,每行都包含一個正則表達式以及該正則表達式的名稱,形式爲:
如果某個正則表達式A需要使用其他正則表達式B,則B必須在A之前聲明(如digit和number的關係)
識別源文件是正則定義所能表示的語言。
輸出形式:返回識別源中的每個詞素,即正則定義中每個正則表達式能匹配識別源文件中的的最小單位。
輸出中的一部分:
[a-z]
、[0-9]
中的-
符號,表示a1,a2,a3…an,形成一個邏輯上連續的序列時,可以表示爲a1-an。在其中,字符串規則不是必要規則,只是爲了簡化狀態數所用規則。(在用連接定式時,兩個正則式之間需要插入一條空轉換函數,如果類似
double -> double
這條正則式,每個字符構成的單字符規則,在連接時需要插入五個空轉換函數,將多出五個無用狀態。)
!!!
在當前版本中,SimpleRule還包含一個match方法,即有限狀態機上的一個轉換函數,所有繼承SimpleRule的類纔可調用匹配方法。
所有定式都繼承自BaseStereotypeDiagram,每個定式狀態圖包含一個開始狀態和接受狀態,不用考慮在開始狀態和接受狀態之間有多少轉換。
還有一個比較特殊的抽象基類,BaseClosureStereotypeDiagram,所有閉包類都繼承此類。
一共三種基礎定式和三種閉包定式:
SingleStereotypeState 構建
(圖二
連詞符規則也是一條單定式)
OrStereotypeState 構建
ConnectStereotypeState 構建$ r1r2,
KleeneClosureState 構建
PositiveClosureState 構建
ZeroOneClosureState 構建
Production意爲產生式,即一條正則表達式和該正則表達式的名稱,產生式的叫法是在文法中稱呼的,即有:
head稱爲產生式頭部或產生式左部,body稱爲產生式體或產生式右部。
TransitionGraph存放一條規則和一張轉換表,一行正則表達式對應一個TransitionGraph實例。
DeterministicFiniteAutomaton是指DFA,因爲未實現,所以註解了。
傳入一個NFA 生成一張轉換表
雙緩衝區方案,比之另外一個早期實現的C++要稍好(笑)
雙緩衝區blog c++實現
整個項目寫得挺一般的,代碼約2k,功能不算特別完備,bug也挺多(前文那裏列出了)。至於爲什麼寫,是在學編譯原理的時候想找份代碼瞧瞧詞法分析是怎麼回事(龍書有前端代碼demo),可是網上找不到呀!! 然後就寫了一份;可優化的地方還有幾處,如果以後有時間或許會更新,謝謝!
正則表達式,RE,有窮狀態自動機,DFA,NFA
正則表達式轉不確定的有限狀態自動機
詞法分析 JAVA實現