編輯推薦
                                      深入剖析現代編譯器運用的算法和技術
  強調代碼優化和代碼生成
  體現編譯原理教學的理念                 
內容簡介
     1952年一個編譯器誕生,至今已經過去瞭半個多世紀,編譯器的發展日臻成熟,關於編譯器設計的著作也齣版瞭不少,但既關注設計細節,又具備大局觀的經典之作鳳毛麟角,《編譯器設計(第2版)》即是這樣一本難得的佳作。
兩位作者多年來一直奮戰在研發和教學一綫,理論和實踐上的豐厚經驗都凝結在瞭《編譯器設計(第2版)》中。書中論述瞭一係列構建現代編譯器必需的核心技術,分析瞭編譯器設計者需要麵對的諸多問題,闡釋瞭解決這些問題所用到的一些知識點。第2版是時隔8年之後全新修訂的版本,充分展現瞭編譯器構造技術的進展。作者重寫瞭書中全部示例,並特彆改進瞭闡述順序,使得章與章之間的內容更具連續性,也更適閤專業人士將這本高校教材作為參考書。
 
     作者簡介
     Keith D. Cooper,萊斯大學計算機科學係計算工程專業Doerr特聘教授,曾任該係係主任。Cooper博士的研究課題涵蓋過程間數據流分析、標量指令優化、寄存器分配以及指令調度等方麵。
  Linda Torczon,萊斯大學計算機科學係高級研究員。Torczon的研究內容主要包括代碼生成、過程間數據流分析和優化、編程環境。
  譯者簡介:
  郭旭,資深軟件設計師。主要興趣是復雜軟件係統的分析和設計,目前從事高性能數據集成工具的研發。譯有《深入Linux內核架構》、《C語言接口及實現》等書。     
精彩書評
     “編譯器是一個內容豐富的研究領域,將整個計算機科學融匯在一個優雅的構造中。Cooper和Torczon的這本書很受歡迎,可以指導讀者輕鬆學習編譯器這種軟件係統,新版增加瞭兩位作者的一些設計經驗,並明確指齣瞭許多必須注意的細節,同時又不忘強調設計的大局觀。對任何不熟悉編譯器的人來說,本書都是不可多得的參考手冊。”
  ——Michael D. Smith,哈佛大學文理學院院長,工程與應用科學John H. Finley Jr.講席教授  
  “本書是構建現代優化編譯器的指南。作者汲取瞭編譯器構建領域大量的經驗,以幫助學生掌握整體設計思路,同時引導學生瞭解構建有效的優化編譯器所必需的許多重要而微妙的細節。尤其值得一提的是,在我讀過的書中,本書對靜態單賦值形式的闡述為清晰。”
  ——Jeffery von Ronne,得剋薩斯大學聖安東尼奧分校計算機科學係助理教授  
  “本書采用瞭更常規且一緻的結構,還包含大量輔助教學的內容,如復習題、附加示例、術語解釋和文本框說明等,這提升瞭它作為教科書的價值。本書還包括大量技術上的更新,包括非傳統語言、實際編譯器和編譯器技術非傳統用途方麵的更多內容。優化方麵的內容是第1版的特色,這一版中變得更為清晰易讀。”
  ——Michael L. Sccot,羅徹斯特大學計算機科學係教授,Programming Language Pragmatics的作者  
  “Keith Cooper和Linda Torczon不僅很好地講述瞭編譯器的曆史,也從實踐者的角度闡述瞭如何開發編譯器。書中包括瞭大量頗具實用價值的討論和說明,既涉及理論,也涉及眾多現存編譯器的實例(如Lisp、FORTRAN等)。對入門和高級“分配”與“優化”概念的全麵討論,實際上涵蓋瞭編譯器設計的整個生命周期。對於計算機科學專業的學生以及編譯器設計和開發人員來說,本書都是必備參考書。”
  ——David Orleans,諾瓦東南大學  
  “這本書寫得實在是棒極瞭,內容翔實,輔以大量圖錶和示例說明,作為大學編譯器課程的教科書和從業人員的參考書再閤適不過瞭。代碼優化是其重點。”
  ——Reviews網站     
目錄
   第1章  編譯概觀
1.1  簡介
1.2  編譯器結構
1.3  轉換概述
1.3.1  前端
1.3.2  優化器
1.3.3  後端
1.4  小結和展望
第2章  詞法分析器
2.1  簡介
2.2  識彆單詞
2.2.1  識彆器的形式化
2.2.2  識彆更復雜的單詞
2.3  正則錶達式
2.3.1  符號錶示法的形式化
2.3.2  示例
2.3.3  RE的閉包性質
2.4  從正則錶達式到詞法分析器
2.4.1  非確定性有限自動機
2.4.2  從正則錶達式到NFA:Thompson構造法
2.4.3  從NFA到DFA:子集構造法
2.4.4  從DFA到最小DFA:Hopcroft算法
2.4.5  將DFA用做識彆器
2.5  實現詞法分析器
2.5.1  錶驅動詞法分析器
2.5.2  直接編碼的詞法分析器
2.5.3  手工編碼的詞法分析器
2.5.4  處理關鍵字
2.6  高級主題
2.6.1  從DFA到正則錶達式
2.6.2  DFA最小化的另一種方法:Brzozowski算法
2.6.3  無閉包的正則錶達式
2.7  小結和展望
第3章  語法分析器
3.1  簡介
3.2  語法的錶示
3.2.1  為什麼不使用正則錶達式
3.2.2  上下文無關語法
3.2.3  更復雜的例子
3.2.4  將語義編碼到結構中
3.2.5  為輸入符號串找到推導
3.3  自頂嚮下語法分析
3.3.1  為進行自頂嚮下語法分析而轉換語法
3.3.2  自頂嚮下的遞歸下降語法分析器
3.3.3  錶驅動的LL(1)語法分析器
3.4  自底嚮上語法分析
3.4.1  LR(1)語法分析算法
3.4.2  構建LR(1)錶
3.4.3  錶構造過程中的錯誤
3.5  實際問題
3.5.1  齣錯恢復
3.5.2  一元運算符
3.5.3  處理上下文相關的二義性
3.5.4  左遞歸與右遞歸
3.6  高級主題
3.6.1  優化語法
3.6.2  減小LR(1)錶的規模
3.7  小結和展望
第4章  上下文相關分析
4.1  簡介
4.2  類型係統簡介
4.2.1  類型係統的目標
4.2.2  類型係統的組件
4.3  屬性語法框架
4.3.1  求值的方法
4.3.2  環
4.3.3  擴展實例
4.3.4  屬性語法方法的問題
4.4  特設語法製導轉換
4.4.1  特設語法製導轉換的實現
4.4.2  例子
4.5  高級主題
4.5.1  類型推斷中更睏難的問題
4.5.2  改變結閤性
4.6  小結和展望
第5章  中間錶示
5.1  簡介
5.2  圖IR
5.2.1  與語法相關的樹
5.2.2  圖
5.3  綫性IR
5.3.1  堆棧機代碼
5.3.2  三地址代碼
5.3.3  綫性代碼的錶示
5.3.4  根據綫性代碼建立控製流圖
5.4  將值映射到名字
5.4.1  臨時值的命名
5.4.2  靜態單賦值形式
5.4.3  內存模型
5.5  符號錶
5.5.1  散列錶
5.5.2  建立符號錶
5.5.3  處理嵌套的作用域
5.5.4  符號錶的許多用途
5.5.5  符號錶技術的其他用途
5.6  小結和展望
第6章  過程抽象
6.1  簡介
6.2  過程調用
6.3  命名空間
6.3.1  類Algol語言的命名空間
6.3.2  用於支持類Algol語言的運行時結構
6.3.3  麵嚮對象語言的命名空間
6.3.4  支持麵嚮對象語言的運行時結構
6.4  過程之間值的傳遞
6.4.1  傳遞參數
6.4.2  返迴值
6.4.3  確定可尋址性
6.5  標準化鏈接
6.6  高級主題
6.6.1  堆的顯式管理
6.6.2  隱式釋放
6.7  小結和展望
第7章  代碼形式
7.1  簡介
7.2  分配存儲位置
7.2.1  設定運行時數據結構的位置
7.2.2  數據區的布局
7.2.3  將值保持在寄存器中
7.3  算術運算符
7.3.1  減少對寄存器的需求
7.3.2  訪問參數值
7.3.3  錶達式中的函數調用
7.3.4  其他算術運算符
7.3.5  混閤類型錶達式
7.3.6  作為運算符的賦值操作
7.4  布爾運算符和關係運算符
7.4.1  錶示
7.4.2  對關係操作的硬件支持
7.5  數組的存儲和訪問
7.5.1  引用嚮量元素
7.5.2  數組存儲布局
7.5.3  引用數組元素
7.5.4  範圍檢查
7.6  字符串
7.6.1  字符串錶示
7.6.2  字符串賦值
7.6.3  字符串連接
7.6.4  字符串長度
7.7  結構引用
7.7.1  理解結構布局
7.7.2  結構數組
7.7.3  聯閤和運行時標記
7.7.4  指針和匿名值
7.8  控製流結構
7.8.1  條件執行
7.8.2  循環和迭代
7.8.3  case語句
7.9  過程調用
7.9.1  實參求值
7.9.2  保存和恢復寄存器
7.10  小結和展望
第8章  優化簡介
8.1  簡介
8.2  背景
8.2.1  例子
8.2.2  對優化的考慮
8.2.3  優化的時機
8.3  優化的範圍
8.4  局部優化
8.4.1  局部值編號
8.4.2  樹高平衡
8.5  區域優化
8.5.1  超局部值編號
8.5.2  循環展開
8.6  全局優化
8.6.1  利用活動信息查找未初始化變量
8.6.2  全局代碼置放
8.7  過程間優化
8.7.1  內聯替換
8.7.2  過程置放
8.7.3  針對過程間優化的編譯器組織結構
8.8  小結和展望
第9章  數據流分析
9.1  簡介
9.2  迭代數據流分析
9.2.1  支配性
9.2.2  活動變量分析
9.2.3  數據流分析的局限性
9.2.4  其他數據流問題
9.3  靜態單賦值形式
9.3.1  構造靜態單賦值形式的簡單方法
9.3.2  支配邊界
9.3.3  放置 函數
9.3.4  重命名
9.3.5  從靜態單賦值形式到其他形式的轉換
9.3.6  使用靜態單賦值形式
9.4  過程間分析
9.4.1  構建調用圖
9.4.2  過程間常量傳播
9.5  高級主題
9.5.1  結構性數據流算法和可歸約性
9.5.2  加速計算支配性的迭代框架算法的執行
9.6  小結和展望
第10章  標量優化
10.1  簡介
10.2  消除無用和不可達代碼
10.2.1  消除無用代碼
10.2.2  消除無用控製流
10.2.3  消除不可達代碼
10.3  代碼移動
10.3.1  緩式代碼移動
10.3.2  代碼提升
10.4  特化
10.4.1  尾調用優化
10.4.2  葉調用優化
10.4.3  參數提升
10.5  冗餘消除
10.5.1  值相同與名字相同
10.5.2  基於支配者的值編號算法
10.6  為其他變換製造時機
10.6.1  超級塊復製
10.6.2  過程復製
10.6.3  循環外提
10.6.4  重命名
10.7  高級主題
10.7.1  閤並優化
10.7.2  強度削減
10.7.3  選擇一種優化序列
10.8  小結和展望
第11章  指令選擇
11.1  簡介
11.2  代碼生成
11.3  擴展簡單的樹遍曆方案
11.4  通過樹模式匹配進行指令選擇
11.4.1  重寫規則
11.4.2  找到平鋪方案
11.4.3  工具
11.5  通過窺孔優化進行指令選擇
11.5.1  窺孔優化
11.5.2  窺孔變換程序
11.6  高級主題
11.6.1  學習窺孔模式
11.6.2  生成指令序列
11.7  小結和展望
第12章  指令調度
12.1  簡介
12.2  指令調度問題
12.2.1  度量調度質量的其他方式
12.2.2  是什麼使調度這樣難
12.3  局部錶調度
12.3.1  算法
12.3.2  調度具有可變延遲的操作
12.3.3  擴展算法
12.3.4  在錶調度算法中打破平局
12.3.5  前嚮錶調度與後嚮錶調度
12.3.6  提高錶調度的效率
12.4  區域性調度
12.4.1  調度擴展基本程序塊
12.4.2  跟蹤調度
12.4.3  通過復製構建適當的上下文環境
12.5  高級主題
12.5.1  軟件流水綫的策略
12.5.2  用於實現軟件流水綫的算法
12.6  小結和展望
第13章  寄存器分配
13.1  簡介
13.2  背景問題
13.2.1  內存與寄存器
13.2.2  分配與指派
13.2.3  寄存器類彆
13.3  局部寄存器分配和指派
13.3.1  自頂嚮下的局部寄存器分配
13.3.2  自底嚮上的局部寄存器分配
13.3.3  超越單個程序塊
13.4  全局寄存器分配和指派
13.4.1  找到全局活動範圍
13.4.2  估算全局逐齣代價
13.4.3  衝突和衝突圖
13.4.4  自頂嚮下著色
13.4.5  自底嚮上著色
13.4.6  閤並副本以減小度數
13.4.7  比較自頂嚮下和自底嚮上全局分配器
13.4.8  將機器的約束條件編碼到衝突圖中
13.5  高級主題
13.5.1  圖著色寄存器分配方法的變體
13.5.2  靜態單賦值形式上的全局寄存器分配
13.6  小結和展望
附錄A  ILOC
附錄B  數據結構
參考文獻
索引      
前言/序言
     構建編譯器的實踐方法一直在不斷變化,部分是因為處理器和係統的設計會發生變化。例如,當我們在1998年開始寫作本書初版時,一些同事對書中指令調度方麵的內容頗感疑惑,因為亂序執行威脅到瞭指令調度,很有可能會使其變得不再重要。現在第2版已經付印,隨著多核處理器的崛起和爭取更多核心的推動,順序執行流水綫再次展現吸引力,因為這種流水綫占地較少,設計者能夠將更多核心放置在一塊芯片上。短期內,指令調度仍然很重要。
  同時,編譯器構建社區還將繼續産生新的思路和算法,並重新發現原本有效但在很大程度上卻被遺忘的舊技術。圍繞著寄存器分配中弦圖(chordal graph)使用(參見13.5.2節)的最新研究頗為令人振奮。該項工作承諾可以簡化圖著色分配器(graph-coloring allocator)的某些方麵。Brzozowski的算法是一種DFA最小化技術,可以追溯到20世紀60年代早期,但卻已有數十年未在編譯器課程中講授瞭(參見2.6.2節)。 該算法提供瞭一種容易的路徑,可以從子集構造(subset construction)的實現得到一個最小化DFA的實現。編譯器構建方麵的現代課程本該同時包括這兩種思想。
  那麼,為瞭讓學習者準備好進入這個不斷變化的領域,我們該如何設計編譯器構建課程的結構呢?我們相信,這門課應該使每個學生學會建立新編譯器組件和修改現存編譯器所需的各項基本技能。學生既需要理解籠統的概念,如鏈接約定中隱含的編譯器、鏈接器、裝載器和操作係統之間的協作,也需要理解微小的細節,如編譯器編寫者如何減少每個過程調用時保存寄存器的代碼總共所占的空間。
  第2版中的改變
  本書提供瞭兩種視角:編譯器構建領域中各問題的整體圖景,以及各種可選算法方案的詳細討論。在構思本書的過程中,我們專注於該書的可用性,使其既可作為教科書,又可用做專業人士的參考書。為此,我們特彆進行瞭下述改動。
  改進瞭闡述思想的流程,以幫助按順序閱讀本書的學生。每章章首簡介會解釋該章的目的,列齣主要的概念,並概述主題相關內容。書中的示例已經重寫過,使得章與章之間的內容具有連續性。此外,每章都從摘要和一組關鍵詞開始,以幫助那些會將本書用做參考書的讀者。
  在每節末尾都增加瞭本節迴顧和復習題。復習題用於快速檢查讀者是否理解瞭該節的要點。
  關鍵術語的定義放在瞭它們被首次定義和討論的段落之後。
  大量修訂瞭有關優化的內容,使其能夠更廣泛地涵蓋優化編譯器的各種可能性。
  現在的編譯器開發專注於優化和代碼生成。對於新雇用的編譯器編寫者來說,他們往往會被指派去將代碼生成器移植到新處理器,或去修改優化趟,而不會去編寫詞法分析器或語法分析器。成功的編譯器編寫者必須熟悉優化(如靜態單賦值形式的構建)和代碼生成領域當前最好的實踐技術(如軟件流水綫)。他們還必須擁有相關的背景和洞察力,能理解未來可能齣現的新技術。最後,他們必須深刻理解詞法分析、語法分析和語義推敲(semantic elaboration)技術,能構建或修改編譯器前端。
  本書是一本教科書、一門教程,幫助學生接觸到現代編譯器領域中的各種關鍵問題,並嚮學生提供解決這些問題所需的背景知識。從第1版開始,我們就維持瞭各主題之間的基本均衡。前端是實用組件,可以從可靠的廠商購買或由某個開源係統改編而得。但是,優化器和代碼生成器通常是對特定處理器定製的,有時甚至針對單個處理器型號定製,因為性能嚴重依賴於所生成代碼的底層細節。這些事實影響到瞭當今構建編譯器的方法,它們也應該影響我們講授編譯器構建課程的方法。
  本書結構
  本書內容劃分為篇幅大緻相等的四個部分。
  第一部分(第2章~第4章)涵蓋編譯器前端及建立前端所用工具的設計和構建。
  第二部分(第5章~第7章)探討從源代碼到編譯器的中間形式的映射,這些章考查前端為優化器和後端所生成代碼的種類。
  第三部分(第8章~第10章)介紹代碼優化。第8章提供對優化的概述。第9章和第10章包含瞭對分析和轉換的更深入的處理,本科課程通常略去這兩章。
  第四部分(第11章~第13章)專注於編譯器的後端所使用的算法。
  編譯的藝術性與科學性
  編譯器構建的內容有兩部分,一是將理論應用到實踐方麵所取得的驚人成就,一是對我們能力受限之處的探討。這些成就包括:現代詞法分析器是通過應用正則語言的理論自動構建識彆器而建立的;LR語法分析器使用同樣的技術執行句柄識彆,進而驅動瞭一個移進歸約語法分析器;數據流分析巧妙有效地將格理論應用到程序分析中;代碼生成中使用的近似算法為許多真正睏難的問題提供瞭較好的解。
  另一方麵,編譯器構建也揭示瞭一些難以解決的復雜問題。用於現代處理器的編譯器後端對兩個以上的NP完全問題(指令調度、寄存器分配,也許還包括指令和數據安排)采用瞭近似算法來獲取答案。這些NP完全問題,雖然看起來與諸如錶達式的代數重新關聯這種問題相近(示例見圖7-1)。但後者有著大量的解決方案,更糟的是,對於這些NP完全問題來說,所要的解往往取決於編譯器和應用程序代碼中的上下文信息。在編譯器對此類問題近似求解時,會麵臨編譯時間和可用內存上的限製。好的編譯器會巧妙地混閤理論、實踐知識、技術和經驗。
  打開一個現代優化編譯器,你會發現各式各樣的技術。編譯器使用貪婪啓發式搜索來探索很大的解空間,使用確定性有限自動機來識彆輸入中的單詞。不動點算法被用於推斷程序行為,通過定理證明程序和代數化簡器來預測錶達式的值。編譯器利用快速模式匹配算法將抽象計算映射到機器層次上的操作。它們使用綫性丟番圖方程和普瑞斯伯格算術(Pressburger arithmetic)來分析數組下標。最後,編譯器使用瞭大量經典的算法和數據結構,如散列錶、圖算法和稀疏集實現方法等。
  本書嘗試同時闡釋編譯器構建的藝術和科學這兩方麵內容。通過選取足夠廣泛的題材,嚮讀者錶明,確實存在一些摺中的解決方案,而設計決策的影響可能是微妙而深遠的。另一方麵,本書也省去瞭某些長期以來都列入本科編譯器構建課程的技術,隨著市場、語言和編譯器技術或工具可用性方麵的改變,這些技術已變得不那麼重要瞭。
  講述方法
  編譯器構建是一種工程設計實踐。每個方案的成本、優點和復雜程度各異,編譯器編寫者必須在多種備選方案中做齣抉擇。每個決策都會影響到最終的編譯器。最終産品的質量,取決於抉擇過程中所做的每一個理性決斷。
  因而,對於編譯器中的許多設計決策來說,並不存在唯一的正確答案。即使在“理解透徹”和“已解決”的問題中,設計和實現中的細微差彆都會影響到編譯器的行為及其産生的代碼的質量。每個決策都涉及許多方麵。舉例來說,中間錶示的選擇對於編譯器中其餘部分有著深刻的影響,無論是時間和空間需求,還是應用不同算法的難易程度。但實際上確定該決策時,通常可供設計者考慮的時間並不多。第5章考察瞭中間錶示的空間需求,以及其他一些應該在選擇中間錶示時考慮的問題。在本書中其他地方,我們會再次提齣該問題,既會在正文中直接提齣,也會在習題裏間接提齣。
  本書探索瞭編譯器的設計空間,既從深度上闡釋問題,也從廣度上探討可能的答案。它給齣瞭這些問題的某些解決方法,並說明瞭使用這些方案的約束條件。編譯器編寫者需要理解這些問題及其答案,以及所作決策對編譯器設計的其他方麵的影響。隻有這樣,編寫者纔能作齣理性和明智的選擇。
  思想觀念
  本書闡釋瞭我們在構建編譯器方麵的思想觀念,這是在各自超過25年的研究、授課和實踐過程中發展起來的。例如,中間錶示應該展示最終代碼所關注的那些細節,這種理念導緻瞭對底層錶示的偏愛。又比如,值應該駐留在寄存器中,直至分配器發現無法繼續保留它為止,這種做法産生瞭使用虛擬寄存器的例子,以及僅在無可避免時纔將值存儲到內存的例子。每個編譯器都應該包括優化,它簡化瞭編譯器其餘的部分。多年以來的經驗,使得我們能夠理性地選擇書的主題和展現方式。
  關於編程習題的選擇
  編譯器構建方麵的課程,提供瞭在一個具體應用程序(編譯器)環境中探索軟件設計問題的機會,任何具備編譯器構建課程背景的學生,都已經透徹理解瞭該應用程序的基本功能。在多數編譯器設計課程中,編程習題發揮瞭很大的作用。
  我們以這樣的方式講授過這門課:學生從頭到尾構建一個簡單的編譯器,從生成的詞法分析器和語法分析器開始,結束於針對某個簡化的RISC指令集的代碼生成器。我們也以另一種方式講授過這門課程,學生編寫程序來解決各個良好自包含的問題,諸如寄存器分配或指令調度。編程習題的選擇實際上非常依賴於本課程在相關課程中所扮演的角色。
  在某些學校,編譯器課程充當高年級的頂級課程,將來自許多其他課程的概念匯集到一個大型的實際設計和實現項目中。在這樣的課程中,學生應該為一門簡單的語言編寫一個完整的編譯器,或者修改一個開源的編譯器,以支持新的語言或體係結構特性。這門課程可以按本書的內容組織,從頭到尾講授本書的內容。
  在另外一些學校,編譯器設計齣現在其他課程中,或以其他方式呈現在教學中。此時,編譯器設計教師應該專注於算法及其實現,比如局部寄存器分配器或樹高重新平衡趟這樣的編程習題。在這種情況下,可以選擇性講解本書中的內容,也可以調整講述的順序,以滿足編程習題的需求。例如,在萊斯大學,我們通常使用簡單的局部寄存器分配器作為第一個編程習題,任何具有匯編語言編程經驗的學生,都可以理解該問題的基本要素。但這種策略,需要讓學生在學習第2章之前,首先接觸第13章的內容。
  不管采用哪種方案,本課程都應該從其他課程取材。在計算機組織結構、匯編語言編程、操作係統、計算機體係結構、算法和形式語言之間,存在著明顯的關聯。盡管編譯器構建與其他課程的關聯不那麼明顯,但這種關聯同等重要。第7章中討論的字符復製,對於網絡協議、文件服務器和Web服務器等應用程序的性能而言,都發揮著關鍵的作用。第2章中用於詞法分析的技術可以應用到文本編輯和URL過濾等領域。第13章中自底嚮上的局部寄存器分配器是最優離綫頁麵替換算法MIN的“近親”。
  補充材料
  還有一些補充的資源可用,可幫助讀者改編本書的內容,使之適用於自己的課程。這包括作者在萊斯大學講授這門課程的一套完整的講義以及習題答案。讀者可以聯係本地的Elsevier業務代錶,詢問如何獲取這些補充材料 。
  緻謝
  許多人參與瞭第1版的齣版工作,他們的貢獻也體現在第2版中。許多人指齣瞭第1版中的問題,包括Amit Saha、Andrew Waters、Anna Youssefi、Ayal Zachs、Daniel Salce、David Peixotto、Fengmei Zhao、Greg Malecha、Hwansoo Han、Jason Eckhardt、Jeffrey Sandoval、John Elliot、Kamal Sharma、Kim Hazelwood、Max Hailperin、Peter Froehlich、Ryan Stinnett、Sachin Rehki、Sa·nak Ta··rlar、Timothy Harvey和Xipeng Shen,在此嚮他們緻謝。我們還要感謝第2版的審閱者,包括Jeffery von Ronne、Carl Offner、David Orleans、K. Stuart Smith、John Mallozzi、Elizabeth White和Paul C. Anagnostopoulos。Elsevier的産品團隊,特彆是Alisa Andreola、Andre Cuello和Megan Guiney,在將草稿轉換成書的過程中發揮瞭關鍵作用。所有這些人都以其深刻的洞察力和無私的幫助,從各個重要方麵提升瞭本書的質量。
  最後,在過去5年中,無論是從精神方麵,還是從知識方麵,許多人都為我們提供瞭莫大的支持。首先,我們的傢庭和萊斯大學的同事都在不斷地鼓勵我們。特彆感謝小女Christine和Carolyn,她們耐心容忍瞭無數次關於編譯器構建方麵各種主題的長時間討論。Nate McFadden以其耐心和齣色的幽默感,從開始到齣版,一直指導著本書的工作。Penny Anderson對於日常行政事務管理方麵的幫助對於本書的完成至關重要。對所有這些人,我們錶示衷心的感謝。    
				
 
				
				
					編程語言的靈魂:深入理解編譯器的奧秘  我們每天都在使用各種編程語言,它們是我們與計算機交流的橋梁。而在這層交流的背後,有一個至關重要的“翻譯官”——編譯器,它默默地將我們編寫的、富有邏輯和創造力的代碼,轉化為計算機能夠理解和執行的機器指令。本書將帶你踏上一段深入探究編譯器設計原理的旅程,揭示這一復雜而精妙的工程過程。  為何要理解編譯器?  你或許會問,作為一名程序員,瞭解編譯器的工作原理有多重要?答案是:非常重要。  首先,深刻的理解能讓你寫齣更高效、更優化的代碼。 當你瞭解編譯器如何進行代碼優化,如何處理不同的數據類型,以及如何生成機器碼時,你就能更有意識地調整自己的編碼風格,避免那些可能導緻低效執行的陷阱。例如,瞭解循環展開、內聯函數、寄存器分配等優化技術,可以幫助你編寫齣性能更佳的程序。  其次,有助於你更好地調試和排查錯誤。 編譯器在分析代碼時,會發現語法錯誤、類型錯誤以及一些潛在的邏輯問題。理解編譯器産生的錯誤信息和警告,能夠讓你更快地定位問題的根源。有時,編譯器報告的“錯誤”可能源於你對語言特性理解的偏差,或是代碼設計上的微妙缺陷。  第三,讓你成為一名更全麵的軟件工程師。 編譯器是現代軟件開發生態係統中不可或缺的一環。掌握編譯器的設計原理,不僅能提升你的編程技能,還能讓你對整個軟件開發流程有更宏觀的認識,為未來在係統軟件、性能調優、甚至新語言設計等領域的發展奠定堅實的基礎。  最後,激發你對計算機科學核心問題的探索。 編譯器的設計本身就是計算機科學領域的一項經典而復雜的課題,它融閤瞭形式語言理論、算法設計、數據結構、離散數學等多個學科的知識。深入研究編譯器,是對這些核心概念的實踐與應用,能夠極大地拓展你的計算機科學視野。  本書將為你呈現什麼?  本書將以一種係統化、循序漸進的方式,帶領你領略編譯器設計的各個環節。我們將從最基礎的概念講起,逐步深入到更復雜的優化技術和實現細節。  第一部分:基礎構建——編譯器的前奏     引言與概覽: 我們將首先勾勒齣編譯器的整體架構,介紹編譯器在軟件開發鏈條中的位置,以及它所扮演的關鍵角色。你將瞭解編譯器的基本組成部分,如前端(詞法分析、語法分析、語義分析)和後端(中間代碼生成、代碼優化、目標代碼生成)。    形式語言與自動機理論: 編譯器的理論基石之一是形式語言與自動機。我們將迴顧正則錶達式、有限自動機、上下文無關文法、下推自動機等概念,它們是詞法分析和語法分析的強大工具,能夠精確地描述編程語言的結構。    詞法分析(掃描): 這一階段,編譯器將原始源代碼分解成一係列有意義的“符號”或“標記”。我們將學習如何利用正則錶達式和有限自動機來識彆標識符、關鍵字、運算符、常量等,並理解詞法分析器的設計原理和實現方法。    語法分析(解析): 詞法分析産生的標記流需要被組織成一個有結構的錶示,通常是抽象語法樹(AST)。我們將深入探討各種語法分析技術,包括自頂嚮下的遞歸下降解析、LL(k)解析,以及自底嚮上的算符優先解析、LR(k)解析(SLR、LR(1)、LALR)等。理解這些技術,是掌握如何驗證代碼的語法正確性的關鍵。    語義分析: 語法正確隻是第一步,代碼的意義同樣重要。語義分析負責檢查代碼的類型兼容性、變量的作用域、函數的參數匹配等。我們將學習如何構建和遍曆抽象語法樹,執行類型檢查,以及管理符號錶,確保代碼在邏輯上也是閤法的。  第二部分:核心轉換——代碼的生成與優化     中間錶示(IR): 在將高級語言代碼轉化為機器碼之前,編譯器通常會先將其轉換成一種中間錶示。這種中間錶示既獨立於源語言,也獨立於目標機器,便於後續的優化和代碼生成。我們將介紹常見的中間錶示形式,如三地址碼、靜態單賦值(SSA)形式等,並探討它們各自的優缺點。    代碼優化: 這是編譯器中最具挑戰性也最能體現其智能的部分。優化旨在改進生成代碼的性能,包括執行速度、內存占用等。我們將詳細講解一係列重要的優化技術:        局部優化: 在基本塊內部進行的優化,如常量摺疊、代數簡化、公共子錶達式消除等。        全局優化: 在整個函數或程序範圍內進行的優化,如循環不變代碼外提、死代碼消除、強度削弱等。        過程間優化: 跨越函數邊界的優化,如內聯函數、過程間分析等。        機器相關優化: 針對特定目標機器架構進行的優化,如寄存器分配、指令調度等。    數據流分析: 許多全局優化技術依賴於對程序數據的流動進行分析。我們將學習各種數據流分析框架,如定義-使用鏈、活躍變量分析、常數傳播分析等,理解它們如何幫助編譯器做齣更智能的優化決策。    目標代碼生成: 這是編譯過程的最後階段,將中間代碼轉化為特定目標機器的機器指令。我們將關注指令選擇(選擇閤適的機器指令來執行IR操作)、寄存器分配(高效地利用CPU寄存器存儲變量)以及指令調度(重新排序指令以提高流水綫效率)等關鍵問題。  第三部分:高級話題與實踐     運行時係統: 編譯器生成的代碼並非孤立運行,它需要與運行時係統協同工作。我們將討論垃圾迴收、異常處理、動態類型支持等運行時機製。    現代編譯器技術: 隨著計算機體係結構和編程語言的發展,編譯器技術也在不斷演進。我們將觸及一些現代編譯器麵臨的挑戰和前沿技術,例如多核處理器的並行化、函數式編程語言的編譯、以及即時編譯(JIT)等。    編譯器工具與實踐: 為瞭便於學習和實踐,本書還會介紹一些常用的編譯器開發工具,如lex/flex(詞法分析器生成器)、yacc/bison(語法分析器生成器)等,並可能通過具體的例子,引導讀者動手實現一些編譯器的模塊。  誰適閤閱讀本書?  本書適閤以下人群:     計算機科學專業的學生: 為理解操作係統、數據庫、程序語言設計等更高級的課程打下堅實基礎。    希望提升編程技能的程序員: 想要寫齣更高效、更健壯代碼的開發者。    對係統軟件感興趣的工程師: 渴望瞭解底層工作原理,對編譯器、解釋器、靜態分析工具等領域充滿好奇的專業人士。    有誌於從事編譯器、語言工具鏈、高性能計算等領域的開發者。  閱讀本書的收獲  通過本書的學習,你不僅將掌握編譯器設計的核心理論和技術,更能培養齣嚴謹的邏輯思維能力、抽象思維能力以及解決復雜工程問題的能力。你將能夠:     理解編程語言的內在機製。    分析和設計編譯器的工作流程。    識彆和應用各種代碼優化策略。    評估和選擇閤適的編譯技術。    為開發更優的軟件打下堅實基礎。  編譯器設計是一門既有深度又有廣度的學科。它連接著抽象的理論與具體的計算,是軟件工程領域的一顆璀璨明珠。本書將是你探索這片領域、解鎖編程語言強大潛力的理想指南。讓我們一起踏上這段激動人心的旅程,揭示編程語言的靈魂所在。