aboutsummaryrefslogtreecommitdiffstats
path: root/runner.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'runner.cpp')
-rw-r--r--runner.cpp2190
1 files changed, 2190 insertions, 0 deletions
diff --git a/runner.cpp b/runner.cpp
new file mode 100644
index 0000000..546b660
--- /dev/null
+++ b/runner.cpp
@@ -0,0 +1,2190 @@
+// runner.cpp
+// Revision 24-apr-2009
+
+#include "runner.h"
+
+#include "result.h"
+
+// Testing
+#include "runnerline.h"
+//#include "runnerline_impl.h"
+
+#include "program.h"
+#include "keyword.h"
+#include "var.h"
+#include "codeline.h"
+#include "dim.h"
+#include "cursor.h"
+#include "graphics.h"
+#include "sysvar.h"
+
+#include "util.h"
+using util::to_string;
+using util::touch;
+
+#include "trace.h"
+#include "edit.h"
+#include "socket.h"
+#include "memory.h"
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <iomanip>
+#include <cmath>
+#include <ctime>
+#include <vector>
+#include <algorithm>
+#include <memory>
+#include <typeinfo>
+
+#include <math.h>
+
+#include <cassert>
+#define ASSERT assert
+
+#if __BORLANDC__ >= 0x0560
+#pragma warn -8091
+#endif
+
+using std::cerr;
+using std::endl;
+using std::for_each;
+using std::auto_ptr;
+
+namespace sysvar= blassic::sysvar;
+namespace onbreak= blassic::onbreak;
+
+using namespace blassic::file;
+
+//************************************************
+// Auxiliar
+//************************************************
+
+namespace {
+
+const std::string strbreak ("**+BREAK+**");
+
+void deletefile (GlobalRunner::ChanFile::value_type & chf)
+{
+ delete chf.second;
+}
+
+} // namespace
+
+//************************************************
+// GlobalRunner
+//************************************************
+
+GlobalRunner::GlobalRunner (Program & prog) :
+ program (prog),
+ fTron (false),
+ alreadypolled (false),
+ breakstate (onbreak::BreakStop),
+ fn_current_level (0)
+{
+ TRACEFUNC (tr, "GlobalRunner::GlobalRunner");
+
+ clearerrorgoto ();
+ clearreadline ();
+ resetfile0 ();
+ resetfileprinter ();
+ trigonometric_default ();
+}
+
+GlobalRunner::~GlobalRunner ()
+{
+ TRACEFUNC (tr, "GlobalRunner::~GlobalRunner");
+
+ for_each (chanfile.begin (), chanfile.end (), deletefile);
+ blassic::memory::dyn_freeall ();
+}
+
+void GlobalRunner::tron (bool fLine, BlChannel blc)
+{
+ fTron= true;
+ fTronLine= fLine;
+ BlChar flags= static_cast <BlChar> (fLine ? 3 : 1);
+ BlChar oldflags= sysvar::get (sysvar::TronFlags);
+ flags= flags | (oldflags & static_cast <BlChar> (~3) );
+ sysvar::set (sysvar::TronFlags, flags);
+ blcTron= blc;
+ sysvar::set16 (sysvar::TronChannel, blc);
+}
+
+void GlobalRunner::troff ()
+{
+ fTron= false;
+ fTronLine= false;
+ BlChar oldflags= sysvar::get (sysvar::TronFlags);
+ sysvar::set (sysvar::TronFlags, oldflags & static_cast <BlChar> (~3) );
+ sysvar::set16 (sysvar::TronChannel, 0);
+}
+
+void GlobalRunner::do_tronline (const CodeLine & codeline)
+{
+ if (codeline.number () == LineDirectCommand)
+ return;
+
+ BlFile & file= getfile (blcTron);
+ if (fTronLine)
+ program.listline (codeline, file);
+ else
+ {
+ //file << '[' << BlNumber (codeline.number () ) << ']';
+ file << '[' <<
+ static_cast <BlInteger> (codeline.number () ) <<
+ ']';
+ file.flush ();
+ }
+}
+
+void GlobalRunner::clearerrorgoto ()
+{
+ blnErrorGoto= LineEndProgram;
+ blnErrorGotoSource= LineEndProgram;
+}
+
+void GlobalRunner::seterrorgoto (BlLineNumber line, BlLineNumber source)
+{
+ // Line must be a valid program line except 0, because 0 mean
+ // deactivate, source can be a valid program line or a direct
+ // command.
+ if (line > BlMaxLineNumber ||
+ (source > BlMaxLineNumber && source != LineDirectCommand ) )
+ {
+ ASSERT (false);
+ throw ErrBlassicInternal;
+ }
+ blnErrorGoto= line;
+ blnErrorGotoSource= source;
+}
+
+bool GlobalRunner::assign_channel_var
+ (const std::string & var, const Dimension & dim,
+ const std::string & value, BlFile::Align align)
+{
+ bool r= false;
+ for (ChanFile::iterator it= chanfile.begin ();
+ it != chanfile.end ();
+ ++it)
+ // Changed behaviour: instead to assign to all possible
+ // fields with the same name in all files, assign only
+ // to the first.
+ // Retesting the initial behaviour.
+ #if 1
+ {
+ if (it->second->assign (var, dim, value, align) )
+ r= true;
+ }
+ return r;
+ #else
+ {
+ if (it->second->assign (var, dim, value, align) )
+ return true;
+ }
+ return false;
+ #endif
+}
+
+bool GlobalRunner::assign_mid_channel_var
+ (const std::string & var, const Dimension & dim,
+ const std::string & value,
+ size_t inipos, std::string::size_type len)
+{
+ bool r= false;
+ for (ChanFile::iterator it= chanfile.begin ();
+ it != chanfile.end ();
+ ++it)
+ {
+ if (it->second->assign_mid (var, dim, value, inipos, len) )
+ r= true;
+ }
+ return r;
+}
+
+BlChannel GlobalRunner::freefile () const
+{
+ for (BlChannel channel= 1; channel < PrinterChannel; ++channel)
+ if (chanfile.find (channel) == chanfile.end () )
+ return channel;
+ return 0;
+}
+
+BlFile & GlobalRunner::getfile (BlChannel channel) const
+{
+ ChanFile::const_iterator it= chanfile.find (channel);
+ if (it == chanfile.end () )
+ {
+ if (showdebuginfo () )
+ cerr << "Channel " << channel <<
+ " is not opened" << endl;
+ throw ErrFileNumber;
+ }
+ return * it->second;
+}
+
+void GlobalRunner::setfile (BlChannel channel, BlFile * npfile)
+{
+ TRACEFUNC (tr, "GlobalRunner::setfile");
+
+ std::pair <ChanFile::iterator, bool> r
+ (chanfile.insert (ChanFile::value_type (channel, npfile) ) );
+ if (! r.second)
+ {
+ TRMESSAGE (tr, "Exist, delete and substitute");
+ delete r.first->second;
+ r.first->second= npfile;
+ }
+ else
+ {
+ TRMESSAGE (tr, "Inserted new");
+ }
+}
+
+void GlobalRunner::resetfile0 ()
+{
+ TRACEFUNC (tr, "GlobalRunner::resetfile0");
+
+ auto_ptr <BlFile> pf (graphics::ingraphicsmode () ?
+ newBlFileWindow (DefaultChannel) :
+ newBlFileConsole () );
+ setfile (DefaultChannel, pf.get () );
+ pf.release ();
+}
+
+void GlobalRunner::resetfileprinter ()
+{
+ auto_ptr <BlFile> pf (newBlFilePrinter () );
+ setfile (PrinterChannel, pf.get () );
+ pf.release ();
+}
+
+void GlobalRunner::close_all ()
+{
+ std::vector <BlChannel> w;
+ for (ChanFile::iterator it= chanfile.begin ();
+ it != chanfile.end (); ++it)
+ {
+ BlFile * f= it->second;
+ if (f->isfile () )
+ {
+ delete f;
+ w.push_back (it->first);
+ }
+ }
+ for (size_t i= 0, l= w.size (); i < l; ++i)
+ {
+ size_t d= chanfile.erase (w [i] );
+ ASSERT (d == 1);
+ (void) d; // Avoid warning about unused.
+ }
+}
+
+void GlobalRunner::destroy_windows ()
+{
+ TRACEFUNC (tr, "GlobalRunner::destroy_windows");
+
+ std::vector <BlChannel> w;
+ for (ChanFile::iterator it= chanfile.begin ();
+ it != chanfile.end (); ++it)
+ {
+ BlFile * f= it->second;
+ //if (typeid (* f) == typeid (BlFileWindow) )
+ if (f->istextwindow () )
+ {
+ delete f;
+ w.push_back (it->first);
+ }
+ }
+ for (size_t i= 0, l= w.size (); i < l; ++i)
+ {
+ TRMESSAGE (tr, "Destroying window " + to_string (w [i] ) );
+ size_t d= chanfile.erase (w [i] );
+ ASSERT (d == 1);
+ touch (d);
+ }
+}
+
+void GlobalRunner::closechannel (BlChannel channel)
+{
+ if (channel == PrinterChannel)
+ resetfileprinter ();
+ else
+ {
+ ChanFile::iterator it= chanfile.find (channel);
+ if (it != chanfile.end () )
+ {
+ delete it->second;
+ chanfile.erase (it);
+ }
+ }
+}
+
+void GlobalRunner::windowswap (BlChannel ch1, BlChannel ch2)
+{
+ bool showdebug= showdebuginfo ();
+ ChanFile::iterator it1= chanfile.find (ch1);
+ ChanFile::iterator it2= chanfile.find (ch2);
+ if (it1 == chanfile.end () || it2 == chanfile.end () )
+ {
+ if (showdebug)
+ {
+ if (it1 == chanfile.end () )
+ cerr << "Channel " << ch1 <<
+ " is not opened" << endl;
+ if (it2 == chanfile.end () )
+ cerr << "Channel " << ch2 <<
+ " is not opened" << endl;
+ }
+ throw ErrFileNumber;
+ }
+
+ //bool fail1= typeid (* it1->second) != typeid (BlFileWindow);
+ //bool fail2= typeid (* it2->second) != typeid (BlFileWindow);
+ bool fail1= ! it1->second->istextwindow ();
+ bool fail2= ! it2->second->istextwindow ();
+ if (fail1 || fail2)
+ {
+ if (showdebug)
+ {
+ if (fail1)
+ cerr << "Channel " << ch1 <<
+ " is not a window" << endl;
+ if (fail2)
+ cerr << "Channel " << ch2 <<
+ " is not a window" << endl;
+ }
+ throw ErrFileMode;
+ }
+
+ std::swap (it1->second, it2->second);
+}
+
+void GlobalRunner::pollchannel (BlChannel ch, BlLineNumber line)
+{
+ TRACEFUNC (tr, "GlobalRunner::pollchannel");
+
+ if (! isfileopen (ch) )
+ throw ErrFileNumber;
+ if (line == 0)
+ chanpolled.erase (ch);
+ else
+ chanpolled [ch]= line;
+}
+
+bool GlobalRunner::channelspolled ()
+{
+ // This is to let the program execute one instruction
+ // before doing other poll check.
+
+ if (chanpolled.empty () )
+ return false;
+ else
+ {
+ if (alreadypolled)
+ {
+ if (clearingpolled)
+ alreadypolled= false;
+ return false;
+ }
+ else
+ return true;
+ }
+}
+
+void GlobalRunner::setpolled ()
+{
+ alreadypolled= true;
+ clearingpolled= false;
+}
+
+void GlobalRunner::clearpolled ()
+{
+ clearingpolled= true;
+}
+
+namespace {
+
+class Polled {
+ GlobalRunner & gr;
+public:
+ Polled (GlobalRunner & gr) :
+ gr (gr)
+ { }
+ bool operator () (const GlobalRunner::ChanPolled::value_type & cp)
+ {
+ BlFile & f= gr.getfile (cp.first);
+ return f.poll ();
+ }
+};
+
+} // namespace
+
+BlLineNumber GlobalRunner::getpollnumber ()
+{
+ TRACEFUNC (tr, "GlobalRunner::getpollnumber");
+
+ ChanPolled::iterator it=
+ std::find_if (chanpolled.begin (), chanpolled.end (),
+ Polled (* this) );
+ if (it != chanpolled.end () )
+ return it->second;
+ else
+ return LineEndProgram;
+}
+
+void GlobalRunner::inc_fn_level ()
+{
+ const unsigned long maxlevel= sysvar::get32 (sysvar::MaxFnLevel);
+ if (fn_current_level >= maxlevel)
+ {
+ if (showdebuginfo () )
+ cerr << "Maximum level of FN recursion of " <<
+ maxlevel << " has been reached" << endl;
+ throw ErrFnRecursion;
+ }
+
+ ++fn_current_level;
+}
+
+void GlobalRunner::dec_fn_level ()
+{
+ if (fn_current_level == 0)
+ {
+ if (showdebuginfo () )
+ cerr << "Internal problem handling FN exit" <<
+ endl;
+ throw ErrBlassicInternal;
+ }
+ --fn_current_level;
+}
+
+//************************************************
+// LocalLevel
+//************************************************
+
+class LocalLevel::Internal {
+ typedef blassic::result::BlResult BlResult;
+ friend class LocalLevel; // Only to avoid a warning in gcc.
+public:
+ Internal () : nref (1) { }
+ void addref () { ++nref; }
+ void delref ()
+ {
+ if (--nref == 0)
+ delete this;
+ }
+ void addlocalvar (const std::string & name);
+ void freelocalvars ();
+private:
+ ~Internal () { }
+ size_t nref;
+ typedef std::map <std::string, BlResult> maploc_t;
+ maploc_t maploc;
+};
+
+void LocalLevel::Internal::addlocalvar (const std::string & name)
+{
+ TRACEFUNC (tr, "LocalLevel::Internal::addlocalvar");
+
+ // Changing this to make it exception safe.
+ #if 0
+ if (maploc.find (name) != maploc.end () )
+ return;
+ BlResult result;
+
+ switch (typeofvar (name) )
+ {
+ case VarNumber:
+ {
+ BlNumber n= 0;
+ std::swap (n, * addrvarnumber (name) );
+ result= n;
+ TRMESSAGE (tr, std::string ("Saving ") + name +
+ " " + to_string (n) );
+ }
+ break;
+ case VarInteger:
+ {
+ BlInteger n= 0;
+ std::swap (n, * addrvarinteger (name) );
+ result= n;
+ TRMESSAGE (tr, std::string ("Saving ") + name +
+ " " + to_string (n) );
+ }
+ break;
+ case VarString:
+ {
+ std::string str;
+ swap (str, * addrvarstring (name) );
+ result= str;
+ TRMESSAGE (tr, std::string ("Saving ") + name +
+ " " + str);
+ }
+ break;
+ default:
+ if (showdebuginfo () )
+ cerr << "Type of local variable '" <<
+ name << "'unknown" << endl;
+ throw ErrBlassicInternal;
+ }
+ maploc [name]= result;
+ #else
+
+ BlResult result;
+ VarType vtype= typeofvar (name);
+ VarPointer vp;
+ switch (vtype)
+ {
+ case VarInteger:
+ vp.pinteger= addrvarinteger (name);
+ result= * vp.pinteger;
+ TRMESSAGE (tr, std::string ("Saving ") + name +
+ " " + to_string (result.integer () ) );
+ break;
+ case VarNumber:
+ vp.pnumber= addrvarnumber (name);
+ result= * vp.pnumber;
+ TRMESSAGE (tr, std::string ("Saving ") + name +
+ " " + to_string (result.number () ) );
+ break;
+ case VarString:
+ vp.pstring= addrvarstring (name);
+ result= * vp.pstring;
+ TRMESSAGE (tr, std::string ("Saving ") + name +
+ " " + result.str () );
+ break;
+ default:
+ if (showdebuginfo () )
+ cerr << "Type of local variable '" <<
+ name << "'unknown" << endl;
+ throw ErrBlassicInternal;
+ }
+ std::pair <maploc_t::iterator, bool> r= maploc.insert
+ (maploc_t::value_type (name, result) );
+
+ // If already declared as local, does nothing.
+ if (! r.second)
+ {
+ TRMESSAGE (tr, name + " was already saved");
+ return;
+ }
+
+ switch (vtype)
+ {
+ case VarInteger:
+ * vp.pinteger= BlInteger ();
+ break;
+ case VarNumber:
+ * vp.pnumber= BlNumber ();
+ break;
+ case VarString:
+ vp.pstring->erase ();
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+
+ #endif
+}
+
+namespace {
+
+using blassic::result::BlResult;
+
+void freelocalvar (const std::pair <std::string, BlResult> & p)
+{
+ TRACEFUNC (tr, "freelocalvar");
+
+ switch (p.second.type () )
+ {
+ case VarNumber:
+ assignvarnumber (p.first, p.second.number () );
+ TRMESSAGE (tr, std::string ("Restoring ") + p.first +
+ " to " + to_string (p.second.number () ) );
+ break;
+ case VarInteger:
+ assignvarinteger (p.first, p.second.integer () );
+ TRMESSAGE (tr, std::string ("Restoring ") + p.first +
+ " to " + to_string (p.second.integer () ) );
+ break;
+ case VarString:
+ assignvarstring (p.first, p.second.str () );
+ TRMESSAGE (tr, std::string ("Restoring ") + p.first +
+ " to " + p.second.str () );
+ break;
+ default:
+ if (showdebuginfo () )
+ cerr << "Freeing local variable of unknown type" <<
+ endl;
+ throw ErrBlassicInternal;
+ }
+}
+
+} // namespace
+
+void LocalLevel::Internal::freelocalvars ()
+{
+ for_each (maploc.begin (), maploc.end (), freelocalvar);
+}
+
+LocalLevel::LocalLevel () :
+ pi (new Internal)
+{
+}
+
+LocalLevel::LocalLevel (const LocalLevel & ll) :
+ //Element (ge),
+ pi (ll.pi)
+{
+ pi->addref ();
+}
+
+LocalLevel::~LocalLevel ()
+{
+ pi->delref ();
+}
+
+LocalLevel & LocalLevel::operator = (const LocalLevel & ll)
+{
+ ll.pi->addref ();
+ pi->delref ();
+ pi= ll.pi;
+ return * this;
+}
+
+void LocalLevel::freelocalvars ()
+{
+ pi->freelocalvars ();
+}
+
+void LocalLevel::addlocalvar (const std::string & name)
+{
+ pi->addlocalvar (name);
+}
+
+//************************************************
+// class GosubStack
+//************************************************
+
+GosubStack::GosubStack (GlobalRunner & globalrunner) :
+ globalrunner (globalrunner)
+{
+}
+
+GosubStack::~GosubStack ()
+{
+ // This is to ensure that on exiting from a multiline
+ // DEF FN the local variables are correctly restored,
+ // even on exceptions.
+
+ TRACEFUNC (tr, "GosubStack::~GosubStack");
+
+ const bool inexcept= std::uncaught_exception ();
+
+ try
+ {
+ while (! st.empty () )
+ {
+ GosubElement & ge= st.top ();
+ ge.freelocalvars ();
+ if (ge.ispolled () )
+ globalrunner.clearpolled ();
+ st.pop ();
+ }
+ }
+ catch (...)
+ {
+ // Bad thing. Perhaps restoring a local variable
+ // has run out of memory?
+ // Try to inform the user without aborting.
+ if (! inexcept)
+ throw;
+ else
+ {
+ cerr << "**ERROR** "
+ "Failed to restore local variables" <<
+ endl;
+ }
+ }
+}
+
+void GosubStack::erase ()
+{
+ // Unnecessary restore local vars here, when is called
+ // vars will be cleared after.
+ while (! st.empty () )
+ st.pop ();
+}
+
+//************************************************
+// Auxiliar functions of Runner
+//************************************************
+
+namespace {
+
+const char * statusname (Runner::RunnerStatus status)
+{
+ const char * str= "unknown";
+ switch (status)
+ {
+ case Runner::Ended:
+ str= "Ended"; break;
+ case Runner::FnEnded:
+ str= "FnEnded"; break;
+ case Runner::ReadyToRun:
+ str= "ReadyToRun"; break;
+ case Runner::Running:
+ str= "Runnig"; break;
+ case Runner::Stopped:
+ str= "Stopped"; break;
+ case Runner::Jump:
+ str= "Jump"; break;
+ case Runner::Goto:
+ str= "Goto"; break;
+ //case Runner::InitingCommand:
+ // str= "InitingCommand"; break;
+ //case Runner::Command:
+ // str= "Command"; break;
+ case Runner::JumpResumeNext:
+ str= "JumpResumeNext"; break;
+ }
+ return str;
+}
+
+} // namespace
+
+std::ostream & operator << (std::ostream & os, Runner::RunnerStatus status)
+{
+ os << "RunnerStatus is: " << statusname (status) << std::endl;
+ return os;
+}
+
+//************************************************
+// class Runner
+//************************************************
+
+Runner::Runner (GlobalRunner & gr) :
+ globalrunner (gr),
+ program (gr.getprogram () ),
+ status (Ended),
+ fInElse (false),
+ fInWend (false),
+ gosubstack (globalrunner),
+ posbreak (LineEndProgram),
+ blnAuto (LineEndProgram)
+{
+ TRACEFUNC (tr, "Runner::Runner");
+
+ clearerror ();
+}
+
+Runner::Runner (const Runner & runner) :
+ globalrunner (runner.globalrunner),
+ program (runner.program),
+ status (Ended),
+ fInElse (false),
+ fInWend (false),
+ gosubstack (globalrunner),
+ posbreak (LineEndProgram),
+ blnAuto (LineEndProgram)
+{
+ TRACEFUNC (tr, "Runner::Runner (copy)");
+}
+
+Runner::~Runner ()
+{
+}
+
+void Runner::clear ()
+{
+ close_all ();
+
+ // Clear loops stacks.
+ while (! forstack.empty () )
+ for_pop ();
+ gosubstack.erase ();
+ while (! repeatstack.empty () )
+ repeatstack.pop ();
+ while (! whilestack.empty () )
+ whilestack.pop ();
+
+ // Do RESTORE
+ clearreadline ();
+
+ // Errors
+ clearerror ();
+ globalrunner.clearerrorgoto ();
+}
+
+// Runner ************ errors ***************
+
+BlErrNo Runner::geterr () const
+{
+ return berrLast.geterr ();
+}
+
+ProgramPos Runner::geterrpos () const
+{
+ return berrLast.getpos ();
+}
+
+BlLineNumber Runner::geterrline () const
+{
+ return berrLast.getpos ().getnum ();
+}
+
+void Runner::clearerror ()
+{
+ //berrLast= BlError (0, LineEndProgram);
+ berrLast.clear ();
+}
+
+BlError Runner::geterror () const
+{
+ return berrLast;
+}
+
+void Runner::seterror (const BlError & er)
+{
+ berrLast= er;
+}
+
+void Runner::spectrumwindows ()
+{
+ // Only can be called in graphics mode, default channel must
+ // be a window.
+ ASSERT (graphics::ingraphicsmode () );
+ ASSERT (getfile0 ().istextwindow () );
+
+ // Adjust main window to the normal print area.
+ getfile0 ().reset (1, 32, 1, 22);
+
+ // Set channel 1, if free or already a window, to the window
+ // of the INPUT area. Leave untouched if is not a window.
+ if (! isfileopen (1) )
+ {
+ auto_ptr <BlFile> pf (newBlFileWindow (1, 1, 32, 23, 24) );
+ setfile (1, pf.get () );
+ pf.release ();
+ }
+ else
+ {
+ BlFile & f1= getfile (1);
+ if (f1.istextwindow () )
+ f1.reset (1, 32, 23, 24);
+ }
+}
+
+void Runner::getline (std::string & line)
+{
+ clean_input ();
+ BlFile & file= getfile0 ();
+ file.getline (line);
+}
+
+void Runner::run ()
+{
+ // Una chapuza por ahora.
+ std::string str ("RUN");
+ CodeLine code;
+ code.scan (str);
+ runline (code);
+}
+
+bool Runner::next ()
+{
+ //TRACEFUNC (tr, "Runner::next ()");
+
+ if (forstack.empty () )
+ throw ErrNextWithoutFor;
+ ForElement * pfe= forstack.top ();
+ if (pfe->next () )
+ {
+ //TRMESSAGE (tr, "NEXT -> " +
+ // to_string (pfe->getpos ().getnum () ) + ":" +
+ // to_string (pfe->getpos ().getchunk () ) );
+ jump_to (pfe->getpos () );
+ return true;
+ }
+ else
+ {
+ //TRMESSAGE (tr, "End FOR");
+ forstack.pop ();
+ return false;
+ }
+}
+
+bool Runner::next (const std::string & varname)
+{
+ if (forstack.empty () )
+ throw ErrNextWithoutFor;
+ ForElement * pfe= forstack.top ();
+ if (! pfe->isvar (varname) )
+ {
+ if (sysvar::get (sysvar::TypeOfNextCheck) == 0)
+ {
+ if (showdebuginfo () )
+ cerr << "Processing NEXT " <<
+ varname <<
+ " but current FOR is " <<
+ pfe->var () <<
+ " and mode is strict" <<
+ endl;
+ throw ErrNextWithoutFor;
+ }
+ else
+ {
+ // In ZX style NEXT can be omitted.
+ do
+ {
+ forstack.pop ();
+ if (forstack.empty () )
+ throw ErrNextWithoutFor;
+ pfe= forstack.top ();
+ } while (! pfe->isvar (varname) );
+ }
+ }
+ if (pfe->next () )
+ {
+ jump_to (pfe->getpos () );
+ return true;
+ }
+ else
+ {
+ forstack.pop ();
+ return false;
+ }
+}
+
+void Runner::tron (bool fLine, BlChannel blc)
+{
+ globalrunner.tron (fLine, blc);
+}
+
+void Runner::troff ()
+{
+ globalrunner.troff ();
+}
+
+namespace {
+
+inline bool goto_relaxed ()
+{
+ return sysvar::hasFlags1 (sysvar::RelaxedGoto);
+}
+
+} // namespace
+
+inline Runner::StatusRun Runner::checkstatusEnded
+ (CodeLine &, const CodeLine &)
+{
+ return StopNow;
+}
+
+inline Runner::StatusRun Runner::checkstatusFnEnded
+ (CodeLine &, const CodeLine &)
+{
+ TRACEFUNC (tr, "Runner::checkstatusFnEnded");
+
+ if (fn_level () == 0)
+ throw ErrUnexpectedFnEnd;
+ gosub_check_fn ();
+
+ return StopNow;
+}
+
+inline Runner::StatusRun Runner::checkstatusReadyToRun
+ (CodeLine & codeline, const CodeLine &)
+{
+ BlLineNumber gline= posgoto.getnum ();
+ if (gline == LineBeginProgram)
+ codeline= program.getfirstline ();
+
+ else
+ {
+ CodeLine aux;
+ program.getline (gline, aux);
+ if (aux.number () != gline)
+ {
+ if (showdebuginfo () )
+ cerr << "Line " << gline <<
+ " not exist" << endl;
+ throw ErrLineNotExist;
+ }
+ codeline= aux;
+ }
+ //if (codeline.number () == 0)
+ if (codeline.number () == LineEndProgram)
+ {
+ //setstatus (Ended);
+ //throw blassic::ProgramPassedLastLine ();
+
+ setstatus (Ended);
+ return StopNow;
+ }
+ else
+ {
+ setstatus (Running);
+ return KeepRunning;
+ }
+}
+
+inline Runner::StatusRun Runner::checkstatusRunning
+ (CodeLine & codeline, const CodeLine &)
+{
+ if (codeline.number () == LineDirectCommand)
+ {
+ setstatus (Ended);
+ return StopNow;
+ }
+ else
+ {
+ program.getnextline (codeline);
+ if (codeline.number () == LineEndProgram)
+ {
+ #if 1
+
+ if (fn_level () > 0)
+ {
+ //throw blassic::ProgramPassedLastLine ();
+ throw ErrNoFnEnd;
+ }
+ setstatus (Ended);
+ return StopNow;
+
+ #else
+ throw blassic::ProgramPassedLastLine ();
+ #endif
+ }
+ else
+ return KeepRunning;
+ }
+}
+
+inline Runner::StatusRun Runner::checkstatusStopped
+ (CodeLine &, const CodeLine &)
+{
+ return StopNow;
+}
+
+inline Runner::StatusRun Runner::checkstatusJump
+ (CodeLine & codeline, const CodeLine & codeline0)
+{
+ TRACEFUNC (tr, "Runner::checkstatusJump");
+
+ const BlLineNumber gotoline= posgoto.getnum ();
+ if (gotoline != LineDirectCommand)
+ {
+ if (codeline.number () != gotoline)
+ {
+ program.getline (posgoto, codeline);
+ if (codeline.number () == LineEndProgram)
+ {
+ //throw blassic::ProgramPassedLastLine ();
+ if (fn_level () > 0)
+ throw ErrNoFnEnd;
+ setstatus (Ended);
+ return StopNow;
+ }
+ }
+ else
+ {
+ TRMESSAGE (tr, "Same line");
+ codeline.gotochunk (posgoto.getchunk () );
+ }
+ }
+ else
+ {
+ if (codeline.number () != LineDirectCommand)
+ codeline= codeline0;
+ codeline.gotochunk (posgoto.getchunk () );
+ }
+ setstatus (Running);
+ return KeepRunning;
+}
+
+inline Runner::StatusRun Runner::checkstatusGoto
+ (CodeLine & codeline, const CodeLine &)
+{
+ const BlLineNumber gotoline= posgoto.getnum ();
+ if (codeline.number () != gotoline)
+ {
+ CodeLine aux;
+ program.getline (gotoline, aux);
+ BlLineNumber l= aux.number ();
+ //if (l == 0 ||
+ // (l != gotoline && ! goto_relaxed () ) )
+ if (l != gotoline && ! goto_relaxed () )
+ {
+ if (showdebuginfo () )
+ cerr << "Line " << gotoline <<
+ " not exist" << endl;
+ throw ErrLineNotExist;
+ }
+ codeline= aux;
+ }
+ else
+ codeline.gotochunk (posgoto.getchunk () );
+ setstatus (Running);
+ return KeepRunning;
+}
+
+#if 0
+inline Runner::StatusRun Runner::checkstatusInitingCommand
+ (CodeLine &, const CodeLine &)
+{
+ setstatus (Command);
+ return KeepRunning;
+}
+
+inline Runner::StatusRun Runner::checkstatusCommand
+ (CodeLine &, const CodeLine &)
+{
+ return StopNow;
+ //return KeepRunning;
+}
+#endif
+
+inline Runner::StatusRun Runner::checkstatusJumpResumeNext
+ (CodeLine & codeline, const CodeLine & codeline0)
+{
+ const BlLineNumber gotoline= posgoto.getnum ();
+ if (gotoline != LineDirectCommand)
+ {
+ if (codeline.number () != gotoline)
+ {
+ program.getline (posgoto, codeline);
+ if (codeline.number () == LineEndProgram)
+ {
+ //throw blassic::ProgramPassedLastLine ();
+ if (fn_level () > 0)
+ throw ErrNoFnEnd;
+ setstatus (Ended);
+ return StopNow;
+ }
+ }
+ else
+ codeline.gotochunk
+ (posgoto.getchunk () );
+ }
+ else
+ {
+ if (codeline.number () != LineDirectCommand)
+ codeline= codeline0;
+ codeline.gotochunk (posgoto.getchunk () );
+ }
+
+ BlLineNumber n= codeline.number ();
+ if (n == gotoline)
+ {
+ CodeLine::Token tok;
+ codeline.gettoken (tok);
+ if (tok.code == keyIF)
+ {
+ if (n == LineDirectCommand)
+ {
+ setstatus (Ended);
+ return StopNow;
+ }
+ program.getnextline (codeline);
+ if (codeline.number () == LineEndProgram)
+ {
+ //throw blassic::ProgramPassedLastLine ();
+ if (fn_level () > 0)
+ throw ErrNoFnEnd;
+ setstatus (Ended);
+ return StopNow;
+ }
+ }
+ else
+ {
+ while (! tok.isendsentence () )
+ codeline.gettoken (tok);
+ }
+ }
+ setstatus (Running);
+ return KeepRunning;
+}
+
+Runner::checkstatusfunc Runner::checkstatus [Runner::LastStatus + 1]=
+{
+ &Runner::checkstatusEnded,
+ &Runner::checkstatusFnEnded,
+ &Runner::checkstatusReadyToRun,
+ &Runner::checkstatusRunning,
+ &Runner::checkstatusStopped,
+ &Runner::checkstatusJump,
+ &Runner::checkstatusGoto,
+ //&Runner::checkstatusInitingCommand,
+ //&Runner::checkstatusCommand,
+ &Runner::checkstatusJumpResumeNext,
+};
+
+#if 0
+inline bool Runner::checkstatus
+ (CodeLine & codeline, const CodeLine & codeline0)
+{
+ switch (status)
+ {
+ case ReadyToRun:
+ {
+ BlLineNumber gline= posgoto.getnum ();
+ if (gline == LineBeginProgram)
+ codeline= program.getfirstline ();
+
+ else
+ {
+ CodeLine aux;
+ program.getline (gline, aux);
+ if (aux.number () != gline)
+ {
+ if (showdebuginfo () )
+ cerr << "Line " << gline <<
+ " not exist" << endl;
+ throw ErrLineNotExist;
+ }
+ codeline= aux;
+ }
+ //if (codeline.number () == 0)
+ if (codeline.number () == LineEndProgram)
+ //setstatus (Ended);
+ throw blassic::ProgramPassedLastLine ();
+ else
+ {
+ setstatus (Running);
+ return true;
+ }
+ }
+ //break;
+ case Jump:
+ {
+ const BlLineNumber gotoline= posgoto.getnum ();
+ if (gotoline != LineDirectCommand)
+ {
+ if (codeline.number () != gotoline)
+ {
+ program.getline (posgoto, codeline);
+ if (codeline.number () == LineEndProgram)
+ throw blassic::ProgramPassedLastLine ();
+ }
+ else
+ codeline.gotochunk
+ (posgoto.getchunk () );
+ }
+ else
+ {
+ if (codeline.number () != LineDirectCommand)
+ codeline= codeline0;
+ codeline.gotochunk (posgoto.getchunk () );
+ }
+ }
+ setstatus (Running);
+ return true;
+ case Goto:
+ {
+ const BlLineNumber gotoline= posgoto.getnum ();
+ if (codeline.number () != gotoline)
+ {
+ CodeLine aux;
+ program.getline (gotoline, aux);
+ BlLineNumber l= aux.number ();
+ //if (l == 0 ||
+ // (l != gotoline && ! goto_relaxed () ) )
+ if (l != gotoline && ! goto_relaxed () )
+ {
+ if (showdebuginfo () )
+ cerr << "Line " << gotoline <<
+ " not exist" << endl;
+ throw ErrLineNotExist;
+ }
+ codeline= aux;
+ }
+ else
+ codeline.gotochunk (posgoto.getchunk () );
+ }
+ setstatus (Running);
+ return true;
+ case Running:
+ //if (codeline.number () != 0)
+ // program.getnextline (codeline);
+ //if (codeline.number () == 0)
+ //{
+ // status= Ended;
+ // if (fn_level () > 0)
+ // throw blassic::ProgramPassedLastLine ();
+ //}
+ //else
+ // return true;
+ if (codeline.number () == LineDirectCommand)
+ {
+ setstatus (Ended);
+ return false;
+ }
+ else
+ {
+ program.getnextline (codeline);
+ if (codeline.number () == LineEndProgram)
+ #if 0
+ {
+ setstatus (Ended);
+ if (fn_level () > 0)
+ throw blassic::ProgramPassedLastLine
+ ();
+ return false;
+ }
+ #else
+ throw blassic::ProgramPassedLastLine ();
+ #endif
+ else
+ return true;
+ }
+ case InitingCommand:
+ setstatus (Command);
+ return true;
+ default:
+ ;
+ }
+ return false;
+}
+
+#else
+
+inline bool Runner::is_run_status
+ (CodeLine & codeline, const CodeLine & codeline0)
+{
+ return (this->*(checkstatus [status]) ) (codeline, codeline0)
+ == KeepRunning;
+}
+
+#endif
+
+void Runner::showfailerrorgoto () const
+{
+ if (! showdebuginfo () )
+ return;
+ BlLineNumber source= geterrorgotosource ();
+
+ cerr << "Line " << geterrorgoto () <<
+ " specified in ON ERROR GOTO on ";
+ if (source == LineDirectCommand)
+ cerr << "a direct command";
+ else
+ cerr << "line " << source;
+ cerr << " does not exist" <<
+ endl;
+}
+
+namespace {
+
+bool handle_error (Runner & runner, BlError & berr)
+{
+ BlLineNumber errorgoto= runner.geterrorgoto ();
+ if (errorgoto == LineEndProgram)
+ {
+ if (runner.fn_level () > 0)
+ {
+ // The position of the error
+ // will be defined by the
+ // first fn caller.
+ if (showdebuginfo () )
+ cerr << "Error " << berr.geterr () <<
+ " inside DEF FN on line " <<
+ berr.getpos ().getnum () <<
+ endl;
+ }
+ return true;
+ }
+ else
+ {
+ CodeLine aux;
+ runner.getprogram ().getline (errorgoto, aux);
+ if (aux.number () != errorgoto)
+ {
+ runner.showfailerrorgoto ();
+ berr.seterr (ErrLineNotExist);
+ return true;
+ }
+ runner.seterror (berr);
+ // Clear berr, or it will be still active
+ // next time something is throwed.
+ berr.clear ();
+ runner.jump_to (errorgoto);
+ return false;
+ }
+}
+
+} // namespace
+
+#if 0
+void Runner::runline_catch (const CodeLine & codeline, ProgramPos pos,
+ BlError & berr, bool & endloop, bool & dobreak)
+{
+ TRACEFUNC (tr, "Runner::runline_catch");
+
+ //bool fnend= false;
+
+ try
+ {
+ throw; // Relaunch pending exception to catch it.
+ }
+ catch (std::bad_alloc &)
+ {
+ berr= BlError (ErrOutMemory,
+ //runnerline.getposactual () );
+ pos);
+ endloop= handle_error (* this, berr);
+ //if (endloop)
+ // break;
+ }
+ catch (SocketError & se)
+ {
+ if (showdebuginfo () )
+ cerr << se.what () << endl;
+ berr= BlError (ErrSocket,
+ //runnerline.getposactual () );
+ pos);
+ endloop= handle_error (* this, berr);
+ //if (endloop)
+ // break;
+ }
+ catch (BlErrNo e)
+ {
+ berr= BlError (e,
+ //runnerline.getposactual () );
+ pos);
+ endloop= handle_error (* this, berr);
+ //if (endloop)
+ // break;
+ }
+ catch (BlError & newberr)
+ {
+ berr= newberr;
+ endloop= handle_error (* this, berr);
+ //if (endloop)
+ // break;
+ }
+ catch (BlBreak &)
+ {
+ fInterrupted= false;
+ //ProgramPos actual= runnerline.getposactual ();
+ ProgramPos actual= pos;
+ switch (getbreakstate () )
+ {
+ case onbreak::BreakStop:
+ if (fn_level () > 0)
+ throw;
+ endloop= true;
+ dobreak= true;
+ break;
+ case onbreak::BreakCont:
+ throw BlError (ErrBlassicInternal, actual);
+ case onbreak::BreakGosub:
+ gosub_line (getbreakgosub (), actual);
+ break;
+ }
+ //if (endloop)
+ // break;
+ }
+ #if 0
+ catch (blassic::ProgramEnd &)
+ {
+ if (fn_level () > 0)
+ {
+ if (showdebuginfo () )
+ cerr << "END inside DEF FN in line " <<
+ codeline.number () <<
+ endl;
+ throw;
+ }
+ close_all ();
+ setstatus (Ended);
+ //break;
+ endloop= true; // New
+ }
+ catch (blassic::ProgramPassedLastLine &)
+ {
+ if (fn_level () > 0)
+ {
+ if (showdebuginfo () )
+ cerr << "End of program reached "
+ "inside DEF FN" <<
+ endl;
+ throw;
+ }
+ //break;
+ endloop= true; // New
+ }
+ catch (blassic::ProgramStop &)
+ {
+ if (fn_level () > 0)
+ {
+ if (showdebuginfo () )
+ cerr << "STOP inside DEF FN "
+ "in line "
+ <<
+ codeline.number () <<
+ endl;
+ throw;
+ }
+ BlFile & f= getfile0 ();
+ f << "**Stopped**";
+ if (codeline.number () != LineDirectCommand)
+ f << " in " << codeline.number ();
+ f.endline ();
+ //ProgramPos posbreak (runnerline.getposactual () );
+ ProgramPos posbreak (pos);
+ posbreak.nextchunk ();
+ set_break (posbreak);
+ setstatus (Stopped);
+ //break;
+ endloop= true; // New
+ }
+ catch (blassic::ProgramFnEnd &)
+ {
+ #if 0
+ TRMESSAGE (tr, "FnEnd");
+ if (fn_level () == 0)
+ {
+ berr= BlError (ErrUnexpectedFnEnd, pos);
+ endloop= handle_error (* this, berr);
+ }
+ try
+ {
+ gosub_check_fn ();
+ setstatus (Ended);
+ endloop= true;
+ }
+ catch (BlErrNo e)
+ {
+ berr.set (e, pos);
+ endloop= handle_error (* this, berr);
+ }
+ #else
+
+ fnend= true;
+
+ #endif
+ }
+ if (fnend)
+ {
+ TRMESSAGE (tr, "FnEnd");
+ if (fn_level () == 0)
+ {
+ berr.set (ErrUnexpectedFnEnd, pos);
+ endloop= handle_error (* this, berr);
+ }
+ try
+ {
+ gosub_check_fn ();
+ setstatus (Ended);
+ endloop= true;
+ }
+ catch (BlErrNo e)
+ {
+ berr.set (e, pos);
+ endloop= handle_error (* this, berr);
+ }
+ }
+ #endif
+}
+#endif
+
+#if 0
+
+void Runner::runline (const CodeLine & codeline0)
+{
+ TRACEFUNC (tr, "Runner::runline");
+
+ if (codeline0.number () != LineDirectCommand)
+ {
+ ASSERT (false);
+ throw ErrBlassicInternal;
+ }
+
+ auto_ptr <RunnerLine> prunnerline
+ (newRunnerLine (* this, codeline0) );
+ RunnerLine & runnerline= * prunnerline.get ();
+
+ CodeLine & codeline= runnerline.getcodeline ();
+ bool endloop= false;
+ bool dobreak= false;
+ BlError berr;
+
+ setstatus (InitingCommand);
+
+ // Test:
+ otra:
+
+ //for (;;)
+ //{
+ try
+ {
+ TRMESSAGE (tr, statusname (status) );
+ if (! is_run_status (codeline, codeline0) )
+ //if ( (this->*(checkstatus [status]) )
+ // (codeline, codeline0) == StopNow)
+ {
+ // Test:
+ //break;
+ goto atloopend;
+ }
+
+ //do {
+ //TRMESSAGE (tr, statusname (status) );
+
+ //runnerline.setline (codeline);
+
+ // Do tron if active.
+ tronline (codeline);
+
+ //runnerline.execute ();
+ prunnerline->execute ();
+ //} while (checkstatus (codeline, codeline0) );
+ }
+ catch (std::bad_alloc &)
+ {
+ berr.set (ErrOutMemory, runnerline.getposactual () );
+ endloop= handle_error (* this, berr);
+ //if (endloop)
+ // break;
+ }
+ catch (SocketError & se)
+ {
+ if (showdebuginfo () )
+ cerr << se.what () << endl;
+ berr.set (ErrSocket, runnerline.getposactual () );
+ endloop= handle_error (* this, berr);
+ //if (endloop)
+ // break;
+ }
+ catch (BlErrNo e)
+ {
+ berr.set (e, runnerline.getposactual () );
+ endloop= handle_error (* this, berr);
+ //if (endloop)
+ // break;
+ }
+ catch (BlError & newberr)
+ {
+ berr= newberr;
+ endloop= handle_error (* this, berr);
+ //if (endloop)
+ // break;
+ }
+ catch (BlBreak &)
+ {
+ fInterrupted= false;
+ ProgramPos actual= runnerline.getposactual ();
+ //ProgramPos actual= pos;
+ switch (getbreakstate () )
+ {
+ case onbreak::BreakStop:
+ if (fn_level () > 0)
+ throw;
+ endloop= true;
+ dobreak= true;
+ break;
+ case onbreak::BreakCont:
+ throw BlError (ErrBlassicInternal, actual);
+ case onbreak::BreakGosub:
+ gosub_line (getbreakgosub (), actual);
+ break;
+ }
+ //if (endloop)
+ // break;
+ }
+ #if 0
+ catch (blassic::ProgramEnd &)
+ {
+ if (fn_level () > 0)
+ {
+ if (showdebuginfo () )
+ cerr << "END inside DEF FN in line " <<
+ codeline.number () <<
+ endl;
+ throw;
+ }
+ close_all ();
+ setstatus (Ended);
+ //break;
+ endloop= true; // New
+ }
+ catch (blassic::ProgramPassedLastLine &)
+ {
+ if (fn_level () > 0)
+ {
+ if (showdebuginfo () )
+ cerr << "End of program reached "
+ "inside DEF FN" <<
+ endl;
+ throw;
+ }
+ setstatus (Ended);
+ //break;
+ endloop= true; // New
+ }
+ catch (blassic::ProgramStop &)
+ {
+ if (fn_level () > 0)
+ {
+ if (showdebuginfo () )
+ cerr << "STOP inside DEF FN "
+ "in line "
+ <<
+ codeline.number () <<
+ endl;
+ throw;
+ }
+ BlFile & f= getfile0 ();
+ std::ostringstream oss;
+ oss << "**Stopped**";
+ if (codeline.number () != LineDirectCommand)
+ oss << " in " << codeline.number ();
+ f << oss.str ();
+ f.endline ();
+ ProgramPos posbreak (runnerline.getposactual () );
+ //ProgramPos posbreak (pos);
+ posbreak.nextchunk ();
+ set_break (posbreak);
+ setstatus (Stopped);
+ //break;
+ endloop= true; // New
+ }
+ catch (blassic::ProgramFnEnd &)
+ {
+ #if 0
+ TRMESSAGE (tr, "FnEnd");
+ if (fn_level () == 0)
+ {
+ berr= BlError (ErrUnexpectedFnEnd, pos);
+ endloop= handle_error
+ (* this, berr);
+ }
+ try
+ {
+ gosub_check_fn ();
+ setstatus (Ended);
+ endloop= true;
+ }
+ catch (BlErrNo e)
+ {
+ berr= BlError (e, pos);
+ endloop= handle_error
+ (* this, berr);
+ }
+ #else
+
+ if (fn_level () == 0)
+ {
+ berr= BlError (ErrUnexpectedFnEnd,
+ //pos);
+ runnerline.getposactual () );
+ }
+ else
+ {
+ gosub_check_fn ();
+ setstatus (Ended);
+ }
+ endloop= true;
+
+ #endif
+ }
+ #endif
+ catch (...)
+ {
+ TRMESSAGE (tr, "catched ...");
+ throw;
+ }
+
+ #if 0
+ catch (...)
+ {
+ runline_catch (codeline, runnerline.getposactual (),
+ berr, endloop, dobreak);
+ }
+ #endif
+
+ // Test
+ #if 0
+
+ if (endloop)
+ break;
+ #else
+
+ if (! endloop)
+ goto otra;
+ #endif
+
+ #if 0
+ check_again:
+ try
+ {
+ if (! checkstatus (codeline, codeline0) )
+ //break;
+ endloop= true;
+ }
+ catch (...)
+ {
+ runline_catch (codeline, runnerline.getposactual (),
+ berr, endloop, dobreak);
+ if (endloop)
+ {
+ //break;
+ }
+ else
+ goto check_again;
+ }
+ if (endloop)
+ break;
+ #endif
+
+ // Test:
+ //} // for (;;)
+ atloopend:
+
+ if (endloop)
+ {
+ if (dobreak)
+ throw BlBreakInPos (runnerline.getposactual () );
+ else if (berr.geterr () != 0)
+ {
+ seterror (berr);
+ throw berr;
+ }
+ }
+}
+
+#else
+
+void Runner::runline (const CodeLine & codeline0)
+{
+ TRACEFUNC (tr, "Runner::runline");
+
+ if (codeline0.number () != LineDirectCommand)
+ {
+ ASSERT (false);
+ throw ErrBlassicInternal;
+ }
+
+ #if 1
+
+ auto_ptr <RunnerLine> prunnerline
+ (newRunnerLine (* this, codeline0) );
+ RunnerLine & runnerline= * prunnerline.get ();
+
+ #else
+
+ RunnerLineImpl runnerline (* this, codeline0);
+
+ #endif
+
+ CodeLine & codeline= runnerline.getcodeline ();
+ bool endloop= false;
+ bool dobreak= false;
+ BlError berr;
+
+ //setstatus (InitingCommand);
+ setstatus (Running);
+
+ // {
+ // TRACEFUNC (traux, "runline auxiliar block");
+
+ while (! endloop)
+ {
+ try
+ {
+ do {
+ //TRMESSAGE (tr, statusname (status) );
+
+ // Do tron if active.
+ tronline (codeline);
+
+ //prunnerline->execute ();
+ runnerline.execute ();
+
+ TRMESSAGE (tr, "Line finished");
+ } while (is_run_status (codeline, codeline0) );
+ endloop= true;
+ }
+ catch (std::bad_alloc &)
+ {
+ berr.set (ErrOutMemory, runnerline.getposactual () );
+ endloop= handle_error (* this, berr);
+ }
+ catch (SocketError & se)
+ {
+ if (showdebuginfo () )
+ cerr << se.what () << endl;
+ berr.set (ErrSocket, runnerline.getposactual () );
+ endloop= handle_error (* this, berr);
+ }
+ catch (BlErrNo e)
+ {
+ berr.set (e, runnerline.getposactual () );
+ endloop= handle_error (* this, berr);
+ }
+ catch (BlError & newberr)
+ {
+ berr= newberr;
+ endloop= handle_error (* this, berr);
+ }
+ catch (BlBreak &)
+ {
+ fInterrupted= false;
+ ProgramPos actual= runnerline.getposactual ();
+ switch (getbreakstate () )
+ {
+ case onbreak::BreakStop:
+ if (fn_level () > 0)
+ throw;
+ endloop= true;
+ dobreak= true;
+ break;
+ case onbreak::BreakCont:
+ throw BlError (ErrBlassicInternal, actual);
+ case onbreak::BreakGosub:
+ gosub_line (getbreakgosub (), actual);
+ break;
+ }
+ }
+ //catch (Exit & e)
+ //{
+ // //TRMESSAGE (traux, "Exitting");
+ // throw (Exit (e.code () ) );
+ //}
+
+ } // while
+
+ // } // Auxiliar block
+
+ //if (endloop)
+ //{
+ if (dobreak)
+ throw BlBreakInPos (runnerline.getposactual () );
+ else if (berr.geterr () != 0)
+ {
+ seterror (berr);
+ throw berr;
+ }
+ //}
+}
+
+#endif
+
+bool Runner::processline (const std::string & line)
+{
+ TRACEFUNC (tr, "Runner::processline");
+
+ CodeLine codeline;
+ codeline.scan (line);
+ BlLineNumber nline= codeline.number ();
+ //if (nline == 0)
+ if (nline == LineDirectCommand)
+ {
+ if (blnAuto != LineEndProgram)
+ {
+ // This probably must be changed.
+ if (codeline.empty () )
+ program.deletelines (blnAuto, blnAuto);
+ else
+ {
+ codeline.setnumber (blnAuto);
+ program.insert (codeline);
+ }
+ if (blnAuto > BlMaxLineNumber - blnAutoInc)
+ {
+ blnAuto= LineEndProgram;
+ throw BlError (ErrLineExhausted,
+ LineDirectCommand);
+ }
+ else
+ blnAuto+= blnAutoInc;
+ }
+ else
+ {
+ if (codeline.empty () )
+ return false;
+ runline (codeline);
+ return true;
+ }
+ }
+ else
+ {
+ if (nline > BlMaxLineNumber)
+ throw BlError (ErrLineExhausted);
+ if (codeline.empty () )
+ program.deletelines (nline, nline);
+ else
+ program.insert (codeline);
+ if (blnAuto != LineEndProgram)
+ {
+ blnAuto= codeline.number ();
+ if (blnAuto > BlMaxLineNumber - blnAutoInc)
+ {
+ blnAuto= LineEndProgram;
+ throw BlError (ErrLineExhausted,
+ LineDirectCommand);
+ }
+ else
+ blnAuto+= blnAutoInc;
+ }
+ }
+ return false;
+}
+
+namespace {
+
+void welcome (BlFile & f)
+{
+ f.endline ();
+ f << "Blassic " << version::Major << '.' <<
+ version::Minor << '.' <<
+ version::Release;
+ f.endline ();
+ f << "(C) 2001-2009 Julian Albo";
+ f.endline ();
+ f.endline ();
+}
+
+} // namespace
+
+bool Runner::editline (BlLineNumber bln, std::string & str)
+{
+ TRACEFUNC (tr, "editline - line number->string");
+
+ std::string buffer;
+ {
+ BlFileOutString bfos;
+ program.list (bln, bln, bfos);
+ buffer= bfos.str ();
+ if (buffer.empty () )
+ {
+ bfos << bln << ' ';
+ bfos.endline ();
+ buffer= bfos.str ();
+ }
+ }
+ buffer.erase (buffer.size () - 1);
+ TRMESSAGE (tr, std::string (1, '\'') + buffer + '\'');
+
+ static const std::string number ("01234567890");
+ size_t inipos= buffer.find_first_of (number);
+ ASSERT (inipos != std::string::npos);
+ inipos= buffer.find_first_not_of (number, inipos);
+ ASSERT (inipos != std::string::npos);
+ ++inipos;
+
+ BlFile & bf= getfile0 ();
+ bool r;
+ if ( (r= blassic::edit::editline (bf, buffer, inipos) ) == true)
+ str= buffer;
+ return r;
+}
+
+void Runner::interactive ()
+{
+ TRACEFUNC (tr, "Runner::interactive");
+
+ // Now the title is stablished in blassic.cpp
+ //set_title ("blassic");
+
+ welcome (getfile0 () );
+
+ bool showprompt= true;
+ for (;;)
+ {
+ std::string line;
+ if (blnAuto != LineEndProgram)
+ {
+ if (! editline (blnAuto, line) )
+ fInterrupted= true;
+ }
+ else
+ {
+ if (showprompt)
+ {
+ BlFile & f= getfile0 ();
+ f << strPrompt;
+ f.endline ();
+ }
+ //cout << "] " << flush;
+
+ getfile0 ().getline (line, true);
+ }
+
+ if (fInterrupted)
+ {
+ fInterrupted= false;
+ BlFile & bf= getfile0 ();
+ bf << strbreak;
+ bf.endline ();
+ std::cin.clear ();
+ blnAuto= LineEndProgram;
+ continue;
+ }
+ if (! std::cin)
+ break;
+
+ #ifndef _Windows
+
+ if (! line.empty () && line [line.size () - 1] == '\r')
+ line= line.substr (0, line.size () - 1);
+
+ #endif
+
+ try
+ {
+ showprompt= processline (line);
+ }
+ catch (BlErrNo ben)
+ {
+ BlFile & f= getfile0 ();
+ f << ErrStr (ben);
+ f.endline ();
+ setstatus (Stopped);
+ }
+ catch (BlError & be)
+ {
+ BlFile & f= getfile0 ();
+ f << to_string (be);
+ f.endline ();
+ setstatus (Stopped);
+ }
+ catch (BlBreakInPos & bbip)
+ {
+ BlFile & f= getfile0 ();
+ f << to_string (bbip);
+ f.endline ();
+ set_break (bbip.getpos () );
+ setstatus (Stopped);
+ }
+ } // for (;;)
+}
+
+void Runner::clean_input ()
+{
+ if (graphics::ingraphicsmode () )
+ graphics::clean_input ();
+ else
+ cursor::clean_input ();
+}
+
+void Runner::ring ()
+{
+ if (graphics::ingraphicsmode () )
+ graphics::ring ();
+ else
+ cursor::ring ();
+}
+
+void Runner::set_title (const std::string & str)
+{
+ if (graphics::ingraphicsmode () )
+ graphics::set_title (str);
+ else
+ cursor::set_title (str);
+}
+
+// End of runner.cpp
Un proyecto texto-plano.xyz