看板 Gossiping作者 aeolus811tw (aekt)標題 Re: [問卦] 寫編譯器的人是不是很屌?時間 Thu Jan 31 06:46:02 2019
以下文章我盡力用中文說明部分
Debugger 只是一種輔助你除錯的工具而已, 他並不算語言編譯的一種
在程式語言編譯世界裡主要分為兩種
Compiler (編譯器) & Interpreter (翻譯器)
而各自還有更多的細分.
編譯器主要把程式碼變成機器碼讓人執行
翻譯器不變成程式碼的直接執行, 一般用在除錯/Script語言上
編譯器分為前後兩端, 而其流程為:
1. Lexical Analysis (字元分析)
將程式碼本身分割成為字塊(lexemes), 每個字塊都需要有相對的資料結構保留
譬如
if (1 == 1){}
會被分裂為
if, (, 1, ==, 1, ), {, }
如果你有寫過計算機的prefix / postfix notation就差不多能明白為何要這樣分割
當遇到無法理解的字元的時候(如if 打成 ef)就對丟錯
2. Syntax Analysis (結構分析)
將字元分析後取得的字塊組成一個AST (抽象語法樹), 這是為了保留資料的邏輯結構
譬如
樓上的案例會被做成
if
/ \
= nil
1 1
如果有不對稱邏輯問題, 這步會丟出相關的錯誤 (如少打'}')
3. Semantic Analysis (語意分析)
利用第二步產生的AST來檢查是否有違反語言的規矩
這一步會檢查你是否有打錯計算符號, 檢查你的物件的類別是否正確, 以及推論出物件的類別
譬如
javascript / swift / python
你可以用
let x = 1 / var x = 1 / x = 1
在非C / Java 那種強烈識別(Strong typed)的語言裡, 語意分析就需要把這些變數的類別型態推論出來
這步如果遇到型態不符的問題會丟錯
完畢後會產生aAST (已標示抽象語法樹) 和 Symbol Table (符號表)
符號表內部會記錄目前遇到的任何函式字符&變數名字
4. Intermediate Code Gen (中間語法產生)
利用第三步產生的aAST來產生無硬體依賴性的低階語法
最常見為3AC (Three Address Code)
這種就很類似ASM 只不過還帶有你所知的計算符號等內容
譬如
第三步的if可能會變成
t1 = 1 eq 1
ifz t1 goto L1
以上為前端作業
完畢後就換後端作業
5. Optimization (最佳化)
這步會把第四步的產生結果進行刪減/重排列作業
譬如
要是你第四步產生了
t1 = x - 2
t2 = x * t1
t3 = t2 / 6
o1 = t3
可能會被最佳化為
t1 = x - 2
t2 = x * t1
o1 = t2 / 6
6. Code Generation (機器碼產生)
這一步會把第五步的吐出物轉成相關硬體規範的機器碼
譬如
t1 = x - 2
t2 = x * t1
o1 = t2 / 6
可能會變成
lea eax, x
sub eax, 2
mul eax, n
div eax, 6
ret eax
以上為很基礎的編譯器運作方式. VM Bytecode 之類的會加雜其他步驟, 不過大致上雷同
而翻譯器的話跟一開始所說的一樣跟編譯器很相似
差異在於翻譯器是單行翻譯完就直接跑, 直接跳過最佳化步驟
他會一直跑下去直到遇到錯誤
除錯的話一般就跟著最後產生的機器碼來執行
而除錯能一步一步走主要是利用跟翻譯器互動所達成的
BP 就是設定翻譯器要偵測的錯誤或硬體自己截斷的錯誤
讓翻譯器一直跑, 直到條件達成就丟錯的斷點錯誤
很多防盜版 / 防駭程式都會特別去偵測斷點錯誤來故意跑不同路線或直接讓系統死當
如hackshield & nProtect (玩過網路遊戲的應該都知道這兩款)
他曾經用過計時計算時間的手法來確保程式不會因為被斷點而暫停來讓反制反編譯
要說差很多? 未必
因為大致上有一定程度的關聯性.
當然你要說它們用處有差別就另當別論了.
要避免最佳化的除錯是因為要確認錯誤並非由編譯器所生, 如heisenbug.
而一步步的除錯也是IDE普遍化後才大眾化的功能, 在那之前的語言幾乎都沒提供完善版的功能
在石器時代能有IDE就該謝天謝地 (用emac, vi/vim, notepad 寫過程式的人應該都懂這個痛苦)
可是你最後丟出的東西都是最佳化過的, 因此你終究還是得從最佳化機器碼下手來除錯.
※ 引述《KILLE (啃)》之銘言:
: ※ 引述《paupauGO (ouo)》之銘言:
: : 就是阿
: : 寫程式的時候都需要編譯器
: : 可以code出各種東西
: : 但本魯很好奇的是
: : 編譯器到底是怎麼寫出來der
: : 內建各種方法,可以除錯跟設中斷點
: : 這麼屌的東西要開發應該hen辛苦ㄅ
: : 能寫出這麼厲害的工具的人是不是很猛?
: : -----
: : Sent from JPTT on my Asus ASUS_Z017DA.
--
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 17.115.109.225
※ 文章代碼(AID): #1SKYaiWp (Gossiping)
※ 文章網址: https://www.ptt.cc/bbs/Gossiping/M.1548888364.A.833.html
推 backzerg: 這種時間出現這種專業文 不會是工作到天亮吧2F 01/31 06:51
→ moonshade: 但現在最佳化有一大半是code gen在做
其實cmd line用習慣是覺得IDE沒必要,IDE的好處是
找code,但是tag/cscope都做得到,所以emacs/gvim並
不會很痛苦(除了碰到多重繼承的C++以外...)3F 01/31 06:51
推 neo5277: 在八卦這麼認真做什麼…10F 01/31 07:09
推 GGing: 推!但嚴格來說 compiler 不一定是把 source code 直接變成 machine code。像 Javac 就是變成 byte code,然後 JVM 才把 byte code 變成 machine code。11F 01/31 07:09
推 youchen68: 推,我以為要寫成001100之類的…(遮臉)XDDD22F 01/31 07:39
推 khalid: 名人耶 應該是教主死對頭24F 01/31 07:45
推 zxc1028: 快推 不然別人以為我不懂25F 01/31 07:49
推 OGC218: 文組· · 路過26F 01/31 07:50
推 twPenn: 編譯器4ni?27F 01/31 07:54
推 mhliu8: .NET 也是,C# Code# CompilerLNET Runtime
IT CompilerachinecodeExecution
C# Code# Compiler誄誃ET Runtime訿T Co
mpiler趏chinecode Execution31F 01/31 08:00
推 mhliu8: 忘了濾掉特殊符號XD, 應該是 C sharp Code 轉 C sharp Compiler 轉 IL 轉 .NET Runtime 轉 JIT Compiler 轉 machine code 轉 Execution36F 01/31 08:04
推 Wand: 這種文都是凌晨發,肝表示:47F 01/31 08:25
推 foxher: 熬夜寫程式,我懂51F 01/31 08:35
推 Marty: 半夜寫程式 就像開了加速器 Coding的日常~53F 01/31 08:37
推 amows: 強者推56F 01/31 08:44
推 CRong: 看不懂的推59F 01/31 08:48
推 kisweet999: 最佳化除了精簡指令外, 就是避免掉資料危障吧64F 01/31 09:01
推 goldflower: 像Jeff Dean直接寫機器碼就沒這麼多問題惹(?)65F 01/31 09:05
推 KBTIT: 我也是這麼覺得67F 01/31 09:06
推 cool9203: 推,編譯器前端,但我也沒學過,好想學ㄚ74F 01/31 09:38
推 pjason: 推,有機會會來深入研習一下79F 01/31 09:56
推 hw1: 推 我大學修的砍拍了全都還給學校了 XD80F 01/31 09:56
推 yukinoba: 要對機器碼debug記得optimization level不能太高...84F 01/31 10:04
推 hikku: 完全看不懂 能讀懂這種東西的人到底是怎麼辦到的啦85F 01/31 10:12
推 MoseHas: 好像重回了大三在修compiler的感覺QQ90F 01/31 10:42
推 penta: 有修過相關科目蠻好懂的XD94F 01/31 11:20
推 dfast: 只懂得 if else96F 01/31 11:29
→ vul3kuo: CS本科就有教 只是一堆半路出家來寫程式的才覺得很神99F 01/31 11:57
→ liflguy: 大一就介紹過了吧103F 01/31 12:20
推 Luba: 跪求履歷啊110F 01/31 16:20
推 ph49: 你在八卦板這麼認真幹嘛…112F 01/31 16:54
推 shiwa: 推推113F 01/31 17:18
--