写在前头:
这是小鱼上的网课整理来的笔记,希望可以帮助大家更好的理解编译原理这门课!
一、计算机程序设计语言(编程语言)
计算机程序设计语言是一组用来定义计算机程序的语法规则。
现如今,计算机程序设计语言被划分为三大类:
1️⃣机器语言
机器语言是机器能直接识别的程序语言或指令代码,勿需经过翻译,每一操作码在计算机内部都有相应的电路来完成它,或指不经翻译即可为机器直接理解和接受的程序语言或指令代码。机器语言使用绝对地址和绝对操作码。不同的计算机都有各自的机器语言,即指令系统。从使用的角度看,机器语言是最低级的语言。
简单来说,机器语言是能被计算机直接理解的语言,一般是以二进制或者十六进制构成的序列。
例如:C706 0000 0002
就是一道机器语言
前四位表示操作码,表示C706
所要执行的是移入操作
后面八位表示操作数,0000
表示位置,0002
表示数值,表示将0002
这个值存放在(移入)0000
的位置
机器语言所存在的缺点:
1.大量繁杂琐碎的细节牵制着程序员,使他们不可能有更多的时间和精力去从事创造性的劳动,执行对他们来说更为重要的任务。如确保程序的正确性、高效性。
2.程序员既要驾驭程序设计的全局又要深入每一个局部直到实现的细节,即使智力超群的程序员也常常会顾此失彼,屡出差错,因而所编出的程序可靠性差,且开发周期长。
3.由于用机器语言进行程序设计的思维和表达方式与人们的习惯大相径庭,只有经过较长时间职业训练的程序员才能胜任,使得程序设计曲高和寡。
4.因为它的书面形式全是密码,所以可读性差,不便于交流与合作。
5.因为它严重地依赖于具体的计算机,所以可移植性差,重用性差。 这些弊端造成当时的计算机应用未能迅速得到推广。
早期的程序设计均使用机器语言,但是这种语言的不便性阻碍了计算机行业的发展。此时,另一个语言孕育而生。
2️⃣汇编语言
汇编语言(assemblylanguage)是一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。在汇编语言中,用助记符代替机器指令的操作码,用地址符号或标号代替指令或操作数的地址。在不同的设备中,汇编语言对应着不同的机器语言指令集,通过汇编过程转换成机器指令。特定的汇编语言和特定的机器语言指令集是一一对应的,不同平台之间不可直接移植。
简单来说,就是用一些容易理解和记忆的字母,单词来代替一个特定的指令。
例如:MOV X,2
MOV
表示操作码,表示所要执行的是移入操作
假设X的位置为0000,那么这里操作表示将2移入X(0000)中
汇编语言所存在的缺点:
1、因为代码非常单调,特殊指令字符很少,所以造成了代码的冗长以及编写的困难
2、因为汇编仍然需要自己去调用存储器存储数据,很容易出现BUG,而且调试起来也不容易
3、就算完成了一个程序,后期维护时候也需要耗费大量的时间。
4、因为机器的特殊性造成了代码兼容性差的缺陷。
简单来说就是需要程序员熟悉目标机的特性(限制了非计算机人员使用),处理能力的效率低下。这时,人们发现需要一门更加简单且高效的语言。
3️⃣高级语言
高级语言(High-level programming language)是一种独立于机器,面向过程或对象的语言。
我们熟悉的BASIC、JAVA、C、C++、python等等,都是高级语言。
例子:x=2;
(简单明了)
三语言之间关系:
二、编译器在语言处理系统中的位置
预处理器:
把存储在不同文件中的源程序聚合在一起,把被称为宏的缩写语句转换为原始语句
可重定位:
机器代码在内存中存放的起始位置L不是固定的
起始位置➕相对地址=绝对地址
编译器:
编译的过程就是将源程序翻译成目标程序:源程序—编译器—目标程序,编译器还有报告源程序错误的作用。
链接器:
将多个可重定位的机器 代码文件(包括库文件) 连接到一起
解决外部内存地址问题
加载器:
修改可重定位的地址,将修改后的指令和数据放在内存适当的位置
我们知道一个英语句子,他是由各种成分组成,我们将源语言翻译成目标语言的过程,相当于将英语翻译成汉语
看看这个句子:
In the room,he broke a window with a hammer
在房间里,他用锤子砸了一扇窗户。
假设这句话就是一个源语言,我们第一步要做的就是要分析源语言
而在执行这三步中,我们还需要理解中间表示,例如这句英语中的中间表达可以这样描述:
类似于将各个成分分析翻译出来
分析源语言分为三步:
1、词法分析
英语中词法分为名词,代词,冠词,数词,动词,形容词,副词,介词,连词和感叹词
这句话我们可以这样看:
2、语法分析
同样是这句话,按照语法分析,我们可以:
而根据以上内容,我们可以绘制出一棵语法分析树
3、语义分析
将各个成分依据语法组合成一句完整却正确的句子
分析完这英语句子我们来看看编译器具体的结构:
前面红色框框为分析部分/ 前端(front end)
后面红色框框为综合部分/ 后端(back end)
而中间那部分独立于具体语言,起桥梁作用
1️⃣词法分析
编译的第一阶段,词法分析的主要任务 :
从左向右逐行扫描源程序的字符,识别出各个单词,确定单词的类型。 将识别出的单词转换成统一的机内表示——词法单元(token)形式
token是一个二元组,由种别码,属性值构成
token:<种别码,属性值>
种别码:单词表示种别
我们来看看种别码的具体分法:
这样说有些枯燥,我们来举例子说明下:
2️⃣语法分析
语法分析器(parser)从词法分析器输出的token序列中 识别出各类短语,并构造语法分析树(parsetree)
语法分析树描述了具体结构
我们依旧那个例子来说明:
根据上表我们可知:
一个标识符和一个常数可以构成一个表达式
一个表达式+一个表达式可以构成更大的表达式
一个标识符连接上一个赋值符连接上一个表达式和一个分号可以构成赋值语句
如果我们要构建一个变量声明语句的分析树,我们来看看这个例子
3️⃣语义分析
①收集标识符的属性信息
种属(Kind)
简单变量、复合变量(数组、记录、…)、过程、…
类型(Type)
整型、实型、字符型、布尔型、指针型、…
存储位置、长度
例:
begin real x[8];
integer i, j;
…… end
值
作用域
参数和返回值信息
参数个数、参数类型、参数传递方式、返回值类型、…
语义检查
变量或过程未经声明就使用
变量或过程名重复声明
运算分量类型不匹配
操作符与操作数之间的类型不匹配
数组下标不是整数
对非数组变量使用数组访问操作符
对非过程名使用过程调用操作符
过程调用的参数类型或数目不匹配
函数返回类型有误
4️⃣常用的中间表示形式
有印象的同学应该记得这副图:
在这里,我们常用这几种表达形式:
1️⃣三地址码(Three-address Code)
2️⃣语法结构树/语法树(Syntax Trees)
首先我们来说说三地址码吧
三地址码由类似于汇编语言的指令序列组成, 每个指令最多有三个操作数(operand)
红色表示指令操作符
第一个式子中op表示成二元运算符,y,z运算分量的地址,x运算结果的存放地址
第二个式子中op表示成一元运算符
第三个式子(序号为3)中如果x,y满足关系relop就跳转
第四个式子中表示无条件跳转
第六个式子中p过程名字,n过程参数个数
第七个式子中表示跳转到地址X
第八个式子中y对应数组名字,表示数组的基地址,i是数组元素的偏移地址
三地址指令有三种表达形式:(将三地址指令表示成数据结构:)
四元式(Quadruples)
三元式(Triples)
间接三元式(Indirect triples)
其中三地址指令的四元式的表达:
第一位对应指令作符
第二、三位对应指令中源操作数
第四位对应目标操作数
第二个式子为一元运算语句,只有一个源操作数y
第九个式子=【】表示等号右边是个数组元素,二三位表示数组的基地址和偏移地址,第四位表示左边的变量
第十个式子【】=表示等号左边是数组元素,第二位对应等号右边变量,第三四位基地址+偏移地址
接下来我们看看中间代码生成的例子:
这一部分比较繁琐,但理解应该不难,要多加练习
我们看看右边的小图:
冒号前面的数字:指令的编号
第一个式子条件跳转指令
j是jump的缩写,表示a<b就跳转到102号,否则继续执行102号指令
第二个式子(101)是无条件跳转指令,到112
最后我们看看目标代码生成器和机器相关代码优化器
和
1️⃣目标代码生成器
目标代码生成以源程序的中间表示形式作为输入,并把它映射到目标语言
目标代码生成的一个重要任务是为程序中使用的变量合理分配寄存器
2️⃣机器相关代码优化器
为改进代码所进行的等价 程序变换,使其运行得更 快一些、占用空间更少一 些,或者二者兼顾
今天的学习笔记就分享到这里!!
PS:小鱼学习网站是中国大学MOOC(慕课),学习的课程是编译原理(哈尔滨大学),里面有老师精心准备的视频和PDF文档,小鱼的截图和例子皆出自里面!