diff options
| author | tomsmeding <hallo@tomsmeding.nl> | 2015-08-19 17:37:41 +0200 | 
|---|---|---|
| committer | tomsmeding <hallo@tomsmeding.nl> | 2015-08-19 19:06:41 +0200 | 
| commit | a8e5f14082f656e8a329969c96940cc547aa54d8 (patch) | |
| tree | ae9d0b2e66e0549e25fb88d48a87fc913dc6be9f | |
| parent | 14ec4b8342ee1abc268d13f6c5c33f982c16f41e (diff) | |
LOTS of stuff and BRAINFUCK INTERPRETER
Lots of builtins added, made ready for the brainfuck interpreter, included as bf.prn.
| -rw-r--r-- | bf.prn | 86 | ||||
| -rw-r--r-- | postrun.cpp | 465 | ||||
| -rw-r--r-- | test.bf | 1 | ||||
| -rw-r--r-- | test.prn | 5 | 
4 files changed, 413 insertions, 144 deletions
@@ -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){ @@ -0,0 +1 @@ +++++++++++[>++++++++++++<-]>----.<+++[>-----<-]>.<++[>+++++++<-]>.+.<++++++++++. @@ -16,4 +16,7 @@ end  0 if  	"yup!" print lf  end -"done." print lf + + +42 "vv" store +vv print lf  | 
