Detailed description of the assignment type code in lua

Source: Internet
Author: User

Detailed description of the assignment type code in lua

This article mainly introduces the process of parsing and copying type code in lua, which is very detailed and comprehensive. If you need it, you can refer

Let's take a look at the entire process of lua vm parsing the following source code and generating bytecode:

?

1

2

3

Foo = "bar"

Local a, B = "a", "B"

Foo =

First, we will use the ChunkySpy tool to see what kind of vm instructions will be generated by the vm.

Here, the line starting with [number] is the real byte code generated by the vm. We can see that a total of six lines of bytecode are generated. Loadk first assigns the constant with the subscript of 1 in the constant table "bar" to register 0; then setglobal assigns the content of register 0 to the global variable table with the subscript of 0, that is, foo; loadk assigned "a" and "B" to registers 0 and 1 respectively. Here, registers 0 and 1 indicate the local variables of the current function, that is, variables a and B; finally, setglobal assigns the value of variable a to the global variable foo. The last return01 is generated by the vm at the end of each chunk, Which is useless. Now we should clear the meaning of the bytecode generated by lua vm. Next we will look at how and why the vm generates these bytecode.

When we use the luaL_dofile function to execute the lua script source code, there will be two phases. The first one is to load the script into the memory, parse tokens, generate bytecode, and wrap the entire chunk into the top of the lua stack. The second is to call lua_pcall to execute the chunk. Here we will only analyze the first process.

As mentioned in the previous articles, dofile runs to a function called luaY_parser,

?

1

2

3

4

5

6

7

8

9

10

Proto * luaY_parser (lua_State * L, ZIO * z, Mbuffer * buff, const char * name ){

Struct LexState lexstate;

Struct FuncState funcstate;

--......

Funcstate. f-> is_vararg = VARARG_ISVARARG;/* main func. is always vararg */

LuaX_next (& lexstate);/* read first token */

Chunk (& lexstate );

--......

Return funcstate. f;

}

The first two lines of the luaY_parser function define the LexState and FuncState struct variables. The LexState function not only saves the current lexical analysis status information, but also saves the global status of the entire compilation system, funcState struct to save the status data compiled by the current function. In the lua source code, there will be a global function execution body, that is, main func. At the time of parsing, the current function must be the main func function, at this time, the funcstate in the third row indicates the state of this function. lua requires that this function will inevitably receive an indefinite parameter. Therefore, the is_vararg identifier in the fifth row is set to VARARG_ISVARARG. Next, the sixth line luaX_next parses the file stream to separate the first token and save it to the t member of lexstate. t is the global variable "foo. Then the chunk function is called, and the whole process of recursive descent Parsing is started here:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

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 has the concept of a scope level. Therefore, when you enter a level, the enterlevel function is called. When you exit the current level, the leavelevel function is called. First, go to the while loop. The current token is "foo". This is neither an ending sign nor a block start word, so it will enter the statement function, the main body of the statement function is a long switch... case... code structure: enter different call resolution branches based on the first token. In this example, we enter the default Branch:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

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:

?

1

2

3

4

5

6

7

8

9

10

11

12

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 struct in the fourth line is used to handle multi-variable assignment, such as a, B, c = .... In LHS_assign, the member v type is expdesc, which describes the variable on the left of the equal sign. For details, see the Introduction to expdesc in the previous article. Next, enter primaryexp to obtain and fill in the expdesc information of the "foo" variable. This will go to the prefixexp function.

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

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", go to the TK_NAME branch and call singlevar.

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

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 at current level */

If (v> = 0 ){

Init_exp (var, VLOCAL, v );

If (! Base)

Markupval (fs, v);/* local will be used as an upval */

Return VLOCAL;

}

Else {/* not found at current level; try upper one */

If (singlevaraux (fs-> prev, n, var, 0) = VGLOBAL)

Return VGLOBAL;

Var-> u.s.info = indexupvalue (fs, n, var);/* else was LOCAL or UPVAL */

Var-> k = VUPVAL;/* upvalue in this level */

Return VUPVAL;

}

}

The singlevaraux function determines whether the variable is local, upvalue, or global. If fs is null, the variable is global. Otherwise, searchvar is used to search for the local variable array of the current function, otherwise, the FuncState of the parent function is obtained based on the prev member of fs and the recursive search is passed in to singlevaraux. If none of the preceding conditions are met, the variable is upvlaue. In this example, in row 21st, fs has pointed to main func, so its prev is null, "foo" is regarded as global and returned to the exprstate function. After obtaining the information of "foo", because "foo" is not a function call, it then enters the assignment function.

?

1

2

3

4

5

6

7

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 example, if it is not a single variable value, check that the next token is "=, call explist1 to determine the number of values on the right of the equal sign. In this example, the number of variables on the left is equal to the number of values on the right. If the number is not the same, the adjust_assign function is used to adjust the value, in this example, the luaK_setoneret and luaK_storevar functions are entered in sequence. In luaK_storevar, first enter int e = luaK_exp2anyreg (fs, ex). The K of the luaK_exp2anyreg function indicates that this function is a bytecode-related function, and the ex value is bar. this function calls discharge2reg to generate different bytecode Based on the ex type:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

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, call the luaK_codeABx function to generate the loadk bytecode. Reg is the register number for storing the loaded constant value. e-> u.s.info represents different meanings based on different types of values. According to the annotations, we know that info is the subscript of the constant array.

?

1

2

3

4

5

6

7

8

Typedef enum {

//......

VK,/* info = index of constant in 'K '*/

VKNUM,/* nval = numerical value */

VLOCAL,/* info = local register */

VGLOBAL,/* info = index of table; aux = index of global name in 'K '*/

//......

} Expkind;

After loadk is generated, it is returned to the above function and then enters luaK_codeABx (fs, OP_SETGLOBAL, e, var-> u.s.info). Where e is the return value of luaK_exp2anyreg, which indicates the register label of the constant, info indicates the corresponding subscript of the global table according to the annotation when it is of the global type. Therefore, the luaK_codeABx function will generate the setglobal bytecode, load the constant to the value in the register with loadk and save it to the corresponding location of the global table. Therefore, the foo = "bar" statement completely generates the corresponding bytecode.

The bytecode of the local a, B = "a", "B" statement is generated. The process is roughly the same. The difference is that a and B are local variables and the value assignment statement is a multi-variable value assignment statement. Therefore, the previous function uses the LHS_assign linked list to connect a and B variables. :

The above is all the content in this article. I hope you will like it.

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.