2、正則表達式
我們現在需要尋找一種可以描述記號類型的工具,在此之前我們首先研究一下常見的記號的結構。為了表示出具有某種共性的字符串的集合,我們需要書寫出一些能代表字符串集合的規則。這個集合中的所有成員都將被認為是一種特定類型的記號。
首先,規則可以把一個特定的字符或者是空字符串認為是一種類型的記號的全部。上文所說到的四則運算式子的例子,“左括號”這種類型的記號就僅僅對應着字符”(“,其他的字符或者字符串都不可能是“左括號”這個類型的記號。
其次,規則可以進行串聯。串聯的意思是這樣的,我們可以讓一個字符串的前綴符合某一個指定的規則,剩下的部分的前綴符合第二個規則,剩下的部分的前綴符合第三個規則等等,一直到最后一個部分的全部要符合最后一個規則。如果我們把”function”這個字符串作為一個記號類型來處理的話,我們可以把”function”這個字符串替換成8個串聯的規則:”f”,”u”,”n”,”c”,”t”,”i”,”o”,”n”。首先,字符串”function”的前綴”f”符合規則”f”,剩下的部分”unction”的前綴”u”符合規則”u”,等等,一直到最后一個部分”n”的全部符合規則”n”。
第三,規則可以進行並聯。並聯的意思就是,如果一個字符串符合一系列規則中的其中一個的話,我們就說這個字符串符合這一些規則的並聯。於是這些規則的並聯就構成了一個新的規則。一個典型的例子就是判斷一個字符串是否關鍵字。關鍵字可以是”if”,可以是”else”,可以是”while”等等。當然,一個關鍵字是不可能同時符合這些規則的,不過只要一個字符串符合這些規則的其中一個的話,我們就說這個字符串是關鍵字。於是,關鍵字這個規則就是”if”、”else”、”while”等規則的並聯。
第四,一個規則可以是可選的。可選的規則實際上是屬於並聯的一種特殊形式。加入我們需要規則”abc”和”abcde”並聯,我們會發現這兩個規則有着相同的前綴”abc”,而且這個前綴恰好就是其中的一個規則。於是我們可以把規則改寫成”abc”與””和”de”的並聯的串聯。但是規則””指定的規則是空串,因此這個規則與”de”的並聯就可以看成是一個可選的規則”de”。
第五,規則可以被重復。有限次的重復可以使用串聯表示,但是如果我們不想限制重復的次數的話,串聯就沒法表示這個規則了,於是我們引入了“重復”。一個典型的例子就是程序設計語言的標識符。標識符可以是一個變量的名字或者是其他東西。一門語言通常沒有規定變量名的最大長度。因此為了表示這個規則,就需要將52個字母進行並聯,然后對這個規則進行重復。
上述的5種構造規則的方法中,后面的4個方法被用於把規則組合成為更大的規則。為了給出這種規則的形式化表示,我們引入了一種范式。這種范式有以下語法:
1:字符用雙引號包圍起來,空串使用ε代替。
2:兩個規則頭尾連接代表規則的串聯。
3:兩個規則使用 | 隔開代表規則的並聯。
4:規則使用[]包圍代表該規則是可選的,規則使用{}包圍代表該規則是重復的。
5:規則使用()包圍代表該規則是一個整體,通常用於改變操作符 | 的優先級。
舉個例子,一個實數的規則書寫如下:
{“0”|”1”|”2”|”3”|”4”|”5”|”6”|”7”|”8”|”9”}”.”[{“0”|”1”|”2”|”3”|”4”|”5”|”6”|”7”|”8”|”9”}]。
但是,我們如何表示“不是數字的其他字符呢”?字符的數量是有限的,因此我們可以使用規則的並聯來表示。但是所有的字符實在是太多(ASCII字符集有127個字符,UTF-16字符集有65535個字符),因此后來人們想出了各種各樣的簡化規則書寫的辦法。比較著名的有BNF范式。BNF范式經常被用於理論研究,但是更加實用的是正則表達式。
正則表達式的字符不需要用雙引號括起來,但是如果需要表示一些被定義了的字符(如 “|” )的話,就使用轉義字符的方法表示(如 “/|”)。其次,X?代表[X],X+代表{X},X*代表[{X}]。字符集合可以用區間來表示,[0-9]可以表示“0”|”1”|”2”|”3”|”4”|”5”|”6”|”7”|”8”|”9”,[^0-9]則表示“除了數字以外的其他字符”。正則表達式還有各種各樣的其他規則來簡化我們的書寫,不過由於本文並不是“精通正則表達式”,因此我們只保留若干比較本質的操作來進行詞法分析原理的描述。
正則表達式的表達能力極強,小數的規則可以使用[0-9]+.[0-9]來表示,C語言的注釋可以表示為//*([^/*]|/*+[^/*/])*/*+/來表示。