(编译原理)第一节 编译概述

计算机中的编译

高级语言(C、Java等)编写的代码不能直接在计算机上执行,计算机只能直接执行机器语言。
代码需要用相应的翻译程序翻译为机器语言,编译程序就是一种用于翻译的程序
编写编译程序涉及的原理、技术及方法 即为编译原理

影响计算机系统性能几大要素

程序设计:算法、数据结构、软件架构、协议等
硬件基础:计算器、存储器、网络等硬件性能
编译器性能:将源代码转为的机器码时的效果

不同的程序

翻译程序:能够将某种语言写的程序转换成另一种语言的程序,而且后者与前者在逻辑上是等价的。
解释程序:将高级程序设计语言写的源程序作为输入,边解释边执行源程序本身,而不产生目标程序的翻译程序。编译程序实质上是一个翻译程序,要注意等价交换
其他程序:诊断编译程序、优化编译程序、交叉编译程序、可变目标编译程序

高级语言的运行方式

编译方式:利用编译程序 将高级语言程 序翻译为机器语言程序,然后再运行这个机器语言程序
解释方式:利用解释程序直接读取高级语言程序中的每个语句,翻译并直接执行
混和方式:先编译再解释

高级语言编译流程

(用户源程序.c)预处理程序(标准源程序.i)编译程序(汇编语言程序.asm)汇编程序(可程序定位的二进制目标代码.obj)连接程序(可执行的机器代码.exe)

预处理

C语言的预处理程序(Preprocessor)首先要对用户源程序中的宏定义和文件包含等进行处理
宏定义——宏展开
文件包含——将文件中的内容插入到此处来替换此语句
有些预处理程序还能够处理语言功能的扩充,就把它转换为该语言编译程序能够识别的形式加入到标准源程序中。
在VC++6.0中,通过预处理后,将.c的源程序变为了.i的文本文件。

编译

标准的C语言程序由编译程序翻译为对应于某个计算机上的汇编语言程序。
汇编语言是和机器语言一一对应的易于阅读的文本形式的语言。编译的结果是某种机器上汇编语言书写的程序。
在VC++6.0中,编译这一步将.i的文本文件生成了.cod的文本文件,这就是汇编代码。有的编译器生成.s或.asm后缀的文件。

汇编

汇编语言程序需要由汇编程序翻译为二进制机器目标代码(机器语言描述的程序)。大多数编译器生成的目标代码是后缀为.obj的二进制文件。
有些编译程序不生成汇编代码,直接生成二进制目标代码,直接传给链接程序。也有编译程序直接生成可执行代码

链接

目标文件本身还不能直接运行 。链接程序(Linker)把目标文件转换为最终可以运行的程序。
待链接的目标文件可以是多个,它们可以是分别编译或汇编得到的,也可以是系统提供的库文件。
链接过程中需要修改重定位的地址,修改其中的指令和数据,以便后续放在内存中适当的地方,最终形成可执行文件。
VC++6.0编译器链接后生成的文件是后缀名为.exe的可执行文件。
静态链接方式:把公用库内的代码合并到可执行文件内部,可执行文件的体积庞大。
不足:会导致可执行文件版本难以控制; 如果有多个程序调用相同的公用库函数,在运行时这些公用库函数的代码在内存中将有多份拷贝,占用了多余的内存空间
动态链接方式:
仅记录动态链接库的路径信息。允许程序运行前才加载所需的动态链接库。 这样不仅节约磁盘和内存空间,还有利于可执行文件版本的更新。
不足:运行时加载会增加程序执行的时间开销;而且如果动态链接库的版本错误可能会导致程序无法执行。
不同工具的编译流程:
VC++6.0: hello.c - hello.i - hello.cod - hello.obj - hello.exe
GCC:hello.c - hello.i - hello.s - hello.o - hello.exe

编译过程和编译程序的结构

编译程序完成从源程序到目标程序的翻译工作。整个工作过程需要分阶段完成,每个阶段完成不同的任务,各个阶段进行的操作在逻辑上是紧密相关的,每个阶段的工作都通过相应的程序来完成。
编译程序就是由完成这些功能的全部程序组成的。每个阶段把源程序从一种表示变换成另一种表示
源程序 - 编译程序(词法分析、语法分析、语义分析、中间代码生成、中间代码优化、目标代码生成) - 目标程序

词法分析

任务:识别单词、 滤掉无意义的字符、发现错误
单词种类:
(1) 标识符
(2) 关键字(char、int、if、else、while、for等)
(3) 运算符(即运算符号 +、-、* 、/、&等)
(4) 界符(常见的有 ; , : ( )等)
(5) 常数
词法分析依据语言的词法规则

语法分析

任务: 根据语法规则,判断句子结构是否正确 。例:程序、语句、表达式
根据规则判定:
表达式 :标识符、常数是表达式。表达式的运算也是表达式
赋值语句(一种特殊的表达式): 标识符 赋值运算符(=) 表达式
area = 5 + length * width + length * width是一个赋值语句,也是一个表达式
5 + length * width + length * width是一个表达 式而不是一个赋值语句

语义分析

任务:对源程序中各种符号的必要信息进行收集,如变量的类型、作用域、初值等,并将这些信息填入符号表中。

源程序中的符号主要有两种:函数和变量。 变量是数据的符号化形式,函数是代码的符号化形式。

语义分析依据语言的语义规则

对程序进行静态语义检查:
变量和函数使用前是否定义;
变量赋值的类型是否兼容;
数组维数是否相同,数组下标是否越界;
renturn语句返回的类型和函数返回值的类型是否兼容;
break、continue语句的使用是否合适;
函数调用时参数列表是否兼容

中间代码生成

任务:进行初步的翻译(翻译成中间代码)。
中间代码形式
四元式: (运算符,运算对象1,运算对象2,结果)
对赋值语句area =5 + length * width + length * width
id1=int1 + id2 * id3 + id2 * id3

代码优化

任务:对已产生的中间代码进行加工变换,使生成的目标代码更为高效(时间和空间)。

目标代码生成

任务:把中间代码(或经优化的中间代码)变换成特定机器上的低级语言代码(汇编语言或机器语言)

编译阶段的基本概念

编译前端:主要指与源语言有关,与目标语言无关的部分,通常包括词法分析、语法分析、语义分析和中间代码生成,与机器无关部分的代码优化
编译后端:指与目标机器有关的部分。如与机器有关的优化、目标代码生成

编译程序的构造方法

构造编译程序要掌握以下几方面的内容:
源语言:理解其结构和含义
目标语言:清楚硬件的系统结构和指令的格式等
编译方法

一般实现编译程序的方法有:
1.直接用机器语言或汇编语言编写编译程序
2.用高级语言编写编译程序 (用编译工具自动生成:LEX与YACC 、自编译 、移植)

Sample语言

Sample语言是类C语言的一种简易语言。
Sample语言选择实现了C语言的基本功能,包括常量、变量、函数定义,常见的表达式、赋值语句、分支if语句、循环while、do while、for语句,以及函数调用与返回 。删除了一些复杂的、难理解的成分,比如数组和指针

Sample语言规范

(1)字符集
Sample语言的字符集就是编写Sample语言程序能够使用的所有字符的集合。
Sample语言的字符集是由英文大写字母、小写字母、数字、下划线和空白符号,以及下述特殊符号构成的集合:+、-、*、/、%、=、>、<、!、&、|、(、)、[、]、{、}、,、.、;、'、"、\

(2)单词
单词是由字符集中的符号按照构词规则组成的。Sample语言中的单词分为5类:常数、标识符、关键字、运算符、分界符
关键字、运算符和界符的种类是固定的,可以列表。
注意:运算符由优先级和结合性来决定运算对象的运算次序;

(3)关键字

有三个保留字:main、read和write,它们不是Sample的关键字,但有固定含义,不能作它用;
(4)运算符
运算符由优先级和结合性来决定运算对象的运算次序;
界符用来分隔单词,除运算符外,还包括左右大括号{和}、分号;和逗号,以及不计入合法单词的单引号、双引号、句号、空白符号和注释,它们不能独立作为单词,但它们可以用来分隔单词。
注释是用/*和*/括起来的任意多行字符、以及用//标识的单行注释;
空白符包括:空格、\t、\n、\r等几个。
(5)数据类型
Sample语言内部数据类型:
1. 整型
2. 字符型
3. 实型
(6)表达式
通过运算符对运算对象进行操作。
算术运算符包括+、-、*、/、%,运算对象是指各种标识符和常量,也可以是函数调用,运算符之间服从“先乘除,后加减”的运算优先次序,服从左结合规律。
关系运算对象是算术表达式,运算符有大于(>)、小于(<)、大于等于(>=)、小于等于(<=)、等于(==)和不等于(!=)6种。
布尔表达式的运算对象是关系表达式,运算符有非(!)、与(&&)、或(||)。
赋值表达式就是一个表达式通过一个赋值符号(=)赋值给一个变量
算术运算的优先级比关系运算的优先级高,关系运算的优先 比布尔运算的优先级高,赋值运算符最低。
所有的运算除了!和-是单目运算外,都是双目运算。单目运算只需要一个运算对象,如!a,双目运算需要两个运算对象a+b。
(7)语句
Sample语言每个语句以分号结束
(8)函数
函数是将一段代码用一个函数名来代表,以实现重用(函数声明、函数定义、函数调用)
函数首先要声明,然后定义,把该函数名和这段代码对应起来,最后才能在其他地方调用它。
Sample语言中的函数定义遵循C语言的规范,函数是独立定义的,不能嵌套在另一个函数中定义。
(9)程序
Sample语言中程序是最大的概念,main函数,它是程序的入口,规定main函数不带返回类型
main函数后面可以跟若干个函数定义。全局声明的 常量、变量和函数必须放在main函数之前。因此程序的构成形式是: 声明语句 main()复合语句 函数定义
其中的声明语句 就是全局声明的常量、变量和函数等,这些声明之间没有顺序之分,复合语句 是在main函数中需要执行的语句,函数定义 是定义其他函数,可以没有函数定义,也可以有1个或多个函数定义

总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值