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

(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();
		}
		
	}

根据不同的类型调用不同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");//压入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写好再说了。



  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值