Compiler|Overview & Architecture & Phase

Introduction

Purpose for compiler

通过之前的部分学习其实我们已经可以知道了,编译器的目的本质上其实是将 高级编程语言 写下的代码在不改变原有意义的情况下转化为 目标代码

同时编译器应当针对生成的目标代码进行最优化处理并使从时间和空间上运行更高效

Why compiler

  • 因为考试要考XD
  • 计算机本质上是硬件+软件的平衡组合,而两者之间之所以需要结合,存在一定的问题。
    • 硬件只是一堆机械设备,他们以高低电平(不是0就是1)的方式来理解我们的指令。
    • 如果让软件开发者直接通过0和1来写代码不仅繁琐而且可读性可维护性都很差,因此需要借助编译器。

Prerequisites

不需要别的,起码你会 c 或者是 java,能有汇编基础那就更好了。

Audience

本教程基于 Compiler Design Tutorial 进行学习,针对后续深入的理解,可以考虑二刷的时候配合 龙书 + CS143 进行学习。

Overview

Language Processing System

硬件理解的是 0 和 1,而我们通过人类可以理解的高级编程语言语法所写下的代码,将他们作为系列 OS 组件以及工具的输入,最后得到机器可以执行的二进制代码,这一步骤就称为 Language Processing System

Program executed

编译器整个系统可以大致概括为如下的图

Language Processing System

我们直接举一个例子:

当我们写的 c 语言的代码在编译执行的过程中,其实是如下的几个阶段

  • 我们通过遵循高级编程语言的语法来编写 c 语言的代码。
  • c 语言的编译一起将程序编译并转化为低级编程语言的汇编代码。
  • 汇编器将汇编代码转化为可执行的目标代码(机器码)。
  • 连接器将程序所需要的各个部分连接在一起合并生成可执行文件。
  • 装载器将程序的指令和数据状态进内存之后执行程序。

tools work closely with compilers

Preprocessor

预处理器。

他是被认为是编译器的其中一个部分,通过文件包含,语言扩展等方式来处理将结果作为编译器的输出文件。

Interpreter

和编译器类似,但是有区别,区别在于读取源码/输入的方式。

  • 编译器一次读取整个代码,而解释器一次读取一条语句(statement)。
  • 编译器遇到多个错误也会读取整个程序,而编译器遇到错误就直接停止。

Assembler

汇编器的目的主要是将汇编代码转化为机器码。

Linker

用于连接多个汇编器执行的目标代码结果。

Loader

操作系统提供的一个抽象,用于加载程序并计算程序指令和数据在内存中的具体位置。

Cross-compiler

可以生成(另一个)跨平台可执行文件的汇编器我们就说他是一个 cross-compiler

Source-to-source compiler

一般的编译器都是直接生成可执行的机器码,但是如果对于一个编译器他生成的是另一种高级编程语言的代码则称他是 source-to-source 的编译器。

Architecture

根据编译的不同方式主要可以分为两个部分:分析阶段和合成阶段。

Analysis and Synthesis phase of compiler

Analysis Phase

编译器的前端。

读取源码,检验语法准确性。

生成中间状态的源代码以及 symbol table 作为 Synthesis Phase 的输入。

Synthesis Phase

编译器的后端

读取源码的中间表示形式以及 symbol table 生成机器代码**(target code)**。

Phases

基本概念

需要区分一下基本的 Pass 和 Phase 的区别。

Pass 指的是编译器针对源程序的一次完整遍历。

而编译器的 Phase 指的是一次可区分的阶段,一次阶段通过读取上一阶段的输出作为输入,同时将这一阶段的输出作为下一阶段的输入。

Phases of compiler

编译器有不同的几个阶段,如下图:

Phases of compiler

Lexical Analysis

扫描源码为字符流,同时词法分析器(lexical analyzer)会读取源程序生成 token。

1
<token-name,attribute-value>

Syntax Analysis

检查词法分析器生成的 token 是否在语法上正确。

语法分析器最终会生成 parse tree。

Semantic Analysis

语义分析主要检查 语法分析树 是否遵循语法的规则。

例如检查变量赋值是否遵循这个语言规定的类型(类型是否能兼容)。

同时也会记录程序中声明的标识符等出现的情况(比如是否要求先声明所有变量之后再使用)。

最终语义分析阶段会在语法分析树的基础上生成带有注释的语法分析树

Intermediate Code Generation

生成介于高级编程语言和机器语言两者之间的汇编代码,要求这个汇编代码能够易于转化为机器码。

对于 gcc,我们有如下的操作来生成 intermediate code

1
gcc -s hello.c

这里的 s 就表示 stop,表示到了这一阶段就停止。

Code Optimization

编译器的优化阶段,这一阶段的目的是为了让二进制程序运行所占用的资源更小。

1
gcc -o

这里的 -o 就是 optimize 开启编译器的优化阶段。

Code Generation

将上一个阶段生成的优化后的汇编代码对应映射到机器码中并生成。

Symbol Table

这是在编译器的所有阶段都维护的一个数据结构

所有标识符的名称以及类型都存储在这个表格中。

其作用在于让编译器更快速定位标识符和标识符的作用域管理。


Compiler|Overview & Architecture & Phase
http://example.com/2022/11/22/Compiler-Overview-Architecture-Phase/
作者
Noctis64
发布于
2022年11月22日
许可协议