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

📄 brun.c

📁 smallbasic for linux
💻 C
📖 第 1 页 / 共 2 页
字号:
/***	SmallBasic byte-code executor**	Nicholas Christopoulos**	This program is distributed under the terms of the GPL v2.0 or later*	Download the GNU Public License (GPL) from www.gnu.org*/#include "sys.h"#include "panic.h"#include "blib.h"#include "device.h"#include "str.h"#include "kw.h"#include "var.h"#include "smbas.h"#define BRUN_MODULE#include "pproc.h"byte	opt_graphics = 1;#if defined(_PalmOS)#define	idSmBa	0x536D4261#define	idDATA	0x44415441#endif//#define _CHECK_STACKword	prog_line;			// The current source lineint		prog_error;			// The last error code (its work as flag)word	prog_length;		// The byte-code length (program length in bytes)word	prog_ip;			// The instruction pointerbyte	*prog_source;		// The byte-codeword	data_ip;			// READ/DATA positionvar_t	**tvar;				// The table of variableslab_t	*tlab;				// The table of labelsstknode_t	*prog_stack;	// The program stack word	prog_stack_alloc;	// The stack sizeword	prog_stack_count;	// The stack pointerword	prog_varcount;word	prog_labcount;char	*prog_file;static dword evt_check_every;#if defined(_PalmOS) static char	fileName[65];#elsestatic char	fileName[1024];#endifmem_t	bytecode_h;#if defined(_PalmOS)DmOpenRef	bytecode_fp;word		bytecode_recidx;#define	fatal(c,m)	ErrNonFatalDisplayIf((c), (m))#endif/***	run-time error*/void	rt_raise(const char *fmt, ...){	char	*buff;	va_list ap;	va_start(ap, fmt);	prog_error = 1;	buff = tmp_alloc(256);	#if defined(_PalmOS)	StrVPrintF(buff, fmt, ap);	#else	vsprintf(buff, fmt, ap);	#endif	va_end(ap);		dev_printf("* ERROR AT %s:%d *\n", prog_file, prog_line);	dev_printf("> %s\n", buff);	tmp_free(buff);}/* ERROR MESSAGES */void	err_stackoverflow()		SEC(TRASH);void	err_stackoverflow()		{	rt_raise("STACK OVERFLOW");	}void	err_stackunderflow()	SEC(TRASH);void	err_stackunderflow()	{	rt_raise("STACK UNDERFLOW");	}void	err_arrmis_lp()			SEC(TRASH);void	err_arrmis_lp()			{	rt_raise("ARRAY: MISSING '('"); }void	err_arrmis_rp()			SEC(TRASH);void	err_arrmis_rp()			{	rt_raise("ARRAY: MISSING ')'"); }void	err_arridx()			SEC(TRASH);void	err_arridx()			{	rt_raise("ARRAY: INDEX OUT OF RANGE");	}void	err_typemismatch()		SEC(TRASH);void	err_typemismatch()		{	rt_raise("TYPE MISMATCH");	}void	err_varisnotarray()		SEC(TRASH);/**	returns the code of the next commandbyte	code_peek(){	return prog_source[prog_ip];}*//**	moves the instruction pointer to the next instructionbyte	code_getnext(){	byte	v;	v = prog_source[prog_ip];	prog_ip ++;	return v;}*//**	returns the next 16bit and moves the instruction pointer to the next instructionword	code_getnext16(){	word	v;	memcpy(&v, prog_source+prog_ip, 2);	prog_ip += 2;	return v;}*//**	returns the next 32bit and moves the instruction pointer to the next instruction*/dword	code_getnext32(){	dword	v;	memcpy(&v, prog_source+prog_ip, 4);	prog_ip += 4;	return v;}/**	returns the next 64bit and moves the instruction pointer to the next instruction*/double	code_getnext64f(){	double	v;	memcpy(&v, prog_source+prog_ip, 8);	prog_ip += 8;	return v;}/**	jump to label*/void	code_jump_label(word label_id){	prog_ip = tlab[label_id].ip;}/**	jump to IPvoid	code_jump(word ip){	prog_ip = ip;}*//**	Put the node 'node' in stack (PUSH)*/void	code_push(stknode_t *node){#if defined(_UnixOS) && defined(_CHECK_STACK)	int		i;#endif	if	( prog_stack_count + 1 >= prog_stack_alloc )	{		err_stackoverflow();		return;		}	prog_stack[prog_stack_count] = *node;#if defined(_UnixOS) && defined(_CHECK_STACK)	for ( i = 0; keyword_table[i].name[0] != '\0'; i ++ )	{		if	( node->type == keyword_table[i].code )	{			printf("%3d: PUSH %s (%d)\n", prog_stack_count, keyword_table[i].name, prog_line);			break;			}		}#endif	prog_stack_count ++;}/**	Returns and deletes the topmost node from stack (POP)*/void	code_pop(stknode_t *node){#if defined(_UnixOS) && defined(_CHECK_STACK)	int		i;#endif	if	( prog_stack_count )	{		prog_stack_count --;		if	( node )			*node = prog_stack[prog_stack_count];#if defined(_UnixOS) && defined(_CHECK_STACK)		for ( i = 0; keyword_table[i].name[0] != '\0'; i ++ )	{			if	( prog_stack[prog_stack_count].type == keyword_table[i].code )	{				printf("%3d: POP %s (%d)\n", prog_stack_count, keyword_table[i].name, prog_line);				break;				}			}#endif		}	else	{		if	( node )	{			err_stackunderflow();			node->type = 0xFF;			}		}}/**	Peek the topmost node of stack*/stknode_t*	code_stackpeek(){	if	( prog_stack_count )		return &prog_stack[prog_stack_count-1];		return NULL;}/**	Returns the varptr of the next variable*	if the variable is an array returns the element ptr*/var_t	*code_getvarptr(){	var_t	*basevar_p, *var_p = NULL;	long	array_index;	basevar_p = tvar[code_getnext16()];	if	( basevar_p->type == V_ARRAY )	{		/*		*	Variable is an array		*/		if	( code_peek() != kwTYPE_LEVEL_BEGIN )			err_arrmis_lp();		else	{			code_skipnext();	// '('			array_index = getarrayidx(basevar_p);			if	( !prog_error )	{				if	( array_index < basevar_p->size )	{					var_p = (var_t*) (basevar_p->ptr + (array_index * sizeof(var_t)));					if	( code_peek() == kwTYPE_SEP )							code_skipnext();		// ','					else if	( code_peek() == kwTYPE_LEVEL_END )							code_skipnext();		// ')', ')' level					else						err_arrmis_rp();					}				else						err_arridx();				}			}		}	else	{		var_p = basevar_p;		if	( code_peek() == kwTYPE_LEVEL_BEGIN )			err_varisnotarray();		}	return var_p;}/**	returns true if the next element is a null-array i.e. v() keyword**	example:*	v()    --- true*   v(1)   --- false*/int		code_isnullarray_nc(int start){	var_t	*basevar_p;	int16	idx;	memcpy(&idx, prog_source+prog_ip+start, 2);	if	( idx < prog_varcount )	{		basevar_p = tvar[idx];		if	( basevar_p->type == V_ARRAY )	{			if	( prog_source[prog_ip+start+2] != kwTYPE_LEVEL_BEGIN )				return 1;			}		}	return 0;}int		code_isnullarray(){	if	( prog_source[prog_ip] == kwTYPE_VAR )			return code_isnullarray_nc(1);	return 0;}/**/void	setsysvar_int(int index, long value){	var_t	*var_p = tvar[index];		var_p->type = V_INT;	var_p->const_flag = 1;	var_p->i = value;}/**/void	setsysvar_num(int index, double value){	var_t	*var_p = tvar[index];		var_p->type = V_NUM;	var_p->const_flag = 1;	var_p->n = value;}/**/void	setsysvar_str(int index, const char *value){	var_t	*var_p = tvar[index];	int		l = strlen(value)+1;		if	( var_p->type == V_STR )		tmp_free(var_p->ptr);	var_p->type = V_STR;	var_p->const_flag = 1;	var_p->ptr = tmp_alloc(l);	strcpy(var_p->ptr, value);	var_p->size = l;}/**	RUN byte-code*	*	source structure:*		[word]	number_of_variables*		[word]	number_of_labels*		for each label:* 			[word]	... label-ip*		[word]	bytecode_length*		...**	brun_init(source)*	brun()*	brun_close()*/void	brun_init(byte *source){	word	i;	memcpy(&prog_varcount, source  , 2);	memcpy(&prog_labcount, source+2, 2);	if	( prog_varcount == 0 )		prog_varcount ++;	tvar = tmp_alloc(sizeof(var_t *) * prog_varcount);	for ( i = 0; i < prog_varcount; i ++ )			tvar[i] = v_new();	if	( prog_labcount == 0 )			tlab = tmp_alloc(sizeof(lab_t));	else	{		tlab = tmp_alloc(sizeof(lab_t) * prog_labcount);		for ( i = 0; i < prog_labcount; i ++ )				memcpy(&tlab[i].ip, source+(i<<1)+4, 2);		}	prog_stack_alloc = 256;	prog_stack = tmp_alloc(sizeof(stknode_t) * prog_stack_alloc);	prog_stack_count = 0;	prog_error  = 0;	prog_line   = 0;		memcpy(&data_ip, &source[(prog_labcount<<1)+4], 2);	memcpy(&prog_length, &source[(prog_labcount<<1)+6], 2);	prog_source = &source[(prog_labcount << 1) + 8];	prog_ip     = 0;	// predefined variables	setsysvar_int(SYSVAR_OSVER, os_ver);	#if defined(_PalmOS)		setsysvar_str(SYSVAR_OSNAME, "PalmOS");	#else		#if !defined(_Win32)			setsysvar_str(SYSVAR_OSNAME, "Unix");		#else			setsysvar_str(SYSVAR_OSNAME, "Win32");		#endif	#endif	setsysvar_int(SYSVAR_SBVER, SB_DWORD_VER);	setsysvar_num(SYSVAR_PI,    3.14159265358979323846);	setsysvar_int(SYSVAR_XMAX,	160);	setsysvar_int(SYSVAR_YMAX,	160);	setsysvar_int(SYSVAR_BPP,	1);	setsysvar_int(SYSVAR_TRUE,  1);	setsysvar_int(SYSVAR_FALSE, 0);	setsysvar_int(SYSVAR_LINECHART, 1);	setsysvar_int(SYSVAR_BARCHART,  2);	//	cmd_play_reset();}/**	load & compile the source file 'fileName'*/void	brun_load(char *fileName){	char		*ptr;#if defined(_PalmOS)	DmOpenRef	fp;	LocalID		lid;#endif	bc_init();	prog_file = fileName;	/*	*	compile - pass1	*/	bc_load(fileName);	/*	*	compile - pass2 & binary	*/	bytecode_h = 0;	if	( !bc_get_error() )	{		bc_pass2();		if	( !bc_get_error() )	{			bc_check_labels();			if	( !bc_get_error() )					bytecode_h = bc_createbin();			}		}	bc_close();	/*	*	run	*/	if	( bytecode_h )	{		#if defined(_PalmOS)		/*		*	PalmOS - Memory optimization		*		*	We'll free 'bytecode' memory by using a database record handle		*	Because 'bytecode' it is working as read-only we have no problems		*	using record's memory handle instead of a dynamic-RAM handle		*/		word		recIndex;		mem_t		rec_h;		char		*prevrec, *newrec;		lid = DmFindDatabase(0, (char *) "SBVM.BIN");		if	( lid )				DmDeleteDatabase(0, lid);		DmCreateDatabase(0, "SBVM.BIN", idSmBa, idDATA, 0);		lid = DmFindDatabase(0, (char *) "SBVM.BIN");		fp = DmOpenDatabase(0, lid, dmModeReadWrite);		// save bytecode_h		recIndex = dmMaxRecordIndex;		rec_h = DmNewRecord(fp, &recIndex, MemHandleSize(bytecode_h));		newrec = mem_lock(bytecode_h);		prevrec = mem_lock(rec_h);		DmWrite(prevrec, 0, newrec, MemHandleSize(bytecode_h));		mem_unlock(rec_h);		mem_unlock(bytecode_h);		DmReleaseRecord(fp, recIndex, 1);		// free bytecode_h		mem_free(bytecode_h);		bytecode_h = DmGetRecord(fp, recIndex);		bytecode_fp = fp;		bytecode_recidx = recIndex;		/*		*	Try to defrag dynamic memory		*/		MemHeapCompact(0);		#endif		ptr = mem_lock(bytecode_h);		brun_init(ptr);		#if defined(_PalmOS)		EvtWakeup();		// !@$!@#$@#!$#@#$$!		#endif		}	else		prog_error = -32;}int		brun_close(void){	word	i;	if	( bytecode_h )	{		// clean up		for ( i = 0; i < prog_varcount; i ++ )	{			v_free(tvar[i]);			tmp_free(tvar[i]);			}		tmp_free(tvar);		tmp_free(tlab);		tmp_free(prog_stack);		mem_unlock(bytecode_h);		#if defined(_PalmOS)		DmReleaseRecord(bytecode_fp, bytecode_recidx, 1);		DmRemoveRecord(bytecode_fp, bytecode_recidx);		DmCloseDatabase(bytecode_fp);		#else		mem_free(bytecode_h);		#endif		bytecode_h = 0;		}	//	if	( prog_error != -1 && prog_error != 0 )		return 1;	return 0;}/**	BREAK*/void	brun_stop(){	prog_error = -3;}/**	returns the status of executor (runing or stopped)*/										int		brun_status(){	if	( prog_error )		return BRUN_STOPPED;	return BRUN_RUNNING;}/**	BREAK - display message, too*/void	brun_break(){	if	( brun_status() == BRUN_RUNNING )	{		if	( os_graphics )				dev_settextcolor(0, 15);		dev_printf("\n\a* BREAK AT LINE %d *\n", prog_line);		}	brun_stop();}/**/void	cmd_chain(void){	var_t	var;	v_init(&var);	eval(&var);	if	( prog_error )			return;	else	{		if	( var.type != V_STR )	{			err_typemismatch();			return;			}		else	{			strcpy(fileName, var.ptr);			if	( !basFileExist(fileName) )	{				rt_raise("CHAIN: FILE '%s' DOES NOT EXIST", fileName);				v_free(&var);				return;				}			v_free(&var);			}		}	brun_close();	#if defined(_PalmOS)	dev_cls();	#endif	brun_load(fileName);}/**	RUN "program"**	For PalmOS use RUN CreatorID (i.e. run "calc")*/void	cmd_run(void){	var_t	var;	v_init(&var);	eval(&var);	if	( prog_error )			return;	else	{		if	( var.type != V_STR )	{			err_typemismatch();			return;			}		else	{			strcpy(fileName, var.ptr);			v_free(&var);			}		}//	brun_close();	if	( !dev_run(fileName) )		rt_raise("RUN \"%s\" FAILED", fileName);}/*static void	run_events(){	static dword next_check;	register dword now;	#if defined(_PalmOS)	now = TimGetTicks();	#else	now = clock();	#endif	// events	if	( now >= next_check )	{		next_check = now + evt_check_every;		switch ( dev_events(0) )		{		case	-1:			break;				// break event		case	-2:			prog_error=-2;			if	( os_graphics )					dev_settextcolor(0, 15);			dev_printf("\n\a* BREAK AT LINE %d *\n", prog_line);			break;			};		}}*//**/void	bc_loop(int isf){	byte	code, pops;	byte	trace_flag = 0;	word	next_ip;	stknode_t	node;	int		udf_level = 0;	static dword next_check;	register dword now;	/**	*	DO NOT CREATE FUNCTION-PTR-TABLE	*	function tables does not works with multiseg	*	*	For commands witch changes the IP use	*	*   case mycommand:	*		command();	*		if	( prog_error )	break;	*		continue;	*/	while ( prog_ip < prog_length )	{//		run_events();		#if defined(_PalmOS)		now = TimGetTicks();		#else		now = clock();		#endif		// events		if	( now >= next_check )	{			next_check = now + evt_check_every;			switch ( dev_events(0) )		{			case	-1:

⌨️ 快捷键说明

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