您的位置:首页 > 编程语言

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

2013-06-16 13:39 253 查看
(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)cproppublic 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写好再说了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐