#ifndef INCLUDE_BLASSIC_RUNNER_H #define INCLUDE_BLASSIC_RUNNER_H // runner.h // Revision 6-feb-2005 //#include "program.h" class Program; #include "blassic.h" #include "error.h" #include "file.h" #include "codeline.h" #include "var.h" #include "element.h" //#include "runnerline.h" #include #include #include #include // ********************* GlobalRunner ********************** namespace blassic { namespace onbreak { enum BreakState { BreakStop, BreakCont, BreakGosub }; } // namespace onbreak } // namespace blassic enum TrigonometricMode { TrigonometricRad, TrigonometricDeg }; // We encapsulate the random generator in a class to have all code // related to it in a place, and to be able to change it easily. // random in some systems may not use the RAND_MAX value, // then we use it only in linux. class RandomGenerator { public: BlNumber operator () () { #if defined __linux__ return BlNumber (random () ) / (RAND_MAX + 1.0); #else return BlNumber (rand () ) / (RAND_MAX + 1.0); #endif } void seed (unsigned int value) { #if defined __linux__ srandom (value); #else srand (value); #endif } }; class GlobalRunner { public: GlobalRunner (Program & prog); ~GlobalRunner (); // Program private: Program & program; public: Program & getprogram () { return program; } // TRON stuff private: bool fTron, fTronLine; BlChannel blcTron; void do_tronline (const CodeLine & line); public: void tron (bool fLine, BlChannel blc); void troff (); void tronline (const CodeLine & codeline) { if (fTron) do_tronline (codeline); } // GlobalRunner Channel stuff public: typedef std::map ChanFile; typedef std::map ChanPolled; private: ChanFile chanfile; ChanPolled chanpolled; bool alreadypolled; bool clearingpolled; public: bool assign_channel_var (const std::string & var, const Dimension & dim, const std::string & value, blassic::file::BlFile::Align align); bool assign_mid_channel_var (const std::string & var, const Dimension & dim, const std::string & value, size_t inipos, std::string::size_type len); bool isfileopen (BlChannel channel) const { return chanfile.find (channel) != chanfile.end (); } BlChannel freefile () const; blassic::file::BlFile & getfile (BlChannel channel) const; void setfile (BlChannel channel, blassic::file::BlFile * npfile); void resetfile0 (); void resetfileprinter (); void close_all (); void destroy_windows (); void closechannel (BlChannel channel); void windowswap (BlChannel ch1, BlChannel ch2); void pollchannel (BlChannel ch, BlLineNumber line); bool channelspolled (); BlLineNumber getpollnumber (); void setpolled (); void clearpolled (); // GlobalRunner DATA / READ / RESTORE stuff private: BlLineNumber datanumline; BlChunk datachunk; unsigned short dataelem; public: BlLineNumber & getdatanumline () { return datanumline; } BlChunk & getdatachunk () { return datachunk; } unsigned short & getdataelem () { return dataelem; } void setreadline (BlLineNumber bln) { datanumline= bln; datachunk= 0; dataelem= 0; } void clearreadline () { datanumline= LineBeginProgram; datachunk= 0; dataelem= 0; } // GlobalRunner ON ERROR GOTO stuff. private: BlLineNumber blnErrorGoto; BlLineNumber blnErrorGotoSource; public: void clearerrorgoto (); void seterrorgoto (BlLineNumber line, BlLineNumber source); BlLineNumber geterrorgoto () const { return blnErrorGoto; } BlLineNumber geterrorgotosource () const { return blnErrorGotoSource; } // GlobalRunner ON BREAK private: blassic::onbreak::BreakState breakstate; BlLineNumber breakgosubline; public: void setbreakstate (blassic::onbreak::BreakState newstate) { breakstate= newstate; } blassic::onbreak::BreakState getbreakstate () const { return breakstate; } void setbreakgosub (BlLineNumber bln) { breakstate= blassic::onbreak::BreakGosub; breakgosubline= bln; } BlLineNumber getbreakgosub () { return breakgosubline; } // Control of depth of fn calls. private: size_t fn_current_level; public: size_t fn_level () const { return fn_current_level; } void inc_fn_level (); void dec_fn_level (); // Trigonometric mode. private: TrigonometricMode trigmode; public: TrigonometricMode trigonometric_mode () const { return trigmode; } void trigonometric_default () { trigmode= TrigonometricRad; } void trigonometric_mode (TrigonometricMode trigmode_n) { trigmode= trigmode_n; } // Random number generator. private: RandomGenerator randgen; public: BlNumber getrandom () { return randgen (); } void seedrandom (unsigned int value) { randgen.seed (value); } }; // ********************* Runner ********************** class GosubStack { private: GlobalRunner & globalrunner; typedef std::stack st_t; st_t st; public: typedef st_t::size_type size_type; public: GosubStack (GlobalRunner & globalrunner); ~GosubStack (); bool empty () const { return st.empty (); } size_type size () const { return st.size (); } void check_fn () const { if (st.empty () ) throw ErrUnexpectedFnEnd; if (st.top ().isgosub () ) throw ErrGosubWithoutReturn; } void erase (); void push (ProgramPos pos, bool is_polled) { st.push (GosubElement (pos, is_polled) ); if (is_polled) globalrunner.setpolled (); } void push (LocalLevel & ll) { st.push (GosubElement (ll) ); } void pop (ProgramPos & ppos) { if (st.empty () ) throw ErrReturnWithoutGosub; GosubElement & go= st.top (); if (! go.isgosub () ) throw ErrReturnWithoutGosub; ppos= go.getpos (); go.freelocalvars (); if (go.ispolled () ) globalrunner.clearpolled (); st.pop (); } void popfn () { if (st.empty () ) throw ErrReturnWithoutGosub; GosubElement & go= st.top (); if (go.isgosub () ) throw ErrGosubWithoutReturn; go.freelocalvars (); st.pop (); } void addlocalvar (const std::string & name) { if (st.empty () ) throw ErrMisplacedLocal; GosubElement go= st.top (); go.addlocalvar (name); } }; class Runner { public: enum RunnerStatus { Ended, FnEnded, ReadyToRun, Running, Stopped, Jump, Goto, //InitingCommand, //Command, JumpResumeNext, LastStatus= JumpResumeNext, }; private: enum StatusRun { KeepRunning, StopNow }; typedef StatusRun (Runner::* checkstatusfunc) (CodeLine &, const CodeLine &); static checkstatusfunc checkstatus [LastStatus + 1]; StatusRun checkstatusEnded (CodeLine & line, const CodeLine & line0); StatusRun checkstatusFnEnded (CodeLine & line, const CodeLine & line0); StatusRun checkstatusReadyToRun (CodeLine & line, const CodeLine & line0); StatusRun checkstatusRunning (CodeLine & line, const CodeLine & line0); StatusRun checkstatusStopped (CodeLine & line, const CodeLine & line0); StatusRun checkstatusJump (CodeLine & line, const CodeLine & line0); StatusRun checkstatusGoto (CodeLine & line, const CodeLine & line0); //StatusRun checkstatusInitingCommand // (CodeLine & line, const CodeLine & line0); //StatusRun checkstatusCommand // (CodeLine & line, const CodeLine & line0); StatusRun checkstatusJumpResumeNext (CodeLine & line, const CodeLine & line0); bool is_run_status (CodeLine & line, const CodeLine & line0); GlobalRunner & globalrunner; Program & program; RunnerStatus status; bool fInElse; bool fInWend; public: //Runner (Program & prog); Runner (GlobalRunner & gr); Runner (const Runner & runner); ~Runner (); Program & getprogram () { return program; } void clear (); void getline (std::string & line); void runline_catch (const CodeLine & codeline, ProgramPos pos, BlError & berr, bool & endloop, bool & dobreak); void runline (const CodeLine & codeline0); void run (); bool editline (BlLineNumber bln, std::string & str); void interactive (); // Runner *********** Errors ************** private: BlCode codprev; BlError berrLast; public: BlErrNo geterr () const; ProgramPos geterrpos () const; BlLineNumber geterrline () const; void clearerror (); BlError geterror () const; void seterror (const BlError & er); // Runner *********** Flow control ************** private: ProgramPos posgoto; public: void setstatus (RunnerStatus stat) { status= stat; } void run_to (BlLineNumber line) { posgoto= line; status= ReadyToRun; } void run_to (ProgramPos pos) { posgoto= pos; status= ReadyToRun; } void jump_to (BlLineNumber line) { posgoto= line; status= Jump; } void jump_to (ProgramPos pos) { posgoto= pos; status= Jump; } void goto_to (BlLineNumber line) { posgoto= line; status= Goto; } void goto_to (ProgramPos pos) { posgoto= pos; status= Goto; } void resume_next (ProgramPos pos) { posgoto= pos; status= JumpResumeNext; } // Runner *********** FOR / NEXT ************** private: std::stack > forstack; public: void push_for (ForElement * pfe) { forstack.push (pfe); } //bool for_empty () const { return forstack.empty (); } ForElement & for_top () { if (forstack.empty () ) throw ErrNextWithoutFor; return * forstack.top (); } void for_pop () { delete forstack.top (); forstack.pop (); } // New version, supposed faster. bool next (); bool next (const std::string & varname); // Runner *********** GOSUB / RETURN / FN ************** private: GosubStack gosubstack; public: bool gosub_empty () const { return gosubstack.empty (); } size_t gosub_size () const { return gosubstack.size (); } void gosub_check_fn () const { gosubstack.check_fn (); } void gosub_pop (ProgramPos & pos) { gosubstack.pop (pos); } void fn_pop () { gosubstack.popfn (); } void gosub_addlocalvar (const std::string & str) { gosubstack.addlocalvar (str); } void gosub_push (LocalLevel & ll) { gosubstack.push (ll); } void gosub_line (BlLineNumber dest, ProgramPos posgosub, bool is_polled= false) { gosubstack.push (posgosub, is_polled); goto_to (dest); } size_t fn_level () const { return globalrunner.fn_level (); } void inc_fn_level () { globalrunner.inc_fn_level (); } void dec_fn_level () { globalrunner.dec_fn_level (); } // Runner *********** REPEAT / UNTIL ************** private: std::stack repeatstack; public: bool repeat_empty () const { return repeatstack.empty (); } void repeat_pop () { repeatstack.pop (); } RepeatElement & repeat_top () { return repeatstack.top (); } void repeat_push (const RepeatElement & re) { repeatstack.push (re); } // Runner *********** WHILE / WEND ************** private: std::stack whilestack; public: bool in_wend () { return fInWend; } void in_wend (bool f) { fInWend= f; } bool while_empty () { return whilestack.empty (); } void while_pop () { whilestack.pop (); } WhileElement & while_top () { return whilestack.top (); } void while_push (const WhileElement & we) { whilestack.push (we); } // Runner *********** TRON ************** void tron (bool fLine, BlChannel blc); void troff (); void tronline (const CodeLine & line) { globalrunner.tronline (line); } // Runner *********** BREAK / CONT ************** private: ProgramPos posbreak; public: void jump_break () { //if (! posbreak) if (posbreak.getnum () == LineEndProgram || posbreak.getnum () == LineDirectCommand) throw ErrNoContinue; posgoto= posbreak; //posbreak= 0; posbreak= LineEndProgram; status= Jump; } void set_break (ProgramPos pos) { posbreak= pos; } #if 0 void setbreakstate (BreakState newstate) { breakstate= newstate; } BreakState getbreakstate () { return breakstate; } void setbreakgosub (BlLineNumber bln) { breakstate= BreakGosub; breakgosubline= bln; } BlLineNumber getbreakgosub () { return breakgosubline; } #else void setbreakstate (blassic::onbreak::BreakState newstate) { globalrunner.setbreakstate (newstate); } blassic::onbreak::BreakState getbreakstate () const { return globalrunner.getbreakstate (); } void setbreakgosub (BlLineNumber bln) { globalrunner.setbreakgosub (bln); } BlLineNumber getbreakgosub () { return globalrunner.getbreakgosub (); } #endif // Runner *********** DATA / READ / RESTORE ************** BlLineNumber & getdatanumline () { return globalrunner.getdatanumline (); } BlChunk & getdatachunk () { return globalrunner.getdatachunk (); } unsigned short & getdataelem () { return globalrunner.getdataelem (); } // Runner *********** ON ERROR GOTO ************** void showfailerrorgoto () const; void clearerrorgoto () { globalrunner.clearerrorgoto (); } void seterrorgoto (BlLineNumber line, BlLineNumber source) { globalrunner.seterrorgoto (line, source); } BlLineNumber geterrorgoto () const { return globalrunner.geterrorgoto (); } BlLineNumber geterrorgotosource () const { return globalrunner.geterrorgotosource (); } // Runner *********** Channels ************** #if 0 void assign_channel_var (const std::string & var, const std::string & value, blassic::file::BlFile::Align align) { for (ChanFile::iterator it= chanfile.begin (); it != chanfile.end (); ++it) { it->second->assign (var, value, align); } } #else bool assign_channel_var (const std::string & var, const Dimension & dim, const std::string & value, blassic::file::BlFile::Align align) { return globalrunner.assign_channel_var (var, dim, value, align); } #endif bool assign_mid_channel_var (const std::string & var, const Dimension & dim, const std::string & value, size_t inipos, std::string::size_type len) { return globalrunner.assign_mid_channel_var (var, dim, value, inipos, len); } //bool isfileopen (BlChannel channel) const //{ return chanfile.find (channel) != chanfile.end (); } bool isfileopen (BlChannel channel) const { return globalrunner.isfileopen (channel); } BlChannel freefile () const { return globalrunner.freefile (); } blassic::file::BlFile & getfile (BlChannel channel) const { return globalrunner.getfile (channel); } blassic::file::BlFile & getfile0 () const { return globalrunner.getfile (DefaultChannel); } void setfile (BlChannel channel, blassic::file::BlFile * npfile) { globalrunner.setfile (channel, npfile); } void resetfile0 () { globalrunner.resetfile0 (); } void close_all () { globalrunner.close_all (); } void destroy_windows () { globalrunner.destroy_windows (); } void closechannel (BlChannel channel) { globalrunner.closechannel (channel); } void windowswap (BlChannel ch1, BlChannel ch2) { globalrunner.windowswap (ch1, ch2); } void pollchannel (BlChannel ch, BlLineNumber line) { globalrunner.pollchannel (ch, line); } bool channelspolled () { return globalrunner.channelspolled (); } BlLineNumber getpollnumber () { return globalrunner.getpollnumber (); } void spectrumwindows (); // Runner *********** DATA / READ / RESTORE ************** void setreadline (BlLineNumber bln) { globalrunner.setreadline (bln); } void clearreadline () { globalrunner.clearreadline (); } // Runner *********** AUTO ************** private: BlLineNumber blnAuto, blnAutoInc; public: void setauto (BlLineNumber line, BlLineNumber inc) { blnAuto= line; blnAutoInc= inc; } // Runner *********** Trigonometric mode ************** TrigonometricMode trigonometric_mode () { return globalrunner.trigonometric_mode (); } void trigonometric_default () { globalrunner.trigonometric_default (); } void trigonometric_mode (TrigonometricMode trigmode_n) { globalrunner.trigonometric_mode (trigmode_n); } private: bool processline (const std::string & line); public: // Runner *********** Random number generator ************** BlNumber getrandom () { return globalrunner.getrandom (); } void seedrandom (unsigned int value) { globalrunner.seedrandom (value); } // Runner *********** Auxiliars ************** void clean_input (); void ring (); void set_title (const std::string & str); }; std::ostream & operator << (std::ostream & os, Runner::RunnerStatus status); #endif // Fin de runner.h