学习了一个学期的编译原理,每次上课都认真听讲,今天复习了一个上午,下面把我的心得写出来。
其实这一个上午,我只看了引论与PL/0编译程序的实现,才发现其实在上机实验的时候自己有的时候的想法未免有点肤浅了。
1.编译程序与解释程序的区别:
编译程序的任务是把高级语言源程序翻译成为目标汇编程序,它是把编译和运行分开进行的,编译过程中需要对源程序、目标代码以及相应的符号表开辟空间,运行阶段需要存储目标代码以及数据,优点:对源程序进行编译,可以对代码进行相应的报错处理或代码优化,节省运行时间。
解释程序不需要先把源程序翻译成为目标代码,也可以让我们实现在某台机器上面运行程序并生成结果,也就是它接受某个源程序并立即运行它。它的工作模式是分析并执行源程序语句,比较适合程序员交互方式的工作情况,希望在获取下一个语句之前了解每个语句的执行结果,并且允许执行的时候修改程序。但是缺点:源程序与相应的符号表存放于代码区,开销大,运行慢。
2.前端、后端
前端:和源程序密切相关的阶段,与目标机无关(词法分析、语法分析、语义分析、中间代码生成、代码优化、相应的符号表管理、出错处理)。
后端:和目标机密切相关,只与中间代码有关的阶段(目标代码生成、相应出错处理、符号表管理)。
3.遍(趟)
这个”遍“指的是对源程序或者其等价的中间代码语言程序进行从头到尾扫视,并完成规定任务的过程。
遍数的确定:1)源语言:对于有些名字说明在使用之后的至少需要2遍
2)目标机:对于一些内存较小的机器适合多遍,因为编译程序少占的内存。
4.编译程序的各个阶段
词法分析:任务.从左到右一个一个字符的读入源程序,对构成源程序的字符流进行扫描和分解,滤空格,识别出一个一个的单词(逻辑上紧紧密相连的一组字符),以PL/0语言为例,这些单词分为标识符、关键字(保留字)、常数、运算符、界符,并找到相应的关键字、运算符、界符的类别编码存入sym[]数组中,找到标识符、常数的用户自定义的类别编码存入sym[]中及其所对应的值,输出结果。
语法分析:任务.分析PL/0源程序是否符合其语法规范。读入词法分析后的结果,利用递归下降分析子程序法来分析语法的正确性,对于每一个非终结符,我们都为其编写一个子程序,按照其语法描述图的箭头所指的方向,确定调用子程序的调用顺序,其中如果不符合语法规则有相应的详细的报错处理。其他分析方法:LL(1)分析法、算符优先级分析法、SLR(1)分析法、递归下降子程序分析法等。
语义分析:任务.对于语法分析正确的程序,我们就要分析其语义是否符合规范,比如%前后只能是整形变量,/后面不能为0,等等。
中间代码生成:任务.对于语法语义分析正确的源程序,我们要生成一个中间代码比如四元式,对于语法制导分析方法,表达式的四元式的生成顺序和语义值计算的顺序是一样的,先是小括号里面的,再是*或/,最后+或-,同时,四元式里面有t1、t2……这些怎么输出呢?这就要用到一个全局变量k,每次输出一个四元式,我们的k+1,并且把已经翻译过的小的表达式进行处理,把它变成‘t‘’k+47’,变成字符,每次翻译到处理过的表达式的时候,直接输出就可以了,我们可以利用这一点进行写代码。
代码优化:任务.对代码进行等价变换,使得变换后的代码运行结果与变换前的代码运行结果相同,但是运行速度加快或占用的存储空间减小。可以删除多余的运算、代码外提、强度削弱、合并已知量、循环优化、删除无用赋值等。
代码生成:任务.把优化后的中间代码转换为特定的目标机的机器语言或汇编语言。涉及到的问题是代码生成程序的输入、指令选择、寄存器分配。
注:本文纯属自己对编译原理这门课学过之后的整体的总结,后续会有详细的编译程序各个阶段所用到的方法的总结介绍。
参考文献:编译原理(第2版)清华大学出版社。