一切从编译开始 | 青训营笔记

93 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 16 天

1.1 前言

真正学习一门语言是离不开和其底层源码打交道的,本文将从 Go 语言的编译机制出发,深入了解 Go 语言的设计初衷和其优势与劣势。

1.2 基本术语介绍

1.2.1 抽象语法树

抽象语法树(Abstract Syntax Tree,俗称 AST),是源代码语法的结构的一种抽象表示,它用树状的方式表示编程语言的语法结构。抽象语法树中的每一个节点都表示源代码中的一个元素,每一棵子树都表示一个语法元素,以表达式 2 * 3 + 7 为例,编译器的语法分析阶段会生成如下图所示的抽象语法树。

image.png

抽象语法树将源代码中不重要的字符省略后分析得出一个抽象语法树,以此辅助编译器进行语义分析,同时也可以确定语法正确的程序是否存在一些类型不匹配的问题。

1.2.2 静态单赋值

静态单赋值(Static Single Assignment,俗称 SSA),是中间代码的特性,如果中间代码具有静态单赋值的特性,那么每个变量就只会被赋值一次。在实践中,我们通常会用下标实现静态单赋值,这里以下面的代码举个例子。

x := 1
x := 2
y := x

那么以上代码生成的 SSA 中间代码显然如下。

x_1 := 1
x_2 := 2
y_1 := x_2

由此可见前一段代码中x := 1其实是没有意义的,经过 SSA 优化后会自动舍去从而减少需要执行的指令量。

1.3 编译原理

1.3.1 编译器

Go 语言编译器的源代码在src/cmd/compile目录中,目录下的文件共同组成了 Go 语言的编译器。

image.png

编译器一般分为前端和后端,前端一般负责着词法分析、语法分析、类型检查、和中间代码生成,后端一般负责目标代码的生成和优化,即优化中间代码后译为二进制机器码。

1.3.2 核心过程

Go 语言的编译器可按逻辑分为四个阶段,分别如下图所示。

image.png

以上四个阶段中,蓝色部分为编译器前端承担的工作,剩下则为编译器后端承担的工作,那么下文将在一定深度去了解以上四个阶段具体内容(更多内容见下期笔记)。

文章参考:左书祺《Go语言设计与编译》——「编译原理」