1977-龍書#
案件摘要#
1960 年代,形式語言與自動機理論已在 Aho、Hopcroft、Ullman 等人手中成熟,論文散落各處,卻沒有一本書把「如何建造編譯器」整合成一套方法學。1977 年,Bell Labs 的 Alfred Aho 與 Columbia 的 Jeffrey Ullman 聯手出版《Principles of Compiler Design》——封面上一名騎士持劍馴龍,從此「馴服編譯器這條惡龍」成為每個資訊系學生的成人禮。這本書被暱稱為「龍書」,統治編譯器教育近半世紀,無人能撼動。
前因 -- 為什麼會有這個案子#
- 理論已成熟卻散落:Chomsky 階層(1956)、Knuth 的 LR(k) 分析(1965)、Lewis 與 Stearns 的 LL(k) 理論等成果,都發表在期刊論文中,一般工程師難以觸及;理論與實務之間隔著一道鴻溝。
- 編譯器寫作被視為巫術:1960 年代每個編譯器都是手工打造的藝術品,FORTRAN I 編譯器耗費 18 人年;沒有系統化的方法,每個新語言、新機器都要重新發明輪子。
- Aho 與 Ullman 的背景:兩人合著過《The Theory of Parsing, Translation, and Compiling》(1972-73,兩卷本),內容偏理論;他們意識到需要一本「給工程師的版本」——把理論轉譯成可操作的演算法。
- 教科書市場空缺:當時僅有的編譯器教材(如 Gries 的《Compiler Construction for Digital Computers》, 1971)偏實務細節,缺乏形式語言理論的統攝。
線索與推理 -- 數學式、程式、理論#
編譯器六階段管線:資料流的抽象#
龍書最重要的貢獻之一,是把編譯器拆成線性管線,每個階段吃進一種表示法、吐出另一種:
每一階段都可獨立替換、獨立測試、獨立教學——這正是抽象化思維的典範。龍書告訴讀者:編譯器不是巫術,而是一條可分析的生產線。
用偽代碼描述管線:
def compile(source):
tokens = lexer(source) # 詞法:正則表達式驅動
ast = parser(tokens) # 語法:上下文無關文法驅動
checked = semantic(ast) # 語意:符號表 + 型別檢查
ir = irgen(checked) # 中間碼:三址碼 (three-address code)
opt = optimizer(ir) # 優化:資料流分析、常數折疊
return codegen(opt) # 目標碼:暫存器分配 + 指令選擇
每個函數對應書中的一章,讀者可逐章攻克——這就是「把惡龍切成七段」的戰術。
FIRST 與 FOLLOW 集合:LL(1) 分析的鑰匙#
龍書用形式語言理論統攝語法分析。對文法 \(G\) ,定義:
FIRST 是某符號串能推導出的開頭終端符號集合;FOLLOW 是某非終端符號在句型中可以出現的後繼終端符號集合。有了這兩組集合,就能建構預測分析表:若 \(a \in \text{FIRST}(\alpha)\) 則在 \(M[A, a]\) 填入 \(A \to \alpha\) ;若 \(\epsilon \in \text{FIRST}(\alpha)\) 且 \(a \in \text{FOLLOW}(A)\) 亦然。無衝突即為 LL(1) 文法,可用一遍掃描的遞迴下降或表格驅動分析器解析。
Python 計算 FIRST 集合#
# 文法:E -> T E' | T E'
# E'-> + T E' | ε
# T -> F T'
# T'-> * F T' | ε
# F -> ( E ) | id
G = {
"E": [["T","E'"]],
"E'": [["+","T","E'"], ["ε"]],
"T": [["F","T'"]],
"T'": [["*","F","T'"], ["ε"]],
"F": [["(","E",")"], ["id"]],
}
def first(sym):
if sym in ("id", "+", "*", "(", ")"): # 終端符號
return {sym}
out = set()
for prod in G[sym]:
head = prod[0]
if head == "ε" or head == sym: # 空產生式或左遞迴
if head == "ε": out.add("ε")
continue
f = first(head)
out |= f - {"ε"}
if "ε" not in f: # FIRST(head) 無 ε 即停
continue
out |= {"ε"} if len(prod) == 1 else first(prod[1])
return out
for nt in G:
print(f"FIRST({nt}) = {sorted(first(nt))}")
# 輸出:FIRST(F) = ['(', 'id'],其餘非終端皆同——
# 這正確反映 E、E'、T、T'、F 的開頭符號只能是 '(' 或 id
這段程式是遞迴不動點迭代:不斷用子符號的 FIRST 擴充父符號的 FIRST,直到不再變化——龍書中所有分析表建構演算法都是這個模式,LL(1)、LR(0)、LALR 皆是同一思想的變奏。
騎士與龍的寓意#
封面上騎士持劍(寫著 Pascal)迎戰噴火的綠龍,龍鱗上嵌著 "Compiler" 字樣。寓意:編譯器設計是資訊科學中最兇險的巨龍,而形式語言理論是屠龍之劍。第二版(1986,與 Monica Lam 之夫 Ravi Sethi 合著)封面改為騎士凱旋騎龍——龍已被馴服。
結案 -- 後果與影響#
- 統治編譯器教育:龍書成為全球編譯器課程的標準教材,至今仍是最常引用的教科書;第二版《Compilers: Principles, Techniques, and Tools》(1986,加 Monica Lam 為 2006 修訂版作者)持續再版。
- 理論與實務的橋樑:把 Chomsky 文法、LR/LALR 分析、資料流分析從論文轉譯成演算法與習題,讓一般學生也能掌握——編譯器課程從此成為資訊系核心必修。
- 工具化的先聲:書中方法直接催生了 lex/yacc(1975)等編譯器產生器;現代 ANTLR、LLVM 的文件仍以龍書為理論基準。
- Aho 獲 2020 年圖靈獎(與 Ullman 共同獲獎),表揚其在形式語言與編譯器理論的奠基貢獻——龍書正是這份遺產最廣為人知的載體。
關鍵人物與文獻#
- Alfred Aho(Bell Labs/Columbia)、Jeffrey Ullman(Princeton→Stanford):龍書作者,2020 年圖靈獎。
- John Hopcroft:與 Aho/Ullman 合著《The Design and Analysis of Computer Algorithms》(1974),形式語言三部曲之一。
- 文獻:
- A. V. Aho, J. D. Ullman, Principles of Compiler Design, Addison-Wesley, 1977.
- A. V. Aho, R. Sethi, J. D. Ullman, Compilers: Principles, Techniques, and Tools, 2nd ed., 1986/2006.
- D. E. Knuth, "On the Translation of Languages from Left to Right," Information and Control 8, 607 (1965).
- N. Chomsky, "Three Models for the Description of Language," IRE Trans. IT 2, 113 (1956).