新聞中心

EEPW首頁(yè) > 探索 GCC 前端的內(nèi)部結(jié)構(gòu)(二)

探索 GCC 前端的內(nèi)部結(jié)構(gòu)(二)

——
作者: 時(shí)間:2007-04-17 來(lái)源:嵌入開(kāi)發(fā)網(wǎng) 收藏
Treelang 的代碼框架

讀者朋友們?cè)陂喿x這一部分代碼分析的時(shí)候,手邊最好能準(zhǔn)備上一份 GCC 3.3 的源代碼。這個(gè)源代碼可以從 GCC 的站點(diǎn) http://gcc.gnu.org上獲得。本文作者力圖做到把整個(gè)情況像說(shuō)故事一樣娓娓道來(lái),但是讀者朋友們?nèi)绻谶m當(dāng)?shù)臅r(shí)候能夠查閱一下源代碼,可能更能把問(wèn)題了解的清楚透徹。 

這個(gè) treelang 語(yǔ)言的實(shí)現(xiàn),主要有兩個(gè) C 語(yǔ)言文件,把整個(gè)代碼框架分成兩個(gè)部分。第一部分以 tree1.c 為主,帶上 parse.y 這個(gè) YACC 源程序,組成了和 GCC 前端的接口;第二部分以 treetree.c 為主,組成了和 GCC 后端的接口。 

這里首先說(shuō)明一下 tree1.c 這個(gè)文件。它和上級(jí)目錄中的 GCC 框架文件 toplev.c 交互作用,實(shí)現(xiàn) tree1 這個(gè)執(zhí)行程序的主體部分。這個(gè) tree1 就相當(dāng)于 GCC 的 C 語(yǔ)言前端中的 cc1 執(zhí)行程序,該程序是 C 語(yǔ)言前端的主體。 

我們首先試圖說(shuō)明從 toplev.c 到 tree1.c 的路徑。這樣我們就注意到 toplev.c 中這個(gè)引人注目的 lang_hooks 變量。當(dāng)然,接下來(lái)就注意到在 toplev.c 同一目錄下的 langhooks.c 這個(gè)文件。我們希望在其中發(fā)現(xiàn)一點(diǎn)有趣的東西。這一共是三個(gè)文件:langhooks.[ch] 和 langhooks-def.h 其中在 langhooks.h 中定義了一堆各式各樣的 struct lang_hooks_for_xxx 結(jié)構(gòu),以及最后還有一個(gè) struct lang_hooks 結(jié)構(gòu)把前面的那些 for_xxx 的結(jié)構(gòu)都總括了起來(lái)。這每一個(gè)結(jié)構(gòu)都是若干個(gè)至少看上去像是回調(diào)函數(shù)的函數(shù)指針??磥?lái)這就是我們要尋找的東西。那么大概就是這樣了,前端向 GCC 主體部分注冊(cè)自己的 lang_hooks 來(lái)完成各樣的任務(wù)。接下來(lái)一個(gè)自然的問(wèn)題就是這個(gè)注冊(cè)是如何進(jìn)行的;另外一個(gè)問(wèn)題就是要對(duì)這些回調(diào)函數(shù)指針進(jìn)行分析了。 

這個(gè) langhooks.h 文件中關(guān)于 struct lang_hooks 結(jié)構(gòu)字段的注釋很詳細(xì),這里我們暫時(shí)先跳過(guò)去。等到 treelang 中具體的注冊(cè)回調(diào)函數(shù)出現(xiàn)的時(shí)候,我們根據(jù)需要再做仔細(xì)說(shuō)明。在 langhooks-def.h 文件中定義了一些這個(gè) struct lang_hooks 結(jié)構(gòu)的默認(rèn)值。 

現(xiàn)在我們進(jìn)入 treelang 目錄下的 treetree.c 這個(gè)文件。來(lái)察看一下在 treelang 中對(duì) struct lang_hooks 這個(gè)結(jié)構(gòu)的初始化過(guò)程。這個(gè)過(guò)程不是按照我們通常所熟悉的 C 語(yǔ)言的 C99 標(biāo)準(zhǔn)或者是 GCC 擴(kuò)展語(yǔ)法來(lái)進(jìn)行的。而是采用了大量的 #define 和 #undef 并結(jié)合上層目錄中的 langhooks-def.h 來(lái)進(jìn)行。細(xì)想一下,這是理所當(dāng)然的事情,因?yàn)檫@是在編譯 C 語(yǔ)言本身嘛。當(dāng)然就不好用到 C 語(yǔ)言的新的東西或者是自己做的擴(kuò)展的東西。 

注釋開(kāi)始::::: 

我們以初始化如下定義的 struct sample 結(jié)構(gòu)為例。



struct sample {
        int member_int;
        char *member_str;
        void (*member_fun)(void);
};

 


在 C99 中,初始化一個(gè) struct 結(jié)構(gòu)數(shù)據(jù),使用下面這樣的語(yǔ)法。 



struct sample inst_c99 = {
        .member_int = 78,
        .member_str = "iloveqhq",
        .member_fun = real_fun,
};

 


在 C99 標(biāo)準(zhǔn)出現(xiàn)之前,GCC 定義了自己的擴(kuò)展,下面的例子就是按照這個(gè) GCC 對(duì) C 語(yǔ)言的擴(kuò)展,來(lái)初始化一個(gè) struct 結(jié)構(gòu)數(shù)據(jù)。 



struct sample inst_gcc = {
        member_int: 76,
        member_str: "zhaoway",
        member_fun: real_fun,
};

 


在 GCC 的源代碼中沒(méi)有使用上面的兩種辦法,而是大量使用了宏定義。這個(gè)辦法首先要申明一份輔助的宏定義。這些個(gè)輔助的宏定義,在一個(gè)軟件項(xiàng)目里面,針對(duì)一個(gè) struct 結(jié)構(gòu),只需要一份即可。 



#define MEMBER_INT 0
#define MEMBER_STR ""
#define MEMBER_FUN NULL
                                                                                      
#define SAMPLE_INITIALIZER {   
        MEMBER_INT,            
        MEMBER_STR,            
        MEMBER_FUN,            
}

 


按照上面這樣的辦法申明了這些關(guān)于這個(gè) struct sample 的輔助宏定義以后,在每次要初始化一個(gè) struct sample 數(shù)據(jù)結(jié)構(gòu)的時(shí)候,只需要按照如下操作即可。除了要稍微多打一些字以外,這個(gè)方法的方便程度和以上兩種方法是差不多的。 



#undef MEMBER_INT
#define MEMBER_INT 12
#undef MEMBER_STR
#define MEMBER_STR "trtr"
#undef MEMBER_FUN
#define MEMBER_FUN real_fun
struct sample inst_def = SAMPLE_INITIALIZER;

 


這樣就也可以像 C99 標(biāo)準(zhǔn)或者 GCC 的擴(kuò)展一樣,按照成員變量的名稱(chēng)來(lái)初始化一個(gè) struct 類(lèi)型的數(shù)據(jù)結(jié)構(gòu)了。不過(guò)話又說(shuō)回來(lái),在我們一般的軟件項(xiàng)目中,還是應(yīng)該沿著 C99 標(biāo)準(zhǔn)這個(gè) C 語(yǔ)言的發(fā)展方向來(lái)走的。 

:::::注釋結(jié)束 

接下來(lái)的線路很清楚,就是一個(gè)一個(gè)的分析這些個(gè)回調(diào)函數(shù)啦。 


評(píng)論


相關(guān)推薦

技術(shù)專(zhuān)區(qū)

關(guān)閉