2020-09-06 12:57:28 +02:00
|
|
|
//
|
|
|
|
// interpreter.cpp
|
|
|
|
// curly
|
|
|
|
//
|
|
|
|
// Created by Bob Polis at 2020-09-05
|
|
|
|
// Copyright (c) 2020 SwiftCoder. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "interpreter.hpp"
|
2020-09-07 11:40:58 +02:00
|
|
|
#include <cctype>
|
|
|
|
#include <algorithm>
|
2020-09-13 16:55:02 +02:00
|
|
|
#include <iostream>
|
2020-09-07 11:40:58 +02:00
|
|
|
|
|
|
|
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();
|
2020-09-22 10:51:20 +02:00
|
|
|
_pc_offsets.clear();
|
2020-09-07 11:40:58 +02:00
|
|
|
_pc = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string interpreter::eval(std::istream& in, bool& done) {
|
|
|
|
std::string result;
|
|
|
|
reset();
|
|
|
|
done = false;
|
|
|
|
|
|
|
|
// first pass: read program & resolve labels
|
2020-09-22 10:51:20 +02:00
|
|
|
for (std::string line; std::getline(in, line);) {
|
2020-09-21 16:37:40 +02:00
|
|
|
if (line[0] == ':') { // check label definition
|
2020-09-22 10:51:20 +02:00
|
|
|
_labels.emplace(line.substr(1), _prog.size());
|
|
|
|
_pc_offsets.push_back(_prog.size());
|
2020-09-21 12:41:29 +02:00
|
|
|
} else if (line[0] == '#') { // check comment
|
2020-09-22 10:51:20 +02:00
|
|
|
_pc_offsets.push_back(_prog.size());
|
2020-09-07 11:40:58 +02:00
|
|
|
} else {
|
|
|
|
_prog.push_back(line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// second pass: run program
|
|
|
|
_pc = 0;
|
|
|
|
while (_pc < _prog.size() && !done) {
|
|
|
|
// fetch next instruction
|
|
|
|
std::string code {_prog[_pc]};
|
2020-09-21 10:45:49 +02:00
|
|
|
|
2020-09-07 11:40:58 +02:00
|
|
|
// 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();
|
2020-09-07 18:50:09 +02:00
|
|
|
else if (code == "enl") enl();
|
2020-09-21 10:17:16 +02:00
|
|
|
else if (code == "inp") inp();
|
|
|
|
else if (code == "out") out();
|
|
|
|
else if (code == "err") err();
|
2020-09-21 16:37:40 +02:00
|
|
|
else {
|
|
|
|
auto it = std::upper_bound(_pc_offsets.begin(), _pc_offsets.end(), _pc);
|
|
|
|
size_t lineno {it - _pc_offsets.begin() + _pc + 1};
|
|
|
|
throw syntax_error {code, lineno};
|
|
|
|
}
|
2020-09-07 11:40:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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++;
|
|
|
|
}
|
|
|
|
|
2020-09-07 18:50:09 +02:00
|
|
|
void interpreter::enl() {
|
|
|
|
std::string val {_stack.back()};
|
|
|
|
_stack.pop_back();
|
|
|
|
val += '\n';
|
|
|
|
_stack.push_back(val);
|
|
|
|
_pc++;
|
|
|
|
}
|
|
|
|
|
2020-09-07 11:40:58 +02:00
|
|
|
// 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();
|
2020-09-13 16:55:02 +02:00
|
|
|
int val2 {to_int(_stack.back())};
|
2020-09-07 11:40:58 +02:00
|
|
|
_stack.pop_back();
|
2020-09-13 16:55:02 +02:00
|
|
|
int val1 {to_int(_stack.back())};
|
2020-09-07 11:40:58 +02:00
|
|
|
_stack.pop_back();
|
|
|
|
if (val1 < val2) {
|
|
|
|
_pc = _labels[label];
|
|
|
|
} else {
|
|
|
|
_pc++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void interpreter::gle() {
|
|
|
|
std::string label {_stack.back()};
|
|
|
|
_stack.pop_back();
|
2020-09-13 16:55:02 +02:00
|
|
|
int val2 {to_int(_stack.back())};
|
2020-09-07 11:40:58 +02:00
|
|
|
_stack.pop_back();
|
2020-09-13 16:55:02 +02:00
|
|
|
int val1 {to_int(_stack.back())};
|
2020-09-07 11:40:58 +02:00
|
|
|
_stack.pop_back();
|
|
|
|
if (val1 <= val2) {
|
|
|
|
_pc = _labels[label];
|
|
|
|
} else {
|
|
|
|
_pc++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void interpreter::ggt() {
|
|
|
|
std::string label {_stack.back()};
|
|
|
|
_stack.pop_back();
|
2020-09-13 16:55:02 +02:00
|
|
|
int val2 {to_int(_stack.back())};
|
2020-09-07 11:40:58 +02:00
|
|
|
_stack.pop_back();
|
2020-09-13 16:55:02 +02:00
|
|
|
int val1 {to_int(_stack.back())};
|
2020-09-07 11:40:58 +02:00
|
|
|
_stack.pop_back();
|
|
|
|
if (val1 > val2) {
|
|
|
|
_pc = _labels[label];
|
|
|
|
} else {
|
|
|
|
_pc++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void interpreter::gge() {
|
|
|
|
std::string label {_stack.back()};
|
|
|
|
_stack.pop_back();
|
2020-09-13 16:55:02 +02:00
|
|
|
int val2 {to_int(_stack.back())};
|
2020-09-07 11:40:58 +02:00
|
|
|
_stack.pop_back();
|
2020-09-13 16:55:02 +02:00
|
|
|
int val1 {to_int(_stack.back())};
|
2020-09-07 11:40:58 +02:00
|
|
|
_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();
|
|
|
|
}
|
2020-09-13 16:55:02 +02:00
|
|
|
|
|
|
|
// debugging --------------------------------------------------------------
|
|
|
|
|
2020-09-21 10:17:16 +02:00
|
|
|
void interpreter::inp() {
|
|
|
|
std::string val;
|
|
|
|
std::cin >> val;
|
|
|
|
_stack.push_back(val);
|
|
|
|
_pc++;
|
|
|
|
}
|
|
|
|
|
2020-09-13 16:55:02 +02:00
|
|
|
void interpreter::out() {
|
|
|
|
std::cout << _stack.back() << '\n';
|
|
|
|
_pc++;
|
|
|
|
}
|
2020-09-21 10:17:16 +02:00
|
|
|
|
|
|
|
void interpreter::err() {
|
|
|
|
std::cerr << _stack.back() << '\n';
|
|
|
|
_pc++;
|
|
|
|
}
|