summaryrefslogtreecommitdiff
path: root/postrun.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'postrun.cpp')
-rw-r--r--postrun.cpp572
1 files changed, 2 insertions, 570 deletions
diff --git a/postrun.cpp b/postrun.cpp
index 78998cf..4933d8b 100644
--- a/postrun.cpp
+++ b/postrun.cpp
@@ -10,88 +10,13 @@
#include <unistd.h>
#include <fcntl.h>
-using namespace std;
+#include "runtime.h"
-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);}
+using namespace std;
int g_argc;
char **g_argv;
-vector<string> tokenise(istream &stream){
- vector<string> tokens;
- string token;
- char c,stringmode;
- bool gotminus=false;
- while(true){
- c=stream.get();
- if(!stream)break;
- while(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(isword(c)||(token.size()>0&&isextword(c))){
- token+=c;
- } else {
- if(token.size())tokens.push_back(move(token));
- 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();
- if(!stream)throw string("Non-terminated string at end of file");
- if(c==stringmode){
- token="'"+token;
- tokens.push_back(move(token));
- break;
- }
- if(c=='\\'){
- c=stream.get();
- if(!stream)throw string("Non-terminated escape sequence in string at end of file");
- switch(c){
- case 'n':c='\n';break;
- 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();
- if(!stream)throw string("Non-terminated hexadecimal escape sequence in string at end of file");
- res=c>='0'&&c<='9'?c-'0':(c>='a'&&c<='f')||(c>='A'&&c<='F')?(c&~32)-'A'+10:-1;
- if(res==-1)throw "Invalid character '"+string(1,c)+"'' in hexadecimal escape sequence in string";
- res*=16;
- c=stream.get();
- if(!stream)throw string("Non-terminated hexadecimal escape sequence in string at end of file");
- res+=c>='0'&&c<='9'?c-'0':(c>='a'&&c<='f')||(c>='A'&&c<='F')?(c&~32)-'A'+10:-241;
- if(res<0)throw "Invalid character '"+string(1,c)+"'' in hexadecimal escape sequence in string";
- c=(char)res;
- break;
- }
- }
- }
- token+=c;
- }
- } else if(isspace(c));
- else throw string("Invalid character found in source: '")+c+'\'';
- }
- }
- if(token.size())tokens.push_back(move(token));
- return tokens;
-}
-
string readfile(ifstream stream){
stream.seekg(0,ios::end);
size_t len=stream.tellg();
@@ -102,499 +27,6 @@ string readfile(ifstream stream){
return contents;
}
-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){}
- 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);}
-};
-
-#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_back(a.intval+b.intval);
- return;
- }
- if(!a.isstr){
- a.strval=to_string(a.intval);
- a.isstr=true;
- }
- if(!b.isstr){
- b.strval=to_string(b.intval);
- b.isstr=true;
- }
- S.emplace_back(a.strval+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)throw string("Builtin '-' cannot accept a string argument");
- S.emplace_back(a.intval-b.intval);
- }},
- {"*",[](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_back(a.intval*b.intval);
- }},
- {"/",[](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_back(a.intval/b.intval);
- }},
- {"%",[](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_back(a.intval%b.intval);
- }},
- {"^",[](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_back((int)pow(a.intval,b.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);
- }},
- {"=",[](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);
- }},
- {"<",[](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);
- }},
- {">",[](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",[](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",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){
- BUILTIN_GUARD_STACKSIZE("lf",0)
- cout<<endl;
- }},
- {"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);
- }},
- {"getc",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &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<Stackitem> &S,unordered_map<string,Stackitem> &variables){
- BUILTIN_GUARD_STACKSIZE("fprint",2)
- Stackitem file=move(S.back()); S.pop_back();
- Stackitem v=move(S.back()); S.pop_back();
- if(file.isstr)throw string("Second argument to 'fprint' not a number");
- if(v.isstr)write(file.intval,v.strval.data(),v.strval.size());
- else {
- string s=to_string(v.intval);
- write(file.intval,s.data(),s.size());
- }
- }},
- {"flf",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){
- BUILTIN_GUARD_STACKSIZE("flf",1)
- Stackitem file=move(S.back()); S.pop_back();
- if(file.isstr)throw string("Argument to 'flf' not a number");
- write(file.intval,"\n",1);
- }},
- {"fgetc",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){
- BUILTIN_GUARD_STACKSIZE("fgetc",1)
- Stackitem file=move(S.back()); S.pop_back();
- if(file.isstr)throw string("Argument to 'fgetc' not a number");
- 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<Stackitem> &S,unordered_map<string,Stackitem> &variables){
- BUILTIN_GUARD_STACKSIZE("fopen",2)
- Stackitem mode=move(S.back()); S.pop_back();
- Stackitem fname=move(S.back()); S.pop_back();
- if(!fname.isstr)throw string("First argument to 'fopen' not a string");
- if(!mode.isstr)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");
- S.emplace_back(ret);
- }},
- {"argc",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){
- BUILTIN_GUARD_STACKSIZE("argc",0)
- S.emplace_back(g_argc);
- }},
- {"argvget",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){
- BUILTIN_GUARD_STACKSIZE("argvget",1)
- Stackitem idx=move(S.back()); S.pop_back();
- if(idx.isstr)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<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="";
- }},
- {"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,
- 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_back((int)strtol(word.data()+1,NULL,10));
- } else if(word[0]=='\''){
- S.push_back(word.substr(1));
- } else {
- auto it=variables.find(word);
- if(it!=variables.end()){
- S.push_back(it->second);
- } else {
- auto it=functions.find(word);
- if(it!=functions.end()){
- 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.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.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;
- }
-
- auto it=builtins.find(word);
- if(it==builtins.end())throw "Unknown variable or function '"+word+"'";
- it->second(S,variables);
- }
- }
- }
- }
-}
-
-void populatejumpmap(const vector<string> &T,unordered_map<unsigned int,unsigned int> &jumpmap){
- //first, index flow control keywords
- vector<unsigned int> flowindexes;
- for(unsigned int cursor=0;cursor<T.size();cursor++){
- const string &word=T[cursor];
- if(word=="end"||word=="while"||word=="if"||word=="else")flowindexes.push_back(cursor);
- }
-
- //then, 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' 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--;
- 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
- //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);
- }
-
- //third pass, evaluate code
- runpasseval(T,S,functions,variables,jumpmap);
-}
-
int main(int argc,char **argv){
if(argc<2){
cerr<<"Call this interpreter with the Postrun source file"<<endl;