📄 program.cpp
字号:
// program.cpp
#include <cassert>
#define ASSERT assert
#include <string>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <algorithm>
#include <cctype>
#include <sstream>
using std::string;
// For debugging.
using std::cerr;
using std::endl;
using std::flush;
#include "blassic.h"
#include "token.h"
#include "keyword.h"
#include "var.h"
#include "program.h"
#include "error.h"
#include "sysvar.h"
#ifndef USE_HASH_MAP
#include <map>
#define MAP std::map
#else
#include <hash_map>
#define MAP std::hash_map
template <> struct hash <std::string>
{
hash () : hashstr (hash <const char *> () ) { }
size_t operator () (const std::string & str) const
{ return hashstr (str.c_str () ); }
private:
hash <const char *> hashstr;
};
#endif
#ifdef __BORLANDC__
#pragma warn -inl
#endif
typedef unsigned long Position;
namespace {
inline BlLineNumber getLineNumber (const BlChar * pos)
{
return peek32 (pos);
}
inline void setLineNumber (BlChar * pos, BlLineNumber n)
{
poke32 (pos, n);
}
inline BlLineLength getLineLength (BlChar * pos)
{
return peek32 (pos);
}
inline void setLineLength (BlChar * pos, BlLineLength n)
{
poke32 (pos, n);
}
} // namespace
//**********************************************************
// Program::Internal
//**********************************************************
class Program::Internal {
public:
Internal () :
program (0),
size (0)
{ }
inline BlChar * programptr () { return program; }
inline BlLineNumber getlabel (const std::string & str);
inline CodeLine getfirstline ();
//inline CodeLine getnextline (CodeLine & line);
inline void getnextline (CodeLine & line);
//BlLineNumber getnextnum (CodeLine & line);
//inline CodeLine getline (BlLineNumber num);
inline void getlineinpos (Position pos, CodeLine & line);
inline void getline (BlLineNumber num, CodeLine & line);
void insert (const CodeLine & code);
void deletelines (BlLineNumber iniline, BlLineNumber endline);
void list (BlLineNumber iniline, BlLineNumber endline,
BlFile & out) const;
void save (const std::string & name) const;
void load (const std::string & name);
void merge (const std::string & name);
void renew ();
void renum (BlLineNumber blnNew, BlLineNumber blnOld,
BlLineNumber blnInc);
private:
BlChar * program;
BlLineLength size;
typedef MAP <BlLineNumber, Position> linecache_t;
linecache_t linecache;
typedef MAP <string, BlLineNumber> labelcache_t;
labelcache_t labelcache;
void clear_cache ();
inline Position nextline (Position pos) const;
inline BlLineLength sizeline (Position) const;
inline BlLineNumber numline (Position pos) const;
inline const BlChar * linecontent (Position pos) const;
inline BlChar * linecontent (Position pos);
static const size_t BLOCK= 16 * 1024;
inline static size_t blockrounded (size_t size)
{
return ( (size + BLOCK - 1) / BLOCK) * BLOCK;
}
void loadtext (std::istream & is);
void loadbinary (std::istream & is);
};
inline BlLineLength Program::Internal::sizeline (Position pos) const
{
BlChar * aux= program + pos + sizeof (BlLineNumber);
return getLineLength (aux);
}
inline Position Program::Internal::nextline (Position pos) const
{
return pos + sizeline (pos) +
sizeof (BlLineNumber) + sizeof (BlLineLength);
}
inline BlLineNumber Program::Internal::numline (Position pos) const
{
return getLineNumber (program + pos);
}
inline const BlChar * Program::Internal::linecontent (Position pos) const
{
return program + pos + sizeof (BlLineNumber) + sizeof (BlLineLength);
}
inline BlChar * Program::Internal::linecontent (Position pos)
{
return program + pos + sizeof (BlLineNumber) + sizeof (BlLineLength);
}
void Program::Internal::clear_cache ()
{
linecache.clear ();
labelcache.clear ();
}
#if 0
void Program::setlabel (const std::string & label, BlLineNumber number)
{
labelcache [label]= number;
}
#endif
inline BlLineNumber Program::Internal::getlabel (const std::string & label)
{
labelcache_t::iterator it= labelcache.find (label);
if (it != labelcache.end () )
return it->second;
CodeLine line= getfirstline ();
CodeLine::Token token;
while (line.number () != 0)
{
//CodeLine::Token token= line.gettoken ();
line.gettoken (token);
if (token.code == keyLABEL)
{
//token= line.gettoken ();
line.gettoken (token);
if (label == token.str)
{
BlLineNumber n (line.number () );
labelcache [label]= n;
// Probably the next action is jump to it,
// then we put it in the cache.
linecache [n]= line.content () - program
- sizeof (BlLineNumber)
- sizeof (BlLineLength);
;
return line.number ();
}
}
//line= getnextline (line);
getnextline (line);
}
return 0;
}
inline CodeLine Program::Internal::getfirstline ()
{
if (size == 0)
return CodeLine (0, 0, 0);
return CodeLine (
//program + sizeof (BlLineNumber) + sizeof (BlLineLength),
linecontent (0),
numline (0), sizeline (0) );
}
//inline CodeLine Program::Internal::getnextline (CodeLine & line)
inline void Program::Internal::getnextline (CodeLine & line)
{
if (line.number () == 0)
{
//return CodeLine (0, 0, 0);
line.assign (0, 0, 0);
return;
}
Position pos= line.content () - program;
pos+= line.length ();
if (pos >= size)
{
//return CodeLine (0, 0, 0);
line.assign (0, 0, 0);
return;
}
//return CodeLine (
// //program + pos + sizeof (BlLineNumber) + sizeof (BlLineLength),
// linecontent (pos),
// numline (pos), sizeline (pos) );
line.assign (linecontent (pos), numline (pos), sizeline (pos) );
}
#if 0
inline BlLineNumber Program::Internal::getnextnum (CodeLine & line)
{
if (line.number () == 0)
return 0;
Position pos= line.content () - program;
pos+= line.length ();
if (pos >= size)
return 0;
return numline (pos);
}
#endif
inline void Program::Internal::getlineinpos (Position pos, CodeLine & line)
{
line.assign (linecontent (pos), numline (pos), sizeline (pos) );
}
//inline CodeLine Program::Internal::getline (BlLineNumber num)
inline void Program::Internal::getline (BlLineNumber num, CodeLine & line)
{
Position pos= 0;
linecache_t::iterator it= linecache.find (num);
if (it != linecache.end () )
pos= it->second;
else
{
while (pos < size && numline (pos) < num)
pos= nextline (pos);
if (pos >= size)
{
//return CodeLine (0, 0, 0);
line.assign (0, 0, 0);
return;
}
linecache [num]= pos;
}
//return CodeLine (
// //program + pos + sizeof (BlLineNumber) + sizeof (BlLineLength),
// linecontent (pos),
// numline (pos), sizeline (pos) );
//line.assign (
// //program + pos + sizeof (BlLineNumber) + sizeof (BlLineLength),
// linecontent (pos),
// numline (pos), sizeline (pos) );
getlineinpos (pos, line);
}
void Program::Internal::insert (const CodeLine & code)
{
clear_cache ();
Position pos= 0;
while (pos < size && numline (pos) < code.number () )
pos= nextline (pos);
const BlChar * strnew= code.content ();
BlLineLength linesize= code.length () +
sizeof (BlLineNumber) + sizeof (BlLineLength);
unsigned long osize= size;
Position destpos= pos + linesize;
Position origpos;
if (pos < size && numline (pos) == code.number () )
{
origpos= nextline (pos);
//destpos= pos + sizenew;
size+= code.length () - sizeline (pos);
}
else
{
origpos= pos;
//destpos= pos + sizenew;
size+= linesize;
}
if (destpos > origpos)
{
ASSERT (size > osize);
size_t newblock= blockrounded (size);
if (newblock != blockrounded (osize) )
{
unsigned char * newprog=
(unsigned char *) realloc (program, newblock);
if (! newprog)
throw ErrOutMemory;
program= newprog;
}
if (pos < osize)
{
memmove (program + destpos,
program + origpos,
osize - origpos);
}
}
else if (destpos < origpos)
{
ASSERT (size < osize);
memmove (program + destpos,
program + origpos,
osize - origpos);
size_t newblock= blockrounded (size);
if (newblock != blockrounded (osize) )
{
unsigned char * newprog=
(unsigned char *) realloc (program, newblock);
if (! newprog)
throw ErrOutMemory;
program= newprog;
}
}
setLineNumber (program + pos, code.number () );
setLineLength (program + pos + sizeof (BlLineNumber), code.length () );
memcpy (linecontent (pos), strnew, code.length () );
}
void Program::Internal::deletelines
(BlLineNumber iniline, BlLineNumber endline)
{
clear_cache ();
Position pos= 0;
while (pos < size && numline (pos) < iniline)
pos= nextline (pos);
if (pos >= size)
return;
Position posend= pos;
while (posend < size && numline (posend) <= endline)
posend= nextline (posend);
if (posend == pos)
return;
#if 0
cout << "Deleting from " << numline (pos) << " to ";
if (posend < size)
cout << "(not including) " << numline (posend);
else
cout << "the end";
cout << endl;
#endif
if (posend < size)
memmove (program + pos,
program + posend,
size - posend);
size_t osize= size;
size-= posend - pos;
if (size > 0)
{
size_t newblock= blockrounded (size);
if (newblock != blockrounded (osize) )
realloc (program, newblock);
}
else
{
free (program);
program= NULL;
}
}
void Program::Internal::list
(BlLineNumber iniline, BlLineNumber endline, BlFile & out) const
{
Position pos= 0;
while (pos < size && numline (pos) < iniline)
pos= nextline (pos);
while (pos < size)
{
BlLineNumber number= numline (pos);
if (number > endline)
break;
BlLineLength linesize= sizeline (pos);
out << /*std::setw (7) << */ number << ' ';
const BlChar * aux= linecontent (pos);
pos= nextline (pos);
std::string line;
for (unsigned long i= 0; i < linesize; ++i)
{
unsigned char c= aux [i];
if (c == '\0') // Skip garbage
break;
if (iskey (c) )
{
BlCode s= c;
s<<= 8;
s|= aux [++i];
line+= decodekeyword (s);
}
else if (c == INTEGER_PREFIX)
{
//BlInteger n;
//n= * (BlInteger *) (aux + i + 1);
BlInteger n= peek32 (aux + i + 1);
std::ostringstream oss;
oss << n;
line+= oss.str ();
i+= 4;
}
else if (c == '"')
{
line+= c;
while ( (c= aux [++i]) != 0)
if (c == '"')
line+= "\"\"";
else
line+= c;
line+= '"';
}
else if (c == '\t')
{
const size_t l= line.size ();
line.insert (l, 8 - l % 8, ' ');
}
else
line+= c;
}
//out << line;
//out << '\n';
line+= '\n';
out << line;
if (fInterrupted)
break;
}
}
namespace {
bool hasblassicextension (const std::string & name)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -