1.1 翻译程序、编译程序、解释程序
翻译程序:把某一种语言程序(称之为 源语言程序)等价地转换成另一种语言程序(称之为 目标语言程序) 的程序。
编译程序:把某一种高级语言程序等价的转换称另一种低级语言程序(如汇编语言或及其语言程序) 的程序。编译程序可以分为诊断编译程序(重点放在对程序员写的程序进行挑错和诊断,帮助程序员快速完成对程序正确性的检查)、优化编译程序、交叉编译程序、可变目标编译程序。
解释程序:把源语言写的 源程序 作为输入,但不产生目标程序,而是 边解释边执行 源程序本身。
区分编译程序和解释程序:以将英文文档翻译为中文文档为例,编译就是直接将稿子翻译成中文,而解释就是一边说一边翻译成中文。
翻译程序与解释程序的比较 :翻译程序:以源程序输入顺序处理程序语句 解释程序:按照源程序的逻辑流程进行工作。
根据编译器的编译过程,编译程序可以分为编译器和解释器两种。 编译器是将源代码转换成可执行程序,然后再运行可执行程序; 解释器是在程序界面中输入一条命令后,将直接得到运行结果; 常用的开发工具,如VC、delphi等的是编译器。 Matlab、foxpro等是解释器。数据库的查询端也是解释器。
1.2 计算思维
抽象:从众多的事物中抽取出共同的、本性的特征,舍弃其非本质的特征。
自动化:编译原理中的自动化如有限自动机、预测分析程序等
分解:将大规模的复杂问题分解成若干个较小规模的、更简单的问题加以解决。
递归:问题的解决又依赖类似问题的解决,只不过后者的复杂程度较原来的问题更小。
权衡(折中):理论可实现与实际可实现。
1.3 编译过程
编译程序的工作一般可以分为五个阶段:
- 词法分析:从左至右读源程序(字符流),识别出句子中的一个个单词符号(又称记号token) ;源程序字符序列 → 单词符号序列 。
- 语法分析:依据源程序的语法规则进行层次分析;单词符号序列 → 分析树(Parse Tree)(或语法树-Syntax Tree) ;语法分析又称解析(Parsing)
- 语义分析和中间代码产生:语义分析的功能是进行语义检查,即验证语法结构合法的程序是否在语义上正确(程序的各个组成部分组合在一起是否有意义), 需收集代码生成阶段需要的语义信息 ;类型检查与类型转换 ;分析树 → 带语义(注释)的树。
中间代码生成的功能是生成源程序的中间表示。 三地址代码(three address-code); 带语义(注释)的树 → 中间代码 。
position = initial + rate * 60的中间代码:
(1) ( inttoreal, 60 - t1 )
(2) ( * , id3 t1 t2 )
(3) ( + , id2 t2 t3 )
(4) ( = , t3 - id1 )
- 优化:对中间代码进行优化,以提高目标程序的时间与空间效率; 在此要特别说明的是,这里的代码优化与目标机器无关。
(1) (inttoreal, 60 - t1 )
(2) ( * , id3 t1 t2 )
(3) ( + , id2 t2 t3 )
(4) ( = , t3 - id1 )
代码优化后:
(1) ( * ,id3 60.0 t1)
( 2)( + ,id2 t1 id1)
- 目标代码生成:机器代码(machine code)、可重定位的机器代码(relocatable machine code )、汇编语言代码(assembly code)
(1) ( * ,id3 60.0 t1)
( 2)( + ,id2 t1 id1)
生成:
movf id3 , R2
mulf #60.0 , R2
movf id2 , R1
addf R2 , R1
movf R1 , id1
此外,还有两个贯穿整个编译过程的工作: 符号表管理、 错误处理
符号表管理的功能:管理分析过程中得到的源程序中的标识符的各种信息 :记录源程序中使用的标识符(identifier) 收集每个标识符的各种属性(attribute)信息,包括类型(type)、作用域(scope)、存储分配(storage allocated)信息 。
出错处理的功能: 检查错误的位置 :检查错误的性质(词法、语法、语义…)与 错误恢复
1.4 编译器的分析综合模式
前端主要由与源语言有关而与目标机器无关的那些部分组成:1. 词法分析、语法分析、符号表的建立、语义分析和中间代码生成 2.与机器无关的代码优化工作 3.相应的错误处理工作和符号表操作
后端由编译程序中与目标机器有关的部分组成 :1.与机器有关的代码优化、目标代码的生成 2.相应的错误处理和符号表操作
把编译程序划分成前端和后端的优点: 便于移植、便于编译程序的构造。
1.5 语言之间的翻译
1.6 编译器扫描的遍数
一“遍”是指对源程序或其中间形式从头到尾扫描一遍,并作相关的加工处理,生成新的中间形式或目标程序。 编译程序的结构受“遍”的影响 。分为:一遍扫描的编译程序和 多遍编译程序。
1.7 编译程序的前后处理器
1.7.1 预处理器
1.7.1.1预处理器——宏
预处理器的功能 :宏处理 、文件包含、 语言扩充
预处理器允许用户在源程序中定义宏。
C语言源程序中的一个宏定义: #define prompt(s) fprintf(stderr, s)
宏处理器处理两类语句,即宏定义和宏调用。
宏定义通常用统一的字符或关键字表示,如define或macro,宏定义由宏名字及宏体组成,通常宏处理器允许在宏定义中使用形参。
宏调用由调用宏的命令名(宏名)和所提供的实参组成。宏处理器用实参代替宏体中的形参,再用变换后的宏体替换宏调用本身。
1.7.1.2 预处理器——文件包含
预处理器把文件的包含声明扩展为程序正文。 例:C语言程序中的“头文件”包含声明行: #include <stdio.h> ,预处理器处理到该语句时,就用文件stdio.h的内容替换此语句。
1.7.1.3 预处理器——语言扩充
有些预处理器用更先进的控制流和数据结构来增强原来的语言。 例如: 预处理器可以将类似于while或if-then-else语句结构的内部宏提供给用户使用,而这些结构在原来的程序设计语言中是没有的。 当程序中使用了这样的结构时,由预处理器通过宏调用实现语言功能的扩充。
1.7.2 汇编程序
1.7.3连接装配程序
下篇:【编译原理】02词法分析