代碼在硬盤上是一堆二進制
- 弄清楚文件在硬盤/內存中的存儲值
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
vim查看 :%!xxd

在終端里執行 man ascii

觀察發現, 中間列和最右列 是一一對應的。
也就是說,剛剛寫完的 hello.go 文件都是由 ASCII 字符表示的(文本文件)
- 匯編轉換位機器指令

- go語句轉換為機器指令過程
Go 程序並不能直接運行,每條 Go 語句必須轉化為一系列的低級機器語言指令,將這些指令打包到一起,
並以二進制磁盤文件的形式存儲起來,也就是可執行目標文件。

探索編譯和運行的過程
通常將編譯和鏈接合並到一起的過程稱為構建(Build)。
編譯過程就是對源文件進行詞法分析、語法分析、語義分析、優化,最后生成匯編代碼文件,以 .s 作為文件后綴的匯編指令。
匯編器會將匯編代碼轉變成機器可以執行的指令。
由於每一條匯編語句幾乎都與一條機器指令相對應,所以只是一個簡單的一一對應,比較簡單,沒有語法、語義分析,也沒有優化這些步驟。
- 編譯器的作用: 將高級語言翻譯成機器語言

- 詞法分析
使用一種有限狀態機的算法

有限自動機是有限個狀態的自動機器。
我們可以拿抽水馬桶舉例,它分為兩個狀態:“注水”和“水滿”。
摁下沖馬桶的按鈕,它轉到“注水”的狀態,而浮球上升到一定高度,就會把注水閥門關閉,它轉到“水滿”狀態。
我們會識別出if、else、int這樣的關鍵字,main、printf、age這樣的標識符,+、-、=這樣的操作符號,還有花括號、圓括號、分號這樣的符號,以及數字字面量、字符串字面量等。這些都是Token。
token一般分為這幾類:關鍵字、標識符、字面量(包含數字、字符串)、特殊符號(如加號、等號)。
slice[i] = i * (2 + 6)
總共包含 16 個非空字符,經過掃描(對那棵樹 遞歸下降算法(Recursive Descent Parsing)構建一棵完整的樹)后,

- src/cmd/compile/internal/syntax/scanner.go
最關鍵的函數就是 next 函數,它不斷地讀取下一個字符(go utf8以字符為單位)
func (s *scanner) next() {
- src/cmd/compile/internal/syntax/token.go
var tokstrings = [...]string{
// source control
_EOF: "EOF",
// names and literals
_Name: "name",
_Literal: "literal",
// operators and operations
_Operator: "op",
_AssignOp: "op=",
_IncOp: "opop",
_Assign: "=",
_Define: ":=",
_Arrow: "<-",
_Star: "*",
// delimitors
_Lparen: "(",
_Lbrack: "[",
_Lbrace: "{",
_Rparen: ")",
_Rbrack: "]",
_Rbrace: "}",
_Comma: ",",
_Semi: ";",
_Colon: ":",
_Dot: ".",
_DotDotDot: "...",
// keywords
_Break: "break",
_Case: "case",
_Chan: "chan",
_Const: "const",
_Continue: "continue",
_Default: "default",
_Defer: "defer",
_Else: "else",
_Fallthrough: "fallthrough",
_For: "for",
_Func: "func",
_Go: "go",
_Goto: "goto",
_If: "if",
_Import: "import",
_Interface: "interface",
_Map: "map",
_Package: "package",
_Range: "range",
_Return: "return",
_Select: "select",
_Struct: "struct",
_Switch: "switch",
_Type: "type",
_Var: "var",
}
-
語法分析
例如“2+3*5”,你會得到一棵類似下圖的AST。

-
語義分析
以“You can never drink too much water.” 這句話為例。它的確切含義是什么?
是“你不能喝太多水”,
還是“你喝多少水都不嫌多”?
實際上,這兩種解釋都是可以的,我們只有聯系上下文才能知道它的准確含義。
詞法分析是把程序分割成一個個Token的過程,可以通過構造有限自動機來實現。
語法分析是把程序的結構識別出來,並形成一棵便於由計算機處理的抽象語法樹。可以用遞歸下降的算法來實現。
語義分析是消除語義模糊,生成一些屬性信息,讓計算機能夠依據這些信息生成目標代碼。
-
目標代碼生成與優化
不同機器的機器字長、寄存器等等都不一樣,意味着在不同機器上跑的機器碼是不一樣的。最后一步的目的就是要生成能在不同 CPU 架構上運行的代碼。
為了榨干機器的每一滴油水,目標代碼優化器會對一些指令進行優化,例如使用移位指令代替乘法指令等。 -
鏈接
鏈接過程就是要把編譯器生成的一個個目標文件鏈接成可執行文件。最終得到的文件是分成各種段的,比如數據段、代碼段、BSS段等等,運行時會被裝載到內存中。各個段具有不同的讀寫、執行屬性,保護了程序的安全運行。



從上圖: 將編寫的一個c程序(源代碼 )轉換成可以在硬件上運行的程序(可執行代碼 ),需要進行
編譯階段
先通過“編譯器 “把一個 .c/.cpp 源代碼 編譯成 .s的匯編代碼;
再經過“匯編器 ” 把這 個.s的匯編代碼匯編成 .o 的 目標代碼
鏈接階段
通過連接其他 .o 代碼(如果需要的話) 庫文件 和 1 中的.o 目標代碼生成可執行文件
該文件流被這三種程序(紅色)的加工,分別表現出四種形式(藍色),這就是c程序的編譯和鏈接過程。
如果再詳細的話,編譯器在將源文件編譯成匯編文件的過程又分為:預處理階段(生成 .i 代碼) 和 優化階段

