(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 stub ArrayList<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(); } }
(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");//压入1 al.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");//压入1 al.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");//压入1 al.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");//压入1 al.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");//压入1 al.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");//压入1 al.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");//压入1 al.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");//压入1 al.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");//压入1 al.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");//压入1 al.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");//压入1 al.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");//压入1 al.add(code); code=new Code(0x17);//和0比较 al.add(code); } } }比较运算符的genCode虽然代码比较长但是逻辑很简单。
首先需要根据待比较的expr来决定是否进行类型转换,目前在语言的设计中,只有double和int是可比的,其它类型的比较虽然在编译器不会报错但在运行时中会进行报错。
其次根据类型来调用不同的比较指令,再次根据逻辑需要进行二次比较(因为比较指令会根据大于小于等于返回1、0或-1,和运算符并不等价,需要通过比较两次使之和运算符等价)。
大体上代码就这么多,目前的编译器已经可以编译出正确的字节码了,但目前代码还无法执行,需要等到Runtime写好之后才能运行。
因此本系列博客到这里暂时告一段落,若给语言再添加一些高级点的特性,也需要等到我把Runtime写好再说了。