implemented interpreter; setup code dir; added code sync to Makefile
This commit is contained in:
parent
df283d562d
commit
b0a3637b1d
8
Makefile
8
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)
|
||||
|
||||
|
18
code/start.txt
Normal file
18
code/start.txt
Normal file
@ -0,0 +1,18 @@
|
||||
\a
|
||||
=result
|
||||
5
|
||||
=ctr
|
||||
:loop
|
||||
$result
|
||||
dup
|
||||
cat
|
||||
=result
|
||||
$ctr
|
||||
dec
|
||||
=ctr
|
||||
$ctr
|
||||
0
|
||||
>loop
|
||||
gne
|
||||
$result
|
||||
end
|
366
interpreter.cpp
366
interpreter.cpp
@ -7,3 +7,369 @@
|
||||
//
|
||||
|
||||
#include "interpreter.hpp"
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
|
||||
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();
|
||||
}
|
||||
|
@ -13,17 +13,31 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
|
||||
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<std::string> _ops;
|
||||
std::map<std::string, std::vector<std::string>> _funs;
|
||||
std::vector<std::string> _prog;
|
||||
std::vector<std::string> _stack;
|
||||
std::map<std::string, int> _labels;
|
||||
std::map<std::string, std::string> _vars;
|
||||
std::vector<int> _calls;
|
||||
std::vector<std::string>::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_
|
||||
|
17
main.cpp
17
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';
|
||||
|
Loading…
x
Reference in New Issue
Block a user