diff options
author | tomsmeding <hallo@tomsmeding.nl> | 2015-12-29 13:17:37 +0100 |
---|---|---|
committer | tomsmeding <hallo@tomsmeding.nl> | 2015-12-29 13:17:37 +0100 |
commit | 2a952e107509cbc743b351e32663bfc8c6df9211 (patch) | |
tree | 0f3f47899e07ad1e495ad551f9ab19b4f16e9b2e | |
parent | 92c104d8a2ba69db1f59890d2f62019186aece05 (diff) |
add sys_select (WIP) and fix source from stdin
-rw-r--r-- | functions.cpp | 106 | ||||
-rw-r--r-- | postrun.cpp | 30 | ||||
-rw-r--r-- | runtime.cpp | 16 |
3 files changed, 139 insertions, 13 deletions
diff --git a/functions.cpp b/functions.cpp index 4e67bfa..91f6ba9 100644 --- a/functions.cpp +++ b/functions.cpp @@ -10,6 +10,9 @@ #include <cassert> #include <unistd.h> #include <fcntl.h> +#include <termios.h> +#include <sys/time.h> +#include <sys/select.h> #include "runtime.h" @@ -20,6 +23,20 @@ extern char **g_argv; #define BUILTIN_GUARD_STACKSIZE(nm,sz) {if(S.size()<(sz))throw string("Builtin '" nm "' needs " #sz " stack item")+(sz==1?"":"s");} +struct Fdinfo{ + bool read,write; + bool open; + + Fdinfo(void):read(false),write(false),open(false){} + Fdinfo(bool _r,bool _w,bool _o):read(_r),write(_w),open(_o){} +}; + +unordered_map<int,Fdinfo> fdtable={ + {0,{true,false,false}}, + {0,{false,true,false}}, + {0,{false,true,false}} +}; + stack<unordered_map<string,pair<Stackitem,bool>>> scopestack; //Each stack frame contains the variables local to the stack frame. The bool is //whether it was already present in the previous frame, and the Stackitem @@ -191,6 +208,8 @@ unordered_map<string,function<void(vector<Stackitem>&,unordered_map<string,Stack Stackitem file=move(S.back()); S.pop_back(); Stackitem v=move(S.back()); S.pop_back(); if(file.type!=SIT_INT)throw string("Second argument to 'fprint' not a number"); + if(!fdtable[file.intval].open||!fdtable[file.intval].write) + throw string("File not open or not writable in 'fprint'"); if(v.type==SIT_STR)write(file.intval,v.strval.data(),v.strval.size()); else { string s=to_string(v); @@ -201,12 +220,16 @@ unordered_map<string,function<void(vector<Stackitem>&,unordered_map<string,Stack BUILTIN_GUARD_STACKSIZE("flf",1) Stackitem file=move(S.back()); S.pop_back(); if(file.type!=SIT_INT)throw string("Argument to 'flf' not a number"); + if(!fdtable[file.intval].open||!fdtable[file.intval].write) + throw string("File not open or not writable in 'flf'"); 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.type!=SIT_INT)throw string("Argument to 'fgetc' not a number"); + if(!fdtable[file.intval].open||!fdtable[file.intval].read) + throw string("File not open or not readable in 'fgetc'"); char c; int ret=read(file.intval,&c,1); if(ret==-1)perror("read"); @@ -230,8 +253,20 @@ unordered_map<string,function<void(vector<Stackitem>&,unordered_map<string,Stack if(oflag==0)oflag=O_RDONLY; int ret=open(fname.strval.c_str(),oflag); if(ret<0)perror("open"); + fdtable[ret].read=(oflag&(O_RDONLY|O_RDWR))!=0; + fdtable[ret].write=(oflag&(O_WRONLY|O_RDWR))!=0; + fdtable[ret].open=true; S.emplace_back(ret); }}, + {"fclose",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("fclose",1) + Stackitem file=move(S.back()); S.pop_back(); + if(file.type!=SIT_INT)throw string("Argument to 'fclose' not a number"); + if(!fdtable[file.intval].open) + throw string("File not open in 'fclose'"); + fdtable.erase(file.intval); + if(close(file.intval))perror("close"); + }}, {"argc",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ BUILTIN_GUARD_STACKSIZE("argc",0) S.emplace_back(g_argc); @@ -522,6 +557,77 @@ unordered_map<string,function<void(vector<Stackitem>&,unordered_map<string,Stack const int rval=rand(); S.emplace_back(rval%(to.intval-from.intval)+from.intval); }}, + {"sys_select",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("sys_select",4); + const Stackitem timeoutstk=move(S.back()); S.pop_back(); + const Stackitem erstk=move(S.back()); S.pop_back(); + const Stackitem wrstk=move(S.back()); S.pop_back(); + const Stackitem rdstk=move(S.back()); S.pop_back(); + if(rdstk.type!=SIT_ARR)throw string("First argument to 'sys_select' not an array"); + if(wrstk.type!=SIT_ARR)throw string("Second argument to 'sys_select' not an array"); + if(erstk.type!=SIT_ARR)throw string("Third argument to 'sys_select' not an array"); + if(timeoutstk.type!=SIT_INT)throw string("Fourth argument to 'sys_select' not a number"); + fd_set rd,wr,er; + FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&er); + int mxf=0; + for(const Stackitem &si : rdstk.arrval){ + if(!fdtable[si.intval].read) + throw string("File in read array to 'sys_select' not readable"); + FD_SET(si.intval,&rd); + if(si.intval>mxf)mxf=si.intval; + } + for(const Stackitem &si : wrstk.arrval){ + if(!fdtable[si.intval].write) + throw string("File in read array to 'sys_select' not writable"); + FD_SET(si.intval,&wr); + if(si.intval>mxf)mxf=si.intval; + } + for(const Stackitem &si : erstk.arrval){ + FD_SET(si.intval,&er); + if(si.intval>mxf)mxf=si.intval; + } + struct timeval *timeout,start,end; + if(timeoutstk.intval<0)timeout=NULL; + else { + timeout=new struct timeval; + timeout->tv_sec=timeoutstk.intval/1000000; + timeout->tv_usec=timeoutstk.intval%1000000; + } + gettimeofday(&start,NULL); + select(mxf+1,&rd,&wr,&er,timeout); + gettimeofday(&end,NULL); + const int timetaken=(end.tv_sec-start.tv_sec)*1000000+end.tv_usec-start.tv_usec; + delete timeout; + Stackitem rdstk2,wrstk2,erstk2; + rdstk2.type=SIT_ARR; wrstk2.type=SIT_ARR; erstk2.type=SIT_ARR; + for(const Stackitem &si : rdstk.arrval) + if(FD_ISSET(si.intval,&rd))rdstk2.arrval.push_back(si.intval); + for(const Stackitem &si : wrstk.arrval) + if(FD_ISSET(si.intval,&wr))wrstk2.arrval.push_back(si.intval); + for(const Stackitem &si : erstk.arrval) + if(FD_ISSET(si.intval,&er))erstk2.arrval.push_back(si.intval); + S.push_back(move(rdstk2)); + S.push_back(move(wrstk2)); + S.push_back(move(erstk2)); + if(timeoutstk.intval<0||timetaken>=timeoutstk.intval||(rdstk2.arrval.size()==0&&wrstk2.arrval.size()==0&&erstk2.arrval.size()==0))S.emplace_back(0); + else S.emplace_back(timeoutstk.intval-timetaken); + }}, + {"sys_rawmode",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("sys_rawmode",0); + struct termios old={0}; + if(tcgetattr(0,&old)<0)perror("tcgetattr"); + old.c_lflag&=~ICANON; + old.c_lflag&=~ECHO; + if(tcsetattr(0,TCSANOW,&old)<0)perror("tcsetattr"); + }}, + {"sys_unrawmode",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ + BUILTIN_GUARD_STACKSIZE("sys_unrawmode",0); + struct termios old={0}; + if(tcgetattr(0,&old)<0)perror("tcgetattr"); + old.c_lflag|=ICANON; + old.c_lflag|=ECHO; + if(tcsetattr(0,TCSANOW,&old)<0)perror("tcsetattr"); + }}, {"sleep",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){ BUILTIN_GUARD_STACKSIZE("sleep",1) if(S.back().type!=SIT_INT)throw string("Argument to 'sleep' not a number"); diff --git a/postrun.cpp b/postrun.cpp index 2c3c97f..c880337 100644 --- a/postrun.cpp +++ b/postrun.cpp @@ -11,6 +11,8 @@ using namespace std; int g_argc; char **g_argv; +bool input_is_stdin=false; + string readfile(ifstream stream){ stream.seekg(0,ios::end); size_t len=stream.tellg(); @@ -26,24 +28,30 @@ int main(int argc,char **argv){ cerr<<"Call this interpreter with the Postrun source file"<<endl; return 1; } - g_argc=argc-2; - g_argv=argv+2; //skip this executable and the postrun file - ifstream srcf(argv[1]); - if(!srcf){ - cerr<<"Could not open file '"<<argv[1]<<"'"<<endl; - return 1; - } struct timeval tv; gettimeofday(&tv,NULL); srand(tv.tv_sec*1000000+tv.tv_usec); - //string source=readfile(srcf); + g_argc=argc-2; + g_argv=argv+2; //skip this executable and the postrun file + try { - const vector<string> tokens=tokenise(srcf); - //for(const string &tok : tokens)cerr<<'['<<tok<<"] "; cerr<<endl; + ifstream srcf; + vector<string> tokens; + if(strcmp(argv[1],"-")==0){ + tokens=tokenise(cin); + input_is_stdin=true; + } else { + srcf.open(argv[1]); + if(!srcf){ + cerr<<"Could not open file '"<<argv[1]<<"'"<<endl; + return 1; + } + tokens=tokenise(srcf); + } run(tokens); - srcf.close(); + if(srcf)srcf.close(); } catch(string e){ cerr<<"ERROR: "<<e<<endl; return 1; diff --git a/runtime.cpp b/runtime.cpp index 19108cd..9fbb3c5 100644 --- a/runtime.cpp +++ b/runtime.cpp @@ -7,9 +7,12 @@ #include <functional> #include <cstring> #include <cassert> +#include <termios.h> #include "runtime.h" +extern bool input_is_stdin; + using namespace std; inline bool isword(char c){return isalpha(c)||c=='_'||c=='@'||c=='$';} @@ -94,8 +97,8 @@ vector<string> tokenise(istream &stream){ while(c=='#'){ while((c=stream.get())!='\n'&&stream); c=stream.get(); - if(!stream)break; } + if(!stream)break; if(isdigit(c)){ if(token.size()==0){ token="#"; @@ -149,7 +152,7 @@ vector<string> tokenise(istream &stream){ token+=c; } } else if(isspace(c)); - else throw string("Invalid character found in source: '")+c+'\''; + else throw string("Invalid character found in source: '")+c+"' ("+to_string((int)(unsigned char)c)+')'; } } if(token.size())tokens.push_back(move(token)); @@ -346,4 +349,13 @@ void run(vector<string> T){ //third pass, evaluate code runpasseval(T,S,functions,variables,jumpmap); + + if(!input_is_stdin){ + //restore canonical mode, since the code might have changed it to raw mode + struct termios old={0}; + if(tcgetattr(0,&old)<0)perror("tcgetattr"); + old.c_lflag|=ICANON; + old.c_lflag|=ECHO; + if(tcsetattr(0,TCSANOW,&old)<0)perror("tcsetattr"); + } } |