本章我们来看table的基本操作
1. 一个简单的例子
local a = {1,2,3}
a[6] = 1
a["aaa"]= 1
1.1 执行我们的例子
gafq test/hello.gafq
1.有了上一节的基础我们直接来到词法分析处
//gparser.c
// 解释器,解释文件内容
Proto *gafqY_parser(gafq_State *L, ZIO *z, Mbuffer *buff, const char *name)
{
struct LexState lexstate;
struct FuncState funcstate;
gafqX_next(&lexstate); // 读取第一个token
}
2.词法分析
glex.c
void gafqX_next(LexState *ls)
{
...
ls->t.token = glex(ls, &ls->t.seminfo); 读取下一个token
...
}
// 读取下一个token, 词法分析 SemInfo是语义信息
static int glex(LexState *ls, SemInfo *seminfo)
{
gafqZ_resetbuffer(ls->buff);
for (;;)
{
switch (ls->current)// 首先我们的例子第一个字节是local中的l 这里ls_current = 108 就是l的ascii码
{
default:
{
// 判断是字母
if (isalpha(ls->current) || ls->current == '_')
{
TString *ts;
// 循环如果接下去的字符是数字,字符或者下划线就不断读取
do
{
save_and_next(ls);
} while (isalnum(ls->current) || ls->current == '_');
// 前面的读取操作,到这里,我们的ls->buff 等于 local
ts = gafqX_newstring(ls, gafqZ_buffer(ls->buff), gafqZ_bufflen(ls->buff));
if (ts->tsv.reserved > 0) // 这里得到的字符串ts 的值是12, 认为这是一个关键字
return ts->tsv.reserved - 1 + FIRST_RESERVED;
}
}
}
}
}
3.回到1中,读取了第一个token是local 12, 开始解析整个文件chunk
// 解释器,解释文件内容
3.1 Proto *gafqY_parser(gafq_State *L, ZIO *z, Mbuffer *buff, const char *name)
{
...
gafqX_next(&lexstate);
chunk(&lexstate);
...
}
// 这里是解析代码块?
3.2 static void chunk(LexState *ls)
{
-- 不是结尾就不断解析
while (!islast && !block_follow(ls->t.token))
{
islast = statement(ls);
}
}
// 判断当前的token, 根据token获取接下去解析的规则?
3.3 static int statement(LexState *ls)
{
switch (ls->t.token)
{
case TK_LOCAL:
{
gafqX_next(ls); // 跳过local的token
localstat(ls);
return 0;
}
}
}
3.4 static void localstat(LexState *ls)
{
...
if (testnext(ls, '=')) // 跳过 61 '='
nexps = explist1(ls, &e); // 准备解析 = 后面的东西
...
}
//解析参数列表?, 变量的值
3.5 static int explist1(LexState *ls, expdesc *v)
{
...
expr(ls, v); // 285(TK_NAME)
while (testnext(ls, ','))
{
gafqK_exp2nextreg(ls->fs, v);
expr(ls, v);
n++;
}
return n;
}
3.6 static BinOpr subexpr(LexState *ls, expdesc *v, unsigned int limit)
{
uop = getunopr(ls->t.token); // 这里现在token是123
simpleexp(ls, v); // 认为后面是简单类型
}
3.7 static void simpleexp(LexState *ls, expdesc *v)
{
switch (ls->t.token) // token = 123
{
case '{':
{
constructor(ls, v);
return;
}
}
// 这里解析{ 之后的东西, 认为是个table
3.8 static void constructor(LexState *ls, expdesc *t)
{
checknext(ls, '{');
do
{
gafq_assert(cc.v.k == VVOID || cc.tostore > 0);
if (ls->t.token == '}')
break;
switch (ls->t.token) // 接下去是个数字 token = 284
{
default:
{
listfield(ls, &cc);
break;
}
}
} while (testnext(ls, ',') || testnext(ls, ';'));
}
3.9 static void listfield(LexState *ls, struct ConsControl *cc)
{
expr(ls, &cc->v);
}
3.10 static BinOpr subexpr(LexState *ls, expdesc *v, unsigned int limit)
{
...
simpleexp(ls, v);
...
}
//简单类型, 数字 | 字符串 | nil | 对 | 错 | ... | { | 函数体 |
3.11 static void simpleexp(LexState *ls, expdesc *v)
{
switch (ls->t.token) // token = 284
{
case TK_NUMBER:
{
init_exp(v, VKNUM, 0);
v->u.nval = ls->t.seminfo.r;
break;
}
}
gafqX_next(ls); // 之后token = 44
}
// 回到了3.18的地方
3.12 // 这里解析{ 之后的东西, 认为是个table
static void constructor(LexState *ls, expdesc *t)
{
checknext(ls, '{');
do
{
gafq_assert(cc.v.k == VVOID || cc.tostore > 0);
if (ls->t.token == '}')
break;
closelistfield(fs, &cc);
switch (ls->t.token)
{
case TK_NAME:
{ /* may be listfields or recfields */
gafqX_lookahead(ls);
if (ls->lookahead.token != '=') /* expression? */
listfield(ls, &cc);
else
recfield(ls, &cc);
break;
}
case '[':
{ /* constructor_item -> recfield */
recfield(ls, &cc);
break;
}
default:
{ /* constructor_part -> listfield */
listfield(ls, &cc);
break;
}
}
} while (testnext(ls, ',') || testnext(ls, ';'));// 遇到,或者;就跳过
}
3.13 一路解析完回到了3.2的地方 开始解析 例子 a[6] = 1
static void chunk(LexState *ls)
{
while (!islast && !block_follow(ls->t.token))
{
islast = statement(ls); // 现在的token是新的一样 token=285 TK_NAME
testnext(ls, ';');
}
}
// 3.14
static int statement(LexState *ls)
{
switch (ls->t.token) // token=285 TK_NAME
{
default:
{
exprstat(ls);
return 0;
}
}
}
// 3.15 表达式解析
static void exprstat(LexState *ls)
{
...
primaryexp(ls, &v.v);
...
}
// 3.16 表达式解析
static void primaryexp(LexState *ls, expdesc *v)
{
prefixexp(ls, v);
}
// 3.17 解析 变量名 或者是()
static void prefixexp(LexState *ls, expdesc *v)
{
switch (ls->t.token)
{
case TK_NAME:
{
singlevar(ls, v);
return;
}
}
}
// 3.18 简单的变量名
static void singlevar(LexState *ls, expdesc *var)
{
TString *varname = str_checkname(ls); // 检查是TK_NAME就跳下一个
}
// 3.19 回到 3.16的地方
// 表达式解析
static void primaryexp(LexState *ls, expdesc *v)
{
prefixexp(ls, v);
for (;;)
{
switch (ls->t.token) 现在tokens是91
{
case '[':
{ /* `[' exp1 `]' */
expdesc key;
yindex(ls, &key);
}
}
}
// 3.20 解析a[6] 中[]中间的表达式
static void yindex(LexState *ls, expdesc *v)
{
gafqX_next(ls);
expr(ls, v); // 解析出里面的表达是 284(TK_NUMBER)
gafqK_exp2val(ls->fs, v);
checknext(ls, ']');
}
// 3.21 回到3.15的地方,开始解析 a[6] 后面的东西
static void exprstat(LexState *ls)
{
...
primaryexp(ls, &v.v);
...
assignment(ls, &v, 1); //到这里token等于61
}
//3.22 从exprstat来, 这里是计算变量赋值表达式
static void assignment(LexState *ls, struct LHS_assign *lh, int nvars)
{
expdesc e;
int nexps;
checknext(ls, '=');
nexps = explist1(ls, &e);
}
}
//3.23 解析参数列表?, 变量的值
static int explist1(LexState *ls, expdesc *v)
{
expr(ls, v);
return n;
}
3.24 一路解析完回到了3.2的地方 开始解析 例子a["aaa"]= 1
static void chunk(LexState *ls)
{
while (!islast && !block_follow(ls->t.token))
{
islast = statement(ls); // 现在的token是新的一样 token=285 TK_NAME
testnext(ls, ';');
}
}
//3.25
static int statement(LexState *ls)
{
switch (ls->t.token)
{
default:
{
exprstat(ls);
}
}
}
//3.26
static void exprstat(LexState *ls)
{
primaryexp(ls, &v.v); // 解析 a["aaa"] 部分
assignment(ls, &v, 1); // 解析 = 1部分
}
4.解析出的token是什么
// 我们的例子
local a = {1,2,3}
a[6] = 1
a["aaa"]= 1
268(TK_LOCAL) -> 285(TK_NAME) -> 61('=') -> 123('{') -> 284(TK_NUMBER) -> 44(',') -> 284(TK_NUMBER) -> 44(',') -> 284(TK_NUMBER) -> 125('}')
285(TK_NAME) -> 91('[') -> 284(TK_NUMBER) -> 93(']') -> 61('=') -> 284(TK_NUMBER)
285(TK_NAME) -> 91('[') -> 286(TK_STRING) -> 93(']') -> 61('=') -> 284(TK_NUMBER)