Skip to content

Instantly share code, notes, and snippets.

@itarato
Created October 27, 2018 20:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save itarato/d7270c96a3ee5332d397fc92a71be533 to your computer and use it in GitHub Desktop.
Save itarato/d7270c96a3ee5332d397fc92a71be533 to your computer and use it in GitHub Desktop.
Stack base interpreter
#include <iostream>
#include <string>
#include <utility>
#include <vector>
#include <regex>
#include <unordered_map>
#include <cmath>
using namespace std;
using value_t = double;
template<typename T>
void debug_vec(vector<T> v) {
size_t i{0};
for (const auto & e : v) {
cout << '#' << i++ << ": '" << e << "'" << endl;
}
}
enum IfState {
Exec,
Wait,
};
namespace StackLang {
value_t add(value_t lhs, value_t rhs) { return lhs + rhs; }
value_t mul(value_t lhs, value_t rhs) { return lhs * rhs; }
value_t div(value_t lhs, value_t rhs) { return lhs / rhs; }
value_t sub(value_t lhs, value_t rhs) { return lhs - rhs; }
value_t pow(value_t lhs, value_t rhs) { return std::pow(lhs, rhs); }
value_t sqrt(value_t v) { return std::sqrt(v); }
value_t print(value_t lhs) {
cout << lhs << endl;
return lhs;
}
}
struct Tokenizer {
string source;
Tokenizer(string &&source) : source(move(source)) { };
vector<string> tokenize() {
vector<string> out{};
size_t prev_find{0};
while (prev_find < source.size()) {
size_t current_find = source.find(' ', prev_find);
if (current_find == string::npos) {
current_find = source.size();
}
out.emplace_back(source.substr(prev_find, current_find - prev_find));
prev_find = current_find + 1;
}
return out;
};
};
struct Interpreter {
Tokenizer tokenizer;
vector<value_t> stack;
vector<IfState> if_states;
unordered_map<string, vector<string>> functions;
Interpreter(string &&source) : tokenizer({move(source)}), if_states({}) {
tokens = tokenizer.tokenize();
tokens_it = tokens.begin();
};
void interpret() {
const regex num_regex("^[\\-+]?\\d+(\\.\\d+|)$");
for (optional<string> token_opt = next_token(); token_opt.has_value(); token_opt = next_token()) {
const string token = token_opt.value();
cout << "Token read: '" << token << '\'' << endl;
if (token == "if") {
if (top() != 0.0) {
if_states.emplace_back(IfState::Exec);
} else {
if_states.emplace_back(IfState::Wait);
}
continue;
} else if (token == "else") {
if (if_states.back() == IfState::Exec) {
if_states.back() = IfState::Wait;
} else {
if_states.back() = IfState::Exec;
}
continue;
} else if (token == "endif") {
if_states.pop_back();
continue;
} else if (!if_states.empty() && if_states.back() == IfState::Wait) {
continue;
}
if (regex_match(token, num_regex)) {
push(stod(token));
} else if (token == "fn") {
read_function();
} else if (token == "+") {
push(StackLang::add(pop(), pop()));
} else if (token == "print") {
push(StackLang::print(pop()));
} else if (token == "flush") {
flush();
} else if (token == "dup") {
dup();
} else if (token == "nop") {
// No op.
} else if (token == "pop") {
pop();
} else {
auto fn_it = functions.find(token);
if (fn_it != functions.end()) {
current_fn_key = token;
current_fn_ip = 0;
} else {
cerr << "Unknown command." << endl;
abort();
}
}
}
};
private:
vector<string> tokens;
vector<string>::iterator tokens_it;
optional<string> current_fn_key{};
size_t current_fn_ip{0};
value_t pop() {
if (stack.empty()) {
cerr << "Empty stack cannot pop." << endl;
abort();
}
value_t val{stack.back()};
stack.pop_back();
cout << "POP <" << val << "> to stack." << endl;
return val;
};
void push(value_t val) {
stack.emplace_back(val);
cout << "PUSH <" << val << "> to stack." << endl;
};
value_t top() {
if (stack.empty()) {
cerr << "Empty stack has no top." << endl;
abort();
}
return stack.back();
}
void flush() {
stack.clear();
cout << "FLUSH" << endl;
};
void dup() {
push(stack.back());
};
optional<string> next_token() {
if (current_fn_key.has_value()) {
string token = functions[current_fn_key.value()][current_fn_ip];
current_fn_ip++;
if (current_fn_ip >= functions[current_fn_key.value()].size()) {
current_fn_key = {};
}
return {token};
}
if (tokens_it != tokens.end()) {
string token = *tokens_it;
tokens_it++;
return {token};
}
return {};
}
void read_function() {
string name = next_token().value();
vector<string> tokens{};
for (optional<string> token_opt = next_token(); token_opt.has_value() && token_opt.value() != "endfn"; token_opt = next_token()) {
tokens.emplace_back(token_opt.value());
}
functions[name] = tokens;
}
};
int main() {
Interpreter("1 print").interpret();
Interpreter("fn add + print endfn 2 5 add").interpret();
Interpreter("4 if 1 print else 2 print if 3 print else 4 print endif endif ").interpret();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment