编译器就是将“一种语言(通常为高级语言)”翻译为“另一种语言(通常为低级语言)”的程序。在这里,谢谢华保健老师的《编译原理》公开课视频,也谢谢其他老师的免费视频,让我有了编译知识的入门。
一、编译器的概况。
编译器一般分前端与后端两部分,前端部分一般为对源代码的处理与理解,后端部分一般为不断地优化最终输出指定的语言。其中又分为下面的四大块:词法分析、语法分析、语义分析、代码生成。各个过程均要对源代码的错误与不当作反应,并准确输出错误信息与警告信息,也就要求将行列信息传递到最后。
![689d798014cc9037beb6439e7454e60b.png](https://i-blog.csdnimg.cn/blog_migrate/17ec20b96fbd775ba74bc7642886a072.png)
二、词法分析。
将源代码中的字符序列转换为标记(token)序列的过程,输入源代码输出记号流。词法分析器一般以函数的形式存在,供语法分析器调用。
- 源代码对于编译器来说一连串的字符串;
- 编译器遂个读取源代码中的字符;
- 通过正规式(初步了解为一种低级的正则式),使用NFA(不确定有限状态自动机),转为DFA(确定有限状态自动机),再最小化DFA,从而生成记号表,即形成记号流;
- 正规式是一种以或、连接、闭包、正闭包方式来定义字符的方式;
- NFA对于正规式有对应用的方式来处理;
- NFA转DFA可以使用子集构造法来处理;
- DFA可以通过分割法实现最小化;
- 记号流的表现形式是类型与值对应表达;
// 源代码
三、语法分析。
语法分析器从词法分析器获取一个记号流,并验证这个记号流是否可以由源语言的文法生成。
- 为了与语意分析分开,一般来语法分析时表现为上下文无关文法,语意分析时表现为上下文有关文法;
- 接收记号流生成语法树;
- 在上下文无关文法中,使用非终结符与终结符表达推导规则,以制定程序文法;
- 其于推导规则,于是存在两种分析方法,一种为自顶向下分析法、一种为自底向上分析法;
- 自顶向下分析法中,一般常用递归下降分析法与LL(1)分析法;
- 自底向上分析法中,一般常LR(1)分析法;
- LL(1)、LR(1)分别是对LL(0)、LR(0)的一种改进;
- LL(1)较LL(0)消除了回溯;
- 其中LL(1)、LR(1)中的1为前看符号,表示再多看一个字符;
- 二义性的清除还需要从文法设计上避免,比如说消除左递归等。
四、语义分析。
语义分析将变量与其用法关联起来,检查每个表达式是否有正确的类型等。语意分析使用上下文有关文法。由于需要检查变量所以需要使用符号表。
- 接收语法树生成抽象语法树;
- 使用符号表,符号表将标识符和其类型、位置关联起来,当我们去处理变量,函数的声明时,就是将这些信息组织(绑定)起来,放在表里,当需要知道这些函数,变量的意义时,就去这个表里查;
- 可使用哈希表、红黑树来构建符号表,使用类型检查算法,获取符最近的值;
- 哈希表与红黑树,前者占空间,后者耗时间;
- 也可以输出中间代码或目标代码。
五、代码多级优化。
出于对代码编译后的效能考虑,一般会在语义分析后,去生成平台无关的中间代码,经过对中间代码的进行多级优化,生成最终运行机器平台上的目标代码。也可以对目标代码再进行多级优化,以生成高质量的目标代码。这里涉及到了三地址代码等中间形式。
- 常量传播,将编译期间可计算出结果的变量转换成常量,减少了变量的使用。
- 常量折叠,当计算公式中出现多个变量进行计算的情况时,且编译器可以在编译期间计算出结果时,用结果代替所有的常量计算。
- 删除冗余的存、取操作,如对相互赋值的变量;
- 删除不可达代码,如流程流不到的代码。
六、假定的K语言的规则说明,供编译原理学习用。
这里提供一个小程序及代码规则,在后面的编译原理学习中将连续使用,以便我们理解。你需要多看看,后面常用到。
- 原则。
- 变量名规则为字母数字下划线组成,数字不能放在第一位;
- 数据类型有:bool, int, string, array, map, function;
- 运算符有: +, -, /, *, %, >, >=, <, <=, !=, ==, &&, ||, !, &, ^, |, <<, >>,=;
- 控制语句如C语言相同;
- 结束符是分号。
- 示例代码。
// 这部分为代码。
下一章,学C语言写自己的K语言:编译器词法分析。
让我们在这里,遇见明天的自己!姜友华