天天看點

自己動手構造編譯系統:編譯、彙編與連結1.4 設計自己的編譯系統

<b>1.4  設計自己的編譯系統</b>

  

    根據以上描述,我們意欲構造一個能将進階語言轉化為可執行檔案的編譯系統。進階語言文法由我們自己定義,它可以是c語言文法,也可以是它的一個子集,但是無論如何,該進階語言由我們根據程式設計需要自行設計。另外,我們要求生成的可執行檔案能正常執行,無論它是linux系統的elf可執行檔案,還是windows系統的pe檔案,而本書選擇生成linux系統的elf可執行檔案。正如本章開始所描述的,我們要做的就是:自己動手完成當初單擊“編譯”按鈕時計算機在背後做的事情。

  然而在真正開工之前,我們需要承認一個事實——我們是無法實作一個像gcc那樣完善的工業化編譯器的。是以必須降低編譯系統實作的複雜度,確定實際的工作在可控的範圍内。本書對編譯系統的實作做了如下修改和限制:

  1)預編譯的處理。如前所述,預編譯作為編譯前期的工作,其主要的内容在于宏指令的展開和文本替換。本質上,預編譯器也需要識别源代碼語義,它與編譯器實作的内容十分相似。通過後面章節對編譯器實作原理的介紹,我們也能學會如何構造一個簡單的預編譯器。是以,在進階語言的文法設計中,本書未提供與預編譯處理相關的文法,而是直接對源代碼進行編譯,這樣使得我們的精力更關注于編譯器的實作細節上。

  2)一遍編譯的方式。編譯器的設計中可以對編譯器的每個子產品獨立設計,比如詞法分析器、文法分析器、中間代碼優化器等。這樣做可能需要對源代碼進行多遍的掃描,雖然編譯效率相對較低,但是獲得的源碼語義資訊更完善。我們設計的編譯系統目标非常直接——保證編譯系統輸出正确的可執行檔案即可,是以采用一遍編譯的方式會更高效。

  3)進階語言文法。為了友善大多數讀者對文法分析的了解,我們參考c語言的文法格式設計自己的進階語言。不完全實作c語言的所有文法,不僅可以減少重複的工作量,還能将精力重點放在編譯算法的實作上,而不是複雜的語言文法上。是以在c語言的基礎上,我們删除了浮點類型和struct類型,并将數組和指針的維數簡化到一維。

  4)編譯優化算法。編譯器内引入了編譯優化相關的内容,考慮到編譯優化算法的多樣性,我們挑選了若幹經典的編譯優化算法作為優化器的實作。通過對資料流問題優化算法的實作,可以幫助了解優化器的工作原理,對以後深入學習編譯優化算法具有引導意義。

  5)彙編語言的處理。本書的編譯器産生的彙編指令屬于intel x86處理器指令集的子集,雖然這間接降低了彙編器實作的複雜度,但是不會影響彙編器關鍵流程的實作。另外,編譯器在産生彙編代碼之前已經分析了源程式的正确性,生成的彙編代碼都是合法的彙編指令,是以在彙編器的實作過程中不需要考慮彙編語言的詞法、文法和語義錯誤的情況。

  6)靜态連結方式。本書的編譯系統實作的連結器采用靜态連結的方式。這是因為動态連結器的實作相對複雜,而且其與靜态連結器處理的核心問題基本相同。讀者在了解了靜态連結器的構造的基礎上,通過進一步的學習也可以實作一個動态連結器。

  7)elf檔案資訊。除了elf檔案必需的段和資料,我們把代碼全部存放在“.text”段,資料存儲在“.data”段。按照這樣的檔案結構組織方式,不僅能保證二進制代碼正常執行,也有助于我們更好地了解elf檔案的結構群組織。

  綜上所述,我們所做的限制并沒有删除編譯系統關鍵的流程。按照這樣的設計,是可以允許一個人獨立完成一個較為完善的編譯系統的。

繼續閱讀