<转>LUA语法分析
本文选自:http://www.cnblogs.com/nazhizq/p/6516561.html
一步步调试,在lparser.c文件中luaY_parser函数是语法分析的重点函数,词法分析也是在这个过程中调用的。在这个过程中,用到一些数据结构,下面会详细说。
Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) {
struct LexState lexstate;
struct FuncState funcstate;
lexstate.buff = buff;
luaX_setinput(L, &lexstate, z, luaS_new(L, name));
open_func(&lexstate, &funcstate);//初始化funcstate
funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */
luaX_next(&lexstate); //Luax_next用于获取下一个字符
chunk(&lexstate);//代码块分析
check(&lexstate, TK_EOS);//判断lua程序文件是否到达末尾
close_func(&lexstate);//关闭程序
lua_assert(funcstate.prev == NULL);
lua_assert(funcstate.f->nups == );
lua_assert(lexstate.fs == NULL);
return funcstate.f;
}
好,不着急,一步一步来看。lua_State ,LexState ,FuncState 是啥玩意呢?
lua_state是lua程序运行过程中一直存在的,并且一个运行程序只有一个lua_State实例。
struct lua_State {
CommonHeader;
lu_byte status;
StkId top; /* first free slot in the stack */
StkId base; /* base of current function */
global_State *l_G;//全局状态的指针
CallInfo *ci; /* call info for current function */当前函数的调用信息
const Instruction *savedpc; /* `savedpc' of current function */记录上一个函数的pc位置
StkId stack_last; /* last free slot in the stack */
StkId stack; /* stack base */
CallInfo *end_ci; /* points after end of ci array*/函数调用栈的栈顶
CallInfo *base_ci; /* array of CallInfo's */函数调用栈的栈底
int stacksize;
int size_ci; /* size of array `base_ci' */
unsigned short nCcalls; /* number of nested C calls */
lu_byte hookmask;
lu_byte allowhook;
int basehookcount;
int hookcount;
lua_Hook hook;
TValue l_gt; /* table of globals */
TValue env; /* temporary place for environments */
GCObject *openupval; /* list of open upvalues in this stack */
GCObject *gclist;
struct lua_longjmp *errorJmp; /* current error recover point */
ptrdiff_t errfunc; /* current error handling function (stack index) */
};
LexState是用于存储词法分析时的上下文数据。
typedef struct LexState {
int current; /* current character (charint) */指向下一个要读取的字符
int linenumber; /* input line counter */行号
int lastline; /* line of last token `consumed' */
Token t; /* current token */
Token lookahead; /* look ahead token */ 预读的下一个token
struct FuncState *fs; /* `FuncState' is private to the parser */函数状态的数据结构
struct lua_State *L;
ZIO *z; /* input stream */ 输入流
Mbuffer *buff; /* buffer for tokens */ 临时缓冲区
TString *source; /* current source name */ 源文件名
char decpoint; /* locale decimal point */
} LexState;
FuncState是用于存储函数状态的数据结构。
typedef struct FuncState {
Proto *f; /* current function header */函数头信息
Table *h; /* table to find (and reuse) elements in `k' */
struct FuncState *prev; /* enclosing function */指向函数链表的上一个函数
struct LexState *ls; /* lexical state */
struct lua_State *L; /* copy of the Lua state */
struct BlockCnt *bl; /* chain of current blocks */
int pc; /* next position to code (equivalent to `ncode') */
int lasttarget; /* `pc' of last `jump target' */
int jpc; /* list of pending jumps to `pc' */
int freereg; /* first free register */
int nk; /* number of elements in `k' */
int np; /* number of elements in `p' */
short nlocvars; /* number of elements in `locvars' */local变量个数
lu_byte nactvar; /* number of active local variables */
upvaldesc upvalues[LUAI_MAXUPVALUES]; /* upvalues */
unsigned short actvar[LUAI_MAXVARS]; /* declared-variable stack */
} FuncState;
初始化完成后,就要进行词法分析,即读取下一个token,调用luaX_next(&lexstate); 下面进入llex.c文件的源代码中
void luaX_next (LexState *ls) {
ls->lastline = ls->linenumber;
if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */
ls->t = ls->lookahead; /* use this one */
ls->lookahead.token = TK_EOS; /* and discharge it */
}
else
ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */调用llex函数读取下一个token
}
llex函数:里面是一大串的switch...case...语句,对各种可能的情况进行处理,正常的变量名或者保留字会进入default语句,分别处理空格,数字或者变量名。
for (;;) {
switch (ls->current) {
case '\n':
case '\r':
case '-':
case '[':
case '=':
case '<':
case '>':
case '~':
case '"':
case '\'':
case '.':
case EOZ:
default: {
if (isspace(ls->current)) {
lua_assert(!currIsNewline(ls));
next(ls);
continue;
}
else if (isdigit(ls->current)) {
read_numeral(ls, seminfo);
return TK_NUMBER;
}
else if (isalpha(ls->current) || ls->current == '_') {
/* identifier or reserved word */
TString *ts;
do {
save_and_next(ls);
} while (isalnum(ls->current) || ls->current == '_');
ts = luaX_newstring(ls, luaZ_buffer(ls->buff),
luaZ_bufflen(ls->buff));
if (ts->tsv.reserved > ) /* reserved word? */
return ts->tsv.reserved - + FIRST_RESERVED;
else {
seminfo->ts = ts;
return TK_NAME;
}
}
else {
int c = ls->current;
next(ls);
return c; /* single-char tokens (+ - / ...) */
}
}
}
}
luaX_newstring用于生成变量名,如果全局变量表中没有该变量的字符串,则会创建新的变量字符串。对每个token,如果是保留字段,都会预先加载在全局变量表中,因此,如果不是保留字段,就会生成TK_NAME。保留字段的判定来自于if (ts->tsv.reserved > 0),关于Token的种类,定义在llex.h头文件中。
获取token字符串后,进入chunk代码:
static void chunk (LexState *ls) {
/* chunk -> { stat [`;'] } */
int islast = ;
enterlevel(ls);//内嵌调用层数
while (!islast && !block_follow(ls->t.token)) {//当前token既不是block的开始也不是结束
islast = statement(ls);//代码语句分析
testnext(ls, ';');
lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&
ls->fs->freereg >= ls->fs->nactvar);
ls->fs->freereg = ls->fs->nactvar; /* free registers */
}
leavelevel(ls);
}
statement函数用于分析语义,里面是也是大大的switch...case...语句。如果是if, while, do, for, function等等关键字,都会进入相应的处理函数中,在default语句中处理赋值和函数调用的分析。
static int statement (LexState *ls) {
int line = ls->linenumber; /* may be needed for error messages */
switch (ls->t.token) {
case TK_IF: { /* stat -> ifstat */
ifstat(ls, line);
return ;
}
case TK_WHILE: { /* stat -> whilestat */
whilestat(ls, line);
return ;
}
case TK_DO: { /* stat -> DO block END */
luaX_next(ls); /* skip DO */
block(ls);
check_match(ls, TK_END, TK_DO, line);
return ;
}
case TK_FOR: { /* stat -> forstat */
forstat(ls, line);
return ;
}
case TK_REPEAT: { /* stat -> repeatstat */
repeatstat(ls, line);
return ;
}
case TK_FUNCTION: {
funcstat(ls, line); /* stat -> funcstat */
return ;
}
case TK_LOCAL: { /* stat -> localstat */
luaX_next(ls); /* skip LOCAL */
if (testnext(ls, TK_FUNCTION)) /* local function? */
localfunc(ls);
else
localstat(ls);
return ;
}
case TK_RETURN: { /* stat -> retstat */
retstat(ls);
return ; /* must be last statement */
}
case TK_BREAK: { /* stat -> breakstat */
luaX_next(ls); /* skip BREAK */
breakstat(ls);
return ; /* must be last statement */
}
default: {
exprstat(ls);
return ; /* to avoid warnings */
}
}
}
语句中的表达式通过exprstat(ls)函数处理,还有lua代码指令的生成,有时间再写。
<转>LUA语法分析的更多相关文章
- 【Lua篇】静态代码扫描分析(三)语法分析
一.语法分析 通过将词法分析获取的Token流按照目标语言的语法进行解析的过程,例如解析函数声明.函数调用.变量声明.各种语句等. 二.Lua语法分析 在写语法分析程序前,先需要了解Lua的语句和语法 ...
- lua函数随记
在大多数Lua语法分析中可以获得这些标准Lua函数. 无可争辩, 我们可以查阅Lua网站, 但是一些少了的函数被Blizzard进行了调整. 下面列出了所有Lua函数. WoW API中的Lua注意在 ...
- Lua函数[转]
在大多数Lua语法分析中可以获得这些标准Lua函数. 无可争辩, 我们可以查阅Lua网站, 但是一些少了的函数被Blizzard进行了调整. 下面列出了所有Lua函数. WoW API中的Lua注意在 ...
- lua源码学习篇二:语法分析
一步步调试,在lparser.c文件中luaY_parser函数是语法分析的重点函数,词法分析也是在这个过程中调用的.在这个过程中,用到一些数据结构,下面会详细说. Proto *luaY_parse ...
- C++混合编程之idlcpp教程Lua篇(5)
上一篇在这 C++混合编程之idlcpp教程Lua篇(4) 第一篇在这 C++混合编程之idlcpp教程(一) 与前面的工程相似,工程LuaTutorial3中,同样加入了三个文件:LuaTutori ...
- Lua 架构 The Lua Architecture
转载自:http://magicpanda.net/2010/10/lua%E6%9E%B6%E6%9E%84%E6%96%87%E6%A1%A3/ Lua架构文档(翻译) 十 102010 前段时间 ...
- Lua 解释器
Lua 解释器 警告⚠️:这将是一个又臭又长的系列教程,教程结束的时候,你将拥有一个除了性能差劲.扩展性差.标准库不完善之外,其他方面都和官方相差无几的 Lua 语言解释器.说白了,这个系列的教程实现 ...
- Lua学习系列(二)
资源整理: 风云老师博客: http://blog.codingnow.com/eo/luaoeeeaeau/ 知乎: https://www.zhihu.com/question/20736660 ...
- 深入浅出Lua虚拟机
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 作者:郑小辉 | 腾讯 游戏客户端开发高级工程师 写在前面:本文所有的文字都是我手工一个一个敲的,以及本文后面分享的Demo代码都是我一行一 ...
随机推荐
- asp.net使用jquery.form实现图片异步上传
首先我们需要做准备工作: jquery下载:http://files.cnblogs.com/tianguook/jquery1.8.rar jquery.form.js下载:http://files ...
- TextureView SurfaceView 简介 案例
简介 Android普通窗口的视图绘制机制是一层一层的,任何一个子元素或者是局部的刷新都会导致整个视图结构全部重绘一次,因此效率相对较低.视频或者opengl内容往往是显示在SurfaceView中的 ...
- SVN详细配置与使用 ——一步步教会您使用
项目管理在项目开发活动中起到非常重要的作用,而对于初学者来说学习有一定的难度,且不说如何使用,就是搭建过程恐怕也要费一般周折,介于此下面就通过图解的方式一步一步详细的教大家如何使用SVN,你只要耐心的 ...
- Linq-批量删除方法
linq中批量删除用DeleteAllOnSubmit,里面的参数是数据集 传入某要删除的ID列表,使用对象的Contains方法与数据库中值比较,相同就删除. //批量删除 public void ...
- 在centos7.4上安装mysql5.5
from: https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-centos-7
- Win10系统80端口被系统进程占用
一.问题 有系统需要用到80端口,为了方便,但是发现80端口被占用,执行netstat -ano 发现80端口竟然被一个System process占用了,当然这个是不能被杀掉的 二.解决问题 在网上 ...
- (转)Unity3D研究院之手游开发中所有特殊的文件夹(assetbundle与Application.persistentDataPath)
这里列举出手游开发中用到了所有特殊文件夹. 1.Editor Editor文件夹可以在根目录下,也可以在子目录里,只要名子叫Editor就可以.比如目录:/xxx/xxx/Editor 和 /Edi ...
- VS2013第一个应用boost的程序
下载boost binary https://sourceforge.net/projects/boost/files/boost-binaries/1.67.0_b1/ 由于我用的是Windows1 ...
- Sublime 3156 LICENSE key
mac sublime3 3156 LICENSE 转自:http://blog.csdn.net/myboyliu2007/article/details/78748253 下载地址:https:/ ...
- 无法ping通自身
今日,ping localhost 超时,ping 127.0.0.1 显示一般故障.无法访问自己电脑上的tomcat.... 居然,居然是防火墙打开了,关了就好了.我勒个去!!!!