diff --git a/Makefile b/Makefile index 8f1a266..1217adb 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ MANPAGE := $(BIN).$(MANSECTION) SRCS := $(wildcard *.cpp) OBJS := $(subst .cpp,.o,$(SRCS)) DEPS := $(subst .cpp,.d,$(SRCS)) +CODE := $(wildcard code/*.txt) CXX ?= g++ PKG_CONFIG ?= pkg-config @@ -29,9 +30,9 @@ endif LDLIBS := -lm -lpthread -lcurl -lsclogging -.PHONY: all clean install +.PHONY: all sync clean install -all: $(BIN) +all: $(BIN) sync $(BIN): $(OBJS) $(DEPS) $(CXX) $(OBJS) $(LDFLAGS) $(LDLIBS) -o $(BIN) @@ -43,6 +44,9 @@ $(BIN): $(OBJS) $(DEPS) %.d: ; +sync: $(CODE) + rsync -av code/ pi@www.swiftcoder.nl:/var/www/html/cpp1/ + clean: $(RM) $(OBJS) $(DEPS) $(BIN) diff --git a/code/start.txt b/code/start.txt new file mode 100644 index 0000000..ab7b36c --- /dev/null +++ b/code/start.txt @@ -0,0 +1,18 @@ +\a +=result +5 +=ctr +:loop +$result +dup +cat +=result +$ctr +dec +=ctr +$ctr +0 +>loop +gne +$result +end diff --git a/interpreter.cpp b/interpreter.cpp index 13b059c..e57f83f 100644 --- a/interpreter.cpp +++ b/interpreter.cpp @@ -7,3 +7,369 @@ // #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 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++; +} + +// 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(); +} diff --git a/interpreter.hpp b/interpreter.hpp index 4e533de..3b0ff19 100644 --- a/interpreter.hpp +++ b/interpreter.hpp @@ -13,17 +13,31 @@ #include #include #include +#include +#include + +class syntax_error : public std::runtime_error { + public: + syntax_error(const std::string& what_arg) : std::runtime_error(what_arg) {} +}; class interpreter { public: interpreter() = default; - std::string eval(std::istream& in); + std::string eval(std::istream& in, bool& done); private: - std::vector _ops; - std::map> _funs; + std::vector _prog; + std::vector _stack; + std::map _labels; + std::map _vars; + std::vector _calls; + std::vector::size_type _pc {0}; + void reset(); + void exec_instruction(const std::string& code, bool& done); + // integer operations void add(); void sub(); @@ -32,11 +46,11 @@ class interpreter { void mod(); void abs(); void neg(); - void dup(); void inc(); void dec(); // string operations + void dup(); void rev(); void slc(); void idx(); @@ -44,30 +58,18 @@ class interpreter { void len(); void rot(); - // tests - void teq(); - void tne(); - void tlt(); - void tle(); - void tgt(); - void tge(); + // tests & jumps + void gto(); + void geq(); + void gne(); + void glt(); + void gle(); + void ggt(); + void gge(); - // blocks - void end(); - - // conditionals - void ift(); - void els(); - - // loops - void whl(); - - // functions + // subroutines void fun(); - void run(); - - // solution - void sol(); + void ret(); }; #endif // _interpreter_H_ diff --git a/main.cpp b/main.cpp index 9ae0a4a..30a24fa 100644 --- a/main.cpp +++ b/main.cpp @@ -66,13 +66,20 @@ int main(int argc, const char * argv[]) { } } + bool done {false}; + std::string base_url {"https://www.swiftcoder.nl/cpp1/"}; + std::string next_url {"start.txt"}; + std::string code; requester req; - std::string code {req.get("https://www.swiftcoder.nl/cpp1/start.txt")}; - std::cerr << code << '\n'; - std::istringstream in {code}; interpreter proc; - std::string result {proc.eval(in)}; - std::cerr << result << '\n'; + while (!done) { + code = req.get(base_url + next_url); + std::cerr << code << '\n'; + std::istringstream in {code}; + next_url = proc.eval(in, done); + std::cerr << next_url << '\n'; + } + std::cout << next_url << '\n'; } catch (const std::exception& ex) { std::cerr << "curly: " << ex.what() << '\n';