編譯原理(一)——詞法分析

版權聲明:本文爲原創文章,未經博主允許不得用於商業用途。

詞法分析

1、基本概念

  • 詞法單元(Token):由詞法單元名和屬性值(可選)組成。其中屬性值用於區分同一符號表中重複的同種詞法單元。
  • 模式(Pattern):描述一類詞法單元可能具有的形勢。
  • 詞素(Lexeme):源程序中的一個字符序列,可以和某個詞法單元的模式匹配,並被詞法分析器識別爲該詞法單元的一個實例。

可以看出,詞法單元、模式和詞素是"一對一對多"的關係,下圖給出了c語言詞法一個示例:

在這裏插入圖片描述

2、概述

詞法分析在編譯器中位於以下位置:

在這裏插入圖片描述

​ 從圖片上可知,詞法分析將字符串形式的源程序解析爲詞法單元,並且生成符號表。具體來說,詞法分析器具有如下作用:

  • 讀入字符流,組成詞素,輸出詞法單元序列

  • 過濾空白、換行、製表符、註釋等

  • 將詞素添加到符號表中

  • 將編譯器生成的錯誤信息和在源程序中的位置聯繫起來(後續)

    從作用可以看出,其工作流程分爲掃描階段(去除註釋、多餘的空白符)和詞法分析(生成詞法單元)階段。

3、正則表達式

​ 這裏所說的正則表達式爲最基本的正則表達式,只包含如下四種運算:並(a|b)、連接(ab)、Kleene閉包(a*)、正閉包(a+)。其中運算優先級爲{‘*’,‘+’}>‘連接’>‘|’。

遞歸定義

​ 正則表達式可以通過遞歸定義,設正則表達式集合爲R,則

  • 空串ϵR\epsilon\in RaΣ,aR\forall a\in \Sigma, a\in R
  • r,sR,(r),(r)(s),(r)(s),(r),(r)+R\forall r,s\in R,(r),(r)(s),(r)|(s),(r)^*,(r)^+\in R

正則定義

爲了書寫方便,主流語言常常使用了正則定義預定義了常用正則串。正則定義規則如下:

按照如下形式定義串:
d1r1, d2r2, d3r3,... d_1\rightarrow r_1,\ d_2\rightarrow r_2,\ d_3\rightarrow r_3,...
其中滿足:

  • did_i爲新符號,不在符號集合Σ\Sigma中,且各不相同
  • rir_i是定義在字母表$\Sigma \bigcup {d_1,d_2,…,d_{i-1}} $上的正則表達式。(避免遞歸定義)

有窮自動機

比正則表達式更加優秀的語言表示方法是有窮自動機。所有的正則表達式都可以用有窮自動機來表示。

一個有窮自動機包含:

  • 有限的狀態集合SS
  • 有限的符號集合Σ\Sigma
  • 轉移函數(可以用狀態表表示)
  • 初始狀態s0s_0(有些有窮自動機可以有多個)
  • 接受狀態集合FF

有窮自動機分爲兩類:

  • 不確定的又窮自動機(Nondeterministic Finite Automate, NFA),即對狀態圖中邊上的標號沒有限制,特別的,同一符號可以出現在離開同一狀態的多條邊上,且空串ϵ\epsilon可以作爲符號出現在邊上。
  • 確定的有窮自動機(Deterministic Finite Automate,DFA),對於每個狀態及一個符號有且只有一條邊。

算法1:NFA到DFA

算法如下:

在這裏插入圖片描述

其中,ϵclosure(s)\epsilon-closure(s)表示NFA中通過空串符可以從s狀態到達的狀態集合,move(T,a)move(T,a)表示T狀態接收到a字符後可達的狀態集合,Dtran[T,a]Dtran[T,a]表示轉換表中T行a列的表項,即T狀態接收到a字符後的下一個狀態。

​ 算法的流程即將0步可達的狀態合併爲同一個狀態,之後不斷遍歷字符集移動到下一個狀態集合,如果之前沒出現過此狀態集合則定義爲DFA中的新的狀態。

例:NFA轉化爲DFA

在這裏插入圖片描述

初始狀態A:ϵclosure(0)={0,1,2,4,7}A:\epsilon-closure(0)=\{0,1,2,4,7\},接受a後可達move(A,a)={3,8}move(A,a)=\{3,8\},因此下一個狀態爲ϵclosure({3,8})={1,2,3,4,6,7,8}\epsilon-closure(\{3,8\})=\{1,2,3,4,6,7,8\},之前沒有出現過,因此作爲DFA中的新狀態B。

按順序計算即可得轉換表:

在這裏插入圖片描述

其中A爲初始狀態,E爲接受狀態。

算法2:正則表達式到NFA

正則表達式到NFA的轉化可以通過對四種運算的遞歸獲得。

  • 基本規則:

    • ϵ\epsilon
      在這裏插入圖片描述
    • aa
      在這裏插入圖片描述
  • 歸納部分

    • sts|t
      在這裏插入圖片描述
    • stst
      在這裏插入圖片描述
    • ss^*
      在這裏插入圖片描述

算法3:DFA狀態數量最小化

  • 把所有可區分的狀態分開 (迭代過程)
    • 基本步驟:ε區分了接受狀態和非接受狀態
    • 歸納步驟:如果s和t是可區分的,且s’到s、t’到t有標號 爲a的邊,那麼s’和t’也是可區分的
  • 最終沒有區分開的狀態就是等價的
例:簡化DFA

在這裏插入圖片描述

如圖,

  • 首先區分接受狀態{A,B,C,D}\{A,B,C,D\}和非接受狀態{E}\{E\}

  • 之後細分第一個集合,根據字符b可以劃分爲{A,B,C}\{A,B,C\}{D}\{D\}(D收到b後移動到可區分狀態E)

  • 之後細分第一個集合,根據字符b可以劃分爲{A,C}\{A,C\}{B}\{B\}(B收到b後到達可區分狀態狀態D)

  • {A,C}\{A,C\}對於任何字符都不可區分,因此可以合併爲一個狀態。簡化完成。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章