1、词法分析,将原文件划分为单独的单词或关键字。
2、语法分析,利用上下文无关文法分析程序的短语结构。
3、语义分析,根据短语建立抽象语法树,确定短语含义、变量关联声明、检查表达式类型。
4、翻译,根据抽象语法树翻译成中间表示树不依赖任何特定的程序语言和目标机器结构。
5、指令选择,根据目标机器的指令体系,对中间表示树的节点进行划分。
6、控制流分析。
7、数据流分析。
8、寄存器分配。
9、代码生成。
在上编译原理课程的时候,我们完成了一个基于miniJava的编译器和垃圾回收器
代码:https://github.com/xuhaoavl/tiger
1、词法记号,编程语言语法单元的一系列字符,词法记号一般分为有限的几种。
例如:ID(字符串)、NUM(整数)、REAL(实数)、IF(if)、VOID(void)、COMMA(逗号)。。。。
2、正则表达式,一般用正则表达式匹配字符窜的方式检查字符串类型。
符号(a,v,h,b等),或(a|b)、并(a·b)、空(ε)、重复(克林闭包,所有可能的字符串)
有一些可能会产生模糊性,例如if8是字符串还是if和8,对此有以下两种解决方法
a、最长匹配,选择可以匹配正则表达式的最长输入字符串。
b、优先匹配,选择最先与之匹配的正则表达式,这时候正则表达式的顺序很重要。
3、有限自动机DFA,不存在两个从统一状态出发且标记完全相同的边,不存在空串。
一般使用DFA来实现词法分析。
4、非确定有限自动机NFA,可能存在多条从一个状态出发且标记一样的边,也可能有空边。
一般使用正则表达式表示一个语言的词法,然后将其转换为NFA(正则表达式转NFA比较容易),最后再将NFA转DFA,并用代码实现。
1、上下文无关文法
使用上下文无关文法描述词法结构。
推导形式有最左推导和最右推导,可以使用一颗分析树表示推导的过程,每一步推导都对分析树中的某一个节点进行一步拓展。
二义性文法是指能够产生两颗不同的分析树。,可以通过改写文法消除二义性。
2、预测分析的过程
递归下降,每个递归下降分析器对应一个非终结符号的推导。
但是在推导的过程中有可能会产生冲突,即在某一步有多个候选式。
这时候可以通过计算当前非终结符的first集和follow集来解决冲突。
LL(k):从左到右分析,最左推导,k个lookahead符号。
LR(k):从左到右分析,最右推导,k个lookahead符号。
消除左递归,根据first集和follow集,左递归会导致多重定义入口。
消除左因子,用一个新的非终结符替代。
1、在一个递归下降分析器中,语义动作是分析函数返回的值。
2、抽象语法树,其实也就是前面所说的分析树
在Java中其实也就是一颗对象树,main函数所在的类也就是树根,树上有表达式对象,语句对象等。
如图所示,在语法分析的过程中,已经构建出了一颗抽象语法树。
3、抽象语法树的遍历
从根步遍历语法分析树的时候并不知道每个子节点的类型,可以通过instanceof解决,但是更好的一个解决方法是使用访问者模式。
意图:主要将数据结构与数据操作分离。
主要解决:稳定的数据结构和易变的操作耦合问题。
把变量的定义与使用联系到一起,检查表达式的类型。通过符号表进行。
1、符号表,将标识符与其类型和位置进行映射。实际中可能含有很多个符号表,每一个类、每一个方法都有一个符号表,第一次遇到该变量的时候会将其加入到符号表中,作用域结束后将其删除。
符号表主要用于检查变量的使用和定义、检查表达式类型。