This blog introduces the parsing mechanism of JavaScript.
The parsing process of JavaScript is divided into two phases: Compilation and execution. Compiling here refers to the Javascript preprocessing (pre-compilation ). During the pre-compilation period, the javascript interpreter completes the preprocessing of JavaScript code and converts it to bytecode. During execution, the javascript interpreter converts bytecode into binary code and runs it in sequence.
Pre-compiled Compiler
Javascript is an interpreted language, that is, compiling and execution. The general compiler and workflow are as follows:
This is the compilation principle. For more information, see my blog "Overview of compilation principles". However, for Javascript, it only requires the lexical analysis and syntax analysis stages. After creating the syntax tree, start interpretation.
Lexical Analysis
In the lexical analysis stage, the javascript interpreter first converts the pipeline stream of the Code to the mark stream, for example:
a=(b-c)
To mark the stream:
NAME "a"EQUALSOPEN_PARENTHESISNAME "b"MINUSNAME "c"CLOSE_PARENTHESISSEMICOLON
What can be implemented in the lexical analysis phase is:
- Remove comments and generate documents
- Record error information
- Complete preprocessing
Syntax analysis
In the syntax analysis phase, the tokens generated during the lexical analysis phase are used to generate a syntax tree. That is, the information collected from the program is stored in the data structure. There are two types of data structures:
- Symbol table: records variables, functions, and classes
- Syntax tree: Tree Representation of the program structure, which generates intermediate code.
For example, convert the following statement into a syntax tree:
if(typeof a=="undefined"){a=0;}
Syntax tree:
When a syntax tree cannot be constructed, a syntax error is reported and the entire code block is parsed.
The lexical analysis and syntax analysis stages are staggered. Every time a lexical mark is taken, it is sent to the syntax analyzer for analysis.
Execution period
After preparation in the compilation phase, the Code has already built an idiom tree in the memory, and the JavaScript engine will explain and execute it based on this spell structure. During the interpretation process, the engine strictly follows the scope mechanism. The Lexical scopes used by JavaScript are defined by the scope of variables and functions, depending on the source code structure.
Function
When the engine interprets and executes each function, it first creates an execution environment and a call object in this environment, this object stores all local variables, parameters, nested functions, reference functions, and parent lists in the current domain. The call object declaration cycle is the same as that of the function. When the function call is completed without external reference, it is reclaimed by the garbage collection mechanism.
At the same time, the interpreter concatenates multiple nested scopes through the scope chain, and uses this chain to search for variable values from the inside out until the global object is located, return "undefined ".
This will be further discussed in subsequent blogs.
Closure
If a function references the value of an external variable, the interpreter will create a closure for the function. The closure is a completely closed and independent scope and will not be reclaimed after the function is called, it can exist for a long time. It is recycled only when all external references of the closure are set to null. The disadvantage is that it is prone to spam flooding.
This will be further discussed in subsequent blogs.