跳转至

OpenEX VM 解释器架构

本文档主要介绍了OpenEX解释器的结构以及原理,方便您更好的开发一个简单的解释器,为了方便和执行效率起见,字节码文件架构会采用特殊的存储方法

ByteCode 字节码文件

ByteCode 字节码

OpenEX中每个字节码都有自己的存储格式以及对应的二进制代码

OperationCode 运算指令

OpenEX的运算和操作指令都为单行,可以直接被逐行解析

助记符 二进制代码 格式 说明
push 0x02 push <type> <data> 将指定类型元素压入操作栈
add 0x03 add 取栈顶两元素相加
sub 0x04 sub 取栈顶两元素相减
mul 0x05 mul 取栈顶两元素相乘
div 0x06 div 取栈顶两元素相除
and 0x07 and 取栈顶两元素进行与运算
or 0x08 or 取栈顶两元素进行或运算
not 0x09 not 取栈顶两元素进行非运算
big 0x10 big 取栈顶两元素进行大于比较运算
less 0x11 less 取栈顶两元素进行小于比较运算
equ 0x12 equ 取栈顶两元素进行等于比较运算
big_equ 0x13 big_equ 取栈顶两元素进行大于等于比较运算
less_equ 0x14 less_equ 取栈顶两元素进行大于等于比较运算

StructCode 结构指令

OpenEX结构指令代表每一个脚本中的语句,其存储采用缩进的方式

invoke调用指令

  • 二进制代码0x01
  • 助记符invoke
    格式
    1
    2
    3
    4
    5
    6
    7
    invoke
      name 调用路径(库名.函数名)
      var_num <num> 参数个数
      var_1      
        <opcode> 参数
      var_2
        <codes> 参数
    

jne判断指令

  • 二进制代码0x15
  • 助记符jne
    格式
    1
    2
    3
    4
    5
    jne
      bool      
        <opcode> 布尔表达式
      code
        <codes> 代码块
    

whi循环指令

  • 二进制代码0x16
  • 助记符whi
    格式
    1
    2
    3
    4
    5
    whi
      bool     
        <opcode> 布尔表达式
      code
        <codes> 代码块
    

fuc函数定义指令

  • 二进制代码0x17
  • 助记符fuc
    格式
    1
    2
    3
    4
    5
    6
    fuc
      var
        var_name1 参数
        var_name2
      code
        <codes> 代码
    

mov变量重赋值指令

  • 二进制代码0x18
  • 助记符mov
    格式
    1
    2
    3
    4
    mov
      name <name> 变量名
      var
        <opcode> 值
    

lar数组定义指令

  • 二进制代码0x19
  • 助记符lar
    格式
    1
    2
    3
    4
    5
    6
    7
    lar
      name <name> 变量名
      var_size <size>长度
      var
        <opcode> 值
      var
        <opcode> 值
    

lva变量定义指令

  • 二进制代码0x20
  • 助记符lva
    格式
    1
    2
    3
    4
    lva
      name <name> 变量名
      var
        <opcode> 值
    

ret返回指令

  • 二进制代码0x21
  • 助记符ret
    格式
    1
    2
    3
    ret
      var    
        <opcode> 值
    

nol空操作

  • 二进制代码0x00
  • 助记符nol
    格式
    nol
    

数据类型

因push指令需要,以下会定义一些二进制代码代表一个值的类型

OpenEX的字节码文件头由两个byte数据组成

script.ebc
0x3a 0x01
其中,0x3a为文件“魔数”,解释器会率先检查该魔数判断是否为OpenEX字节码文件
0x01代表编译的版本号,因每个小版本号更新跨度不大,该版本号只会存储大版本号,如0.2.1只会变成0.2.X并转换成对应编号存储,0x01代表AST版本的0.1.X系列

Executor执行引擎

存储模型

OpenEX解释器会有一个全局变量池以及函数池

  • 全局变量池 -负责存储global关键字定义的变量
  • 函数池 -存储脚本内定义的各种函数
  • 私有变量池 -存储local定义的变量,是线程私有的

线程管理器

因为OpenEX本质是支持多线程的,所以为统一结构,线程管理器需要具备能创建,中断,释放线程的能力,每个线程内配备一个操作栈用于表达式计算和私有变量池
如果非主线程发生解释器运行时异常,只会终止该线程的运行,其他线程不受影响,如果主线程发生运行时异常,则触发ShutdownHook后关闭解释器运行