<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

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

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

          ——
          作者: 時間:2007-04-17 來源:嵌入開發(fā)網(wǎng) 收藏

          GNU 家族 GCC 介紹

          作為自由軟件的旗艦項目,Richard Stallman 在十多年前剛開始寫作 GCC 的時候,還只是把它當(dāng)作僅僅一個 C 程序語言的;GCC 的意思也只是 GNU C Compiler 而已。經(jīng)過了這么多年的發(fā)展,GCC 已經(jīng)不僅僅能支持 C 語言;它現(xiàn)在還支持 Ada 語言,C++ 語言,Java 語言,Objective C 語言,Pascal 語言,COBOL 語言,以及支持函數(shù)式編程和邏輯編程的 Mercury 語言,等等。而 GCC 也不再單只是 GNU C 語言的意思了,而是變成了 GNU Compiler Collection 也即是 GNU 編譯器家族的意思了。 

          另一方面,說到 GCC 對于各種硬件平臺的支持,概括起來就是一句話:無所不在。幾乎所有有點實際用途的硬件平臺,甚至包括有些不那么有實際用途的硬件平臺,比如 Don Knuth 設(shè)計的 MMIX 計算機,GCC 都提供了完善的支持。 

          我們在這篇文章中要弄清楚的就是 GCC 是如何做到能夠支持這么多種程序語言的。所謂的 GCC 的程序語言前端到底是怎么回事。如果我們要設(shè)計實現(xiàn)自己的編程語言的話,應(yīng)該從何入手。回答這些問題的第一步,就是分析清楚 GCC 源碼包中,為了說明 GCC 的程序語言前端的編寫方法,而寫作的 Treelang 編程語言在 GCC 中的實現(xiàn)細節(jié)。 

          如果把我們自己的程序語言的實現(xiàn)建立于 GCC 之上,也立刻使得我們的程序語言的實現(xiàn)版本可以運行在幾乎所有有用的硬件平臺之上。這對于程序語言的作者來說,也是一個確實的有極大誘惑力的好處。 

          關(guān)于代碼分析

          在這一小節(jié)里面我們著重說明兩個問題:第一、為什么要閱讀源代碼;第二、代碼分析應(yīng)該怎么寫。 

          閱讀源代碼對提高自己的編程水平是非常有幫助的。這個幫助至少體現(xiàn)在兩個方面。第一個方面是學(xué)會大型軟件項目設(shè)計的模式。這樣的模式是真實可靠的第一手資料,這樣學(xué)來的模式要比從書本上,用日常語言陳述的模式,更能深入到你的腦海中去。而且它的真實性和可靠性都是有保證的。并且這樣的模式還非常的具體。我曾經(jīng)看到計算機系的同學(xué)推薦去讀亞歷山大的建筑學(xué)方面的經(jīng)典著作;個人以為這是走的太遠了。與其去讀建筑學(xué)的書,不如去分析一下成功的自由軟件項目的源代碼。具體的用代碼說明的模式,無論如何要比虛無飄渺的美學(xué)概念,或者模棱兩可的工程紀(jì)律,都要更加容易學(xué)習(xí)吧? 

          閱讀源代碼的第二個好處,是增加自己的自信心。就象學(xué)習(xí)英語,要和別人談話,要看看別人的文章,不能只是看教科書上的簡單的例子。教科書上的例子限于篇幅,不可能做到像真實、完整的英文小說那樣,把一個完整的設(shè)計呈現(xiàn)在你的面前。只有當(dāng)你硬著頭皮,拋開字典,把一本英文小說生生啃下來之后,你才能有把握說:我的確能做到。類似的,只有當(dāng)我們看過大型軟件項目的源代碼,作過修改,摸爬滾打之后,我們才能有把握的說:我也能寫出來。 

          上面說了閱讀源代碼至少有這么兩個好處。那么在閱讀源代碼的時候,我們必然要做代碼分析筆記。這個代碼分析筆記如何寫,這就是我們關(guān)心的一個問題了。在這里,我提出一些我自己的也許不太成熟的看法,也請讀者朋友們不吝指教。 

          我總覺得,與其作一行一行的代碼注釋,說明每一行代碼的作用;不如設(shè)計一個故事,把代碼的框架說清楚。這也是我前面提到的,所謂模式一說。因為閱讀源代碼,最關(guān)鍵的是要了解大型軟件項目設(shè)計的模式,而不是要把每一次讀者分析每一行代碼細節(jié)的樂趣從此剝奪掉。 

          另一方面,代碼分析的寫作風(fēng)格,可以是參考手冊似的;也可以是航海日志似的。我個人覺得參考手冊似的代碼分析是比較乏味的,讀起來乏味,寫起來也不免乏味,雖然它可能更有用。對于一個急著要快點結(jié)束加班工作的軟件工程師來說,也許參考手冊更加實用。但是對于一個想要了解這一份成功的軟件背后的工作奧秘的探索者來說,一個航海日志似的代碼分析,也許讀起來更有味道,更能讓一個程序員在鍵盤與屏幕之間,體會到那地理大發(fā)現(xiàn)的激動與樂趣。 

          Treelang 的代碼框架

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

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

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

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

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

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



          評論


          相關(guān)推薦

          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();