[廢話]
其實寫C語言的解譯器也是出於偶然的原因,本來只是想給自己的編輯器添加指令碼解析的功能,或者簡單的宏調用的功能。結果就想實現簡單的C語言的指令碼解析,後來乾脆就想支援C的全部文法。至今還未完成...前幾天實現了C的先行編譯的部分功能,主要是#define先行編譯宏。
可以下載使用,呵呵:)
[先行編譯]
1. C的先行編譯主要是由代碼中的先行編譯行實現,以#開始的行是預先處理命令列,#前後可出現空白符,一行中可以只有#, 稱為空白行。命令列後面可以有注釋,可以\換行
2. C的先行編譯命令有很多,包括:
#define
#ifdef
#ifndef
#if
#elif
define
#endif
#
##
等等...
現在我僅僅是實現了#define, 包括函數形式的宏調用。
3. #define 宏的特點:
a. 定義式宏,#define後面不是緊跟著(
#define :
"#define" name (sequence-of-tokens)?
b. 函數式好宏,#define後緊跟(
參數不能重名,宏體重可以不用提及所有的參數
調用 1) ( 前可以有空格
2) 參數以 ","來分隔參數列表,但是:macro( fun1(a,b), fun2() );
中的fun1的參數列表不影響參數的解析!!
3) 宏中不會對自己的宏名做進一步擴充: marco( marco(a), b );
這樣子,宏名可以以函數名重複。
#define :
"#define" name"(" (identifier-list)? ")"
[實現方法]
1. 建立一個棧,用於記錄所有的先行編譯行,暫時僅僅記錄#define行。
2. 從頭掃描指令檔,尋找符合的先行編譯行,將其入棧,並作處理。例如:
指令碼: #define MARCO(a,b) ((a)+(b))
那麼,尋找到該行時,必須按照下面的步驟處理:
1) 得到#define 後面的宏名字 MARCO
2) 判斷MARCO後面是否緊跟著 ( 左括弧。如果緊跟著,說明是函數式的宏調用,必須做進一步的解析,否則只要將後面的字元序列儲存到棧中即可。
3) 函數式宏的解析問題。 必須找到調用的參樹,即上述例子中的a、b,並將其也儲存到棧中。然後再將後面的序列((a)+(b))也儲存下來。
3. 宏擴充問題,當掃描檔案是,如果得到的字元是一個標識名,那麼我們必須判斷它是否被定義成宏。如果是,我們必須對它進行宏擴充。例如,我們現在掃描到一個串文本: MARCO( fun(a,b), b );
那麼我們搜尋棧,知道MARCO被定義成函數式的宏,參數列表是a、b。所以繼續往後解析,得到fun(a,b)和b, 替換掉((a)+(b))中的a和b,得到:((fun(a,b))+(b))。
這時,其實事情還沒結束,我們必須對((fun(a,b))+(b))做進一步的宏替換,如果fun又是被定義的一個宏,那麼我們繼續替換它,直至重複檢查,沒有可以替換的宏。
[舉例]
#define MAX 120
#define MARCO(a,b) ((a)+(b))
MARCO( MAX, MARCO(a,b) );
1. 棧的內容:
宏名 參數個數 參數列表 字串序列
MAX 0 120
MARCO 2 a b ((a)+(b))
2. 宏調用MARCO( MAX, MARCO(a,b) );的展開過程:
第一步: ((MAX)+(MARCO(a,b)));
第二步: ((120)+(MARCO(a,b)));
第三步: 繼續替換,發現MARCO和自己同名,不會繼續替換,不然將導致死迴圈。而且,這樣子,宏名可以以函數名重複。
最終結果:((120)+(MARCO(a,b)));