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

📄 runnerline.cpp

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