#include #include #include // #include #include #include #include #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");} struct Fdinfo{ bool read,write; bool open; Fdinfo(void):read(false),write(false),open(false){} Fdinfo(bool _r,bool _w,bool _o):read(_r),write(_w),open(_o){} }; unordered_map fdtable={ {0,{true,false,false}}, {0,{false,true,false}}, {0,{false,true,false}} }; stack>> scopestack; //Each stack frame contains the variables local to the stack frame. The bool is //whether it was already present in the previous frame, and the Stackitem //is the value held by the previous frame, if any. //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.type==SIT_INT&&b.type==SIT_INT){ S.emplace_back(a.intval+b.intval); return; } if(a.type==SIT_ARR||b.type==SIT_ARR){ if(a.type!=SIT_ARR){ b.arrval.insert(b.arrval.begin(),move(a)); S.push_back(move(b)); } else if(b.type!=SIT_ARR){ a.arrval.push_back(move(b)); S.push_back(move(a)); } else { const auto bsz=b.arrval.size(); a.arrval.reserve(a.arrval.size()+b.arrval.size()); for(unsigned int i=0;i at least one is string and other is int if(a.type!=SIT_STR){ S.emplace_back(to_string(a.intval)+b.strval); } else if(b.type!=SIT_STR){ S.emplace_back(a.strval+to_string(b.intval)); } else { 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.type!=SIT_INT||b.type!=SIT_INT) throw string("Builtin '-' expects two number arguments"); 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.type!=SIT_INT||b.type!=SIT_INT) throw string("Builtin '*' expects two number arguments"); 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.type!=SIT_INT||b.type!=SIT_INT) throw string("Builtin '/' expects two number arguments"); 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.type!=SIT_INT||b.type!=SIT_INT) throw string("Builtin '%' expects two number arguments"); 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.type!=SIT_INT||b.type!=SIT_INT) throw string("Builtin '&' expects two number arguments"); 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.type!=SIT_INT||b.type!=SIT_INT) throw string("Builtin '|' expects two number arguments"); S.emplace_back(a.intval|b.intval); }}, {"~",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("~",1) Stackitem &back=S.back(); if(back.type!=SIT_INT)throw string("Builtin '~' expects a number argument"); else back.intval=~back.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.type!=SIT_INT||b.type!=SIT_INT) throw string("Builtin '^' expects two number arguments"); S.emplace_back((int)pow(a.intval,b.intval)); }}, {"!",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("!",1) Stackitem &back=S.back(); if(back.type==SIT_ARR){ back.type=SIT_INT; back.intval=!back.arrval.size(); back.arrval.clear(); } else if(back.type==SIT_STR){ back.type=SIT_INT; back.intval=!back.strval.size(); back.strval.clear(); } else back.intval=!back.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.type==SIT_ARR&&b.type==SIT_ARR)S.emplace_back(a.arrval.size()",[](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.type==SIT_ARR&&b.type==SIT_ARR)S.emplace_back(a.arrval.size()>b.arrval.size()); else if(a.type==SIT_ARR||b.type==SIT_ARR){ throw string("Builtin '>' cannot accept an array and a non-array argument"); } else if(a.type==SIT_STR&&b.type==SIT_STR)S.emplace_back(a.strval>b.strval); else if(a.type==SIT_INT&&b.type==SIT_INT)S.emplace_back(a.intval>b.intval); else if(a.type==SIT_STR)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) 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(move(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.type!=SIT_INT)throw string("Second argument to 'fprint' not a number"); if(!fdtable[file.intval].open||!fdtable[file.intval].write) throw string("File not open or not writable in 'fprint'"); if(v.type==SIT_STR)write(file.intval,v.strval.data(),v.strval.size()); else { string s=to_string(v); 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.type!=SIT_INT)throw string("Argument to 'flf' not a number"); if(!fdtable[file.intval].open||!fdtable[file.intval].write) throw string("File not open or not writable in 'flf'"); 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.type!=SIT_INT)throw string("Argument to 'fgetc' not a number"); if(!fdtable[file.intval].open||!fdtable[file.intval].read) throw string("File not open or not readable in 'fgetc'"); 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.type!=SIT_STR)throw string("First argument to 'fopen' not a string"); if(mode.type!=SIT_STR)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"); fdtable[ret].read=(oflag&O_RDONLY)==O_RDONLY||(oflag&O_RDWR)==O_RDWR; fdtable[ret].write=(oflag&O_WRONLY)==O_WRONLY||(oflag&O_RDWR)==O_RDWR; fdtable[ret].open=true; S.emplace_back(ret); }}, {"fclose",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("fclose",1) Stackitem file=move(S.back()); S.pop_back(); if(file.type!=SIT_INT)throw string("Argument to 'fclose' not a number"); if(!fdtable[file.intval].open) throw string("File not open in 'fclose'"); fdtable.erase(file.intval); if(close(file.intval))perror("close"); }}, {"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.type!=SIT_INT)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(move(b)); S.push_back(move(a)); }}, {"store",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("store",2) Stackitem name=move(S.back()); S.pop_back(); if(name.type!=SIT_STR)throw string("Second argument to 'store' not a string"); auto it=variables.find(name.strval); bool exists=it!=variables.end(); if(scopestack.size()&&scopestack.top().find(name.strval)==scopestack.top().end()){ if(exists) scopestack.top()[name.strval]={move(variables[name.strval]),true}; else scopestack.top()[name.strval]={Stackitem(),false}; } //insert_or_assign is C++17 sadly /*if(exists)variables.insert_or_assign(it,make_pair(name.strval,move(S.back()))); else variables[name.strval]=move(S.back());*/ variables[name.strval]=move(S.back()); S.pop_back(); }}, {"gstore",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("gstore",2) Stackitem name=move(S.back()); S.pop_back(); if(name.type!=SIT_STR)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.type!=SIT_STR)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.type!=SIT_STR)throw string("Second argument to 'swapoutvar' not a string"); auto it=variables.find(name.strval); if(it==variables.end()){ variables.emplace(piecewise_construct, forward_as_tuple(name.strval), forward_as_tuple()); it=variables.find(name.strval); } S.push_back(move(it->second)); it->second.intval=0; it->second.type=SIT_INT; }}, {"enterscope",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("enterscope",0) scopestack.emplace(); }}, {"leavescope",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("leavescope",0) if(scopestack.size()<1)throw string("Scope stack empty while requesting scope leave"); for(const pair> &var : scopestack.top()){ if(var.second.second){ variables[var.first]=move(var.second.first); } else { variables.erase(var.first); } } scopestack.pop(); }}, //positive n: roll off bottom ONTO top (clockwise); negative n: roll OFF top to bottom (anti-clockwise) {"roll",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("roll",1) Stackitem ns=move(S.back()); S.pop_back(); if(ns.type!=SIT_INT)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 tempstore; tempstore.reserve(n); for(int i=0;i &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("rotate",2) Stackitem timess=move(S.back()); S.pop_back(); Stackitem ns=move(S.back()); S.pop_back(); if(ns.type!=SIT_INT)throw string("First argument to 'rotate' not a number"); if(timess.type!=SIT_INT)throw string("Second argument to 'rotate' not a number"); int n=ns.intval,times=timess.intval; bool negative=times<0; if(negative)times=-times; if(n>S.size()||n<0)throw string("Invalid number of items in builtin 'rotate'"); if(n==0)return; if(S.size()<2)return; times%=n; if(times==0)return; if(negative){ vector tempstore; tempstore.reserve(times); const int ssz=S.size(); for(int i=ssz-times;i tempstore; tempstore.reserve(times); const int ssz=S.size(); for(int i=0;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.type!=SIT_STR)throw string("Top of stack is not a string in builtin 'stridx'"); if(idx.type!=SIT_INT)throw string("Argument to 'stridx' not a number"); if(idx.intval<0||idx.intval>=(int)str.strval.size())throw string("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.type!=SIT_STR)throw string("Argument to 'strlen' not a string"); S.emplace_back(str.strval.size()); }}, //leaves the string on the stack; `to` is exclusive {"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.type!=SIT_STR)throw string("Top of stack is not a string in builtin 'substr'"); if(from.type!=SIT_INT)throw string("First argument to 'substr' not a number"); if(to.type!=SIT_INT)throw string("Second 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) if(S.back().type!=SIT_INT)throw string("Argument to 'chr' not a number"); S.back().type=SIT_STR; S.back().strval=string(1,S.back().intval); }}, {"ord",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("ord",1) if(S.back().type!=SIT_STR)throw string("Argument to 'ord' not a string"); S.back().type=SIT_INT; S.back().intval=(int)S.back().strval[0]; S.back().strval.clear(); }}, {"mkarray",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("mkarray",0) S.emplace_back(Stackitem(vector())); }}, //mkarray prefill {"mkarrayp",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("mkarrayp",1) const Stackitem nitems=move(S.back()); S.pop_back(); if(nitems.type!=SIT_INT)throw string("Argument to 'mkarrayp' not a number"); if(nitems.intval<0)throw string("Negative argument to 'mkarrayp'"); BUILTIN_GUARD_STACKSIZE("mkarrayp: prefill",nitems.intval); Stackitem res((vector())); res.arrval.reserve(nitems.intval); const int sz=S.size(); for(int i=sz-nitems.intval;i &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("arridx",2) const Stackitem idx=move(S.back()); S.pop_back(); if(idx.type!=SIT_INT) throw string("Argument to 'arridx' not a number"); if(S.back().type!=SIT_ARR) throw string("Top of stack is not an array in builtin 'arridx'"); if(idx.intval<0||idx.intval>=S.back().arrval.size()) throw string("Argument to 'arridx' out of range"); S.push_back(S.back().arrval[idx.intval]); }}, //leaves the array on the stack {"arrset",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("arrset",3) const Stackitem idx=move(S.back()); S.pop_back(); Stackitem val=move(S.back()); S.pop_back(); if(idx.type!=SIT_INT) throw string("Second argument to 'arrset' not a number"); if(S.back().type!=SIT_ARR) throw string("Top of stack is not an array in builtin 'arrset'"); if(idx.intval<0||idx.intval>=S.back().arrval.size()) throw string("Index argument to 'arrset' out of range"); S.back().arrval[idx.intval]=move(val); }}, //leaves the array on the stack {"arrlen",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("arrlen",1) if(S.back().type!=SIT_ARR) throw string("Top of stack is not an array in builtin 'arrlen'"); S.emplace_back(S.back().arrval.size()); }}, //leaves the array on the stack, obviously {"arrpush",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("arrpush",2) if(S[S.size()-2].type!=SIT_ARR) throw string("Top of stack is not an array in builtin 'arrpush'"); S[S.size()-2].arrval.push_back(move(S.back())); S.pop_back(); }}, //leaves the array on the stack, obviously {"arrpushf",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("arrpushf",2) Stackitem &arrref=S[S.size()-2]; if(arrref.type!=SIT_ARR) throw string("Top of stack is not an array in builtin 'arrpushf'"); arrref.arrval.insert(arrref.arrval.begin(),move(S.back())); S.pop_back(); }}, //leaves the array on the stack, obviously {"arrpop",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("arrpop",1) if(S.back().type!=SIT_ARR) throw string("Top of stack is not an array in builtin 'arrpop'"); S.back().arrval.pop_back(); }}, //leaves the array on the stack, obviously {"arrpopf",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("arrpopf",1) if(S.back().type!=SIT_ARR) throw string("Top of stack is not an array in builtin 'arrpopf'"); S.back().arrval.erase(S.back().arrval.begin()); }}, {"rand",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("rand",0) #if RAND_MAX != 0x7fffffff # error RAND_MAX should be 0x7fffffff for Postrun #endif S.emplace_back(rand()); }}, //`to` exclusive {"randr",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("rand",2) assert(RAND_MAX==0x7fffffff); const Stackitem to=move(S.back()); S.pop_back(); const Stackitem from=move(S.back()); S.pop_back(); if(from.type!=SIT_INT)throw string("First argument to 'randr' not a number"); if(to.type!=SIT_INT)throw string("Second argument to 'randr' not a number"); if(to.intval<=from.intval)throw string("Arguments to 'randr' form an empty range"); const int rval=rand(); S.emplace_back(rval%(to.intval-from.intval)+from.intval); }}, {"sys_select",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("sys_select",4); const Stackitem timeoutstk=move(S.back()); S.pop_back(); const Stackitem erstk=move(S.back()); S.pop_back(); const Stackitem wrstk=move(S.back()); S.pop_back(); const Stackitem rdstk=move(S.back()); S.pop_back(); if(rdstk.type!=SIT_ARR)throw string("First argument to 'sys_select' not an array"); if(wrstk.type!=SIT_ARR)throw string("Second argument to 'sys_select' not an array"); if(erstk.type!=SIT_ARR)throw string("Third argument to 'sys_select' not an array"); if(timeoutstk.type!=SIT_INT)throw string("Fourth argument to 'sys_select' not a number"); fd_set rd,wr,er; FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&er); int mxf=0; for(const Stackitem &si : rdstk.arrval){ if(!fdtable[si.intval].read) throw string("File in read array to 'sys_select' not readable"); FD_SET(si.intval,&rd); if(si.intval>mxf)mxf=si.intval; } for(const Stackitem &si : wrstk.arrval){ if(!fdtable[si.intval].write) throw string("File in read array to 'sys_select' not writable"); FD_SET(si.intval,&wr); if(si.intval>mxf)mxf=si.intval; } for(const Stackitem &si : erstk.arrval){ FD_SET(si.intval,&er); if(si.intval>mxf)mxf=si.intval; } struct timeval *timeout,start,end; if(timeoutstk.intval<0)timeout=NULL; else { timeout=new struct timeval; timeout->tv_sec=timeoutstk.intval/1000000; timeout->tv_usec=timeoutstk.intval%1000000; } gettimeofday(&start,NULL); select(mxf+1,&rd,&wr,&er,timeout); gettimeofday(&end,NULL); const int timetaken=(end.tv_sec-start.tv_sec)*1000000+end.tv_usec-start.tv_usec; delete timeout; Stackitem rdstk2,wrstk2,erstk2; rdstk2.type=SIT_ARR; wrstk2.type=SIT_ARR; erstk2.type=SIT_ARR; for(const Stackitem &si : rdstk.arrval) if(FD_ISSET(si.intval,&rd))rdstk2.arrval.push_back(si.intval); for(const Stackitem &si : wrstk.arrval) if(FD_ISSET(si.intval,&wr))wrstk2.arrval.push_back(si.intval); for(const Stackitem &si : erstk.arrval) if(FD_ISSET(si.intval,&er))erstk2.arrval.push_back(si.intval); S.push_back(move(rdstk2)); S.push_back(move(wrstk2)); S.push_back(move(erstk2)); if(timeoutstk.intval<0||timetaken>=timeoutstk.intval||(rdstk2.arrval.size()==0&&wrstk2.arrval.size()==0&&erstk2.arrval.size()==0))S.emplace_back(0); else S.emplace_back(timeoutstk.intval-timetaken); }}, {"sys_rawmode",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("sys_rawmode",0); struct termios old={0}; if(tcgetattr(0,&old)<0)perror("tcgetattr"); old.c_lflag&=~ICANON; old.c_lflag&=~ECHO; if(tcsetattr(0,TCSANOW,&old)<0)perror("tcsetattr"); }}, {"sys_unrawmode",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("sys_unrawmode",0); struct termios old={0}; if(tcgetattr(0,&old)<0)perror("tcgetattr"); old.c_lflag|=ICANON; old.c_lflag|=ECHO; if(tcsetattr(0,TCSANOW,&old)<0)perror("tcsetattr"); }}, {"sleep",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("sleep",1) if(S.back().type!=SIT_INT)throw string("Argument to 'sleep' not a number"); usleep(S.back().intval); S.pop_back(); }}, {"stackdump",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("stackdump",0) cerr<<"STACKDUMP: "; for(const Stackitem &si : S){ if(si.type==SIT_STR)cerr<<'"'< &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("error",0) exit(1); //STUB IMPLEMENTATION }}, {"exit",[](vector &S,unordered_map &variables){ BUILTIN_GUARD_STACKSIZE("exit",0) exit(0); }}, }; #undef BUILTIN_GUARD_STACKSIZE