Construct a script engine using C language (2)
Author: kevin_qing
Please note
Considering that the script compiler can be implemented independently as a process, and the compiler needs to debug the results of the script compiler,
At present, the development starts from the underlying Virtual Machine section.
1. Virtual Machine structure.
Considering that internal function definitions are not currently supported, it is more convenient to expand the stack in the future by using registers.
Variable register Reg [256] Where Reg [0] is the returned value when an external call is stored
IP address of the instruction register;
Comparison register cflag;
Code segment and data segment are all virtual commands that cannot be rewritten
1. virtual machine running mode
Using function arrays, commands are encoded sequentially and aligned in word mode to accelerate array indexing.
Runtime functions
Bool run (){
While (Brun _){
Uint16_t op = op_readw ();
Assert (OP> = 0) & (OP <countof (vmop ));
Vmop [op] ();
}
}
2. Command Definition
[R] indicates Reg [N]
[I] immediate count
[S] string
[F] external function ID
[IP] Absolute IP Address
MoV class:
MoV [r] [R]
MoV [r] [I]
Comparison commands
Function call and switch
Sreset // reset the selected queue
Case [I] [IP] // select ID/IP Pair
Switch [R] // start to jump
--------------------------
Freset // reset external function parameter queue
Fpush [R] // Add a numeric Parameter
Fpush [s] // Add a string parameter
Fpush [I]
Fcall [f] // call a function
---------------------------
The switch can be compared multiple times without using virtual commands, but within vmop_switch.
If the input case is sorted, it will save a lot of time.
--------------------------------------------------------------------------
The fcall parameter queue makes variable parameters like printf feasible, that is, all external functions can be variable parameters.
Here is my external Function Definition
# Define SC _api _ cdecl
Typedef int (SC _api * fp_ SC _api) (INT nparm ,...);
Struct SC _api_tab {
Fp_ SC _api Papi;
Int nparm;
Const char * apiname;
};
# Define decl_scapi (name, nparm) {& name, nparm, # name}
Extern const SC _api_tab api_table [];
SC _api_tab api_table [] = {
Decl_acapi (say, 1 ),
.....
};
Implementation of vmop_fcall: using inline assembly, because neither c nor C ++ can dynamically implement variable parameter calls.
Vmop_fcall (){
Int nparm = This-> nparm;
DWORD * pparm = paio_parm;
Word FD = ipgetw ();
Void * pF = api_table [FD]. Papi;
Dword retc;
_ ASM {
MoV ECx, nparm
INC ECx
MoV EBX, pparm
MoV edX, PF
Push_loop:
Dec ECx
JZ call_fun
MoV eax, [EBX]
Add EBX, 4
Push eax
JMP push_loop
Call_fun:
MoV ECx, nparm
INC ECx
Push ECx
Call edX
MoV RETC, eax
Pop ECx
Dec ECx
SHL ECx, 2
Add ESP, ECx
}
Reg [0] = RETC;
}
}
Fcall has not been optimized yet
Other commands are easy to implement.
Debugging:
It is easy to implement the single-step execution and register reference.
Disassembly I implemented through String Array
Const char * op _ [] = {
"Halt ",
"Mov", // move R
"Mov", // move R I
.....
};
Const uint32_t op_size [] = {
0,
2,
4,
....
};
You can use the lookup table in disassembly.