#include #include #include #include #include #include #include #include #include "runtime.h" using namespace std; extern int g_argc; extern char **g_argv; #define BUILTIN_GUARD_STACKSIZE(nm,sz) {if(S.size()<(sz))throw string("Builtin '" nm "' needs " #sz " stack item")+(sz==1?"":"s");} //please extern this shit with const! unordered_map&,unordered_map&)>> builtins={ {"+",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("+",2) Stackitem b=move(S.back()); S.pop_back(); Stackitem a=move(S.back()); S.pop_back(); if(!a.isstr&&!b.isstr){ S.emplace_back(a.intval+b.intval); return; } if(!a.isstr){ a.strval=to_string(a.intval); a.isstr=true; } if(!b.isstr){ b.strval=to_string(b.intval); b.isstr=true; } S.emplace_back(a.strval+b.strval); }}, {"-",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("-",2) Stackitem b=move(S.back()); S.pop_back(); Stackitem a=move(S.back()); S.pop_back(); if(a.isstr||b.isstr)throw string("Builtin '-' cannot accept a string argument"); S.emplace_back(a.intval-b.intval); }}, {"*",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("*",2) Stackitem b=move(S.back()); S.pop_back(); Stackitem a=move(S.back()); S.pop_back(); if(a.isstr||b.isstr)throw string("Builtin '*' cannot accept a string argument"); S.emplace_back(a.intval*b.intval); }}, {"/",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("/",2) Stackitem b=move(S.back()); S.pop_back(); Stackitem a=move(S.back()); S.pop_back(); if(a.isstr||b.isstr)throw string("Builtin '/' cannot accept a string argument"); S.emplace_back(a.intval/b.intval); }}, {"%",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("%",2) Stackitem b=move(S.back()); S.pop_back(); Stackitem a=move(S.back()); S.pop_back(); if(a.isstr||b.isstr){ cerr<<"modding "; if(a.isstr)cerr<<'"'< &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("^",2) Stackitem b=move(S.back()); S.pop_back(); Stackitem a=move(S.back()); S.pop_back(); if(a.isstr||b.isstr)throw string("Builtin '^' cannot accept a string argument"); S.emplace_back((int)pow(a.intval,b.intval)); }}, {"!",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("!",1) Stackitem v=move(S.back()); S.pop_back(); if(v.isstr)S.emplace_back(!v.strval.size()); else S.emplace_back(!v.intval); }}, {"=",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("=",2) Stackitem b=move(S.back()); S.pop_back(); Stackitem a=move(S.back()); S.pop_back(); S.emplace_back(a==b); }}, {"<",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("<",2) Stackitem b=move(S.back()); S.pop_back(); Stackitem a=move(S.back()); S.pop_back(); if(a.isstr&&b.isstr)S.emplace_back(a.strval",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE(">",2) Stackitem b=move(S.back()); S.pop_back(); Stackitem a=move(S.back()); S.pop_back(); if(a.isstr&&b.isstr)S.emplace_back(a.strval>b.strval); else if(!a.isstr&&!b.isstr)S.emplace_back(a.intval>b.intval); else if(a.isstr)S.emplace_back(a.strval>to_string(b.intval)); else S.emplace_back(to_string(a.intval)>b.strval); }}, {"print",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("print",1) Stackitem v=move(S.back()); S.pop_back(); if(v.isstr)cout< &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("lf",0) cout< &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("getline",0) string line; getline(cin,line); if(!cin)S.emplace_back(-1); else S.emplace_back(line); }}, {"getc",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("getc",0) char c=cin.get(); if(!cin)S.emplace_back(-1); else S.emplace_back(string(1,c)); }}, {"fprint",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("fprint",2) Stackitem file=move(S.back()); S.pop_back(); Stackitem v=move(S.back()); S.pop_back(); if(file.isstr)throw string("Second argument to 'fprint' not a number"); if(v.isstr)write(file.intval,v.strval.data(),v.strval.size()); else { string s=to_string(v.intval); write(file.intval,s.data(),s.size()); } }}, {"flf",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("flf",1) Stackitem file=move(S.back()); S.pop_back(); if(file.isstr)throw string("Argument to 'flf' not a number"); write(file.intval,"\n",1); }}, {"fgetc",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("fgetc",1) Stackitem file=move(S.back()); S.pop_back(); if(file.isstr)throw string("Argument to 'fgetc' not a number"); char c; int ret=read(file.intval,&c,1); if(ret==-1)perror("read"); if(ret<=0)S.emplace_back(-1); else S.emplace_back(string(1,c)); }}, {"fopen",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("fopen",2) Stackitem mode=move(S.back()); S.pop_back(); Stackitem fname=move(S.back()); S.pop_back(); if(!fname.isstr)throw string("First argument to 'fopen' not a string"); if(!mode.isstr)throw string("Second argument to 'fopen' not a string"); int oflag=0; if(mode.strval.find('r')!=string::npos)oflag|=O_RDONLY; if(mode.strval.find('w')!=string::npos){ if(oflag&O_RDONLY)oflag=(oflag&~O_RDONLY)|O_RDWR; else oflag|=O_WRONLY; } if(mode.strval.find('a')!=string::npos)oflag|=O_APPEND; if(mode.strval.find('x')!=string::npos)oflag|=O_EXCL|O_CREAT; if(oflag==0)oflag=O_RDONLY; int ret=open(fname.strval.c_str(),oflag); if(ret<0)perror("open"); S.emplace_back(ret); }}, {"argc",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("argc",0) S.emplace_back(g_argc); }}, {"argvget",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("argvget",1) Stackitem idx=move(S.back()); S.pop_back(); if(idx.isstr)throw string("Argument to 'argvget' not a number"); if(idx.intval<0||idx.intval>=g_argc)throw string("Argument to 'argvget' out of bounds"); S.emplace_back(g_argv[idx.intval]); }}, {"dup",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("dup",1) S.push_back(S.back()); }}, {"pop",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("pop",1) S.pop_back(); }}, {"swap",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("swap",2) Stackitem b=move(S.back()); S.pop_back(); Stackitem a=move(S.back()); S.pop_back(); S.push_back(b); S.push_back(a); }}, {"store",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("store",2) Stackitem name=move(S.back()); S.pop_back(); if(!name.isstr)throw string("Second argument to 'store' not a string"); variables[name.strval]=move(S.back()); S.pop_back(); }}, {"get",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("get",1) Stackitem name=move(S.back()); S.pop_back(); if(!name.isstr)throw string("Argument to 'get' not a string"); S.push_back(variables[name.strval]); }}, //leaves variable with value 0 {"swapoutvar",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("swapoutvar",1) Stackitem name=move(S.back()); S.pop_back(); if(!name.isstr)throw string("Second argument to 'swapoutvar' not a string"); S.push_back(move(variables[name.strval])); variables[name.strval].intval=0; }}, //positive n: roll OFF top to bottom; negative n: roll off bottom ONTO top {"roll",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("roll",1) Stackitem ns=move(S.back()); S.pop_back(); if(ns.isstr)throw string("Argument to 'roll' not a number"); int n=ns.intval; if(S.size()<2)return; bool negative=n<0; if(negative)n=-n; n%=S.size(); if(n==0)return; if(negative){ vector tempstore; tempstore.reserve(n); int ssz=S.size(); for(int i=ssz-n;i &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("stridx",2) Stackitem idx=move(S.back()); S.pop_back(); const Stackitem &str=S.back(); if(!str.isstr)throw string("First argument to 'stridx' not a string"); if(idx.isstr)throw string("Second argument to 'stridx' not a number"); if(idx.intval<0||idx.intval>=(int)str.strval.size())throw string("Index argument to 'stridx' out of range"); S.emplace_back(string(1,str.strval[idx.intval])); }}, //leaves the string on the stack {"strlen",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("strlen",1) const Stackitem &str=S.back(); if(!str.isstr)throw string("Argument to 'strlen' not a string"); S.emplace_back(str.strval.size()); }}, //leaves the string on the stack {"substr",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("substr",3) const Stackitem to=move(S.back()); S.pop_back(); const Stackitem from=move(S.back()); S.pop_back(); const Stackitem &str=S.back(); if(!str.isstr)throw string("First argument to 'substr' not a string"); if(from.isstr)throw string("Second argument to 'substr' not a number"); if(to.isstr)throw string("Third argument to 'substr' not a number"); S.emplace_back(str.strval.substr(from.intval,to.intval-from.intval)); }}, {"chr",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("chr",1) Stackitem ascii=move(S.back()); S.pop_back(); if(ascii.isstr)throw string("Argument to 'chr' not a number"); S.emplace_back(string(1,ascii.intval)); }}, {"ord",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("ord",1) if(!S.back().isstr)throw string("Argument to 'ord' not a string"); S.back().isstr=false; S.back().intval=(int)S.back().strval[0]; S.back().strval=""; }}, {"stackdump",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("stackdump",0) cerr<<"STACKDUMP: "; for(const Stackitem &si : S){ if(si.isstr)cerr<<'"'< &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("exit",0) exit(0); }}, }; #undef BUILTIN_GUARD_STACKSIZE