Lua之table創(chuàng)建

專門負責構(gòu)造表的函數(shù)

    (lparser.c)
    static void constructor (LexState *ls, expdesc *t) {
      /* constructor -> '{' [ field { sep field } [sep] ] '}'
         sep -> ',' | ';' */
      FuncState *fs = ls->fs;
      int line = ls->linenumber;
      int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); // 生成一條 OP_NEWTABLE 指令
      struct ConsControl cc; // 初始化 ConsControl 結(jié)構(gòu)體
      cc.na = cc.nh = cc.tostore = 0;
      cc.t = t;
      init_exp(t, VRELOCABLE, pc);
      init_exp(&cc.v, VVOID, 0);  /* no value (yet) */ // 將 ConsControl 結(jié)構(gòu)體中的 v 初始化為 VVOID
      luaK_exp2nextreg(ls->fs, t);  /* fix it at stack top */
      checknext(ls, '{');
      do {
        lua_assert(cc.v.k == VVOID || cc.tostore > 0);
        if (ls->t.token == '}') break; // 當解析到 } 時探越,循環(huán)停止
        closelistfield(fs, &cc);
        field(ls, &cc);
      } 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 */ // 數(shù)組大小
      SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh));  /* set initial table size */ // 散列表大小
    }
    // 調(diào)用 closelistfield 函數(shù)生成上一個表達式的相關(guān)指令
    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.info, cc->na, cc->tostore);  /* flush */
        cc->tostore = 0;  /* no more items pending */
      }
    }
    static void field (LexState *ls, struct ConsControl *cc) {
      /* field -> listfield | recfield */
      switch(ls->t.token) {
        case TK_NAME: {  /* may be 'listfield' or 'recfield' */
          if (luaX_lookahead(ls) != '=')  /* expression? */
            listfield(ls, cc);
          else
            recfield(ls, cc);
          break;
        }
        case '[': {
          recfield(ls, cc);
          break;
        }
        default: {
          listfield(ls, cc);
          break;
        }
      }
    }

field 函數(shù)針對具體的類型來做解析:
(1)如果解析到一個變量狡赐,那么看緊跟著這個符號的是不是 =,如果不是钦幔,就是一個數(shù)組方式的賦值枕屉,否則就是散列方式的賦值;
(2)如果看到的是 [ 符號鲤氢,就認為是散列部分的構(gòu)造搀庶;
(3)否則就是數(shù)組部分的構(gòu)造了。數(shù)組部分的構(gòu)造進入 listfield函數(shù)铜异,散列部分進入 recfield 函數(shù)哥倔;

創(chuàng)建空表

local p = {}

使用 ChunkSpy 反編譯出來的指令是:

    ; function [0] definition (level 1)
    ; 0 upvalues, 0 params, 2 stacks
    .function  0 0 2 2
    .local  "p"  ; 0
    ; (1)  local p = {}
    [1] newtable   0   0   0    ; array=0, hash=0
    [2] return     0   1      
    ; end of function

對應(yīng)的是 OPCODE(lopcodes.h)OP_NEWTABLE,用于創(chuàng)建一個表揍庄,將結(jié)果存入寄存器:
OP_NEWTABLE,/* A B C R(A) := {} (size = B,C) */
參數(shù)說明:
參數(shù) A咆蒿,創(chuàng)建好的表存入寄存器的索引
參數(shù) B,表的數(shù)組部分大小
參數(shù) C蚂子,表的散列部分大小

創(chuàng)建一個表沃测,添加數(shù)組部分

local p = {1, 2}

使用 ChunkSpy 反編譯出來的指令是:

    ; function [0] definition (level 1)
    ; 0 upvalues, 0 params, 3 stacks
    .function  0 0 2 3
    .local  "p"  ; 0
    .const  1  ; 0
    .const  2  ; 1
    ; (1)  local p = {1, 2}
    [1] newtable   0   2   0    ; array=2, hash=0
    [2] loadk      1   0        ; 1
    [3] loadk      2   1        ; 2
    [4] setlist    0   2   1    ; index 1 to 2
    [5] return     0   1      
    ; end of function

newtable 指令之后,跟著兩條 loadk 指令和一條 setlist 指令食茎,loadk 指令用于把表構(gòu)造表達式中的常量12加載到函數(shù)棧中蒂破,而 setlist 指令則使用這兩個常量初始化表的數(shù)組部分。
setlist 指令的格式:
OP_SETLIST,/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
參數(shù)說明:
參數(shù) A别渔,OP_NEWTABLE指令中創(chuàng)建好的表所在的寄存器附迷,它后面緊跟著代寫入的數(shù)據(jù)
參數(shù) B,待寫入數(shù)據(jù)的數(shù)量
參數(shù) C哎媚,F(xiàn)PF索引(即 LFIELDS_PER_FLUSH 常量)喇伯,即每次寫入最多的是 LFIELDS_PER_FLUSH

    /* number of list items to accumulate before a SETLIST instruction */
    #define LFIELDS_PER_FLUSH   50

用途:當前構(gòu)造表時內(nèi)部的數(shù)組部分的數(shù)據(jù)如果超過這個值,就首先調(diào)用一次 OP_SETLIST 函數(shù)寫入寄存器中拨与。

創(chuàng)建一個表稻据,添加散列部分

local p = {["a"]=1}

使用 ChunkSpy 反編譯出來的指令是:

    ; function [0] definition (level 1)
    ; 0 upvalues, 0 params, 2 stacks
    .function  0 0 2 2
    .local  "p"  ; 0
    .const  "a"  ; 0
    .const  1  ; 1
    ; (1)  local p = {["a"]=1}
    [1] newtable   0   0   1    ; array=0, hash=1
    [2] settable   0   256 257  ; "a" 1
    [3] return     0   1      
    ; end of function

newtable 指令之后,跟著 settable 指令买喧,這個指令用來完成散列部分的初始化捻悯,其格式:
OP_SETTABLE,/* A B C R(A)[RK(B)] := RK(C) */
參數(shù)說明:
參數(shù) A,表所在的寄存器
參數(shù) B淤毛,key 存放的位置今缚,注意其格式是 RK,也就說這個值可能來自寄存器钱床,也可能來自常量數(shù)組
參數(shù) C荚斯,value 存放的位置埠居,注意其格式是 RK查牌,也就說這個值可能來自寄存器事期,也可能來自常量數(shù)組

在前面的分析中,初始化散列部分的代碼會走入 recfield 函數(shù)中纸颜。散列部分的初始化分為兩部分:
(1)key 是一個常量兽泣;
(2)key 是一個變量,需要首先去獲取這個變量的值胁孙;

第一種情況比較簡單唠倦,分為幾個步驟:
(1)得到 key 常量在常量數(shù)組中的索引,根據(jù)這個值調(diào)用 luaK_exp2RK 函數(shù)生成 RK 值涮较;
(2)得到 value 表達式的索引稠鼻,根據(jù)這個值調(diào)用 luaK_exp2RK函數(shù)生成 RK 值;
(3)將前兩步的值以及表在寄存器中的索引狂票,寫入 OP_SETTABLE 的參數(shù)中候齿;

創(chuàng)建一個表,鍵為變量

local a = "a"
local p = {[a]=1}

使用 ChunkSpy 反編譯出來的指令是:

    ; function [0] definition (level 1)
    ; 0 upvalues, 0 params, 2 stacks
    .function  0 0 2 2
    .local  "a"  ; 0
    .local  "p"  ; 1
    .const  "a"  ; 0
    .const  1  ; 1
    ; (1)  local a = "a"
    [1] loadk      0   0        ; "a"
    ; (2)   local p = {[a]=1}
    [2] newtable   1   0   1    ; array=0, hash=1
    [3] settable   1   0   257  ; 1
    [4] return     0   1      
    ; end of function

最開始多了loadk 指令闺属,將常量 "a" 加載到寄存器 0 中慌盯。然后 settable 指令中的key值小于255,也就是這個值來自于寄存器0掂器。

創(chuàng)建一個表亚皂,既添加數(shù)組部分,也添加散列部分国瓮,散列部分的 key 是整數(shù)

local p = {1, [2]=2, 3, [4]=4, 5}

使用 ChunkSpy 反編譯出來的指令是:

    ; function [0] definition (level 1)
    ; 0 upvalues, 0 params, 4 stacks
    .function  0 0 2 4
    .local  "p"  ; 0
    .const  1  ; 0
    .const  2  ; 1
    .const  3  ; 2
    .const  4  ; 3
    .const  5  ; 4
    ; (1)  local p = {1, [2]=2, 3, [4]=4, 5}
    [1] newtable   0   3   2    ; array=3, hash=2
    [2] loadk      1   0        ; 1
    [3] settable   0   257 257  ; 2 2
    [4] loadk      2   2        ; 3
    [5] settable   0   259 259  ; 4 4
    [6] loadk      3   4        ; 5
    [7] setlist    0   3   1    ; index 1 to 3
    [8] return     0   1      
    ; end of function

創(chuàng)建一個表灭必,既添加數(shù)組部分,也添加散列部分乃摹,散列部分的 key 是字符串

local p = {1, ["a"]=2, 3, ["b"]=4, 5, ["c"]=6}

使用 ChunkSpy 反編譯出來的指令是:

    .function  0 0 2 4
    .local  "p"  ; 0
    .const  1  ; 0
    .const  "a"  ; 1
    .const  2  ; 2
    .const  3  ; 3
    .const  "b"  ; 4
    .const  4  ; 5
    .const  5  ; 6
    .const  "c"  ; 7
    .const  6  ; 8
    ; (1)  local p = {1, ["a"]=2, 3, ["b"]=4, 5, ["c"]=6}
    [1] newtable   0   3   3    ; array=3, hash=3
    [2] loadk      1   0        ; 1
    [3] settable   0   257 258  ; "a" 2
    [4] loadk      2   3        ; 3
    [5] settable   0   260 261  ; "b" 4
    [6] loadk      3   6        ; 5
    [7] settable   0   263 264  ; "c" 6
    [8] setlist    0   3   1    ; index 1 to 3
    [9] return     0   1      
    ; end of function

ChunkSpy 使用方法參考

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末厂财,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子峡懈,更是在濱河造成了極大的恐慌璃饱,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肪康,死亡現(xiàn)場離奇詭異荚恶,居然都是意外死亡,警方通過查閱死者的電腦和手機磷支,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門谒撼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人雾狈,你說我怎么就攤上這事廓潜。” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵辩蛋,是天一觀的道長呻畸。 經(jīng)常有香客問我,道長悼院,這世上最難降的妖魔是什么伤为? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮据途,結(jié)果婚禮上绞愚,老公的妹妹穿的比我還像新娘。我一直安慰自己颖医,他們只是感情好位衩,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著熔萧,像睡著了一般蚂四。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上哪痰,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天遂赠,我揣著相機與錄音,去河邊找鬼晌杰。 笑死跷睦,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的肋演。 我是一名探鬼主播抑诸,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼爹殊!你這毒婦竟也來了蜕乡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤梗夸,失蹤者是張志新(化名)和其女友劉穎层玲,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體反症,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡辛块,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了铅碍。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片润绵。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖胞谈,靈堂內(nèi)的尸體忽然破棺而出尘盼,到底是詐尸還是另有隱情憨愉,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布卿捎,位于F島的核電站配紫,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏娇澎。R本人自食惡果不足惜笨蚁,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一睹晒、第九天 我趴在偏房一處隱蔽的房頂上張望趟庄。 院中可真熱鬧,春花似錦伪很、人聲如沸戚啥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽猫十。三九已至,卻和暖如春呆盖,著一層夾襖步出監(jiān)牢的瞬間拖云,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工应又, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留宙项,地道東北人。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓株扛,卻偏偏與公主長得像尤筐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子洞就,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容