lua词法语法分析

lua是我工作中的第一语言,因而工作的大部分时间,都在敲着lua代码。虽然它语法是否简单
好学,但它来做工程的人,都不免要抱怨作者的一些设定理念。 据说作者是一个学院派的人(从他的
sample代码中就能看出这点),很少也不会去考虑做工程的人的需求。 因而,留给我们这些使用lua
的人不少痛苦。
<wbr><wbr><wbr>大伙不爽的事情如下:<br><wbr><wbr><wbr>1. 默认的变量声明是全局的, 局部需要 local 关键字。<br><wbr><wbr><wbr>原因: 正常的一段代码, local的变量怎么也比全局的多, 如果反过来, 想python一样,<br><wbr><wbr><wbr>默认是local , global 来定义全局能省下不少要敲的代码量。并且避免不小心敲错一个<br><wbr><wbr><wbr>单词导致多一个global变量,而又无法察觉。<br><br><wbr><wbr><wbr>2. 没有continue....<br><wbr><wbr><wbr><wbr><wbr><wbr>- -,说不好其实也没啥,毕竟绕一下还是能实现,但作为一门成熟的编程语言,应该<br><wbr><wbr><wbr>不至于为了省点语法分析代码而不实现continue吧<br><wbr><wbr><wbr><br><wbr><wbr><wbr>3. hash 和 array不区分<br><wbr><wbr><wbr><wbr><wbr><wbr>这应该说是lua的特点, 只要把table用得正确也不会有太大问题。 但对于初学者<br><wbr><wbr><wbr>每次都必须花时间去了解table.getn之类的语义。 而且在我们项目里,因为很多table<br><wbr><wbr><wbr>不能区分到底是当array还是hash用,每次求table的大小时都必须一项一项去数。而且这<br><wbr><wbr><wbr>似乎还成为了编程的惯例。因而,我的设想是如果table里面能多一项来跟着table元素的<br><wbr><wbr><wbr>个数。将省不少麻烦。<br><br> 说是这样说,但是如果真正去改虚拟机,也是个不少的工作量。而最麻烦的是,如果项目真的使用<br> 自己改虚拟机,那么将会对以后使用第三方库带来很多麻烦。所以这一直只是个想法而没人去尝试。<br><wbr><wbr><wbr><br> 不过既然都想到这点,就不能不了解一下lua虚拟机的词法和语法分析过程。 前阵子花的点时间去<br> 阅读这部分源码。在此大家分享一些笔记。<br><br><wbr><wbr><wbr>lua源文件中与编译相关的主要有四个lopcodes(字节码),llex(词法分析),lparser(语法分析),lcode(目标代码生成).<br> lopcodes里定义了指令的格式,寄存器和常数的表示等.这里记录下一些用语的细节,方便下文.相信大家都比较熟悉. <wbr><br> --[[<br> 一个指令由32位的值,对于有三种模式。<br> iABC,iABx 和 iAsBx, i是6位的操作码,A为8位, BC为9位, Bx 和 sBx为18位。<br> A参数通常用作为需要赋值的寄存器, sBx一般用于做跳转量。<br><br> 然后是常量与寄存器的索引。lua通常使用255个寄存器,第n个寄存器一般表示为R(n),<br> 而常量从256开始编号。 常量与寄存器一起成为RK值,RK(x)如果x小于256则为R(x)<br> 否则,为K(x-256),即第x-256+1个常量。RK值经常作为指令的参数。<br><br> pc指下一个指令的位置<br> --]]<br><br> ----------------------------------------------------------------------------------------------------------------<br> 词法分析<br><br><wbr><wbr><wbr>词法分析过程比较简单,主要的处理函数是int llex(LexState *ls, SemInfo *seminfo)<br> 它接受一个LexState结构,通过其中的buff读取字节,返回一个token和将语义信息填充到SemInfo中(字符串和数值)。<br> 要注意的地方有两个。<br><br><wbr><wbr><wbr>一是保留字的处理。lua在初始化时调用luaX_init,建立起所有保留字的字符串对象(同时让它永远不回收,调用luaS_fix)。<br> 并且设定其reserved值为该保留字的枚举值。因为lua中相同的字符串只有一份,所以在llex中遇到reserved字段非空的<br> 字符串即为保留字,否则为TK_NAME。<br><br><wbr><wbr><wbr>二是多行注释和字符串。即当读取到'--[' 或 '['的时候,要处理长字符串的情况。通过skip_sep 和 read_long_string处理两段‘=’<br> 数量的匹配。<br> ----------------------------------------------------------------------------------------------------------------<br><br> 语法分析<br><wbr><wbr><wbr><br><wbr><wbr><wbr>语法分析是编译过程的重点,其外部接口是Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name)<br> 它从字节流z读取符合, 建议LexState做词法分析, 同时按照语法生成规则展开, 最后调用到lcode里的接口生成各条指令记录到函数体Proto.<br><br><wbr><wbr><wbr>最上层的语法规则都比较容易理解, 如 chunk , statment, block等. 执行根据生成规则一层层打开即可.<br> 需要注意的是以下的内容:<br><br> ----------------------------------------------------------------------------------------------------------------<br> 1.table的构造过程<br><br> 表构造的处理函数是void constructor (LexState *ls, expdesc *t)<br> 它先生存一条OP_NEWTABLE指令, 然后根据语法, 按','(或';')切分每项, 根据格式调用listfield 或者 recfield<br> recfield 生成的是 记录项, 也就是 x = y 或者 [x] = y 的形式, 它用分别用expr求出key 和 value 表单式值,<br> 然后生成一条OP_SETTABLE指令.<br><br> 这里想说的是数组项的处理方式, 它并没有对每一项产生一个OP_SETTABLE指令, 而是缓存起来再一次性处理的.<br> 其实listfield的只是对之listfield里面仅仅是对value 进行expr调用. 然后记录待处理的项数量+1 (cc-&gt;tostore++)<br> 在每次遇到项处理前, 都调用closelistfield, closelistfield 发现当待处理的项达到FPF时(默认50个)<br> 生成一个OP_SETLIST指令, 批量对他们赋值.<br> OP_SETLIST指令的格式为 OP_SETLIST<br> 意外把 寄存器A中的table批量赋值, 数量为B个, 目标值所指寄存器范围是 [C-1]*FPF+1 ~ [C-1]*FPF+B<br><br> 因而, 以下语句<br> local a = { 1; 2; 3; [5] = 'a', 4, 5, [7] = 'b', 6, 7, 8}<br><br> 的编译结果将是<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> [01] newtable<wbr><wbr> 0<wbr><wbr> 8<wbr><wbr> 2<wbr><wbr><wbr> ; array=8, hash=2<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> [02] loadk<wbr><wbr><wbr><wbr><wbr> 1<wbr><wbr> 0<wbr><wbr><wbr><wbr><wbr><wbr><wbr> ; 1<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> [03] loadk<wbr><wbr><wbr><wbr><wbr> 2<wbr><wbr> 1<wbr><wbr><wbr><wbr><wbr><wbr><wbr> ; 2<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> [04] loadk<wbr><wbr><wbr><wbr><wbr> 3<wbr><wbr> 2<wbr><wbr><wbr><wbr><wbr><wbr><wbr> ; 3<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> [05] settable<wbr><wbr> 0<wbr><wbr> 259 260<wbr> ; 5 "a"<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> [06] loadk<wbr><wbr><wbr><wbr><wbr> 4<wbr><wbr> 5<wbr><wbr><wbr><wbr><wbr><wbr><wbr> ; 4<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> [07] loadk<wbr><wbr><wbr><wbr><wbr> 5<wbr><wbr> 3<wbr><wbr><wbr><wbr><wbr><wbr><wbr> ; 5<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> [08] settable<wbr><wbr> 0<wbr><wbr> 262 263<wbr> ; 7 "b"<br><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值