仮想命令のコードを 68000 のアセンブリ言語に変換する処理を追加しました。ChatGPT でやってもらったところ動かなかったのでそれを改造して作りました。
class VirtualTo68000 { unordered_map<string, string> variables; public: void translate(map<int, string> program) { int labelCounter = 0; vector<int> destnums = getdestnums(); for (auto& [ln, code] : program) { stringstream ss(code); string cmd; ss >> cmd; //cout << ln << " "; if (std::find(destnums.begin(), destnums.end(), ln) != destnums.end()) { cout << "LABEL_" << ln << ":\n"; } if (cmd == "PUSH") { int num; ss >> num; cout << " MOVE.L #" << num << ", -(A7)\n"; } else if (cmd == "LOAD") { string var; ss >> var; variables[var] = variables.count(var) ? variables[var] : "VAR_" + var; cout << " MOVE.L " << variables[var] << ", -(A7)\n"; } else if (cmd == "STORE") { string var; ss >> var; variables[var] = variables.count(var) ? variables[var] : "VAR_" + var; cout << " MOVE.L (A7)+, " << variables[var] << "\n"; } else if (cmd == "ADD") { binaryOp("ADD.L"); } else if (cmd == "SUB") { binaryOp("SUB.L"); } else if (cmd == "MUL") { binaryOp("MULS"); // 符号付き乗算 } else if (cmd == "DIV") { binaryOp("DIVS"); // 符号付き除算 } else if (cmd == "NEG") { cout << " MOVE.L (A7)+, D0\n"; cout << " NEG.L D0\n"; cout << " MOVE.L D0, -(A7)\n"; } else if (cmd == "EQ" || cmd == "NE" || cmd == "LT" || cmd == "LE" || cmd == "GT" || cmd == "GE") { compareOp(cmd, labelCounter++); } else if (cmd == "JMP") { string label; ss >> label; cout << " JMP LABEL_" << label << "\n"; } else if (cmd == "JNZ") { string label; ss >> label; cout << " MOVE.L (A7)+, D0\n"; cout << " TST.L D0\n"; cout << " BNE LABEL_" << label << "\n"; } else if (cmd == "CALL") { string label; ss >> label; cout << " JSR LABEL_" << label << "\n"; } else if (cmd == "RET") { cout << " RTS\n"; } else if (cmd == "OUT") { cout << " JSR OUTPUT" << "\n"; } else if (cmd == "IN") { string var; ss >> var; cout << " JSR INPUT" << "\n"; variables[var] = variables.count(var) ? variables[var] : "VAR_" + var; cout << " MOVE.L (A7)+, " << variables[var] << "\n"; } else if (cmd == "REM") { // コメント string cmt; getline(ss, cmt); cout << ";" << cmt << "\n"; } else { cout << " ; Unknown instruction: " << cmd << "\n"; } } // グローバル変数定義(必要に応じて) if (!variables.empty()) { cout << "\n SECTION DATA\n"; for (const auto& [name, label] : variables) { cout << label << ": DC.L 0\n"; } } } private: vector<string> tokenize(const string& line) { vector<string> tokens; size_t start = 0, end; while ((end = line.find(' ', start)) != string::npos) { tokens.push_back(line.substr(start, end - start)); start = end + 1; } if (start < line.size()) tokens.push_back(line.substr(start)); return tokens; } void binaryOp(const string& op) { cout << " MOVE.L (A7)+, D0\n"; cout << " MOVE.L (A7)+, D1\n"; if (op == "SUB.L" || op == "DIVS") cout << " " << op << " D0, D1\n"; // D1 - D0 or D1 / D0 else cout << " " << op << " D0, D1\n"; // D1 + D0 or D1 * D0 cout << " MOVE.L D1, -(A7)\n"; } void compareOp(const string& op, int labelId) { string trueLabel = "LABEL_TRUE_" + to_string(labelId); string endLabel = "LABEL_END_" + to_string(labelId); cout << " MOVE.L (A7)+, D0\n"; cout << " MOVE.L (A7)+, D1\n"; cout << " CMP.L D0, D1\n"; string branch; if (op == "EQ") branch = "BEQ"; else if (op == "NE") branch = "BNE"; else if (op == "LT") branch = "BLT"; else if (op == "LE") branch = "BLE"; else if (op == "GT") branch = "BGT"; else if (op == "GE") branch = "BGE"; cout << " " << branch << " " << trueLabel << "\n"; cout << " MOVE.L #0, -(A7)\n"; cout << " BRA " << endLabel << "\n"; cout << trueLabel << ":\n"; cout << " MOVE.L #1, -(A7)\n"; cout << endLabel << ":\n"; } // 仮想命令コードの行き先になっている行番号を返す int getdestnum(const string& line) { stringstream ss(line); string cmd; ss >> cmd; cmd = to_upper(cmd); if (cmd == "JMP" || cmd == "JNZ" || cmd == "CALL") { int target; ss >> target; return target; } return -1; } // 仮想命令コードの行き先になっているすべての行番号を返す vector<int> getdestnums() { vector<int> result; auto pit = program.begin(); while (pit != program.end()) { int destnum = getdestnum(pit->second); if (destnum >= 0) { result.push_back(destnum); } pit++; } return result; } }; void compileVirtualTo68000() { cout << "=== COMPILED OUTPUT ===\n"; VirtualTo68000 translator; translator.translate(program); cout << "=== END COMPILE ===\n"; }
フィボナッチ数列の例を変換した結果は以下のようになります。
; フィボナッチ数列 MOVE.L #10, -(A7) MOVE.L (A7)+, VAR_N MOVE.L #1, -(A7) MOVE.L (A7)+, VAR_I MOVE.L #1, -(A7) MOVE.L (A7)+, VAR_A MOVE.L #1, -(A7) MOVE.L (A7)+, VAR_B LABEL_100: MOVE.L VAR_A, -(A7) JSR OUTPUT MOVE.L VAR_B, -(A7) MOVE.L (A7)+, VAR_T MOVE.L VAR_A, -(A7) MOVE.L VAR_B, -(A7) MOVE.L (A7)+, D0 MOVE.L (A7)+, D1 ADD.L D0, D1 MOVE.L D1, -(A7) MOVE.L (A7)+, VAR_B MOVE.L VAR_T, -(A7) MOVE.L (A7)+, VAR_A MOVE.L VAR_I, -(A7) MOVE.L #1, -(A7) MOVE.L (A7)+, D0 MOVE.L (A7)+, D1 ADD.L D0, D1 MOVE.L D1, -(A7) MOVE.L (A7)+, VAR_I MOVE.L VAR_I, -(A7) MOVE.L VAR_N, -(A7) MOVE.L (A7)+, D0 MOVE.L (A7)+, D1 CMP.L D0, D1 BLE LABEL_TRUE_0 MOVE.L #0, -(A7) BRA LABEL_END_0 LABEL_TRUE_0: MOVE.L #1, -(A7) LABEL_END_0: MOVE.L (A7)+, D0 TST.L D0 BNE LABEL_100 SECTION DATA VAR_N: DC.L 0 VAR_A: DC.L 0 VAR_I: DC.L 0 VAR_B: DC.L 0 VAR_T: DC.L 0
「JSR OUTPUT」で数値を出力できるとします。これが動くかどうかは確認できていません。







