mud++0.35/etc/
mud++0.35/etc/guilds/
mud++0.35/help/propert/
mud++0.35/mudC/
mud++0.35/player/
mud++0.35/src/interface/
mud++0.35/src/os/cygwin32/
mud++0.35/src/os/win32/
mud++0.35/src/os/win32/bcppbuilder/
mud++0.35/src/osaddon/
mud++0.35/src/util/
/*
....[@@@..[@@@..............[@.................. MUD++ is a written from
....[@..[@..[@..[@..[@..[@@@@@....[@......[@.... scratch multi-user swords and
....[@..[@..[@..[@..[@..[@..[@..[@@@@@..[@@@@@.. sorcery game written in C++.
....[@......[@..[@..[@..[@..[@....[@......[@.... This server is an ongoing
....[@......[@..[@@@@@..[@@@@@.................. development project.  All 
................................................ contributions are welcome. 
....Copyright(C).1995.Melvin.Smith.............. Enjoy. 
------------------------------------------------------------------------------
Melvin Smith (aka Fusion)         msmith@hom.net
MUD++ development mailing list    mudpp@van.ml.org
------------------------------------------------------------------------------
vmrun.cc
*/

#include "config.h"
#include "string.h"
#include "io.h"
#include "memoryblock.h"
#include "vmopcodes.h"
#include "vmachine.h"
#include "asmloader.h"
#include "vmarray.h"

#define PUSH_I( x ) psobj++; psobj->type = VMT_INT; psobj->val.i = x;
#define PUSH_F( x ) psobj++; psobj->type = VMT_FLOAT; psobj->val.f = x;


void VMachine::run()
{

	int itmp,itmp2;
	float ftmp;
	const char * txt;
	vmstack otmp,otmp2;
	vmstack * ptmp;
	memorycell cell;
	VMarray * array;

// Main execution loop
while ( live )
{

// 	Cout << (int) pmem << " " << (int) low_border << " " << (int) high_border << endl;

	VM_SECURE_2( (pmem < low_border) || (pmem >= high_border ),
			"Scope borders broken." );

	cell = getCell();

	switch( cell.s.opcode )
	{

		case VMOPC_AADD:
			ASSURE_SSIZE(2);
			VM_SECURE_2( !IS_ARRAY( (psobj-1)->type ) , "non-narray" );
			((VMarray*)(psobj-1)->val.o)->add(psobj->val);
			psobj--;
			break;

		case VMOPC_ABORT:
			crit_error("Abort hit");
			break;

		case VMOPC_ADD:
			ASSURE_SSIZE( 2 );
			if ( psobj->type == VMT_INT )
			{
				psobj--;
				VM_SECURE_2( psobj->type != VMT_INT,
					 "Tried to add different types" );
				psobj->val.i += (psobj + 1)->val.i;
			}
			else
			{
				psobj--;
				VM_SECURE_2( (psobj + 1)->type != VMT_FLOAT,
					"Tried to add strange type" );
				VM_SECURE_2( psobj->type != VMT_FLOAT,
					 "Tried to add different types" );
				psobj->val.f += (psobj + 1)->val.f;
			}
			break;

		case VMOPC_ALEN:
			NEED_OSTACK( 1 );
			VM_SECURE_2( !IS_ARRAY( psobj->type ) , "non-narray" );
			psobj++;
			psobj->type = VMT_INT;
			psobj->val.i = ((VMarray*)(psobj-1)->val.o)->count();
			break;

		case VMOPC_APOP:
			ASSURE_SSIZE( 3 );
			VM_SECURE_2( !IS_ARRAY( (psobj-2)->type ) , "non-narray" );
			VM_SECURE_2( (psobj-1)->type != VMT_INT, "array can be indexed only by ints.");
			itmp = (psobj-1)->val.i;
			array = (VMarray *)(psobj-2)->val.o;
			if ( (itmp < 0) || (itmp >= array->count()) )
			{
				crit_error( "index of of bounds" );
				break;
			}
			VM_SECURE_2( IS_VMOBJ(psobj->type) && psobj->val.o &&
				!canCastTo( psobj->val.o->getVMType(), array->type),
				"wrong vmtype put into array");
			dereference_obj( array->type, array->table()[itmp].val );
			array->table()[itmp].val = psobj->val;
			array->table()[itmp].type = array->type;
			psobj--;
			break;

		case VMOPC_APUSH:
			ASSURE_SSIZE(2);
			VM_SECURE_2( !IS_ARRAY( (psobj-1)->type ) , "non-narray" );
			VM_SECURE_2( psobj->type != VMT_INT, "array can be indexed only by ints.");
			itmp = psobj->val.i;
			array = (VMarray*)(psobj-1)->val.o;
			if ( (itmp < 0) || (itmp >= array->count()) )
			{
				crit_error( (String(" index ") + itmp + " of out bounds").chars() );
				break;
			}
			*psobj = array->table()[itmp];
			psobj->val = reference_obj(psobj);
			break;

		case VMOPC_CALL:
			crit_error("CALL opcode hit - illegal outside obj file");
			break;

		case VMOPC_CAST2F:
			ASSURE_STACK1( VMT_INT );
			psobj->type = VMT_FLOAT;
			psobj->val.f = (float) psobj->val.i;
			break;

		case VMOPC_CAST2I:
			ASSURE_STACK1( VMT_FLOAT );
			psobj->type = VMT_INT;
			psobj->val.i = (s32) psobj->val.f;
			break;

		case VMOPC_CHECKCAST:
			ASSURE_SSIZE( 1 );
			VM_SECURE_2( !IS_VMOBJ(psobj->type), "Tried to checkcast non-vmobject" );
			if ( !psobj->val.o )
			{
				psobj->type = VMT_INT;
				psobj->val.i = 1;
			}
			else
			{
				if ( canCastTo( psobj->val.o->getVMType(),
						((vmtype) cell.s.u.number) ) )
					psobj->val.i = 1;
				else
					psobj->val.i = 0;

				psobj->type = VMT_INT;
			}
			break;


	   	case VMOPC_CLONE:
			ASSURE_SSIZE( 1 );
			NEED_OSTACK( 1 );
			psobj++;
			psobj->type = (psobj - 1)->type;
			psobj->val = reference_obj( psobj - 1 );
			break;

		case VMOPC_DEC:
			ASSURE_SSIZE( 1 );
			if ( psobj->type == VMT_INT )
			{
				psobj->val.i--;
			}
			else
			{
				VM_SECURE_2( psobj->type != VMT_FLOAT, "Tried to decrease non-numeric object");
				psobj->val.f--;
			}
			break;

		case VMOPC_DECL:
			ACCESS_VSTACK( cell.s.u.number );
			if ( psvar[cell.s.u.number].type == VMT_INT )
			{
				psvar[cell.s.u.number].val.i--;
			}
			else
			{
				VM_SECURE_2(psvar[cell.s.u.number].type != VMT_FLOAT, "Tried to decrease non-numeric local");
				psvar[cell.s.u.number].val.f--;
			}
			break;

		case VMOPC_DIV:
			ASSURE_SSIZE( 2 );
			if ( psobj->type == VMT_INT )
			{
				psobj--;
				VM_SECURE_2( psobj->type != VMT_INT,
					 "Tried to div different types" );
				psobj->val.i /= (psobj + 1)->val.i;
			}
			else
			{
				psobj--;
				VM_SECURE_2( (psobj + 1)->type != VMT_FLOAT,
					"Tried to div strange type" );
				VM_SECURE_2( psobj->type != VMT_FLOAT,
					 "Tried to div different types" );
				psobj->val.f /= (psobj + 1)->val.f;
			}
			break;
		
		case VMOPC_EXIT:
			exitCode = cell.s.conds;
			live = false;
			break;

		case VMOPC_FCALL:
			NEED_TSTACK();
			leave_trace();
			funID = cell.s.u.number;
			low_border = vmfun_table[funID].low_border;
			high_border = vmfun_table[funID].high_border;
			pmem = low_border;
			break;

		case VMOPC_FCMP:
			ASSURE_STACK2( VMT_FLOAT, VMT_FLOAT );
			ftmp = (psobj-1)->val.f - psobj->val.f;
			psobj -= 2;
			if ( FLAG_CONDITION( ftmp ) )
				pmem = low_border + cell.s.u.number;
			break;

		case VMOPC_FEVAL:
			ASSURE_STACK1( VMT_FLOAT );
			if ( FLAG_CONDITION( psobj->val.f ) )
				pmem = low_border + cell.s.u.number;
			psobj--;
			break;

		case VMOPC_GETFIELD:
			ASSURE_SSIZE( 1 );
			otmp = *psobj;
			psobj--;
			live = (vmtype_table[ otmp.type ].getfield) (this, otmp.val.o, cell.s.u.number);
			dereference_obj( otmp.type, otmp.val );
			if ( !live  )
				Cout << "GetField returned false";
			break;

		case VMOPC_ICALL:
			NEED_TSTACK();
			leave_trace();
			//Cout << "Calling native fun " << cell.s.u.number << endl;
			(vm_interface_table[cell.s.u.number].fun) (this);
			collect_trace();
			break;

		case VMOPC_ICMP:
			ASSURE_STACK2( VMT_INT, VMT_INT );
			itmp = (psobj-1)->val.i - psobj->val.i;
			psobj -= 2;
			if ( FLAG_CONDITION( itmp ) )
				pmem = low_border + cell.s.u.number;
			break;

		case VMOPC_IEVAL:
			ASSURE_STACK1( VMT_INT );
			if ( FLAG_CONDITION( psobj->val.i  ) )
				pmem = low_border + cell.s.u.number;
			psobj--;
			break;


	
		case VMOPC_ILOOKUPSWITCH:
			ASSURE_STACK1( VMT_INT );
			itmp = cell.s.conds;
			itmp2 = cell.s.u.number;
			for ( ; itmp > 0; itmp-- )
			{
				if ( psobj->val.i == getCell().vmint )
				{
					pmem = low_border + getCell().s.u.number;
					itmp2 = -1;
					break;
				}
				else
					pmem++;
			}

			if ( itmp2 != -1)
				pmem = low_border + itmp2;

			break;

		case VMOPC_INC:
			ASSURE_SSIZE( 1 );
			if ( psobj->type == VMT_INT )
			{
				psobj->val.i++;
			}
			else
			{
				VM_SECURE_2( psobj->type != VMT_FLOAT , "Tried to increase non-numeric object" );
				psobj->val.f++;
			}
			break;

		case VMOPC_INCL:
			ACCESS_VSTACK( cell.s.u.number );
			if (psvar[cell.s.u.number].type == VMT_INT )
			{
				psvar[cell.s.u.number].val.i++;
			}
			else
			{
				VM_SECURE_2( psvar[cell.s.u.number].type != VMT_FLOAT, "Tried to increase non-numeric local");
				psvar[cell.s.u.number].val.f++;
			}
			break;

		case VMOPC_INITL:
			NEED_VSTACK( cell.s.u.number );
			// maybe memset ?
			otmp.type = VMT_NULL;
			otmp.val.o = NULL;
			for ( ; cell.s.u.number > 0 ; cell.s.u.number-- )
			{
				psvar[var_count] = otmp;
				var_count++;
			}
			break;
			
		case VMOPC_INITP:
			ASSURE_SSIZE( cell.s.u.number );
			NEED_VSTACK( cell.s.u.number );

			for ( ; cell.s.u.number > 0 ; cell.s.u.number-- )
			{
				psvar[var_count] = *psobj;
				var_count++;
				psobj--;
			}
			break;


		case VMOPC_ISNULL:
			ASSURE_SSIZE( 1 );
			VM_SECURE_2( !IS_VMOBJ( psobj->type ), "Non VMObject compared to null" );
			if ( BOOL_FLAG_CONDITION( !psobj->val.o ) )
				pmem = low_border + cell.s.u.number;
			psobj--;
			break;

		case VMOPC_ITABLESWITCH:
			ASSURE_STACK1( VMT_INT );
			itmp2 = cell.s.u.number;	// default jump
			if ( (psobj->val.i < (itmp = getCell().vmint) ) || 
				 (psobj->val.i > getCell().vmint) )
			{
				pmem = low_border + itmp2;	// jump to default
				break;
			}
			pmem += psobj->val.i - itmp;	// value - minimal
			pmem = low_border + getCell().s.u.number;
			break;

		case VMOPC_JMP:
			pmem = low_border + cell.s.u.number;
			break;

		case VMOPC_LICMP:
			ASSURE_STACK1( VMT_INT );
			ACCESS_VSTACK( cell.s.u.number );
			// vmstack == int ??
			itmp = psvar[cell.s.u.number].val.i - psobj->val.i;
			psobj--;
			if ( FLAG_CONDITION( itmp ) )
				pmem = low_border + getCell().s.u.number;
			else
				pmem++;
			break;

		case VMOPC_LIEVAL:
			ACCESS_VSTACK( cell.s.u.number );
			// vstack == int ???
			itmp = psvar[cell.s.u.number].val.i;
			if ( FLAG_CONDITION( itmp ) )
				pmem = low_border + getCell().s.u.number;
			else
				pmem++;

			break;



		case VMOPC_MOD:
			ASSURE_STACK2( VMT_INT, VMT_INT );
			psobj--;
			psobj->val.i %= (psobj + 1)->val.i;
			break;

		case VMOPC_MOVC:
			ACCESS_VSTACK( cell.s.u.number );
			dereference_obj( psvar + cell.s.u.number );
			psvar[cell.s.u.number] = vmconstant_table[getCell().s.u.number];
			psvar[cell.s.u.number].val = reference_obj(psvar + cell.s.u.number);
			break;

		case VMOPC_MOVF:
			ACCESS_VSTACK( cell.s.u.number );
			dereference_obj( psvar + cell.s.u.number );
			psvar[cell.s.u.number].type = VMT_FLOAT;
			psvar[cell.s.u.number].val.f = getCell().vmfloat;
			break;

		case VMOPC_MOVI:
			ACCESS_VSTACK( cell.s.u.number );
			dereference_obj( psvar + cell.s.u.number );
			psvar[cell.s.u.number].type = VMT_INT;
			psvar[cell.s.u.number].val.i = getCell().vmint;
			break;

		case VMOPC_MPOP:
			ASSURE_SSIZE( cell.s.conds );
			for ( ;cell.s.conds > 0; cell.s.conds--)
			{
				dereference_obj( psobj );
				psobj--;
			}
			break;

		case VMOPC_MUL:
			ASSURE_SSIZE( 2 );
			if ( psobj->type == VMT_INT )
			{
				psobj--;
				VM_SECURE_2( psobj->type != VMT_INT,
					 "Tried to mul different types" );
				psobj->val.i *= (psobj + 1)->val.i;
			}
			else
			{
				psobj--;
				VM_SECURE_2( (psobj + 1)->type != VMT_FLOAT,
					"Tried to mul strange type" );
				VM_SECURE_2( psobj->type != VMT_FLOAT,
					 "Tried to mul different types" );
				psobj->val.f *= (psobj + 1)->val.f;
			}
			break;

		case VMOPC_NOP:
			break;

		case VMOPC_OCMP:
			ASSURE_SSIZE( 2 );
			VM_SECURE_2( !IS_VMOBJ(psobj->type),
				"Tried to ocmp non-vmobject" );
			VM_SECURE_2( !IS_VMOBJ((psobj-1)->type),
				"Tried to ocmp non-vmobject" );
			if ( BOOL_FLAG_CONDITION( (psobj - 1)->val.o == psobj->val.o) )
				pmem = low_border + cell.s.u.number;
			psobj -= 2;
			break;

		case VMOPC_POP:
			ASSURE_SSIZE( 1 );
			dereference_obj( psobj );
			psobj--;
			break;

		case VMOPC_POPL:
			ACCESS_VSTACK( cell.s.u.number );
			// Do I need to deref and then ref ? - for now just copy
			ptmp = (psvar + cell.s.u.number);
			ptmp->type = psobj->type;
			ptmp->val = psobj->val;
			psobj--;
			break;

		case VMOPC_POPSTAT:
			itmp = cell.s.u.number;
			dereference_obj( &vmstatvar_table[itmp] );
			vmstatvar_table[itmp] = *psobj;
			psobj--;
			break;

		case VMOPC_PUSHC:
			NEED_OSTACK( 1 );
			psobj++;
			*psobj = vmconstant_table[cell.s.u.number];
			psobj->val = reference_obj(psobj);
			break;


		case VMOPC_PUSHF:
			NEED_OSTACK( 1 );
			PUSH_F( getCell().vmfloat );
			break;

		case VMOPC_PUSHFZ:
			NEED_OSTACK( 1 );
			PUSH_F( 0 );
			break;

		case VMOPC_PUSHI:
			NEED_OSTACK( 1 );
			PUSH_I( getCell().vmint );
			break;

		case VMOPC_PUSHIZ:
			NEED_OSTACK( 1 );
			PUSH_I( 0 );
			break;

		case VMOPC_PUSHL:
			NEED_OSTACK( 1 );
			ACCESS_VSTACK( cell.s.u.number );
			psobj++;
			ptmp = (psvar + cell.s.u.number);
			psobj->type = ptmp->type;
			psobj->val = reference_obj( ptmp );
			break;

		case VMOPC_PUSHSTAT:
			NEED_OSTACK( 1 );
			itmp = cell.s.u.number;
			psobj++;
			*psobj = vmstatvar_table[itmp];
			psobj->val = reference_obj( psobj );
			break;

		case VMOPC_PUSHTHIS:
			NEED_OSTACK( 1 );
			// this is always variable number 0
			psobj++;
			psobj->type = psvar->type;
			psobj->val = reference_obj(psvar);
			break;

		case VMOPC_RCALL:
			crit_error("Opcode not longer supported");
			break;

		// obsolete
		case VMOPC_REDUCEL:
			crit_error("Opcode not longer supported");
			break;

		case VMOPC_RET:
			collect_trace();
			break;

		case VMOPC_SCHARAT:
			ASSURE_STACK2( VMT_STRING, VMT_INT );
			itmp = psobj->val.i;
			psobj--;
			if ( itmp < psobj->val.s->len() )
				itmp = (psobj->val.s->chars())[itmp];
			else
				itmp = 0;
			delete psobj->val.s;
			psobj->type = VMT_INT;
			psobj->val.i = itmp;
			break;

		case VMOPC_SCHARATL:
			ASSURE_STACK1( VMT_INT );
			ACCESS_VSTACKT( cell.s.u.number, VMT_STRING );
			itmp = psobj->val.i;
			if ( itmp < psvar[cell.s.u.number].val.s->len() )
				itmp = (psvar[cell.s.u.number].val.s->chars())[itmp];
			else
				itmp = 0;
			psobj->val.i = itmp;
			break;

		case VMOPC_SCMP:
			ASSURE_STACK2( VMT_STRING, VMT_STRING );
			if ( BOOL_FLAG_CONDITION( *(psobj->val.s) == *((psobj-1)->val.s) ) )
				pmem = low_border + cell.s.u.number;
			delete psobj->val.s;
			psobj--;
			delete psobj->val.s;
			psobj--;
			break;
 
		case VMOPC_SCONCAT:
			ASSURE_STACK2( VMT_STRING, VMT_STRING );
			*(psobj-1)->val.s += *psobj->val.s;
			delete psobj->val.s;
			psobj--;
			break;

		case VMOPC_SETFIELD:
			ASSURE_SSIZE( 2 );
			otmp2 = *psobj;
			psobj--;
			otmp = *psobj;
			psobj--;
			txt = (vmtype_table[ otmp2.type ].setfield) 
				(this, otmp2.val.o, cell.s.u.number, otmp.val);
			dereference_obj( otmp.type, otmp.val );
			dereference_obj( otmp2.type, otmp2.val );
			if ( txt )
				crit_error(txt);
			break;


		case VMOPC_SFLOATCAT:
			ASSURE_STACK2( VMT_STRING, VMT_FLOAT );
			itmp = (int) psobj->val.f;
			psobj--;
			*(psobj->val.s) += itmp;
			break;

		case VMOPC_SGETARG:
			NEED_OSTACK( 1 );
			psobj++;
			psobj->type = VMT_STRING;
			// memory leak ?
			psobj->val.s = new String( current_args->getArg() );
			break;

		case VMOPC_SGETARGREST:
			NEED_OSTACK( 1 );
			psobj++;
			psobj->type = VMT_STRING;
			// memory leak ?
			psobj->val.s = new String( current_args->getArgRest() );
			break;

		case VMOPC_SINTCAT:
			ASSURE_STACK2( VMT_STRING, VMT_INT );
			itmp = psobj->val.i;
			psobj--;
			*(psobj->val.s) += itmp;
			break;

		case VMOPC_SISEMPTY:
			ASSURE_STACK1( VMT_STRING );
			if ( BOOL_FLAG_CONDITION( !(bool)*(psobj->val.s) ) )
				pmem = low_border + cell.s.u.number;
			delete psobj->val.s;
			psobj--;
			break;

		case VMOPC_SISNUMBER:
			ASSURE_STACK1( VMT_STRING );
			if ( BOOL_FLAG_CONDITION( psobj->val.s->isNumber() ) )
				pmem = low_border + cell.s.u.number;
			delete psobj->val.s;
			psobj--;
			break;

		case VMOPC_SLEEP:
			ASSURE_STACK1( VMT_FLOAT );
			putToSleep( psobj->val.f );
			psobj--;
			return;

		case VMOPC_SLOOKUPSWITCH:
			ASSURE_STACK1( VMT_STRING );
			itmp = cell.s.conds;
			itmp2 = cell.s.u.number;
			for ( ; itmp > 0; itmp-- )
			{
				if ( *(psobj->val.s) == *(vmconstant_table[getCell().s.u.number].val.s) )
				{
					pmem = low_border + getCell().s.u.number;
					itmp2 = -1;
					break;
				}
				else
					pmem++;
			}
			if ( itmp2 != -1)
				pmem = low_border + itmp2;

			break;

		case VMOPC_SPUSHEMPTY:
			NEED_OSTACK( 1 );
			psobj++;
			psobj->type = VMT_STRING;
			psobj->val.s = new String();
			break;

		case VMOPC_SSTARTARGS:
			ASSURE_STACK1( VMT_STRING );
			psobj->val.s->startArgs();
			if ( current_args )
				delete current_args;
			current_args = psobj->val.s;
			psobj--;
			break;

		case VMOPC_STOINT:
			ASSURE_STACK1( VMT_STRING );
			itmp = psobj->val.s->asInt();
			delete psobj->val.s;
			psobj->val.i = itmp;
			psobj->type = VMT_INT;
			break;

		case VMOPC_SUB:
			ASSURE_SSIZE( 2 );
			if ( psobj->type == VMT_INT )
			{
				psobj--;
				VM_SECURE_2( psobj->type != VMT_INT,
					 "Tried to sub different types" );
				psobj->val.i -= (psobj + 1)->val.i;
			}
			else
			{
				psobj--;
				VM_SECURE_2( (psobj + 1)->type != VMT_FLOAT,
					"Tried to sub strange type" );
				VM_SECURE_2( psobj->type != VMT_FLOAT,
					 "Tried to sub different types" );
				psobj->val.f -= (psobj + 1)->val.f;
			}
			break;

	   	case VMOPC_SWAP:
			ASSURE_SSIZE( 2 );
			otmp = *psobj;
			*psobj = *(psobj - 1);
			*(psobj-1) = otmp;
			break;

		case VMOPC_UPCAST:
			ASSURE_SSIZE(1);
			VM_SECURE_2( !IS_VMOBJ(psobj->type), "Tried to upcast non-vmobject" );
			if ( !psobj->val.o )
			{
				psobj->type = (vmtype) cell.s.u.number;
			}
			else
			{
				otmp.type = psobj->val.o->getVMType();
				if ( canCastTo( otmp.type, ((vmtype) cell.s.u.number) ) )
					psobj->type = (vmtype) cell.s.u.number;
				else
					crit_error("Illegal upcast");
			}
			break;

		default:
			char buf[100];
			sprintf(buf, "Unrecognized opcode %d." , cell.s.opcode );
			crit_error( buf );
			break;
	}


}
 
 	// dereference objects on stack and variable stack
	itmp = ( psobj - oStack );

//	Cout << itmp << " objects on oStack"<<endl;

	for ( ; itmp > 0; itmp--, psobj--)
	{
		dereference_obj(psobj);
	}

	itmp = ( psvar + var_count - vStack );
//	Cout << itmp << " objects on vStack"<<endl;

	for ( itmp--; itmp >=0; itmp-- )
	{
//		Cout << "Dereferencing ...";
		dereference_obj( &vStack[itmp] );
//		Cout << "done" <<endl;
	}
	
	if ( current_args )
		delete current_args;
	current_args = NULL;

	Cout << "VMachine exited with code " << (int) exitCode << endl;
	return;
}