编译原理 DAY01

249 阅读5分钟

第一章 引论

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+x0.418t1
2*t1yt2
3/t2wz
  • 优化

对产生的中间代码进行加工,以满足产生更加高效的目标代码。主要方面有:公共子表达式的提取、循环优化、删除无用代码,如下所示。

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中执行的程序