編譯原理: Thompson 構造法(正規表示式 轉 NFA)

超悠閒發表於2020-11-26

編譯原理: Thompson 構造法(正規表示式 轉 NFA)

簡介

編譯過程往往依賴於有限狀態機的構建,其中最具代表性的就是正規表示式(Regular Expression),當然有限狀態機的應用不止於此,在詞法、語法分析都佔有很重要的地位。

接下來幾篇將會依序介紹由正規表示式(RegExp)構建確定有限狀態機(DFA)的流程:

  1. Thompson 構造法:正規表示式 RegExp -> 不確定有限狀態機 NFA
  2. 子集構造法:不確定有限狀態機 NFA -> 確定有限狀態機 DFA
  3. 最小化:最小化確定有限狀態機 DFA
  4. 驗證: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 s0S
  • F F F:終止狀態, F ⊆ S F \subseteq S FS

一個有限狀態機從初始狀態 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),sS,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 構造法將定義基本單元以及三種合併基本單元的原則,接下來我們使用兩個正規表示式作為例子逐步構造

  1. a ( b ∣ c ) ∗ a(b|c)* a(bc)
  2. ( a ∣ b ) ∗ a b b (a|b)*abb (ab)abb

基本單元:單個字元

Thompson 構造法的第一步就是先構建所有基本單元,這邊我們就為符號表中的每一個 符號 c ∈ ∑ c \in \sum c 構建一個基本單元

接下來給出兩個例子的基本單元集合

  1. a ( b ∣ c ) ∗ a(b|c)* a(bc)

  1. a ( b ∣ c ) ∗ a(b|c)* a(bc)

後面我們可以用下面的簡圖簡化基本單元的表示

三種轉換規則:並 |、連線 ⋂ \bigcap 、閉包 *

  • 並: a ∣ b a|b ab

規則:另外新增一個起始狀態和終止狀態,起始狀態可以轉移到兩個基本單元的起始狀態,兩個基本單元的終止狀態可以轉移到最終終止狀態

  • 連線: a b ab ab

規則:連線操作就直接將前一個字元的終止狀態於後一個字元的起始狀態重疊就好了

  • 閉包: a ∗ a* a

規則:對於一個閉包, a a a 相當於是一個存在起始和終止狀態的單元(可以替換成其他任意組成的複雜單元)可以重複 0 到多次,所以加入一個新的起始狀態和終止狀態,並使得 a a a 的終止狀態能重新回到起始狀態

示例

接下來給出兩個例子使用 Thompson 轉換後的 NFA

a ( b ∣ c ) ∗ a(b|c)^{*} a(bc)

( a ∣ b ) ∗ a b b (a|b)^{*}abb (ab)abb

結語

到此我們就完成正規表示式到 NFA 的轉換了,下一篇將延續本篇的結果,將 NFA 裝換成 DFA。

相關文章