一步步写lua解释器--函数语句

函数包括函数名,参数,函数体。函数体又包括语句,返回语句。函数的声明又分为显式,匿名式,例如下面两种:

local f = function(params) ... end
local function f(params) ... end

不管哪种类型,我们需要提取其名字f,保存在局部变量表里,这个倒是不难。然后是对函数的每个部分逐一解析。函数参数是名字变量列表,这个相当于初始化名字列表,把名字压入栈上,等待函数实参传入,然后再赋值。函数体各种语句的解析是一系列语句的解析,与前面代码生成综述里说到的没什么不一样。

由于函数只有被调用的时候才被执行,所以有个很关键的问题是,这些函数生成的代码保存在哪里?一个函数被声明了但始终没有被执行,显然函数声明部分的代码和执行部分的代码是在不同的时空区域。我们可以这样来做,用一个变量来保存一个函数的声明代码,等到函数执行时才跳转去执行保存的代码。显然这个变量有一个容器,来盛装函数代码指令集。这种方法也可以推广到if else语句,因为if else语句中,不确定哪个部分会被执行,哪个部分永远不执行。

我们再来梳理一遍,遇到函数时就开始为函数每个子部分解析,最后将生成的代码保存在一个变量中,然后生成一条OpCode_GenerateClosure的指令。实际上这个指令就相当于一条push的指令,把这个值压入栈上。由于每个闭包都有其自己的作用域,所以我们还需要生成‘进入’和‘退出’闭包的指令,用来保存和释放闭包的局部变量。还有就是函数返回值的处理,这个下面讲函数调用时会说到。

函数的调用虽然只有一条语句,但是处理好函数的调用并不简单。调用函数时首先将函数参数解析,他会将值压入栈上。前面说到实参与形参的个数不一样怎么办?我是这么做的,如果实参个数是m,小于形参个数n,那么则再传入n-m个Nil值。当然也可以不传入Nil值,等到赋值时将多余的形参去掉。如果m>n,实参将会被舍弃掉。实参的个数容易得知,形参的个数在解析函数声明时会保存在指令里。

函数的返回语句被解析后都会压入栈上,有多个返回值,就会压入多少个,但是这些可能并不会被使用,所有我们必须在闭包运行结束时清理掉没有被使用到的值,否则栈就不平衡了。如何知道有多少个返回值被使用呢?一般情况下,函数调用者只需要一个返回值,例如在算术,逻辑语句中调用函数,即使函数没有返回值,也要一个空值。单独调用函数是不需要返回值的。赋值语句中调用函数,需要函数的返回值是不确定的,这个要分情况讨论:

local a,b,c = 1,f()  --函数调用是最后一个语句时,需要剩下没赋值变量个数的返回值
a = f(),1            --只需要一个返回值

所有关于函数的返回值,我们需要两个变量:

  • 函数实际返回了多少个返回值
  • 调用者实际使用了多个返回值    

前者,我们可以在函数return语句中计算,没有return语句就是0个。后者可以在生成调用函数语句时根据情况计算,然后保存在call指令中。

好了关于函数就说这么多了,函数的高级用法,调用函数中嵌套的返回函数将在下一篇讨论。

 

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

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值