📄 runnerline.cpp
字号:
BlNumber n= expectnum ();
dims.add (size_t (n) );
#else
BlResult result;
expect (result);
dims.add (result.integer () );
#endif
if (token.code != ',')
break;
}
requiretoken (')');
gettoken ();
return dims;
}
void RunnerLine::errorifparam ()
{
gettoken ();
require_endsentence ();
}
void RunnerLine::gosub_line (BlLineNumber dest)
{
//ProgramPos posgosub= runner.getposactual ();
ProgramPos posgosub (getposactual () );
posgosub.nextchunk ();
#if 1
if (token.code == keyENDLINE && posgosub.getnum () != 0)
{
#if 1
posgosub.nextline ();
#else
BlLineNumber num= program.getnextnum (line);
if (num != 0)
posgosub= num;
#endif
}
#endif
runner.gosub_line (dest, posgosub);
}
void RunnerLine::getinkparams ()
{
if (endsentence () )
return;
requiretoken (',');
gettoken ();
if (token.code != ',')
{
BlInteger ink= evalinteger ();
graphics::setcolor (ink);
if (token.code != ',')
{
require_endsentence ();
return;
}
}
gettoken ();
BlInteger inkmode= evalinteger ();
require_endsentence ();
graphics::setdrawmode (inkmode);
}
void RunnerLine::getdrawargs (BlInteger & y)
{
requiretoken (',');
y= expectinteger ();
getinkparams ();
}
void RunnerLine::getdrawargs (BlInteger & x, BlInteger & y)
{
x= expectinteger ();
getdrawargs (y);
}
bool RunnerLine::do_empty_sentence ()
{
return false;
}
bool RunnerLine::do_endline ()
{
return true;
}
bool RunnerLine::do_number ()
{
// goto omitido
if (codprev != keyELSE && codprev != keyTHEN)
throw ErrSyntax;
BlLineNumber bln= evallinenumber ();
require_endsentence ();
runner.goto_line (bln);
return true;
}
bool RunnerLine::do_end ()
{
errorifparam ();
runner.setstatus (ProgramEnded);
return true;
}
bool RunnerLine::do_list ()
{
gettoken ();
BlChannel nfile= 0;
if (token.code == '#')
{
nfile= expectchannel ();
if (!endsentence () )
{
requiretoken (',');
gettoken ();
}
}
BlLineNumber iniline, endline;
evallinerange (iniline, endline);
require_endsentence ();
program.list (iniline, endline, getfile (nfile) );
return false;
}
bool RunnerLine::do_rem ()
{
return true;
}
bool RunnerLine::do_load ()
{
using std::ifstream;
using std::ios;
std::string progname= expectstring ();
if (endsentence () )
{
program.load (progname);
runner.setstatus (ProgramEnded);
return true;
}
requiretoken (',');
gettoken ();
if (token.code == keyIDENTIFIER &&
typeofvar (token.str) == VarString)
{
std::string varname= token.str;
gettoken ();
require_endsentence ();
ifstream is (progname.c_str (), ios::binary | ios::in);
// Without explicit in read doesn't work on hp-ux,
// I don't know why.
if (! is.is_open () )
throw ErrFileNotFound;
is.seekg (0, std::ios::end);
size_t size= is.tellg ();
is.seekg (0, std::ios::beg);
util::auto_buffer <char> aux (size);
is.read (aux, size);
std::string result (aux, size);
assignvarstring (varname, result);
}
else
{
char * init;
{
BlNumber bn= evalnum ();
init= reinterpret_cast <char *> (size_t (bn) );
}
size_t len= 0;
if (token.code == ',')
{
BlNumber bn= expectnum ();
len= size_t (bn);
}
require_endsentence ();
ifstream is (progname.c_str (), std::ios::binary);
if (! is.is_open () )
throw ErrFileNotFound;
if (len == 0)
{
is.seekg (0, std::ios::end);
len= is.tellg ();
is.seekg (0, std::ios::beg);
}
is.read (init, len);
}
return false;
}
bool RunnerLine::do_save ()
{
using std::ofstream;
std::string progname= expectstring ();
if (endsentence () )
program.save (progname);
else
{
requiretoken (',');
expecttoken (keyIDENTIFIER);
if (token.str.size () != 1)
throw ErrSyntax;
char c= char (toupper (token.str [0] ) );
switch (c)
{
case 'A':
gettoken ();
require_endsentence ();
{
BlFileRegular fout (progname, BlFile::Output);
program.list (0, BlMaxLineNumber, fout);
}
break;
case 'B':
gettoken ();
if (token.code != ',')
throw ErrSyntax;
gettoken ();
{
const char * init;
size_t len;
if (token.code == keyIDENTIFIER &&
typeofvar (token.str) == VarString)
{
std::string * pstr= addrvarstring (token.str);
init= pstr->data ();
len= pstr->size ();
gettoken ();
}
else
{
BlNumber bn= evalnum ();
init= reinterpret_cast <const char *>
(size_t (bn) );
if (token.code != ',')
throw ErrSyntax;
bn= expectnum ();
len= size_t (bn);
}
require_endsentence ();
ofstream os (progname.c_str (), std::ios::binary);
if (! os.is_open () )
throw ErrFileNotFound;
os.write (init, len);
}
break;
default:
throw ErrSyntax;
}
}
return false;
}
bool RunnerLine::do_new ()
{
errorifparam ();
program.renew ();
clearvars ();
Function::clear ();
runner.setreadline (0);
return true;
}
bool RunnerLine::do_exit ()
{
gettoken ();
int r= 0;
if (! endsentence () )
{
BlNumber n= evalnum ();
if (! endsentence () )
throw ErrSyntax;
r= int (n);
}
throw Exit (r);
}
bool RunnerLine::do_run ()
{
gettoken ();
BlLineNumber dest= 0;
if (token.code == keyNUMBER || token.code == keyINTEGER)
{
dest= evallinenumber ();
require_endsentence ();
}
else if (! endsentence () )
{
std::string progname= evalstring ();
require_endsentence ();
program.renew ();
program.load (progname);
}
clearvars ();
runner.setreadline (0);
runner.run_to (dest);
return true;
}
namespace {
class usingformat {
public:
virtual ~usingformat () { }
virtual bool isliteral () { return false; }
virtual void putliteral (BlFile & out) { throw ErrBlassicInternal; }
virtual void putnumeric (BlFile & out, BlNumber n)
{ throw ErrBlassicInternal; }
virtual void putstring (BlFile & out, const std::string & str)
{ throw ErrBlassicInternal; }
};
class usingliteral : public usingformat {
public:
usingliteral (const std::string & str) :
str (str)
{ }
bool isliteral () { return true; }
void putliteral (BlFile & out)
{ out << str; }
private:
std::string str;
};
class usingnumeric : public usingformat {
public:
usingnumeric (size_t digit, size_t decimal) :
digit (digit), decimal (decimal)
{ }
void putnumeric (BlFile & out, BlNumber n)
{
int numdig= 0;
if (n != 0)
numdig= int (std::log10 (std::fabs (n) * 10) );
if (numdig < 0) numdig= 0;
size_t w= numdig;
if (digit > w) w= digit;
if (decimal > 0)
w+= decimal + 1;
std::ostringstream oss;
if (decimal > 0)
oss.setf (std::ios::showpoint);
oss << std::setw (w) <<
std::setprecision (decimal + numdig) <<
n;
out << oss.str ();
}
private:
size_t digit, decimal;
};
class usingstring : public usingformat {
public:
usingstring (size_t n) :
n (n)
{ }
void putstring (BlFile & out, const std::string & str)
{
if (n > 0)
out << str.substr (0, n);
else
out << str;
}
private:
size_t n;
};
// Someone will call this "abuse of inheritance", but...
class vectorusing : public std::vector <usingformat *>
{
static void delete_it (const usingformat * uf) { delete uf; }
public:
vectorusing () { }
~vectorusing ()
{
std::for_each (begin (), end (), delete_it);
}
private:
vectorusing (const vectorusing &); // Forbidden
vectorusing & operator = (const vectorusing &); // Forbidden
};
bool ischarformat (char c)
{
return c == '#' || c == '\\' || c == '&' || c == '!'; // De momento
}
void getusingformat (const std::string & str, vectorusing & f)
{
const std::string::size_type l= str.size ();
std::string::size_type i= 0;
std::string lit;
for (;;)
{
while (i < l && ! ischarformat (str [i]) )
{
lit+= str [i];
++i;
}
if (! lit.empty () || l == 0)
{
auto_ptr <usingliteral> pul (new usingliteral (lit) );
f.push_back (& * pul);
pul.release ();
lit.erase ();
}
if (i == l)
break;
switch (str [i] )
{
case '#':
{
size_t digit= 1, decimal= 0;
while (++i < l && str [i] == '#')
++digit;
if (i < l && str [i] == '.')
while (++i < l && str [i] == '#')
++decimal;
// We use auto_ptr to avoid memory leak
// if push_back fail.
auto_ptr <usingnumeric>
pun (new usingnumeric
(digit, decimal) );
f.push_back (& * pun);
pun.release ();
}
break;
case '\\':
{
size_t n= 1;
while (++i < l && str [i] == ' ')
++n;
if (i < l && str [i] == '\\')
{ ++n; ++i; }
auto_ptr <usingstring>
pus (new usingstring (n) );
f.push_back (& * pus);
pus.release ();
}
break;
case '&':
{
++i;
auto_ptr <usingstring>
pus (new usingstring (0) );
f.push_back (& * pus);
pus.release ();
}
break;
case '!':
{
++i;
auto_ptr <usingstring>
pus (new usingstring (1) );
f.push_back (& * pus);
pus.release ();
}
break;
default:
throw ErrBlassicInternal;
}
}
}
} // namespace
void RunnerLine::print_using (BlFile & out)
{
std::string format= expectstring ();
vectorusing usingf;
getusingformat (format, usingf);
if (token.code == ',' || token.code == ';')
gettoken ();
const size_t l= usingf.size ();
size_t ind= 0;
usingformat * pf= usingf [ind];
for (;;)
{
if (ind == 0 && pf->isliteral () )
{
pf->putliteral (out);
ind= (ind + 1) % l;
if (ind == 0)
throw ErrFunctionCall;
pf= usingf [ind];
}
BlResult result;
eval (result);
switch (result.type () )
{
case VarNumber:
pf->putnumeric (out, result.number () );
break;
case VarInteger:
pf->putnumeric (out, result.number () );
break;
case VarString:
pf->putstring (out, result.str () );
break;
default:
throw ErrBlassicInternal;
}
ind= (ind + 1) % l;
pf= usingf [ind];
if (ind != 0 && pf->isliteral () )
{
pf->putliteral (out);
ind= (ind + 1) % l;
// Seen unnecessary, and is erroneous.
//if (ind == 0)
// throw ErrFunctionCall;
pf= usingf [ind];
}
if (endsentence () )
{
out << '\n';
break;
}
if (token.code == ';' || token.code == ',')
{
gettoken ();
if (endsentence () )
break;
}
}
}
bool RunnerLine::do_print ()
{
gettoken ();
BlChannel channel= 0;
if (token.code == '#')
{
channel= expectchannel ();
if (token.code == ',')
gettoken ();
else
require_endsentence ();
}
BlFile & out= getfile (channel);
if (token.code == '@')
{
BlResult result;
expect (result);
BlInteger pos= result.integer ();
requiretoken (',');
gettoken ();
#if 0
BlInteger row= (pos / 32) + 1;
BlInteger col= (pos % 32) + 1;
if (graphics::ingraphicsmode () )
graphics::locate (row, col);
else
locate (row, col);
#else
out.gotoxy (pos % 32, pos / 32);
#endif
}
if (endsentence () )
{
out << '\n';
return false;
}
BlResult result;
size_t n;
bool ended= false;
do {
switch (token.code) {
case ',':
case ';':
// Line if it were preceded by an empty statement
break;
case keyUSING:
print_using (out);
ended= true;
break;
case keyTAB:
//getparenarg (result);
// Not required to improve Sinclair ZX compatibility.
expect (result);
n= result.integer ();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -