本節書摘來自華章社群《編譯與反編譯技術實戰》一書中的第2章,第2.3節編譯器的設計與實作概述,作者劉曉楠 陶紅偉 嶽峰 戴超,更多章節内容可以通路雲栖社群“華章社群”公衆号檢視
2.3 編譯器的設計與實作概述
根據不同的用途和側重點,編譯程式可以進一步分類,換句話說,有許多不同種類的編譯器變體。譬如:用于幫助程式開發和調試的編譯程式稱為診斷編譯程式,這類編譯器可對程式進行詳細檢查并報告錯誤;另一類側重于提高目标代碼效率的編譯程式稱為優化編譯程式,這類編譯器通常使用多種混合的“變換”來改善程式的性能,但這往往是以編譯器的複雜性和編譯時間的增加為代價的。通常,将運作編譯程式的機器成為主控端,将運作編譯程式所産生的目标代碼的機器稱為目标機。如果一個編譯程式産生不同于其主控端指令集的機器代碼,則稱它為交叉編譯程式(cross compiler)。還有一類編譯器,其目标機器可以改變,而不需要重寫它的與機器無關的元件,這類編譯器稱為可再目标編譯器(retargetable compiler),通常,這類編譯器難以生成高效的代碼,因為其難以利用特殊情況和目标機器特性。目前,很多編譯程式同時提供了調試、優化、交叉編譯等多種功能,使用者可以通過“編譯選項”進行選擇。
編譯器本身也是一個程式,這個程式是怎麼編寫的呢?早期人們使用彙編語言編寫編譯器。雖然用彙編語言編寫的編譯器代碼效率很高,但由于彙編語言程式設計與進階語言程式設計相比難度較大,對編譯器這種複雜的系統編寫起來效率不高,是以,後來人們改用進階語言來編寫編譯器。随着編譯技術的逐漸成熟,一些專門的編譯器編寫工具相繼湧現,比較成熟和通用的工具有詞法分析器生成器(如lex)和文法分析器生成器(如yacc)等。還有一些工具,如用于語義分析的文法制導翻譯工具、用于目标代碼生成的自動的代碼生成器、用于優化的資料流工具等。下面簡單介紹利用一些工具實作一個新的語言編譯器的基本流程。
2.3.1 利用flex和bison實作詞法和文法分析
在unix環境中編寫程式,你往往會邂逅神秘的lex和yacc,而gnu/linux使用者則會邂逅flex和bison。
flex是一個與lex相容的詞法分析器生成器,可以用它來生成一個新的語言的詞法分析器,flex就是由vern paxon實作的一個lex,使用它既可以節省時間,也可以提高正确性。
bison是一個與yacc相容的文法分析器生成器,可以用它來生成一個新的語言的文法分析器,使用它也可以提高正确性并節省開發時間,實際上,bison是一個可以把符合 lalr(1)文法規範的上下文無關文法轉換成 c語言程式的文法分析器生成器,是一個gnu版本的yacc。
實作一種新語言,需要做的工作主要包括設計文法、進行文法制導的翻譯、優化和代碼生成,而後續的工作還可以由llvm的相關工具提供支援。
2.3.2 利用llvm實作代碼優化和代碼生成
llvm是一個包含一系列子產品化可重用編譯器和工具鍊技術的項目。llvm主要的子項目有llvm core libraries、clang、dragonegg、lldb等。其中llvm core libraries
(llvm核心庫)提供了一個不依賴于目标平台的優化器,同時還為許多典型架構的cpu提供了代碼生成的支援。這些庫是圍繞着一個有詳細說明的中間代碼表示形式(llvm ir)建立起來的。也就是說,隻要能夠把待設計的語言翻譯成llvm ir這種中間語言,就可以利用llvm完成代碼優化和代碼生成的工作。當然,這要求目标cpu架構必須是llvm已經支援的,否則就得自己完成代碼生成的工作。clang是一個llvm自身的c/c++/objective-c編譯器,目标是提供快速的編譯。
dragonegg的功能是把llvm的優化器、代碼生成器和gcc 4.5的分析器結合在一起,這樣就使得llvm能夠編譯像ada、fortran等其他gcc編譯器前端支援的語言,且能夠擁有一些clang不支援的c特性(如openmp等)。lldb則是建立在llvm庫和clang之上的一個非常好的本地調試器。