[C++] 纯文本查看 复制代码 #include <iostream>
#include <vector>
#include <cstdint>
#include <stdexcept>
enum class VM_OPCODE : uint8_t
{
NOP = 0x00,
PUSH,
POP,
ADD,
SUB,
MUL,
DIV,
PRINT,
JMP,
JNZ,
HALT
};
struct VM_CONTEXT
{
std::vector<int64_t> vStack;
size_t vEip=0;
std::vector<uint8_t> bytecode;
};
class MiniCodeVM
{
VM_CONTEXT m_ctx;
int64_t fetch_imm()
{
if (m_ctx.vEip + 4 > m_ctx.bytecode.size())
{
throw std::runtime_error("bytecode out of range");
}
int64_t val = 0;
val |= m_ctx.bytecode[m_ctx.vEip + 0] << 0;
val |= m_ctx.bytecode[m_ctx.vEip + 1] << 8;
val |= m_ctx.bytecode[m_ctx.vEip + 2] << 16;
val |= m_ctx.bytecode[m_ctx.vEip + 3] << 24;
m_ctx.vEip += 4;
return val;
}
public:
void load_bytecode(const std::vector<uint8_t>& code)
{
m_ctx.bytecode = code;
m_ctx.vEip = 0;
m_ctx.vStack.clear();
}
void run()
{
while (m_ctx.vEip < m_ctx.bytecode.size())
{
VM_OPCODE op = static_cast<VM_OPCODE>(m_ctx.bytecode[m_ctx.vEip]);
m_ctx.vEip++;
switch (op)
{
case VM_OPCODE::NOP:
break;
case VM_OPCODE::PUSH:
{
int64_t val = fetch_imm();
m_ctx.vStack.push_back(val);
}
break;
case VM_OPCODE::POP:
{
if (m_ctx.vStack.empty()) {break;}
m_ctx.vStack.pop_back();
}
break;
case VM_OPCODE::ADD:
{
auto b = m_ctx.vStack.back(); m_ctx.vStack.pop_back();
auto a = m_ctx.vStack.back();m_ctx.vStack.pop_back();
m_ctx.vStack.push_back(a + b);
}
break;
case VM_OPCODE::SUB:
{
auto b = m_ctx.vStack.back(); m_ctx.vStack.pop_back();
auto a = m_ctx.vStack.back();m_ctx.vStack.pop_back();
m_ctx.vStack.push_back(a - b);
}
break;
case VM_OPCODE::MUL:
{
auto b = m_ctx.vStack.back(); m_ctx.vStack.pop_back();
auto a = m_ctx.vStack.back();m_ctx.vStack.pop_back();
m_ctx.vStack.push_back(a * b);
}
break;
case VM_OPCODE::DIV:
{
auto b = m_ctx.vStack.back(); m_ctx.vStack.pop_back();
auto a = m_ctx.vStack.back();m_ctx.vStack.pop_back();
m_ctx.vStack.push_back(a / b);
}
break;
case VM_OPCODE::PRINT:
{
if (!m_ctx.vStack.empty())
{
std::cout <<"[VM Output]" << m_ctx.vStack.back() << std::endl;
}
}
break;
case VM_OPCODE::JMP:
{
int64_t offset =static_cast<int64_t>(fetch_imm());
m_ctx.vEip = offset;
}
break;
case VM_OPCODE::JNZ:
{
int64_t offset = static_cast<int64_t>(fetch_imm());
if (!m_ctx.vStack.empty())
{
if (m_ctx.vStack.back() != 0)
{
m_ctx.vEip = offset;
}
}
}
break;
case VM_OPCODE::HALT:
{
std::cout << "VM halted successfully" << std::endl;
m_ctx.vEip = m_ctx.bytecode.size();
}
break;
default:
throw std::runtime_error("invalid opcode");
}
}
}
};
std::vector<uint8_t> compile_sample()
{
std::vector<uint8_t> code;
// PUSH 10
code.push_back(static_cast<uint8_t>(VM_OPCODE::PUSH));
for (int i = 0; i < 4; i++) code.push_back((10 >> (8 * i)) & 0xFF);
// PUSH 20
code.push_back(static_cast<uint8_t>(VM_OPCODE::PUSH));
for (int i = 0; i < 4; i++) code.push_back((20 >> (8 * i)) & 0xFF);
// ADD -> 栈顶=30
code.push_back(static_cast<uint8_t>(VM_OPCODE::ADD));
// PUSH 5
code.push_back(static_cast<uint8_t>(VM_OPCODE::PUSH));
for (int i = 0; i < 4; i++) code.push_back((5 >> (8 * i)) & 0xFF);
// MUL -> 30*5=150
code.push_back(static_cast<uint8_t>(VM_OPCODE::MUL));
// PRINT 输出结果
code.push_back(static_cast<uint8_t>(VM_OPCODE::PRINT));
// 停止虚拟机
code.push_back(static_cast<uint8_t>(VM_OPCODE::HALT));
return code;
}
int main()
{
MiniCodeVM vm;
vm.load_bytecode(compile_sample());
vm.run();
std::cin.get();
return 0;
} |