/* * SmojoVM ver 0.0.7 * Published by arnold on 17-Feb-2023 15:40 UTC * (c) Terra Weather Pte. Ltd. * This code is released under the * Creative Commons Share-and-Share Alike with Attribution, * version 4.0. */ #include #include #include #include #include #include #include #include using namespace std; class Instance { int IP,RP,SP,LP,DP; vector instructions; vector strings; any dstack[64]; any sstack[16]; any lstack[128]; int rstack[32]; bool running = true; public: Instance(){} Instance( const vector& strings , const vector& libs , const vector& instructions) { this->instructions = instructions; this->strings = strings; IP = LP = 0; DP = RP = SP = -1; /* ISP = -1; initLib(libs); */ } void error( const string& s ){ cout << "ERROR: " << s << "\n" << endl; } void message( const string& s ){ cout << s << endl; } int tob( bool f ){ return f ? 1 : 0; } any a, b, c; void run() { int op; while(running) { op = instructions[IP]; switch(op){ case 0: running=false; break; case 1: ++RP; rstack[RP] = IP + 2; IP = instructions[IP+1]; break; case 2: IP = instructions[IP+1]; break; case 3: if((any_cast(dstack[DP]) != 0)){ IP += 2; }else{ IP = instructions[IP+1]; } --DP; break; case 4: ++DP; dstack[DP] = instructions[IP+1]; IP += 2; break; case 5: ++DP; dstack[DP] = strings[instructions[IP+1]]; IP += 2; break; case 6: lstack[LP + instructions[IP+1]] = dstack[DP]; --DP; IP += 2; break; case 7: ++DP; dstack[DP] = lstack[LP + instructions[IP+1]]; IP += 2; break; case 8: ++RP; rstack[RP]=LP; LP = LP + instructions[IP+1]; IP += 2; break; case 32: IP = rstack[RP]; --RP; break; case 33: LP = rstack[RP]; --RP; ++IP; break; case 36: dstack[DP - 1] = tob(any_cast(dstack[DP-1]) == any_cast(dstack[DP]) ); --DP; ++IP; break; case 37: dstack[DP - 1] = tob(any_cast(dstack[DP-1]) < any_cast(dstack[DP]) ); --DP; ++IP; break; case 38: dstack[DP - 1] = tob(any_cast(dstack[DP-1]) > any_cast(dstack[DP]) ); --DP; ++IP; break; case 39: dstack[DP - 1] = tob(any_cast(dstack[DP-1]) <= any_cast(dstack[DP]) ); --DP; ++IP; break; case 40: dstack[DP - 1] = tob(any_cast(dstack[DP-1]) >= any_cast(dstack[DP]) ); --DP; ++IP; break; case 41: dstack[DP - 1] = any_cast(dstack[DP-1]) % any_cast(dstack[DP]) ; --DP; ++IP; break; case 42: a = dstack[DP]; if (a.type() == typeid(int)) { cout << any_cast(a); } else if (a.type() == typeid(double)) { cout << any_cast(a); } else if (a.type() == typeid(string)) { cout << any_cast(a); } else { cout << "???"; } /* dstack[DP] = null; */ --DP; ++IP; break; case 43: dstack[DP - 1] = any_cast(dstack[DP-1]) + any_cast(dstack[DP]) ; --DP; ++IP; break; case 44: dstack[DP - 1] = any_cast(dstack[DP-1]) - any_cast(dstack[DP]) ; --DP; ++IP; break; case 45: dstack[DP - 1] = any_cast(dstack[DP-1]) * any_cast(dstack[DP]) ; --DP; ++IP; break; case 46: dstack[DP - 1] = any_cast(dstack[DP-1]) / any_cast(dstack[DP]) ; --DP; ++IP; break; case 47: ++DP; dstack[DP] = dstack[DP-1]; ++IP; break; case 48: a = dstack[DP]; dstack[DP] = dstack[DP-1]; dstack[DP-1] = a; ++IP; break; case 49: /* dstack[DP] = null; */ --DP; ++IP; break; case 53: dstack[DP] = dstack[any_cast(dstack[DP])]; ++IP; break; case 54: ++SP; sstack[SP] = dstack[DP]; /* dstack[DP] = null; */ --DP; ++IP; break; case 55: ++DP; dstack[DP] = sstack[SP]; /* sstack[SP] = null; */ --SP; ++IP; break; case 56: ++DP; dstack[DP] = sstack[SP]; ++IP; break; case 57: ++DP; dstack[DP] = DP; ++IP; break; default: error("Unknown opcode " + to_string(op)); running = false; break; } } } }; void error(const string& s) { cout << "ERROR: " << s << "\n" << endl; } void error(const string& msg, const string& desc){ cout << "ERROR: " << msg << "\n\t" << desc << "\n" << endl; } string readStringLocal(const string& uri){ cout << "Loading " << uri << "\n" << endl; return ""; } size_t write_callback(char* ptr, size_t size, size_t nmemb, std::string* userdata) { userdata->append(ptr, size * nmemb); return size * nmemb; } string readStringRemote(const string& uri){ CURL* curl = curl_easy_init(); if (!curl) return ""; string response; curl_easy_setopt(curl, CURLOPT_URL, uri.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); CURLcode res = curl_easy_perform(curl); curl_easy_cleanup(curl); if (res != CURLE_OK) return ""; return response; } string readString(const string& uri){ if(uri.starts_with("file://")) return readStringLocal(uri); return readStringRemote(uri); } vector getIntArray(const string& json) { vector xs = getStringArray(json); if(xs.empty()) return vector(); vector ins = vector(); for(int i = 0 ; i < xs.size(); ++i){ ins.push_back(stoi(xs[i])); } return ins; } string getJsonElement(const string& key, const string& json, const char startDelim, const char endDelim) { string s = "\"" + key + "\":" + startDelim; int a = json.find(s); if(string::npos == a) return ""; a += s.size(); int b = json.find(endDelim,a); if(string::npos == b) { error("Malformed json for:",key); return ""; } return json.substr(a,b-a); } string getJsonArray(const string& key, const string& json) { return getJsonElement(key,json,'[',']'); } void gsub(string& s , const string& oc, const string& nc){ size_t pos = s.find(oc); while (pos != string::npos) { s.replace(pos, oc.length(), nc); pos = s.find(oc, pos + nc.length()); } } string unescape(string& s) { gsub(s,"\"", ""); gsub(s,"%20", " "); gsub(s,"%0A", "\n"); gsub(s,"%0D", "\r"); gsub(s,"%09", "\t"); gsub(s,"%2C", ","); gsub(s,"%22", "\""); gsub(s,"%5B", "["); gsub(s,"%3A", ":"); gsub(s,"%5D", "]"); gsub(s,"%7B", "{"); gsub(s,"%7D", "}"); return s; } void display(const vector& vs){ for(const auto &item : vs){ cout << item << " "; } cout << "\n" << endl; } void display(const vector& vs){ for(const auto &item : vs){ cout << item << " "; } cout << "\n" << endl; } vector split(const string& ws, const char delim){ stringstream ss(ws); vector ret; string x; while (getline(ss, x, delim)) { ret.push_back(x); } return ret; } vector getStringArray(const string& json) { if(json.empty()) return vector(); vector ss = split(json,','); for(int i = 0; i < ss.size(); ++i) ss[i] = unescape(ss[i]); return ss; } Instance loadJsonFromString(const string& json) { vector ss = getStringArray(getJsonArray("strings", json)); vector ls = getStringArray(getJsonArray("libraries", json)); vector ins = getIntArray(getJsonArray("instructions", json)); if(ins.empty()){ error("Can't find instructions."); return nullptr; } /* loadJsonLibraries(ls); */ return new Instance(ss, ls, ins); } Instance loadJson(const string& uri) { return loadJsonFromString(readString(uri)); } /* */ Instance loadInstance(const string& uri) { if(uri.ends_with(".json")) return loadJson(uri); cout << "ERROR: unknown bytecode format:\n\t" << uri << "\n" << endl; return new Instance{}; } int main(int argc, char *argv[]) { if (argc < 2){ cout << "Usage:\n\tsmojovm \n" ; return 1; } Instance c = loadInstance(argv[1]); c.run(); return 0; }