官术网_书友最值得收藏!

1.6 編譯器

編譯器本質(zhì)上是一種翻譯器,其作用是將一種高級(jí)編譯型語(yǔ)言翻譯為計(jì)算機(jī)可以識(shí)別的機(jī)器語(yǔ)言(即低級(jí)語(yǔ)言)。編譯器有本地編譯器和交叉編譯器之分。本地編譯器用來(lái)生成編譯器所在的計(jì)算機(jī)和操作系統(tǒng)相同的平臺(tái)環(huán)境下可執(zhí)行的目標(biāo)代碼。交叉編譯器可以用來(lái)生成在其他平臺(tái)上可執(zhí)行的目標(biāo)代碼。

現(xiàn)代編譯器都是分層架構(gòu),分層能夠增加層之間的獨(dú)立性,從而更好地完成任務(wù)。Go編譯器分為前端和后端。Go編譯器的可執(zhí)行代碼在cmd/compile目錄中。Go編譯器的編譯過(guò)程主要分為如下幾個(gè)階段:詞法解析和語(yǔ)法解析、類(lèi)型檢查、生成SSA中間代碼、生成機(jī)器代碼。

1.6.1 詞法分析和語(yǔ)法分析

Go語(yǔ)言的編譯器根據(jù)編譯的參數(shù),對(duì)當(dāng)前涉及的所有Go源代碼文件進(jìn)行詞法分析。詞法分析的作用就是將源代碼文件中的字符串序列化成Token(標(biāo)記)序列,便于編譯器后面的進(jìn)一步處理和分析。一般來(lái)說(shuō),我們把執(zhí)行詞法分析的程序稱(chēng)為詞法分析器(Lexer)。

Go語(yǔ)法分析過(guò)程就是將詞法分析生成的Token序列按照Go語(yǔ)言定義好的語(yǔ)法(Grammar)進(jìn)行整理,從而構(gòu)建出抽象語(yǔ)法樹(shù)(AST)。每一個(gè)AST都對(duì)應(yīng)著一個(gè)單獨(dú)的Go源代碼文件,這個(gè)AST中包括當(dāng)前文件所屬的包名、定義的常量、結(jié)構(gòu)體和函數(shù)等信息,方便后續(xù)調(diào)試。

1.6.2 類(lèi)型檢查

Go作為一門(mén)靜態(tài)類(lèi)型語(yǔ)言,Go源代碼文件經(jīng)過(guò)編譯器的詞法分析和語(yǔ)法分析會(huì)生成多個(gè)文件的AST。Go語(yǔ)言的編譯器會(huì)對(duì)AST中定義和使用的類(lèi)型信息進(jìn)行檢查。類(lèi)型檢查的主要內(nèi)容有:

· 常量、類(lèi)型和函數(shù)名和函數(shù)類(lèi)型。

· 變量的賦值和初始化。

· 函數(shù)和閉包的主體。

· 哈希鍵值對(duì)的類(lèi)型。

· 導(dǎo)入函數(shù)體。

· 外部的聲明。

通過(guò)遍歷所有AST語(yǔ)法樹(shù)上的節(jié)點(diǎn),實(shí)現(xiàn)對(duì)每一個(gè)AST節(jié)點(diǎn)上的類(lèi)型進(jìn)行驗(yàn)證。在這個(gè)過(guò)程中,只要有一處類(lèi)型錯(cuò)誤或不匹配,編譯器就會(huì)終止編譯過(guò)程,并拋出錯(cuò)誤信息。

注意

類(lèi)型檢查這個(gè)階段除了類(lèi)型驗(yàn)證外,還會(huì)對(duì)AST進(jìn)行細(xì)節(jié)優(yōu)化,比如無(wú)用代碼消除、函數(shù)調(diào)用內(nèi)聯(lián)化等。

1.6.3 生成SSA中間代碼

Go編譯器對(duì)AST每個(gè)節(jié)點(diǎn)上的類(lèi)型檢查通過(guò)后,就可以認(rèn)為Go源代碼沒(méi)有語(yǔ)法錯(cuò)誤,此時(shí)Go編譯器可以將分析得到的AST翻譯成中間代碼。

Go編譯器利用SSA(Static Single Assignment Form)特性來(lái)生成中間代碼(Go匯編語(yǔ)言)。SSA能夠比較容易地分析出代碼中的無(wú)用變量和片段,并對(duì)代碼進(jìn)行優(yōu)化。

Go匯編語(yǔ)言作為一種中間代碼,可以更好地實(shí)現(xiàn)Go語(yǔ)言的跨平臺(tái)運(yùn)行。Go匯編語(yǔ)言基于Plan 9匯編,并不直接體現(xiàn)機(jī)器底層的硬件特性,直到最后續(xù)才會(huì)根據(jù)編譯的參數(shù)來(lái)決定把Go匯編語(yǔ)言翻譯成具體平臺(tái)的機(jī)器代碼。

1.6.4 生成機(jī)器代碼

要執(zhí)行Go程序代碼,必須借助Go編譯器來(lái)生成對(duì)應(yīng)的二進(jìn)制可執(zhí)行文件。Go編譯器會(huì)針對(duì)特定硬件架構(gòu)把中間代碼轉(zhuǎn)換成機(jī)器代碼。該編譯過(guò)程同樣會(huì)進(jìn)行代碼優(yōu)化,例如將變量移動(dòng)到更靠近它們被使用的位置、刪除從未被讀取的局部變量以及分配寄存器。

Go目錄cmd/compile/internal中包含了非常多的用于生成不同機(jī)器代碼所需的包。不同類(lèi)型的CPU(AMD64、ARM、ARM64、MIPS、MIPS 64、ppc64、s390x、x86和WASM)會(huì)用特定的包來(lái)生成機(jī)器代碼,這也是Go語(yǔ)言能夠在上述不同指令集的CPU上運(yùn)行的原因。

其中,WASM(Web Assembly)是一種在棧虛擬機(jī)上使用的二進(jìn)制指令格式,使得它成為Web瀏覽器上具有高可移植性的目標(biāo)語(yǔ)言。Go語(yǔ)言的編譯器可以通過(guò)參數(shù)GOARCH=wasm GOOS=js來(lái)生成WASM格式的可執(zhí)行目標(biāo)文件,該可執(zhí)行文件能夠運(yùn)行在主流的瀏覽器中。

注意

Go編譯器的編譯過(guò)程在不同版本中存在差異,而且實(shí)際過(guò)程往往更加復(fù)雜。

綜上所述,Go編譯器的編譯過(guò)程大致如圖1.13所示。

圖1.13 Go編譯器編譯過(guò)程示意圖

主站蜘蛛池模板: 永城市| 古丈县| 新民市| 崇阳县| 衡南县| 滕州市| 左权县| 贵南县| 阜阳市| 资中县| 天镇县| 运城市| 阜城县| 遂川县| 菏泽市| 怀远县| 黎城县| 长宁县| 屯留县| 平乡县| 黔江区| 新邵县| 宜春市| 翼城县| 左云县| 盐津县| 南阳市| 平乡县| 岳普湖县| 巫山县| 西和县| 民县| 镇远县| 遵义县| 上栗县| 腾冲县| 台中市| 大田县| 衡东县| 科技| 缙云县|