概念地圖・編譯器管線
分類:系統
這一頁不只是把一個概念解釋一遍——一張自己畫的結構圖,加上拿台灣情境從頭走一次的實例演練、這個框架什麼時候會騙你,以及它接回 P.A.I.N. 之後長什麼樣。一頁必須交付的三層 →
編譯器管線:六段轉手,每站留下證據
一段程式碼從你打完到機器跑得動,中間換了六次手。每換一次,它就變成另一種樣子——先變成一串記號,再變成一棵樹,再變成一份不綁機器的中間碼。這六段轉手就是編譯器管線。它最出名的地方在於錯誤訊息:括號少收一個,它指得出第幾行第幾個字。指得出來,靠的是每一站都把手上的東西寫成下一站看得懂的格式,然後把那份東西留在原地。
六站接力,各自把什麼變成什麼
先把六站攤成一張表。左邊是監理站的驗車動線,右邊是編譯器真正在做的事——兩邊的共同點在於,每一站都得交出一份東西,下一站才動得了。
| 驗車站(耗時) | 編譯階段 | 交出什麼給下一站 | 這一站攔得住什麼 |
|---|---|---|---|
| 外觀 3 分 | 詞法分析 | 一串帶著行號的記號 | 你打了機器不認得的符號 |
| 煞車 4 分 | 語法分析 | 一棵結構樹 | 括號沒收、句子沒收尾 |
| 燈光 2 分 | 語意檢查 | 標好名字與型別的樹 | 名字對不上、型別接不起來 |
| 排氣 5 分 | 中間表示 | 一份不綁機器的中間碼 | 轉出來的中間碼自己站不站得住 |
| 底盤 6 分 | 最佳化 | 一份瘦過的中間碼 | 改寫前後的行為有沒有跑掉 |
| 儀器判讀 2 分 | 碼生成 | 目標機器跑得動的碼 | 指令與暫存器對不對得上這顆晶片 |
表看到第四列會有一個轉折。前三站攔的是你寫的東西本身:符號打錯、括號沒收、名字對不上。第四站開始,被檢查的對象換人了——那份中間碼是編譯器自己轉出來的,所以後三站攔到的錯,講的多半是它內部的一致性。這件事在錯誤訊息上看得最清楚:前三站的訊息你讀得懂,後三站的訊息常常長得像天書。
你那條流程算不算真的分了站
一、交接處躺著一份東西,還是躺著一句話。外觀站交出的是一張勾好的表格,煞車站不必再問車主任何事,照著往下量就行。真正分了站的流程,交接處會有一份寫死的東西,而口頭交代在那裡撐不住三天。自問:你那條流程的第三步,收到的是一份看得懂的檔案嗎?
二、退回的那一刻,前面幾站的紀錄還在嗎。排氣量出超標,檢驗員手上還翻得到燈光站那 2 分鐘量到的角度——所以他指得出是哪一台儀器的讀數不對。紀錄沒留下的流程,退回時只剩一句「不合格」,然後整台從頭來過。自問:你上次流程走不下去,翻得到前一站當時交出的數字嗎?
三、後半段的站,還在看原車嗎。底盤那 6 分鐘檢查的是車體本身,可是它拿來對照的,是前面幾站量出來的那組數據。編譯器的後三站也一樣——它們驗的是自己轉出來的中間碼站不站得住,原始碼那時候早就沒人在看了。自問:你那條流程的後半段,還有機會發現一開始就填錯的資料嗎?
四、一站被拉長,別站會不會跟著亂。底盤從 6 分鐘變成 8 分鐘,排氣那 5 分鐘不該受影響——因為它交出去的東西已經定型了。站與站真的切開時,一站塞車不會傳染給隔壁。自問:你那條流程某一步延誤時,前後兩步得不得跟著重做?
一輛車的驗車動線,實際跟一次
底下這座台灣中部的公路監理站驗車線,是為了把這個結構講清楚而編出來的示意情境,沒有指涉任何真實單位。跟的是同一輛七年份的自小客,順利的話 22 分鐘走完。
- 外觀 3 分:核對車身號碼、對照有沒有未申報的改裝,勾完一張表交出去。後面五站都靠這張表認車
- 煞車 4 分:上滾筒量左右輪制動力,兩個數字寫進同一張表,差值也記下來。寫下來了,之後翻得到
- 燈光 2 分:頭燈照射角度偏了一格,當場調回來,調整前後的讀數照樣留在紀錄上。
- 排氣 5 分:怠速一氧化碳超標,退回。檢驗員指得出是排氣分析儀那一格的數字不對,車主只要回頭處理那一項。每 100 輛裡有 14 輛倒在這一關
- 底盤 6 分:修好回來,前三站的紀錄直接沿用,只補做排氣那一關,底盤這 6 分鐘才輪得到。前三站不必重驗
- 儀器判讀 2 分:把六站的數據彙整成一張合格單,這張單子才是外面世界看得到的東西。
這趟 22 分鐘裡,真正撐住整條線的是那幾張中途交出去的表。排氣退回時,車主聽到的只有一句「排氣不合格」,可是檢驗員桌上躺著前三站 9 分鐘的量測——外觀勾好的項目、煞車兩輪的制動力、燈光調整前後的角度。三份紀錄擺在一起,原因就縮到一格,指得出來也講得清楚。等車修好回來,前三站不必重驗,那三份東西還算數。這就是分站真正的報酬——出錯時能從中間接回去,而不必把整台車重推一遍。以上為說明結構用的示意情境,僅供理解框架之用。
這六站什麼時候會騙你
- 最花時間的站,未必是最容易出事的站。底盤要 6 分鐘,是六站裡最久的一段;退回卻集中在只要 5 分鐘的排氣。看圖的人很容易把長條當成風險指標,然後把人力全堆到底盤去。時間量的是工作量,退回率量的是失敗率,兩個數字各自回答不同的問題——擺在同一張圖上時,記得標清楚哪一條線是哪一件事。
- 後三站報的錯,讀起來像在怪你。前三站的訊息你讀得懂:第 12 行少一個括號。第四站以後,錯誤訊息開始出現你從沒寫過的名字——那些是編譯器自己轉出來的中間表示。它在講自己內部對不上,措辭卻長得像在指控你手滑。碰到這種訊息,往回翻前三站留下的紀錄,比逐字啃它有用得多。
- 六個方塊是畫給人看的,實作不長那樣。真正的編譯器會把幾站併成一趟,也會在最佳化裡來回走好幾遍;監理站遇到大車,也可能把外觀跟底盤合在同一個地坑做完。這張圖的價值在於講清楚誰交給誰、誰在等誰——把它當成實作的施工圖照著蓋,第一天就會發現對不上。
中間產物值錢在哪
一條流程最值錢的東西,常常是它順手掉出來的那幾份紙。
編譯器管線被抄了幾十年,靠的是每一次切割都逼出一份能單獨拿走的東西。詞法交出記號、語法交出樹、第四站交出一份誰的機器都不綁的中間碼——這些本來只是工序的殘渣,後來卻變成整個生態的地基:換一種語言,前三站重寫就好;換一顆晶片,後三站重寫就好。中間那份東西沒動,兩邊各自省下大半的工。
回到《痛點》那把尺。這張圖畫得出每一站交出什麼、錯誤會在第幾站被攔下來,畫不出有沒有人願意為那一站付錢。P.A.I.N. 的第一個字問的是誰在痛——一條分得漂漂亮亮的六站流程,可能六站都在解你自己的痛,客戶連一站都感覺不到。結構算得出來,痛感算不出來。
今晚可以做一件小事:打開你最近一次出錯的專案,找出第四步當時交給第五步的那份東西,看它現在還在不在硬碟裡。
關於編譯器管線,常見問題
為什麼編譯器指得出錯誤在第幾行第幾個字?
因為位置資訊在第一站就被記下來了。詞法分析把原始碼切成記號的時候,順手把每個記號的行號與欄號寫進去,後面幾站再怎麼改寫,這個標籤都跟著走。所以語意檢查在第三站發現名字對不上,它翻得到那個名字最早出現在哪。反過來說,位置資訊愈往後愈模糊:最佳化把兩行合併之後,錯誤訊息指的行號有時候會偏掉,因為那一行已經被合併掉了。
中間表示到底在幹嘛,為什麼要多這一層?
它就是那份誰都不綁的中間碼。少了這一層,N 種語言配 M 種晶片得寫 N×M 套翻譯;有了它,只要 N 套前端加 M 套後端。這一層也讓最佳化有地方站——直接在原始碼上做重排很難,在機器碼上做更難,中間表示剛好保留了足夠的結構,又脫離了語法的細節。代價是它一旦出錯,訊息會變得難讀,因為它談的東西你從來沒親手寫過。
六個階段一定要照順序跑完嗎?
概念上是接力,實作上不一定。很多編譯器把詞法與語法合成一趟做完;最佳化那一站更常見的做法是來回跑好幾遍,每一遍只做一種改寫。也有編譯器根本不走完——直譯器與 JIT 常在中間表示那一站就停下來直接執行,需要更快的時候才把後兩站補上。順序真正的意義在相依:後面那一站要用前面交出來的東西,所以誰先誰後改不了,跑幾遍、合不合站則是實作自由。
編譯器管線能拿來類比一般的產品流程嗎?
能借過來的部分是交接:每一站交出一份下一站看得懂的東西,出事時翻得到。要小心的是錯誤成本的差距——編譯器退回一次只是重跑幾秒,人跑的流程退回一次可能是一週。所以人的流程通常會把最貴的檢查往前挪,寧可在第一站多花時間篩掉不該進來的東西。編譯器沒有這個壓力,它的站序純粹照相依性排。
找出你那條流程裡最說不清楚的那一站,問它交了什麼給下一站。答案是一份檔案就往下走,答案是「我跟他講一下」就先停在那裡補。想看同一條流程的另外兩種量法,價值流圖量的是等待與加工各佔多久,滾動良率算的是每站良率乘起來還剩多少——三張圖擺在一起,一條流程的形狀才算描完。
喜歡這篇文章嗎?
每週幫你拆二本好書,把判斷力、好書金句、好問題,直送你的信箱。
不適合你可隨時退訂 · 每週兩封,陪你把書讀進生活。
送出即表示同意我們依隱私權政策使用你的 email。