2019独角兽企业重金招聘Python工程师标准>>>
编译原理学习笔记(一)
1.编译器与解释器的区别与优劣
- 编译器:将完整的用户代码经过一系列处理翻译成完整的目标语言。
- 解释器:直接利用用户提供的输入执行源程序中的操作。因此可以逐个语句的执行源程序。
编译器产生的机器语言目标程序通常比解释器快很多,代码的优化效果也比解释器好。但是利用解释器逐句执行的特点,解释器更容易进行错误诊断,与用户的交互效果也比编译器好。
2.一个编译器的结构
一个编译器可以分为前端和后端,前端包括词法分析,语法分析,语义分析,中间代码生成。后端包括中间代码优化,代码生成,机器相关代码优化等。
2.1词法分析
输入:源程序字符流
输出:词法单元和符号表信息
词法分析读入组成源程序的字符流,并将它们组织成有意义的词素序列。对于每个词素,词法分析其产生词法单元作为输出。
2.2语法分析
输入:词法单元和符号表
输出:语法树
语法分析器利用token来产生语法树。之后会讲到利用上下文无关文法来设计语言,并且检测某次输入是否符合语法规范。
2.3语义分析
输入:语法树和符号表
输出:经过类型检查和自动类型转换的语法树
语义分析器:使用语法树和符号表中的信息来检查源程序是否和语言定义的语义一致。
2.4中间代码生成
输入:具与正确语义的语法树和符号表
输出:三地址代码
三地址代码满足几点规范:右部最多只有一个运算符,运算分量小于或等于三个。
2.5代码优化
与机器无关代码优化:优化中间代码
与机器有关代码优化:优化机器码
2.6代码生成
输入:经过优化的三地址代码
输出:机器码(目标语言)
3.编译技术的应用
- 高级程序设计语言的实现:编译器最基础的用法,将高级程序设计语言编译成机器码
-
针对地算计体系结构的优化:
并行性:指令集并行和多处理器并行,前者通过流水线等技术将多条指令同时执行以加快程序的执行速度,后者通过在多处理器机器中分发计算任务加快程序的执行速度 内存层次结构:现代计算系统都是由几层不同速度和大小的存储器构成的,利用编译器可以改变数据的布局或数据访问代码顺序来提高内存层次结构的效率。
综上就是通过编译技术加快程序的执行速度。
-
程序翻译
二进制翻译:不同平台间机器代码的转换 硬件合成:实现高级硬件描述语言 数据查询解释器:将sql等数据库查询语言编译为可执行代码 编译然后模拟:....?
-
软件生产率工具:利用编译技术制作类型检查,边界检查,内存管理工具等。
4.程序设计语言基础
4.1环境与状态
环境其实就是名字到存储位置的映射,一个相同的名字,在不同的环境下的指向不同的存储区域。
状态就是位置到值的映射,在程序运行过程中,一个位置不可能总是相同的值,有可能因为数据的删除和更新导致相同位置的值发生改变。
4.2静态作用域和块结构
静态作用域:一种在词法分析阶段就可以判断出来的作用域类型,一个声明的作用域由该声明在程序中出现的位置来确定,静态作用域与块结构密切相关。每个块结构都有自己的作用域,块结构的相互嵌套构成了一个程序的静态作用域。
4.2.1名字,标识符和变量
名字:代表一个内存位置的符号
变量:名字在运行时刻所指的内存位置。
标识符:指向一个实体,比如数据对象,过程,类,所有标识符都是名字,但是不是所有名字都是标识符,比如x.y就是名字不是标识符,因为它是复合的,标识符知识但单一的整个实体。
4.2.2过程,函数和方法
函数:是指可以有返回值的一段在一起的、可以做某一件事儿的程序
过程:没有返回值的函数
方法:仅限于面向对象的程序设计语言,存在于对象中的函数属性。
4.2.3声明和定义
声明:说明事物的类型,比如int a
定义:给事物赋值,比如a=1
4.3动态作用域
动态作用域通常指一下策略:对一个名字x的使用指向的是最近被调用(从函数栈顶端往下的的第一个)但还没有终止声明了x的过程中的这个声明。 例子:
var a = 2
function foo(){
console.log(a);
}
function bar(){
var a=3
foo();
}
bar();
//静态输出2
//动态输出3
4.4参数传递机制
- 按值传递:比如变量a按值传递给变量b,则a将a的内存地址的储存的值传给了b,b有自己的内存地址
- 按引用传递:变量a按引用传递给变量b,则a和b指向同一块内存地址,显然a和b的值相同
- 名调用:......
4.5别名
别名指两个变量代表同一个数据对象、过程或者类。可以是变量a与b指向同一块地址,可以是变量a与b指向不同的地址,但是这个地址都保存同一个的对象的引用。