summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--postrun.cpp184
-rw-r--r--test.prn19
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){
diff --git a/test.prn b/test.prn
index 4cf7828..c04d8a9 100644
--- a/test.prn
+++ b/test.prn
@@ -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