前端(compiler front end)
當你把一個檔案交給編譯器,它要做的第一件事是真正讀懂這份人寫的文字:哪些字元組成單詞、這些單詞如何符合語言的文法、以及你寫的東西到底通不通。前端就是編譯器負責這一切的部分——它是懂語言的那一側,把你的原始碼轉成有結構的意義。
具體而言,前端會跑一條小型子管線。首先是詞法分析(lexing,也叫 tokenizing),把原始字元切成詞元(token):文字 int x = 1; 變成詞元 [int] [x] [=] [1] [;]。接著剖析(parsing)依文法把這些詞元排成一棵樹,叫做抽象語法樹(abstract syntax tree,AST),它捕捉巢狀結構(這個指派,在這個函式裡,在這個檔案裡)。然後語意分析(semantic analysis)檢查文法本身無法檢查的規則:名字有沒有宣告、型別合不合、你是不是把指標加到一個結構上。若這一切都通過,前端就把程式以編譯器的 IR 形式輸出,供後續階段最佳化。
它重要在於:你的語法錯誤和大多數型別錯誤都來自前端——那些訊息就是這個階段拒絕往下進行。它也是最依賴語言的部分:C、C++、Rust、Swift 各需要不同的前端,但它們都能透過共同的 IR 匯入同一個共用的最佳化器與後端。一個提醒:「剖析過了」與「語意分析過了」只代表程式格式正確,不代表它正確——前端看不出你的邏輯有錯。
int x = 1 + 2; 詞法 -> [int][x][=][1][+][2][;] 剖析 -> Assign(x, Add(1, 2)) // 這就是 AST 語意 -> ok: x 是 int,1+2 是 int // 型別檢查通過
前端的三個內部步驟:字元到詞元到一棵樹,再檢查這棵樹遵守語言的規則。
編譯乾淨只代表前端接受你的程式為格式正確;它完全不保證程式做了你想要的事——邏輯 bug 與未定義行為都會暢通無阻。