summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bf.prn86
-rw-r--r--postrun.cpp465
-rw-r--r--test.bf1
-rw-r--r--test.prn5
4 files changed, 413 insertions, 144 deletions
diff --git a/bf.prn b/bf.prn
new file mode 100644
index 0000000..11f0e69
--- /dev/null
+++ b/bf.prn
@@ -0,0 +1,86 @@
+20 "TAPELEN" store
+
+
+##First, read in the source
+
+""
+1 while
+ getline
+ dup -1 = if
+ pop
+ 0
+ else
+ "\n" swap + +
+ 1
+ end
+end
+strlen 1 swap substr swap pop
+#bottom of stack now contains 1 string, the source code
+strlen "len" store
+"code" store
+
+
+
+##Then, create the tape
+TAPELEN
+dup 0 > while
+ 0 swap
+1 - dup 0 > end
+
+
+
+##Finally, start executing
+
+@defun "execute" {
+ #"start of 'execute': " print stackdump
+
+ depth 1 + "depth" store
+
+ #"trying to execute " print dup print lf
+
+ "code" depth + store
+
+ 0 "i" store
+ i len < while
+ #"i = " print i print lf
+ "code" depth + dup swapoutvar
+ i stridx "c" store
+ swap store #uses the dupped name before the matching swapoutvar
+ #"c = " c + print stackdump
+
+ c "+" = if 1 + 256 % end
+ c "-" = if 255 + 256 % end
+ c "." = if dup chr print end
+ c "," = if pop getc ord 256 % end
+ c ">" = if 1 roll end
+ c "<" = if -1 roll end
+ c "]" = if
+ i "loopend" depth 1 - + store
+ len "i" store #essentially, break
+ end
+ c "[" = if
+ i "loopstart" depth + store
+ #"loopstart" print depth print " = " print "loopstart" depth + get print lf
+ dup while
+ "code" depth + get i 1 + len substr swap "code" depth + store execute
+ #stackdump "i = " print i print lf
+ "loopstart" depth + get "i" store
+ dup end
+ "loopend" depth + get 1 + "loopstart" depth + get + "i" store
+ #"after loop, i = " print i print lf
+ end
+
+ i 1 + "i" store
+ i len < end
+
+ depth 1 - "depth" store
+}
+
+0 "depth" store
+
+"code" swapoutvar
+execute #kaboom
+
+depth 0 = ! if
+ "The interpreter exited in depth " depth + "..." + print
+end
diff --git a/postrun.cpp b/postrun.cpp
index 7d2a08d..916c65c 100644
--- a/postrun.cpp
+++ b/postrun.cpp
@@ -3,7 +3,6 @@
#include <sstream>
#include <vector>
#include <unordered_map>
-#include <stack>
#include <functional>
#include <cstdlib>
#include <cstring>
@@ -13,24 +12,36 @@ using namespace std;
inline bool isword(char c){return isalpha(c)||c=='_'||c=='@'||c=='$';}
inline bool isextword(char c){return isword(c)||isdigit(c);}
-inline bool isoperator(char c){return (bool)strchr("+-*/=><!%^?{}",c);}
+inline bool isoperator(char c){return (bool)strchr("+-*/=><!%^{}",c);}
vector<string> tokenise(istream &stream){
vector<string> tokens;
string token;
char c,stringmode;
+ bool gotminus=false;
while(true){
c=stream.get();
if(!stream)break;
- if(isword(c)||(token.size()>0&&isextword(c))){
+ if(c=='#'){
+ while((c=stream.get())!='\n'&&stream);
+ c=stream.get();
+ if(!stream)break;
+ }
+ if(isdigit(c)){
+ if(token.size()==0){
+ token="#";
+ if(gotminus)token+="-";
+ gotminus=false;
+ }
token+=c;
- } else if(isdigit(c)){
- if(token.size()==0)token="#";
+ } else if(isword(c)||(token.size()>0&&isextword(c))){
token+=c;
} else {
if(token.size())tokens.push_back(move(token));
- if(isoperator(c))tokens.push_back(string(1,c));
- else if(c=='"'||c=='\''){
+ if(isoperator(c)){
+ if(c=='-'&&isdigit(stream.peek()))gotminus=true;
+ else tokens.push_back(string(1,c));
+ } else if(c=='"'||c=='\''){
stringmode=c;
while(true){
c=stream.get();
@@ -48,6 +59,8 @@ vector<string> tokenise(istream &stream){
case 'r':c='\r';break;
case 't':c='\t';break;
case '0':c='\0';break;
+ case '"':c='"';break;
+ case '\'':c='\'';break;
case 'x':{
int res;
c=stream.get();
@@ -70,6 +83,7 @@ vector<string> tokenise(istream &stream){
else throw string("Invalid character found in source: '")+c+'\'';
}
}
+ if(token.size())tokens.push_back(move(token));
return tokens;
}
@@ -91,18 +105,31 @@ struct Stackitem{
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);}
+ Stackitem(const Stackitem&)=default;
+ Stackitem(Stackitem &&other):isstr(other.isstr),strval(move(other.strval)),intval(other.intval){
+ other.isstr=false;
+ }
+ Stackitem& operator=(const Stackitem&)=default;
+ Stackitem& operator=(Stackitem &&other){
+ isstr=other.isstr;
+ strval=move(other.strval);
+ intval=other.intval;
+ other.isstr=false;
+ return *this;
+ }
+ explicit operator bool(void) const{return (isstr&&strval.size())||(!isstr&&intval);}
+ bool operator==(const Stackitem &other) const{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;
- b=S.top(); S.pop();
- a=S.top(); S.pop();
+#define BUILTIN_GUARD_STACKSIZE(nm,sz) {if(S.size()<(sz))throw string("Builtin '" nm "' needs " #sz " stack item")+(sz==1?"":"s");}
+
+const unordered_map<string,function<void(vector<Stackitem>&,unordered_map<string,Stackitem>&)>> builtins={
+ {"+",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &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(a.intval+b.intval);
+ S.emplace_back(a.intval+b.intval);
return;
}
if(!a.isstr){
@@ -113,139 +140,271 @@ const unordered_map<string,function<void(stack<Stackitem>&,unordered_map<string,
b.strval=to_string(b.intval);
b.isstr=true;
}
- S.emplace(a.strval+b.strval);
+ S.emplace_back(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;
- b=S.top(); S.pop();
- a=S.top(); S.pop();
+ {"-",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &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(a.intval-b.intval);
+ S.emplace_back(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();
+ {"*",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &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(a.intval*b.intval);
+ S.emplace_back(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();
+ {"/",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &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(a.intval/b.intval);
+ S.emplace_back(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();
+ {"%",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &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<<'"'<<a.strval<<'"'; else cerr<<a.intval;
+ cerr<<" and ";
+ if(b.isstr)cerr<<'"'<<b.strval<<'"'; else cerr<<b.intval;
+ cerr<<endl;
+ }
if(a.isstr||b.isstr)throw string("Builtin '%' cannot accept a string argument");
- S.emplace(a.intval%b.intval);
+ S.emplace_back(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();
+ {"^",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &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((int)pow(a.intval,b.intval));
+ S.emplace_back((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);
+ {"!",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &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);
}},
- {"=",[](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);
+ {"=",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &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);
}},
- {"<",[](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);
+ {"<",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &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);
}},
- {">",[](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);
+ {">",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &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",[](stack<Stackitem> &S,unordered_map<string,Stackitem> &variables){
- if(S.size()<1)throw string("Builtin 'print' needs 1 stack item");
- Stackitem v;
- v=S.top(); S.pop();
+ {"print",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){
+ BUILTIN_GUARD_STACKSIZE("print",1)
+ Stackitem v=move(S.back()); S.pop_back();
if(v.isstr)cout<<v.strval<<flush;
else cout<<v.intval<<flush;
}},
- {"lf",[](stack<Stackitem> &S,unordered_map<string,Stackitem> &variables){
+ {"lf",[](vector<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());
+ {"dup",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){
+ BUILTIN_GUARD_STACKSIZE("dup",1)
+ S.push_back(S.back());
+ }},
+ {"pop",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){
+ BUILTIN_GUARD_STACKSIZE("pop",1)
+ S.pop_back();
+ }},
+ {"swap",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &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<Stackitem> &S,unordered_map<string,Stackitem> &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<Stackitem> &S,unordered_map<string,Stackitem> &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<Stackitem> &S,unordered_map<string,Stackitem> &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<Stackitem> &S,unordered_map<string,Stackitem> &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<Stackitem> tempstore;
+ tempstore.reserve(n);
+ int ssz=S.size();
+ for(int i=ssz-n;i<ssz;i++)tempstore.push_back(move(S[i]));
+ S.erase(S.end()-n,S.end());
+ S.insert(S.begin(),n,Stackitem());
+ for(int i=0;i<n;i++)S[i]=move(tempstore[i]);
+ } else {
+ //cerr<<"rolling back n="<<n<<endl;
+ vector<Stackitem> tempstore;
+ tempstore.reserve(n);
+ for(int i=0;i<n;i++)tempstore.push_back(move(S[i]));
+ S.erase(S.begin(),S.begin()+n);
+ for(int i=0;i<n;i++)S.push_back(move(tempstore[i]));
+ }
+ }},
+ //leaves the string on the stack
+ {"stridx",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &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<Stackitem> &S,unordered_map<string,Stackitem> &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<Stackitem> &S,unordered_map<string,Stackitem> &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<Stackitem> &S,unordered_map<string,Stackitem> &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<Stackitem> &S,unordered_map<string,Stackitem> &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="";
+ }},
+ {"getline",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){
+ BUILTIN_GUARD_STACKSIZE("getline",0)
+ string line;
+ getline(cin,line);
+ if(!cin)S.emplace_back(-1);
+ else S.emplace_back(line);
}},
- {"pop",[](stack<Stackitem> &S,unordered_map<string,Stackitem> &variables){
- if(S.size()<1)throw string("Builtin 'pop' needs 1 stack item");
- S.pop();
+ {"getc",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){
+ BUILTIN_GUARD_STACKSIZE("getc",0)
+ if(!cin)S.emplace_back(-1);
+ else S.emplace_back(string(1,cin.get()));
+ }},
+ {"stackdump",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){
+ BUILTIN_GUARD_STACKSIZE("stackdump",0)
+ cerr<<"STACKDUMP: ";
+ for(const Stackitem &si : S){
+ if(si.isstr)cerr<<'"'<<si.strval<<"\" ";
+ else cerr<<si.intval<<' ';
+ }
+ cerr<<endl;
+ }},
+ {"exit",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){
+ BUILTIN_GUARD_STACKSIZE("exit",0)
+ exit(0);
}},
};
+#undef BUILTIN_GUARD_STACKSIZE
void runpasseval(const vector<string> &T,
- stack<Stackitem> &S,
- const unordered_map<string,vector<string>> &functions,
- unordered_map<string,Stackitem> &variables,
- const unordered_map<unsigned int,unsigned int> &jumpmap){
+ vector<Stackitem> &S,
+ const unordered_map<string,pair<vector<string>,unordered_map<unsigned int,unsigned int>>> &functions,
+ 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.emplace((int)strtol(word.data()+1,NULL,10));
+ S.emplace_back((int)strtol(word.data()+1,NULL,10));
} else if(word[0]=='\''){
- S.push(word.substr(1));
+ S.push_back(word.substr(1));
} else {
auto it=variables.find(word);
if(it!=variables.end()){
- S.push(it->second);
+ S.push_back(it->second);
} else {
auto it=functions.find(word);
if(it!=functions.end()){
- runpasseval(it->second,S,functions,variables,jumpmap);
+ runpasseval(it->second.first,S,functions,variables,it->second.second);
} else {
if(word=="while"){
if(S.size()<1)throw string("Keyword 'while' needs 1 stack item");
- Stackitem v=S.top(); S.pop();
+ Stackitem v=S.back(); S.pop_back();
if(!v){
+ auto it=jumpmap.find(cursor);
+ if(it==jumpmap.end()){
+ cerr<<"NO JUMPMAP ENTRY FOR "<<word<<" AT INDEX "<<cursor<<endl;
+ }
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();
+ Stackitem v=S.back(); S.pop_back();
if(!v){
+ auto it=jumpmap.find(cursor);
+ if(it==jumpmap.end()){
+ cerr<<"NO JUMPMAP ENTRY FOR "<<word<<" AT INDEX "<<cursor<<endl;
+ }
cursor=jumpmap.find(cursor)->second-1; //jump to corresponding else/end
}
continue;
} else if(word=="else"||word=="end"){
+ auto it=jumpmap.find(cursor);
+ if(it==jumpmap.end()){
+ cerr<<"NO JUMPMAP ENTRY FOR "<<word<<" AT INDEX "<<cursor<<endl;
+ }
cursor=jumpmap.find(cursor)->second-1;
continue;
}
@@ -259,53 +418,15 @@ void runpasseval(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
- while(cursor<T.size()){
- const string &word=T[cursor];
- if(word=="@defun"){
- if(cursor+3>=T.size())throw string("Unterminated @defun statement at end of file");
- string name=T[cursor+1];
- if(name[0]!='\'')throw string("@defun expected a string as name, but got '")+name+"'";
- name.erase(0,1);
- if(T[cursor+2]!="{")throw string("Invalid @defun statement of function ")+name;
- unsigned int start=cursor+3;
- unsigned int end;
- for(end=start;end<T.size()&&T[end]!="}";end++);
- vector<string> &functoks=functions[name];
- functoks.resize(end-start);
- for(unsigned int i=start;i<end;i++)functoks[i-start]=move(T[i]);
- T.erase(T.begin()+cursor,T.begin()+end+1);
- } else if(word=="@include"){
- if(cursor+1>=T.size())throw string("Unterminated @include statement at end of file");
- string name=T[cursor+1];
- if(name[0]!='\'')throw string("@include expected a string as file, but got '")+name+"'";
- name.erase(0,1);
- ifstream file(name);
- if(!file)throw string("Could not open file '")+name+"' specified by @include statement";
- vector<string> included=tokenise(file);
- file.close();
- T.erase(T.begin()+cursor,T.begin()+cursor+2);
- T.insert(T.begin()+cursor,included.begin(),included.end());
- } else {
- cursor++;
- }
- }
-
- //second pass, index flow control keywords and translate '?'
+void populatejumpmap(const vector<string> &T,unordered_map<unsigned int,unsigned int> &jumpmap){
+ //first, index flow control keywords
vector<unsigned int> flowindexes;
- for(cursor=0;cursor<T.size();cursor++){
+ for(unsigned int 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
+ //then, index jump targets in jumpmap
for(unsigned int i=0;i<flowindexes.size();i++){
const string &word=T[flowindexes[i]];
if(word=="while"){
@@ -330,7 +451,7 @@ void run(vector<string> T){
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(els==flowindexes.size())throw string("No 'else' or 'end' 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--;
@@ -342,13 +463,71 @@ void run(vector<string> T){
jumpmap[flowindexes[els]]=flowindexes[end]+1;
jumpmap[flowindexes[end]]=flowindexes[end]+1;
} else { //we found an end in the first place
+ //cerr<<"coupling if-end indexes "<<flowindexes[i]<<" and "<<flowindexes[els]<<endl;
jumpmap[flowindexes[i]]=flowindexes[els]+1;
jumpmap[flowindexes[els]]=flowindexes[els]+1;
}
}
}
+}
+
+void run(vector<string> T){
+ unordered_map<string,pair<vector<string>,unordered_map<unsigned int,unsigned int>>> functions;
+ //functions is a pair of tokens and jumpmap
+ unordered_map<string,Stackitem> variables;
+ unordered_map<unsigned int,unsigned int> jumpmap;
+ vector<Stackitem> S;
+ unsigned int cursor=0;
+ //first pass, handle functions and includes
+ while(cursor<T.size()){
+ const string &word=T[cursor];
+ if(word=="@defun"){
+ if(cursor+3>=T.size())throw string("Unterminated @defun statement at end of file");
+ string name=T[cursor+1];
+ if(name[0]!='\'')throw string("@defun expected a string as name, but got '")+name+"'";
+ name.erase(0,1);
+ if(T[cursor+2]!="{")throw string("Invalid @defun statement of function ")+name;
+ unsigned int start=cursor+3;
+ unsigned int end;
+ int depth=1;
+ for(end=start;end<T.size();end++){
+ if(T[end]=="{")depth++;
+ else if(T[end]=="}")depth--;
+ else if(T[end]=="\""){
+ while(++end<T.size()&&T[end]!="\"")if(T[end]=="\\")end++;
+ } else if(T[end]=="'"){
+ while(++end<T.size()&&T[end]!="'")if(T[end]=="\\")end++;
+ }
+ if(depth==0)break;
+ }
+ if(depth!=0)throw string("Non-terminated @defun statement at end of file");
+ vector<string> &functoks=functions[name].first;
+ functoks.resize(end-start);
+ for(unsigned int i=start;i<end;i++)functoks[i-start]=move(T[i]);
+ T.erase(T.begin()+cursor,T.begin()+end+1);
+ } else if(word=="@include"){
+ if(cursor+1>=T.size())throw string("Unterminated @include statement at end of file");
+ string name=T[cursor+1];
+ if(name[0]!='\'')throw string("@include expected a string as file, but got '")+name+"'";
+ name.erase(0,1);
+ ifstream file(name);
+ if(!file)throw string("Could not open file '")+name+"' specified by @include statement";
+ vector<string> included=tokenise(file);
+ file.close();
+ T.erase(T.begin()+cursor,T.begin()+cursor+2);
+ T.insert(T.begin()+cursor,included.begin(),included.end());
+ } else {
+ cursor++;
+ }
+ }
+
+ //second pass, populate jumpmaps
+ populatejumpmap(T,jumpmap);
+ for(auto &p : functions){
+ populatejumpmap(p.second.first,p.second.second);
+ }
- //fourth pass, evaluate code
+ //third pass, evaluate code
runpasseval(T,S,functions,variables,jumpmap);
}
@@ -365,7 +544,7 @@ int main(int argc,char **argv){
//string source=readfile(srcf);
try {
const vector<string> tokens=tokenise(srcf);
- for(const string &tok : tokens)cerr<<'['<<tok<<"] "; cerr<<endl;
+ //for(const string &tok : tokens)cerr<<'['<<tok<<"] "; cerr<<endl;
run(tokens);
srcf.close();
} catch(string e){
diff --git a/test.bf b/test.bf
new file mode 100644
index 0000000..cb6719f
--- /dev/null
+++ b/test.bf
@@ -0,0 +1 @@
+++++++++++[>++++++++++++<-]>----.<+++[>-----<-]>.<++[>+++++++<-]>.+.<++++++++++.
diff --git a/test.prn b/test.prn
index c04d8a9..65549f9 100644
--- a/test.prn
+++ b/test.prn
@@ -16,4 +16,7 @@ end
0 if
"yup!" print lf
end
-"done." print lf
+
+
+42 "vv" store
+vv print lf