(接上篇)
> EQOP
c++
case EQOP: { Object *l = top-2; Object *r = top-1; --top; if (tag(l) != tag(r)) tag(top-1) = T_NIL; else { switch (tag(l)) { case T_NIL: tag(top-1) = T_NUMBER; break; case T_NUMBER: tag(top-1) = (nvalue(l) == nvalue(r)) ? T_NUMBER : T_NIL; break; case T_ARRAY: tag(top-1) = (avalue(l) == avalue(r)) ? T_NUMBER : T_NIL; break; case T_FUNCTION: tag(top-1) = (bvalue(l) == bvalue(r)) ? T_NUMBER : T_NIL; break; case T_CFUNCTION: tag(top-1) = (fvalue(l) == fvalue(r)) ? T_NUMBER : T_NIL; break; case T_USERDATA: tag(top-1) = (uvalue(l) == uvalue(r)) ? T_NUMBER : T_NIL; break; case T_STRING: tag(top-1) = (strcmp (svalue(l), svalue(r)) == 0) ? T_NUMBER : T_NIL; break; case T_MARK: return 1; } } nvalue(top-1) = 1; } break;
判斷棧頂的兩個 Object 是否相等。
先判斷是不是相同類型,若是不是,則不等。
不然,判斷值是否相等。數值和字符串類型是判斷是否值相等,而數組、函數這種則是判斷其指針是否相等。
若是相等,把棧頂 Object 設置爲 T_NUMBER 類型,值設置爲 1。
若是不等,設置棧頂 Object 爲 T_NIL(空類型足以識別它本身,此時能夠認爲設置什麼值都無心義)。
> LTOP
express
case LTOP: { Object *l = top-2; Object *r = top-1; --top; if (tag(l) == T_NUMBER && tag(r) == T_NUMBER) tag(top-1) = (nvalue(l) < nvalue(r)) ? T_NUMBER : T_NIL; else { if (tostring(l) || tostring(r)) return 1; tag(top-1) = (strcmp (svalue(l), svalue(r)) < 0) ? T_NUMBER : T_NIL; } nvalue(top-1) = 1; } break;
判斷 top-2 是否小於 top-1。只在兩個 Object 均爲數值型,或者可轉化爲字符串型時有意義。
若是判斷結果爲真,設置棧頂元素類型爲 T_NUMBER,值爲 1。
若是判斷結果爲假,設置棧頂元素類型爲 T_NIL。
> LEOP
數組
case LEOP: { Object *l = top-2; Object *r = top-1; --top; if (tag(l) == T_NUMBER && tag(r) == T_NUMBER) tag(top-1) = (nvalue(l) <= nvalue(r)) ? T_NUMBER : T_NIL; else { if (tostring(l) || tostring(r)) return 1; tag(top-1) = (strcmp (svalue(l), svalue(r)) <= 0) ? T_NUMBER : T_NIL; } nvalue(top-1) = 1; } break;
判斷 top-2 是否小於等於 top-1。只在兩個 Object 均爲數值型,或者可轉化爲字符串型時有意義。
若是判斷結果爲真,設置棧頂元素類型爲 T_NUMBER,值爲 1。
若是判斷結果爲假,設置棧頂元素類型爲 T_NIL。
> ADDOP
函數
case ADDOP: { Object *l = top-2; Object *r = top-1; if (tonumber(r) || tonumber(l)) return 1; nvalue(l) += nvalue(r); --top; } break;
棧頂兩元素 top-2 和 top-1 相加,top-1 出棧,結果保存在新的棧頂。
只在兩個 Object 都可轉化爲數值型時該運算有效。
> SUBOP,
lua
case SUBOP: { Object *l = top-2; Object *r = top-1; if (tonumber(r) || tonumber(l)) return 1; nvalue(l) -= nvalue(r); --top; } break;
棧頂兩元素 top-2 和 top-1 相減,top-1 出棧,結果保存在新的棧頂。
只在兩個 Object 都可轉化爲數值型時該運算有效。
> MULTOP,
debug
case MULTOP: { Object *l = top-2; Object *r = top-1; if (tonumber(r) || tonumber(l)) return 1; nvalue(l) *= nvalue(r); --top; } break;
棧頂兩元素 top-2 和 top-1 相乘,top-1 出棧,結果保存在新的棧頂。
只在兩個 Object 都可轉化爲數值型時該運算有效。
> DIVOP,
指針
case DIVOP: { Object *l = top-2; Object *r = top-1; if (tonumber(r) || tonumber(l)) return 1; nvalue(l) /= nvalue(r); --top; } break;
棧頂兩元素 top-2 和 top-1 相除,top-1 出棧,結果保存在新的棧頂。
只在兩個 Object 都可轉化爲數值型時該運算有效。
> CONCOP,
code
case CONCOP: { Object *l = top-2; Object *r = top-1; if (tostring(r) || tostring(l)) return 1; svalue(l) = lua_createstring (lua_strconc(svalue(l),svalue(r))); if (svalue(l) == NULL) return 1; --top; } break;
棧頂兩元素 top-2 和 top-1 字符串鏈接,top-1 出棧,結果保存在新的棧頂。
只在兩個 Object 都可轉化爲字符串型時該運算有效。
鏈接結果是新生成的字符串,原來的兩個字符串保持不變。
> MINUSOP
字符串
case MINUSOP: if (tonumber(top-1)) return 1; nvalue(top-1) = - nvalue(top-1); break;
棧頂元素數值取反,只在其可轉化爲數值型時有效。
> NOTOP
get
case NOTOP: tag(top-1) = tag(top-1) == T_NIL ? T_NUMBER : T_NIL; break;
棧頂元素邏輯取反。
當棧頂元素爲假(T_NIL)時設置其爲真(T_NUMBER)。
當棧頂元素爲真(非 T_NIL 型)時設置其爲假(T_NIL)。
> ONTJMP
case ONTJMP: { CodeWord code; get_word(code,pc); if (tag(top-1) != T_NIL) pc += code.w; } break;
真跳轉,若是判斷棧頂元素爲真則跳轉,指令偏移量從字節碼中取得。
> ONFJMP
case ONFJMP: { CodeWord code; get_word(code,pc); if (tag(top-1) == T_NIL) pc += code.w; } break;
假跳轉,若是判斷棧頂元素爲假則跳轉,指令偏移量從字節碼中取得。
> JMP
case JMP: { CodeWord code; get_word(code,pc); pc += code.w; } break;
無條件跳轉,指令偏移量從字節碼中取得。
> UPJMP
case UPJMP: { CodeWord code; get_word(code,pc); pc -= code.w; } break;
向上無條件跳轉,指令偏移量從字節碼中取得。
> IFFJMP
case IFFJMP: { CodeWord code; get_word(code,pc); top--; if (tag(top) == T_NIL) pc += code.w; } break;
假跳轉,若是判斷棧頂元素爲假則跳轉,指令偏移量從字節碼中取得。
判斷條件出棧。
> IFFUPJMP
case IFFUPJMP: { CodeWord code; get_word(code,pc); top--; if (tag(top) == T_NIL) pc -= code.w; } break;
假跳轉,若是判斷棧頂元素爲假則向上跳轉,指令偏移量從字節碼中取得。
判斷條件出棧。
> POP
case POP: --top; break;
出棧。
> CALLFUNC
case CALLFUNC: { Byte *newpc; Object *b = top-1; while (tag(b) != T_MARK) b--; if (tag(b-1) == T_FUNCTION) { lua_debugline = 0; /* always reset debug flag */ newpc = bvalue(b-1); bvalue(b-1) = pc; /* store return code */ nvalue(b) = (base-stack); /* store base value */ base = b+1; pc = newpc; if (MAXSTACK-(base-stack) < STACKGAP) { lua_error ("stack overflow"); return 1; } } else if (tag(b-1) == T_CFUNCTION) { int nparam; lua_debugline = 0; /* always reset debug flag */ nvalue(b) = (base-stack); /* store base value */ base = b+1; nparam = top-base; /* number of parameters */ (fvalue(b-1))(); /* call C function */ /* shift returned values */ { int i; int nretval = top - base - nparam; top = base - 2; base = stack + (int) nvalue(base-1); for (i=0; i<nretval; i++) { *top = *(top+nparam+2); ++top; } } } else { lua_reportbug ("call expression not a function"); return 1; } } break;
函數調用,從棧頂到棧中類型爲 T_MARK 的 Object 均爲函數參數。
類型爲 T_MARK 的 Object 的下一個 Object 爲函數名。
函數調用有兩種:
一種爲 Lua 腳本中定義的函數的調用,相應的 Object 類型爲 T_FUNCTION。
另外一種爲 Lua 腳本中調用 C 寫的函數,相應的 Object 類型爲 T_CFUNCTION。
T_FUNCTION 調用前保存當前執行字節碼 pc 和棧的 base 以作調用結束後的恢復,設置 pc 爲調用函數的字節碼地址便可。
T_CFUNCTION 調用前保存棧的 base 以作調用結束後的恢復,取得函數參數個數。
函數調用結束後,調整返回值的位置,恢復 top 和 base 的值。把返回值調整得和 Lua 函數返回的同樣。
也就是原來函數 Object 和 T_MARK 的地方被返回值替掉。
能夠看出來,這裏的函數調用和彙編或者 C 語言裏的函數調用的棧楨是長得很像的(除了沒有寄存器)。
> RETCODE
case RETCODE: { int i; int shift = *pc++; int nretval = top - base - shift; top = base - 2; pc = bvalue(base-2); base = stack + (int) nvalue(base-1); for (i=0; i<nretval; i++) { *top = *(top+shift+2); ++top; } } break;
拷貝返回值到函數調用前的位置,就是棧裏 T_MARK 前面的那個函數類型的 Object 處。
當前的字節碼保存的偏移量,經過計算 top, base, shift 之差獲得返回值個數。 shift 是指函數有幾個參數。
重置 top, pc, base。
把函數的返回值拷貝到棧上原來的函數 Object 處。
> HALT
case HALT: base = oldbase; return 0; /* success */
正常中止,重置棧。
> SETFUNCTION
case SETFUNCTION: { CodeWord file, func; get_word(file,pc); get_word(func,pc); if (lua_pushfunction (file.w, func.w)) return 1; } break;
設置函數,函數的文件名和函數地址從字節碼裏取得。
> SETLINE
case SETLINE: { CodeWord code; get_word(code,pc); lua_debugline = code.w; } break;
設置 debug 行號。
> RESET
case RESET: lua_popfunction (); break;
彈出函數