// // interpreter.cpp // curly // // Created by Bob Polis at 2020-09-05 // Copyright (c) 2020 SwiftCoder. All rights reserved. // #include "interpreter.hpp" #include #include int to_int(const std::string& val) { std::istringstream iss {val}; int result; iss >> result; return result; } void interpreter::reset() { _prog.clear(); _stack.clear(); _labels.clear(); _vars.clear(); _calls.clear(); _pc = 0; } std::string interpreter::eval(std::istream& in, bool& done) { std::string result; reset(); done = false; // first pass: read program & resolve labels for (std::string line; std::getline(in, line); ++_pc) { if (line[0] == ':') { _labels.emplace(line.substr(1), _pc); } else { _prog.push_back(line); } } // second pass: run program _pc = 0; while (_pc < _prog.size() && !done) { // fetch next instruction std::string code {_prog[_pc]}; // check literal int if (std::isdigit(code[0])) { _stack.push_back(code); _pc++; continue; } // check literal string if (code[0] == '\\') { _stack.push_back(code.substr(1)); _pc++; continue; } // check label ref if (code[0] == '>') { _stack.push_back(code.substr(1)); _pc++; continue; } // check var assignment if (code[0] == '=') { _vars[code.substr(1)] = _stack.back(); _stack.pop_back(); _pc++; continue; } // check var ref if (code[0] == '$') { _stack.push_back(_vars[code.substr(1)]); _pc++; continue; } // exec instruction exec_instruction(code, done); } if (_stack.size()) { result = _stack.back(); } return result; } void interpreter::exec_instruction(const std::string& code, bool& done) { if (code == "end") done = true; else if (code == "add") add(); else if (code == "sub") sub(); else if (code == "mul") mul(); else if (code == "div") div(); else if (code == "mod") mod(); else if (code == "abs") abs(); else if (code == "neg") neg(); else if (code == "dup") dup(); else if (code == "inc") inc(); else if (code == "dec") dec(); else if (code == "rev") rev(); else if (code == "slc") slc(); else if (code == "idx") idx(); else if (code == "cat") cat(); else if (code == "len") len(); else if (code == "rot") rot(); else if (code == "gto") gto(); else if (code == "geq") geq(); else if (code == "gne") gne(); else if (code == "glt") glt(); else if (code == "gle") gle(); else if (code == "ggt") ggt(); else if (code == "gge") gge(); else if (code == "fun") fun(); else if (code == "ret") ret(); else if (code == "enl") enl(); else throw syntax_error {code}; } // integer operations ----------------------------------------------------- void interpreter::add() { int val2 {to_int(_stack.back())}; _stack.pop_back(); int val1 {to_int(_stack.back())}; _stack.pop_back(); _stack.push_back(std::to_string(val1 + val2)); _pc++; } void interpreter::sub() { int val2 {to_int(_stack.back())}; _stack.pop_back(); int val1 {to_int(_stack.back())}; _stack.pop_back(); _stack.push_back(std::to_string(val1 - val2)); _pc++; } void interpreter::mul() { int val2 {to_int(_stack.back())}; _stack.pop_back(); int val1 {to_int(_stack.back())}; _stack.pop_back(); _stack.push_back(std::to_string(val1 * val2)); _pc++; } void interpreter::div() { int val2 {to_int(_stack.back())}; _stack.pop_back(); int val1 {to_int(_stack.back())}; _stack.pop_back(); _stack.push_back(std::to_string(val1 / val2)); _pc++; } void interpreter::mod() { int val2 {to_int(_stack.back())}; _stack.pop_back(); int val1 {to_int(_stack.back())}; _stack.pop_back(); _stack.push_back(std::to_string(val1 % val2)); _pc++; } void interpreter::abs() { int val {to_int(_stack.back())}; _stack.pop_back(); _stack.push_back(std::to_string(val < 0 ? -val : val)); _pc++; } void interpreter::neg() { int val {to_int(_stack.back())}; _stack.pop_back(); _stack.push_back(std::to_string(-val)); _pc++; } void interpreter::inc() { int val {to_int(_stack.back()) + 1}; _stack.pop_back(); _stack.push_back(std::to_string(val)); _pc++; } void interpreter::dec() { int val {to_int(_stack.back()) - 1}; _stack.pop_back(); _stack.push_back(std::to_string(val)); _pc++; } // string operations ------------------------------------------------------ void interpreter::dup() { _stack.push_back(_stack.back()); _pc++; } void interpreter::rev() { std::string val {_stack.back()}; _stack.pop_back(); std::string result; for (auto it = val.rbegin(); it != val.rend(); ++it) { result += *it; } _stack.push_back(result); _pc++; } void interpreter::slc() { int to {to_int(_stack.back())}; _stack.pop_back(); int from {to_int(_stack.back())}; _stack.pop_back(); std::string val {_stack.back()}; _stack.pop_back(); _stack.push_back(val.substr(from, to - from)); _pc++; } void interpreter::idx() { int idx {to_int(_stack.back())}; _stack.pop_back(); std::string val {_stack.back()}; _stack.pop_back(); val = val[idx]; _stack.emplace_back(val); _pc++; } void interpreter::cat() { std::string val2 {_stack.back()}; _stack.pop_back(); std::string val1 {_stack.back()}; _stack.pop_back(); _stack.emplace_back(val1 + val2); _pc++; } void interpreter::len() { std::string val {_stack.back()}; _stack.pop_back(); _stack.push_back(std::to_string(val.size())); _pc++; } void interpreter::rot() { std::string val {_stack.back()}; _stack.pop_back(); std::transform(val.begin(), val.end(), val.begin(), [](char ch) -> char { if (ch >= 'a' && ch <= 'm') { return ch + 13; } else if (ch >= 'n' && ch <= 'z') { return ch - 13; } else if (ch >= 'A' && ch <= 'M') { return ch + 13; } else if (ch >= 'N' && ch <= 'Z') { return ch - 13; } return ch; }); _stack.push_back(val); _pc++; } void interpreter::enl() { std::string val {_stack.back()}; _stack.pop_back(); val += '\n'; _stack.push_back(val); _pc++; } // tests & jumps ---------------------------------------------------------- void interpreter::gto() { _pc = _labels[_stack.back()]; _stack.pop_back(); } void interpreter::geq() { std::string label {_stack.back()}; _stack.pop_back(); std::string val2 {_stack.back()}; _stack.pop_back(); std::string val1 {_stack.back()}; _stack.pop_back(); if (val1 == val2) { _pc = _labels[label]; } else { _pc++; } } void interpreter::gne() { std::string label {_stack.back()}; _stack.pop_back(); std::string val2 {_stack.back()}; _stack.pop_back(); std::string val1 {_stack.back()}; _stack.pop_back(); if (val1 != val2) { _pc = _labels[label]; } else { _pc++; } } void interpreter::glt() { std::string label {_stack.back()}; _stack.pop_back(); std::string val2 {_stack.back()}; _stack.pop_back(); std::string val1 {_stack.back()}; _stack.pop_back(); if (val1 < val2) { _pc = _labels[label]; } else { _pc++; } } void interpreter::gle() { std::string label {_stack.back()}; _stack.pop_back(); std::string val2 {_stack.back()}; _stack.pop_back(); std::string val1 {_stack.back()}; _stack.pop_back(); if (val1 <= val2) { _pc = _labels[label]; } else { _pc++; } } void interpreter::ggt() { std::string label {_stack.back()}; _stack.pop_back(); std::string val2 {_stack.back()}; _stack.pop_back(); std::string val1 {_stack.back()}; _stack.pop_back(); if (val1 > val2) { _pc = _labels[label]; } else { _pc++; } } void interpreter::gge() { std::string label {_stack.back()}; _stack.pop_back(); std::string val2 {_stack.back()}; _stack.pop_back(); std::string val1 {_stack.back()}; _stack.pop_back(); if (val1 >= val2) { _pc = _labels[label]; } else { _pc++; } } // subroutines ------------------------------------------------------------ void interpreter::fun() { _calls.push_back(_pc + 1); // push return address gto(); } void interpreter::ret() { _pc = _calls.back(); _calls.pop_back(); }