自己动手写编译器:实现简单if语句的跳转代码生成

本节我们要完成的目的是将下面带有if语句的代码转换为中间代码:

{int x; int y; int z;
		        x = 1;
				y = 2;
				if (y > x) {
					z = 2;
				}
				z = 3;
	}

完成本节代码后,上面代码会被转译成如下中间代码:

L1:
        x = 1
L3:
        y = 2
L4:
        http://m.study.163.com/provider/7600199/index.htm?share=2&shareId=7600199 y > x goto L5
L6:
        z = 2
L5:
        z = 3
L2:

注意看L4, L5, L6三个地方的分支,中间代码有一个指令叫iffalse,后面跟着一个表达式,如果表达式结果能转换为false,那么goto语句就产生作用,跳转到它对应的语句,如果表达式结果为true,那么控制流直接跳转到L4下面的语句。

我们先看看if语句对应的语法规则表达式:

stmt -> if "(" bool ")" stmt
bool -> expr rel expr
rel -> LE | LESS_OPERATOR | GE | GREATER_OPERATOR | NE | EQ

if语句的规则是,在关键字if后面必须跟着左括号,然后对应bool表达式,它实际上是两个算术表达式进行比较操作,也就是两个表达式之间对应这<, <=, >, >=, !=, ==等比较操作符,两个表达式比较完后就会得出true或是false的结果,然后使用iffalse指令在表达式比较结果上对执行流进行操作。

因此我们实现的方法是,在遇到if语句前先给他一个跳转标签,也就是前面例子中的L4,然后if条件成立时对应的语句集合其实是一个stmt,所有语句对应一个标签,也就是L5。由于if语句后面会跟着一个左大括号,里面对应这如果判断条件成立就要执行的代码,于是对应右大括号后面的语句就是if判断条件不成立时要执行的代码,那么这些代码对应的跳转标签就紧接着L5,也就是上面例子中的L6。因此本节难点在于:1,为if语句生成对应代码,由于我们要由浅入深,因此本节if对应判断条件就是两个ID对象,或是ID和Constant常量对象比较,后面我们还会加上&&和||这种运算符。2,如何决定跳转的标签号。这些逻辑不好用言语表述,还是得在代码实现和调试中更好理解。

接下来我看代码实现,首先要修改一下ExprInterface的接口:

type ExprInterface interface {
	NodeInterface
	Gen() ExprInterface
	Reduce() ExprInterface
	Type() *Type
	ToString() string
	//新增两个接口
	Jumping(t uint32, f uint32)
	EmitJumps(test string, t uint32, f uint32)
}

这里新增两个接口分别为Jumping和EmitJumps,它们用来设置if, if…else…,for, while, do…while等控制语句的跳转,由于接口修改了,因此任何实现它的实例都得修改,我们下面只显示正要的修改,其他修改他家可以直接下载代码查看,代码下载地址我在末尾给出。首先要修改的是expr.go:

func (e *Expr) Jumping(t uint32, f uint32) {
	e.EmitJumps(e.ToString(), t, f)
}

func (e * Expr) EmitJumps(test string, t uint32, f uint32) {
	if t != 0 && f != 0 {
		e.Emit("if " + test + " got L" + str
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值