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

📄 runnerline.cpp

📁 由一个古老的BASIC解释器改进而成, 保留了ANSI C固有的艺术美感.
💻 CPP
📖 第 1 页 / 共 5 页
字号:
// runnerline.cpp

#include "runnerline.h"

#include "error.h"
#include "dynamic.h"
#include "runner.h"
#include "cursor.h"
#include "sysvar.h"
#include "graphics.h"
#include "function.h"
#include "edit.h"
#include "util.h"

#include <sstream>
#include <iomanip>
#include <algorithm>
#include <functional>
#include <memory>
using std::auto_ptr;
#include <cmath>
#include <cstdio>
#include <cerrno>
#include <ctime>
#include <cctype>
using std::isalpha;

#include <iostream>
using std::cerr;
using std::endl;

#if defined __unix__ || defined __linux__ // Kylix defines only __linux__
#include <unistd.h>
#include <glob.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/utsname.h>
#else
// Define unlink?
using std::unlink;
#include <dir.h>
#endif

#include <cassert>
#define ASSERT assert

namespace {

#if defined __unix__ || defined __linux__

const char * os_family= "unix";

#else

const char * os_family= "windows";

#endif

// We encapsulate the random generator in a class to have all code
// related to it in a place, and to be able to change it easily.

// random in some systems may not use the RAND_MAX value,
// then we use it only in linux.

class RandomGenerator {
public:
	BlNumber operator () ()
	{
		#if defined __linux__
		return BlNumber (random () ) / (RAND_MAX + 1.0);
	        #else
		return BlNumber (rand () ) / (RAND_MAX + 1.0);
		#endif
	}
	void seed (unsigned int value)
	{
		#if defined __linux__
		srandom (value);
		#else
		srand (value);
		#endif
	}
};

RandomGenerator randgen;

inline bool iscomp (BlCode code)
{
	return code == '=' || code == keyDISTINCT ||
		code == '<' || code == keyMINOREQUAL ||
		code == '>' || code == keyGREATEREQUAL;
}

typedef std::map <std::string, Function> mapfunction_t;
mapfunction_t mapfunction;

} // namespace

const RunnerLine::mapfunc_t RunnerLine::mapfunc= initmapfunc ();

// Avoid call mapfunc.end every time.
const RunnerLine::mapfunc_t::const_iterator
	RunnerLine::mapend= mapfunc.end ();

RunnerLine::mapfunc_t RunnerLine::initmapfunc ()
{
	mapfunc_t m;
	m [':']=             & RunnerLine::do_empty_sentence;
	m [keyENDLINE]=      & RunnerLine::do_endline;
	m [keyNUMBER]=       & RunnerLine::do_number;
        m [keyINTEGER]=      & RunnerLine::do_number;
	m [keyEND]=          & RunnerLine::do_end;
	m [keyLIST]=         & RunnerLine::do_list;
	m [keyREM]=          & RunnerLine::do_rem;
	m [keyLOAD]=         & RunnerLine::do_load;
	m [keySAVE]=         & RunnerLine::do_save;
	m [keyNEW]=          & RunnerLine::do_new;
	m [keyEXIT]=         & RunnerLine::do_exit;
	m [keyRUN]=          & RunnerLine::do_run;
	m [keyPRINT]=        & RunnerLine::do_print;
	m [keyFOR]=          & RunnerLine::do_for;
	m [keyNEXT]=         & RunnerLine::do_next;
	m [keyIF]=           & RunnerLine::do_if;
	m [keyTRON]=         & RunnerLine::do_tron;
	m [keyTROFF]=        & RunnerLine::do_troff;
	m [keyLET]=          & RunnerLine::do_let;
	m [keyIDENTIFIER]=   & RunnerLine::do_let;
	m [keyGOTO]=         & RunnerLine::do_goto;
	m [keySTOP]=         & RunnerLine::do_stop;
	m [keyCONT]=         & RunnerLine::do_cont;
	m [keyCLEAR]=        & RunnerLine::do_clear;
	m [keyGOSUB]=        & RunnerLine::do_gosub;
	m [keyRETURN]=       & RunnerLine::do_return;
	m [keyPOKE]=         & RunnerLine::do_poke;
	m [keyREAD]=         & RunnerLine::do_read;
	m [keyDATA]=         & RunnerLine::do_data;
	m [keyRESTORE]=      & RunnerLine::do_restore;
	m [keyINPUT]=        & RunnerLine::do_input;
	m [keyLINE]=         & RunnerLine::do_line;
	m [keyRANDOMIZE]=    & RunnerLine::do_randomize;
	m [keyAUTO]=         & RunnerLine::do_auto;
	m [keyDIM]=          & RunnerLine::do_dim;
	m [keySYSTEM]=       & RunnerLine::do_system;
	m [keyON]=           & RunnerLine::do_on;
	m [keyERROR]=        & RunnerLine::do_error;
	m [keyOPEN]=         & RunnerLine::do_open;
	m [keyCLOSE]=        & RunnerLine::do_close;
	m [keyLOCATE]=       & RunnerLine::do_locate;
	m [keyCLS]=          & RunnerLine::do_cls;
	m [keyWRITE]=        & RunnerLine::do_write;
	m [keyMODE]=         & RunnerLine::do_mode;
	m [keyMOVE]=         & RunnerLine::do_move;
	m [keyCOLOR]=        & RunnerLine::do_color;
	m [keyGET]=          & RunnerLine::do_get;
	m [keyLABEL]=        & RunnerLine::do_label;
	m [keyDELIMITER]=    & RunnerLine::do_delimiter;
	m [keyREPEAT]=       & RunnerLine::do_repeat;
	m [keyUNTIL]=        & RunnerLine::do_until;
	m [keyWHILE]=        & RunnerLine::do_while;
	m [keyWEND]=         & RunnerLine::do_wend;
	m [keyPLOT]=         & RunnerLine::do_plot;
        // Open and popen use same function.
        m [keyPOPEN]=        & RunnerLine::do_open;
        m [keyRESUME]=       & RunnerLine::do_resume;
	m [keyDELETE]=       & RunnerLine::do_delete;
	m [keyLOCAL]=        & RunnerLine::do_local;
	m [keyPUT]=          & RunnerLine::do_put;
        m [keyFIELD]=        & RunnerLine::do_field;
        // Lset and rset use same function.
        m [keyLSET]=         & RunnerLine::do_lset;
        m [keyRSET]=         & RunnerLine::do_lset;
        m [keySOCKET]=       & RunnerLine::do_socket;
        m [keyMID_S]=        & RunnerLine::do_mid_s;
        m [keyDRAW]=         & RunnerLine::do_draw;
        m [keyDEF]=          & RunnerLine::do_def;
        m [keyFN]=           & RunnerLine::do_fn;
        m [keyPROGRAMARG_S]= & RunnerLine::do_programarg_s;
        m [keyERASE]=        & RunnerLine::do_erase;
        m [keySWAP]=         & RunnerLine::do_swap;
        m [keySYMBOL]=       & RunnerLine::do_symbol;
        m [keyZONE]=         & RunnerLine::do_zone;
        m [keyPOP]=          & RunnerLine::do_pop;
	m [keyNAME]=         & RunnerLine::do_name;
	m [keyKILL]=         & RunnerLine::do_kill;
	m [keyFILES]=        & RunnerLine::do_files;
	m [keyPAPER]=        & RunnerLine::do_paper;
	m [keyPEN]=          & RunnerLine::do_pen;
	m [keySHELL]=        & RunnerLine::do_shell;
	m [keyMERGE]=        & RunnerLine::do_merge;
	m [keyCHDIR]=        & RunnerLine::do_chdir;
	m [keyMKDIR]=        & RunnerLine::do_mkdir;
	m [keyRMDIR]=        & RunnerLine::do_rmdir;
	m [keySYNCHRONIZE]=  & RunnerLine::do_synchronize;
	m [keyPAUSE]=        & RunnerLine::do_pause;
	m [keyCHAIN]=        & RunnerLine::do_chain;
        m [keyENVIRON]=      & RunnerLine::do_environ;
        m [keyEDIT]=         & RunnerLine::do_edit;
        m [keyDRAWR]=        & RunnerLine::do_drawr;
        m [keyPLOTR]=        & RunnerLine::do_plotr;
        m [keyMOVER]=        & RunnerLine::do_mover;
        m [keyPOKE16]=       & RunnerLine::do_poke16;
        m [keyPOKE32]=       & RunnerLine::do_poke32;
        m [keyRENUM]=        & RunnerLine::do_renum;
        m [keyCIRCLE]=       & RunnerLine::do_circle;
        m [keyMASK]=         & RunnerLine::do_mask;
        m [keyWINDOW]=       & RunnerLine::do_window;
        m [keyGRAPHICS]=     & RunnerLine::do_graphics;
	return m;
}

#if 0 // Use macros instead to avoid strange errors on hp-ux.
inline void RunnerLine::requiretoken (BlCode code) const throw (BlErrNo)
{
        if (token.code != code)
                throw ErrSyntax;
}

inline void RunnerLine::expecttoken (BlCode code) throw (BlErrNo)
{
        gettoken ();
        requiretoken (code);
}
#else
#define requiretoken(c) if (token.code == c) ; else throw ErrSyntax
#define expecttoken(c) do { \
                gettoken (); \
                if (token.code != c) throw ErrSyntax; \
                } while (0)
#endif

void RunnerLine::getnextchunk ()
{
	while (! endsentence () )
		gettoken ();
	if (token.code != keyENDLINE)
		gettoken ();
}

inline BlFile & RunnerLine::getfile (BlChannel channel)
{
	return runner.getfile (channel);
}

inline BlNumber RunnerLine::evalnum ()
{
	BlResult result;
	eval (result);
	return result.number ();
}

inline BlNumber RunnerLine::expectnum ()
{
	gettoken ();
	return evalnum ();
}

inline BlInteger RunnerLine::evalinteger ()
{
	BlResult result;
	eval (result);
	return result.integer ();
}

inline BlInteger RunnerLine::expectinteger ()
{
	gettoken ();
	return evalinteger ();
}

inline BlChannel RunnerLine::evalchannel ()
{
	BlResult result;
	eval (result);
	return util::checked_cast <BlChannel> (result.integer (), ErrMismatch);
}

inline BlChannel RunnerLine::expectchannel ()
{
	gettoken ();
	return evalchannel ();
}

inline std::string RunnerLine::evalstring ()
{
	BlResult result;
	eval (result);
	return result.str ();
}

inline std::string RunnerLine::expectstring ()
{
	gettoken ();
	return evalstring ();
}

void RunnerLine::parenarg (BlResult & result)
{
	expect (result);
	requiretoken (')');
	gettoken ();
}
void RunnerLine::getparenarg (BlResult & result)
{
	expecttoken ('(');
	expect (result);
	requiretoken (')');
	gettoken ();
}

void RunnerLine::valnumericfunc (double (* f) (double), BlResult & result)
{
	getparenarg (result);
	result= f (result.number () );
}

namespace { // Auxiliary math functions

double auxFIX (double n)
{
	double r;
	std::modf (n, & r);
	return r;
}

#ifdef __WIN32__

double auxCINT (double n)
{
        // Provisional.
        double r;
        n= std::modf (n, & r);
        if (n >= 0.5) r+= 1.0;
        else if (n <= -0.5) r-= 1.0;
        return r;
}

#endif

} // namespace

void RunnerLine::valasc (BlResult & result)
{
	getparenarg (result);
	const std::string & str= result.str ();
	if (str.empty () ) result= 0;
	else result= BlInteger ( (unsigned char) str [0] );
}

void RunnerLine::vallen (BlResult & result)
{
	getparenarg (result);
	result= result.str ().size ();
}

void RunnerLine::valpeek (BlResult & result)
{
	getparenarg (result);
	BlChar * addr= (BlChar *) size_t (result.number () );
	//result= BlNumber (size_t (* addr) );
	result= BlInteger (size_t (* addr) );
}

void RunnerLine::valpeek16 (BlResult & result)
{
	getparenarg (result);
	BlChar * addr= (BlChar *) size_t (result.number () );
	result= peek16 (addr);
}

void RunnerLine::valpeek32 (BlResult & result)
{
	getparenarg (result);
	BlChar * addr= (BlChar *) size_t (result.number () );
	result= BlNumber (static_cast <unsigned long> (peek32 (addr) ) );
}

void RunnerLine::valprogramptr (BlResult & result)
{
	gettoken ();
	result= BlNumber (size_t (program.programptr () ) );
}

void RunnerLine::valrnd (BlResult & result)
{
	BlNumber n;
	gettoken ();
	if (token.code == '(')
	{
		parenarg (result);
		n= result.number ();
	}
	else n= 1;

	static BlNumber previous= 0;

	if (n == 0)
	{
		result= previous;
		return;
	}

	if (n < 0)
		srand (time (0) );

	BlNumber r;

	#if 0
	#if defined __unix__ || defined __linux__
	r= BlNumber (random () ) / (RAND_MAX + 1.0);
        #else
        r= BlNumber (rand () ) / (RAND_MAX + 1.0);
        #endif
        #else
        r= randgen ();
        #endif

	result= r;
	previous= r;
}

void RunnerLine::valinstr (BlResult & result)
{
	expecttoken ('(');
	std::string str;
	size_t init= 0;
	
	expect (result);
	switch (result.type () )
	{
	case VarString:
		str= result.str ();
		break;
	case VarNumber:
		init= size_t (result.number () );
		if (init > 0)
			--init;
                requiretoken (',');
		str= expectstring ();
		break;
	case VarInteger:
		init= result.integer ();
		if (init > 0)
			--init;
		requiretoken (',');
		str= expectstring ();
		break;
	default:
		throw ErrBlassicInternal;
	}
	requiretoken (',');
	std::string tofind= expectstring ();
	requiretoken (')');
	gettoken ();
	size_t pos;
	if (tofind.empty () )
	{
		if (str.empty () )
			pos= 0;
		else
			if (init < str.size () )
				pos= init + 1;
			else
				pos= 0;
	}
	else
	{
		pos= str.find (tofind, init);
		if (pos == std::string::npos)
			pos= 0;
		else ++pos;
	}
	result= BlInteger (pos);
}

namespace {

class GuardHandle {
public:
        GuardHandle (DynamicHandle * pn) :
                phandle (pn)
        { }
        ~GuardHandle ()
        {
                if (* phandle)
                        dynamicclose (* phandle);
        }
private:
        DynamicHandle * phandle;
};

} // namespace

void RunnerLine::valusr (BlResult & result)
{
	expecttoken ('(');
	void * symaddr;
	DynamicHandle libhandle= 0;
        GuardHandle guard (& libhandle);

	expect (result);
	switch (result.type () )
	{
	case VarNumber:
		symaddr= reinterpret_cast <void *>
			(size_t (result.number () ) );
		break;
	case VarInteger:
		symaddr= reinterpret_cast <void  *> (result.integer () );
		break;
	case VarString:
		{
			std::string libname= result.str ();
                        requiretoken (',');
			std::string funcname= expectstring ();
                        libhandle= dynamicload (libname);
			if (! libhandle)
				throw ErrNoDynamicLibrary;
                        symaddr= dynamicaddr (libhandle, funcname);
                        #ifdef _Windows
                        if (! symaddr)
                        {
                                funcname= std::string (1, '_') + funcname;
                                symaddr= dynamicaddr (libhandle, funcname);
                        }
                        #endif
			if (! symaddr)
				throw ErrNoDynamicSymbol;
		}
		break;
	default:
		throw ErrBlassicInternal;
	}

        int nparams= 0;
        std::vector <int> vparam;
        while (token.code == ',')
        {
                //BlNumber newpar= expectnum ();
                //vparam.push_back (int (newpar) );
		expect (result);
		vparam.push_back (result.integer () );
                ++nparams;
        }
	requiretoken (')');
        gettoken ();
	util::auto_buffer <int> param;
	if (nparams)
	{
		param.alloc (nparams);
		std::copy (vparam.begin (), vparam.end (), param.begin () );
	}

	// reinterpret_cast produces a warning in gcc.
	//DynamicUsrFunc f= reinterpret_cast <DynamicUsrFunc> (symaddr);
	DynamicUsrFunc f= (DynamicUsrFunc) symaddr;
	result= static_cast <BlInteger> (f (nparams, param) );
}

void RunnerLine::valval (BlResult & result)
{
        getparenarg (result);
        std::string str= result.str ();
        switch (sysvar::get (sysvar::TypeOfVal) )
	{
	case 0:
		// VAL simple.
		{
			#if 0
			size_t i= 0, l= str.size ();
			while (i < l && str [i] == ' ')
				++i;
			#else
			std::string::size_type i=
				str.find_first_not_of (" \t");
			if (i > 0)
				if (i == std::string::npos)
					str.erase ();
				else
					str= str.substr (i);
			#endif
		}
		result= CodeLine::Token::number (str);
		break;
	case 1:
		// VAL with expression evaluation (Sinclair ZX)
		if (str.find_first_not_of (" \t")
			== std::string::npos)
		{
			result= 0;

⌨️ 快捷键说明

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