动手做汇编解释器【3】
跳转语句
- 增加了条件跳转指令,无条件跳转指令
- 增加了cmp,没有这个指令,无法进行跳转
int cmp_flag = 0;
作为cmp比较结果的标志位
- opcode_map是指令hash,所有支持的指令都在这个hash的key中,不在hash的key中的指令运行抛出异常。
- labels标签hash,记录标签标注指令的ip(索引)。
- instructions存放指令集。
- registers为寄存器。
代码如下:
#include
#include
#include
#include
#include
class AsmVM {
public:
AsmVM() {
initRegs();
initOpcodes();
}
void loadProgram(const std::vector<std::string>& program);
void execute();
double getRegVal(const std::string& regName);
private:
size_t ip = 0;
bool running = true;
int cmp_flag = 0;
std::unordered_map<std::string, int> opcode_map;
std::unordered_map<std::string, size_t> labels;
std::vector<std::string> instructions;
std::unordered_map<std::string, double> registers;
void initRegs();
void initOpcodes();
bool isRegister(const std::string& name);
void executeInstruction(const std::string& instruction);
void jumpToLabel(const std::string& label);
double getValue(const std::string& arg);
};
void AsmVM::loadProgram(const std::vector<std::string>& program) {
for (size_t i = 0; i < program.size(); i++) {
std::string codeLine = program[i];
std::transform(codeLine.begin(), codeLine.end(), codeLine.begin(), ::tolower);
codeLine.erase(0, codeLine.find_first_not_of(" "));
if (codeLine.back() == ':') {
std::string label = codeLine.substr(0, codeLine.size() - 1);
labels[label] = instructions.size();
}
else {
instructions.push_back(codeLine);
}
}
}
void AsmVM::execute() {
while (running && ip < instructions.size()) {
executeInstruction(instructions[ip]);
ip++;
}
}
void AsmVM::initRegs() {
registers = { {"eax", 0}, {"ebx", 0}, {"ecx", 0}, {"edx", 0} };
}
void AsmVM::initOpcodes() {
opcode_map = {
{"mov", 1}, {"add", 1}, {"sub", 1}, {"mul", 1}, {"div", 1},
{"cmp", 1}, {"jmp", 1}, {"jl", 1}, {"jg", 1}, {"je", 1}, {"jne", 1},
{"hlt", 1}, {"out", 1}
};
}
double AsmVM::getRegVal(const std::string& regName) {
if (registers.find(regName) == registers.end()) {
throw std::runtime_error("寄存器不存在: " + regName);
}
return registers.at(regName);
}
bool AsmVM::isRegister(const std::string& name) {
return registers.find(name) != registers.end();
}
void AsmVM::executeInstruction(const std::string& instruction) {
std::istringstream iss(instruction);
std::string opcode, args, arg1, arg2;
iss >> opcode;
std::getline(iss, args);
args.erase(0, args.find_first_not_of(" "));
if (opcode_map.find(opcode) == opcode_map.end()) {
throw std::runtime_error("未知指令: " + opcode);
}
size_t commaPos = args.find(',');
if (commaPos != std::string::npos) {
arg1 = args.substr(0, commaPos);
arg2 = args.substr(commaPos + 1);
arg1.erase(arg1.find_last_not_of(" ") + 1);
arg2.erase(0, arg2.find_first_not_of(" "));
}
else {
arg1 = args;
}
if (opcode == "mov") {
if (!isRegister(arg1)) throw std::runtime_error("找不到寄存器 " + arg1);
registers[arg1] = getValue(arg2);
}
else if (opcode == "add") {
registers[arg1] += getValue(arg2);
}
else if (opcode == "sub") {
registers[arg1] -= getValue(arg2);
}
else if (opcode == "mul") {
registers[arg1] *= getValue(arg2);
}
else if (opcode == "div") {
double divisor = getValue(arg2);
if (divisor == 0) throw std::runtime_error("除数不能为 0");
registers[arg1] /= divisor;
}
else if (opcode == "cmp") {
double val1 = registers[arg1];
double val2 = getValue(arg2);
cmp_flag = (val1 == val2) ? 0 : (val1 > val2 ? 1 : -1);
}
else if (opcode == "out") {
std::cout << "Register "<< arg1 <<":"<< getRegVal(arg1) << std::endl;
}
else if (opcode == "jl" && cmp_flag == -1) {
jumpToLabel(arg1);
}
else if (opcode == "jg" && cmp_flag == 1) {
jumpToLabel(arg1);
}
else if (opcode == "je" && cmp_flag == 0) {
jumpToLabel(arg1);
}
else if (opcode == "jne" && cmp_flag != 0) {
jumpToLabel(arg1);
}
else if (opcode == "jmp") {
jumpToLabel(arg1);
}
else if (opcode == "hlt") {
running = false;
}
}
void AsmVM::jumpToLabel(const std::string& label) {
if (labels.find(label) == labels.end()) {
throw std::runtime_error("标签不存在: " + label);
}
ip = labels[label] - 1;
}
double AsmVM::getValue(const std::string& arg) {
if (isRegister(arg)) return registers[arg];
return std::stod(arg);
}
int main() {
AsmVM vm;
std::vector<std::string> program = {
"MOV eax,10.5",
"MOV ebx, 25.2",
"ADD eax, 0.5",
"CMP eax, ebx",
"JL less",
"SUB eax, ebx",
"JMP end",
"less:",
"MOV eax, 0",
"end:",
"out eax",
"out ebx",
"HLT"
};
try {
vm.loadProgram(program);
vm.execute();
}
catch (const std::runtime_error& e) {
std::cerr << "程序异常: " << e.what() << std::endl;
return -1;
}
return 0;
}

参考文献
- chatgpt