大致過程可分爲以下4個步驟:
預處理->編譯->彙編->鏈接
一、預處理
處理源代碼文件以“#”開始的預編譯指令。
1)展開宏定義
2)處理所有條件編譯指令
3)處理#include預編譯指令,遞歸地將被包含的文件插入進來
4)刪除註釋
5)添加行號和文件名標識,這樣編譯器產生錯誤和警告時才能顯示行號
6)保留#pragma編譯器指令
最終生成.i文件(c語言),或者.ii文件(C++語言)。
二、編譯
1)掃描,將源代碼輸入到掃描器。
1)詞法分析,將源代碼的字符序列分割成一個個記號:關鍵字、標識符、字面量、特殊符號,如“(”是一個記號,變量i是一個記號。詞法掃描工具:lex
2)語法分析,生成一棵結點爲表達式的語法樹,同時檢查表達式是否合法,如括號不匹配、缺少操作符在這步可以檢查出來。語法分析工具:yacc
3)語義分析,檢查表達式是否有意義,如類型匹配、除0。爲語法樹中的所有結點標上類型。
4)源代碼優化,如2 * 5,在這個期間就可以被確定,直接用10替換該表達式。在該步會將語法樹生成中間代碼(不包含數據的大小、變量地址、寄存器名字)。
5)目標代碼生成,將中間代碼生成目標機器代碼。中間代碼跟機器無關,目標機器代碼跟機器有關,會標出字長、寄存器名字等。
6)目標代碼優化,用位移代替乘法、刪除多餘的指令等。
最終會生成彙編代碼文件。
三、彙編
將匯率代碼轉變爲機器可以執行的指令。僅簡單根據彙編指令和機器指令的對照表一一翻譯,不做指令優化。
彙編器工具:as
四、鏈接
鏈接主要是處理各個模塊相互引用的部分,使得它們能正確銜接。比如A模塊引用了B模塊的某個函數、C模塊的某個全局變量等。
1)地址和空間分配
2)符號決議(也叫地址綁定)
3)重定位。有些全局變量或函數定義在其它庫中,重定位找到它們的地址。