一步步写lua解释器--代码生成

上一篇讲了如何生成语法树。生成语法树之后就要生成代码了,即可以被执行的指令,想想都有点激动。前面提到再复杂的代码都可以转换为赋值,运算,比较等指令。赋值是将一个确定的数值或字符串赋给一个变量,他是一个二元操作。运算无非是简单的四则运算,加减乘除,他们都是二元的。比较也是将值与true or false对比,也是二元操作。

赋值拿local a = 1 举例,变量是a,值是1。遇到这个语句时,怎么样让它执行呢?最终肯定是要给一个名字叫'a'的变量绑定值1的,'a',1是他的两个元,我们可以先找一个地方存放这两个值,然后让他们相等。存放值的地方其实是一个数据容器,我们可以叫做栈,因为我们经常要做出栈和入栈操作,栈是一种后进先出的数据结构。

我们可以直接把数值1进行入栈操作,当然‘a’也要做入栈操作,然后进行赋值操作,引导这个赋值操作的是一条指令。反过来我们这么想,遇到一条赋值操作指令时,先后出栈两个值,然后将他们赋值。显然‘a’和1入栈和出栈的顺序要保存一致,这个在生成指令和解析指令时做到一致即可。

有个问题是,让变量‘a’ = 1,究竟是哪个的值等于1?我们先要建立一个规则,遇到像‘a’这样的字符时,找到一个变量,让其等于1。了解数据结构的朋友会想到,这种规则是字典map一类的数据结构,我代码中用的是hashmap。说变量赋值其实很笼统,因为变量有初始化和赋值两种。初始化就是生成一个新的变量,让他等于某个值,赋值则是找到之前已经存在的一个值再赋值,如果找不到,说明语法或者解析错误了。所以要对这两种操作作区分,而且是很重要的区分,因为他们是两种完全不一样的语义。

还有一个问题是,其实叫‘a’的变量有很多,每个函数都有可以有这个合法的变量。如何解决这个变量名一致的问题,其实很简单,不同的作用域嘛。一个函数就是一个作用域,而且函数里面的局部模块(如if else等)也要有一个新的作用域。每一个作用域都有一个map表来保存其局部变量,所以不同函数中有相同名字的局部变量名,不会发生冲突。当然相同模块中有相同名字的变量名,那就是是错误的了。我们要在进入函数或一个模块的时候,有生成新作用域的指令。

运算操作也是类似这样的,先入栈两个操作数,然后根据不同的运算指令出栈这两个操作数,进行运算操作,然后把结果入栈,等待如赋值,再次出栈等处理。我们再重点说说函数代码的生成。

前面说到,lua中的函数和C++,Java中的函数有些区别,其实我们可以把它看做是一种值,只不过他是一种很复杂的值。不过再复杂的值我们也能把它拆分开来。而且生成函数指令和其他指令有个不一样的地方是,函数只是一种定义,我们并不知道什么时候调用它,所以我们遇到函数时,只是记录他的的指令,只有等到他被调用时,才真正执行其代码。if else语句也是这样的,因为你不知道if else模块中的代码什么时候被执行。前面提到一个词,记录,对,就是记录,也就是把函数的指令保存在一个值中。显然这个值包含一个容器来盛装这些指令,然后就可以把这个值赋值给函数名变量。函数调用只不过是取出这个值,然后执行这个值容器中的指令。

关于如何生成函数的指令我后面还会具体介绍,其他语句也会有讲解,这篇只讲了大概。生成好指令之后就是执行指令了,按照自己想法生成的指令就要被执行了,是不是很鸡冻呢。

有问题可以在后面留言,或者加入QQ群 858791125 讨论。

项目地址:
https://github.com/shonm520/mlua

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值