為了將一個程序從一種語言翻譯成另一種語言,編譯器必須首先把程序的各種成分拆開,並搞清其結構和含義,然後再用另一種方式把這些成分組合起來。編譯器的前端執行分析,後端進行合成。
而分析一般分為 3 種:詞法分析 句法分析 語義分析
本階段進行的是詞法分析,目的是將輸入文件分解成一個個獨立的詞法符號,即單詞。
根據虎書的提示,在本階段分了三個模塊:
1. 錯誤處理模塊(errormsg.c errormsg.h):用來產生含文件名和行號的報錯信息
2. 詞法分析模塊(lexical.lex token.h):通過 Lex 進行詞法分析
3. 常用工具模塊(util.c util.h):定義一些常用的函數
詞法分析模塊與錯誤處理模塊:兩者通過 errormsg.h 中聲明的變量和函數進行通信:EM_tokPos 變量傳遞每個單詞以字符為單位的位置;EM_newline () 函數記錄行號;EM_error () 輸出報錯信息。
錯誤處理模塊與常用工具模塊:錯誤處理模塊使用 util.h 中聲明的 checked_malloc () 分配內存函數
另外還包含了 驅動程序(driver.c)測試文件(test.c) makefile
下面主要介紹本階段最重要的詞法分析模塊。
tokens.h:定義詞法單詞常量以及 yylval
上述代碼定義了 yylval,yylval 是一個表示不同語義值的集合,其中的 ival cval dval sval 分別用來保存 整數 字符 浮點數 字符串 單詞的語義值。
這段定義了一些常數,這些常數供 lexical.lex 使用,它們指明被匹配的是何種類型的單詞。
lexical.lex:Lex 的源文件,可以通過 Lex 生成一個詞法分析器
Lex 是一個可以將正則表達式轉換成詞法分析器的生成器,它由詞法規範生成一個 C 程序(lex.yy.c)。該規範包含一個正則表達式和一個動作。這個動作將單詞類型(可能和其他信息一起)傳給編譯器的下一處理階段。
第一部分,即位於 %{...%} 之間的部分,包含有若干由此文件其餘部分 C 代碼使用的 include 和聲明。
第二部分,即位於 %}...%% 之間的部分,包含正則表達式的簡寫形式和狀態說明,比如你可以寫上
那麼第三部分中就可以用 {digits} 代替 [0-9]+ 了。
第三部分,即位於 %% 後面的部分,包含正則表達式和動作。每個動作返回一個 int 類型的值(token.h 定義的常數),指出匹配的是哪一種單詞。
其中有兩條匹配的原則來消除二義性:
規則優先:對於一個特定的最長初始子串,第一個與之匹配的正則式決定這個子串的單詞類型;
最長匹配:通過規則優先確定正則式之後,子串取與正則式匹配的最長的字符串。
幾個變量:yytext 是正則式匹配的字符串;yyleng 是所匹配的字符串的長度;charPos 追蹤每一個單詞的位置,並告知 EM_tokPos。
詞法分析 Done.