自制编译器:后端代码生成(三)

来源:互联网 发布:正规的淘宝代运营 编辑:程序博客网 时间:2024/05/17 08:18

(14)expr

/*                         Type
* expr -->  (expr)           0
                ids|             1
              number|           2
              literal|           3
             func-call|         4
            expr  ops expr|      5
*/

public void genCode() {ArrayList<Code> al=BackendClassManager.tFunc.codes;if(Type==0){expr1.genCode();}else if(Type==1){ids.genCode();}else if(Type==2){Code code;if(number.isInt==true){code=new Code(0x01);code.Operands.add(number.toString());}else{code=new Code(0x02);code.Operands.add(number.toString());}al.add(code);}else if(Type==3){literal.genCode();}else if(Type==4){fc.genCode();}else if(Type==5){expr1.genCode();Code code=new Code(0x05);int pos=BackendClassManager.nameSlot.keySet().size();BackendClassManager.nameSlot.put(this.toString(), pos);code.Operands.add(String.valueOf(pos));al.add(code);expr2.genCode();code=new Code(0x03);code.Operands.add(String.valueOf(pos));al.add(code);BackendClassManager.expr1=expr1;BackendClassManager.expr2=expr2;op.genCode();}}

expr的genCode方法产生的效果是把此expr的值放到栈顶。

如果type=0,则递归调用括号里的expr的genCode;如果type=1,则把ids的值放到栈顶;如果type=2,先判断立即数的类型之后再压入立即数;如果type=3,把字符串的句柄压入栈顶;type=4调用funccall的genCode;type=5,先生成expr1的字节码,然后将结果暂存到局部变量表,之后生成expr2的字节码,再把之前的结果压栈,调用op的genCode代码为运算符生成字节码。

值得注意的是,调用op的genCode之前首先要把参与运算的expr放到全局变量里,op的字节码生成过程需要使用这两个expr的信息。


(15)funccall

func-call --> ids . func-name(NUL|args)

public void genCode() {// TODO Auto-generated method stubArrayList<Code> al=BackendClassManager.tFunc.codes;memberfuncdeclare mfc=(memberfuncdeclare)SyntaxTreeGenerator.getFunctions().get(fn.toString()).value;ArrayList<ids> ags=ag.getidsList();ArrayList<Integer> poses=new ArrayList<Integer>();for(int i=0;i<=ags.size()-1;i++){ags.get(i).genCode();poses.add(CodeGenHelper.StoreToLocalTable(al));}for(int i=0;i<=poses.size()-1;i++){CodeGenHelper.LoadToStack(al, poses.get(i));}if(mfc.isstatic==true){Code code=new Code(0x1B);code.Operands.add(IDS.toString()+"."+fn.toString());al.add(code);}else{IDS.genCode();Code code=new Code(0x1A);code.Operands.add(fn.toString());al.add(code);}}
函数调用的过程如下:

首先所有参数压栈,然后虚拟机执行call指令,给新函数分配执行环境(栈帧),把之前压栈的参数放到局部变量表中(如果有this参数的话this也要以参数的形式放到局部变量表中);函数执行完之后虚拟机释放资源,并把堆栈顶元素(返回值)放到其调用者的堆栈顶。

首先先从符号表中找到这个函数(封装在了SyntaxTreeGenerator中),然后得到所有参数,并存储到局部变量表中(之所以这么做因为参数的获取过程可能会把堆栈顺序打乱),接着把之前存过的所有参数压入堆栈,再判断该函数是否是个静态函数来使用不同的字节码进行调用。


(16)ops

ops --> bitop | logiop | artmop | cprop

public void genCode() {if(type==TYPE_BITOP){bo.genCode();}else if(type==TYPE_LOGIOP){lo.genCode();}else if(type==TYPE_ARMTOP){ao.genCode();}else if(type==TYPE_CPROP){co.genCode();}}

根据不同的类型调用不同op的genCode方法。


(17)cprop

public void genCode() {expr expr1,expr2;ArrayList<Code> al=BackendClassManager.tFunc.codes;expr1=BackendClassManager.expr1;expr2=BackendClassManager.expr2;boolean intint=true;if(expr1.tp.toString().equals("int") && expr2.tp.toString().equals("int")){intint=true;}if(expr1.tp.toString().equals("double") && expr2.tp.toString().equals("double")){intint=false;}if(expr1.tp.toString().equals("int") && expr2.tp.toString().equals("double")){CodeGenHelper.i2d(al);intint=false;}if(expr1.tp.toString().equals("double") && expr2.tp.toString().equals("int")){int pos=CodeGenHelper.StoreToLocalTable(al);Code code=new Code(0x23);al.add(code);CodeGenHelper.i2d(al);CodeGenHelper.LoadToStack(al, pos);intint=false;}if(value.equals(">")){if(intint==true){Code code=new Code(0x16);//比较al.add(code);code=new Code(0x01);code.Operands.add("1");//压入1al.add(code);code=new Code(0x16);//和1比较al.add(code);code=new Code(0x24);//取非al.add(code);}else{Code code=new Code(0x17);//比较al.add(code);code=new Code(0x02);code.Operands.add("1");//压入1al.add(code);code=new Code(0x17);//和1比较al.add(code);code=new Code(0x24);//取非al.add(code);}}if(value.equals("<")){if(intint==true){Code code=new Code(0x16);//比较al.add(code);code=new Code(0x01);code.Operands.add("-1");//压入1al.add(code);code=new Code(0x16);//和1比较al.add(code);code=new Code(0x24);//取非al.add(code);}else{Code code=new Code(0x17);//比较al.add(code);code=new Code(0x02);code.Operands.add("-1");//压入1al.add(code);code=new Code(0x17);//和1比较al.add(code);code=new Code(0x24);//取非al.add(code);}}if(value.equals(">=")){if(intint==true){Code code=new Code(0x16);//比较al.add(code);code=new Code(0x01);code.Operands.add("-1");//压入1al.add(code);code=new Code(0x16);//和1比较al.add(code);}else{Code code=new Code(0x17);//比较al.add(code);code=new Code(0x02);code.Operands.add("-1");//压入1al.add(code);code=new Code(0x17);//和1比较al.add(code);code=new Code(0x24);//取非al.add(code);}}if(value.equals("<=")){if(intint==true){Code code=new Code(0x16);//比较al.add(code);code=new Code(0x01);code.Operands.add("1");//压入1al.add(code);code=new Code(0x16);//和1比较al.add(code);}else{Code code=new Code(0x17);//比较al.add(code);code=new Code(0x02);code.Operands.add("1");//压入1al.add(code);code=new Code(0x17);//和1比较al.add(code);}}if(value.equals("==")){if(intint==true){Code code=new Code(0x16);//比较al.add(code);code=new Code(0x01);code.Operands.add("0");//压入1al.add(code);code=new Code(0x16);//和0比较al.add(code);code=new Code(0x24);//取非al.add(code);}else{Code code=new Code(0x17);//比较al.add(code);code=new Code(0x02);code.Operands.add("0");//压入1al.add(code);code=new Code(0x17);//和0比较al.add(code);code=new Code(0x24);//取非al.add(code);}}if(value.equals("!=")){if(intint==true){Code code=new Code(0x16);//比较al.add(code);code=new Code(0x01);code.Operands.add("0");//压入1al.add(code);code=new Code(0x16);//和0比较al.add(code);}else{Code code=new Code(0x17);//比较al.add(code);code=new Code(0x02);code.Operands.add("0");//压入1al.add(code);code=new Code(0x17);//和0比较al.add(code);}}}
比较运算符的genCode虽然代码比较长但是逻辑很简单。

首先需要根据待比较的expr来决定是否进行类型转换,目前在语言的设计中,只有double和int是可比的,其它类型的比较虽然在编译器不会报错但在运行时中会进行报错。

其次根据类型来调用不同的比较指令,再次根据逻辑需要进行二次比较(因为比较指令会根据大于小于等于返回1、0或-1,和运算符并不等价,需要通过比较两次使之和运算符等价)。


大体上代码就这么多,目前的编译器已经可以编译出正确的字节码了,但目前代码还无法执行,需要等到Runtime写好之后才能运行。


因此本系列博客到这里暂时告一段落,若给语言再添加一些高级点的特性,也需要等到我把Runtime写好再说了。



原创粉丝点击