A detailed explanation of the assignment type code in Lua _lua

Source: Internet
Author: User
Tags lua prev

Let's look at the entire process of the LUA VM when parsing the source code below and generating bytecode:

 foo = "Bar" local
 A, B = "A", "B"
 foo = a

First we use the Chunkyspy tool to see exactly what VM the VM will eventually produce instructions

Here, the line that starts with [numbers] is the byte code that the VM actually generates, and we see a symbiotic six-line byte code. First, you assign a constant of the constant table subscript 1 to register 0, and then setglobal the contents of register 0 to a global variable labeled 0 in the global variable table, FOO;LOADK and LOADK "a" and "B" respectively to register 0, 1, where registers 0 and 1 represent the local variables of the current function, that is, variables A and B, and finally Setglobal assigns the value of variable A to global variable Foo; the last Return01 is that the VM will eventually be generated in every chunk, and it is useless. Now it's time to compare the cleanup to the meaning of the bytecode generated by the LUA VM, and then we'll look at how and why the VM generates these bytecode.

When we use the Lual_dofile function to execute this LUA script source, there are two phases, the first is to load the script into memory, parse and generate the bytecode, and place the entire package as main chunk on the LUA stack stack, and the second is to call Lua_ Pcall execute this chunk, here we will only analyze the first process.

A few previous articles said that when Dofile would run to a function called Luay_parser,

Proto *luay_parser (lua_state *l, Zio *z, Mbuffer *buff, const char *name) {struct lexstate
 ;
 struct Funcstate funcstate;
 -- ... ...
 Funcstate.f->is_vararg = Vararg_isvararg; /* main Func. is always vararg * *
 luax_next (&lexstate);/* read-A/token
 (chunk);
 -- ... ...
 return funcstate.f;
}

Function Luay_parser The first two lines define the lexstate and funcstate struct variables, where lexstate not only holds the current lexical analysis state information, but also preserves the global state of the entire compilation system, Funcstate the structure body to hold the state data of the current function compilation. In the LUA source code will have a global function of the body, that is the main func, at the beginning of parsing the current function must be the main Func function, at this time the third row of Funcstate represents the state of the function, Because Lua prescribes that this function will inevitably receive indefinite parameters, the fifth line is_vararg the identity to Vararg_isvararg. Then the sixth line Luax_next parse the file stream to separate the first token and save it in the Lexstate T member, at which time t is the "foo" global variable. The chunk function is then invoked, where the entire process of recursive descent parsing begins:

static void Chunk (Lexstate *ls) {/
 * chunk-> {stat ['; ']} */
 int islast = 0;
 Enterlevel (LS);
 while (!islast &&!block_follow (Ls->t.token)) {
  islast = statement (LS);//Recursive Descent point
  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 is a scoping concept, so when you go to a hierarchy, you call the Enterlevel function, and the Leavelevel function is invoked when you leave the current level. First into the while loop, the current token is "foo", which is neither a Terminator nor a block-beginning morpheme, so it goes into the statement function, the statement function body is a long switch...case ... A code structure that enters a different invocation resolution branch according to the first token. In our case, we'll go to the default branch:

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 * *}}

Enter the Exprstate function:

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

The lhs_assign structure in the Forth line is to handle multivariate assignment, such as A,b,c = .... The member V type in lhs_assign describes the variable on the left side of the equal sign Expdesc, and details are shown in the previous article about Expdesc. Next, enter the Primaryexp to get and populate the EXPDESC information for the "foo" variable, which will then go into the PREFIXEXP function

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

Because the current token is "foo", it enters the Tk_name branch and invokes 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//if (v >= 0) {init_exp (Var, vlocal, V); if (!base) markupval (FS, v);
  /* Local would be used as a upval * * return vlocal; else {/* not found at the current level; try Upper one */if (Singlevaraux (Fs->prev, N, var, 0) = Vglobal) ret
   Urn Vglobal; Var->u.s.info = Indexupvalue (FS, N, var); //else is local or upval */var->k = Vupval;
  /* Upvalue in the level */return vupval; }
 }

The Singlevaraux function determines whether the variable is local, Upvalue, or global. If FS is null, then the variable is global, otherwise enter Searchvar in the current function local variable array, otherwise, according to the Prev member of FS obtains the funcstate of its parent function and passes the recursive lookup in Singlevaraux. If the front is not satisfied then the variable is Upvlaue. In this example, in line 21st, because FS has pointed to main func so its prev is null, "foo" is determined to be global and returned to the Exprstate function. After the information for "Foo" is obtained, because "foo" is not a function call, it then goes into the assignment function

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

   

In the assignment function, first determine whether the next token is "," in this case it is not the assignment of a single variable, then check the next token as "=", set up, and then call Explist1 to judge the right of the equal sign has several values, this example is 1, It then determines whether the number of variables on the left equals the number of values on the right, not equal to the Adjust_assign function, which is equal and thus enters the Luak_setoneret and Luak_storevar functions sequentially. Enter int e = Luak_exp2anyreg (FS, ex) first in Luak_storevar, and function Luak_exp2anyreg K represents a byte-code-related function, ex is the value "bar", This function also invokes Discharge2reg, which generates different bytecode according to the type of 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;
//... ...
}

Because "bar" is a constant, the LUAK_CODEABX function is called to generate a LOADK byte code. Reg to hold the register number of the loaded constant value, e->u.s.info the different meaning according to the different type value, according to the annotation we know that this time the info is the subscript of the constant array.

typedef enum {
 //
 ... VK,/    * info = index of constant in ' K '/
 vknum,/  * nval = numerical value */
 vlocal,/  * info = l ocal Register *
 /Vglobal,  /* info = index of table; aux = index of global name in ' K '
 /////...
} E Xpkind;

When the LOADK is generated, it is returned to the function above to enter the LUAK_CODEABX (FS, Op_setglobal, E, Var->u.s.info), where E is the return value of Luak_exp2anyreg representing a constant-preserving register label. Info indicates the corresponding subscript for the global table when it is a global type, so the LUAK_CODEABX function generates Setglobal bytecode, saving the values that were just loaded into the register with LOADK to the global Table at the appropriate location. So the Foo = "Bar" statement generates the corresponding bytecode in its entirety.

Next, the byte code of the local a,b = "A" and "B" statements is generated. The process is roughly the same, and the difference is that the a,b is a local variable and the assignment statement is a multivariable assignment statement, so the previous function joins the A,B variable with the Lhs_assign list. As shown in the figure:

The above mentioned is the entire content of this article, I hope you can enjoy.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.