⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 program.cpp

📁 由一个古老的BASIC解释器改进而成, 保留了ANSI C固有的艺术美感.
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// 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 + -