「C++ の調査(10) - 非専門的シンギュラリティー研究所」のコンパイルの処理で行番号を出力するようにします。
void compileExpression(const string& expr, int& line_number) { vector<string> postfix = toPostfix(expr); bool first = true; for (const string& tok : postfix) { if (!first) { cout << ++line_number << " "; } first = false; if (tok == "+" || tok == "-" || tok == "*" || tok == "/") { if (tok == "+") cout << "ADD\n"; if (tok == "-") cout << "SUB\n"; if (tok == "*") cout << "MUL\n"; if (tok == "/") cout << "DIV\n"; } else if (tok == "u-") { cout << "NEG\n"; } else { if (isdigit(tok[0]) || (tok[0] == '-' && tok.size() > 1)) cout << "PUSH " << tok << "\n"; else cout << "LOAD " << tok << "\n"; } } } void compileProgram() { cout << "=== COMPILED OUTPUT ===\n"; for (auto& [ln, code] : program) { stringstream ss(code); string cmd; ss >> cmd; cout << ln << " "; if (cmd == "LET") { string var, eq; ss >> var >> eq; string expr; getline(ss, expr); int line_number = ln; compileExpression(expr, line_number); cout << ++line_number << " "; cout << "STORE " << var << "\n"; } else if (cmd == "PRINT") { string expr; getline(ss, expr); int line_number = ln; compileExpression(expr, line_number); cout << ++line_number << " "; cout << "OUT\n"; } else if (cmd == "INPUT") { string var; ss >> var; cout << "IN " << var << "\n"; } else if (cmd == "IF") { string cond; getline(ss, cond); size_t thenPos = cond.find("THEN"); if (thenPos != string::npos) { string condition = cond.substr(0, thenPos); string action = cond.substr(thenPos + 4); string op; string cmpOps[] = { "<=", ">=", "<>", "=", "<", ">" }; for (const string& co : cmpOps) { size_t pos = condition.find(co); if (pos != string::npos) { string lhs = condition.substr(0, pos); string rhs = condition.substr(pos + co.size()); int line_number = ln; compileExpression(lhs, line_number); cout << ++line_number << " "; compileExpression(rhs, line_number); if (co == "=") op = "EQ"; if (co == "<") op = "LT"; if (co == ">") op = "GT"; if (co == "<=") op = "LE"; if (co == ">=") op = "GE"; if (co == "<>") op = "NE"; cout << ++line_number << " "; cout << op << "\n"; cout << ++line_number << " "; cout << "JNZ " << action << "\n"; break; } } } } else if (cmd == "GOTO") { int target; ss >> target; cout << "JMP " << target << "\n"; } else if (cmd == "GOSUB") { int target; ss >> target; cout << "CALL " << target << "\n"; } else if (cmd == "RETURN") { cout << "RET\n"; } else if (cmd == "END") { cout << "HALT\n"; } else if (cmd == "REM") { string cmt; getline(ss, cmt); cout << "REM" << cmt << "\n"; } else { cout << "REM\n"; } } cout << "=== END COMPILE ===\n"; }
「C++ の調査(10) - 非専門的シンギュラリティー研究所」のフィボナッチ数列のサンプルを仮想命令にコンパイルします。
10 REM フィボナッチ数列 20 PUSH 10 21 STORE N 30 PUSH 1 31 STORE I 40 PUSH 1 41 STORE A 50 PUSH 1 51 STORE B 60 LOAD A 61 OUT 70 LOAD B 71 STORE T 80 LOAD A 81 LOAD B 82 ADD 83 STORE B 90 LOAD T 91 STORE A 100 LOAD I 101 PUSH 1 102 ADD 103 STORE I 110 LOAD I 111 LOAD N 112 LE 113 JNZ 60
「C++ の調査(10) - 非専門的シンギュラリティー研究所」のコードに仮想命令のインタープリターを追加します。
stack<int> dataStack; void unary_op(function<int(int)> op) { int x = dataStack.top(); dataStack.pop(); dataStack.push(op(x)); } void binary_op(function<int(int, int)> op) { int y = dataStack.top(); dataStack.pop(); int x = dataStack.top(); dataStack.pop(); dataStack.push(op(x, y)); } void binary_comp_op(function<bool(int, int)> op) { binary_op([op](int x, int y) -> int {return op(x, y) ? -1 : 0; }); } // アセンブリ言語の行を実行 bool executeAsmLine(const string& line, map<int, string>::iterator& it) { stringstream ss(line); string cmd; ss >> cmd; cmd = to_upper(cmd); if (cmd == "PUSH") { int num; ss >> num; dataStack.push(num); } else if (cmd == "LOAD") { string var; ss >> var; dataStack.push(variables[var]); } else if (cmd == "STORE") { string var; ss >> var; variables[var] = dataStack.top(); dataStack.pop(); } else if (cmd == "OUT") { cout << dataStack.top() << endl; dataStack.pop(); } else if (cmd == "IN") { string var; ss >> var; cout << "? "; cin >> variables[var]; } else if (cmd == "ADD") { binary_op([](int x, int y) -> int {return x + y; }); } else if (cmd == "SUB") { binary_op([](int x, int y) -> int {return x - y; }); } else if (cmd == "MUL") { binary_op([](int x, int y) -> int {return x * y; }); } else if (cmd == "DIV") { binary_op([](int x, int y) -> int {return x / y; }); } else if (cmd == "NEG") { unary_op([](int x) -> int {return -x; }); } else if (cmd == "EQ") { binary_comp_op([](int x, int y) -> int {return x == y; }); } else if (cmd == "NE") { binary_comp_op([](int x, int y) -> int {return x != y; }); } else if (cmd == "LT") { binary_comp_op([](int x, int y) -> int {return x < y; }); } else if (cmd == "LE") { binary_comp_op([](int x, int y) -> int {return x <= y; }); } else if (cmd == "GT") { binary_comp_op([](int x, int y) -> int {return x > y; }); } else if (cmd == "GE") { binary_comp_op([](int x, int y) -> int {return x >= y; }); } else if (cmd == "JMP") { int target; ss >> target; it = program.find(target); return true; } else if (cmd == "JNZ") { int target; ss >> target; int cond = dataStack.top(); dataStack.pop(); if (cond) { it = program.find(target); return true; } } else if (cmd == "CALL") { int target; ss >> target; returnStack.push(next(it)); it = program.find(target); return true; } else if (cmd == "RET") { it = returnStack.top(); returnStack.pop(); return true; } else if (cmd == "HALT") { // プログラムを中断 if (it != program.end()) { ++it; } return false; } else if (cmd == "LIST") { // プログラムを表示 for (auto& [ln, code] : program) { cout << ln << " " << code << endl; } } else if (cmd == "RUN") { // プログラムを実行 it = program.begin(); while (it != program.end()) { if (!executeAsmLine(it->second, it)) { return true; } } return true; } else if (cmd == "EXIT") { // アセンブリ言語 インタープリターを終了 exit(0); } else if (cmd == "RENUM") { // 行番号を揃える program = renum(renumAsmLine); // プログラムが変更されたときは実行位置をリセット it = program.begin(); return true; } else if (cmd == "REM") { // コメント } else if (cmd == "BASIC") { lang = "basic"; } else if (cmd == "ASM") { lang = "asm"; } else { cout << "コマンドが誤っています:" << cmd; } if (it != program.end()) { ++it; return true; } return false; }
フィボナッチ数列のサンプルを実行すると以下のようになります。
1 1 2 3 5 8 13 21 34 55







