Chapter 2 (11-3)
Section 2 Local function declaration
We have studied the definition of local variables. Next we will study the method for defining local functions in Lua.
The syntax defined by the local function is:
Local function funcname (parlist) chunk end
First, Lua detects the local function keywords, knowing that the local function is defined later. Lua skips these two keywords and uses llex_next () and testnext () respectively (). The difference between testnext () and checknext () Is that checknext () expects a token to be followed. If yes, it will be read. If not, an error will be reported, testnext () is to check whether a token is followed. If it is followed, it will read the token. If it is not followed, no error will be reported.
If the two keywords "Local function" are skipped. The local function name is now available. In this case, Lua regards this local function as a local variable and registers a local variable name for this function name. Newlocalvar () is used to register a local variable (). This function adds an item to the number of local variables to record the function name. The record does not check whether the local variable already exists. However, when used, Lua will traverse the search from the beginning, that is, the local variable registered for the first time will be used.
As mentioned above, in the Syntax Parsing process, there is a data structure that is very important, that is, expdesc, which represents an expression. When defining a local function, two such data structures are used, respectively V and B. V represents this function, and B represents the body, that is, the function body. When it is parsed here, V is initialized and its type is assigned to vlocal, V-> K.
= Vlocal, and record the location of the current idle register, V-> u.s.info = FS-> freereg.
The next step is to add a pointer to the idle register and the number of local variables.
As a result, the part of the parsing function body is entered, body ().
First, a new funcstate data structure is created. Through the open_func () function, the data structure is the LS-> FS we have seen all the time. This data structure is used in Syntax Parsing. It represents a function. It has a function header called Proto. Each function uses this header. Each function records its own intermediate code, which exists in the proto header of this function, specifically in the array of LS-> FS-> F-> code. During Syntax Parsing, the entire Lua program is treated as a function, that is, the first funcstate, that is, the first LS-> fs. Then, every defined function is encountered, A new funcstate will be created and linked to LS-> FS, that is, all ls-> FS chain into a linked list. And LS-> FS is the function currently parsed.
After the function structure funcstate is created, it and its constant array are pushed into the stack.
The parameter list and function body are parsed. Ignore this because we have a general understanding of the parsing function. Assume that our function looks like this:
Local function funcname () end;
That is to say, there is no parameter table or the simplest function of the function body.
When Lua parses this function, as previously said, funcname will be registered in the local variable table, and a new funcstate data structure will be created, linked to LS-> FS, as the current function.
When Lua detects that the syntax defined by the function is correct, that is, the parameter table is included in parentheses (), the function body ends with end. After the detection, the close_func () function is executed.
This function is interesting. It contains some interesting functions. The first interesting function is removevar (), which literally removes variables. What does that mean? After the function definition is complete, the internal variables of the function are invisible to the outside. Therefore, the variables should be removed from the visible area. This function is used to handle this situation. It is easy to mark the endpc of the local variable in each function as the current PC. That is to say, to the current position, after the current Code, local variables are invisible. The visibility and scope are associated with commands. That is to say, starting from a command, local variables are visible, and ending from a command, local variables are invisible. Then, the local variable of the function is removed from the visible field.
Then an op_return command is generated through the luak_ret () function.
Finally, kill the function from LS, that is, LS-> FS = FS-> Prev. At this point, this function has been parsed. However, the script code generated by this function is in the function structure fs. Now it is kicked off. How can I call it when I want to call it?
This is the last question, but the body is not over, and the last function pushclosure (). After reading this function, we will find that, in fact, Lua did not kill this function, but saved it in its parent function. This is the case: each function can define a function. This function name is saved in the local variable table of the parent function as a local variable of its parent function. Then, the function structure funcstate will be saved in the internal function array of its parent function, that is, the header structure of each function structure, FS-> F, there will be an array of function headers, FS-> F-> P [], which contains the functions defined in this function.
Pushclosure () will first do this, that is, save the function structure in the FS-> F-> P [] of its parent function structure.
Then, an instruction op_closure is generated, indicating that a function is defined here. What does this command do?
Don't forget what we said at the beginning. A local function definition is the same as a local variable definition. An empty slot (Register) will be retained in the stack. However, what is stored in that register? This will be answered at runtime. When the Lua virtual machine runs to op_closure, a new closure will be created, and this closure will be used to initialize the reserved register, that is, the local function.
In the first two expdesc data structures, one of which is B, which represents the body, is used to store the op_closure command. The V, its V-> u.s.info stores the register location of the local function. Here, an op_closure command has been generated, but where does the generated closure exist in the stack when the command runs? That is, it should be placed in the register corresponding to the local function. The following is the function to complete this operation: luak_storevar (). The register location originally saved in E is saved in the op_closure command.
This is to create a local function, which is similar to a local variable. Writing to the present, I found that the architecture of the article is too messy. It is a draft and I will change it later.