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

📄 program.cpp

📁 由一个古老的BASIC解释器改进而成, 保留了ANSI C固有的艺术美感.
💻 CPP
📖 第 1 页 / 共 2 页
字号:
{
	std::string::size_type l= name.size ();
	if (l < 4)
		return false;
	std::string ext= name.substr (l - 4);
	//#ifdef _Windows
	std::transform (ext.begin (), ext.end (), ext.begin (), tolower);
	//#endif
	if (ext == ".blc" || ext == ".bas")
		return true;
	return false;
}

void openblassicprogram (std::ifstream & is, const std::string & name)
{
        const std::ios::openmode mode= std::ios::binary | std::ios::in;
	is.open (name.c_str (), mode);
	if (! is)
	{
		if (! hasblassicextension (name) )
		{
			std::string namex= name;
			namex+= ".blc";
			is.clear ();
			is.open (namex.c_str (), mode);
			if (! is.is_open () )
			{
				namex= name;
				namex+= ".bas";
				is.clear ();
				is.open (namex.c_str (), mode);
				if (! is.is_open () )
					throw ErrFileNotFound;
			}
		}
		else
			throw ErrFileNotFound;
	}
}

const char signature []=
	{ 'B', 'l', 'a', 's', 's', 'i', 'c', '\0' };
const size_t lsig= sizeof (signature);

bool isblassicbinary (std::istream & is)
{
	char magicstring [lsig];
	is.read (magicstring, lsig);
	if (! is || memcmp (magicstring, signature, lsig) != 0)
		return false;
	return true;
}

inline void checkread (std::istream & is, size_t readed)
{
	if (! is || size_t (is.gcount () ) != readed)
		throw ErrFileRead;
}

const unsigned long endian_mark= 0x12345678;

} // namespace

void Program::Internal::save (const std::string & name) const
{
	std::ofstream os (name.c_str (), std::ios::binary | std::ios::out);
	if (! os)
		return;
	os.write (signature, lsig);
	COMPILE_ASSERT (sizeof (unsigned long) == 4);
	os.write ( (char *) & endian_mark, 4);
	BlChar caux [4];
	poke32 (caux, size);
	os.write ( (char *) caux, 4);
	os.write ( (char *) program, size);
	if (! os)
		throw ErrFileWrite;
}

void Program::Internal::loadtext (std::istream & is)
{
	is.clear ();
	is.seekg (0);
	std::string str;
	std::getline (is, str);
	if (str [0] == '#')
	{
		str.erase ();
		std::getline (is, str);
	}
	CodeLine code;
	BlLineNumber nextnumline= sysvar::get32 (sysvar::AutoInit);
	BlLineNumber incnumline= sysvar::get32 (sysvar::AutoInc);
	BlLineNumber maxnumline= BlMaxLineNumber - incnumline;
	bool fExhausted= false;
	do {
		if (!str.empty () && str [str.size () - 1] == '\r')
			str.erase (str.size () - 1);
		code.scan (str);
		if (code.number () == 0)
		{
			if (fExhausted)
				throw ErrLineExhausted;
			code.setnumber (nextnumline);
			fExhausted= nextnumline > maxnumline;
			nextnumline+= incnumline;
		}
		else
		{
			fExhausted= code.number () > maxnumline;
			nextnumline= code.number () + incnumline;
		}
		if (code.length () > 0)
			insert (code);
		std::getline (is, str);
	} while (is);
}

void Program::Internal::loadbinary (std::istream & is)
{
	// This was intended to check endianess, but is
	// currently unused.
	COMPILE_ASSERT (sizeof (unsigned long) == 4);
	unsigned long endian_check;
	is.read ( (char *) & endian_check, 4);
	checkread (is, 4);
	BlChar caux [4];
	is.read ( (char *) caux, 4);
	checkread (is, 4);
	unsigned long newsize= peek32 (caux);
	size_t newblock= blockrounded (newsize);
	util::auto_alloc <BlChar> newprog (newblock);
	is.read (reinterpret_cast <char *> (newprog.data () ),
                newsize);
	checkread (is, newsize);
	renew ();
	program= newprog;
	newprog.release ();
	size= newsize;
}

void Program::Internal::load (const std::string & name)
{
        clear_cache ();
	std::ifstream (is);
	openblassicprogram (is, name);

	if (! isblassicbinary (is) )
	{
		renew ();
		loadtext (is);
	}
	else
	{
		loadbinary (is);
	}
}

void Program::Internal::merge (const std::string & name)
{
        clear_cache ();
	std::ifstream is;
	openblassicprogram (is, name);

	if (! isblassicbinary (is) )
	{
		loadtext (is);
	}
	else
	{
		Program::Internal inload;
		inload.loadbinary (is);
		for (CodeLine line= inload.getfirstline ();
			line.number () != 0;
			//line= inload.getnextline (line)
			inload.getnextline (line)
		)
		{
			insert (line);
		}
	}
}

void Program::Internal::renew ()
{
	size= 0;
        clear_cache ();
	if (program)
	{
		free (program);
		program= 0;
	}
}

namespace {

typedef MAP <BlLineNumber, BlLineNumber> MapLine;

void showmappedline (const MapLine::value_type & linepair)
{
	cerr << linepair.first << " mappped to " << linepair.second << endl;
}

bool iscodewithnumber (BlCode code)
{
	return (code == keyGOTO || code == keyGOSUB || code == keyRUN ||
		code == keyRESTORE || code == keyRESUME ||
		code == keyDELETE || code == keyLIST ||
		code == keyEDIT ||
		code == keyTHEN || code == keyELSE);
}

void changeline (CodeLine & line, const MapLine & mapline)
{
	const BlLineLength l= line.length ();
	BlChar * s= line.content ();
	BlLineLength p= 0;
	BlChar c;
	while (p < l)
	{
		c= s [p];
		if (iskey (c) )
		{
			BlCode code= BlCode ( (BlCode (c) << 8 ) ) |
				BlCode (s [p+1] );
			p+= 2;
			//cerr << "Key " << decodekeyword (code) << flush;
			if (iscodewithnumber (code) )
			{
				//cerr << " analyzing" << flush;
				for (;;)
				{
					while (p < l && isspace (s [p] ) )
						++p;
					if (p >= l)
						break;
					c= s [p];
					if (c == INTEGER_PREFIX)
					{
						BlLineNumber old= getLineNumber
							(s + p + 1);
						//cerr << " Find " << old <<
						//	flush;
						MapLine::const_iterator it=
							mapline.find (old);
						if (it != mapline.end () )
						{
							//cerr << " Changed " <<
							//	it->second <<
							//	flush;
							setLineNumber
								(s + p + 1,
								it->second);
						}
						p+= 1 + sizeof (BlInteger);
					}
					else if (c == ':')
					{
						++p;
						break;
					}
					else if (c == '"')
					{
						while (s [++p] != '\0')
							continue;
						++p;
					}
					else if (iskey (c) )
						p+= 2;
					else if (c == '\'')
					{
						p= l;
						break;
					}
					else ++p;
				}
				//cerr << endl;
			}
			//else cerr << endl;
		}
		else if (c == INTEGER_PREFIX)
			p+= 1 + sizeof (BlInteger);
		else if (c == '"')
		{
			while (s [++p] != '\0')
				continue;
			++p;
		}
		else if (c == '\'')
			break;
		else ++p;
	}
}

}

void Program::Internal::renum (BlLineNumber blnNew, BlLineNumber blnOld,
	BlLineNumber blnInc)
{
	clear_cache ();

	Position pos= 0;
	MapLine mapline;

	// Find first line to renum.
	BlLineNumber previous= 0;
	while (pos < size && numline (pos) < blnOld)
	{
		previous= numline (pos);
		//cerr << "Skipping line " << previous << endl;
		pos= nextline (pos);
	}
	if (previous >= blnNew)
		throw ErrMismatch;

	// Change the line numbers.
	BlLineNumber actual;
	BlLineNumber blnMax= BlMaxLineNumber - blnInc;
	bool overflow= false;
	for ( ; pos < size; pos= nextline (pos) )
	{
		actual= numline (pos);
		if (actual != blnNew)
		{
			if (overflow)
				throw ErrLineExhausted;
			mapline [actual]= blnNew;
			//setLineNumber (program + pos, blnNew);
		}
		if (blnNew > blnMax)
			overflow= true;
		else
			blnNew+= blnInc;
	}

	//for_each (mapline.begin (), mapline.end (), showmappedline);

	// Change refereneces to lines.
	MapLine::iterator it, mapend= mapline.end ();
	CodeLine line;
	for (pos= 0; pos < size; pos= nextline (pos) )
	{
		actual= numline (pos);
		getlineinpos (pos, line);
		//cerr << "Exploring line " << actual << endl;
		it= mapline.find (actual);
		if (it != mapend)
		{
			//cerr << "Changing line " << actual <<
			//	" by " << it->second << endl;
			setLineNumber (program + pos, it->second);
		}
		changeline (line, mapline);
	}
}

//**********************************************************
//		Program
//**********************************************************

Program::Program () :
	pin (new Internal)
{
}

Program::~Program ()
{
	delete pin;
}

BlChar * Program::programptr ()
{
	return pin->programptr ();
}

BlLineNumber Program::getlabel (const std::string & str)
{
	return pin->getlabel (str);
}

CodeLine Program::getfirstline ()
{
	return pin->getfirstline ();
}

//CodeLine Program::getnextline (CodeLine & line)
void Program::getnextline (CodeLine & line)
{
	//return pin->getnextline (line);
	pin->getnextline (line);
}

#if 0
BlLineNumber Program::getnextnum (CodeLine & line)
{
	return pin->getnextnum (line);
}
#endif

#if 0
CodeLine Program::getline (BlLineNumber num)
{
	return pin->getline (num);
}
#endif

void Program::getline (BlLineNumber num, CodeLine & line)
{
	pin->getline (num, line);
}

void Program::getline (ProgramPos pos, CodeLine & line)
{
	BlLineNumber n= pos.getnum ();
	pin->getline (n, line);
	if (line.number () == n)
	{
		BlChunk ch= pos.getchunk ();
		if (ch != 0)
			line.gotochunk (ch);
	}
}

void Program::insert (const CodeLine & code)
{
	pin->insert (code);
}

void Program::deletelines (BlLineNumber iniline, BlLineNumber endline)
{
	pin->deletelines (iniline, endline);
}

void Program::list (BlLineNumber iniline, BlLineNumber endline,
	BlFile & out) const
{
	pin->list (iniline, endline, out);
}

void Program::save (const std::string & name) const
{
	pin->save (name);
}

void Program::load (const std::string & name)
{
	pin->load (name);
}

void Program::merge (const std::string & name)
{
	pin->merge (name);
}

void Program::renew ()
{
	pin->renew ();
}

void Program::renum (BlLineNumber blnNew, BlLineNumber blnOld,
	BlLineNumber blnInc)
{
	pin->renum (blnNew, blnOld, blnInc);
}

// Fin de program.cpp

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -