diff options
Diffstat (limited to 'runner.h')
-rw-r--r-- | runner.h | 658 |
1 files changed, 658 insertions, 0 deletions
diff --git a/runner.h b/runner.h new file mode 100644 index 0000000..e1faeda --- /dev/null +++ b/runner.h @@ -0,0 +1,658 @@ +#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 <iostream> +#include <stack> +#include <vector> +#include <map> + + +// ********************* 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 <BlChannel, blassic::file::BlFile *> ChanFile; + typedef std::map <BlChannel, BlLineNumber> 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 <GosubElement> 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 <ForElement *, std::vector <ForElement *> > 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 <RepeatElement> 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 <WhileElement> 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 |