詞法分析是編譯原理中最容易理解的,就算沒有了解過編譯原理,也能寫出一個詞法分析器。我們不用理解正則表達式,不用理解狀態機原理,就可以輕松的完成詞法的分析。
這里首先介紹下自頂向下的解析過程,所謂的自頂向下,按我的理解,就是從一個大的集合解析到小的集合。例如:解析一個文件,那么進入文件,解析一個函數,進入一個函數,解析局部變量,解析表達式,進入表達式,解析變量、常量等等,最終完成一個C文件的解析過程。整個過程,其實就是一個猜測的過程。但是這個過程中,我們必須依賴於文件中的每個詞(token),token可以看成是解析過程中的一個單位。
例如:
1. 關鍵詞有:int char double long for while ......
2. 運算符有:+ - * / ......
3. 數字常量:12 0x34 3.45
4. 字符串 :"hello"
...
等等.
那么我們必須實現一個函數get_token,執行這個函數,我們獲取文件中的一個token。例如現在一個C文件:
int main(int agrc, char **argv ){
return 0;
}
那么多次執行get_token,分別得到的token為:
int
main
( <----③
int
argc
...
...
除了一個get_token函數外,還需要一個叫做put_back的函數,因為腳本解析是一個猜測的過程。有時候我們必須知道下一個的token是什么,才能判斷該走哪個分支。還是上面的例子,在③的地方,我們得到了"(",所以知道main是一個函數,那么如果該token不是"(", 而是"=", 我們知道它不是一個函數,而是一個基本的變量定義,並且需要初始化。那么我們必須調用put_back函數,把該token重新放到緩存中,使得下次get_token的時候,還會拿到這個token,而不是下個token。
至於get_token和put_back函數如何實現,我就不多說了。我使用了最笨的方法,無非就是每個字符一個一個的向后掃描,判斷是該返回什么標示。每個token被分為各種類型token_type:
enum tok_types{ DELIMITER = 1, IDENTIFIER, KEYWORD, TEMP, STRING, CHARACTOR, NUMBER, TYPE, BLOCK, PRECOMPILE };
類型 意義 例如
-----------------------------------------------------------------------------
DELIMITER 標示分隔符 ; | + -
IDENTIFIER 標示ID標示符 var hello
KEYWORD 關鍵字 int char while do
STRING 字符串 "string"
CHARACTOR 字符 'c'
NUMBER 數字常量 123 012 0x34
TYPE 類型 typedef int int32; 那么int32就被標示為TYPE
BLOCK 塊標志 { }
PRECOMPILE 預編譯行 #define
TEMP 保留
詞法分析的目的就是掃描源碼,區分出這些類型,變返回該token。供解釋器的其他模塊使用。