Skip to content

1 、编译器简介


一、基础🧀

  • 编译器是一个程序,把源代码变成目标代码
    • 源代码是指比如C++,Java
    • 目标代码是指比如×86,ARM,MIPS
flowchart LR
    A["源代码"] --> B["编译器"]
    B -->|静态计算| C["目标程序"]
    C --> D["计算机"]
    D -->|动态计算| E["计算结果"]
  • 解释器也是一种程序,但是输出和编译器不一样
flowchart TB
    I1["I"] --> C["C"] --> O1["O:可执行程序"]
    I2["I"] --> INT["I"] --> O2["O:结果"]

    style C fill:#fff,stroke:#333,stroke-width:2px
    style INT fill:#fff,stroke:#333,stroke-width:2px

二、结构🧀

编译器是由多个阶段构成的流水线结构

flowchart TB
    S["字符序列"] --> L["词法分析"]
    L -->|记号序列| P["语法分析"]
    P -->|抽象语法树| M["语义分析"]
    M -->|中间代码| G["代码生成"]
    G --> T["目标代码"]

    ST["符号表"]
    ST --- L
    ST --- P
    ST --- M
    ST --- G

    style S fill:none,stroke:none,color:#3344cc
    style T fill:none,stroke:none,color:#3344cc

    style L fill:#ffffff,stroke:#555,stroke-width:1.5px
    style P fill:#ffffff,stroke:#555,stroke-width:1.5px
    style M fill:#ffffff,stroke:#555,stroke-width:1.5px
    style G fill:#ffffff,stroke:#555,stroke-width:1.5px
    style ST fill:#ffffff,stroke:#555,stroke-width:1.5px

没有优化的编译器

flowchart TB
    S["源代码"] --> A["词法分析"]
    A -->|记号| B["语法分析"]
    B -->|动作| C["语法树构造"]
    C -->|抽象语法树| D["语义分析"]

    D -->|中间树| E["翻译"]
    E -->|中间树| F["正规化"]
    F -->|中间树| G["指令选择"]
    G -->|抽象汇编| H["控制流分析"]

    H -->|控制流图| I["数据流分析"]
    I -->|寄存器分配| J["代码生成"]
    J -->|汇编代码| K["汇编器"]
    K -->|可重定位目标代码| L["连接器"]
    L --> T["可执行代码"]

    style S fill:none,stroke:none
    style T fill:none,stroke:none

    style A fill:#fff,stroke:#222,stroke-width:2px
    style B fill:#fff,stroke:#222,stroke-width:2px
    style C fill:#fff,stroke:#222,stroke-width:2px
    style D fill:#fff,stroke:#222,stroke-width:2px
    style E fill:#fff,stroke:#222,stroke-width:2px
    style F fill:#fff,stroke:#222,stroke-width:2px
    style G fill:#fff,stroke:#222,stroke-width:2px
    style H fill:#fff,stroke:#222,stroke-width:2px
    style I fill:#fff,stroke:#222,stroke-width:2px
    style J fill:#fff,stroke:#222,stroke-width:2px
    style K fill:#fff,stroke:#222,stroke-width:2px
    style L fill:#fff,stroke:#222,stroke-width:2px

更加复杂的编译器

把表达式 1+2+3 编译成栈式计算机指令

首先,编译器前端对源程序进行词法、语法和语义分析,构造抽象语法树。由于加法通常按左结合处理,因此表达式会被解析为:

(1 + 2) + 3

对应的抽象语法树为:

1
2
3
4
5
        +
       / \
      +   3
     / \
    1   2

随后,代码生成器按抽象语法树的后序遍历顺序生成栈式指令

1
2
3
4
5
push 1
push 2
add
push 3
add

执行过程是:先将 12 压栈,执行 add 得到 3;再将常量 3 压栈,再次执行 add,最终栈顶结果为 6

三、简单实例🧀

1、源语言🧀

加法表达式语言 Sum

  • 两种语法形式
    • 整形数字 \(n\)
    • 加法 \(e_1+e_2\)

2、栈式计算机 Stack🧀

  • 一个操作数栈
  • 两条指令
    • 压栈指令:push n
    • 加法指令: add