編譯原理: Thompson 構造法(正規表示式 轉 NFA)
編譯原理: Thompson 構造法(正規表示式 轉 NFA)
文章目錄
簡介
編譯過程往往依賴於有限狀態機的構建,其中最具代表性的就是正規表示式(Regular Expression)
,當然有限狀態機的應用不止於此,在詞法、語法分析都佔有很重要的地位。
接下來幾篇將會依序介紹由正規表示式(RegExp)
構建確定有限狀態機(DFA)
的流程:
- Thompson 構造法:正規表示式 RegExp -> 不確定有限狀態機 NFA
- 子集構造法:不確定有限狀態機 NFA -> 確定有限狀態機 DFA
- 最小化:最小化確定有限狀態機 DFA
- 驗證:DFA 轉換為的等價正規表示式並驗證等價
本篇將會介紹解析正規表示式的第一步驟:Thompson 構造法
參考
什麼是NFA(不確定的有窮自動機)和DFA(確定的有窮自動機) | https://www.cnblogs.com/AndyEvans/p/10240790.html |
Thompson構造法 | https://www.beichengjiu.com/mathematics/173003.html |
從正規表示式到NFA:Thompson構造法 | https://www.cnblogs.com/peng-lei/articles/5755107.html |
正文
什麼是狀態機
在開始介紹 Thompson 構造法之前我們先來了解一下 NFA、DFA 究竟是啥,又為啥我們要透過簡介提到的流程來識別正規表示式
- 非確定有限狀態機 NFA = NonDeterministic Finite Automation
- 確定有限狀態機 DFA = Deterministic Finite Automation
兩者的構成元素就是一個有限狀態機 FA = Finite Automation
有限狀態機 FA
我們可以以下列五個元素的集合表示一個有限狀態機:
A = ( S , ∑ , δ , s 0 , F s ) A = (S, \sum, \delta, s0, Fs) A=(S,∑,δ,s0,Fs)
- S S S:狀態集合
- ∑ \sum ∑:輸入的字母表(輸入字元的集合)
- δ \delta δ:狀態轉移函式, δ : S × ∑ → S \delta: S \times \sum \to S δ:S×∑→S
- s 0 s0 s0:初始狀態, s 0 ∈ S s0 \in S s0∈S
- F F F:終止狀態, F ⊆ S F \subseteq S F⊆S
一個有限狀態機從初始狀態 s 0 s0 s0 出發,到終止狀態 F F F 結束,中間透過輸入字元 c ∈ ∑ c \in \sum c∈∑ 和轉移函式 δ \delta δ 決定狀態的變化。
NFA vs DFA
兩種的差別在於確定
和不確定
,也就是對於轉換函式
δ
\delta
δ 的限制:
- DFA 的轉換函式
δ
\delta
δ 對於一組輸入
(
s
,
c
)
,
s
∈
S
,
c
∈
∑
(s,c), s \in S, c \in \sum
(s,c),s∈S,c∈∑ 有
唯一確定
的輸出,即 ∣ δ ( s , c ) ∣ = 1 |\delta(s, c)| = 1 ∣δ(s,c)∣=1 - 而 NFA 的轉換函式對於同一種輸入則可能存在多個
輸出狀態
,即 ∣ δ ( s , c ) ∣ > 0 |\delta(s, c)| > 0 ∣δ(s,c)∣>0
現在我們知道要能夠正確並順序解析正規表示式並加以利用我們需要構建出一個 DFA,因為 NFA 在解析時存在狀態轉換的不確定性
Thompson 構造法
接下來就進入本篇的重點:Thompson 構造法(正規表示式 -> NFA)
Thompson 構造法將定義基本單元
以及三種合併基本單元的原則
,接下來我們使用兩個正規表示式作為例子逐步構造
- a ( b ∣ c ) ∗ a(b|c)* a(b∣c)∗
- ( a ∣ b ) ∗ a b b (a|b)*abb (a∣b)∗abb
基本單元:單個字元
Thompson 構造法的第一步就是先構建所有基本單元
,這邊我們就為符號表中的每一個 符號
c
∈
∑
c \in \sum
c∈∑ 構建一個基本單元
接下來給出兩個例子的基本單元集合
- a ( b ∣ c ) ∗ a(b|c)* a(b∣c)∗
- a ( b ∣ c ) ∗ a(b|c)* a(b∣c)∗
後面我們可以用下面的簡圖簡化基本單元的表示
三種轉換規則:並 |、連線 ⋂ \bigcap ⋂、閉包 *
- 並: a ∣ b a|b a∣b
規則:另外新增一個起始狀態和終止狀態,起始狀態可以轉移到兩個基本單元的起始狀態,兩個基本單元的終止狀態可以轉移到最終終止狀態
- 連線: a b ab ab
規則:連線操作就直接將前一個字元的終止狀態於後一個字元的起始狀態重疊就好了
- 閉包: a ∗ a* a∗
規則:對於一個閉包, a a a 相當於是一個存在起始和終止狀態的單元(可以替換成其他任意組成的複雜單元)可以重複 0 到多次,所以加入一個新的起始狀態和終止狀態,並使得 a a a 的終止狀態能重新回到起始狀態
示例
接下來給出兩個例子使用 Thompson 轉換後的 NFA
a ( b ∣ c ) ∗ a(b|c)^{*} a(b∣c)∗
( a ∣ b ) ∗ a b b (a|b)^{*}abb (a∣b)∗abb
結語
到此我們就完成正規表示式到 NFA 的轉換了,下一篇將延續本篇的結果,將 NFA 裝換成 DFA。
相關文章
- 正規表示式語法(轉)
- 正規表示式匹配原理
- [譯]正規表示式匹配
- 正規表示式語法
- [轉]UltraEdit正規表示式
- 深入正規表示式(3):正規表示式工作引擎流程分析與原理釋義
- 正規表示式的基本語法
- 正規表示式語法介紹
- 正規表示式教程——語法篇
- 正規表示式 轉義字元字元
- c# 正規表示式(轉)C#
- 通過js正規表示式例項學習正規表示式基本語法JS
- 磨練構建正規表示式模式的技能(轉)模式
- java 正規表示式語法學習Java
- 正規表示式
- 揭開正規表示式語法的神秘面紗 (轉)
- 正規表示式使用詳解(轉)
- 常用有效的正規表示式【轉】
- 【譯】JS常用正規表示式備忘錄JS
- 使用正規表示式編寫更好的 SQLSQL
- 使用正規表示式編寫更好的SQLSQL
- 如何編寫python的正規表示式Python
- 【正規表示式】常用的正規表示式(數字,漢字,字串,金額等的正規表示式)字串
- js正規表示式基本語法學習JS
- Java正規表示式的語法與示例Java
- OC 正規表示式的語法及使用
- 從詞法分析到正規表示式(1)詞法分析
- 從詞法分析到正規表示式(2)詞法分析
- [譯]JavaScript的新功能將改變正規表示式的編寫方式JavaScript
- 正規表示式需要轉義的字元字元
- 轉義正規表示式中特殊字元字元
- UltraEdit利用正規表示式查詢(轉)
- 正規表示式中的特殊字元(轉)字元
- JavaScript中的正規表示式(2) (轉)JavaScript
- JavaScript中的正規表示式(1) (轉)JavaScript
- 在JAVA中使用正規表示式 (轉)Java
- 正規表示式學習筆記 (轉)筆記
- 【JavaScript】正規表示式JavaScript