diff options
-rw-r--r-- | postrun.cpp | 184 | ||||
-rw-r--r-- | test.prn | 19 |
2 files changed, 186 insertions, 17 deletions
diff --git a/postrun.cpp b/postrun.cpp index 17d72ca..7d2a08d 100644 --- a/postrun.cpp +++ b/postrun.cpp @@ -7,6 +7,7 @@ #include <functional> #include <cstdlib> #include <cstring> +#include <cmath> using namespace std; @@ -28,7 +29,7 @@ vector<string> tokenise(istream &stream){ token+=c; } else { if(token.size())tokens.push_back(move(token)); - else if(isoperator(c))tokens.push_back(string(1,c)); + if(isoperator(c))tokens.push_back(string(1,c)); else if(c=='"'||c=='\''){ stringmode=c; while(true){ @@ -86,16 +87,22 @@ struct Stackitem{ bool isstr; string strval; int intval; + + Stackitem(void):isstr(false),intval(0){} + Stackitem(int _i):isstr(false),intval(_i){} + Stackitem(const string &_s):isstr(true),strval(_s),intval(0){} + operator bool(void){return (isstr&&strval.size())||(!isstr&&intval);} + bool operator==(const Stackitem &other){return isstr==other.isstr&&(isstr?strval==other.strval:intval==other.intval);} }; const unordered_map<string,function<void(stack<Stackitem>&,unordered_map<string,Stackitem>&)>> builtins={ {"+",[](stack<Stackitem> &S,unordered_map<string,Stackitem> &variables){ if(S.size()<2)throw string("Builtin '+' needs 2 stack items"); - Stackitem a,b,c; + Stackitem a,b; b=S.top(); S.pop(); a=S.top(); S.pop(); if(!a.isstr&&!b.isstr){ - S.push({false,"",a.intval+b.intval}); + S.emplace(a.intval+b.intval); return; } if(!a.isstr){ @@ -106,15 +113,81 @@ const unordered_map<string,function<void(stack<Stackitem>&,unordered_map<string, b.strval=to_string(b.intval); b.isstr=true; } - S.push({true,a.strval+b.strval,0}); + S.emplace(a.strval+b.strval); }}, {"-",[](stack<Stackitem> &S,unordered_map<string,Stackitem> &variables){ if(S.size()<2)throw string("Builtin '-' needs 2 stack items"); - Stackitem a,b,c; + Stackitem a,b; b=S.top(); S.pop(); a=S.top(); S.pop(); if(a.isstr||b.isstr)throw string("Builtin '-' cannot accept a string argument"); - S.push({false,"",a.intval-b.intval}); + S.emplace(a.intval-b.intval); + }}, + {"*",[](stack<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + if(S.size()<2)throw string("Builtin '*' needs 2 stack items"); + Stackitem a,b; + b=S.top(); S.pop(); + a=S.top(); S.pop(); + if(a.isstr||b.isstr)throw string("Builtin '*' cannot accept a string argument"); + S.emplace(a.intval*b.intval); + }}, + {"/",[](stack<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + if(S.size()<2)throw string("Builtin '/' needs 2 stack items"); + Stackitem a,b; + b=S.top(); S.pop(); + a=S.top(); S.pop(); + if(a.isstr||b.isstr)throw string("Builtin '/' cannot accept a string argument"); + S.emplace(a.intval/b.intval); + }}, + {"%",[](stack<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + if(S.size()<2)throw string("Builtin '%' needs 2 stack items"); + Stackitem a,b; + b=S.top(); S.pop(); + a=S.top(); S.pop(); + if(a.isstr||b.isstr)throw string("Builtin '%' cannot accept a string argument"); + S.emplace(a.intval%b.intval); + }}, + {"^",[](stack<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + if(S.size()<2)throw string("Builtin '^' needs 2 stack items"); + Stackitem a,b; + b=S.top(); S.pop(); + a=S.top(); S.pop(); + if(a.isstr||b.isstr)throw string("Builtin '^' cannot accept a string argument"); + S.emplace((int)pow(a.intval,b.intval)); + }}, + {"!",[](stack<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + if(S.size()<1)throw string("Builtin '!' needs 1 stack item"); + Stackitem v; + v=S.top(); S.pop(); + if(v.isstr)S.emplace(!v.strval.size()); + else S.emplace(!v.intval); + }}, + {"=",[](stack<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + if(S.size()<2)throw string("Builtin '=' needs 2 stack items"); + Stackitem a,b; + b=S.top(); S.pop(); + a=S.top(); S.pop(); + S.emplace(a==b); + }}, + {"<",[](stack<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + if(S.size()<2)throw string("Builtin '<' needs 2 stack items"); + Stackitem a,b; + b=S.top(); S.pop(); + a=S.top(); S.pop(); + if(a.isstr&&b.isstr)S.emplace(a.strval<b.strval); + else if(!a.isstr&&!b.isstr)S.emplace(a.intval<b.intval); + else if(a.isstr)S.emplace(a.strval<to_string(b.intval)); + else S.emplace(to_string(a.intval)<b.strval); + }}, + {">",[](stack<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + if(S.size()<2)throw string("Builtin '>' needs 2 stack items"); + Stackitem a,b; + b=S.top(); S.pop(); + a=S.top(); S.pop(); + if(a.isstr&&b.isstr)S.emplace(a.strval>b.strval); + else if(!a.isstr&&!b.isstr)S.emplace(a.intval>b.intval); + else if(a.isstr)S.emplace(a.strval>to_string(b.intval)); + else S.emplace(to_string(a.intval)>b.strval); }}, {"print",[](stack<Stackitem> &S,unordered_map<string,Stackitem> &variables){ if(S.size()<1)throw string("Builtin 'print' needs 1 stack item"); @@ -122,21 +195,33 @@ const unordered_map<string,function<void(stack<Stackitem>&,unordered_map<string, v=S.top(); S.pop(); if(v.isstr)cout<<v.strval<<flush; else cout<<v.intval<<flush; - }} + }}, + {"lf",[](stack<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + cout<<endl; + }}, + {"dup",[](stack<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + if(S.size()<1)throw string("Builtin 'dup' needs 1 stack item"); + S.push(S.top()); + }}, + {"pop",[](stack<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + if(S.size()<1)throw string("Builtin 'pop' needs 1 stack item"); + S.pop(); + }}, }; -void runpass2(const vector<string> &T, +void runpasseval(const vector<string> &T, stack<Stackitem> &S, const unordered_map<string,vector<string>> &functions, - unordered_map<string,Stackitem> &variables){ + unordered_map<string,Stackitem> &variables, + const unordered_map<unsigned int,unsigned int> &jumpmap){ unsigned int cursor; for(cursor=0;cursor<T.size();cursor++){ const string &word=T[cursor]; //cerr<<"Executing word <"<<word<<'>'<<endl; if(word[0]=='#'){ - S.push({false,"",(int)strtol(word.data()+1,NULL,10)}); + S.emplace((int)strtol(word.data()+1,NULL,10)); } else if(word[0]=='\''){ - S.push({true,word.substr(1),0}); + S.push(word.substr(1)); } else { auto it=variables.find(word); if(it!=variables.end()){ @@ -144,8 +229,27 @@ void runpass2(const vector<string> &T, } else { auto it=functions.find(word); if(it!=functions.end()){ - runpass2(it->second,S,functions,variables); + runpasseval(it->second,S,functions,variables,jumpmap); } else { + if(word=="while"){ + if(S.size()<1)throw string("Keyword 'while' needs 1 stack item"); + Stackitem v=S.top(); S.pop(); + if(!v){ + cursor=jumpmap.find(cursor)->second-1; //jump to corresponding end + } + continue; + } else if(word=="if"){ + if(S.size()<1)throw string("Keyword 'if' needs 1 stack item"); + Stackitem v=S.top(); S.pop(); + if(!v){ + cursor=jumpmap.find(cursor)->second-1; //jump to corresponding else/end + } + continue; + } else if(word=="else"||word=="end"){ + cursor=jumpmap.find(cursor)->second-1; + continue; + } + auto it=builtins.find(word); if(it==builtins.end())throw "Unknown variable or function '"+word+"'"; it->second(S,variables); @@ -158,6 +262,7 @@ void runpass2(const vector<string> &T, void run(vector<string> T){ unordered_map<string,vector<string>> functions; unordered_map<string,Stackitem> variables; + unordered_map<unsigned int,unsigned int> jumpmap; stack<Stackitem> S; unsigned int cursor=0; //first pass, handle functions and includes @@ -192,8 +297,59 @@ void run(vector<string> T){ } } - //second pass, evaluate file - runpass2(T,S,functions,variables); + //second pass, index flow control keywords and translate '?' + vector<unsigned int> flowindexes; + for(cursor=0;cursor<T.size();cursor++){ + const string &word=T[cursor]; + if(word=="?")T[cursor]="if"; + if(word=="end"||word=="while"||word=="if"||word=="else")flowindexes.push_back(cursor); + } + + //third pass (over flowindexes), index jump targets in jumpmap + for(unsigned int i=0;i<flowindexes.size();i++){ + const string &word=T[flowindexes[i]]; + if(word=="while"){ + if(i==flowindexes.size()-1)throw string("No 'end' after 'while' in source"); + int depth=1; + unsigned int end; + for(end=i+1;end<flowindexes.size();end++){ + if(T[flowindexes[end]]=="end")depth--; + else if(T[flowindexes[end]]=="while"||T[flowindexes[end]]=="if")depth++; + if(depth==0)break; + } + if(end==flowindexes.size())throw string("No 'end' after 'while' in source"); + jumpmap[flowindexes[i]]=flowindexes[end]+1; + jumpmap[flowindexes[end]]=flowindexes[i]; + } else if(word=="if"){ + if(i==flowindexes.size()-1)throw string("No 'end' after 'if' in source"); + int depth=1; + unsigned int els,end; + for(els=i+1;els<flowindexes.size();els++){ + if(depth==1&&T[flowindexes[els]]=="else")break; + else if(T[flowindexes[els]]=="end")depth--; + else if(T[flowindexes[els]]=="while"||T[flowindexes[els]]=="if")depth++; + if(depth==0)break; + } + if(els==flowindexes.size())throw string("No 'else' after 'if' in source"); + if(depth!=0){ //we found an else + for(end=els+1;end<flowindexes.size();end++){ + if(T[flowindexes[end]]=="end")depth--; + else if(T[flowindexes[end]]=="while"||T[flowindexes[end]]=="if")depth++; + if(depth==0)break; + } + if(end==flowindexes.size())throw string("No 'end' after 'if' in source"); + jumpmap[flowindexes[i]]=flowindexes[els]+1; + jumpmap[flowindexes[els]]=flowindexes[end]+1; + jumpmap[flowindexes[end]]=flowindexes[end]+1; + } else { //we found an end in the first place + jumpmap[flowindexes[i]]=flowindexes[els]+1; + jumpmap[flowindexes[els]]=flowindexes[els]+1; + } + } + } + + //fourth pass, evaluate code + runpasseval(T,S,functions,variables,jumpmap); } int main(int argc,char **argv){ @@ -1,6 +1,19 @@ @defun "hoi" { "hoi\n" print } -hoi hoi hoi -"a" "b\x0a" + print -1 12 + 3 - print +"post" "run\x0a" + print +5 dup while + dup " " + print hoi + 1 - +dup end + +2 1 > if + "2>1!" print lf +else + "logic?" print lf +end + +0 if + "yup!" print lf +end +"done." print lf |