Skip to content

Instantly share code, notes, and snippets.

@roachsinai
Last active October 13, 2023 07:22
Show Gist options
  • Save roachsinai/e670d0281ce6973682fa17bd12416ff3 to your computer and use it in GitHub Desktop.
Save roachsinai/e670d0281ce6973682fa17bd12416ff3 to your computer and use it in GitHub Desktop.
// https://www.zhihu.com/question/33084689/answer/58994758
#include <stdio.h>
#include <string.h>
typedef struct inst
{
unsigned char code; // 指令
unsigned char cond; // 执行该指令的条件
short p1, p2; // 参数1、2
} inst_t;
typedef unsigned short data_t; // 我们操作的就是16位数
typedef struct vm_state
{
int ip; // 指令ptr
int flag; // 记录最后判断的标志
inst_t *code; // 代码段地址
data_t *data; // 数据段地址
} vm_state_t;
#define IADD 1 // 加法
#define ISUB 2 // 减法
#define ICMP 3 // 判断
#define IJMP 4 // 跳转
#define IMOV 5 // 赋值
#define ISTIP 6 // 保存IP
#define ILDIP 7 // 设置IP(跳转)
#define ILD 8 // 加载一个立即数
#define IOUT 9 // 输出
#define ISTOP 255 // 挂起虚拟机
#define FNA 0 // 任何状态下都执行
#define FEQ 1 // 状态为“相等”时执行
#define FNE 2 // 状态为“不等”时执行
void execute(vm_state_t *state)
{
for (;;) // 执行到挂起为止
{
inst_t current = state->code[state->ip];
state->ip++; // 取出指令以后自动ip后移
if (current.cond != FNA && current.cond != state->flag)
// 该指令要求的状态不符合当前状态,略过
continue;
switch (current.code)
{
case IADD:
// 将p1指向的数据加上p2指向的数据
state->data[current.p1] += state->data[current.p2];
break;
case ISUB:
state->data[current.p1] -= state->data[current.p2];
break;
case ICMP:
// 比较p1指向的数据和p2指向的数据
if (state->data[current.p1] == state->data[current.p2])
state->flag = FEQ;
else
state->flag = FNE;
break;
case IJMP:
// 跳转,指令根据p1进行偏移
state->ip += current.p1;
break;
case IMOV:
// 将p1指向的数据设置为p2指向的数据
state->data[current.p1] = state->data[current.p2];
break;
case ISTIP:
// 把IP保存到p1指向的数据
state->data[current.p1] = (data_t) state->ip;
break;
case ILDIP:
// 将IP设置为p1指向的数据,该指令会导致跳转
state->ip = state->data[current.p1];
break;
case ILD:
// 将立即数p2加载到p1指向的数据
state->data[current.p1] = current.p2;
break;
case IOUT:
// 输出p1指向的数据
printf("%d\n", state->data[current.p1]);
break;
case ISTOP:
return;
}
}
}
inst_t sample_code[] =
{
{ ILD, FNA, 2, 101 },
{ ILD, FNA, 3, 1 },
{ ILD, FNA, 1, 1 },
{ ILD, FNA, 0, 0 },
{ ICMP, FNA, 1, 2 },
{ IJMP, FEQ, 3, 0 },
{ IADD, FNA, 0, 1 },
{ IADD, FNA, 1, 3 },
{ IJMP, FNA, -5, 0 },
{ IOUT, FNA, 0, 0 },
{ ISTOP, FNA, 0, 0 }
};
data_t data_seg[16];
int main(int argn, char *argv[])
{
vm_state_t state;
memset(&state, 0, sizeof(state));
state.code = sample_code;
state.data = data_seg;
execute(&state);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment