// // interpreter.cpp // curly // // Created by Bob Polis at 2020-09-05 // Copyright (c) 2020 SwiftCoder. All rights reserved. // #include "interpreter.hpp" #include #include #include void interpreter::reset() { _prog.clear(); _values.clear(); _labels.clear(); _vars.clear(); _calls.clear(); _pc_offsets.clear(); _pc = 0; } std::string interpreter::eval(std::istream& in, bool& done) { std::string result; reset(); done = false; // first pass: read program & resolve labels, ignore comments for (std::string line; std::getline(in, line);) { if (line[0] == ':') { // check label definition _labels.emplace(line.substr(1), _prog.size()); _pc_offsets.push_back(_prog.size()); } else if (line[0] == '#') { // check comment _pc_offsets.push_back(_prog.size()); } else { _prog.push_back(line); } } // second pass: run program while (_pc < _prog.size() && !done) { // fetch next instruction std::string code {_prog[_pc]}; if (std::isdigit(code[0])) { // check literal int _values.push_back(code); _pc++; } else if (code[0] == '\\' || code[0] == '>') { // check literal string or label ref _values.push_back(code.substr(1)); _pc++; } else if (code[0] == '=') { // check var assignment _vars[code.substr(1)] = _values.back(); _values.pop_back(); _pc++; } else if (code[0] == '$') { // check var ref _values.push_back(_vars[code.substr(1)]); _pc++; } else { exec_instruction(code, done); } } if (_values.size()) { result = _values.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 if (code == "inp") inp(); else if (code == "out") out(); else if (code == "err") err(); else { auto it = std::upper_bound(_pc_offsets.begin(), _pc_offsets.end(), _pc); long num_removed_source_lines {it - _pc_offsets.begin()}; size_t lineno {num_removed_source_lines + _pc + 1}; throw syntax_error {code, lineno}; } } inline int interpreter::pop_int() { std::istringstream iss {pop_str()}; int result; iss >> result; return result; } inline std::string interpreter::pop_str() { auto val = _values.back(); _values.pop_back(); return val; } // integer operations ----------------------------------------------------- void interpreter::add() { auto val2 = pop_int(); auto val1 = pop_int(); _values.push_back(std::to_string(val1 + val2)); _pc++; } void interpreter::sub() { auto val2 = pop_int(); auto val1 = pop_int(); _values.push_back(std::to_string(val1 - val2)); _pc++; } void interpreter::mul() { auto val2 = pop_int(); auto val1 = pop_int(); _values.push_back(std::to_string(val1 * val2)); _pc++; } void interpreter::div() { auto val2 = pop_int(); auto val1 = pop_int(); _values.push_back(std::to_string(val1 / val2)); _pc++; } void interpreter::mod() { auto val2 = pop_int(); auto val1 = pop_int(); _values.push_back(std::to_string(val1 % val2)); _pc++; } void interpreter::abs() { auto val = pop_int(); _values.push_back(std::to_string(val < 0 ? -val : val)); _pc++; } void interpreter::neg() { auto val = pop_int(); _values.push_back(std::to_string(-val)); _pc++; } void interpreter::inc() { auto val = pop_int(); _values.push_back(std::to_string(val + 1)); _pc++; } void interpreter::dec() { auto val = pop_int(); _values.push_back(std::to_string(val - 1)); _pc++; } // string operations ------------------------------------------------------ void interpreter::dup() { _values.push_back(_values.back()); _pc++; } void interpreter::rev() { auto val = pop_str(); std::string result; for (auto it = val.rbegin(); it != val.rend(); ++it) { result += *it; } _values.push_back(result); _pc++; } void interpreter::slc() { auto to = pop_int(); auto from = pop_int(); auto val = pop_str(); _values.push_back(val.substr(from, to - from)); _pc++; } void interpreter::idx() { auto idx = pop_int(); auto val = pop_str(); val = val[idx]; _values.emplace_back(val); _pc++; } void interpreter::cat() { auto val2 = pop_str(); auto val1 = pop_str(); _values.emplace_back(val1 + val2); _pc++; } void interpreter::len() { auto val = pop_str(); _values.push_back(std::to_string(val.size())); _pc++; } void interpreter::rot() { auto val = pop_str(); 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; }); _values.push_back(val); _pc++; } void interpreter::enl() { auto val = pop_str(); _values.emplace_back(val + '\n'); _pc++; } // tests & jumps ---------------------------------------------------------- void interpreter::gto() { _pc = _labels[pop_str()]; } void interpreter::geq() { auto label = pop_str(); auto val2 = pop_str(); auto val1 = pop_str(); if (val1 == val2) { _pc = _labels[label]; } else { _pc++; } } void interpreter::gne() { auto label = pop_str(); auto val2 = pop_str(); auto val1 = pop_str(); if (val1 != val2) { _pc = _labels[label]; } else { _pc++; } } void interpreter::glt() { auto label = pop_str(); auto val2 = pop_int(); auto val1 = pop_int(); if (val1 < val2) { _pc = _labels[label]; } else { _pc++; } } void interpreter::gle() { auto label = pop_str(); auto val2 = pop_int(); auto val1 = pop_int(); if (val1 <= val2) { _pc = _labels[label]; } else { _pc++; } } void interpreter::ggt() { auto label = pop_str(); auto val2 = pop_int(); auto val1 = pop_int(); if (val1 > val2) { _pc = _labels[label]; } else { _pc++; } } void interpreter::gge() { auto label = pop_str(); auto val2 = pop_int(); auto val1 = pop_int(); 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(); } // I/O -------------------------------------------------------------------- void interpreter::inp() { std::string val; std::cin >> val; _values.push_back(val); _pc++; } void interpreter::out() { std::cout << _values.back() << '\n'; _pc++; } void interpreter::err() { std::cerr << _values.back() << '\n'; _pc++; }