From d16640ae2a2bc1e8264a1b71008b65f02f1e252b Mon Sep 17 00:00:00 2001 From: tomsmeding Date: Wed, 19 Aug 2015 09:54:11 +0200 Subject: Initial, first working version --- .gitignore | 2 + postrun.cpp | 222 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ test.prn | 2 + 3 files changed, 226 insertions(+) create mode 100644 .gitignore create mode 100644 postrun.cpp create mode 100644 test.prn diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..babfeab --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +postrun +*.dSYM diff --git a/postrun.cpp b/postrun.cpp new file mode 100644 index 0000000..4de856b --- /dev/null +++ b/postrun.cpp @@ -0,0 +1,222 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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("+-*/=> tokenise(istream &stream){ + vector tokens; + string token; + char c,stringmode; + while(true){ + c=stream.get(); + if(!stream)break; + if(isword(c)||(token.size()>0&&isextword(c))){ + token+=c; + } else if(isdigit(c)){ + if(token.size()==0)token="#"; + token+=c; + } else { + if(token.size())tokens.push_back(move(token)); + else if(isoperator(c))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 'x':{ + int res; + c=stream.get(); + cerr<<"Parsed "<='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(); + cerr<='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; + cerr<<(int)c<&,unordered_map&)>> builtins={ + {"+",[](stack &S,unordered_map &variables){ + if(S.size()<2)throw string("Builtin '+' needs 2 stack items"); + Stackitem a,b,c; + b=S.top(); S.pop(); + a=S.top(); S.pop(); + if(!a.isstr&&!b.isstr){ + S.push({false,"",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.push({true,a.strval+b.strval,0}); + }}, + {"-",[](stack &S,unordered_map &variables){ + if(S.size()<2)throw string("Builtin '-' needs 2 stack items"); + Stackitem a,b,c; + 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}); + }}, + {"print",[](stack &S,unordered_map &variables){ + if(S.size()<1)throw string("Builtin 'print' needs 1 stack item"); + Stackitem v; + v=S.top(); S.pop(); + if(v.isstr)cout< &T, + stack &S, + const unordered_map> &functions, + unordered_map &variables){ + unsigned int cursor; + for(cursor=0;cursor'<second); + } else { + auto it=functions.find(word); + if(it!=functions.end()){ + runpass2(it->second,S,functions,variables); + } else { + auto it=builtins.find(word); + if(it==builtins.end())throw "Unknown variable or function '"+word+"'"; + it->second(S,variables); + } + } + } + } +} + +void run(vector T){ + unordered_map> functions; + unordered_map variables; + stack S; + unsigned int cursor=0; + //first pass, handle functions and includes + while(cursor=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 &functoks=functions[name]; + functoks.resize(end-start); + for(unsigned int i=start;i=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 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, evaluate file + runpass2(T,S,functions,variables); +} + +int main(int argc,char **argv){ + if(argc!=2){ + cerr<<"Call this interpreter with the Postrun source file"< tokens=tokenise(srcf); + for(const string &tok : tokens)cerr<<'['<