Golang入门指南


  • 首页

  • todo

  • 思考

  • life

  • food

  • OS

  • lua

  • redis

  • Golang

  • C

  • TCP/IP

  • ebpf

  • p4

  • OpenVPN

  • IPSec

  • L2TP

  • DNS

  • distributed

  • web

  • OpenWRT

  • 运维

  • Git

  • 鸟哥的私房菜

  • IT杂谈

  • 投资

  • About Me

  • 友情链接

  • FTP

  • 搜索
close

亿级系统的Redis缓存如何设计???

时间: 2021-07-05   |   分类: 分布式   cs   redis   distributed     |   阅读: 2795 字 ~6分钟

亿级系统的Redis缓存如何设计???

以下文章来源于微观技术 ,作者TomGE

缓存设计可谓老生常谈了,早些时候都是采用memcache,现在大家更多倾向使用redis,除了知晓常用的数据存储类型,结合业务场景有针对性选择,好像其他也没有什么大的难点。

阅读全文 »

lua51 Instructions Commment

时间: 2021-07-01   |   分类: lua     |   阅读: 552 字 ~2分钟
typedef enum {
/*----------------------------------------------------------------------
name		args	description
------------------------------------------------------------------------*/
OP_MOVE,		/*	A B		R(A) := R(B)						*/
OP_LOADK,		/*	A Bx	R(A) := Kst(Bx)						*/
OP_LOADBOOL,		/*	A B C	R(A) := (Bool)B; if (C) pc++		*/
OP_LOADNIL,		/*	A B		R(A) := ... := R(B) := nil			*/
OP_GETUPVAL,		/*	A B		R(A) := UpValue[B]					*/

OP_GETGLOBAL,		/*	A Bx	R(A) := Gbl[Kst(Bx)]				*/
OP_GETTABLE,		/*	A B C	R(A) := R(B)[RK(C)]					*/

OP_SETGLOBAL,		/*	A Bx	Gbl[Kst(Bx)] := R(A)				*/
OP_SETUPVAL,		/*	A B		UpValue[B] := R(A)					*/
OP_SETTABLE,		/*	A B C	R(A)[RK(B)] := RK(C)				*/

OP_NEWTABLE,		/*	A B C	R(A) := {} (size = B,C)				*/

OP_SELF,		/*	A B C	R(A+1) := R(B); R(A) := R(B)[RK(C)]	*/

OP_ADD,			/*	A B C	R(A) := RK(B) + RK(C)				*/
OP_SUB,			/*	A B C	R(A) := RK(B) - RK(C)				*/
OP_MUL,			/*	A B C	R(A) := RK(B) * RK(C)				*/
OP_DIV,			/*	A B C	R(A) := RK(B) / RK(C)				*/
OP_MOD,			/*	A B C	R(A) := RK(B) % RK(C)				*/
OP_POW,			/*	A B C	R(A) := RK(B) ^ RK(C)				*/
OP_UNM,			/*	A B		R(A) := -R(B)						*/
OP_NOT,			/*	A B		R(A) := not R(B)					*/
OP_LEN,			/*	A B		R(A) := length of R(B)				*/

OP_CONCAT,		/*	A B C	R(A) := R(B).. ... ..R(C)			*/

OP_JMP,			/*	sBx		pc+=sBx								*/

OP_EQ,			/*	A B C	if ((RK(B) == RK(C)) ~= A) then pc++*/
OP_LT,			/*	A B C	if ((RK(B) <  RK(C)) ~= A) then pc++*/
OP_LE,			/*	A B C	if ((RK(B) <= RK(C)) ~= A) then pc++*/

/* !!!! <=>:用bool值做相等性比较,而不是判断不相等 */
OP_TEST,		/*	A C		if not (R(A) <=> C) then pc++		*/ 
OP_TESTSET,		/*	A B C	if (R(B) <=> C) then R(A) := R(B) else pc++	*/ 

/* 
** B=1表示没有传入参数,2:传入一个参数,0:传入了不定参数 
** C=1:期待没有返回值,2:期待一个返回值,0:期待不定数量返回值
*/
OP_CALL,		/*	A B C	R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */

OP_TAILCALL,		/*	A B C	return R(A)(R(A+1), ... ,R(A+B-1))		*/

/* B=1:无返回值,2:一个返回值,0:不定数量返回值 */
OP_RETURN,		/*	A B		return R(A), ... ,R(A+B-2)	(see note)	*/

OP_FORLOOP,		/*	A sBx	R(A)+=R(A+2);
								if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
OP_FORPREP,		/*	A sBx	R(A)-=R(A+2); pc+=sBx				*/

OP_TFORLOOP,		/*	A C	R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); 
                        		if R(A+3) ~= nil then R(A+2)=R(A+3) else pc++	*/ 
OP_SETLIST,		/*	A B C	R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B	*/

OP_CLOSE,		/*	A 		close all variables in the stack up to (>=) R(A)*/
OP_CLOSURE,		/*	A Bx	R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n))	*/

OP_VARARG		/*	A B		R(A), R(A+1), ..., R(A+B-1) = vararg		*/
} OpCode;

哈希表

时间: 2021-06-26   |   分类: algorithm     |   阅读: 1227 字 ~3分钟

哈希表

什么是哈希表

哈希表就是一个元素有一一对应位置的一个表,如下图,哈希表也叫散列表,和函数的一个x对应一个y类似,不存在多个y对应一个x,当然哈希表可能有多个数对应一个下标,我们后面讲,这里暂且理解为和函数一样,是一种映射。 在图中,哈希表存的数据位整形,如果我们存手机号,可以将后四位作为key,或者是后四位经过一个算数处理,当作key也可以。

阅读全文 »

如何避免Go变量被GC

时间: 2021-06-15   |   分类: go     |   阅读: 984 字 ~2分钟

img

Illustration created for “A Journey With Go”, made from the original Go Gopher, created by Renee French.

本文基于 Go 1.13。

在 Go 中,我们不需要自己管理内存分配和释放。然而,有些时候我们需要对程序进行更细粒度的控制。Go 运行时提供了很多种控制运行时状态及其与内存管理器之间相互影响的方式。本文中,我们来审查让变量不被 GC 回收的能力。

阅读全文 »

分布式锁实现原理与最佳实践

时间: 2021-06-15   |   分类: 分布式   cs   面试     |   阅读: 2224 字 ~5分钟

分布式锁实现原理与最佳实践

分布式锁应用场景

很多应用场景是需要系统保证幂等性的(如api服务或消息消费者),并发情况下或消息重复很容易造成系统重入,那么分布式锁是保障幂等的一个重要手段。

阅读全文 »

lua源码注释lcode.c

时间: 2021-06-08   |   分类: lua     |   阅读: 6252 字 ~13分钟
/*
** $Id: lcode.c,v 2.25.1.5 2011/01/31 14:53:16 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/


#include <stdlib.h>

#include <stdio.h>

#define lcode_c
#define LUA_CORE

#include "lua.h"

#include "lcode.h"
#include "ldebug.h"
#include "ldo.h"
#include "lgc.h"
#include "llex.h"
#include "lmem.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lparser.h"
#include "ltable.h"

/* e的类型 expdesc */
#define hasjumps(e)	((e)->t != (e)->f)


static int isnumeral(expdesc *e) {
  return (e->k == VKNUM &&	/* 仅仅e->k == VKNUM 不够么? */
		  	e->t == NO_JUMP &&
		  	e->f == NO_JUMP);
}

/* 给连续的变量赋nil
** OP_LOADNIL A B R(A) := ... := R(B) := nil
** 当可以合并前一条OP_LOADNIL时则尝试合并,可以利用fun'stack的默认NIL时,直接用NIL
*/
void luaK_nil (FuncState *fs, int from, int n) {
  Instruction *previous;
  if (fs->pc > fs->lasttarget) {  /* no jumps to current position? */
    if (fs->pc == 0) {  /* function start? */
      if (from >= fs->nactvar)  /* 新调用一个fun时,其私有stack默认会被置NULL,这种情况直接使用默认的NULL即可 */
        return;  /* positions are already clean */
    }
    else {
      previous = &fs->f->code[fs->pc-1];
      if (GET_OPCODE(*previous) == OP_LOADNIL) {	/* 尝试合并前后连续的OP_LOADNIL指令 */
        int pfrom = GETARG_A(*previous);
        int pto = GETARG_B(*previous);
        if (pfrom <= from && from <= pto+1) {  /* can connect both? */
          if (from+n-1 > pto)
            SETARG_B(*previous, from+n-1);
          return;
        }
      }
    }
  }
  luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0);  /* else no optimization */
}

/* 
** OP_JMP sBx PC += sBx
**
** 待回填的跳转链表指向我,而我又指向其它pc,那么将上述链表和我串联在一起即可
*/
int luaK_jump (FuncState *fs) {
  int jpc = fs->jpc;  /* save list of jumps to here */
  int j;
  fs->jpc = NO_JUMP;
  j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
  luaK_concat(fs, &j, jpc);  /* keep them on hold */
  return j;
}

/* 从函数返回
** OP_RETURN A B return R(A), ... ,R(A+B-2)
*/
void luaK_ret (FuncState *fs, int first, int nret) {
  luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);	/* 这里可以反推OP_RETURNS中A,B,C的含义了 */
}

/* 有条件跳转 OP_TEST, OP_TESTSET */
static int condjump (FuncState *fs, OpCode op, int A, int B, int C) {
  luaK_codeABC(fs, op, A, B, C);
  return luaK_jump(fs);
}

/* 将待回填的跳转指令pc指向dest */
static void fixjump (FuncState *fs, int pc, int dest) {
  Instruction *jmp = &fs->f->code[pc];
  /* 下面计算跳转指令的跳转目标绝对值时也加了1,和这里是一致的 */
  int offset = dest-(pc+1);		
  lua_assert(dest != NO_JUMP);
  if (abs(offset) > MAXARG_sBx)
    luaX_syntaxerror(fs->ls, "control structure too long");
  SETARG_sBx(*jmp, offset);
}


/*
** returns current `pc' and marks it as a jump target (to avoid wrong
** optimizations(优化) with consecutive(连续) instructions not in the same basic block).
*/
int luaK_getlabel (FuncState *fs) {
  fs->lasttarget = fs->pc;
  return fs->pc;
}

/* 获取跳转指令指向的绝对位置 */
static int getjump (FuncState *fs, int pc) {
  int offset = GETARG_sBx(fs->f->code[pc]);
  if (offset == NO_JUMP)  /* point to itself represents end of list */
    return NO_JUMP;  /* end of list */
  else
    return (pc+1)+offset;  /* turn offset into absolute position */
}


static Instruction *getjumpcontrol (FuncState *fs, int pc) {
  Instruction *pi = &fs->f->code[pc];
  if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))
    return pi-1;
  else
    return pi;
}


/*
** check whether list has any jump that do not produce a value
** (or produce an inverted(颠,倒) value)
*/
static int need_value (FuncState *fs, int list) {
  for (; list != NO_JUMP; list = getjump(fs, list)) {
    Instruction i = *getjumpcontrol(fs, list);
    if (GET_OPCODE(i) != OP_TESTSET) return 1;
  }
  return 0;  /* not found */
}


static int patchtestreg (FuncState *fs, int node, int reg) {
  Instruction *i = getjumpcontrol(fs, node);
  if (GET_OPCODE(*i) != OP_TESTSET)
    return 0;  /* cannot patch other instructions */
  if (reg != NO_REG && reg != GETARG_B(*i))
    SETARG_A(*i, reg);
  else  /* no register to put value or register already has the value */
    *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));

  return 1;
}


static void removevalues (FuncState *fs, int list) {
  for (; list != NO_JUMP; list = getjump(fs, list))
      patchtestreg(fs, list, NO_REG);
}

/* 
** 回填跳转指令链表上的指令到指定目标
**
** 将待回填跳转指令列表list上指令的跳转参数sBx更新到target上 
*/
static void patchlistaux (FuncState *fs, int list, int vtarget, int reg,
                          int dtarget) {
  while (list != NO_JUMP) {
    int next = getjump(fs, list);
    if (patchtestreg(fs, list, reg))
      fixjump(fs, list, vtarget);
    else
      fixjump(fs, list, dtarget);  /* jump to default target */
    list = next;
  }
}

/* 将待回填的跳转到当前指令的跳转链表上的跳转指令的sBx更新为fs->pc */
static void dischargejpc (FuncState *fs) {
  patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
  fs->jpc = NO_JUMP;	/* 置空 */
}


void luaK_patchlist (FuncState *fs, int list, int target) {
  if (target == fs->pc)
    luaK_patchtohere(fs, list);
  else {
    lua_assert(target < fs->pc);
    patchlistaux(fs, list, target, NO_REG, target);
  }
}

/* 将待回填的跳转指令链表list挂到fs->jpc,等生成下一条指令时回填sBx */
void luaK_patchtohere (FuncState *fs, int list) {
  luaK_getlabel(fs);
  luaK_concat(fs, &fs->jpc, list);
}

/*  l1.sBx = l2 
** 将l2指向的待回填跳转指令/指令链表挂到l1的跳转链表上
*/
void luaK_concat (FuncState *fs, int *l1, int l2) {
  if (l2 == NO_JUMP) /* l2不是一条跳转指令,直接返回 */
  	return;
  else if (*l1 == NO_JUMP)	/* 当前跳转列表为空 */
    *l1 = l2;	/* l1尚未初始化,直接赋值即可 */
  else {
    int list = *l1;
    int next;
    while ((next = getjump(fs, list)) != NO_JUMP)  /* find last element */
      list = next;
    fixjump(fs, list, l2);	/* 将待回填的跳转指令链表l2挂到l1的末尾 */
  }
}

/* 调整maxstacksize以便匹配locvar的数量 */
void luaK_checkstack (FuncState *fs, int n) {
  int newstack = fs->freereg + n;
  if (newstack > fs->f->maxstacksize) {	/* 这个判断是必须的 */
    if (newstack >= MAXSTACK)
      luaX_syntaxerror(fs->ls, "function or expression too complex");
    fs->f->maxstacksize = cast_byte(newstack);
  }
}

/* reserve reg:预定 寄存器 实际上是占用n个寄存器的意思
*/
void luaK_reserveregs (FuncState *fs, int n) {
  luaK_checkstack(fs, n);
  fs->freereg += n;	/* 占用n个locvar,释放则n为负值或在其它函数中实现 */
}

/* 重点函数,需要细读 */
static void freereg (FuncState *fs, int reg) {
  if (!ISK(reg) &&            /* 常量的就不用释放了,压根没占用reg */
      reg >= fs->nactvar) {   /* reg从0开始,nactvar从1开始,所以这里reg>=fs->nactvar是可以的
      
  	/* 释放一个reg后,reg==fs->freereg:确保只能释放最新一个被激活的reg(作为exp的临时reg占用?) */
    fs->freereg--;
    lua_assert(reg == fs->freereg);
  }
}

/* 释放被临时占用的reg */
static void freeexp (FuncState *fs, expdesc *e) {
  if (e->k == VNONRELOC)		/* 表达式的值已被CP_XXX到reg中的,才释放 (还没加载到reg,那压根没占用reg,释放个锤子*/
    freereg(fs, e->u.s.info);	/* VNONRELOC info = result register */ 
}

/*
** 将常量加载到fs->f的常量表中
**
** local var = "hello
" 则本函数的k,v="hello" 
*/
static int addk (FuncState *fs, TValue *k, TValue *v) {
  lua_State *L = fs->L;
  TValue *idx = luaH_set(L, fs->h, k);
  Proto *f = fs->f;
  int oldsize = f->sizek;
  if (ttisnumber(idx)) {
    lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v));	
    return cast_int(nvalue(idx));
  }
  else {  /* constant not found; create a new entry */
    setnvalue(idx, cast_num(fs->nk));
    luaM_growvector(L, f->k, fs->nk, f->sizek, TValue,
                    MAXARG_Bx, "constant table overflow");
    while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
    setobj(L, &f->k[fs->nk], v);
    luaC_barrier(L, f, v);
    return fs->nk++;
  }
}

/* 将字符串常量加载到fs->f的常量表中 */
int luaK_stringK (FuncState *fs, TString *s) {
  TValue o;
  setsvalue(fs->L, &o, s);
  return addk(fs, &o, &o);
}


int luaK_numberK (FuncState *fs, lua_Number r) {
  TValue o;
  setnvalue(&o, r);
  return addk(fs, &o, &o);
}


static int boolK (FuncState *fs, int b) {
  TValue o;
  setbvalue(&o, b);
  return addk(fs, &o, &o);
}


static int nilK (FuncState *fs) {
  TValue k, v;
  setnilvalue(&v);
  /* cannot use nil as key; instead use table itself to represent nil */
  sethvalue(fs->L, &k, fs->h);
  return addk(fs, &k, &v);
}

/* nresults:-1, C=0,表示希望返回变参
** nresults: 0, C=1, 表示希望返回0个参数
** nresults: 2, C=2, 表示希望返回1个参数
*/
void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
  /* OP_CALL A B C 		R(A), … ,R(A+C-2) := R(A)(R(A+1), … ,R(A+B-1)) */
  if (e->k == VCALL) {  /* expression is an open function call? */
    SETARG_C(getcode(fs, e), nresults+1);
  }
  else if (e->k == VVARARG) {
  	/* OP_VARARG A B 	R(A), R(A+1), ..., R(A+B-1) = vararg 
  	** 将变参拷贝到RA指定的寄存器开始的地方,拷贝B个元素,这里仅使用了一个寄存器的编码?
  	*/
    SETARG_B(getcode(fs, e), nresults+1);
    SETARG_A(getcode(fs, e), fs->freereg);
    luaK_reserveregs(fs, 1);
  }
}

/* 对于可能返回变参的表达式,强制其仅返回一个值 */
void luaK_setoneret (FuncState *fs, expdesc *e) {
  if (e->k == VCALL) {  /* expression is an open function call? */
  	/* A B C R(A), … ,R(A+C-2) := R(A)(R(A+1), … ,R(A+B-1)) */
  
  	/* 函数调用返回的第一个值占用的reg就是函数指针本身占用的reg,
  	** 不能返回到其它地方,故而这里是VNONRELOC
  	*/
    e->k = VNONRELOC;	
    e->u.s.info = GETARG_A(getcode(fs, e));
  }
  else if (e->k == VVARARG) {
    SETARG_B(getcode(fs, e), 2);	/* 2:期待返回一个返回值 */
    e->k = VRELOCABLE;  /* can relocate its simple result */
  }
}

/* 生成LOAD_XXX(加载)系列指令,(为后续加载间接表达式的值到reg做准备)
**
** 对需间接读取src.val的表达式生成对应的读值指令(eg:OP_GETTABLE),以便下一步的dst=src
**
** 需要间接求表达式src.val的:
** 生成求表达式src.val的指令
** e->u.s.info---->pc.addr方便后面确定dst后进行指令回填
** e.k        ---->VNONRELOC 表达式的src.val对应读值指令已生成,但不在reg中
**
** 表达式的src.val已经在reg中的
** src.val已在reg中的表达式(VLOCAL,VCALL)
**   e.k      ----> e.k=VNONRELOC
** 
** 表达式的src.val是直接值的
** src.val是直接值的表达式,无需处理
** 
** discharge:释放
*/
void luaK_dischargevars (FuncState *fs, expdesc *e) {
  switch (e->k) {
    case VLOCAL: {	/* exp.src已在reg中,故而这里是VNONRELOC */
      e->k = VNONRELOC;
      break;
    }
    case VUPVAL: {
      e->u.s.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.s.info, 0);
      e->k = VRELOCABLE;
      break;
    }
    case VGLOBAL: {
      e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info);
      e->k = VRELOCABLE;
      break;
    }
    case VINDEXED: {	/* OP_GETTABLE A B C R(A) := R(B)[RK(C)] */
	  /* !!这里是依次释放的
	  ** a.b.c.d.e... 释放a.b.c.d之前占用的reg,以便重利用reg
	  */
      freereg(fs, e->u.s.aux);
      freereg(fs, e->u.s.info);
	
	  /* A填 0,配合下面的可重定位VRELOCALBLE */
      e->u.s.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.s.info, e->u.s.aux);
      e->k = VRELOCABLE;
      break;
    }
    case VVARARG:
    case VCALL: {
      luaK_setoneret(fs, e);
      break;
    }
	
	/* !!!!常量,常量,常量 不需要用到reg,无需更新reg的信息e->k了 */
	case VNIL:
	case VTRUE:
	case VFALSE:
	case VKNUM:
	case VK: {
		break;
	}
	
	/* 还没遇到过,不太理解 */
	case VJMP:
		break;
			
	/* e->k已经确定了寄存器的信息了,直接返回 */
	case VRELOCABLE:
	case VNONRELOC:
		break;
	
    default:
      break;  /* there is one value available (somewhere) */
  }
}


static int code_label (FuncState *fs, int A, int b, int jump) {
  luaK_getlabel(fs);  /* those instructions may be jump targets */
  return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
}

/* 
** CP_XXX拷贝指令
**
** 拷贝表达式的值到指定的目的寄存器(reg(dst) = exp(src)

** step.1 生成表达式的src.val的加载指令(R(B))
** step.2 回填表达式的目标寄存器(RA),对VNONRELOC的则生成MV指令
**
** 参考init_exp 和 luaK_dischargevars函数来理解本函数
*/
static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
  /* 
  ** step1. 对"间接表达式"生成求值指令 
  */
  luaK_dischargevars(fs, e);
  
  /*
  ** step2. 对"直接表达式"生成求值指令
  ** 
  ** step3. 对"上述表达式"进行回填处理(确定目标寄存器(R(A)))
  */
  switch (e->k) {
  	/* 表达式的值是常值, 这里生成指令并回填R(A) */
    case VNIL: {
      luaK_nil(fs, reg, 1);
      break;
    }
    case VFALSE:  case VTRUE: {
      luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
      break;
    }
	
	/* 表达式的值在e->u.s.info:常量表中,这里提出来,生成指令并回填R(A)                       */
    case VK: {
	  /* reg:指令的目标寄存器RA, e->u.s.info:指令中常量exp在常量表中的索引 */
      luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info);
      break;
    }
	/* 同上VK,只是nval在常量中的索引延迟到这里确定 */
    case VKNUM: {
      luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval));
      break;
    }
	
	/* 指令,表达式的值都已确定,这里回填指令的目的地R(A)即可 */
    case VRELOCABLE: {
      Instruction *pc = &getcode(fs, e);
      SETARG_A(*pc, reg);
      break;
    }
	/* 表达式的值已确定,生成OP_MOVE指令,回填R(A)=R(B)中的即可 */
    case VNONRELOC: {
      if (reg != e->u.s.info)
        luaK_codeABC(fs, OP_MOVE, reg, e->u.s.info, 0);
      break;
    }
	/* VJMP尚不理解 */
    default: {
      lua_assert(e->k == VVOID || e->k == VJMP);
      return;  /* nothing to do... */
    }
  }
  
  /* 表达式的目的寄存器R(A)已确定 */
  e->u.s.info = reg;
  e->k = VNONRELOC;
}

static void discharge2anyreg (FuncState *fs, expdesc *e) {
  if (e->k != VNONRELOC) {
    luaK_reserveregs(fs, 1);
    discharge2reg(fs, e, fs->freereg-1);
  }
}

/* dst=src CP_XXX指令,将表达式的值赋值给指定的寄存器reg */
static void exp2reg (FuncState *fs, expdesc *e, int reg) {
  /* 将表达式的src.val赋值给dst(reg) */
  discharge2reg(fs, e, reg);
  
  if (e->k == VJMP)
    luaK_concat(fs, &e->t, e->u.s.info);  /* put this jump in `t' list */
  if (hasjumps(e)) {
    int final;  /* position after whole expression */
    int p_f = NO_JUMP;  /* position of an eventual LOAD false */
    int p_t = NO_JUMP;  /* position of an eventual LOAD true */
    if (need_value(fs, e->t) || need_value(fs, e->f)) {
      int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
      p_f = code_label(fs, reg, 0, 1);
      p_t = code_label(fs, reg, 1, 0);
      luaK_patchtohere(fs, fj);
    }
    final = luaK_getlabel(fs);
    patchlistaux(fs, e->f, final, reg, p_f);
    patchlistaux(fs, e->t, final, reg, p_t);
  }
  
  e->f = e->t = NO_JUMP;
  /* 经过dst.(reg) = src.val 后,表达式的目标地址已确定,且已在reg中 */
  e->u.s.info = reg;
  e->k = VNONRELOC;
}

/* 
**
** CP_XXX 拷贝指令 
** reg(var) = exp: 将表达式的src.val拷贝给next'free.reg
*/
void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
  /* 
  ** 更新exp的reg或者op信息
  ** 不能确定exp对应指令的则e->u.info中填入指令地址,方便回填,同时e->k:更新为VRELOCABLE,表示需要回填RA?
  */
  luaK_dischargevars(fs, e);

  /* 释放被临时占用的reg */
  freeexp(fs, e);
  
  /* 申请一个reg,并将exp赋值到reg上 */
  luaK_reserveregs(fs, 1);
  exp2reg(fs, e, fs->freereg - 1);
}

/* 
** LOAD_XXX 加载指令
** 将表达式的值加载到寄存器中(eg:VGLOBAL, VINDEXED)
** 已加载到reg中的则无需此步骤(VNONRELOC)),
**
** RETURNS:寄存器地址 
*/
int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
  /* 对表达式生成估值指令 */
  luaK_dischargevars(fs, e);
  if (e->k == VNONRELOC) {	/* e的src.val已在reg中,则直接返回对应的reg */
    if (!hasjumps(e)) return e->u.s.info;  /* exp is already in a register */
    if (e->u.s.info >= fs->nactvar) {  /* reg. is not a local? */
      exp2reg(fs, e, e->u.s.info);  /* put value on it */
      return e->u.s.info;
    }
  }
  
  /* e的src值还不在reg则将其存入reg */
  luaK_exp2nextreg(fs, e);  /* default */
  return e->u.s.info;
}

/* 类似 LOAD_XXX 生成表达式的加载指令(!!!!不是CP_XXX拷贝一份e的值到reg的拷贝指令) */
void luaK_exp2val (FuncState *fs, expdesc *e) {
  if (hasjumps(e))
    luaK_exp2anyreg(fs, e);	/* 求解表达式的src.val后,将表达式的值放到下一个free.reg中 */
  else
    luaK_dischargevars(fs, e);	/* 对间接表达式(原值不在reg中或不是直接值的)生成求值指令 */
}

/* 
** LOAD_XXX 加载指令 将表达式的值加载到next’free’reg中
** VNONRELOC这种表达式的值已被加载到reg上的就无需处理了
**
** step.1 表达式的值不在reg中的非VNONRELOC,生成对应的加载指令
** step.2 回填上述加载指令,正式将表达式加载到reg中
**
** RETURNS: 加载的reg的地址
*/
int luaK_exp2RK (FuncState *fs, expdesc *e) {
  /* 对[间接]表达式e生成求值指令 */
  luaK_exp2val(fs, e);

  /* e是常量表达式,无需生成求值指令,直接返回常量表中对应的索引即可 */
  switch (e->k) {
    case VKNUM:
    case VTRUE:
    case VFALSE:
    case VNIL: {
      if (fs->nk <= MAXINDEXRK) {  /* constant fit in RK operand? */
        e->u.s.info = (e->k == VNIL)  ? nilK(fs) :
                      (e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) :
                                        boolK(fs, (e->k == VTRUE));
        e->k = VK;
        return RKASK(e->u.s.info);
      }
      else break;
    }
    case VK: {
      if (e->u.s.info <= MAXINDEXRK)  /* constant fit in argC? */
        return RKASK(e->u.s.info);
      else break;
    }
    default: break;
  }
  
  /* not a constant in the right range: put it in a register 
  **
  ** 间接表达式(非常量表达式),将其src.val赋值到下一个free.reg中
  */
  return luaK_exp2anyreg(fs, e);
}

/* var = ex
** 先 LOAD_XXX (ex) 后 SET_XXX(var=ex) 的"赋值组合业务"
*/
void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
  switch (var->k) {
    case VLOCAL: {
      freeexp(fs, ex);
      exp2reg(fs, ex, var->u.s.info);	/* var = ex */
      return;
    }
    case VUPVAL: {
      int e = luaK_exp2anyreg(fs, ex);	/* var = ex */
      luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0);
      break;
    }
    case VGLOBAL: {
      int e = luaK_exp2anyreg(fs, ex);	/* var = ex */
      luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info);
      break;
    }
    case VINDEXED: {
      int e = luaK_exp2RK(fs, ex);	/* var = ex */
      luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e);
      break;
    }
    default: {
      lua_assert(0);  /* invalid var kind to store */
      break;
    }
  }
  freeexp(fs, ex);
}

/* OP_SELF A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
  int func;
  luaK_exp2anyreg(fs, e);
  freeexp(fs, e);
  func = fs->freereg;
  luaK_reserveregs(fs, 2);
  luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key));
  freeexp(fs, key);
  e->u.s.info = func;
  e->k = VNONRELOC;
}

/* invert:颠倒 */
static void invertjump (FuncState *fs, expdesc *e) {
  Instruction *pc = getjumpcontrol(fs, e->u.s.info);
  lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
                                           GET_OPCODE(*pc) != OP_TEST);
  SETARG_A(*pc, !(GETARG_A(*pc)));
}


static int jumponcond (FuncState *fs, expdesc *e, int cond) {
  if (e->k == VRELOCABLE) {
    Instruction ie = getcode(fs, e);
    if (GET_OPCODE(ie) == OP_NOT) {
      fs->pc--;  /* remove previous OP_NOT */
      return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
    }
    /* else go through */
  }
  discharge2anyreg(fs, e);
  freeexp(fs, e);
  return condjump(fs, OP_TESTSET, NO_REG, e->u.s.info, cond);
}

/* and */
void luaK_goiftrue (FuncState *fs, expdesc *e) {
  int pc;  /* pc of last jump */
  luaK_dischargevars(fs, e);
  switch (e->k) {
    case VK: case VKNUM: case VTRUE: {	
      pc = NO_JUMP;  /* always true; do nothing, keep go throught? */
      break;
    }
    case VJMP: {
      invertjump(fs, e);
      pc = e->u.s.info;
      break;
    }
    default: {
      pc = jumponcond(fs, e, 0);
      break;
    }
  }
  luaK_concat(fs, &e->f, pc);  /* insert last jump in `f' list */
  luaK_patchtohere(fs, e->t);
  e->t = NO_JUMP;
}

/* or */
static void luaK_goiffalse (FuncState *fs, expdesc *e) {
  int pc;  /* pc of last jump */
  luaK_dischargevars(fs, e);
  switch (e->k) {
    case VNIL: case VFALSE: {
      pc = NO_JUMP;  /* always false; do nothing */
      break;
    }
    case VJMP: {
      pc = e->u.s.info;
      break;
    }
    default: {
      pc = jumponcond(fs, e, 1);
      break;
    }
  }
  luaK_concat(fs, &e->t, pc);  /* insert last jump in `t' list */
  luaK_patchtohere(fs, e->f);
  e->f = NO_JUMP;
}

/* not  A B R(A) := not R(B) 
** not的stat的左边必须有左值,否则就是语法错误
*/
static void codenot (FuncState *fs, expdesc *e) {
  luaK_dischargevars(fs, e);
  switch (e->k) {
    case VNIL: case VFALSE: {
      e->k = VTRUE;
      break;
    }
    case VK: case VKNUM: case VTRUE: {
      e->k = VFALSE;
      break;
    }
    case VJMP: {
      invertjump(fs, e);
      break;
    }
    case VRELOCABLE:
    case VNONRELOC: {
      discharge2anyreg(fs, e);
      freeexp(fs, e);
      e->u.s.info = luaK_codeABC(fs, OP_NOT, 0, e->u.s.info, 0);
      e->k = VRELOCABLE;
      break;
    }
    default: {
      lua_assert(0);  /* cannot happen */
      break;
    }
  }
  
  /* interchange true and false lists */
  { int temp = e->f; e->f = e->t; e->t = temp; }
  
  removevalues(fs, e->f);
  removevalues(fs, e->t);
}

/* 索引表达式t.k 
** info = table register; aux = index register (or `k') 
** eg: tbl(info).aux(aux) 
*/
void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
  t->u.s.aux = luaK_exp2RK(fs, k);
  t->k = VINDEXED;
}

/* 尝试合并二元操作符以及左右两边的表达式(编译优化) */
static int constfolding (OpCode op, expdesc *e1, expdesc *e2) {
  lua_Number v1, v2, r;
  
  /* 两个操作数都得是numeral */
  if (!isnumeral(e1) || !isnumeral(e2)) return 0;
  
  v1 = e1->u.nval;
  v2 = e2->u.nval;
  switch (op) {
    case OP_ADD: r = luai_numadd(v1, v2); break;
    case OP_SUB: r = luai_numsub(v1, v2); break;
    case OP_MUL: r = luai_nummul(v1, v2); break;
    case OP_DIV:
      if (v2 == 0) return 0;  /* do not attempt to divide by 0 */
      r = luai_numdiv(v1, v2); break;
    case OP_MOD:
      if (v2 == 0) return 0;  /* do not attempt to divide by 0 */
      r = luai_nummod(v1, v2); break;
    case OP_POW: r = luai_numpow(v1, v2); break;
    case OP_UNM: r = luai_numunm(v1); break;
    case OP_LEN: return 0;  /* no constant folding for 'len' */
    default: lua_assert(0); r = 0; break;
  }
  if (luai_numisnan(r)) return 0;  /* do not attempt to produce NaN */
  e1->u.nval = r;
  return 1;
}

/* 
** local a = b + c 
** 表达式运行完毕后,b,c占用的临时的reg就可以被释放了,故而这一行编译完成后b,c占用的reg也可以释放了
*/
static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
  if (constfolding(op, e1, e2))
    return;
  else {
    int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0;
    int o1 = luaK_exp2RK(fs, e1);
    /* 释放exp的规则是从后往前free */
    if (o1 > o2) {
      freeexp(fs, e1);
      freeexp(fs, e2);
    }
    else {
      freeexp(fs, e2);
      freeexp(fs, e1);
    }
	/* 这里R(A)的值尚未确定,e->=VRELOCABLE:表示需要重定位? */
    e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2);
    e1->k = VRELOCABLE;
  }
}

/* 关系表达式 */
static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1,
                                                          expdesc *e2) {
  int o1 = luaK_exp2RK(fs, e1);
  int o2 = luaK_exp2RK(fs, e2);
  freeexp(fs, e2);
  freeexp(fs, e1);
  if (cond == 0 && op != OP_EQ) {
    int temp;  /* exchange args to replace by `<' or `<=' */
    temp = o1; o1 = o2; o2 = temp;  /* o1 <==> o2 */
    cond = 1;
  }
  e1->u.s.info = condjump(fs, op, cond, o1, o2);
  e1->k = VJMP;
}


void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) {
  expdesc e2;
  e2.t = e2.f = NO_JUMP;
  e2.k = VKNUM; e2.u.nval = 0;
  switch (op) {
    case OPR_MINUS: {
      if (!isnumeral(e))
        luaK_exp2anyreg(fs, e);  /* cannot operate on non-numeric constants */
      codearith(fs, OP_UNM, e, &e2);
      break;
    }
    case OPR_NOT: codenot(fs, e); break;
    case OPR_LEN: {
      luaK_exp2anyreg(fs, e);  /* cannot operate on constants */
      codearith(fs, OP_LEN, e, &e2);
      break;
    }
    default: lua_assert(0);
  }
}


void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
  switch (op) {
    case OPR_AND: {
      luaK_goiftrue(fs, v);
      break;
    }
    case OPR_OR: {
      luaK_goiffalse(fs, v);
      break;
    }
    case OPR_CONCAT: {
      luaK_exp2nextreg(fs, v);  /* operand must be on the `stack' */
      break;
    }
    case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
    case OPR_MOD: case OPR_POW: {
      if (!isnumeral(v)) luaK_exp2RK(fs, v);
      break;
    }
    default: {
      luaK_exp2RK(fs, v);
      break;
    }
  }
}


void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) {
  switch (op) {
    case OPR_AND: {
      lua_assert(e1->t == NO_JUMP);  /* list must be closed */
      luaK_dischargevars(fs, e2);
      luaK_concat(fs, &e2->f, e1->f);
      *e1 = *e2;
      break;
    }
    case OPR_OR: {
      lua_assert(e1->f == NO_JUMP);  /* list must be closed */
      luaK_dischargevars(fs, e2);
      luaK_concat(fs, &e2->t, e1->t);
      *e1 = *e2;
      break;
    }
    case OPR_CONCAT: {
      luaK_exp2val(fs, e2);
      if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
        lua_assert(e1->u.s.info == GETARG_B(getcode(fs, e2))-1);
        freeexp(fs, e1);
        SETARG_B(getcode(fs, e2), e1->u.s.info);
        e1->k = VRELOCABLE; e1->u.s.info = e2->u.s.info;
      }
      else {
        luaK_exp2nextreg(fs, e2);  /* operand must be on the 'stack' */
        codearith(fs, OP_CONCAT, e1, e2);
      }
      break;
    }
    case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break;
    case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break;
    case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break;
    case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break;
    case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break;
    case OPR_POW: codearith(fs, OP_POW, e1, e2); break;
    case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break;
    case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break;
    case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break;
    case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break;
    case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break;
    case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break;
    default: lua_assert(0);
  }
}

/* 更新上一个生成的pc对应的行信息 */
void luaK_fixline (FuncState *fs, int line) {
  fs->f->lineinfo[fs->pc - 1] = line;
}


static int luaK_code (FuncState *fs, Instruction i, int line) {
  Proto *f = fs->f;
  dischargejpc(fs);  /* `pc' will change */
  /* put new instruction in code array */
  luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction,
                  MAX_INT, "code size overflow");
  f->code[fs->pc] = i;
  /* save corresponding line information */
  luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int,
                  MAX_INT, "code size overflow");
  f->lineinfo[fs->pc] = line;
  return fs->pc++;
}


int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
  lua_assert(getOpMode(o) == iABC);
  lua_assert(getBMode(o) != OpArgN || b == 0);
  lua_assert(getCMode(o) != OpArgN || c == 0);
  return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline);
}


int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
  lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
  lua_assert(getCMode(o) == OpArgN);
  return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline);
}


void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) {
  int c =  (nelems - 1)/LFIELDS_PER_FLUSH + 1;
  int b = (tostore == LUA_MULTRET) ? 0 : tostore;	/* tostore中最后一个是变参,则tostore==LUA_MULTRET */
  lua_assert(tostore != 0);
  if (c <= MAXARG_C)
    luaK_codeABC(fs, OP_SETLIST, base, b, c);
  else {
  	/* c过大,将其放到下一条指令中 */
    luaK_codeABC(fs, OP_SETLIST, base, b, 0);
    luaK_code(fs, cast(Instruction, c), fs->ls->lastline);
  }
  /* 这里可以回收空闲出来的寄存器了,有意思吧 */
  fs->freereg = base + 1;  /* free registers with list values */
}

lua源码注释 lparse.c

时间: 2021-06-08   |   分类: lua     |   阅读: 9731 字 ~20分钟
/* 参考的BNF地址 shankusu.me/lua/TheCompleteSyntaxOfLua51/ */
/*
** $Id: lparser.c,v 2.42.1.4 2011/10/21 19:31:42 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/


#include <string.h>
#include <stdio.h>

#define lparser_c
#define LUA_CORE

#include "lua.h"

#include "lcode.h"
#include "ldebug.h"
#include "ldo.h"
#include "lfunc.h"
#include "llex.h"
#include "lmem.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lparser.h"
#include "lstate.h"
#include "lstring.h"
#include "ltable.h"


/* 也只有函数调用或变参操作符这两种TOKEN能返回 ... */
#define hasmultret(k)		((k) == VCALL || (k) == VVARARG)

/* i:当前活跃的locvar的索引 */
#define getlocvar(fs, i)	((fs)->f->locvars[(fs)->actvar[i]])

/* 检查value是否超过了limit限制,超过则报错msg */
#define luaY_checklimit(fs,v,l,m)	if ((v)>(l)) errorlimit(fs,l,m)


/*
** nodes for block list (list of active blocks)
** previous:往前跳(eg:查找变量时从now-block往前一级一级的block找)
*/
typedef struct BlockCnt {
  struct BlockCnt *previous;  /* chain */
  int breaklist;  /* list of jumps out of this loop */

  /* 
  ** !!!!在进入本block的瞬间,外面已经激活的var的数量, !!!!
  ** 意味着本块内激活的locvar的reg.idx不会低于整个值,
  ** 用于按照便变量的生存期检索变量 
  ** 退出本block后,将fs->reg重置到本次即可清掉本block内激活的actvar
  */
  lu_byte nactvar;  /* # active locals outside the breakable structure */
  
  lu_byte upval;  /* true if some variable in the block is an upvalue(本块中存在某些变量是其它块的upvalues:本块关闭时要做善后处理?) */
  lu_byte isbreakable;  /* true if `block' is a loop, 语法规则:break仅能用于loop的block中 */
} BlockCnt;



/*
** prototypes for recursive non-terminal functions
*/
static void chunk (LexState *ls);
static void expr (LexState *ls, expdesc *v);

/* anchor:锚 */
static void anchor_token (LexState *ls) {
  if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) {
    TString *ts = ls->t.seminfo.ts;
    luaX_newstring(ls, getstr(ts), ts->tsv.len);
  }
}


static void error_expected (LexState *ls, int token) {
  luaX_syntaxerror(ls,
      luaO_pushfstring(ls->L, LUA_QS " expected", luaX_token2str(ls, token)));
}


static void errorlimit (FuncState *fs, int limit, const char *what) {
  const char *msg = (fs->f->linedefined == 0) ?
    luaO_pushfstring(fs->L, "main function has more than %d %s", limit, what) :
    luaO_pushfstring(fs->L, "function at line %d has more than %d %s",
                            fs->f->linedefined, limit, what);
  luaX_lexerror(fs->ls, msg, 0);
}


static int testnext (LexState *ls, int c) {
  if (ls->t.token == c) {
    luaX_next(ls);
    return 1;
  }
  else return 0;
}

/* 检查当前c是否为特定的token'Type */
static void check (LexState *ls, int c) {
  if (ls->t.token != c)
    error_expected(ls, c);
}

static void checknext (LexState *ls, int c) {
  check(ls, c);
  luaX_next(ls);
}


#define check_condition(ls,c,msg)	{ if (!(c)) luaX_syntaxerror(ls, msg); }


/* 在where(line)这里,who(TK.1)需要一个what(TK.2)匹配
** eg: function 需要一个end来结束函数定义
*/
static void check_match (LexState *ls, int what, int who, int where) {
  if (!testnext(ls, what)) {
    if (where == ls->linenumber)	/* 当前行,那就不需要打印line信息了? */
      error_expected(ls, what);
    else {
		/* 输出连带line信息的错误信息 */
      luaX_syntaxerror(ls, luaO_pushfstring(ls->L,
             LUA_QS " expected (to close " LUA_QS " at line %d)",
              luaX_token2str(ls, what), luaX_token2str(ls, who), where));
    }
  }
}

/* 
** 强制检查并当前token的type为TK_NAME,返回当前token,
** 读取下一个token 
*/
static TString *str_checkname (LexState *ls) {
  TString *ts;
  check(ls, TK_NAME);		/* 当前token'type必须是TK_NAME的类型 */
  ts = ls->t.seminfo.ts;	/* 提取token的值 */
  luaX_next(ls);			/* 继续读下一个token */
  return ts;
}

/*  KEYCODE: 关键函数 */
static void init_exp (expdesc *e, expkind k, int i) {
  e->f = e->t = NO_JUMP;
  
  /*
  ************************************exp对应的reg已定或是一个参数无需reg*********************************
  ** VVOID, VKNUM, VNIL, VTRUE, VFALSE,   	i:0 值直接被包含在表达式expdesc中,无需寄存器
  ** VK   								    i:常量表中的索引
  ** VLOCAL									i:locvar占用的reg索引
  ** VGLOBAL							    i:NO_REG->全局变量名的NAME在常量表中的索引
  **
  **
  ***********************************需回填指令的RA?**********************************
  ** VRELOCABLE								i:?对应指令OP在指令数组中的下标(方便回填指令中的RA?)?
  ** VCALL, VVARARG							i:对应指令OP在指令数组中的下标(方便回填指令中的RA?)
  **
  ** VNONRELOC								i:对应指令OP在指令数组的下标(方便回填指令中的RA?)
  */
  e->k = k;
  e->u.s.info = i;
}

/* 用字符串(TK_NAME)s初始化expdesc的e表达式 */
static void codestring (LexState *ls, expdesc *e, TString *s) {
  init_exp(e, VK, luaK_stringK(ls->fs, s));
}

/* 先检查当前t的类型为NAME,后将其携带的string赋值给expdesc, 内部读取一次luaX_next() */
static void checkname(LexState *ls, expdesc *e) {
  codestring(ls, e, str_checkname(ls));
}

/* 
** 填充一个全新的 Locvar信息到 Proto.locvars (供调试用)
*/
static int registerlocalvar (LexState *ls, TString *varname) {
  FuncState *fs = ls->fs;
  Proto *f = fs->f;
  int oldsize = f->sizelocvars;

  /* 原来的总数组f->sizelocvars空间不足则扩大 */
  luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
                  LocVar, SHRT_MAX, "too many local variables");
  
  while (oldsize < f->sizelocvars)	/* locvars数组扩大则将新增的slot填NULL */
  	f->locvars[oldsize++].varname = NULL;
  
  /* 更新locvar信息, startPC,endPC暂时还不确定 */
  f->locvars[fs->nlocvars].varname = varname; 
  /* printf("registerlocalvar: idx(%d), name(%p)\n", fs->nlocvars, varname); */
  luaC_objbarrier(ls->L, f, varname);
  return fs->nlocvars++;
}

/* 如果v是不变的string则此宏定义可以利用宏处理阶段提高程序速度 */
#define new_localvarliteral(ls,v,n) \
  new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char))-1), n)

/* KEYCODE
** 注册一个本地变量信息到 Proto.locvars ,
** 填充变量名, startpc,endpc稍后再处理
**
*/
static void new_localvar (LexState *ls, TString *name, int n) {
  FuncState *fs = ls->fs;
  luaY_checklimit(fs, fs->nactvar+n+1, LUAI_MAXVARS, "local variables");
  /* 设置actvar 到 Proto.nlocvars 的映射 */
  /* 这里仅设置了变量的name, 尚未设置startpc,endpc */
  fs->actvar[fs->nactvar+n] = cast(unsigned short, registerlocalvar(ls, name));
  //printf("......... %d->%d", fs->nactvar+n, fs->actvar[fs->nactvar+n]);
}

/* 
** 更新!!! FunState.nactvar 数量,更新 Proto.locvars.startpc 
** 一次性生成多个locvar时,nvars可以告诉本函数方便一次性调整到位
*/
static void adjustlocalvars (LexState *ls, int nvars) {
  FuncState *fs = ls->fs;
  
  /* 更新fs中当前激活的locvar数量 */
  /* 更新fs中当前激活的locvar数量 */
  /* 更新fs中当前激活的locvar数量 */
  fs->nactvar = cast_byte(fs->nactvar + nvars);	

  /* 更新localvar的startpc */
  for (; nvars; nvars--) {
    getlocvar(fs, fs->nactvar - nvars).startpc = fs->pc;
	/* 对应的chunk结束时,再更新endpc信息,也只有那个时候才能确切的知道endpc */
  }
}

/* 确定一批actvar的endpc 
** 仔细看这个函数,很有意思哈(结合 new_localvar adjustlocalvars 一起看 )
*/
static void removevars (LexState *ls, int tolevel) {
  FuncState *fs = ls->fs;
  while (fs->nactvar > tolevel)	/* 这里tolevel是指block结束时对应的pc.idx */
    getlocvar(fs, --fs->nactvar).endpc = fs->pc;	/* 离开block时,关闭block内actvar */
}

/* 查找一个upvalue,返回其在upval数组中的索引,没有则构建 */
static int indexupvalue (FuncState *fs, TString *name, expdesc *v) {
  int i;
  Proto *f = fs->f;
  int oldsize = f->sizeupvalues;
  /* 当前存在的upvalue中已存在吗? */
  for (i=0; i<f->nups; i++) {
    if (fs->upvalues[i].k == v->k &&			/* 类型为VUPVAL */
		fs->upvalues[i].info == v->u.s.info) {	/* 在proto中的索引一致 */
      lua_assert(f->upvalues[i] == name);		/* 名字就必须一致了 */
      return i;
    }
  }

  /* new one */
  
  /* 数组容量不够则扩大 */
  luaY_checklimit(fs, f->nups + 1, LUAI_MAXUPVALUES, "upvalues");
  luaM_growvector(fs->L, f->upvalues, f->nups, f->sizeupvalues,
                  TString *, MAX_INT, "");
  while (oldsize < f->sizeupvalues)
  	f->upvalues[oldsize++] = NULL;
  
  f->upvalues[f->nups] = name;
  luaC_objbarrier(fs->L, f, name);
  lua_assert(v->k == VLOCAL || v->k == VUPVAL);	/* 这里的v->k==VLOCAL ? */
  /* 更新到fs */
  fs->upvalues[f->nups].k = cast_byte(v->k);
  fs->upvalues[f->nups].info = cast_byte(v->u.s.info);
  return f->nups++;
}

/* 尝试在当前fs中匹配激活状态的locvar */
static int searchvar (FuncState *fs, TString *n) {
  int i;
  for (i=fs->nactvar-1; i >= 0; i--) {
    if (n == getlocvar(fs, i).varname)
      return i;
  }
  return -1;  /* not found */
}

/* fs中的locvar在其它函数中被当作upval引用
** 标记fs中对应的block,你有变量是其它fs的upval
** level:actvar在reg数组中的索引
*/
static void markupval (FuncState *fs, int level) {
  BlockCnt *bl = fs->bl;
  /* 这个标记过程的逻辑蛮有意思的 */
  while (bl && bl->nactvar > level)
  	bl = bl->previous;
  if (bl)
  	bl->upval = 1;
}

/* 查找变量名对应的表达式类型的值类型(VLOCAL还是?)
**
** 仔细看这个函数的逻辑,搞明白关于变量的查找过程
** step1:先在本地fs6激活中的locvar查找,找到则返回VLOCAL
** step2:往前一个fs5中的激活中的locvar查找,找不到,继续下一步step3
** step3:继续往前一个fs1中的激活的locvar查找,一直到fs1->pre为空,则
**     可以确定var是一个VGLOBAL
** step4:在某一个fs3中的激活中的locvar被找到,则标记此fs3中的bl表示你的某个var被其它fsX当作upval了
**        往前退,在fs4中的upval中新增一条信息(此upval在父fs3中是VLOCAL,且在fs3的actvar中的索引是多少)
**        再往前退,在fs5中的upval中新增一条信息(此upval在父fs4中是UPVAL,且在fs4的upvalues的索引是多少)
**        再往前退,直到初始的fs6,在fs6中的upval中新增一条信息(此upval在父fs5中是UPVAL,且在fs5的upvalues的索引是多少)
**
** 理论上可以优化下:在本地locvar找不到时,先不要在父fs中找,而是在本fs的upvales中找下
*/
static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
  if (fs == NULL) {  /* no more levels? */
  	/* default is global variable, NO_REG:表示此全局变量尚未决定其寄存器的位置
	** 全局变量对应的NAME在p中常量表的索引由singlevar()函数来处理
  	*/
    init_exp(var, VGLOBAL, NO_REG);  
    return VGLOBAL;	/* 往外一层一层都找不到时,则认为它是全局变量 */
  }
  else {
  	/* 在激活的locvar中找到了,则是本地变量 */
    int v = searchvar(fs, n);  /* look up at current level */
    if (v >= 0) {
      init_exp(var, VLOCAL, v);
      if (!base)
        markupval(fs, v);  /* local will be used as an upval */
      return VLOCAL;
    }
    else {  /* not found at current level; try upper one */
      if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL)	/* 都没找到,则是全局变量 */
        return VGLOBAL;
	  /* 父func中找到,在自己的fun中算upval */
      var->u.s.info = indexupvalue(fs, n, var);  /* else was LOCAL or UPVAL */
      var->k = VUPVAL;  /* upvalue in this level */
      return VUPVAL;
    }
  }
}

/* 
** step1: 检查ls->t.token的类型为TK_NAME,读取下一个TOKEN
** step2: 根据上一个token的NAME,确定其变量(VLOCAL,VGLOBAL还是VUPVAL?)类型,
**            后填充expdesc.u.s.info信息
*/
static void singlevar (LexState *ls, expdesc *var) {
  TString *varname = str_checkname(ls);
  FuncState *fs = ls->fs;

  /*
  ** OP_GETGLOBAL A Bx R(A) := Gbl[Kst(Bx)]
  ** OP_SETGLOBAL A Bx Gbl[Kst(Bx)] := R(A)
  ** 全局变量的指令需要知道表示全局变量的NAME在常量表中的idx,
  **     理解这一点就明白了下面var->u.s.info的赋值的意义
  */
  if (singlevaraux(fs, varname, var, 1) == VGLOBAL) {	/* VLOCVAR,VUPVAL在singlevaraux中已被init_exp初始化 */
    var->u.s.info = luaK_stringK(fs, varname);  /* info points to global name */
  }
}

/* 针对 nvars = nexps 赋值进行调整
** 如果右边少了则给左边赋NIL
** 如果右边有call,...则确定期待的返回值个数
**
** !!! 如果右边多了,本函数未处理!!!
*/
static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
  FuncState *fs = ls->fs;
  /* extra: 右边除掉fun和...外,表达式的数量少于左边的val的数量的情况下,缺失的数量? */
  int extra = nvars - nexps;	
  if (hasmultret(e->k)) {	/* exp的类型为VARARG或CALL */
    extra++;  /* includes call itself:除开VARARG和CALL本身 */
	/* 如果右边exp多了,那就不用补偿左边了
	** OP_VARARG A B R(A), R(A+1), ..., R(A+B-1) = vararg
	** 看上面的指令的含义,猜测这里是在确定B的值
	*/
    if (extra < 0) extra = 0;
	
    luaK_setreturns(fs, e, extra);  /* last exp. provides the difference */
    if (extra > 1) luaK_reserveregs(fs, extra-1);
  }
  else {
    if (e->k != VVOID) luaK_exp2nextreg(fs, e);  /* close last expression */
    if (extra > 0) {	/* nexps:包含右边最后一个exp */
      int reg = fs->freereg;
	  /* 为左边多出来的var申请reg,然后填NIL */
      luaK_reserveregs(fs, extra);
      luaK_nil(fs, reg, extra);
    }
  }
}

/* 进入一个新的block */
static void enterlevel (LexState *ls) {
  if (++ls->L->nCcalls > LUAI_MAXCCALLS)
	luaX_lexerror(ls, "chunk has too many syntax levels", 0);
}


#define leavelevel(ls)	((ls)->L->nCcalls--)

/* 进入块时,初始化block信息 */
static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) {
  bl->breaklist = NO_JUMP;
  bl->isbreakable = isbreakable;
  bl->nactvar = fs->nactvar;
  bl->upval = 0;
  
  /* 这里有个印象 */
  bl->previous = fs->bl;
  fs->bl = bl;
  
  lua_assert(fs->freereg == fs->nactvar);
}


static void leaveblock (FuncState *fs) {
  BlockCnt *bl = fs->bl;
  fs->bl = bl->previous;
  
  /* 确定本block内激活的var的生存周期的endpc */
  removevars(fs->ls, bl->nactvar);

  /* OP_CLOSE A close all variables in the stack up to (>=) R(A) */
  if (bl->upval) {
    luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0);
  }
  
  /* a block either controls scope or breaks (never both) */
  lua_assert(!bl->isbreakable || !bl->upval);	/* TODOLOOK 还不是太理解 */
  
  lua_assert(bl->nactvar == fs->nactvar);	/* 这个必须保证 */
  fs->freereg = fs->nactvar;  /* free registers */
  
  luaK_patchtohere(fs, bl->breaklist);
}


static void pushclosure (LexState *ls, FuncState *func, expdesc *v) {
  FuncState *fs = ls->fs;
  Proto *f = fs->f;
  int oldsize = f->sizep;
  int i;
  luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *,
                  MAXARG_Bx, "constant table overflow");
  while (oldsize < f->sizep) f->p[oldsize++] = NULL;
  f->p[fs->np++] = func->f;
  luaC_objbarrier(ls->L, f, func->f);
  init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1));
  for (i=0; i<func->f->nups; i++) {
    OpCode o = (func->upvalues[i].k == VLOCAL) ? OP_MOVE : OP_GETUPVAL;	/* TODOLOOK 这里不是明白 */
    luaK_codeABC(fs, o, 0, func->upvalues[i].info, 0);
  }
}

/* 开始编译函数 */
static void open_func (LexState *ls, FuncState *fs) {
  lua_State *L = ls->L;
  
  fs->L = L;	
  Proto *f = luaF_newproto(L);
  fs->ls = ls;
  fs->f = f;	/* funState 在编译哪个Proto */
  
  /* ls指向最新的一个FuncState,这里可以猜测,只有先编译完了子函数才有可能编译父函数 */
  fs->prev = ls->fs;  /* linked list of funcstates */
  ls->fs = fs;
  
  fs->pc = 0;
  fs->lasttarget = -1;
  fs->jpc = NO_JUMP;
  fs->freereg = 0;
  fs->nk = 0;
  fs->np = 0;
  fs->nlocvars = 0;
  fs->nactvar = 0;
  fs->bl = NULL;	/* 这里是NULL */
  f->source = ls->source;
  f->maxstacksize = 2;  /* registers 0/1 are always valid */
  fs->h = luaH_new(L, 0, 0);
  
  /* anchor table of constants and prototype (to avoid being collected)
  ** 常量和原型的锚表(避免被收集)
  */
  sethvalue2s(L, L->top, fs->h);
  incr_top(L);	/* 放到堆栈上可避免被gc,如果编译失败stack回缩,则可自动被gc(没有被其它obj引用的话 ) */
  setptvalue2s(L, L->top, f);
  incr_top(L);
  
}


static void close_func (LexState *ls) {
  lua_State *L = ls->L;
  FuncState *fs = ls->fs;
  Proto *f = fs->f;

  /* 关闭还处于激活状态的actvar(设置endpc) */
  removevars(ls, 0);

  /* 自动补一个 OP_RETURN 指令 */
  luaK_ret(fs, 0, 0);  /* final return */

  /* 释放多余的mem */
  luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction);
  f->sizecode = fs->pc;
  
  luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int);
  f->sizelineinfo = fs->pc;
  
  luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue);
  f->sizek = fs->nk;
  
  luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *);
  f->sizep = fs->np;
  
  luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar);
  f->sizelocvars = fs->nlocvars;
  
  luaM_reallocvector(L, f->upvalues, f->sizeupvalues, f->nups, TString *);
  f->sizeupvalues = f->nups;
  
  lua_assert(luaG_checkcode(f));	/* 检查生成的字节码是否有明显的问题 */
  lua_assert(fs->bl == NULL);
  
  /* 本子函数编译完毕,切换到母函数中去 */
  ls->fs = fs->prev;
  
  /* last token read was anchored(锚定) in defunct function; must reanchor(锚) it */
  if (fs) anchor_token(ls);
  L->top -= 2;  /* remove table and prototype from the stack */
}


Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) {
  struct LexState lexstate;
  struct FuncState funcstate;	/* mainFunc */
  
  lexstate.buff = buff;
  /* 设置input信息,但,buff在上面就设置了,有点意思吧,z和buff对于lexState是有点不同的 */
  luaX_setinput(L, &lexstate, z, luaS_new(L, name));

  /* 一个lua文件,编译模块将其当做一个函数来看待
  ** 函数原型 function (...)
  **          end
  **
  ** BNF funcbody ::= `(´ [parlist] `)´ block end
  */
  open_func(&lexstate, &funcstate);
  funcstate.f->is_vararg = VARARG_ISVARARG;  /* main func. is always vararg,哈哈知道lua文件一般开头的local modName=...的语法支撑了吧 */
  luaX_next(&lexstate);  /* read first token */
  chunk(&lexstate);
  check(&lexstate, TK_EOS);	/* 直到编译到文件EOF才结束编译流程 */
  close_func(&lexstate);
  
  lua_assert(lexstate.fs == NULL);		/* lexstate下不应该还有未编译完的funState了 */
  lua_assert(funcstate.prev == NULL);	/* 已编译完的主函数上面还有其它函数,不可能的嘛 */
  lua_assert(funcstate.f->nups == 0);	/* 编译结束,主函数不应该有nups了 */
  return funcstate.f;
}



/*============================================================*/
/* GRAMMAR RULES */
/*============================================================*/

/* A.B, A:B 
** 对前缀生成必要的估值指令,放入free'reg(若有必要)
** 用上述值作为A,再和B一起生成新的VINDEXED表达式
*/
static void field (LexState *ls, expdesc *v) {
  /* field -> ['.' | ':'] NAME */
  FuncState *fs = ls->fs;
  expdesc key;
  
  /* 
  **将前缀(a.b.c中的a.b)加载到reg中
  **若前缀已在寄存器中则无需处理(A=VLOCAL(a))
  */
  luaK_exp2anyreg(fs, v);	
  
  luaX_next(ls); 		/* skip the dot or colon */
  
  checkname(ls, &key);	/* 读取NAME这个域的常量exp并返回给key */		

  /* 生成新的VINDEXED表达式(求值指令,指令的目标寄存器尚未处理) */
  luaK_indexed(fs, v, &key);	
}


static void yindex (LexState *ls, expdesc *v) {
  /* index -> '[' expr ']' */
  luaX_next(ls);  /* skip the '[' */
  expr(ls, v);
  luaK_exp2val(ls->fs, v);
  checknext(ls, ']');
}


/*
** {======================================================================
** Rules for Constructors
** =======================================================================
*/

/* 构造表   tbl {a, b, c=val, d.e} */
struct ConsControl {
  expdesc *t;  /* table descriptor 指代本表的expdesc */
  expdesc v;  /* last list item read: 指代正在分析到的哪一个元素eg(b),对于c=val用不上v */
  int nh;  /* total number of `record' elements */
  int na;  /* total number of array elements */
  int tostore;  /* number of array elements pending to be stored */
};

/* 形如 local tbl = { x = y, [a] = b,}
** 中的x=1,这种指定tbl[k]=v的表达式
*/
static void recfield (LexState *ls, struct ConsControl *cc) {
  /* recfield -> (NAME | `['exp1`]') = exp1 */
  FuncState *fs = ls->fs;
  int reg = ls->fs->freereg;
  expdesc key, val;
  int rkkey;

  /* 对key生成加载指令 */
  if (ls->t.token == TK_NAME) {
    luaY_checklimit(fs, cc->nh, MAX_INT, "items in a constructor");
    checkname(ls, &key);
  }
  else  /* ls->t.token == '[' */
    yindex(ls, &key);
  
  cc->nh++;
  checknext(ls, '=');
  /* 回填上述k的加载指令,将表达式的值SET到next'free'reg上 */
  rkkey = luaK_exp2RK(fs, &key);

  /* 初始化表达式val */
  expr(ls, &val);
  /* 先生成对val的LOAD_XXX加载指令,后生成OP_SETTABLE */
  luaK_codeABC(fs, OP_SETTABLE, cc->t->u.s.info, rkkey, luaK_exp2RK(fs, &val));
  
  fs->freereg = reg;  /* free registers 释放表达式占用的临时寄存器 */
}

/* local tbl = {a,b,c,d}
** 解析完毕b,关闭对b的解析
*/
static void closelistfield (FuncState *fs, struct ConsControl *cc) {
  if (cc->v.k == VVOID) return;  /* there is no list item */
  luaK_exp2nextreg(fs, &cc->v);
  cc->v.k = VVOID;	/* 释放表达式 */
  if (cc->tostore == LFIELDS_PER_FLUSH) {
    luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore);  /* flush */
    cc->tostore = 0;  /* no more items pending */
  }
}

/* local tbl = {a, b, c, d}
** 结束d的解析后,调到这里 
** 逻辑独立出来是因为函数调用作为表的最后一个元素和非最后一个元素,其期望对其返回值的个数是不一样的
*/
static void lastlistfield (FuncState *fs, struct ConsControl *cc) {
  if (cc->tostore == 0) return;
  if (hasmultret(cc->v.k)) {
    luaK_setmultret(fs, &cc->v);
    luaK_setlist(fs, cc->t->u.s.info, cc->na, LUA_MULTRET);
    cc->na--;  /* do not count last expression (unknown number of elements) */
  }
  else {
    if (cc->v.k != VVOID)
      luaK_exp2nextreg(fs, &cc->v);
    luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore);
  }
}

/* tbl = {a,b, c = 100} 数组中单个field eg:a
*/
static void listfield (LexState *ls, struct ConsControl *cc) {
  expr(ls, &cc->v);
  luaY_checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor");
  cc->na++;
  cc->tostore++;
}

static void constructor (LexState *ls, expdesc *t) {
  /* constructor -> ?? */
  FuncState *fs = ls->fs;
  int line = ls->linenumber;
  
  int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0);
  struct ConsControl cc;
  cc.na = cc.nh = cc.tostore = 0;
  cc.t = t;
  
  /* 初始化table的exp */
  init_exp(t, VRELOCABLE, pc);
  
  init_exp(&cc.v, VVOID, 0);  /* no value (yet) */
  
  luaK_exp2nextreg(ls->fs, t);  /* fix it at stack top (for gc) */
  checknext(ls, '{');
  do {
    lua_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 */
        luaX_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, ';'));
  check_match(ls, '}', '{', line);
  lastlistfield(fs, &cc);
  SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */
  SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh));  /* set initial table size */
}

/* }====================================================================== */


/* 
** 解析函数的显式形参列表(对于modName:sub(x,y) 这种隐含的第一个self参数,在外面已被解析完毕
*/
static void parlist (LexState *ls) {
  /* parlist -> [ param { `,' param } ] */
  FuncState *fs = ls->fs;
  Proto *f = fs->f;
  int nparams = 0;
  f->is_vararg = 0;
  if (ls->t.token != ')') {  /* is `parlist' not empty? */
    do {
      switch (ls->t.token) {
        case TK_NAME: {  /* param -> NAME */
          new_localvar(ls, str_checkname(ls), nparams++);
		  /* adjustlocalvars 在下面调用:一次性调整到位 */
          break;
        }
        case TK_DOTS: {  /* param -> `...' */
          luaX_next(ls);
#if defined(LUA_COMPAT_VARARG)
          /* use `arg' as default name */
          new_localvarliteral(ls, "arg", nparams++);
          f->is_vararg = VARARG_HASARG | VARARG_NEEDSARG;
#endif
          f->is_vararg |= VARARG_ISVARARG;
          break;
        }
        default: luaX_syntaxerror(ls, "<name> or " LUA_QL("...") " expected");
      }
    } while (!f->is_vararg && testnext(ls, ','));	/* 这里看得出来 ... 只能是最后一个形参 */
  }else {
  	// function name() body end 显式形参为空
  }
  
  adjustlocalvars(ls, nparams);
  f->numparams = cast_byte(fs->nactvar - (f->is_vararg & VARARG_HASARG));
  luaK_reserveregs(fs, fs->nactvar);  /* reserve register for parameters */
}

/* 解析函数形参和函数体 */
static void body (LexState *ls, expdesc *e, int needself, int line) {
  /* body ->  `(' parlist `)' chunk END */
  FuncState new_fs;
  
  /* 更新ls中的fs变量,完成编译对象的切换 */
  open_func(ls, &new_fs);
  
  /* 新函数从哪一方开始定义 */
  new_fs.f->linedefined = line;
  
  /* local name = function () 或者 local function name() 这两种函数定义格式对应的函数都是从‘(’开始,*/
  checknext(ls, '(');

  /* 这里看得出来self将是本fs的第一个locvar,占用一个正常的locvar
  ** Proto.numparams 中也包含self
  */
  if (needself) {	/* 处理 function modName:sub() body end 这种情况,参考funcname()代码可知 */
    new_localvarliteral(ls, "self", 0);
    adjustlocalvars(ls, 1);
  }
  /* 解析显式形参 */
  parlist(ls);
  
  checknext(ls, ')');
  
  chunk(ls);
  
  /* 函数定义结束于哪一行 */
  new_fs.f->lastlinedefined = ls->linenumber;
  
  check_match(ls, TK_END, TK_FUNCTION, line);
  
  close_func(ls);
  
  pushclosure(ls, &new_fs, e);
}

/* 解析表达式,返回表达式中的项的数量 */
static int explist1 (LexState *ls, expdesc *v) {
  /* explist1 -> expr { `,' expr } */
  int n = 1;  /* at least one expression */
  expr(ls, v);
  while (testnext(ls, ',')) {
    luaK_exp2nextreg(ls->fs, v);
    expr(ls, v);
    n++;
  }
  return n;
}

/* funcargs -> `(' [ explist1 ] `)' | constructor | STRING */
static void funcargs (LexState *ls, expdesc *f) {
  FuncState *fs = ls->fs;
  expdesc args;
  int base, nparams;
  int line = ls->linenumber;
  switch (ls->t.token) {
    case '(': {  /* funcargs -> `(' [ explist1 ] `)' */
      if (line != ls->lastline)
        luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)");
      luaX_next(ls);
      if (ls->t.token == ')')  /* arg list is empty? */
        args.k = VVOID;
      else {
        explist1(ls, &args);
        luaK_setmultret(fs, &args);
      }
      check_match(ls, ')', '(', line);
      break;
    }
    case '{': {  /* funcargs -> constructor */
      constructor(ls, &args);
      break;
    }
    case TK_STRING: {  /* funcargs -> STRING */
      codestring(ls, &args, ls->t.seminfo.ts);
      luaX_next(ls);  /* must use `seminfo' before `next' */
      break;
    }
    default: {
      luaX_syntaxerror(ls, "function arguments expected");
      return;
    }
  }
  lua_assert(f->k == VNONRELOC);
  base = f->u.s.info;  /* base register for call */
  if (hasmultret(args.k))
    nparams = LUA_MULTRET;  /* open call */
  else {
    if (args.k != VVOID)
      luaK_exp2nextreg(fs, &args);  /* close last argument */
    nparams = fs->freereg - (base+1);
  }
  init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2));
  luaK_fixline(fs, line);
  fs->freereg = base+1;  /* call remove function and arguments and leaves
                            (unless changed) one result */
}




/*
** {======================================================================
** Expression parsing
** =======================================================================
*/


static void prefixexp (LexState *ls, expdesc *v) {
  /* prefixexp -> NAME | '(' expr ')' */
  switch (ls->t.token) {
    case '(': {
      int line = ls->linenumber;
      luaX_next(ls);
      expr(ls, v);
      check_match(ls, ')', '(', line);
      luaK_dischargevars(ls->fs, v);
      return;
    }
    case TK_NAME: {
      /* 确定当前ls->t.token的变量类型(VLOCAL,VGLOBAL还是VUPVAL?)
      **     填充expdesc.u.s.info信息
      ** 读取下一个Token
      */
      singlevar(ls, v); 
      return;
    }
    default: {
      luaX_syntaxerror(ls, "unexpected symbol");
      return;
    }
  }
}

/* primary:基本的 */
static void primaryexp (LexState *ls, expdesc *v) {
  /* primaryexp -> prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */
  FuncState *fs = ls->fs;
  
  prefixexp(ls, v);
  
  for (;;) {
    switch (ls->t.token) {
      case '.': {  /* field */
        field(ls, v);
        break;
      }
      case '[': {  /* `[' exp1 `]' */
        expdesc key;
        luaK_exp2anyreg(fs, v);
        yindex(ls, &key);
        luaK_indexed(fs, v, &key);
        break;
      }
      case ':': {  /* `:' NAME funcargs */
        expdesc key;
        luaX_next(ls);
        checkname(ls, &key);
        luaK_self(fs, v, &key);
        funcargs(ls, v);
        break;
      }
      case '(': case TK_STRING: case '{': {  /* funcargs 函数调用 */
        luaK_exp2nextreg(fs, v);
        funcargs(ls, v);
        break;
      }
      default: return;
    }
  }
}

/* 对表达式进行初始化,间接表达式则生成求src.val的指令, 等待回填dst.reg */
static void simpleexp (LexState *ls, expdesc *v) {
  /* simpleexp -> NUMBER | STRING | NIL | true | false | ... |
                  constructor | FUNCTION body | primaryexp */
  switch (ls->t.token) {
    case TK_NUMBER: {
      init_exp(v, VKNUM, 0);
      v->u.nval = ls->t.seminfo.r;	/* 直接赋值NUMBER */
      break;
    }
    case TK_STRING: {
      codestring(ls, v, ls->t.seminfo.ts);
      break;
    }
    case TK_NIL: {
      init_exp(v, VNIL, 0);
      break;
    }
    case TK_TRUE: {
      init_exp(v, VTRUE, 0);
      break;
    }
    case TK_FALSE: {
      init_exp(v, VFALSE, 0);
      break;
    }
    case TK_DOTS: {  /* vararg */
      FuncState *fs = ls->fs;
      check_condition(ls, fs->f->is_vararg,
                      "cannot use " LUA_QL("...") " outside a vararg function");
      fs->f->is_vararg &= ~VARARG_NEEDSARG;  /* don't need 'arg' */
      init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0));
      break;
    }
    case '{': {  /* constructor */
      constructor(ls, v);
      return;
    }
    case TK_FUNCTION: {
      luaX_next(ls);
      body(ls, v, 0, ls->linenumber);
      return;
    }
    default: {
      primaryexp(ls, v);
      return;
    }
  }
  luaX_next(ls);
}

/* 返回TK可能的一元操作符TK */
static UnOpr getunopr (int op) {
  switch (op) {
    case TK_NOT: return OPR_NOT;
    case '-': return OPR_MINUS;
    case '#': return OPR_LEN;
    default: return OPR_NOUNOPR;
  }
}


static BinOpr getbinopr (int op) {
  switch (op) {
    case '+': return OPR_ADD;
    case '-': return OPR_SUB;
    case '*': return OPR_MUL;
    case '/': return OPR_DIV;
    case '%': return OPR_MOD;
    case '^': return OPR_POW;
    case TK_CONCAT: return OPR_CONCAT;
    case TK_NE: return OPR_NE;
    case TK_EQ: return OPR_EQ;
    case '<': return OPR_LT;
    case TK_LE: return OPR_LE;
    case '>': return OPR_GT;
    case TK_GE: return OPR_GE;
    case TK_AND: return OPR_AND;
    case TK_OR: return OPR_OR;
    default: return OPR_NOBINOPR;
  }
}

/* 操作符的优先级分左右:用于处理结合性? */
static const struct {
  lu_byte left;  /* left priority for each binary operator */
  lu_byte right; /* right priority */
} priority[] = {  /* ORDER OPR */
   {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7},  /* `+' `-' `/' `%' */
   {10, 9}, {5, 4},                 /* power and concat (right associative) */
   {3, 3}, {3, 3},                  /* equality and inequality */
   {3, 3}, {3, 3}, {3, 3}, {3, 3},  /* order */
   {2, 2}, {1, 1}                   /* logical (and/or) */
};

#define UNARY_PRIORITY	8  /* priority for unary operators,一元操作符的优先级? */


/*
** subexpr -> (simpleexp | unop subexpr) { binop subexpr }
** where `binop' is any binary operator with a priority higher than `limit'
** 操作符表达式
*/
static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) {
  BinOpr op;
  UnOpr uop;
  enterlevel(ls);
  uop = getunopr(ls->t.token);
  if (uop != OPR_NOUNOPR) {
    luaX_next(ls);
    subexpr(ls, v, UNARY_PRIORITY);
    luaK_prefix(ls->fs, uop, v);
  }
  else simpleexp(ls, v);
  
  /* expand while operators have priorities higher than `limit' */
  op = getbinopr(ls->t.token);
  while (op != OPR_NOBINOPR && priority[op].left > limit) {
    expdesc v2;
    BinOpr nextop;
    luaX_next(ls);
    luaK_infix(ls->fs, op, v);
    /* read sub-expression with higher priority */
    nextop = subexpr(ls, &v2, priority[op].right);
    luaK_posfix(ls->fs, op, v, &v2);
    op = nextop;
  }
  leavelevel(ls);
  return op;  /* return first untreated operator */
}


static void expr (LexState *ls, expdesc *v) {
  subexpr(ls, v, 0);
}

/* }==================================================================== */



/*
** {======================================================================
** Rules for Statements
** =======================================================================
*/

/* repeat
**   statements
** until( condition )
*/

static int block_follow (int token) {
  switch (token) {	/* END和EOS还没理解 */
    case TK_ELSE: case TK_ELSEIF: case TK_END:
    case TK_UNTIL: case TK_EOS:
      return 1;
    default: return 0;
  }
}


static void block (LexState *ls) {
  /* block -> chunk */
  FuncState *fs = ls->fs;
  BlockCnt bl;
  enterblock(fs, &bl, 0);
  chunk(ls);
  lua_assert(bl.breaklist == NO_JUMP);
  leaveblock(fs);
}


/*
** structure to chain all variables in the left-hand side of an
** assignment
*/
struct LHS_assign {
  struct LHS_assign *prev;
  expdesc v;  /* variable (global, local, upvalue, or indexed) */
};


/*
** check whether, in an assignment to a local variable, the local variable
** is needed in a previous assignment (to a table). If so, save original
** local value in a safe place and use this safe copy in the previous
** assignment.
*/
static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
  FuncState *fs = ls->fs;
  int extra = fs->freereg;  /* eventual position to save local variable */
  int conflict = 0;
  for (; lh; lh = lh->prev) {
    if (lh->v.k == VINDEXED) {
      if (lh->v.u.s.info == v->u.s.info) {  /* conflict? */
        conflict = 1;
        lh->v.u.s.info = extra;  /* previous assignment will use safe copy */
      }
      if (lh->v.u.s.aux == v->u.s.info) {  /* conflict? */
        conflict = 1;
        lh->v.u.s.aux = extra;  /* previous assignment will use safe copy */
      }
    }
  }
  if (conflict) {
    luaK_codeABC(fs, OP_MOVE, fs->freereg, v->u.s.info, 0);  /* make copy */
    luaK_reserveregs(fs, 1);
  }
}


static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
  expdesc e;
  check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED,
                      "syntax error");
  if (testnext(ls, ',')) {  /* assignment -> `,' primaryexp assignment */
    struct LHS_assign nv;
    nv.prev = lh;
    primaryexp(ls, &nv.v);
    if (nv.v.k == VLOCAL)
      check_conflict(ls, lh, &nv.v);
    luaY_checklimit(ls->fs, nvars, LUAI_MAXCCALLS - ls->L->nCcalls,
                    "variables in assignment");
    assignment(ls, &nv, nvars+1);
  }
  else {  /* assignment -> `=' explist1 */
    int nexps;
    checknext(ls, '=');
    nexps = explist1(ls, &e);
    if (nexps != nvars) {
      adjust_assign(ls, nvars, nexps, &e);
      if (nexps > nvars)
        ls->fs->freereg -= nexps - nvars;  /* remove extra values */
    }
    else {
      luaK_setoneret(ls->fs, &e);  /* close last expression */
      luaK_storevar(ls->fs, &lh->v, &e);
      return;  /* avoid default */
    }
  }
  init_exp(&e, VNONRELOC, ls->fs->freereg-1);  /* default assignment */
  luaK_storevar(ls->fs, &lh->v, &e);
}


static int cond (LexState *ls) {
  /* cond -> exp */
  expdesc v;
  expr(ls, &v);  /* read condition */
  if (v.k == VNIL) v.k = VFALSE;  /* `falses' are all equal here */
  luaK_goiftrue(ls->fs, &v);
  return v.f;
}


static void breakstat (LexState *ls) {
  FuncState *fs = ls->fs;
  BlockCnt *bl = fs->bl;
  int upval = 0;
  while (bl && !bl->isbreakable) {
    upval |= bl->upval;
    bl = bl->previous;
  }
  if (!bl)
    luaX_syntaxerror(ls, "no loop to break");
  if (upval)
    luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0);
  luaK_concat(fs, &bl->breaklist, luaK_jump(fs));
}


static void whilestat (LexState *ls, int line) {
  /* whilestat -> WHILE cond DO block END */
  FuncState *fs = ls->fs;
  int whileinit;
  int condexit;
  BlockCnt bl;
  luaX_next(ls);  /* skip WHILE */
  whileinit = luaK_getlabel(fs);
  condexit = cond(ls);
  enterblock(fs, &bl, 1);
  checknext(ls, TK_DO);
  block(ls);
  luaK_patchlist(fs, luaK_jump(fs), whileinit);
  check_match(ls, TK_END, TK_WHILE, line);
  leaveblock(fs);
  luaK_patchtohere(fs, condexit);  /* false conditions finish the loop */
}


static void repeatstat (LexState *ls, int line) {
  /* repeatstat -> REPEAT block UNTIL cond */
  int condexit;
  FuncState *fs = ls->fs;
  int repeat_init = luaK_getlabel(fs);
  BlockCnt bl1, bl2;
  enterblock(fs, &bl1, 1);  /* loop block */
  enterblock(fs, &bl2, 0);  /* scope block */
  luaX_next(ls);  /* skip REPEAT */
  chunk(ls);
  check_match(ls, TK_UNTIL, TK_REPEAT, line);
  condexit = cond(ls);  /* read condition (inside scope block) */
  if (!bl2.upval) {  /* no upvalues? */
    leaveblock(fs);  /* finish scope */
    luaK_patchlist(ls->fs, condexit, repeat_init);  /* close the loop */
  }
  else {  /* complete semantics when there are upvalues */
    breakstat(ls);  /* if condition then break */
    luaK_patchtohere(ls->fs, condexit);  /* else... */
    leaveblock(fs);  /* finish scope... */
    luaK_patchlist(ls->fs, luaK_jump(fs), repeat_init);  /* and repeat */
  }
  leaveblock(fs);  /* finish loop */
}


static int exp1 (LexState *ls) {
  expdesc e;
  int k;
  expr(ls, &e);
  k = e.k;
  luaK_exp2nextreg(ls->fs, &e);
  return k;
}


static void forbody (LexState *ls, int base, int line, int nvars, int isnum) {
  /* forbody -> DO block */
  BlockCnt bl;
  FuncState *fs = ls->fs;
  int prep, endfor;
  adjustlocalvars(ls, 3);  /* control variables */
  checknext(ls, TK_DO);
  prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs);
  enterblock(fs, &bl, 0);  /* scope for declared variables */
  adjustlocalvars(ls, nvars);
  luaK_reserveregs(fs, nvars);
  block(ls);
  leaveblock(fs);  /* end of scope for declared variables */
  luaK_patchtohere(fs, prep);
  endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) :
                     luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars);
  luaK_fixline(fs, line);  /* pretend that `OP_FOR' starts the loop */
  luaK_patchlist(fs, (isnum ? endfor : luaK_jump(fs)), prep + 1);
}


static void fornum (LexState *ls, TString *varname, int line) {
  /* fornum -> NAME = exp1,exp1[,exp1] forbody */
  FuncState *fs = ls->fs;
  int base = fs->freereg;
  new_localvarliteral(ls, "(for index)", 0);
  new_localvarliteral(ls, "(for limit)", 1);
  new_localvarliteral(ls, "(for step)", 2);
  new_localvar(ls, varname, 3);
  checknext(ls, '=');
  exp1(ls);  /* initial value */
  checknext(ls, ',');
  exp1(ls);  /* limit */
  if (testnext(ls, ','))
    exp1(ls);  /* optional step */
  else {  /* default step = 1 */
    luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1));
    luaK_reserveregs(fs, 1);
  }
  forbody(ls, base, line, 1, 1);
}


static void forlist (LexState *ls, TString *indexname) {
  /* forlist -> NAME {,NAME} IN explist1 forbody */
  FuncState *fs = ls->fs;
  expdesc e;
  int nvars = 0;
  int line;
  int base = fs->freereg;
  /* create control variables */
  new_localvarliteral(ls, "(for generator)", nvars++);
  new_localvarliteral(ls, "(for state)", nvars++);
  new_localvarliteral(ls, "(for control)", nvars++);
  /* create declared variables */
  new_localvar(ls, indexname, nvars++);
  while (testnext(ls, ','))
    new_localvar(ls, str_checkname(ls), nvars++);
  checknext(ls, TK_IN);
  line = ls->linenumber;
  adjust_assign(ls, 3, explist1(ls, &e), &e);
  luaK_checkstack(fs, 3);  /* extra space to call generator */
  forbody(ls, base, line, nvars - 3, 0);
}


static void forstat (LexState *ls, int line) {
  /* forstat -> FOR (fornum | forlist) END */
  FuncState *fs = ls->fs;
  TString *varname;
  BlockCnt bl;
  enterblock(fs, &bl, 1);  /* scope for loop and control variables */
  luaX_next(ls);  /* skip `for' */
  varname = str_checkname(ls);  /* first variable name */
  switch (ls->t.token) {
    case '=': fornum(ls, varname, line); break;
    case ',': case TK_IN: forlist(ls, varname); break;
    default: luaX_syntaxerror(ls, LUA_QL("=") " or " LUA_QL("in") " expected");
  }
  check_match(ls, TK_END, TK_FOR, line);
  leaveblock(fs);  /* loop scope (`break' jumps to this point) */
}


static int test_then_block (LexState *ls) {
  /* test_then_block -> [IF | ELSEIF] cond THEN block */
  int condexit;
  luaX_next(ls);  /* skip IF or ELSEIF */
  condexit = cond(ls);
  checknext(ls, TK_THEN);
  block(ls);  /* `then' part */
  return condexit;
}


static void ifstat (LexState *ls, int line) {
  /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */
  FuncState *fs = ls->fs;
  int flist;	/* false'list */
  int escapelist = NO_JUMP;	/* 块结束的addr */
  flist = test_then_block(ls);  /* IF cond THEN block */
  while (ls->t.token == TK_ELSEIF) {
    luaK_concat(fs, &escapelist, luaK_jump(fs));
    luaK_patchtohere(fs, flist);
    flist = test_then_block(ls);  /* ELSEIF cond THEN block */
  }
  if (ls->t.token == TK_ELSE) {
    luaK_concat(fs, &escapelist, luaK_jump(fs));
    luaK_patchtohere(fs, flist);
    luaX_next(ls);  /* skip ELSE (after patch, for correct line info) */
    block(ls);  /* `else' part */
  }
  else
    luaK_concat(fs, &escapelist, flist);
  luaK_patchtohere(fs, escapelist);
  check_match(ls, TK_END, TK_IF, line);
}


static void localfunc (LexState *ls) {
  expdesc v, b;
  FuncState *fs = ls->fs;
  
  /* local function funA(...) end 
  ** 注册locvar(函数名)到Proto.nlocvars,填充name信息,建立fs->actvar[fs->nactvars]到p.nlocvars的映射
  */
  new_localvar(ls, str_checkname(ls), 0);
  
  /* 给表达式填个初值先 */
  init_exp(&v, VLOCAL, fs->freereg);
  
  /* 上面新增了一个locvar,用掉了一个freereg,这里扩大点maxstacksize, 更新freereg */
  luaK_reserveregs(fs, 1);	/* reserve reg:准备寄存器 */

  /* 更新fs->nactvar, 填充上面新增的p.nlocvars变量的startpc */
  adjustlocalvars(ls, 1);
  
  body(ls, &b, 0, ls->linenumber);
  luaK_storevar(fs, &v, &b);
  
  /* debug information will only see the variable after this point! */
  getlocvar(fs, fs->nactvar - 1).startpc = fs->pc;
}

static void localstat (LexState *ls) {
  /* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */
  int nvars = 0;
  int nexps;
  expdesc e;
  
  do {	/* 登记左边的变量名到 Proto.locvars */
    new_localvar(ls, str_checkname(ls), nvars++);
  } while (testnext(ls, ','));
  
  if (testnext(ls, '='))
    nexps = explist1(ls, &e);	/* 解析表达式 */
  else {
    e.k = VVOID;
    nexps = 0;
  }
  adjust_assign(ls, nvars, nexps, &e);
  adjustlocalvars(ls, nvars);
}


static int funcname (LexState *ls, expdesc *v) {
  /* funcname -> NAME {field} [`:' NAME] */
  int needself = 0;
  singlevar(ls, v);
  while (ls->t.token == '.')
    field(ls, v);
  if (ls->t.token == ':') {
    needself = 1;	/* 需要给函数添加一个self参数 eg:           function modName:sub () body end */
    field(ls, v);
  }
  return needself;
}


static void funcstat (LexState *ls, int line) {
  /* funcstat -> FUNCTION funcname body */
  int needself;
  expdesc v, b;
  luaX_next(ls);  /* skip FUNCTION */
  needself = funcname(ls, &v);
  body(ls, &b, needself, line);
  luaK_storevar(ls->fs, &v, &b);
  luaK_fixline(ls->fs, line);  /* definition `happens' in the first line */
}

/* 处理表达式stat */
static void exprstat (LexState *ls) {
  /* stat -> func | assignment */
  FuncState *fs = ls->fs;
  struct LHS_assign v;
  primaryexp(ls, &v.v);
  if (v.v.k == VCALL)  /* stat -> func */
    SETARG_C(getcode(fs, &v.v), 1);  /* call statement uses no results */
  else {  /* stat -> assignment */
    v.prev = NULL;
    assignment(ls, &v, 1);
  }
}


static void retstat (LexState *ls) {
  /* stat -> RETURN explist */
  FuncState *fs = ls->fs;
  expdesc e;
  int first, nret;  /* registers with returned values */
  luaX_next(ls);  /* skip RETURN */
  if (block_follow(ls->t.token) || ls->t.token == ';')
    first = nret = 0;  /* return no values */
  else {
    nret = explist1(ls, &e);  /* optional return values */
    if (hasmultret(e.k)) {
      luaK_setmultret(fs, &e);
      if (e.k == VCALL && nret == 1) {  /* tail call? */
        SET_OPCODE(getcode(fs,&e), OP_TAILCALL);
        lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar);
      }
      first = fs->nactvar;
      nret = LUA_MULTRET;  /* return all values */
    }
    else {
      if (nret == 1)  /* only one single value? */
        first = luaK_exp2anyreg(fs, &e);
      else {
        luaK_exp2nextreg(fs, &e);  /* values must go to the `stack' */
        first = fs->nactvar;  /* return all `active' values */
        lua_assert(nret == fs->freereg - first);
      }
    }
  }
  luaK_ret(fs, first, nret);
}


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 0;
    }
    case TK_WHILE: {  /* stat -> whilestat */
      whilestat(ls, line);
      return 0;
    }
    case TK_DO: {  /* stat -> DO block END */
      luaX_next(ls);  /* skip DO */
      block(ls);
      check_match(ls, TK_END, TK_DO, line);
      return 0;
    }
    case TK_FOR: {  /* stat -> forstat */
      forstat(ls, line);
      return 0;
    }
    case TK_REPEAT: {  /* stat -> repeatstat */
      repeatstat(ls, line);
      return 0;
    }
    case TK_FUNCTION: {
      funcstat(ls, line);  /* stat -> funcstat */
      return 0;
    }
    case TK_LOCAL: {  /* stat -> localstat */
      luaX_next(ls);  /* skip LOCAL */
      if (testnext(ls, TK_FUNCTION))  /* local function? */
	  	/*
	  	** local function funName()
	  	** end
	  	*/
        localfunc(ls);	
      else
        localstat(ls);
      return 0;
    }
    case TK_RETURN: {  /* stat -> retstat */
      retstat(ls);
      return 1;  /* must be last statement */
    }
    case TK_BREAK: {  /* stat -> breakstat */
      luaX_next(ls);  /* skip BREAK */
      breakstat(ls);
      return 1;  /* must be last statement */
    }
    default: {
      exprstat(ls);
      return 0;  /* to avoid warnings */
    }
  }
}


static void chunk (LexState *ls) {
  /* chunk -> { stat [`;'] } */
  int islast = 0;
  enterlevel(ls);
  while (!islast && !block_follow(ls->t.token)) {
    islast = statement(ls);
	/* statement后面的';'是可选的 */
    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);
}

/* }====================================================================== */

lua源码注释 lparse.h

时间: 2021-06-08   |   分类: lua     |   阅读: 2101 字 ~5分钟
/*
** $Id: lparser.h,v 1.57.1.1 2007/12/27 13:02:25 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/

#ifndef lparser_h
#define lparser_h

#include "llimits.h"
#include "lobject.h"
#include "lzio.h"


/**************************** 官方的BNF **********************************
chunk ::= {stat [`;´]} [laststat [`;´]]

block ::= chunk

stat ::=  varlist `=´ explist | 
	 functioncall | 
	 do block end | 
	 while exp do block end | 
	 repeat block until exp | 
	 if exp then block {elseif exp then block} [else block] end | 
	 for Name `=´ exp `,´ exp [`,´ exp] do block end | 
	 for namelist in explist do block end | 
	 function funcname funcbody | 
	 local function Name funcbody | 
	 local namelist [`=´ explist] 

laststat ::= return [explist] | break

funcname ::= Name {`.´ Name} [`:´ Name]

varlist ::= var {`,´ var}

var ::=  Name | prefixexp `[´ exp `]´ | prefixexp `.´ Name 

namelist ::= Name {`,´ Name}

explist ::= {exp `,´} exp

exp ::=  nil | false | true | Number | String | `...´ | function | 
	 prefixexp | tableconstructor | exp binop exp | unop exp 

prefixexp ::= var | functioncall | `(´ exp `)´

functioncall ::=  prefixexp args | prefixexp `:´ Name args 

args ::=  `(´ [explist] `)´ | tableconstructor | String 

function ::= function funcbody

funcbody ::= `(´ [parlist] `)´ block end

parlist ::= namelist [`,´ `...´] | `...´

tableconstructor ::= `{´ [fieldlist] `}´

fieldlist ::= field {fieldsep field} [fieldsep]

field ::= `[´ exp `]´ `=´ exp | Name `=´ exp | exp

fieldsep ::= `,´ | `;´

binop ::= `+´ | `-´ | `*´ | `/´ | `^´ | `%´ | `..´ | 
	 `<´ | `<=´ | `>´ | `>=´ | `==´ | `~=´ | 
	 and | or

unop ::= `-´ | not | `#´

**************************************************************************/



/**************************** 自己总结的BNF **********************************
chunk ::= {stat [`;´]}

block ::= chunk

stat ::=  
	 ifstat | 
	 whilestat | 
	 DO block END | 
	 forstat | 
	 repeat | 
	 funcstat | 
	 localstat |
	 retstat |
	 breaksat |
	 exprstat

localstat  	::= local fun | localstat‘
localstat' 	::= LOCAL NAME {`,´ NAME } [`=´ explist1]

explist1   	::= expr { `,' expr }

expr 		::= subexpr

subexpr 	::= (simpleexp | unop subexpr) { binop subexpr }

simpleexp 	::= NUMBER | STRING | NIL | true | false | ... |
                  constructor | FUNCTION body | primaryexp

primaryexp 	::= prefixexp { `.' NAME | `[' expr `]' | `:' NAME funcargs | funcargs }

prefixexp 	::= NAME | '(' expr ')'

funcargs 	::= `(' [ explist1 ] `)' | constructor | STRING

exprstat    := func | assignment

assignment 	::= `,' primaryexp assignment |  `=' explist1 

ifstat 		::= IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END

cond 		::= expr

test_then_block :: [IF | ELSEIF] cond THEN block

whilestat 	::= WHILE cond DO block END

repeatstat 	:: REPEAT block UNTIL cond

forstat 	::= FOR (fornum | forlist) END

fornum 		::= NAME = exp1,exp1[,exp1] forbody

forlist 	::= NAME {,NAME} IN explist1 forbody

forbody 	::= DO block

funcstat 	::= FUNCTION funcname body

funcname 	::= NAME {field} [`:' NAME]

field 		::= ['.' | ':'] NAME 

body 		::=  `(' parlist `)' chunk END

parlist 	:: [ param { `,' param } ] 
param 		::= NAME | ...

constructor ::= {recfield|listfield}

recfield 	::= (NAME | `['exp1`]') = exp1

listfield   ::= exp1

exp1        ::= (exp)   ?


retstat ::= RETURN explist

**************************************************************************/

/*
** Expression descriptor
** 表达式的"类型"
** VNONRELOC, VRELOCABLE表示表达式的reg信息(已被安排到指定的reg或可以重定位到任一reg)
** 其它的类型:表达式的类型 相关函数 luaK_dischargevars
*/

typedef enum {
  VVOID,		/* no value:表示表达式尚未进行评估,也可能表达式就是空 */
  	
  VNIL,
  VTRUE,		/* true */
  VFALSE,		/* fales */
  VK,			/* info = index of constant in `k' 常量表达式 */
  VKNUM,		/* nval = numerical value */

  
  VLOCAL,		/* info = local register */
  VUPVAL,   	/* info = index of upvalue in `upvalues' */
  VGLOBAL,		/* info = index of table; aux = index of global name in `k' */

  /* 索引表达式 eg: tbl(info).aux(aux) */
  VINDEXED,		/* info = table register; aux = index register (or `k') */

  /* 跳转表达式,常用于关系表达式 */
  VJMP,			/* info = instruction pc */

  /* 表达式尚未加载到reg(目标reg尚未确定,可以放在栈的任意位置,只要能访问到)
  ** info:本指令在指令数组中的索引,方便后面回填本指令的目标地址寄存器(R(A))
  */
  VRELOCABLE,	/* info = instruction pc */

  /* 表达式的值已被加载到reg中了,info:对应寄存器的idx */
  VNONRELOC,	/* info = result register */
  
  VCALL,		/* info = instruction pc: info表示exp对应的指令在指令f的指令数组中的下标,下同 */
  VVARARG		/* info = instruction pc   ... 变参操作符 */
} expkind;

typedef struct expdesc {
  expkind k;	/* 表达式类型,后面会更新为表达式占用寄存器的类型 */
  union {
    struct { int info, aux; } s;	/* 随着k不同,info,aux表示的意义随之变化,具体看expkind的注释 */
    lua_Number nval;				/* 数值表达式的数值 */
  } u;
  int t;  /* patch list of `exit when true' */
  int f;  /* patch list of `exit when false' */
} expdesc;


typedef struct upvaldesc {
  lu_byte k;
  lu_byte info;
} upvaldesc;


struct BlockCnt;  /* defined in lparser.c */


/* state needed to generate code for a given function 
** 编译阶段的func状态机,成品则是Proto
*/
typedef struct FuncState {
  struct lua_State *L;  /* copy of the Lua state */
  
  struct FuncState *prev;  /* enclosing function,先编译完子函数,才能编译父函数 */

  struct LexState *ls;  /* lexical state */

  Proto *f;  			/* current function header */
  
  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':指向下一个待生成的指令的待回填的跳转链表 */


  /* 存储常量kvar在对应的 Proto.k 常量数组中的下标的映射表 
  **
  ** local var= "hello" , 常量 "hello" 存在Proto.k常量数组中的第0个位置处
  ** h["hello"] = 0
  ** 查找常量过程如下 k="hello", 进入h表查找,找到v(0), 再用v到Proto.k中取值
  ** 参考函数 lcode.c addk
  */
  Table *h;  			/* table to find (and reuse) elements in `k' */
  int nk;  				/* number of elements in `k' */
  
  int np;  				/* number of elements in `p' */


  /* 第一个可用的reg的索引,随着locvar的申请和释放,这个值不断变化
  ** 随着编译过程中临时占用寄存器的申请和释放,这个值也在不断变化
  **  local a = b + c 计算完b+c的结果要存放到一个临时寄存器中,赋值给a后,这个寄存器要释放
  ** 由于locvar的存在需要"始终"占用一个reg,所以freereg>=nactvar
  */
  int freereg;  		/* first free register */

  /* 
  ** 当前函数已使用的本地变量总和(下面的总和为6),整个数组大小的定义在 Proto 的sizelocvars域中 
  **
  ** do
  **   	local v1, v2, v3
  ** end
  ** do
  **	local v1, v2, v3
  ** end
  ** nlocvars:从1->6, 这样每一个locvar都有一个唯一的 Proto.locvars中对应的信息,
  **    至于运行到某一行时,v1到底指代哪一个v1,可以从startpc,endpc中推断出来(调试库也是靠pc推断的哦?)
  */
  short nlocvars;  		/* number of elements in `locvars' */

  /*
  ** declared-variable stack
  ** 当前激活的var的idx到f.locvars的映射 
  */
  unsigned short actvar[LUAI_MAXVARS];
  
  /* number of active local variables:当前激活中的locvar数量
  ** 对于上面的nlocvars第二次声明local时,nactvar:从1->3,因为离开第一个块后,块所属的locvar被释放了(变量的声明周期也结束了)
  */
  lu_byte nactvar;  					

  upvaldesc upvalues[LUAI_MAXUPVALUES];  /* upvalues */
} FuncState;


LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
                                            const char *name);


#endif
60 61 62 63 64 65 66 67 68

日志
分类
标签
RSS 订阅
GitHub
© 2009 - 2025
粤ICP备2021068940号-1 粤公网安备44011302003059
0%