📄 lvm.c
字号:
/*** $Id: lvm.c,v 1.284b 2003/04/03 13:35:34 roberto Exp $** Lua virtual machine** See Copyright Notice in lua.h*/#include <stdarg.h>#include <stdlib.h>#include <string.h>/* needed only when `lua_number2str' uses `sprintf' */#include <stdio.h>#define lvm_c#include "lua.h"#include "ldebug.h"#include "ldo.h"#include "lfunc.h"#include "lgc.h"#include "lobject.h"#include "lopcodes.h"#include "lstate.h"#include "lstring.h"#include "ltable.h"#include "ltm.h"#include "lvm.h"/* function to convert a lua_Number to a string */#ifndef lua_number2str#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n))#endif/* limit for table tag-method chains (to avoid loops) */#define MAXTAGLOOP 100const TObject *luaV_tonumber (const TObject *obj, TObject *n) { lua_Number num; if (ttisnumber(obj)) return obj; if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) { setnvalue(n, num); return n; } else return NULL;}int luaV_tostring (lua_State *L, StkId obj) { if (!ttisnumber(obj)) return 0; else { char s[32]; /* 16 digits, sign, point and \0 (+ some extra...) */ lua_number2str(s, nvalue(obj)); setsvalue2s(obj, luaS_new(L, s)); return 1; }}static void traceexec (lua_State *L) { lu_byte mask = L->hookmask; if (mask & LUA_MASKCOUNT) { /* instruction-hook set? */ if (L->hookcount == 0) { resethookcount(L); luaD_callhook(L, LUA_HOOKCOUNT, -1); return; } } if (mask & LUA_MASKLINE) { CallInfo *ci = L->ci; Proto *p = ci_func(ci)->l.p; int newline = getline(p, pcRel(*ci->u.l.pc, p)); if (!L->hookinit) { luaG_inithooks(L); return; } lua_assert(ci->state & CI_HASFRAME); if (pcRel(*ci->u.l.pc, p) == 0) /* tracing may be starting now? */ ci->u.l.savedpc = *ci->u.l.pc; /* initialize `savedpc' */ /* calls linehook when enters a new line or jumps back (loop) */ if (*ci->u.l.pc <= ci->u.l.savedpc || newline != getline(p, pcRel(ci->u.l.savedpc, p))) { luaD_callhook(L, LUA_HOOKLINE, newline); ci = L->ci; /* previous call may reallocate `ci' */ } ci->u.l.savedpc = *ci->u.l.pc; }}static void callTMres (lua_State *L, const TObject *f, const TObject *p1, const TObject *p2) { setobj2s(L->top, f); /* push function */ setobj2s(L->top+1, p1); /* 1st argument */ setobj2s(L->top+2, p2); /* 2nd argument */ luaD_checkstack(L, 3); /* cannot check before (could invalidate p1, p2) */ L->top += 3; luaD_call(L, L->top - 3, 1); L->top--; /* result will be in L->top */}static void callTM (lua_State *L, const TObject *f, const TObject *p1, const TObject *p2, const TObject *p3) { setobj2s(L->top, f); /* push function */ setobj2s(L->top+1, p1); /* 1st argument */ setobj2s(L->top+2, p2); /* 2nd argument */ setobj2s(L->top+3, p3); /* 3th argument */ luaD_checkstack(L, 4); /* cannot check before (could invalidate p1...p3) */ L->top += 4; luaD_call(L, L->top - 4, 0);}static const TObject *luaV_index (lua_State *L, const TObject *t, TObject *key, int loop) { const TObject *tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); if (tm == NULL) return &luaO_nilobject; /* no TM */ if (ttisfunction(tm)) { callTMres(L, tm, t, key); return L->top; } else return luaV_gettable(L, tm, key, loop);}static const TObject *luaV_getnotable (lua_State *L, const TObject *t, TObject *key, int loop) { const TObject *tm = luaT_gettmbyobj(L, t, TM_INDEX); if (ttisnil(tm)) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTMres(L, tm, t, key); return L->top; } else return luaV_gettable(L, tm, key, loop);}/*** Function to index a table.** Receives the table at `t' and the key at `key'.** leaves the result at `res'.*/const TObject *luaV_gettable (lua_State *L, const TObject *t, TObject *key, int loop) { if (loop > MAXTAGLOOP) luaG_runerror(L, "loop in gettable"); if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); const TObject *v = luaH_get(h, key); /* do a primitive get */ if (!ttisnil(v)) return v; else return luaV_index(L, t, key, loop+1); } else return luaV_getnotable(L, t, key, loop+1);}/*** Receives table at `t', key at `key' and value at `val'.*/void luaV_settable (lua_State *L, const TObject *t, TObject *key, StkId val) { const TObject *tm; int loop = 0; do { if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); TObject *oldval = luaH_set(L, h, key); /* do a primitive set */ if (!ttisnil(oldval) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ setobj2t(oldval, val); /* write barrier */ return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTM(L, tm, t, key, val); return; } t = tm; /* else repeat with `tm' */ } while (++loop <= MAXTAGLOOP); luaG_runerror(L, "loop in settable");}static int call_binTM (lua_State *L, const TObject *p1, const TObject *p2, StkId res, TMS event) { ptrdiff_t result = savestack(L, res); const TObject *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ if (ttisnil(tm)) tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ if (!ttisfunction(tm)) return 0; callTMres(L, tm, p1, p2); res = restorestack(L, result); /* previous call may change stack */ setobjs2s(res, L->top); return 1;}static const TObject *get_compTM (lua_State *L, Table *mt1, Table *mt2, TMS event) { const TObject *tm1 = fasttm(L, mt1, event); const TObject *tm2; if (tm1 == NULL) return NULL; /* no metamethod */ if (mt1 == mt2) return tm1; /* same metatables => same metamethods */ tm2 = fasttm(L, mt2, event); if (tm2 == NULL) return NULL; /* no metamethod */ if (luaO_rawequalObj(tm1, tm2)) /* same metamethods? */ return tm1; return NULL;}static int call_orderTM (lua_State *L, const TObject *p1, const TObject *p2, TMS event) { const TObject *tm1 = luaT_gettmbyobj(L, p1, event); const TObject *tm2; if (ttisnil(tm1)) return -1; /* no metamethod? */ tm2 = luaT_gettmbyobj(L, p2, event); if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */ return -1; callTMres(L, tm1, p1, p2); return !l_isfalse(L->top);}static int luaV_strcmp (const TString *ls, const TString *rs) { const char *l = getstr(ls); size_t ll = ls->tsv.len; const char *r = getstr(rs); size_t lr = rs->tsv.len; for (;;) { int temp = strcoll(l, r); if (temp != 0) return temp; else { /* strings are equal up to a `\0' */ size_t len = strlen(l); /* index of first `\0' in both strings */ if (len == lr) /* r is finished? */ return (len == ll) ? 0 : 1; else if (len == ll) /* l is finished? */ return -1; /* l is smaller than r (because r is not finished) */ /* both strings longer than `len'; go on comparing (after the `\0') */ len++; l += len; ll -= len; r += len; lr -= len; } }}int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r) { int res; if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) return nvalue(l) < nvalue(r); else if (ttisstring(l)) return luaV_strcmp(tsvalue(l), tsvalue(r)) < 0; else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) return res; return luaG_ordererror(L, l, r);}static int luaV_lessequal (lua_State *L, const TObject *l, const TObject *r) { int res; if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); else if (ttisnumber(l)) return nvalue(l) <= nvalue(r); else if (ttisstring(l)) return luaV_strcmp(tsvalue(l), tsvalue(r)) <= 0; else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ return res; else if ((res = call_orderTM(L, r, l, TM_LT)) != -1) /* else try `lt' */ return !res; return luaG_ordererror(L, l, r);}int luaV_equalval (lua_State *L, const TObject *t1, const TObject *t2) { const TObject *tm; lua_assert(ttype(t1) == ttype(t2)); switch (ttype(t1)) { case LUA_TNIL: return 1; case LUA_TNUMBER: return nvalue(t1) == nvalue(t2); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); case LUA_TUSERDATA: { if (uvalue(t1) == uvalue(t2)) return 1; tm = get_compTM(L, uvalue(t1)->uv.metatable, uvalue(t2)->uv.metatable, TM_EQ); break; /* will try TM */ } case LUA_TTABLE: { if (hvalue(t1) == hvalue(t2)) return 1; tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } default: return gcvalue(t1) == gcvalue(t2); } if (tm == NULL) return 0; /* no TM? */ callTMres(L, tm, t1, t2); /* call TM */ return !l_isfalse(L->top);}void luaV_concat (lua_State *L, int total, int last) { do { StkId top = L->base + last + 1; int n = 2; /* number of elements handled in this pass (at least 2) */ if (!tostring(L, top-2) || !tostring(L, top-1)) { if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) luaG_concaterror(L, top-2, top-1); } else if (tsvalue(top-1)->tsv.len > 0) { /* if len=0, do nothing */ /* at least two string values; get as many as possible */ lu_mem tl = cast(lu_mem, tsvalue(top-1)->tsv.len) + cast(lu_mem, tsvalue(top-2)->tsv.len); char *buffer; int i; while (n < total && tostring(L, top-n-1)) { /* collect total length */ tl += tsvalue(top-n-1)->tsv.len; n++; } if (tl > MAX_SIZET) luaG_runerror(L, "string size overflow"); buffer = luaZ_openspace(L, &G(L)->buff, tl); tl = 0; for (i=n; i>0; i--) { /* concat all strings */ size_t l = tsvalue(top-i)->tsv.len; memcpy(buffer+tl, svalue(top-i), l); tl += l; } setsvalue2s(top-n, luaS_newlstr(L, buffer, tl)); } total -= n-1; /* got `n' strings to create 1 new */ last -= n-1; } while (total > 1); /* repeat until only 1 result left */}static void Arith (lua_State *L, StkId ra, const TObject *rb, const TObject *rc, TMS op) { TObject tempb, tempc; const TObject *b, *c; if ((b = luaV_tonumber(rb, &tempb)) != NULL && (c = luaV_tonumber(rc, &tempc)) != NULL) { switch (op) { case TM_ADD: setnvalue(ra, nvalue(b) + nvalue(c)); break; case TM_SUB: setnvalue(ra, nvalue(b) - nvalue(c)); break; case TM_MUL: setnvalue(ra, nvalue(b) * nvalue(c)); break; case TM_DIV: setnvalue(ra, nvalue(b) / nvalue(c)); break; case TM_POW: { const TObject *f = luaH_getstr(hvalue(gt(L)), G(L)->tmname[TM_POW]); ptrdiff_t res = savestack(L, ra); if (!ttisfunction(f)) luaG_runerror(L, "`__pow' (`^' operator) is not a function"); callTMres(L, f, b, c); ra = restorestack(L, res); /* previous call may change stack */ setobjs2s(ra, L->top); break; } default: lua_assert(0); break; } } else if (!call_binTM(L, rb, rc, ra, op)) luaG_aritherror(L, rb, rc);}/*** some macros for common tasks in `luaV_execute'*/#define runtime_check(L, c) { if (!(c)) return 0; }#define RA(i) (base+GETARG_A(i))/* to be used after possible stack reallocation */#define XRA(i) (L->base+GETARG_A(i))#define RB(i) (base+GETARG_B(i))#define RKB(i) ((GETARG_B(i) < MAXSTACK) ? RB(i) : k+GETARG_B(i)-MAXSTACK)#define RC(i) (base+GETARG_C(i))#define RKC(i) ((GETARG_C(i) < MAXSTACK) ? RC(i) : k+GETARG_C(i)-MAXSTACK)#define KBx(i) (k+GETARG_Bx(i))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -