#include "interpreter.hpp" #include #include #include #include "opcodes.hpp" #include "program.hpp" namespace Interpreter { [[noreturn]] static void abortUnknownCode(int segment, int opcode) { const std::string error = "unknown opcode " + std::to_string(opcode) + " in segment " + std::to_string(segment); throw std::runtime_error(error); } [[noreturn]] static void abortUnknownSegment(Type_Code code) { const std::string error = "opcode outside of the allocated segment range: " + std::to_string(code); throw std::runtime_error(error); } template auto& getDispatcher(const T& segment, unsigned int seg, int opcode) { auto it = segment.find(opcode); if (it == segment.end()) { abortUnknownCode(seg, opcode); } return it->second; } void Interpreter::execute(Type_Code code) { unsigned int segSpec = code >> 30; switch (segSpec) { case 0: { const int opcode = code >> 24; const unsigned int arg0 = code & 0xffffff; return getDispatcher(mSegment0, 0, opcode)->execute(mRuntime, arg0); } case 2: { const int opcode = (code >> 20) & 0x3ff; const unsigned int arg0 = code & 0xfffff; return getDispatcher(mSegment2, 2, opcode)->execute(mRuntime, arg0); } } segSpec = code >> 26; switch (segSpec) { case 0x30: { const int opcode = (code >> 8) & 0x3ffff; const unsigned int arg0 = code & 0xff; return getDispatcher(mSegment3, 3, opcode)->execute(mRuntime, arg0); } case 0x32: { const int opcode = code & 0x3ffffff; return getDispatcher(mSegment5, 5, opcode)->execute(mRuntime); } } abortUnknownSegment(code); } void Interpreter::begin() { if (mRunning) { mCallstack.push(mRuntime); mRuntime.clear(); } else { mRunning = true; } } void Interpreter::end() { if (mCallstack.empty()) { mRuntime.clear(); mRunning = false; } else { mRuntime = mCallstack.top(); mCallstack.pop(); } } void Interpreter::run(const Program& program, Context& context) { begin(); try { mRuntime.configure(program, context); while (mRuntime.getPC() >= 0 && static_cast(mRuntime.getPC()) < program.mInstructions.size()) { const Type_Code instruction = program.mInstructions[mRuntime.getPC()]; mRuntime.setPC(mRuntime.getPC() + 1); execute(instruction); } } catch (...) { end(); throw; } end(); } }