第一章 引论
1.1 编译程序基本概念
- 程序能够执行的条件
首先使用编译程序把源程序翻译成机器语言,然后在目标机器上面运行目标语言,源程序和目标
序在逻辑上是等价的。高级语言分为两种,一种是翻译程序(先生成目标代码再执行),一种是
解释程序(一边解释一边执行,不产生目标代码)。
- 编译程序相关概念
宿主机:运行编译程序的主机
目标机:运行编译程序产生的目标代码的机器
交叉编译程序:产生不同于宿主机的机器代码的编译程序
可变目标编译程序:不需要重写编译程序中与机器无关的部分就可以改变目标机
诊断编译程序:用于帮助开发和调试程序
优化编译程序:用于提高目标代码的编译程序
1.2 编译过程的概述
- 类比英文翻译过程,具体过程如下
1.识别句子中的一个个单词(词法分析)
2.分析句子的语法结构(语法分析)
3.根据句子的含义进行初步翻译(语义分析与生成中间代码)
4.对译文进行修饰(优化)
5.写出最后的译文(目标代码的生成)
- 词法分析
扫描源程序,识别出==一个个单词==(关键字,标识符(变量)运算符,括号等)
for I := 1 to 100 do
| 字符串 | 名称 |
|---|---|
| for | 基本字 |
| I | 标识符 |
| := | 赋值号 |
| 1 | 整常数 |
| to | 基本字 |
| 100 | 整常数 |
| do | 基本字 |
- 语法分析
在词法分析的基础上,根据语言的语法规则,把单词符号串分解成各类语法单位。通过语法分析,确定整个输入串是否构成语法上正确的程序。
- 语义分析和中间代码产生
对语法范畴进行静态检查,如变量是否定义,类型是否正确等。检查无误则进行中间代码翻译,这一阶段依据语言的语义规则。许多编译器使用与“三地址指令”非常近似的“四元式”作为中间代码**(还有三元式,间接三元式,逆波兰记号和树形表示)**,如下所示。
Z := (X+0.418)*Y/W
| 序号 | 运算符 | 左操作数 | 右操作数 | 结果 |
|---|---|---|---|---|
| 1 | + | x | 0.418 | t1 |
| 2 | * | t1 | y | t2 |
| 3 | / | t2 | w | z |
- 优化
对产生的中间代码进行加工,以满足产生更加高效的目标代码。主要方面有:公共子表达式的提取、循环优化、删除无用代码,如下所示。
for K := 1 to 100 do
begin
M := I + 10 * K
N := J + 10 * K
end
1.3 编译程序的结构
- 编译程序总框
- 表格和表格管理
用于登记源程序的各类信息和编译各类阶段的进展状况,其中最重要的是符号表,用来登记源程序
中出现的每一个名字以及名字的各种属性。(扫描到一个标识符不能马上确认它所有的属性,有些
属性后面才知道)
- 出错处理
编译过程中发现程序错误,并把错误信息报告给用户
- 遍
遍就是对源程序和源程序的中间结果扫描一边,并作相应的处理,生成新的中间结果和目标程序。
根据不同的情况可以将编译过程的多个阶段合为一边,为了让编译逻辑结构更加清晰也可以将一个
阶段拆分成几遍,通常从外存获得前一遍的结果处理后再放入外存中。实例如下:
词法分析 | 语法分析 | 中间代码生成 ——遍——> 优化 ——遍1——> ... ——遍n——> 目标代码
- 编译的前端和后端
编译前端:前端主要由与源语言有关但与目标机无关的那部分组成,通常包括词法分析,语法分
析,语义分析与中间代码生成。
编译后端:编译程序中与目标机有关的哪些部分,如与目标机有关的代码优化和目标代码生成等。
1.4 编译程序与程序设计环境(略)
1.5 编译程序的生成
- 用L1语言编写L2语言的编译程序
步骤:
1. 使用L1语言编写L2语言编译器程序
2. 将上面的编译器程序作为L1编译器程序的输入,产生可以在A机器上执行的L2编译器程序
3. 将L2语言编写的程序作为上一步骤的编译器程序的输入,则生成可以在A机器上面直接运行的目标代码
- 用L语言编写能在B机器上执行的L编译程序
步骤:
1. 使用L语言编写能够在B上面执行的编译器
2. 将上面的编译器程序作为A中L编译器的输入,生成可以在A执行的L编译程序(这个编译程序产
生可以在B中执行的目标代码)
3. 把L语言编写的编译程序作为上述编译程序的输入,生成可以在B中执行的编译程序
4. 把L语言编译程序作为B中的编译程序的输入,生成可以在B中执行的程序