`

Lua5.1代码阅读(二):llex.h/llex.c

Lua 
阅读更多

 

Lua5.1代码阅读(二):llex.h/llex.c

 

(未完成,待修改)

 

一、作用和参考资料

llex.c是Lua的词法分析器(把单个输入字符串切割为多个输出符号)

参考:

1. Lua 5.1.3源代码分析之词法分析 By 天地沙鸥

http://xenyinzen.wordpress.com/2009/12/09/lua-5-1-3%E6%BA%90%E4%BB%A3%E7%A0%81%E5%88%86%E6%9E%90%E4%B9%8B%E8%AF%8D%E6%B3%95%E5%88%86%E6%9E%90/

二、包含头文件

1. llex.h

#include "lobject.h"

#include "lzio.h"

2. llex.c

#include <ctype.h>

#include <locale.h>

#include <string.h>

#include "lua.h"

#include "ldo.h"

#include "llex.h"

#include "lobject.h"

#include "lparser.h"

#include "lstate.h"

#include "lstring.h"

#include "ltable.h"

#include "lzio.h"

 

三、宏

1. #define FIRST_RESERVED 257

RESERVED枚举值第一个枚举的整数值。

大于256的目的可能是想避开ASCII值的范围(见luaX_token2str)。

2. #define TOKEN_LEN (sizeof("function")/sizeof(char))

保留字的最大内存长度(包括结尾的'\0')。

3. #define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1))

保留字的个数(cast是定义在llimit.h的宏,用于C强制转换)。

4. #define llex_c

llex.c的宏缩写(象征形式)

5. #define LUA_CORE

表示llex.c位于底层实现中(象征形式)

6. #define next(ls) (ls->current = zgetc(ls->z))

从输入流中读取一个字符值,保存为ls(词法分析器)的当前字符值

7. #define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r')

判断当前是否回车。

8. #define save_and_next(ls) (save(ls, ls->current), next(ls))

把当前字符保存到变长缓冲区,然后读下一个符号。

9. #define MAXSRC          80

用于处理源文件名ls->source的临时缓冲区的最大长度(?)

四、枚举

1. 

enum RESERVED {

 TK_AND = FIRST_RESERVED, TK_BREAK,

 TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,

 TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,

 TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,

 TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER,

 TK_NAME, TK_STRING, TK_EOS

};

保留字枚举量(和luaX_tokens对应),表示特殊的token范围。

如果要修改它的顺序,需要修改注释有ORDER RESERVED的代码。

* TK_AND到TK_WHILE是表示保留字的终结符(终结符是指语法中不需要继续推导的符号)

* TK_CONCAT到TK_EOS是非保留字的其它终结符(运算符、字面值和文件结束)。

五、公开的全局变量

1. LUAI_DATA const char *const luaX_tokens [];

const char *const luaX_tokens [] = {

"and", "break", "do", "else", "elseif",

"end", "false", "for", "function", "if",

"in", "local", "nil", "not", "or", "repeat",

"return", "then", "true", "until", "while",

"..", "...", "==", ">=", "<=", "~=",

"<number>", "<name>", "<string>", "<eof>",

NULL

};

names符号(终结符)的常量字符串数组(对应RESERVED枚举的顺序)。

用于把特殊符号转换为字符串。

六、结构体、联合体

1. 

typedef union {

 lua_Number r;

 TString *ts;

} SemInfo;

单个语义信息(联合体)

2. 

typedef struct Token {

 int token;

 SemInfo seminfo;

} Token;

单个符号信息(结构体)

3. 

typedef struct LexState {

 int current;  

 int linenumber;  

 int lastline;  

 Token t;  

 Token lookahead;  

 struct FuncState *fs;  

 struct lua_State *L;

 ZIO *z;  

 Mbuffer *buff;  

 TString *source;  

 char decpoint;  

} LexState;

词法状态:

* current:当前int型字符值

* linenumber:输入行号

* lastline:最后一个被消费的符号的行号。

* Token:当前符号信息

* lookahead:向前看的符号信息

* fs:函数状态,对于parser是私有的

* L:Lua状态机

* z:输入流

* buff:符号缓冲

* source:当前源码文件名

* decpoint:本地区域的十进制浮点

七、全局私有的静态方法

1. static void save (LexState *ls, int c) {

把c接到ls->buff变长缓冲区的结尾(确保不会超出缓冲区范围)

2. static const char *txtToken (LexState *ls, int token) {

根据token取出字面值。

如果token是名称、数、字符串字面值,把ls->buff转成'\0'结束的C字符串。

如果token是特殊token(保留字、运算符),直接返回其字符串形式。

3. static void inclinenumber (LexState *ls) {

增加行号(检查溢出)。

然后跳过附近的'\n'和'\r'。

4. static int check_next (LexState *ls, const char *set) {

检查词法状态机的当前字符值是否在字符集set内。

如果是,则执行save_and_next

5. static void buffreplace (LexState *ls, char from, char to) {

把词法状态机的缓冲区中的字符值from全部替换为字符值to。

6. static void trydecpoint (LexState *ls, SemInfo *seminfo) {

把'.'改为本地(locale)的十进制小数点分割符

(使用<locale.h>的函数localeconv获取本地数字及货币信息格式),

然后继续尝试字符串到数字的转换。

7. static void read_numeral (LexState *ls, SemInfo *seminfo) {

循环(逐字符)读取LUA_NUMBER(内部实现是double型)字面值字符串

8. static int skip_sep (LexState *ls) {

循环读取[=或]=分割符,

然后返回其层数('='的个数,如果是右面则为负数)

9. static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) {

读带分隔符的字符串字面值(如[[abc]])

10. static void read_string (LexState *ls, int del, SemInfo *seminfo) {

读一般的字符串字面值(如"abc",'abc')

11. static int llex (LexState *ls, SemInfo *seminfo) {

词法分析器循环,使用switch进行跳转。

八、全局公开的方法

1. void luaX_init (lua_State *L) {

LUAI_FUNC void luaX_init (lua_State *L);

初始化词法分析器:

* 把所有保留字加入符号表。确保所有保留字的符号表字符串不被回收。

* 诊断TOKEN_LEN是最大的保留字长度。

2. const char *luaX_token2str (LexState *ls, int token) {

LUAI_FUNC const char *luaX_token2str (LexState *ls, int token);

把int型的token(可印刷字符、控制字符、保留字符号)转为可读的字符串。

3. void luaX_lexerror (LexState *ls, const char *msg, int token) {

LUAI_FUNC void luaX_lexerror (LexState *ls, const char *msg, int token);

报告词法错误,然后抛出LUA_ERRSYNTAX异常。

4. void luaX_syntaxerror (LexState *ls, const char *msg) {

LUAI_FUNC void luaX_syntaxerror (LexState *ls, const char *s);

报告语法错误,然后抛出LUA_ERRSYNTAX异常。

和luaX_lexerror相同,只是报告的token是当前词法状态机的符号。

5. TString *luaX_newstring (LexState *ls, const char *str, size_t l) {

LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l);

在符号表中创建字符串(确保不会重复收集),返回TString指针(符号表字符串)。

6. void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) {

LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source);

初始化词法状态机的输入流ls,然后读取第一个字符值

7. void luaX_next (LexState *ls) {

LUAI_FUNC void luaX_next (LexState *ls);

读下一个词法符号。

如果已经有被lookahead的词法符号,就直接取它的值避免遗漏。

8. void luaX_lookahead (LexState *ls) {

LUAI_FUNC void luaX_lookahead (LexState *ls);

向前看(lookahead,即提前读)后一个词法符号。用于语法预测。

九、值得观察的关键代码

1. llex

它是luaX_next和luaX_lookahead的底层实现

 

(未完成,待修改)

 

 

 

分享到:
评论

相关推荐

    lua-utf8.zip

    a utf-8 support module for Lua and LuaJIT 源码地址:https://github.com/starwing/luautf8 编译后可用的库: Linux版:lua-utf8.so Windows版:lua-utf8.dll(若是用在openresty中,openresty版本需使用32位版本...

    luadec解密工具 包含了5.1、5.2、5.3版本的 luareplace.exe/ luaopswap.exe/ luadec.exe/ lua.exe

    ├─5.1 │ └─bin │ liblua51.lib │ lua.exe │ lua51.dll │ lua51.lib │ luac.exe │ luadec.exe │ luaopswap.exe │ luareplace.exe │ ├─5.2 │ └─bin │ liblua52.lib │ lua.exe │ lua52.dll │ ...

    lua5.1 cjson.dll模块

    cjson.dll 需要lua5.1.dll 调用require “cjson” cjson.dll 需要lua5.1.dll 调用require “cjson”

    Lua5.1.5-lib库

    1. **lua.h**: 这是Lua C API的头文件,定义了所有与C语言交互的函数和数据结构。 2. **lua.c/lua.o**: Lua的主解析器和虚拟机实现,编译后的对象文件或静态库。 3. **lapi.c/lapi.o**: 实现了Lua与C之间的接口,...

    lua5.1版本源代码

    Lua脚本可以很容易的被C/C++代码调用,也可以反过来调用C/C++的函数,这使得Lua在应用程序中可以被广泛应用。不仅仅作为扩展脚本,也可以作为普通的配置文件,代替XML,Ini等文件格式,并且更容易理解和维护。 Lua...

    Lua5.1全三套:Lua Programming(中英文版)+中文手册

    首先,我们有《Lua Programming》第二版的中文版和英文版。这本书由Mario J. Silva、Luiz Henrique de Figueiredo和Roberto Ierusalimschy合著,是学习Lua编程的经典教材。中文版对于国内读者来说,降低了语言障碍,...

    lua5.1基础环境包(LuaForWindows_v5.1.5-52及mingw).zip

    总结来说,这个压缩包为Windows用户提供了完整的Lua 5.1开发环境,包括解释器、调试工具以及用于编译C扩展的MinGW。通过这个环境,开发者能够快速入门并深入掌握Lua编程,利用其强大的功能来解决各种问题。

    lua-5.1.5-Win64-bin (exe)程序

    2. **luac5.1.exe**:这是Lua的编译器,它可以将Lua源代码转换为预编译的字节码,这种字节码可以直接由Lua虚拟机执行,提高了加载速度。这对于大型应用或者需要快速启动的环境尤其有用。 3. **bin2c5.1.exe**:这是...

    FairyGUI生成lua代码插件.rar

    FairyGUI生成lua代码插件 导入到FairyGUI编辑器,可以为UI生成lua代码。 Git路径: https://github.com/qufangliu/Plugin_FairyGUI_Lua

    在线编码环境Praxis.zip

    Praxis 是基于 Lua,Lisp 和 Forth 的在线编码环境。 特性 OpenGL 实时音频生成 Midi 立体引擎 可编程的文本编辑器 等等 Introduction: https://www.youtube.com/watch?v=1VRtRazMYSA Running the ...

    ZeroBraneStudio1.9和lua脚本测试代码

    ZeroBrane Studio是一个免费、开源、跨平台(Windows、MacOSX和Linux)的Lua集成开发环境(IDE),它提供了代码提示、远程调试、代码分析、语法高亮等功能,支持Lua 5.1、Lua 5.2、Lua 5.3、LuaJIT和其他Lua引擎1。

    Lua-5.1.5-部分源码注释.rar

    1. **API接口(lapi.c)**:这部分代码定义了Lua与C语言交互的接口,包括创建和销毁lua_State,调用lua_pcall,注册C函数到全局环境等操作。 2. **编译器(lcode.c, llex.c, lparser.c)**:Lua的编译器将源代码转换为...

    lua5.1.lib

    lua5.1.lib文件缺失,LNK1181

    lua-nginx-module-0.10.9rc7

    例如,使用`lua_code_cache on|off`来控制Lua代码缓存策略,用`set_by_lua_file`或`access_by_lua_file`等指令执行Lua脚本。 4. **测试与启动**:在修改配置后,务必先运行`nginx -t`测试配置文件的正确性,无误后...

    lua5.1 +luarocks for windows64安装版

    Lua 5.1是Lua语言的一个版本,发布于2006年,它提供了强大的数据结构,如表(tables),支持动态类型的面向对象编程,以及灵活的接口机制,使它能够方便地与各种C/C++程序进行交互。这个版本相对于更早期或更晚期的...

    Cocos2d-x之C++和Lua通信5个入门Demo

    木头Cocos2d-x教程 Lua篇 Demo源代码。 教程地址: 第1章:http://blog.csdn.net/musicvs/article/details/8440707 第2章:http://blog.csdn.net/musicvs/article/details/8440919 第3章:...

    lua5.1静态库

    源代码通常包含`.c`和`.h`文件,`.c`文件是实现函数和数据结构的C语言代码,`.h`文件则定义了头文件,包含对外接口声明。这对于理解Lua的内部工作原理以及根据特定需求定制功能非常有用。 "编译 lua5.1"标签指示了...

    lua源码下载 Lua-5.3.4 源码 最新 截止2017-3-7

    3. **lualib.h** 和 **luac.h**: 分别包含了标准库和编译器的接口。 4. **lstate.h**: 描述了lua_State结构,它是Lua执行环境的核心,保存了所有运行时信息。 5. **lparser.h** 和 **llex.h**: 用于解析Lua源代码...

    lua5.1压缩包源文件

    其中,`lua.c` 和 `luac.c` 分别是 Lua 解释器和编译器的主要实现。通过阅读这些源码,你可以了解到 Lua 如何解析和执行代码。 2. `lualib/`:这个目录包含了 Lua 标准库的源代码,如数学运算、字符串处理、文件I/O...

    c#调用脚本语言Lua——简单Demo

    c#调用脚本语言Lua——简单Demo 配置: 1. 下载c#下的Lua支持类库。下载地址:http://files.luaforge.net/releases/luainterface/luainterface/2.0.3 将(lua51.dll\LuaInterface.dll)引用自己的项目中。 2. 修改...

Global site tag (gtag.js) - Google Analytics