1.编译器

1.1 三阶段编译器

  • 编译器前端: 次要用于了解源代码、扫描解析源代码并进行语义表白
  • IR: Intermediate Representation,可能有多个,编译器会应用多个 IR 阶段、多种数据结构示意程序,并在两头阶段对代码进行屡次优化
  • 优化器: 次要目标是升高程序资源的耗费,但有实践曾经表明某些优化存在着NP难题,所以编译器无奈进行最佳优化,通常罕用折中计划
  • 编译后端: 次要用于生成特定指标机器上的程序,可能是可执行文件,也可能是须要进一步解决的obj、汇编语言等

1.2 Go语言编译器

src/cmd/compile/internalTips: 留神:大写的GC示意垃圾回收

2.词法解析

go/src/cmd/compile/internal/syntax/tokens.gogo/src/go/scanner、go/src/go/token

2.1 scanner.go 代码简介

go/src/go/scanner
const (
ScanComments    Mode = 1 << iota // 返回正文作为正文标记
dontInsertSemis                  // 不要主动插入分号-仅用于测试
)
func isLetter(ch rune) bool {
return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= utf8.RuneSelf && unicode.IsLetter(ch)
}
func isDigit(ch rune) bool {
return '0' <= ch && ch <= '9' || ch >= utf8.RuneSelf && unicode.IsDigit(ch)
}

2.2 token.go 代码代码简介

go/src/go/token
  • init()函数: 初始化关键字keywords变量(map[string]Token)的值
map[break:61 case:62 chan:63 const:64 continue:65 default:66 defer:67 else:68 fallthrough:69 for:70 func:71 go:72 goto:73 if:74 import:75 interface:76 map:77 package:78 range:79 return:80 select:81 struct:82 switch:83 type:84 var:85]
  • String()函数: 返回与令牌 tok 对应的字符串,对于操作符、分隔符和关键字,字符串是理论的标记字符序列(例如,对于标记ADD,字符串是“+”),对于所有其余令牌,字符串对应于令牌常量名(例如,对于令牌IDENT,字符串为“IDENT”)
  • Precedence()函数: 返回二进制操作符 op 的操作符优先级,如果op不是二进制操作符,则后果为最低优先级
  • Lookup()函数: 查找标记符对应的token
  • IsLiteral() 函数: 判断token值是否是根本类型范畴的值,若是返回true,否则返回false
  literal_beg
  // Identifiers and basic type literals
  // (these tokens stand for classes of literals)
  IDENT  // main
  INT    // 12345
  FLOAT  // 123.45
  IMAG   // 123.45i
  CHAR   // 'a'
  STRING // "abc"
  literal_end
  • IsOperator() 函数: 判断token值是否是操作范畴的值,若是返回true,否则返回false
  operator_beg
  // Operators and delimiters
  ADD // +
  SUB // -
  MUL // *
  QUO // /
  REM // %

  AND     // &
  OR      // |
  XOR     // ^
  SHL     // <<
  SHR     // >>
  AND_NOT // &^

  ADD_ASSIGN // +=
  SUB_ASSIGN // -=
  MUL_ASSIGN // *=
  QUO_ASSIGN // /=
  REM_ASSIGN // %=

  AND_ASSIGN     // &=
  OR_ASSIGN      // |=
  XOR_ASSIGN     // ^=
  SHL_ASSIGN     // <<=
  SHR_ASSIGN     // >>=
  AND_NOT_ASSIGN // &^=

  LAND  // &&
  LOR   // ||
  ARROW // <-
  INC   // ++
  DEC   // --

  EQL    // ==
  LSS    // <
  GTR    // >
  ASSIGN // =
  NOT    // !

  NEQ      // !=
  LEQ      // <=
  GEQ      // >=
  DEFINE   // :=
  ELLIPSIS // ...

  LPAREN // (
  LBRACK // [
  LBRACE // {
  COMMA  // ,
  PERIOD // .

  RPAREN    // )
  RBRACK    // ]
  RBRACE    // }
  SEMICOLON // ;
  COLON     // :
  operator_end
  • IsKeyword() 函数: 判断token值是否是关键字范畴的值,若是返回true,否则返回false
  keyword_beg
  // Keywords
  BREAK
  CASE
  CHAN
  CONST
  CONTINUE

  DEFAULT
  DEFER
  ELSE
  FALLTHROUGH
  FOR

  FUNC
  GO
  GOTO
  IF
  IMPORT

  INTERFACE
  MAP
  PACKAGE
  RANGE
  RETURN

  SELECT
  STRUCT
  SWITCH
  TYPE
  VAR
  keyword_end

3.语法解析

go/src/cmd/compile/internal/syntax/nodes.gogo/src/cmd/compile/internal/syntax/parser.go
//包导入申明
ImportSpec = [ "." | PackageName ] ImportPath .
ImportPath = string_lit .
//动态常量
ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] .
//类型申明
TypeSpec = identifier [ "=" ] Type .
//变量申明
VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .

3.1 nodes.go 代码代码简介

AssignStmt struct {
    Op       Operator // 示意以后的操作符,即":=",0 示意没有操作
    Lhs, Rhs Expr     // Lhs, Rhs 别离代表左右两个表达式,Rhs == ImplicitOne means Lhs++ (Op == Add) or Lhs-- (Op == Sub)
    simpleStmt
}
//Pos() 返回与节点相关联的地位,如下所示:
// 1)示意终端语法产物(Name,BasicLit等)的节点地位是相应产物在源中的地位。
// 2)示意非终端产品(IndexExpr, IfStmt等)的节点的地位是与该产品惟一关联的令牌的地位;通常是最右边的一个('['示意IndexExpr, 'if'示意IfStmt,等等)

type Node interface {
    Pos() Pos
    aNode()
}

3.2 parser.go 代码代码简介

type parser struct {
  file *PosBase
  errh ErrorHandler
  mode Mode
  scanner

  base   *PosBase // 以后地位的基准
  first  error    // 遇到的第一个谬误
  errcnt int      // 遇到的谬误数
  pragma Pragma   // 编译批示标记

  fnest  int    // 函数嵌套级别(用于错误处理)
  xnest  int    // 表达式嵌套级别(用于解决编译歧义)
  indent []byte //跟踪反对
}
const stopset uint64 = 1<<_Break |
1<<_Const |
1<<_Continue |
1<<_Defer |
1<<_Fallthrough |
1<<_For |
1<<_Go |
1<<_Goto |
1<<_If |
1<<_Return |
1<<_Select |
1<<_Switch |
1<<_Type |
1<<_Var

3.3 语法解析举例

a := b + c(10)
//Tips: c(10) 示意强类型转换。

a := b + c(10)语句被语法解析后转换为对应的 syntax.AssignStmt 构造体之后,最顶层的 Op 操作符为 token.Def(:=)。Lhs 表达式类型为标识符syntax.Name,值为标识符 “a”。Rhs表达式为 syntax.Operator 加法运算,加法运算右边为标识符 “b”,左边为函数调用表达式,类型为 CallExpr,其中,函数名 c 的类型为 syntax.Name,参数为常量类型 syntax.BasicLit,代表数字 10。

4.形象语法树构建

func (p *noder) decls(decls []syntax.Decl) (l []*Node) {
var cs constState

for _, decl := range decls {
    p.setlineno(decl)
    switch decl := decl.(type) {
    case *syntax.ImportDecl:
        p.importDecl(decl)

    case *syntax.VarDecl:
        l = append(l, p.varDecl(decl)...)

    case *syntax.ConstDecl:
        l = append(l, p.constDecl(decl, &cs)...)

    case *syntax.TypeDecl:
        l = append(l, p.typeDecl(decl))

    case *syntax.FuncDecl:
        l = append(l, p.funcDecl(decl))

    default:
        panic("unhandled Decl")
    }
}

return
}

5.类型查看

go/src/cmd/compile/internal/gc/typecheck.go

6.变量捕捉

package main

import (
  "fmt"
)

func main()  {
  a := "qinshixian"
  b := make(map[string]int)
  c := "haoweilai"
  go func() {
      fmt.Println(a)
      fmt.Println(b)
      fmt.Println(c)
  }()
  a = "asddss"
}

7.函数内联

package main

import "testing"

//go:noinline
func max(a, b int) int {
  if a > b {
      return a
  }
  return b
}

var Result int

func BenchmarkMax(b *testing.B) {
  var r int
  for i := 0; i < b.N; i++ {
      r = max(-1, i)
  }
  Result = r
}

//Tips://go:noinline 示意以后函数禁止函数内联优化。

没有加上正文 //go:noinline 运行 go test leetcode_test.go -bench=. 如下图:

函数外部有 for、range、go、select 等语句时,如下图:

若想查看函数是否能够应用函数内联,可应用 命令 go tool compile -m=2 leetcode_test.go,如下图所示:

8.逃逸剖析

(1)准则1:指向栈上对象的指针不能被存储到堆中
(2)准则2:指向栈上对象的指针不能超过该栈对象的生命周期
package main

var n *int

func escape(){
  a := 100
  n = &a
}

func main()  {
  escape()
}