一步步写lua解释器--table的实现

lua中的table貌似是lua中唯一的数据结构了,他既可以充当数组,也可以充当map使用,把这两种结合为一个数据结构,足以说明lua的简洁易用性。

原本以为table实现起来会比较复杂,结果一上午就差不多写好了,而if语句却写了一整天,当然也包括了优化其他代码。

table的实现包括构造和存取。一个table的构造:

local a = {b = 3,c = {e = 9}}

语法树会生成一个TableDefine节点,包含了field列表TableNameField系列子节点,b=3, c= {e=9},可以看出filed列表其实是表达式列表,使用表达式列表规则解析即可,生成代码时字段名和字段值都会压入栈,例如‘b’和3都压入栈中。在生成构造表定义的代码里,我们先new一个带hashmap的数据结构table,然后把栈上的两个值pop出来,作为key,value。为了将table一次性构造完毕,我们还需要把表字段的个数附加在指令里,到时执行指令时才知道需要取出多少对key和value。将栈上的key,val键值对填充到table后,把这个table压入栈中,等待被赋值。

上面的过程也适用于构造嵌套表,无非是递归调用而已。

表的存取比构造复杂一些,因为表的层级会大于2个,例如a.c.e。在解析存取表字段时,采取贪婪规则,也就是一直找最长的表名为止,即a.c.e分为两部分a.c和e而不是a和c.e。这样做的目的是右边部分永远是一个单一的字段,左边可以用递归来继续解析,最后a.c被拆成a,c。如果按照a和c.e来拆分,c.e再被拆分为c,e则是错误的,因为不存在c这个表,他只是一个字段。

在表的存取生成代码中,表名和表字段都要是SET模式的,因为需要将表名和字段名的字符串都将压入栈中,而不是将其对于的值压入栈中。

对于简单表名字段的存取较为简单,例如a.b,从栈上获取到表名和字段名a与b,然后从局部变量表中查找a,找到后再获取字段b的值。如果是a.b.c,上面介绍到会先执行a.b,这样先把这个值压入栈上,当再次执行存取字段指令时,则可以从栈中获取到a.b的表,以及字段c的字符串。所以要判断栈上是否是表还是字符串。

带有数组下标访问的表要复杂些, 例如t={1,[2]=22, 2},t[2]实际等于2,t={1,2,[2]=22},t[2]还是等于2,不是因为[2]被忽略了,请看t={1,[2] = 22}这下t[2] = 22了。实际上[4]转换为了['4'],作为一个字符串存在table中了。所以正确的解析方式是,数组下标1,2,3...的元素最后执行,这样就能覆盖[2]了。解析的时候,数值下标字段代码部分要先执行,因为栈是先进后出的数据结构。

 

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值