上 构建Lua解释器Part7:构建完整的语法分析器( 八 )

<<' and '>>'358{9,8},// '..' right associative359{3,3}, {3,3}, {3,3}, {3,3}, {3,3}, {3,3}, // '>', '<', '>=', '<=', '==', '~=',360{2,2}, {1,1},// 'and' and 'or'361 };362 363 static int subexpr(FuncState* fs, expdesc* e, int limit) {364LexState* ls = fs->ls;365int unopr = getunopr(ls);366 367if (unopr != NOUNOPR) {368luaX_next(fs->ls->L, fs->ls);369subexpr(fs, e, UNOPR_PRIORITY);370luaK_prefix(fs, unopr, e);371}372else simpleexp(fs, e);373 374int binopr = getbinopr(ls);375while (binopr != NOBINOPR && priority[binopr].left > limit) {376expdesc e2;377init_exp(&e2, VVOID, 0);378 379luaX_next(ls->L, ls);380luaK_infix(fs, binopr, e);381int nextop = subexpr(fs, &e2, priority[binopr].right);382luaK_posfix(fs, binopr, e, &e2);383 384binopr = nextop;385}386 387return binopr;388 }389 390 static void expr(FuncState* fs, expdesc* e) {391subexpr(fs, e, 0);392 }
代码片段5
我们先从最简单的情况开始讨论 , 先从一张图来大致看一下expr到底做了什么事情:
图11
如图11所示 , expr函数 , 会将我们输入的token , 转化为一个被称之为结构变量的信息之中 , 在完成转化之后 , 我们获取下一个token 。实际上expr可能会处理多个token , 一般在单目运算或者是双目运算的expr里 , 目前我们只来看最简单的情况–只对单个token进行处理的情况 。
实际上 , 并非所有的token都能够被expr函数转化为的信息的 , 只有那些是exp的token才行 , 这些token都被定义在了EBNF范式中的里 , 他们是、、、、、、、’{}‘、等 , 除了 , 其他都能在lua中找到对应的基本类型(因为表示变量 , 可以存储任意一种基本类型的值) 。这些是输入信息的部分 , 现在我们来看一下经过expr转化 , 得到的数据结构是怎样的 , 以下是它的定义:
// luaparser.h// 表达式(exp)的类型typedef enum expkind {VVOID,// 表达式是空的 , 也就是voidVNIL,// 表达式是nil类型VFLT,// 表达式是浮点类型VINT,// 表达式是整型类型VTRUE,// 表达式是TRUEVFALSE,// 表达式是FALSEVINDEXED,// 表示索引类型 , 当exp是这种类型时 , expdesc的ind域被使用VCALL,// 表达式是函数调用 , expdesc中的info字段 , 表示的是instruction pc// 也就是它指向Proto code列表的哪个指令VLOCAL,// 表达式是local变量 , expdesc的info字段 , 表示该local变量 , 在栈中的位置VUPVAL,// 表达式是Upvalue , expdesc的info字段 , 表示Upvalue数组的索引VK,// 表达式是常量类型 , expdesc的info字段表示 , 这个常量是常量表k中的哪个值VRELOCATE,// 表达式可以把结果放到任意的寄存器上 , expdesc的info表示的是instruction pcVNONRELOC,// 表达式已经在某个寄存器上了 , expdesc的info字段 , 表示该寄存器的位置} expkind;// exp临时存储结构typedef struct expdesc {expkind k;// expkindunion {int info;lua_Integer i;// for VINTlua_Number r;// for VFLTstruct {int t;// 表示table或者是UpVal的索引int vt;// 标识上一个字段't'是upvalue(VUPVAL) 还是 table(VLOCAL)int idx;// 常量表k或者是寄存器的索引 , 这个索引指向的值就是被取出值得key// 不论t是Upvalue还是table的索引 , 它取出的值一般是一个table} ind;} u;} expdesc;
我们现在通过一个表格 , 来看一下这些exp是如何转化成结构变量的:
e->k=VFLT
e->u.r =
e->k=VINT
e->u.i =
e->k=VK
e-> = (常量表k的索引值)
e->k=VNIL
e->k=VTRUE
e->k=