概述
Go源码程序首先经过go编译器生成plan9汇编,再由汇编器和链接处理得到最终的可执行程序。
编译器
编译器对go源码的处理过程主要包含以下三个过程:词法语法分析、类型检查和AST转换、SSA优化和降级转换,最终go源码生成对应的plan9汇编。
Go程序的编译入口是 compile/internal/gc/main.go文件的Main函数,Main函数获取命令行参数并更新编译选项和配置,
然后运行parseFiles函数对输入的所有文件进行词法和语法分析,得到对应的AST抽象语法树。这是编译的第一个阶段。
func Main(archInit func(*Arch)) {
// 获取命令行参数、更新编译器选项和配置
...
timings.Start("fe", "parse")
lines := parseFiles(flag.Args()) // 词法语法解析go文件,得到AST
timings.Stop()
// 处理AST,类型检查、AST转换、编译等
...
}
词法语法分析
词法分析:分析go源代码文本,将文本中的字符序列转换为标记序列。 比如说go源码中的关键字package 会转换为 _package 标记,func转换为_func标记,
(
转换为 _Lparen标记 等等
compile/internal/syntax/tokens.go 文件定义了Go语言支持的的全部token类型,
比如说名称和文本、操作符、定界符、关键字等,下面列出了部分token对应关系。
const (
_ token = iota
_EOF // EOF
// names and literals
_Name // name
_Literal // literal
// operators and operations
// _Operator is excluding '*' (_Star)
_Operator // op
...
// delimiters
_Lparen // (
_Lbrack // [
_Lbrace // {
...
// keywords
_Break // break
_Case // case
_Chan // chan
...
// empty line comment to exclude it from .String
tokenCount //
)
compile/internal/syntax/scanner.go 文件实现了词法解析器主要部分,
使用scanner结构体的next方法实现go文件的扫描并转换为token序列,next方法获取文件中未被解析的字符,进入switch/case分支进行词法解析。scanner结构和next主体代码如下:
// scanner 结构体
type scanner struct {
source // 数据源文件
mode uint
nlsemi bool // if set '\n' and EOF translate to ';'
// current token, valid after calling next()
line, col uint
tok token
lit string // valid if tok is _Name, _Literal, or _Semi ("semicolon", "newline", or "EOF")
kind LitKind // valid if tok is _Literal
op Operator // valid if tok is _Operator, _AssignOp, or _IncOp
prec int // valid if tok is _Operator, _AssignOp, or _IncOp
}
// 扫描转换文本为token序列
func (s *scanner) next() {
nlsemi := s.nlsemi
s.