编译原理概论
编译器的核心功能是把源代码翻译成目标代码:
- 理解源代码
- 词法分析、语法分析、语义分析
- 转化为等价的目标代码
- 中间代码生成、目标代码生成
- 优化方法
编译器的概述
- 各种计算设备(计算机、嵌入式系统、智能设备等)都离不开编译器
- 各种计算设备的核心问题都是软件的构造
- 绝大部分软件都使用高级语言编写
- 高级语言种类繁多
- 使用高级语言编写的程序需要通过编译器才能在计算机上运行
- 计算机科学史上出现的第一个编译器是Fortran (Formula Translation) 语言的编译器
- John Backus
什么是编译器
- 编译器是一个程序
- 编译器的核心功能是把源代码翻译成目标代码
- 源代码:C/C++, Java, C#, HTML, …
- 目标代码:x86, IA64, ARM, MIPS, …
编译器的核心功能
源代码——>编译器——>静态计算——>目标代码——>计算机——>动态计算——>计算结果
编译器的结构
- 编译器具有非常模块化的高层结构
- 编译器可看成多个阶段构成的“流水线”结构
这是个简单的C语言程序:
#include <stdio.h>
int main()
{
int a = 3;
int b = 4;
int c = a + b;
printf("c=%d \n",c);
return 0;
}
通过编译器翻译成目标代码:
#include<stdio.h>
int main()
{
00E813C0 push ebp
00E813C1 mov ebp,esp
00E813C3 sub esp,0E4h
00E813C9 push ebx
00E813CA push esi
00E813CB push edi
00E813CC lea edi,[ebp-0E4h]
00E813D2 mov ecx,39h
00E813D7 mov eax,0CCCCCCCCh
00E813DC rep stos dword ptr es:[edi]
int a = 3;
00E813DE mov dword ptr [a],3
int b = 4;
00E813E5 mov dword ptr [b],4
int c = a + b;
00E813EC mov eax,dword ptr [a]
00E813EF mov eax,dword ptr [b]
00E813F2 mov dword ptr [c],eax
printf("c=%d \n",c);
00E813F5mov esi,esp
00E813F7 mov eax,dword ptr [c]
00E813FA push eax
00E813FB push 0E85858h
00E81400 ca11 dword ptr ds:[0E89114h]
00E81406 add esp,8
00E81409 cmp esi,esp
00E8140B call _RTC_CheckEsp (0E81136h)
return 0;
00E81410 xor esi,esp
}
词法分析器
从左到右,一个字符一个字符地读入源程序,对构成源程序的字符
流进行扫描和分解,从而识别出一个个单词。
词法分析器的任务
字符流——>词法分析器——>单词流
# 源代码
float limitedSquare(x)
{
float x;
return (x<=-10.0)||x>10.0)?100:x*x;
}
# 词法分析器转换后
<float,->
<id,limitedSquare>
<(,->
<id, x>
<) ,->
<{,->
<float>
<id, x>
<; ,->
<return,->
<(,->
<id, x>
<op,"<=">
<num, -10.0>
<op, "||">
<id, x>
<op, ">=">
<num, 10.0>
<) ,->
<op, "?">
<num, 100>
<op, ":">
<id, x>
<op, "*">
<id, x>
<; ,->
<},->
语法分析器
根据语言的语法规则,把单词符号串组成各类语法单位。
语法分析:是否符合语法
- 不符合:返回出错处理信息
- 符合:在单词流的基础上建立一个层次结构-----建立语法树
语法分析器是编译器的核心模块:
- 处理程序员所写程序的输入
- 产生编译器需要的重要结构
语法分析器的任务
单词流——>语法分析器(按照某种语言规则)——>语法树
语义分析器
语义检查:
- 变量或过程未经声明就使用
- 变量或过程名重复声明
- 运算分量类型不匹配
- 操作符与操作数之间的类型不匹配
语义分析器的功能
收集标识符的属性、类型(Type)、种属(Kind)、存储位置、长度、值、作用域、参数和返回值等相关信息。
中间代码生成器
中间代码是一种抽象的表示形式,通常比源代码更接近底层的目标机器代码,但又比目标机器代码更容易进行分析、优化和跨平台移植。中间代码可采用多种形式,如虚拟机指令、三地址码、静态单赋值(SSA)等表示。
代码优化器
在尽量不改变程序语义的前提下,对中间代码进行分析和优化,以产生执行速度较快的机器代码,提高程序在执行效率、内存占用和功耗等方面的性能。
代码生成器
生成可重定位的机器代码或汇编代码,以便在目标平台上执行程序。
符号表
基本功能是记录源程序中使用的标识符,并收集与每个标识符相关的各种属性信息,记录到符号表中。
- 符号表是一个数据结构
- 每个标识符在符号表中都有一条记录
例:int a,b;
名字 | 记号 | 类型 | 种属 | …… | addr |
---|---|---|---|---|---|
a | id1(25) | int | 简变 | 0 | |
b | id2(25) | int | 简变 | 4 |
错误处理器
以上各阶段难免会遇到错误:
- 处理方式:报告错误,应继续编译
- 大部分错误在语法分析、语义分析阶段检测出来
- 词法分析:字符无法构成合法单词
- 语法分析:单词流违反语法结构规则
- 语义分析:语法结构正确,但无实际意义
总结
编译器由多个阶段组成,每个阶段都要处理不同的问题
-
使用不同的理论,数据结构,和算法
-
因此,编译器设计中的重要问题是如何合理的划分组织各个阶段
-
接口清晰
-
编译器容易实现与维护
-
编译器技术的应用
- 高级程序设计语言的实现
- 针对计算机体系结构的优化(并行性与内存层次结构)
- 新计算机体系结构的设计(CISC RISC)
- 程序翻译
- 软件生产率工具(查错)