天宇虚拟机(第一代)包含虚拟机程序与编译器程序。项目开发时间表如下:
项目名称 | 开始时间 | 耗时 |
---|---|---|
虚拟机 | 2019-03 | 3个月 |
编译器 | 2019-05 | 1个月 |
天宇虚拟机采用模拟硬件运行的方式实现,通过解析函数指令进行执行。函数指令与C语言调用函数相同,主要包括:函数名+函数边界+参数+结束符组成,其样式为:function(prama1,prama2,...);
。
函数名为指令,分为内存、设备、网络、硬盘、程序、输入输出和运算模块,支持中英文两种指令类型。
在编写指令参数时,包含设定关键字、表达式和其他文本类型三种。其他文本类型主要用于在提供路径、IP地址等情况下需要;设定关键字用于为程序提供部分固定的常用表示方法,并用于当前已经预设的设备;表达式是整数型的表达式,使用{}进行包围,可使用+、-、*、/和^。其运算符的优先级与日常的四则运算相同,^>*,/>+,-,可以使用()改变其运算顺序。
因为本虚拟机需要操作内存,所以在表达式中引入[]用于获取当前内存块的数据,以提供多级寻址的能力。在使用[]运算符时,还应该注意,默认取值为64位数据,当需要改变获取内存的长度时,需要使用:运算符。使用规则为[表达式]:+数据长度,数据长度规定为:1、2、4、8,其中,长度为8时可以省略该运算符。
除了指令系统,天宇虚拟机还提供了中断功能,用于为设备和IO系统提供及时的数据相应,在当前的系统中,提供了针对常用异常和调用的中断。
下面将针对具体的指令系统和中断系统进行说明。
- 内存模块访问指令
中文指令 | 英文指令 | 参数列表 | 说明 |
---|---|---|---|
设定内存 | set | 内存空间大小 | 用于设置程序的初始化大小 |
申请内存 | new | 内存块表达式 | 用于申请信的空闲空间 |
空间大小 | |||
释放内存 | free | 内存块表达式 | 用于释放手动申请的空间 |
初始内存 | minit | 内存块表达式 | 用于初始化、批量初始化连续的内存空间 |
操作数类型 | |||
立即数 | |||
重复次数 | |||
获取时间 | tread | 内存块表达式 | 用于获取指定的时间放入到指定的内存区块 |
时间类型 | |||
写入时间 | twrite | 内存块表达式 | 用于写入指定的时间 |
时间类型 | |||
时间同步 | tsync | - | 用于同步时间 |
- 设备模块指令
中文指令 | 英文指令 | 参数列表 | 说明 |
---|---|---|---|
激活设备 | dact | 设备中断号 | 用于激活指定设备,使设备进入运行状态 |
暂停设备 | dpause | 设备中断号 | 用于暂停设备,使设备进入暂停状态 |
复位设备 | dreset | 设备中断号 | 用于设置设备回复初始化 |
关闭设备 | dclose | 设备中断号 | 用于关闭设备,使设备离线 |
读设备 | dread | 设备中断号 | 用于从设备基础缓冲区中将数据读入新建的内存中 |
内存块表达式 | |||
写设备 | dwrite | 设备中断号 | 将数据从指定的内存中写入到指定的设备, |
内存块表达式 | 并触发指定设备的中断服务程序 | ||
数据长度 |
- 网络模块
中文指令 | 英文指令 | 参数列表 | 说明 |
---|---|---|---|
新建连接 | connect | 网络连接编号 | 用于新建一个网络连接 |
IP地址 | |||
IP端口号 | |||
IP地址类型 | |||
网络协议 | |||
网络连接类型 | |||
暂停连接 | npause | 网络连接编号 | 用于暂停一个网络连接 |
恢复连接 | nreset | 网络连接编号 | 用于将一个网络连接从暂停中恢复 |
结束连接 | stop | 网络连接编号 | 用于将网络连接终止并释放其占用的资源 |
获取端口 | getport | 网络连接编号 | 获取指定网络连接的服务器/客户端IP地址端口 |
端口类型 | |||
内存块表达式 | |||
发送数据 | send | 网络连接编号 | 用于将内存中的指定数据发送到指定连接上 |
内存块表达式 | |||
数据长度 | |||
接受数据 | receive | 网络连接编号 | 从指定连接中获取接收到的数据 |
内存块表达式 |
- 硬盘模块
中文指令 | 英文指令 | 参数列表 | 说明 |
---|---|---|---|
新建 | create | 路径 | 在硬盘中创建指定的目录/文件 |
文件类型 | |||
删除 | delete | 路径 | 从硬盘中删除指定的目录/文件 |
文件类型 | |||
打开文件 | fopen | 文件标志编号 | 打开指定文件 |
文件路径 | |||
写入方式 | |||
关闭文件 | fclose | 文件标志编号 | 关闭打开的文件 |
文件指向 | position | 文件标志编号 | 修改文件访问位置 |
光标指向位置 | |||
读文件 | fread | 文件标志编号 | 用于将文件中的部分数据读入指定的内存 |
内存块表达式 | |||
读取文件长度 | |||
写文件 | fwrite | 文件标志编号 | 用于将指定内存块中的数据写入文件 |
内存块表达式 | |||
数据长度 | |||
拷贝文件 | fcopy | 源文件路径 | 用于拷贝指定文件 |
目标文件路径 |
- 程序模块
中文指令 | 英文指令 | 参数列表 | 说明 |
---|---|---|---|
本地结束 | end | - | 用于程序最后一条指令结束后的自动处理 |
启动进程 | pinit | 文件路径 | 用于打开文件并创建新进程后执行 |
结束进程 | pend | - | 结束正在执行的进程 |
切换进程 | pswitch | - | 用于暂停当前进程并进入下一个进程 |
加载文件 | tinit | 加载文件标识 | 用于打开文件并将代码加载至指令空间 |
文件路径 | |||
结束加载 | tend | 加载文件标识 | 从指令空间中移除指定的代码 |
外部调用 | callo | 加载文件标识 | 用于指示程序进入一个新的代码空间中 |
标识符 | |||
本地调用 | call | 标识符 | 指示程序进入新的过程,并保存当前的执行位置 |
结束调用 | ret | - | 结束当前过程,并返回上一个过程 |
跳转 | jmp | 标识符 | 无条件转移指令,进入新过程,但不保存当前执行位置 |
正跳转 | jns | 标识符 | 当运算标识符为正时转移到新的过程,不保存当前执行位置 |
负跳转 | js | 标识符 | 当运算标识符为负时转移到新的过程,不保存当前执行位置 |
零跳转 | jz | 标识符 | 当运算标识符为零时转移到新的过程,不保存当前执行位置 |
入栈 | push | 内存块表达式 | 将指定数据送入公共数据堆栈 |
出栈 | pop | 内存块表达式 | 将公共数据堆栈栈顶返回到指定的内存中 |
注:当前实例程序尚未加入对多线程、多进程的支持,故线程、进程操作指令无效
- 输入输出模块
中文指令 | 英文指令 | 参数列表 | 说明 |
---|---|---|---|
显示输出 | 内存块表达式 | 用于将指定的内存数据显示在控制台中,采用系统默认编码 | |
数据长度 | |||
字符串 | 将字符串输出在控制台中 | ||
显示字符 | putc | 内存块表达式 | 将指定内存的字符显示在控制台中 |
键盘输入 | scan | 内存块表达式 | 从键盘缓冲区中输入指定长度的数据到内存(内存需要自行申请) |
数据长度 |
- 运算模块
中文指令 | 英文指令 | 参数列表 | 说明 |
---|---|---|---|
加法 | add | 操作数类型 | 用于将后两个内存块中的指定大小数据相加后保存在第一个内存块 |
内存块表达式 | |||
内存块表达式 | |||
内存块表达式 | |||
减法 | sub | 操作数类型 | 用于将后两个内存块中的指定大小数据相减后保存在第一个内存块 |
内存块表达式 | |||
内存块表达式 | |||
内存块表达式 | |||
乘法 | mul | 操作数类型 | 用于将后两个内存块中的指定大小数据相乘后保存在第一个内存块 |
内存块表达式 | |||
内存块表达式 | |||
内存块表达式 | |||
除法 | div | 操作数类型 | 用于将后两个内存块中的指定大小数据相除后的商保存在第一个内存块 |
内存块表达式 | |||
内存块表达式 | |||
内存块表达式 | |||
求余 | mod | 操作数类型 | 用于将后两个内存块中的指定大小数据求余后的余数保存在第一个内存块 |
内存块表达式 | |||
内存块表达式 | |||
内存块表达式 | |||
逻辑与 | and | 操作数类型 | 用于将后两个内存块中的指定大小数据按位相与后保存在第一个内存块 |
内存块表达式 | |||
内存块表达式 | |||
内存块表达式 | |||
逻辑或 | or | 操作数类型 | 用于将后两个内存块中的指定大小数据按位或后保存在第一个内存块 |
内存块表达式 | |||
内存块表达式 | |||
内存块表达式 | |||
逻辑异或 | xor | 操作数类型 | 用于将后两个内存块中的指定大小数据按位异或后保存在第一个内存块 |
内存块表达式 | |||
内存块表达式 | |||
内存块表达式 | |||
逻辑非 | not | 操作数类型 | 用于将内存块中的数据按位取反后保存在原内存块 |
内存块表达式 | |||
随机数 | rand | 内存块表达式 | 用于生成一个32位的指定范围的随机数并保存在指定的内存块 |
起始值 | |||
结束值 |
IP类型
4代IP IPv4 IP地址类型 IP地址长度为32位 6代IP IPv6 IP地址长度为128位
协议类型
TCP协议 TCP/IP 协议类型 可靠的传输服务协议 UDP协议 UDP 不可靠的传输服务协议
服务类型
服务器 Server 连接模式 只用于接收数据的连接 客户端 Client 只用于发送数据的连接 混合模式 Mix 可用于发送与接收数据的连接
端口类型
接收端口 Server 端口类型 用于接收数据的端口 发送端口 Client 用于发送数据的端口 自动端口 Auto 自动的端口类型,默认为服务器端口,无服务器时为客户端端口
文件类型
目录 Entry 路径类型 指定路径为目录 文件 File 指定路径为文件
文件操作类型
追加写入 append 文件写入方式 将数据写入到文件的末尾 覆盖写入 cover 从文件指针开始处写入数据并覆盖掉原有数据 新建写入 create 创建新文件并从头写入,如果文件存在则删除
设备状态
设备正常 DS_OK 设备运行状态 设备暂停 DS_PU 设备异常 DS_ER
时间类型
时间年 Year 时间操作类型 时间月 Month 时间日 Day 时间小时 Hour 时间分 Minute 时间秒 Second
系统枚举是用于模块间调用的指令,包括错误中断以及状态标识,具体如下。
内存异常中断
Mem_Full 内存满异常 Time_Error 时间异常 Over_Flow 内存溢出 Out_Bounds 内存越界
设备异常中断
Add_Failed 设备添加失败 Not_Exist 设备不存在(设备不在设备表中) Off_Line 设备离线(设备关闭或卸载) Work_Failed 设备异常 Interrupt_Error 中断异常
网络连接异常中断
Connection_Exist 网络连接已存在 Create_Error 建立连接失败 ReConnection_Err 重连失败 Send_Failed 数据发送失败
符号值
Positive 正数标志 Negative 负数标志 Zore 零标志
设备运行状态
Closed 设备处于关闭状态 Running 设备正在运行 Paused 设备已暂停 Anomalous 设备运行异常
时间类型
时间年 Year 时间月 Month 时间日 Day 时间小时 Hour 时间分 Minute 时间秒 Second
IP类型
4代IP IPv4 6代IP IPv6
协议类型
TCP协议 TCP/IP UDP协议 UDP
服务类型
服务器 Server 客户端 Client 混合模式 Mix
端口类型
接收端口 Server 发送端口 Client 自动端口 Auto
异常中断号是用于程序内部的调用指令,包括错误中断以及系统调用中断,具体的中断如下表所示。其他未显示的中断号为未分配中断,后期的开发中可以进行扩充。
关键字名 | 助记符 |
---|---|
0x00 | 数学异常-除零中断 |
0x01 | 数学异常-计算溢出 |
0x10 | 数据异常-数组越界 |
0x11 | 数据异常-空地址 |
0x12 | 缺页中断 |
0x13 | 内存申请中断 |
0x14 | 内存释放中断 |
0x15 | 获取时间中断 |
0x16 | 修改时间中断 |
0x17 | 同步时间中断 |
0x18 | 系统异常-堆栈溢出 |
0x19 | 系统异常-堆栈越界 |
0x1A | 系统异常-内存溢出 |
0x20 | 进程切换 |
0x21 | 进程结束 |
0x22 | 结束正在执行的线程(文件)并回退 |
0x23 | 加载进程 |
0x24 | 载入线程 |
0x30 | 键盘输入 |
0x31 | 显示输出 |
0x33 | 数据源空 |
0x40 | 创建网络连接 |
0x41 | 发送数据 |
0x42 | 接收数据 |
0x43 | 获取网络端口号 |
0x45 | 暂停网络连接 |
0x46 | 复位网络连接 |
0x47 | 关闭网络连接 |
0x50 | 设备中断-激活设备 |
0x51 | 设备中断-暂停设备 |
0x52 | 设备中断-复位设备 |
0x53 | 设备中断-关闭设备 |
0x54 | 设备中断-读设备 |
0x55 | 设备中断-写设备 |
0x60 | 打开文件 |
0x61 | 关闭文件 |
0x62 | 读文件 |
0x63 | 写文件 |
0x64 | 拷贝文件 |
0x65 | 移动指针 |
0x67 | 创建文件 |
0x68 | 删除文件 |
0xE0 | 核心中断-设置时间片 |
0xE1 | 核心中断-获取时间片 |
0xE2 | 核心中断-获取核心数 |
注:部分多线程、多进程相关的中断当前只进行了定义,未进行具体的实现,因此暂时不可使用。部分异常在当前的设置环境中还未被使用。
PL0语法的EBNF表示如下:
<表达式> | ::= | [+|-]<项>{<加法运算符><项>} |
<项> | ::= | <因子>{<乘法运算符><因子>} |
<因子> | ::= | <标识符>|<无符号整数>|'('<表达式>')' |
<加法运算符> | ::= | + | - |
<乘法运算符> | ::= | * | / |
<关系运算符> | ::= | = | # | < | <= | > | >= |
<条件语句> | ::= | IF<条件>THEN<语句> |
<过程调用语句> | ::= | CALL<标识符> |
<当型循环语句> | ::= | WHILE<条件>DO<语句> |
<读语句> | ::= | READ '('<标识符>{,<标识符>}')' |
<写语句> | ::= | WRITE '('<表达式>{,<表达式>}')' |
<字母> | ::= | a | b | … | X | Y | Z |
<数字> | ::= | 0 | 1 | … | 8 | 9 |
符号 | 说明 |
---|---|
PL0_ConstSym | Const |
PL0_VarSym | Var |
PL0_ProcedureSym | Procedure |
PL0_BeginSym | Begin |
PL0_EndSym | End |
PL0_OddSym | Odd |
PL0_IfSym | If |
PL0_ThenSym | Then |
PL0_CallSym | Call |
PL0_WhileSym | While |
PL0_DoSym | Do |
PL0_ReadSym | Read |
PL0_WriteSym | Write |
PL0_Dot | '.' |
PL0_Comma | ',' |
PL0_Semicolon | ';' |
PL0_Equal | '=' |
PL0_Become | ':=' |
PL0_Plus | '+' |
PL0_Sub | '-' |
PL0_LBrace | '(' |
PL0_RBrace | ')' |
PL0_Mul | '*' |
PL0_Div | '/' |
PL0_Nequal | '#' |
PL0_Less | '< |
PL0_LessEqual | '<=' |
PL0_Greater | '>' |
PL0_GreaterEqual | '>=' |
PL0_ID | 标识符类型,由字母与数字组成,字母开头 |
PL0_Number | 全部由数字组成 |
PL0_ERROR | 错误单词 |
编译器的语法分析采用自下而上的分析方式,由常量分析开始,以此完成变量、子过程的分析。语法分析进行的同时会根据PL0语法与TYVM指令系统的对应完成目标代码的输出。语法分析器的调用过程图如下:
- Compiler.exe
Compiler.exe为控制台程序,通过CMD或Power Shell命令完成调用,下表为程序的命令参数。
参数 | 参数值 | 说明 |
---|---|---|
-l | <directory> | 独立的词法分析程序,将词法分析结果输出至控制台 |
-c | <directory> [-o] | 执行完整的编译过程,生成.tyh文件,-o为可选参数 |
-o | <outfile> | 指定编译输出文件,只能用于-c命令参数之后,如果不使用则输出为默认文件 |
-h | - | 获取帮助 |
- PL0_Comletion.DLL
PL0_Compeltion.DLL使用C#语言在.Net Standard平台上实现,命名空间为PL0_Completion。
方法一:使用时通过创建Compiler对象完成针对编译器的初始化,通过调用
LexAnalys
和Compiler
完成编译。
方法二:通过使用SyntaxAnalysisUnit类和LexAnalysisUnit类完成。当使用该方法时,需注意类的关联。
注:在使用第二种方法时,由于采用了默认的访问策略,可能需要您自行修改部分类的访问控制符,并重新生成该项目。
天宇虚拟机采用C#语言在.Net Standard平台上实现,基础命名空间为SkyVM,该项目可以放入所有基于C#开发的程序中(项目版本不能低于.netstandard2.0)。在使用时需要将5个模块都加入项目中。如下图所示为TYVM的系统功能框架。
模块 | 文件名 | 命名空间 | 功能 |
---|---|---|---|
分析模块 | SkyVM.AnaModule.dll | SkyVM.AnaModule | 分析模块主要提供文件编译解释和程序段生成功能,用于将文本代码转换为程序可读取的指令 |
核心模块 | SkyVM.CoreModule.dll | SkyVM.CoreModule SkyVM.CoreModule.Complexs | 核心模块包含数学运算、逻辑运算与复杂运算器,提供基本运算与复杂/用户自定义运算 |
执行模块 | SkyVM.ExModule.dll | SkyVM.ExModule | 指定模块包含核心控制器与代码执行组件,提供代码执行、数据操作、指令操作控制功能 |
接口模块 | SkyVM.InterfaceModule.dll | SkyVM.InterfaceModule | 接口模块为数据接口包,包含所有底层原件的数据通讯接口 |
I/O模块 | SkyVM.IOModule.dll | SkyVM.IOModule | 包含网络与基本输入输出控制器组件 |
项目各模块之间通过接口进行连接,使用的接口列表如下所示:
接口名 | 方法 | 说明 | 异常 |
---|---|---|---|
ICache | byte[] Get(long,long,int) |
获取指定段页的指定大小数据 | 使用IMemoryCacheInterrupt提交异常中断,中断值见内存异常中断 |
void Set(long,long,byte[]) |
向指定段页写入数据 | ||
void Bad(long,long) |
清除缓存中指定段页的数据 | ||
MemoryBase | MemoryBlock ReadMemory(long,out long) |
从内存中读取指定内存块 | out值为-1时,内存出现异常,MemoryBlock返回null时出现异常 |
long ApplyMemory(long, out long) |
申请指定大小的内存 | ||
void ReleaseMemory(long) |
释放指定内存块 | ||
IALUnit | Symbol_Flag Symbol |
获取运算结果符号 | 符号值见符号值,计算方法返回bool型标志,返回true为溢出,否则为未溢出 |
bye[] Calculate(out bool,string,CalculateParameter[]) |
计算方法 | ||
bool OperateTest(string) |
运算符测试 | ||
IDeviceControl | void AddDevice(int,IOBase) |
添加一个设备 | 使用IDeviceControlInterrupt提交异常中断,中断值见设备异常中断,设备包含设备运行状态Device_State,具体值见设备运行状态 |
void DeleteDevice(int) |
删除一个设备 | ||
object[] GetDevices |
获取所有设备 | ||
object GetDevice(int) |
获取指定中断的设备 | ||
void SetInterrupt(int,int) |
设置中断号 | ||
void AddInterruptService(int,int,string[]) |
添加中断服务程序 | ||
void DelInterruptService(int,int) |
删除指定中断服务程序 | ||
void CleanInterruptService(int) |
清除指定设备的所有中断服务程序 | ||
TimeBase | void SyncTime() |
同步时间 | TimeOperation_Type值见时间类型 |
short ReadTime(TimeOperation_Type) |
读取指定时间 | ||
void WriteTime(short,TimeOperation_Type) |
写入指定时间 | ||
void Save() |
保存时间 | ||
IOBase | void Run() |
启动设备 | 设备基类包含设备状态值,具体值见设备运行状态 |
void Stop() |
停止设备 | ||
void Pause() |
暂停设备 | ||
void Reset() |
重置设备 | ||
byte[] Get |
获取设备数据 | ||
byte[] Set |
向设备写入数据 | ||
INetControl | void CreateConnection(string,int,IP_Type,Protocol_Type,Connection_Model) |
创建连接 | 异常通过网络控制器终端接口INetControlInterrupt提交,具体异常值见网络连接异常中断;IP_Type类型值见IP类型;Protocol_Type见协议类型;Connection_Model见服务类型;Prot_Type见端口类型 |
void PauseConnection(int) |
暂停连接 | ||
void ResetConnection(int) |
重置连接 | ||
void StopConnection(int) |
停止连接 | ||
int GetPort(int,Port_Type) |
获取连接端口 | ||
void Send(int,byte[]) |
通过指定连接发送数据 | ||
byte[] Receive(int) |
从指定连接获取数据 | ||
IExecutorControl | object Interrupt(int,InterruptCode,object[]) |
核心中断请求 | 执行单元接口用于为底层提供异常请求与数据请求,具体中断说明异常中断表 |
- 虚拟机符号表数据结构
- 虚拟机程序块数据结构