后端早就已经弄的差不多了,因为学校论文的事情耽搁的比较久,一直到现在才发博客。
所谓的编译器后端的作用就是将语法树翻译成目标机器码。所谓目标机器码,考虑到直接翻译成具体平台(如X86,ARM等)过于复杂,因此先设计一个虚拟机,并翻译成这个虚拟机的机器码。
对于虚拟机以及其指令格式可参考这篇文章http://blog.youkuaiyun.com/roger__wong/article/details/8947720,如何去尝试实现这个虚拟机是在我的另外一个系列的博客里进行论述。
本篇文章从以下是那个方面来论述:后端架构与关键数据结构、节点翻译方式。
1、后端架构和关键数据结构
后端接受前端的语法树作为输入,对于其每一个节点根据节点类型的不同产生不同的代码。但在实现过程中为了简单方便,我并没有把后端抽象出一个单独的模块,而是在语法树每一个节点的基础上增加了一个genCode方法,通过调用这个方法来生成该节点及其所有孩子节点(通过递归)的代码。
其次编译器后端直接生成Class文件(文件结构也在上文提到的博客中有说明),程序中后端首先构造一个ClassOfClass的实体,然后再调用此类的方法生成Class文件:
public class ClassOfClass {
public static int isPublic=1;
public static int isStatic=2;
public ArrayList<field> fields;
public ArrayList<function> functions;
public ArrayList<String> constPool;
public String name;
public ClassOfClass()
{
constPool=new ArrayList<String>();
fields=new ArrayList<field>();
functions=new ArrayList<function>();
}
public void WriteClassFile(String path)
{
try {
PrintWriter pw=new PrintWriter(new FileOutputStream(path));
pw.println(name);
pw.println(fields.size());
for(field f:fields)
{
pw.println(f.toString());
}
pw.println(functions.size());
for(function f:functions)
{
pw.println(f.toString());
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
其中field结构:
public class field {
public int head;