編譯器概論–游逸平
← 返回主頁面
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
/1 edit: 近期應該會開始把剩下的補完
Lecture 0 - Why learn Compiler?
- Reverse engineering
- Data processing
- Write better code
- Security
- Compiler 是驅動眾多技術的關鍵 e.g. ref1
If you don’t know how compilers work, then you don’t know how computers work. If you’re not 100% sure whether you know how compilers work, then you don’t know how they work.
Steve Yegge
注意本課程所提及的內容其實已經稍嫌過時,比較屬於上個世紀的技術,現今編譯器技術發展迅速,此課程內容只佔了非常小的一部分。建議各大學課程可以改用這本〈Engineering a compiler〉作為編譯器課程教材。有興趣更深入了解的建議再額外閱讀 gcc 或是 clang 的文件,或是 LLVM 框架的文件等第一手資料,以及 你所不知道的 C 語言:編譯器原理和案例分析。透過廣泛閱讀才有機會掌握現在迅速變革的技術。
Lecture 1 - Overview
先備課程:正規語言–陳穎平 (計算理論)
此課程著重於圖中 compiler 的部份
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
[游逸平(https://people.cs.nctu.edu.tw/~ypyou)]
Compiler
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
- Front End (Analysis)
- Lexical Analyzer
- Syntax Analyzer
- Semantic Analyzer
- IR - Intermediate Representation
- Back End (Synthesis)
- Code Optimizer
- Code Generator
- 本課程不詳細介紹
- Error Handler
- 處理各個階段產生錯誤 (Programmer會很感謝貼心的error reporter的)
- 本課程不詳細介紹
- Symbol Table
- 把各項處理的結果儲存起來的一種資料結構,包括函式名,變數名等,以供各階段需要時調用
Why FrontEnd/IR/BackEnd?
Ans: Reuse of Components
假設今天已經做好一個 c/c++ 的compiler,想改寫給Java用,那就只需要更改負責分析程式碼的 Front End 就好了,Back End可以繼續沿用。
同理,假設今天想從 x86 指令集執行換到 arm 指令集上執行,也只需要更改 Back End 就好
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
Assembler
把組語組譯成一個或多個 object program (不可執行)
Linker
把多個不可執行的 object file merge (例如.o) 起來變成可執行的 object file( 例如 .out/.exe),被引用的函式庫也是在這階段被 link 起來
- Symbol resolution
- Relocation
Loader/Dynamic Linker
- Loader: 負責把程式 load 到 memory 中執行
- Dynamic Linker: 是一種 loader,在程式執行中有需要的時候把 .so (Shared Object) 或是 .dll (Dynamic linking library) 載入記憶體,並進行連結 (linking) 與重新定位 (relocation) 的動作
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
可能需要補一小段程式碼轉成 instruction 的過程
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
再豐富一點的 overview (第一部影片的內容)Others notes
越容易撰寫越有彈性的語言 compiler 要負起的責任就越大,例如需要考慮到各式的語法組合出來的各種 corner cases。
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
Interpreter vs Compiler vs Just-in-time compiler
Interpreter 像是一台 VM
一般我們用的 compiler 是 ahead-of-time compiler
Course project overview
Lecture 2 - Lexical 1
Lexical Analysis(語彙分析)
將輸入的字串分析,切割成數個 token,例如:
if ( b == 0 ) a = b;
,變成
KW: if
(
ID
NUM
)
ID
=
ID
SEMI
Token
描述原始碼中一些字串邏輯上的意義的最小單位,為一對 token name 和 attribute 的組合,以下為範例,詳情見課本或作業
所對應的語彙 (lexemes) |
Token name |
attribute |
, ; : [ ] ( ) |
Delimiters |
no attribute |
array begin boolean |
keyword |
no attribute |
var1 var2 |
identifier |
Pointer to table entry |
1 123 348579 |
integer |
integer value 1, 123, … |
"sdkfjh" "gfgjkhgjhg" |
string |
string content "sdkfjh" … |
Pattern
一段表達式描述 lexeme 如何對應到 token,可以使用正規語言 (regular expression) 表達式,例如:[A−Za−z_][A−Za−z0−9_]*
Error Recovery
(非課程重點) 碰到無法分析的錯誤該怎麼處理?
- panic mode: 忽略接下來的所有字元直到看到一個正確的
- Aggressive: 修改 input
Regular Expression
規則有點多,自己看講義吧,要注意優先度。之前考試有出過給一個特定情境,請寫出能篩選出特定格式的 RE。
推薦一個線上測試 RE 的工具:https://regex101.com/
他還會逐步分析你寫的 RE,展示 test cases 是如何 match 到的
RE 是有能力限制的,並非所有語言都能描述,例如一個 (
就要與一個 )
配對或是其他巢狀的敘述是無法使用 RE 描述的,會變成 infinite state machine
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
Interaction between Scanner and Parser
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
[游逸平(https://people.cs.nctu.edu.tw/~ypyou)]
- 讀取 Source Program
- Parser 呼叫 scanner 給 token
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
- Parser 建構出 parse tree (之後做語意分析)
- 過程中 Parser 和 Scanner 會更新 symbol 資訊到 symbol table
Implementation of Lexical Analysis
其中一種方法是使用 Transition Diagram 來描述並使用 while
配switch
實做
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
example 1

Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
example 2

小問題: 像 if
then
else
這類的保留字會不會被當成一個 identifier? 會!
方法一:先放到 symbol table 當成保留字 (reserved word) 存起來
方法二:特別為那些保留字寫 rule (e.g. if -> KW: if
) 來辨識保留字,不過這樣會跟原本的 rule 有衝突,造成 ambiguity,所以要訂出 rule 之間的優先順序。之後在作業中碰到的方法會是用方法二
Lecture 3 - Lexical 2
Finite Automata
輸入一個字串,從 start state 開始照著 transition rules 走,會停在 Final state 的就是 accept 其餘皆 reject。
Special rule: Epsilon moves,前一個 state 可以直接走到下一個 state
NFA vs DFA
- NFA
- 一個輸入可以從一個 state 可以有多個 transition 到不只一個 next state (包含自己)
- 可以有 epsilon move
- DFA
- 一個輸入只會有一個 transition 從一個 state 走到下一個 state(包含自己)
- 沒有 epsilon move
兩者實質上是等價的,RE 一定可以轉成同等辨識能力 NFA 和 DFA
實做上會採用 NFA 和 DFA 呢? (點擊展開)
DFA,因為一次只有一個 transition 比較好做,但是圖的大小會比 NFA 大指數倍 (理論上)(實際上可能差不多),之後會有詳細分析
其中一種儲存 transition 的方法是用 state 對 state 的 transition table,使用查表的方式使用,如此就不用寫一堆 switch
cases。不過有可能會有太多沒使用到的欄位的缺點,之後會介紹另一個比較有效率的儲存方式。
不過實際上 regular expression matching engine 實做方法有千百種,依據不同使用場合有不同實做方式,例如 cregex 就是一個值得參考的短小精悍實做
實做 NFA 的麻煩點
- Backtrack/Backup
- Parallelism
- Look-ahead
但是 NFA 對人類來說比較好建構,比較直覺,所以會先 Tompson's construction 建構出 NFA ,之後再轉成 DFA
Thompson's construction
Trivial
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
Analysis
- 最多會有
(n(operators) + n(operands)) * 2
個 state
- 因為一個 operator 和 operand 最多只會產生兩個 state (有些只有一個,例如 concatenate)
- 一個 state state,一個 accepting state
- 除了 accepting state 的 state 會有
- 一個使用合法字元或 epsilon transit 出去的 transition
- 或是兩個 epsilon transition 出去
NFA to DFA
核心概念:合併 epsilon transitions
操作方法:
- epsilon-closure(state s)
- 把一坨 epsilon 連接的 NFA 的 state 合併成一個
- epsilon-closure(set T)
- 對 T 裡面的 s 都做一次 epsilon-closure
- move(T, a)
Subset construction
- 產生出 start state
- 對 NFA 的 state state 做 epsilon closure 並視作已經處理完的 state
- 只要有還沒有處理過的 state
- 把還沒有處理過的 state 做 move(T,
a
)
- 把 move 完得到的 set 視為處理完的 state
- 如果 move 完是 Final state 就標示為 Final state
- 新增 transition
a
在 move 前後的 set 之間
pseudo algorithm:
範例
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
有空再用 graphiz 畫Analysis
- 每一個 DFA state 其實是一坨 NFA state
- 理論上 DFA state 個數量會是 NFA 的指數倍,但實際上他們的數量大致相同
- 可以有不只一個 DFA 認得相同的 RE,即兩者之間等價,所以盡可能合併可合併的 state 取得較小的 DFA,降低實做的複雜度
DFA minimization
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
範例
我懶得畫,有空再補
或是看誰要幫我補Distinguishability between states:
如何辨識兩個 state 可不可以合併:
- Final 和 non-Final 不可合併
- 對所有輸入,不管從 state
s
還是 t
出發都會做一樣的決定,那他們就是 indistinguishable (equivalent)
講義上的定義:
- String
x
distinguishes state s
from state t
if exactly one of the states reached from s
and t
by following the path with label x
is an accepting state
- State
s
is distinguishable from state t
if there is some string that distinguishes them
- E.g., empty string distinguishes any accepting state from any non-accepting state
- E.g., string
bb
distinguishes state A
from state B
Method
- Initialization: 把 state 分成 Final 和 non-final
- Division within:
Lecture 4 - lex
作業內容暫時先跳過
Lecture 5 - CFG
Lecture 6 - Parsing 1
Lecture 7 - Parsing 2
Lecture 8 - yacc
作業內容暫時先跳過
Lecture 9 - SDT (Semantic Analysis)
SDD/SDT
- SDD: 比較 high level - guide line
- SDT: 比較 low leve - 細節。e.g. 在Body的部份寫action, 什麼時候該做什麼
- Attrbute: 存放分析時所需要的資訊,甚至是IR
舉例:算式in-fix轉post-fix
SDD: 看到expr
oprator
term
就把expr
的 attibute concatenate term
的 attibute 再 concatenate oprator
SDT: semantic actions,
E.g. rest -> + term { print('+') } rest 1
把SDD定義的動作實做出來
Synthesis/Inherit Attribute
- Synthesis: 來自child的attribute。大多時機是把小孩的attribute合成成自己的attribute,例如加法。
- inherit: 來自父母或兄弟姊妹的attribute。大多時機是對其他人的attribute有attribute有dependency,需要從父母或兄弟姊妹pass attribute來計算自己的。會需要傳遞是因為 parse tree 和 abstract syntax tree 的結構不一樣,所以 parse tree 需要傳遞資訊
舉例:以先乘除後加減的計算算式
請參照講義上 parse tree 的箭頭
[待補圖]
Order of evaluate attribute
正常型況下沒有 cycle 的 DAG (的topology sort的所有可能) 才能執行 SDD,這會需要 two pass,也就是先建構完 parse tree 才建構AST。
如果要邊建構 parse tree 邊執行 SDD,會需要對 SDD 做限制
- S-attribute (S: synthesized)
- L-attribute (L: left-to-right), S-attribute 包含於 L-attribute
S-attribute
S-attribute 只要用 buttom up 的順序就能計算,所以 buttom up parsing 就可以邊 parse 邊計算。
L-attribute
(derivation rule)只能由左至右傳遞 attribute,避免產生cycle,亦即在 parse tree 中只能由左至右,由上至下傳遞
Semantic Rule with side effect???
建立Syntax tree
- parse tree: 透過CFG建立的樹
- syntax tree: 透過執行SDD從 parse tree 建立一棵語法樹(小提醒: inherit attribute就在這邊扮演傳遞資訊的角色),syntax tree才是可執行、可分析的tree。第四次作業的分析就是base on syntax tree。
Implementation of SDT
General SDT implementation
- 建一顆 parse tree
- 執行 action 增加 node
- post traversal 產出 Syntax tree
not that general SDT
post-fix SDT: 都放在 body 最右手邊的 action。最簡單實做的SDT。使用一個stack
舉例:用一個stack和多個action處理四則運算。
SDT with action inside productions: 還沒 match 完整條 grammar rule 就執行 action。不是所有這類的SDT都能正常的邊 parse 邊執行。
有問題的SDT在 parsing 的時候會有conflict,亦即在做LR parsing的時候會有conflict
不確定yacc看到有問題的SDT(講義上的舉例)會怎麼做,需要查一下。保守作法就是action都寫在最後面就好了
有問題的SDT還是可以執行的,但是就是沒辦法邊parse邊執行,需要採正常的兩階段執行
消除left recursion why?
blablablablab…
L-attributed SDD to SDT
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
待補…Lecture 10 - IR
編譯器的中介語言,需要有IR的原因在 Lecture 1 已經提及了。
IR有high level到low level之分,高的比較接近我們寫的程式碼,低的比較接近machine code
Syntax tree: 把parse tree精鍊過只剩下所需資料的tree
DAG: 一樣leaf都是operand,不過operator不會重複出現,還有GVA(Global Value Numbering)最佳化。產生一個node之前會檢查是不是已經存在了,已經存在了就直接指過去,<ValueNumber , Signature> pair存在hash table裡面來查詢 signature: <op, l, r>
Basic info
之前提到的Three address code (e.g. t1 = t2 + t3
) 比較接近 machine code表示法,接下來說明一些資料結構來存放three address code
課本裡的IR有8種operation,我們這邊以這8種為例
ph1
ph2
ph3
ph4
ph5
ph6
ph7
ph8
ph = placeholder,等等補
詳情請自行參考講義
不管什麼語言都轉成這8種opration
範例:把Do-while loop轉成IR
using symbolic label/numbering label兩種後者比較接近machine code
選擇允許的IR的operation是一個很重要的設計
- 比較接近machine code的設計比較容易轉成真的machine code
- 但是會不好維持原本的架構
- 所以會分成很多層級的IR,high到low給不同的用途
IR的資料結構
Quadruple
< op - arg1 - arg2 - result >
three address直接的轉譯的結果
透過temperary存放result
- 直覺
- 比較好做最佳化,像是instruction reordering(不能打破dependency)
- 在triple裡面移動指令VN reference也要改,Quad不用,可以直接移動
- 但是比較佔空間
Triple
沒有temperary需要value number來reference其他operation的計算結果
行為上和syntax tree一樣(op, arg1, arg2)
Indirect Numbering
Triple的變形,解決需要reference的問題。多maintain一個array,這個array會存放每個指令,對調指令時是對調array裡面存放指令的順序而不是更動指令本身,所以就不用動reference了
不過大多open source的IR還是quad因為比較直覺(編譯什麼的吃多一點記憶體很正常的吧)
SSA(課本沒有)
一個變數只會被定義一次
所以會需要renaming,如果有重複用到同一個變數的話
不過在condition的時候會有confliction,所以會用phy function來解決(最後轉成machine code的時候會拿掉)
現今open source compiler常用
- 優點
- code optimization比較方便
- 不同命名消除dependency,做什麼調換順序的比較方便,甚至可以發覺更多可以最佳化的點
詳情請見:〈SSA-based Compiler Design〉
Type Checking
在Symantic Analysis的時候會檢查。現在CPU都是control unit和arithmetic-logic unit是分開的,所以data存在哪個相對位址 (storage layout,等等補圖) compiler要先決定好,arithmetic-logic unit 只負責去存取
Static data: 存放的位置不改變,e.g. 全域變數, static variable
dynamic data: e.g. malloc
, new
, local variable
Type Expression:表示型別的方式, variable, function都有,在動態語言裡面甚至有type variable在type expression裡面來攜帶型別資訊。儲存上可以用graph來儲存
什麼叫做「一樣」的型別?
- Structure eq. : 以下任一者成立即相同
- same basic type
- same structure
- typedef
- Name eq.
- 要完完全全一模一樣(待補充)
- structure eq. 三條都滿足
Storage layout of Names
看到變數宣告就知道要分配多少空間、放在哪,再存放到symbol table,下次要存取變數就查表,直接去那個位置拿資料
小疑問,如果一個頻繁呼叫的函式,裡面用local variable是合適的嗎?因為local variable會一直不停被allocate, deallocate,這樣很耗時嗎?
- address alignment
當存取資料的位址不能被4(在一次存取4 byte的平台上而言,帶補充)整除時,就會多耗很多operation去拿資料,例如一次拿出來之後再抽絲剝繭拿出你要的
在traverse parse tree的時候用SDT產出相關資料
- 例如建構出syntax tree中陣列的型別資訊
- 然後就可以用型別資訊決定變數要存放在table中哪個記憶體位置
- Symbol table裡面存的是相對位置,table起始位置再加上offest才會存到你要的symbol(或是另一張symbol table)
- 起始位置用一個top pointer指著,方便存取
以上在你做完作業4之後會很有感覺
Translation of Expressions
用SDD定義看到各express的grammar rule該怎麼做
- 做運算後存起來到new出來的temp或是覆蓋
- 產生IR(new temp出來可以對應到儲存資訊到temp register)
array的記憶體擺放方法,這個是compiler決定好的,像fortran這種row major的擺法或是C這種column major
存取方法: base + offset
Compiler正規化推斷型別的流程 <–我覺得這部份會考歐
用已知的資訊推導未知資訊
(帶補講義圖p.62)
題外話:Just In Time compiler 也是需要先做 type inference
Control flow Statements
Boolean expression
short circuit expression
- 在or中有人true就直接回傳true了
- 在and中有人false就直接回傳false了
缺點:
- 可能在剩餘的expression中有必須被執行的statement被跳過了
- 不過這應該是programmer的問題
SDD for Boolean expression
backpatching: 把label換成instruction編號
Lecture 11 - Runtime
Lecture 12 - Code Generation & Code Optimization
Compiler 最有趣的地方都在這邊
參考資料
Lectuer 13 - Controlflow
← 返回主頁面
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
廢話
G_G …
我怎麼寫起來都像廢話,排版也亂七八糟
之後有空慢慢寫
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
不知道專題和準備推甄會花多少時間2022 - March -
老師:欸我明年被指派要上編譯系統= =
老師:你有沒有修過編譯器
我:有
老師:((:DDD))
呃…好我懂了
那明年來上這個好了
How to compile C/C++ for WASM, pure Clang, no libs, no framework
https://github.com/ern0/howto-wasm-minimal
或是參考 你所不知道的 C 語言:編譯器原理和案例分析,從最佳化開始講之類的,至少用現代化一點的教材
參考資料
LLVM
聽過 GCC 就也要聽過 LLVM