lua词法语法分析

转载 2013年12月04日 09:04:17
lua是我工作中的第一语言,因而工作的大部分时间,都在敲着lua代码。虽然它语法是否简单
好学,但它来做工程的人,都不免要抱怨作者的一些设定理念。 据说作者是一个学院派的人(从他的
sample代码中就能看出这点),很少也不会去考虑做工程的人的需求。 因而,留给我们这些使用lua
的人不少痛苦。
    大伙不爽的事情如下:
    1. 默认的变量声明是全局的, 局部需要 local 关键字。
    原因: 正常的一段代码, local的变量怎么也比全局的多, 如果反过来, 想python一样,
    默认是local , global 来定义全局能省下不少要敲的代码量。并且避免不小心敲错一个
    单词导致多一个global变量,而又无法察觉。

    2. 没有continue....
        - -,说不好其实也没啥,毕竟绕一下还是能实现,但作为一门成熟的编程语言,应该
    不至于为了省点语法分析代码而不实现continue吧
    
    3. hash 和 array不区分
        这应该说是lua的特点, 只要把table用得正确也不会有太大问题。 但对于初学者
    每次都必须花时间去了解table.getn之类的语义。 而且在我们项目里,因为很多table
    不能区分到底是当array还是hash用,每次求table的大小时都必须一项一项去数。而且这
    似乎还成为了编程的惯例。因而,我的设想是如果table里面能多一项来跟着table元素的
    个数。将省不少麻烦。

说是这样说,但是如果真正去改虚拟机,也是个不少的工作量。而最麻烦的是,如果项目真的使用
自己改虚拟机,那么将会对以后使用第三方库带来很多麻烦。所以这一直只是个想法而没人去尝试。
    
不过既然都想到这点,就不能不了解一下lua虚拟机的词法和语法分析过程。 前阵子花的点时间去
阅读这部分源码。在此大家分享一些笔记。

    lua源文件中与编译相关的主要有四个lopcodes(字节码),llex(词法分析),lparser(语法分析),lcode(目标代码生成).
lopcodes里定义了指令的格式,寄存器和常数的表示等.这里记录下一些用语的细节,方便下文.相信大家都比较熟悉.  
--[[
一个指令由32位的值,对于有三种模式。
iABC,iABx 和 iAsBx, i是6位的操作码,A为8位, BC为9位, Bx 和 sBx为18位。
A参数通常用作为需要赋值的寄存器, sBx一般用于做跳转量。

然后是常量与寄存器的索引。lua通常使用255个寄存器,第n个寄存器一般表示为R(n),
而常量从256开始编号。 常量与寄存器一起成为RK值,RK(x)如果x小于256则为R(x)
否则,为K(x-256),即第x-256+1个常量。RK值经常作为指令的参数。

pc指下一个指令的位置
--]]

----------------------------------------------------------------------------------------------------------------
词法分析

    词法分析过程比较简单,主要的处理函数是int llex(LexState *ls, SemInfo *seminfo)
它接受一个LexState结构,通过其中的buff读取字节,返回一个token和将语义信息填充到SemInfo中(字符串和数值)。
要注意的地方有两个。

    一是保留字的处理。lua在初始化时调用luaX_init,建立起所有保留字的字符串对象(同时让它永远不回收,调用luaS_fix)。
并且设定其reserved值为该保留字的枚举值。因为lua中相同的字符串只有一份,所以在llex中遇到reserved字段非空的
字符串即为保留字,否则为TK_NAME。

    二是多行注释和字符串。即当读取到'--[' 或 '['的时候,要处理长字符串的情况。通过skip_sep 和 read_long_string处理两段‘=’
数量的匹配。
----------------------------------------------------------------------------------------------------------------

语法分析
    
    语法分析是编译过程的重点,其外部接口是Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name)
它从字节流z读取符合, 建议LexState做词法分析, 同时按照语法生成规则展开, 最后调用到lcode里的接口生成各条指令记录到函数体Proto.

    最上层的语法规则都比较容易理解, 如 chunk , statment, block等. 执行根据生成规则一层层打开即可.
需要注意的是以下的内容:

----------------------------------------------------------------------------------------------------------------
1.table的构造过程

表构造的处理函数是void constructor (LexState *ls, expdesc *t)
它先生存一条OP_NEWTABLE指令, 然后根据语法, 按','(或';')切分每项, 根据格式调用listfield 或者 recfield
recfield 生成的是 记录项, 也就是 x = y 或者 [x] = y 的形式, 它用分别用expr求出key 和 value 表单式值,
然后生成一条OP_SETTABLE指令.

这里想说的是数组项的处理方式, 它并没有对每一项产生一个OP_SETTABLE指令, 而是缓存起来再一次性处理的.
其实listfield的只是对之listfield里面仅仅是对value 进行expr调用. 然后记录待处理的项数量+1 (cc->tostore++)
在每次遇到项处理前, 都调用closelistfield, closelistfield 发现当待处理的项达到FPF时(默认50个)
生成一个OP_SETLIST指令, 批量对他们赋值.
OP_SETLIST指令的格式为 OP_SETLIST
意外把 寄存器A中的table批量赋值, 数量为B个, 目标值所指寄存器范围是 [C-1]*FPF+1 ~ [C-1]*FPF+B

因而, 以下语句
local a = { 1; 2; 3; [5] = 'a', 4, 5, [7] = 'b', 6, 7, 8}

的编译结果将是
           [01] newtable   0   8   2    ; array=8, hash=2
           [02] loadk      1   0        ; 1
           [03] loadk      2   1        ; 2
           [04] loadk      3   2        ; 3
           [05] settable   0   259 260  ; 5 "a"
           [06] loadk      4   5        ; 4
           [07] loadk      5   3        ; 5
           [08] settable   0   262 263  ; 7 "b"
         

Lua源码解析之一:lexical

我们知道,任何高级一点的编译器,在解析源代码时,都需要进行词法分析。而词法分析的过程就是先识别token的一个过程,总体来说,lua里面的token大致分为: 1. 数字和字符串 2. 特殊字符:包括...

探索Lua5.2内部实现:编译系统(1) 概述

原文 Lua是一个轻量级高效率的语言。这种轻量级和高效率不仅体现在它本身虚拟机的运行效率上,而且也体现在他整个的编译系统的实现上。因为绝大多数的lua脚本需要运行期动态的加载编译,如果编译过程本...

lua基础——基本语法

lua基础--基础语法

lua 5.1语法约定

Lua 5.1参考手册 由罗伯特·Ierusalimschy路易斯Henrique de Figueiredo沃尔德蔡氏 ‚一个版权©2006 A¢A€“2012 Lua.org,银行业者。免费的根据...

编译器架构的王者LLVM——(4)简单的词法和语法分析

Lex和Yacc真是太好用了,非常方便我们构建一门语言的分析程序。今天我们就来了解一门语言的Lex和Bsion定义文件,如果制作一款合理的词法、语法分析器...

Stanford Parser的使用——进行词法语法分析

http://blog.csdn.net/pipisorry/article/details/42976457 stanford-parser的使用 1、到斯坦福官方网站http://nlp...

编译原理课设——《TINY编译器》,用lex和yacc生成词法语法分析源码,实现编译器

注:工作环境
  • gaixm
  • gaixm
  • 2014年06月20日 09:54
  • 1687

课程设计SNL语言词法/语法分析中遇到的坑

在文件指针指向EOF时,seekg()函数已经不好用了,可以in.clear()清除流,或者找别的方法解决。 不要相信书上的predict集合,很多坑等着你跳。 使用Boost库,好多好用的轮子。 最...

yacc语法分析与lex词法分析相结合

语法对于某些应用,我们所完成的简单的词类识别也许足够用了;而另一些应用需要识别特殊的标记序列并执行适当的动作。传统上,对这样的一套动作描述成为语法。使用右箭头”->”意味着可以用一个新的符号取代一套特...

计算器程序,支持+-*/和(),以#号结尾,有词法分析,和运算,没有语法分析是否正确,但是只要输入正确就能运行

#include #include #include #include using namespace std; class Token{ public: int kind;//0:符号 ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:lua词法语法分析
举报原因:
原因补充:

(最多只允许输入30个字)