詞法分析,是詞法分析器将源程式轉化為線性記号流的過程。該過程中會對各種符号進行分類,比如将變量名換為辨別符。
詞法分析的含義:
- 規定詞形成的規則,定義什麼詞是合法的;
- 根據規則識别輸入的序列(詞法分析),識别合法單詞、指出非法的輸入序列。
詞法分析
模式、記号、單詞
- 模式(Pattern): 産生和識别元素的規則。也就是定義的詞法規則;
- 記号(Token): 按照某個模式(即,規則)識别出的(一組)元素。進行詞法分析時,詞法分析器将程式代碼中的各個部分轉為一個個記号的過程,就是根據規則得到一個記号流的過程;
- 單詞(lexeme): 被識别出的元素自身的值(一個),也稱為詞值。可以了解為源程式中一個個的字元串。
上面三個詞放一起了解:源程式裡面是一個個單詞,我們使用“模式”這個規則,對單詞進行識别、分類,把它們放到相應的記号裡面去。記号是一堆單詞,Pascal 語言的記号舉例如下:
記号的類别 | 單詞舉例 | 模式的非形式化描述 |
---|---|---|
const(01) | const | |
if(03) | if | |
relation(81) | <, <=, =, <>, >, >= | <, <=, =, ... |
id(82) | pi, count, D2 | 字母打頭的字母數字串 |
num(83) | 3.1416, 0, 6.02E23 | 任何數值常數 |
literal(84) | "core dumped" | 雙引号間的任意字元串 |
comment | { x is an integer } | 花括号間的任意字元串 |
- id: 辨別符記号。這裡“字母”需要進行嚴格的形式化描述;
- literal:字面量;
- comment:注釋
單詞的基本分類
- 關鍵字 kw(keyword, reserved word)
- 辨別符 id (identifier)
- 字面量 literal
- 特殊符号 ks (key symbol, special symbol)
例:

記号
記号 = 記号的類别 + 記号的屬性
例如,mycount > 25,由三個記号組成。類别就是上表中對應的類别編号
詞法分析器的作用與工作方式
編譯器中隻有該部分直接接觸源代碼,其他的部分都是通過使用之前的工作成果來間接接觸源代碼。詞法分析器要進行的工作包括:
- 去掉注釋、空格一類的無用部分;
- 處理和平台有關的輸入,比如檔案結束符的不同表示;
- 根據模式識别記号,交給文法分析器;(主要功能)
- 調用符号表管理器/出錯處理器,進行相關處理。
工作方式:
- 詞法分析器單獨進行掃描,生成記号流。再将整個記号流交給文法分析器;
- 詞法分析器作為文法分析器的子程式進行工作,文法分析器調用詞法分析器去讀源程式,得到詞法分析器傳回的記号就拿來構造文法樹。然後用掉了這個記号就再去調用詞法分析器讀新的記号,如此重複;
- 詞法、文法分析器并行工作。兩者有一個共享的記号流,前者不停讀程式、把記号放入記号流,後者不停取記号流來構造文法樹。
模式的形式化描述
字元串與語言
從詞法分析角度來看,語言是記号的集合。
語言 L 是有限字母表 Σ 上有限長度字元串的集合,字母表是字元的集合。
字母表中的字元能夠組成字元串。
例:字母表 Σ={ a, b, c },則其上的語言 L = { ε, a, b, c, aa, ab, ac, ba, bb, bc, ... } (ε為空串,長度為0)
字元串的基本概念
術語 | 示例 |
---|---|
|S| | |abc| = 3 |
ε | |ε| = 0 |
S1S2 | abc def = abcdef |
Sn | (abc)3 = abcabcabc |
S 的字首 X | abc 的字首有:ε, a, ab, abc |
S 的字尾 X | abc 的字尾有:ε, c, bc, abc |
S 的子串 X | abc 的子串有:ε, a, b, c, ... |
S 的真字首 | abc 的真字首有:a, ab(去掉空和全) |
S 的真字尾 | (去掉空和全) |
S 的真子串 | |
S 的子序列 X | abdf 是 abcdef 的一個子序列(和原序列順序相同,可去掉一些字母) |
意義 | |
---|---|
Φ | 空集合 |
{ ε } | 空串是唯一進制素 |
X = L ∪ M | 并: X = { s| s∈L or S ∈M } |
X = L ∩ M | 交:X = { s | s∈L and S ∈M } |
X = LM | 連接配接: X = { st|s∈L and t ∈ M } |
X = L* | (星)閉包:X= L0∪L1∪L2∪... |
X = L+ | 正閉包:X= L1∪L2∪L3∪... |
若 L = {a, b}, M = {c, d}, 則 LM = {ac, bc, ad, bd}, L∪M = Φ
L* = { ε, a, b, aa, bb, ab, ba, aaa, ... }
L+ = { a, b, aa, bb, ab, ba, aaa, ... }
正規式與正規集
正規式是用來描述詞法規則的,也就是描述:記号該長成什麼樣子、數字該長成什麼樣子之類。
正規式(Regular Expression,也叫正規表達式)是在字母表之上的集合——正規式表示集合。
正規式表示的集合叫做正規集,而正規集是語言,是以正規式表示語言。
比如有個正規式是字母 a,那麼正規式 a 表示集合 {a},集合 {a} 就是語言 L(a)。
正規式表示正規集,正規集是與正規式對應的語言。
這兩個概念是詞法分析的基礎。
正規式和正規集的遞歸定義
Σ 是有限字母表,則其上的正規式及其表示的集合(即正規集)遞歸定義如下:
- ε 是正規式,其表示集合(正規集) L(ε) = {ε}
- 若 a 是 Σ 上的字元,則 a 是正規式,它表示集合 L(a)={a}
- 若正規式 r 和 s 分别表示集合 L(r) 和 L(s),則
- r|s 是正規式,表示集合 L(r) ∪ L(s)(“|”在正規式中表示“或”,也可以寫作 r + s )
- rs 是正規式,表示集合 L(r)L(s)(直接将兩個語言拼接起來,也可以寫作 r·s)
- r (正規式是一個星閉包)也是正規式,表示集合(L(r))(L(r)這個語言進行星閉包)
- (r) 是正規式,表示的集合仍然是 L(r)(也就是說正規式 r 外面括上括号得到的 (r) 仍然是正規式,加括号可以用來改變運算次序)
語言是字母表上字元串的集合,而正規式是語言,是以正規式是字母表上字元串的集合。
可以用正規式描述的語言,就是正規語言或正規集
定義的擴充說明
- 運算有優先級和結合性
- 三種運算都有左結合的性質(左結合的意思是,當多個同優先級符号連寫時是從左往右算。如果從右往左算就叫右結合)
- 優先級從高到低:閉包、連接配接、或
正規式中不必要的括号(去掉了也不影響運算順序)是可以省略的。
例:正規式: a|b*c 表示的語言有以下兩種情況:
- 表示一個串:a
- 表示另一個串:以 0 到多個 b 開頭,以 c 結尾
- 正規式的等價
長得不同的正規式可以表示同一個正規集(就像加法中的1+3、2+2都可以表示4一樣),即,同一個正規集可以對應多個正規式。
正規式等價
定義:若正規式 P、Q 表示了同一個正規集,則稱 P、Q 是等價的,記為 P = Q。
【例】: 設字母表 Σ={a, b, c}, 則 Σ 上有:
正規式 | 正規集 |
---|---|
a, b, c | {a}, {b}, {c} |
a|b, b|a | {a}∪{b} = {a, b} |
a(a|b)* | {a, aa, ab, aba, abb, aab, ...},以 a 為首的 ab 串 |
Σ* | {ε, a, b, c, aa, ab, ac, ba, bb, bc, ...} |
【例】:令 L(x) = {a, b}, L(y) = {c, d}
則 L(x|y) = {a, b, c, d}
L(y, x) = {a, b, c, d}
判斷等價性,可以根據定義,證明兩個正規式是否能表達同一個集合;也可以使用正規式的代數性質進行運算比較:
公理 | |
---|---|
r|s = s|r | ( r s ) t = r( s t ) |
r|( s|t ) = ( r|s )|t | ε r = r , r ε = r |
r ( s|t ) = r s | r t | r* = ( r+ | ε ) |
( s|t ) r = s r | t r | r** = r* |
簡言之,就是:
- |可交換、可結合;
- · 對 | 可配置設定;
- · 可結合;
- 幂等
記号的說明
先複讀一遍模式、記号的概念:
- 模式(Pattern): 産生和識别元素的規則,就是定義的詞法規則;
- 記号(Token): 按照某個模式(或規則)識别出的元素(一組)。進行詞法分析時,将程式轉為一個個的記号,就是根據規則得到一個記号流;
正規式可以用于嚴格地規定記号的模式。用正規式說明記号的公式:
記号=正規式 讀作“記号定義為正規式” / “記号是正規式”。不引起混淆的情況下,可以直接把說明記号的公式叫做正規式/規則
e.g. id = a ( a | b )* 讀作:“id定義為a(a|b)*”(這裡的 id 就是一個辨別符了。定義為a開頭的ab串)
【例】記号 relation、id、num 分别是 Pascal 的關系運算符、辨別符和無符号數,它們的正規式表示如下:
relation = < | <= | <> | > | >= | =
id = (a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z)
(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|0|1|2|3|4|5|6|7|8|9)*
num = (0|1|2|3|4|5|6|7|8|9)(0|1|2|3|4|5|6|7|8|9)*
(ε|.(0|1|2|3|4|5|6|7|8|9)(0|1|2|3|4|5|6|7|8|9)*)
(ε|E(+|-|ε)(0|1|2|3|4|5|6|7|8|9)(0|1|2|3|4|5|6|7|8|9)*)
其中,一些東西可以進行簡化描述
簡化描述
- 正閉包:r 表示 L(r) 的正規式,那麼 r+ 就表示 (L(r))+的正規式。
即:r+ = rr = r*r, r = r+|ε
比如:(0|1...|9)(0|1...|9)* 可以化簡為 (0|1...|9)+
- 可預設:r? 表示 L(r)∪{ε} 的正規式。
即:r? = r|ε
比如: E(+|-|ε) 可改寫為:E(+|-)?
上面這些運算中的 +、? 、* 的結合性、優先級相同。
- 字元組。字元組是正規式的一種形式:對于隻由 | 構成的正規表達式 r,可以改寫為[r']:
- r' 可以枚舉:正規式 r = a|b|c 等價于 [abc]
- r' 可以分段:[0123456789abcdefghijklmnopqrstuvwxyz]等價于[0-9a-z]
- 非字元組。這裡的“非”指的是非運算。也就是去掉某部分:
若 [r] 是字元組形式的正規式,則 [^r] 表示 Σ -L(r) 的正規式,例如:
若 Σ={a, b, c, d, e, f, g},則 L(^abc)={d, e, f, g}
- 輔助定義。就是給已有的正規式起個名字,以後可以直接用這個名字指代。
編譯原理筆記2:詞法分析基礎與模式的形式化描述
(如果 digits 不加花括号,那 digits 就是“ digittttt.... ”)
optional_fraction:可選的小數位。小數點如果不加雙引号,在這裡表示任意一個字元。
optional_exponent:可選指數
上面的是 id,下面的是 num