LUA variable lookup and global variable

1. Speaking of hello world

When the print(“Hello World!”) is executed, it is obvious that a specific function of printing a string to the standard output is required. So the first thing involved here is a function search problem, that is, how to connect the string with the corresponding function. In the most common C language, this search is done by the linker: it searches for the definition of this function from all obj files, and then converts this place into the corresponding CPU call instruction. Correspondingly, for lua, there needs to be a way to associate this string with the actual function call. So the final question is: when Lua encounters a variable, how does it look for this variable?

Second, the realization of the search

1, the realization code of the search

The realization of this code is also relatively intuitive: first, search in the Local at the function level, if The search is considered to be of the VLOCAL type, otherwise the upvalue that already exists in the current function is searched, and finally it is considered to be in the global variable table by default. This “global” is a very high level, which is equivalent to the sharing of the entire lua virtual machine, that is, global variables.
The reason why these variables determine the type is that they affect the generation of instructions, and different instructions specify where to look for variables.
lua-5.3.4\src\lparser.c
/*
Find variable with given name’n’. If it is an upvalue, add this
upvalue into all intermediate functions.
*/
static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
if (fs == NULL) /* no more levels? */
init_exp(var , VVOID, 0); /* default is global */
else {
int v = searchvar(fs, n); /* look up locals at current level */
if (v >= 0 ) {/* found? */
init_exp(var, VLOCAL, v); /* variable is local */
if (!base)
markupval(fs, v); /* local will be used as an upval */
}
else {/* not found as local at current level; try upvalues ​​*/
int idx = searchupvalue(fs, n); /* try existing upvalues ​​*/< br> if (idx <0) {/* not found? */
singlevaraux(fs->prev, n, var, 0); /* try upper levels */
if (var->k = = VVOID) /* not found? */
return; /* it is a global */
/* else was LOCAL or UPVAL */
idx = newupvalue(fs, n, var); / * will be a new upvalue */
}
init_exp(var, V UPVAL, idx); /* new or old upvalue */
}
}
}

2, the processing flow of Local variables

Take the following code as Example:
local a,b,c=1,2,3
The first execution is the do while {}(testnext(ls,’,’)) loop in the function, which is equivalent to the locvars in the function The variable is registered in, and its position in it will also be a certain position.
static void localstat (LexState *ls) {
/* stat -> LOCAL NAME {‘,’ NAME} [‘=’ explist] */
int nvars = 0;
int nexps;
expdesc e;
do {
new_localvar(ls, str_checkname(ls));
nvars++;
} while (testnext(ls,’,’));
if ( testnext(ls,’=’))
nexps = explist(ls, &e);
else {
ek = VVOID;
nexps = 0;
}
adjust_assign(ls , nvars, nexps, &e);
adjustlocalvars(ls, nvars);
}

3. Treatment of global variables

For a variable g, if If the local and upvalue are not found, it is considered to use the variable name string to search from the global env, and the register is allocated for the key in the luaK_indexed function, that is, the search of global variables also requires the use of registers.
static void singlevar (LexState *ls, expdesc *var) {
TString *varname = str_checkname(ls);
FuncState *fs = ls->fs;
singlevaraux(fs, varname, var , 1);
if (var->k == VVOID) {/* global name? */
expdesc key;
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
lua_assert(var->k != VVOID); /* this one must exist */
codestring(ls, &key, varname); /* key is variable name */
luaK_indexed(fs, var, &key); /* env[varname] */
}
}

Three, print function search

1, function call Analysis

Since the symbol print is not found locally, the generated code will require searching from env, so just put the string variable in the global variable table at runtime.

2, the registration of system functions

print Because lua internal call function parameters are all a state machine (the advantage of this is that when the function pointer is called, the type of the function pointer is clear ), so it is a customized luaB_print function.

LUAMOD_API int luaopen_base (lua_State *L) {
/* open lib into global table */
lua_pushglobaltable(L);
luaL_setfuncs(L, base_funcs, 0);
/* set global _G */
lua_pushvalue(L, -1);
lua_setfield(L, -2, “_G”);
/* set global _VERSION */
lua_pushliteral(L , LUA_VERSION);
lua_setfield(L, -2, “_VERSION”);
return 1;
}

3. System registry settings

LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
const char *chunkname, const char *mode) {
ZIO z;
int status;
lua_lock(L);< br> if (!chunkname) chunkname = “?”;
luaZ_init(L, &z, reader, data);
status = luaD_protectedparser(L, &z, chunkname, mode);
if (status = = LUA_OK) {/* no errors? */
LClosure *f = clLvalue(L->top-1); /* get newly created function */
if (f->nupvalues ​​>= 1) { /* does it have an upvalue? */
/* get global table from registry */
Table *reg = hvalue(&G(L)->l_registry);
const TVal ue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
/* set global table as 1st upvalue of’f’ (may be LUA_ENV) */
setobj(L, f->upvals[0]->v, gt); luaC_upvalbarrier(L, f->upvals[0]);}} lua_unlock(L); return status;}

Leave a Comment

Your email address will not be published.