亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > 綜合 > 正文

lua中賦值類型代碼詳解

2024-07-21 23:04:47
字體:
來源:轉載
供稿:網友

我們來看看lua vm在解析下面源碼并生成bytecode時的整個過程:

 foo = "bar" local a, b = "a", "b" foo = a

首先我們先使用ChunkySpy這個工具來看看vm最終會具體生成什么樣的vm instructions

lua,賦值類型

在這里,開頭為[數字]的行是vm真正生成的字節碼,我們看到一共生成了六行字節碼。首先loadk將常量表中下標為1的常量即"bar"賦給寄存器0;然后setglobal將寄存器0的內容賦給全局變量表中下標為0的全局變量即foo;loadk再將"a"和"b"分別賦值給了寄存器0、1,在這里寄存器0和1分別表示當前函數的local變量即變量a和b;最后setglobal將變量a的值賦給了全局變量foo;最后一個return01是vm在每一個chunk最后都會生成了,并沒有什么用?,F在應該比較清除的了解了lua vm生成的字節碼的含義了,接下來我們看看vm是怎樣且為什么生成這些個字節碼的。

當我們用luaL_dofile函數執行這個lua腳本源碼時會有兩個階段,第一個是將腳本加載進內存,分詞解析并生成字節碼并將其整個包裹為main chunk放于lua stack棧頂,第二是調用lua_pcall執行這個chunk,這里我們只會分析第一個過程。

前面幾篇文章說了,當dofile時會跑到一個叫做luaY_parser的函數中,

Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { struct LexState lexstate; struct FuncState funcstate; -- ... ... funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */ luaX_next(&lexstate); /* read first token */ chunk(&lexstate); -- ... ... return funcstate.f;}

函數luaY_parser前面兩行定義了LexState和FuncState結構體變量,其中LexState不僅用于保存當前的詞法分析狀態信息,而且也保存了整個編譯系統的全局狀態,FuncState結構體來保存當前函數編譯的狀態數據。在lua源碼中都會有一個全局的函數執行體,即為main func,在開始解析的時候當前的函數必然是main func函數,此時第三行的funcstate表示了這個函數的狀態,由于lua規定這個函數必然會接收不定參數因此第五行將is_vararg標識設為VARARG_ISVARARG。接著第六行luaX_next解析文件流分離出第一個token,將其保存在lexstate的t成員中,此時t為“foo”全局變量。接著調用了chunk函數,這里開始了遞歸下降解析的全部過程:

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

lua是有作用域層次概念的,因此當進入一個層次時會調用enterlevel函數,離開當前層次則會調用leavelevel函數。首先進入while循環,當前token為“foo”,這既不是終結標志也不是一個block開始的詞素,因此會進入statement函數,statement函數主體是一個長長的switch...case...代碼結構,根據第一個token進入不同的調用解析分支。在我們這個例子中會進入default分支:

static int statement (LexState *ls) { -- ... ... switch (ls->t.token) {  case TK_IF: { /* stat -> ifstat */   ifstat(ls, line);   return 0;  }  case TK_WHILE: { /* stat -> whilestat */   whilestat(ls, line);   return 0;  }  -- ... ...  default: {   exprstat(ls);   return 0; /* to avoid warnings */  } }}

進入exprstate函數:

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); }}

第四行的LHS_assign結構體是為了處理多變量賦值的情況的,例如a,b,c = ...。在LHS_assign中成員v類型為expdesc描述了等號左邊的變量,詳情可見上篇文章里對expdesc的介紹。接下來進入primaryexp,來獲取并填充“foo”變量的expdesc信息,這會接著進入prefixexp函數中

 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: {    singlevar(ls, v);    return;   }   default: {    luaX_syntaxerror(ls, "unexpected symbol");    return;   }  } }

由于當前token是“foo”,因此進入TK_NAME分支,調用singlevar。

static void singlevar (LexState *ls, expdesc *var) { TString *varname = str_checkname(ls); FuncState *fs = ls->fs; if (singlevaraux(fs, varname, var, 1) == VGLOBAL)  var->u.s.info = luaK_stringK(fs, varname); /* info points to global name */}static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { if (fs == NULL) { /* no more levels? */  init_exp(var, VGLOBAL, NO_REG); /* default is global variable */  return VGLOBAL; } else {  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;   var->u.s.info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */   var->k = VUPVAL; /* upvalue in this level */   return VUPVAL;  } }

在singlevaraux函數中會判斷變量是local、upvalue還是global的。如果fs為null了則說明變量為全局的,否則進入searchvar在當前的函數局部變量數組中查找,否則根據fs的prev成員取得其父函數的FuncState并傳入singlevaraux中遞歸查找,如果前面的都沒滿足則變量為upvlaue。此例中進入第21行中,由于fs已經指向了main func因此其prev為null,“foo”判定為global并返回到exprstate函數中。在取得了“foo”的信息后,因為“foo”不是函數調用,因此接著進入assignment函數中

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); }

在assignment函數中首先判斷下一個token是否為“,",此例中不是則說明是單變量的賦值,接著check下一個token為”=“,成立,接著調用explist1判斷等號右邊有幾個值,此例為1個,然后會判斷左邊的變量數是否等于右邊的值數,不等于則進入adjust_assign函數進行調整,此例是相等的因此依次進入luaK_setoneret和luaK_storevar函數。在luaK_storevar中首先進入int e = luaK_exp2anyreg(fs, ex);函數luaK_exp2anyreg的K代表了此函數是字節碼相關的函數,ex為值”bar“,這個函數又調用了discharge2reg,根據ex的類型來生成不同的字節碼:

static void discharge2reg (FuncState *fs, expdesc *e, int reg) { luaK_dischargevars(fs, e); switch (e->k) {  case VNIL: {   luaK_nil(fs, reg, 1);   break;  }  case VFALSE: case VTRUE: {   luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);   break;  }  case VK: {   luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info);   break;  }//... ...}

由于”bar“是常量因此調用luaK_codeABx函數生成loadk字節碼。reg為保存載入的常量值的寄存器號,e->u.s.info根據不同類型值代表不同含義,根據注釋我們知道此時info為常量數組的下標。

typedef enum { //... ... VK,    /* info = index of constant in `k' */ VKNUM,  /* nval = numerical value */ VLOCAL,  /* info = local register */ VGLOBAL,  /* info = index of table; aux = index of global name in `k' */ //... ...} expkind;

生成了loadk后返回到上面的函數中接著進入luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info);其中e為luaK_exp2anyreg的返回值表示常量保存在的寄存器標號,info根據注釋當為global類型時表示global table的相應下標,因此luaK_codeABx函數將生成setglobal字節碼,將剛剛用loadk將常量加載到寄存器中的值保存到global table相應的位置上。因此foo = "bar"語句就完整的生成了相應的字節碼了。

接下來將生成local a,b = "a","b"語句的字節碼了。過程大致相同,不同的是a,b是local變量且這個賦值語句是多變量賦值語句,因此前面的函數會用LHS_assign鏈表將a,b變量連接起來。如圖所示:

lua,賦值類型

以上所述就是本文都全部內容了,希望大家能夠喜歡。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美精品第一页在线播放| 日韩精品在线观| 亚洲欧洲日产国产网站| 欧美日本国产在线| 欧美高清无遮挡| 亚洲аv电影天堂网| 深夜精品寂寞黄网站在线观看| 免费91在线视频| 欧美国产第一页| 91国产视频在线播放| 久久久久久亚洲精品中文字幕| 亚洲欧美日韩精品久久| 国产精品国语对白| 51色欧美片视频在线观看| 亚洲欧美中文另类| 92版电视剧仙鹤神针在线观看| 亚洲精品成人网| 日韩av男人的天堂| 亚洲黄页视频免费观看| 欧美日本高清一区| 久久99视频精品| 日韩欧美国产免费播放| 中文字幕v亚洲ⅴv天堂| 中文字幕成人精品久久不卡| 2024亚洲男人天堂| zzijzzij亚洲日本成熟少妇| 国产精品黄色影片导航在线观看| 亚洲人成在线一二| 欧美日韩国产色| 国产欧美在线视频| 中文字幕欧美精品在线| 日韩av在线网址| 欧美一区二区影院| 狠狠做深爱婷婷久久综合一区| 国产mv免费观看入口亚洲| 午夜免费日韩视频| 66m—66摸成人免费视频| 欧美激情国产日韩精品一区18| 91国内免费在线视频| 川上优av一区二区线观看| 俺也去精品视频在线观看| 亚洲国产精品大全| 亚洲欧美综合图区| 九九九热精品免费视频观看网站| 欧美大片va欧美在线播放| 欧美一区二三区| 性欧美长视频免费观看不卡| 欧美视频一区二区三区…| 欧美成人免费一级人片100| 91国语精品自产拍在线观看性色| 久久69精品久久久久久久电影好| 自拍偷拍亚洲欧美| 亚洲精品美女在线| 亚洲欧洲在线视频| 中文字幕亚洲欧美日韩高清| 欧美日韩国产色视频| 亚洲精品久久久久久久久| 国模叶桐国产精品一区| 亚洲影院污污.| 狠狠躁夜夜躁久久躁别揉| 亚洲美女av在线播放| 久久久人成影片一区二区三区| 久久青草福利网站| 亚洲男人天堂2023| 国产精品人成电影| 欧美精品videossex88| 亚洲最新中文字幕| 成人乱人伦精品视频在线观看| 尤物九九久久国产精品的分类| 欧美巨大黑人极品精男| 国产精品极品美女粉嫩高清在线| 国产午夜精品全部视频播放| 久久久久久亚洲精品不卡| 国产精品无av码在线观看| 91亚洲精品久久久| 国产69精品久久久久99| 欧美成人精品在线观看| 日韩视频―中文字幕| 精品久久国产精品| 国产精品亚洲视频在线观看| 91a在线视频| 国产精品久久久久久久电影| 国产手机视频精品| 午夜精品理论片| 亚洲国产精品成人va在线观看| 欧美国产日本高清在线| 久久久久久噜噜噜久久久精品| 精品偷拍一区二区三区在线看| 日韩不卡在线观看| 欧美巨乳在线观看| 国产精品第一视频| 欧美日韩中文字幕在线| 成人欧美一区二区三区黑人| 国产在线观看精品| 国产精品男人的天堂| 色综合久综合久久综合久鬼88| 国产日韩换脸av一区在线观看| 亚洲人成电影网站色www| yw.139尤物在线精品视频| 91精品国产综合久久香蕉922| 亚洲精品福利在线观看| 亚洲最新中文字幕| 日韩欧美中文字幕在线播放| 亚洲jizzjizz日本少妇| 国产精品网站入口| 亚洲变态欧美另类捆绑| 91免费观看网站| 成人精品视频99在线观看免费| 精品成人国产在线观看男人呻吟| 欧美大片网站在线观看| 欧美与黑人午夜性猛交久久久| 欧美午夜精品久久久久久久| 国产精品视频yy9099| 911国产网站尤物在线观看| 欧美日韩国产一区二区三区| 蜜臀久久99精品久久久无需会员| 综合136福利视频在线| 欧美在线xxx| 亚洲精品在线看| 免费99精品国产自在在线| 92看片淫黄大片看国产片| 亚洲精品有码在线| 亚洲美女视频网站| 色琪琪综合男人的天堂aⅴ视频| 国产原创欧美精品| 欧美成人一区在线| 国产精品视频精品| 国产网站欧美日韩免费精品在线观看| 欧美黑人极品猛少妇色xxxxx| 久久精彩免费视频| 日av在线播放中文不卡| 国产精选久久久久久| 日韩福利视频在线观看| 欧美激情视频三区| 中文字幕国内精品| 日韩免费av片在线观看| 国产成人精品国内自产拍免费看| 国产亚洲视频中文字幕视频| 国产精品视频资源| 亚洲天堂av综合网| 欧美日韩免费观看中文| 97精品在线观看| 久久国产精品亚洲| 久久久久日韩精品久久久男男| 成人黄色免费看| 欧美精品久久久久| 91超碰caoporn97人人| 国产小视频国产精品| 欧美国产日韩一区二区在线观看| 久久精品色欧美aⅴ一区二区| 综合网日日天干夜夜久久| 亚洲电影在线观看| 一色桃子一区二区| 日韩欧美福利视频| 琪琪第一精品导航| 久久中文精品视频| 欧美精品免费看| 国产成人亚洲精品| 久久深夜福利免费观看| 国产精品白嫩美女在线观看| 国产+成+人+亚洲欧洲| 91精品国产九九九久久久亚洲| 亚洲男人天堂2023| 亚洲综合中文字幕68页|