SBSPSS/source/script/script.cpp
2001-01-23 21:05:48 +00:00

473 lines
9.7 KiB
C++

/*=========================================================================
script.cpp
Author: PKG
Created:
Project: Spongebob
Purpose:
Copyright (c) 2000 Climax Development Ltd
===========================================================================*/
/*----------------------------------------------------------------------
Includes
-------- */
#include "script\script.h"
#ifndef __SCRIPT_FUNCTION_H__
#include "script\function.h"
#endif
#ifndef __SYSTEM_DBG_H__
#include "system\dbg.h"
#endif
#ifndef __MEMORY_HEADER__
#include "mem\memory.h"
#endif
/* Std Lib
------- */
/* Data
---- */
/*----------------------------------------------------------------------
Tyepdefs && Defines
------------------- */
//#define FULL_CODE_OUTPUT
//#define SHOW_RUN_COUNT
/*----------------------------------------------------------------------
Structure defintions
-------------------- */
/*----------------------------------------------------------------------
Function Prototypes
------------------- */
/*----------------------------------------------------------------------
Vars
---- */
signed short CScript::s_globalVars[NUM_GLOBAL_VARS]=
{
0, // LIVES
};
// Buffer for passing arguments to functions
unsigned short CScript::s_argBuffer[MAX_FUNCTION_ARGS];
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
void CScript::initialise(FileEquate _fe)
{
int i;
m_code=(unsigned short*)CFileIO::loadFile(_fe);
m_stack=(unsigned short*)MemAlloc(sizeof(unsigned short)*STACK_SIZE,"ScriptStack");
reset();
for(i=0;i<NUM_LOCAL_VARS;i++)
{
m_localVars[i]=0;
}
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
void CScript::dump()
{
MemFree(m_stack);
MemFree(m_code);
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
void CScript::run()
{
#ifdef SHOW_RUN_COUNT
int run=0;
#endif
if(m_state<=RUNNING)
{
m_state=RUNNING;
do
{
executeNextInstruction();
#ifdef SHOW_RUN_COUNT
run++;
#endif
}
while(m_state==RUNNING);
}
#ifdef SHOW_RUN_COUNT
if(run)
{
PAUL_DBGMSG("ran %d instructions",run);
}
#endif
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
void CScript::reset()
{
m_pc=0;
m_sp=0;
m_state=RESET;
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
int CScript::isFinished()
{
return !(m_state<=RUNNING);
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
void CScript::executeNextInstruction()
{
unsigned short instruction;
signed short val1,val2,val3;
int i;
#ifdef FULL_CODE_OUTPUT
PAUL_DBGMSG("pc:0x%04d sp:%03d",m_pc*2,m_sp);
#endif
instruction=readNextInstruction();
switch(instruction)
{
case OP_NOP:
#ifdef FULL_CODE_OUTPUT
PAUL_DBGMSG("NOP");
#endif
break;
case OP_STOP: //
PAUL_DBGMSG("STOP");
if(m_sp==0)
{
m_state=STOPPED;
}
else
{
PAUL_DBGMSG("!STACK NOT EMPTY!");
m_state=STOPPED_STACK_NOT_EMPTY;
}
break;
case OP_PAUSE: //
#ifdef FULL_CODE_OUTPUT
PAUL_DBGMSG("PAUSE");
#endif
m_state=PAUSED;
break;
case OP_PUSHVALUE: // value
val1=readNextInstruction();
#ifdef FULL_CODE_OUTPUT
PAUL_DBGMSG("PUSHVALUE %d",val1);
#endif
push(val1);
break;
case OP_PUSHVARVALUE: // varidx
val1=readNextInstruction();
val2=getVar(val1);
#ifdef FULL_CODE_OUTPUT
PAUL_DBGMSG("PUSHVARVALUE $%d ( %d )",val1,val2);
#endif
push(val2);
break;
case OP_POP: // value
val1=pop();
#ifdef FULL_CODE_OUTPUT
PAUL_DBGMSG("POP %d",val1);
#endif
break;
case OP_JMP: // jump
val1=pop();
#ifdef FULL_CODE_OUTPUT
PAUL_DBGMSG("JMP %d",val1);
#endif
jump(val1);
break;
case OP_JMPF: // jump, value
val1=pop();
val2=pop();
#ifdef FULL_CODE_OUTPUT
PAUL_DBGMSG("JMPF %d,%d",val1,val2);
#endif
if(val2==0)jump(val1);
break;
case OP_JMPT: // jump, value
val1=pop();
val2=pop();
#ifdef FULL_CODE_OUTPUT
PAUL_DBGMSG("JMPT %d,%d",val1,val2);
#endif
if(val2!=0)jump(val1);
break;
case OP_IS_EQUAL_VALUE: // value, value pushes result ( 0 or 1 ) to stack
val1=pop();
val2=pop();
#ifdef FULL_CODE_OUTPUT
PAUL_DBGMSG("IS_EQUAL_VALUE %d,%d",val1,val2);
#endif
push(val1==val2);
break;
case OP_IS_NOTEQUAL_VALUE: // value, value pushes result ( 0 or 1 ) to stack
val1=pop();
val2=pop();
#ifdef FULL_CODE_OUTPUT
PAUL_DBGMSG("IS_NOTEQUAL_VALUE %d,%d",val1,val2);
#endif
push(val1!=val2);
break;
case OP_IS_LESSTHAN_VALUE: // value, value pushes result ( 0 or 1 ) to stack
val1=pop();
val2=pop();
#ifdef FULL_CODE_OUTPUT
PAUL_DBGMSG("OP_IS_LESSTHAN_VALUE %d,%d",val1,val2);
#endif
push(val1<val2);
break;
case OP_IS_GREATERTHAN_VALUE:// value, value pushes result ( 0 or 1 ) to stack
val1=pop();
val2=pop();
#ifdef FULL_CODE_OUTPUT
PAUL_DBGMSG("OP_IS_GREATERTHAN_VALUE %d,%d",val1,val2);
#endif
push(val1>val2);
break;
case OP_ASSIGN: // varidx, value
val1=pop();
val2=pop();
#ifdef FULL_CODE_OUTPUT
PAUL_DBGMSG("$%d=%d",val1,val2);
#endif
setVar(val1,val2);
break;
case OP_ADD: // value, value pushes result to stack
val1=pop();
val2=pop();
#ifdef FULL_CODE_OUTPUT
PAUL_DBGMSG("ADD %d,%d",val1,val2);
#endif
push(val1+val2);
break;
case OP_MULTIPLY: // value, value pushes result to stack
val1=pop();
val2=pop();
#ifdef FULL_CODE_OUTPUT
PAUL_DBGMSG("MULTIPLY %d,%d",val1,val2);
#endif
push(val1*val2);
break;
case OP_DIVIDE: // value, value pushes result to stack
val1=pop();
val2=pop();
#ifdef FULL_CODE_OUTPUT
PAUL_DBGMSG("DIVIDE %d,%d",val1,val2);
#endif
if(val2==0)
{
SYSTEM_DBGMSG("[SCRIPT] DIVIDE BY ZERO @%d",m_pc);
m_state=CRASHED_DIVIDE_BY_ZERO;
}
else
{
push(val1/val2);
}
break;
case OP_NEG: // value pushes result to stack
val1=pop();
#ifdef FULL_CODE_OUTPUT
PAUL_DBGMSG("NEG %d",val1);
#endif
push(-val1);
break;
case OP_PRINT: // value
val1=pop();
PAUL_DBGMSG("PRINT %d",val1);
break;
case OP_CALL_FUNCTION: // functionnumber, argcount args pushes return value to stack
val1=readNextInstruction();
val2=readNextInstruction();
#ifdef FULL_CODE_OUTPUT
PAUL_DBGMSG("CALL_FUNCTION %d ( %d args )",val1,val2);
#endif
ASSERT(val2<MAX_FUNCTION_ARGS); // Too many args.. just increase the #define to fix this
for(i=0;i<val2;i++)
{
s_argBuffer[val2-i-1]=pop();
}
val3=callFunction(val1,val2,s_argBuffer);
#ifdef FULL_CODE_OUTPUT
PAUL_DBGMSG("( return value is %d )",val3);
#endif
push(val3);
break;
default:
SYSTEM_DBGMSG("[SCRIPT] ILLEGAL OPCODE@%d ( %d )",m_pc,instruction);
m_state=CRASHED_ILLEGAL_OPCODE;
break;
}
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
unsigned short CScript::readNextInstruction()
{
return m_code[m_pc++];
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
void CScript::jump(signed short _distance)
{
m_pc+=_distance;
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
void CScript::push(unsigned short _data)
{
ASSERT(m_sp<=STACK_SIZE-1); // Stack overflow about to occur :(
m_stack[m_sp++]=_data;
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
unsigned short CScript::pop()
{
ASSERT(m_sp>=1); // Stack underflow about to occur :(
return(m_stack[--m_sp]);
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
void CScript::setVar(int _varIdx,signed short _value)
{
ASSERT(_varIdx>=0&&_varIdx<=NUM_GLOBAL_VARS+NUM_LOCAL_VARS-1);
if(_varIdx<NUM_GLOBAL_VARS)
{
ASSERT(0); // Need to update global vars.. (PKG)
s_globalVars[_varIdx]=_value;
}
else if(_varIdx<NUM_GLOBAL_VARS+NUM_LOCAL_VARS)
{
m_localVars[_varIdx-NUM_GLOBAL_VARS]=_value;
}
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
signed short CScript::getVar(int _varIdx)
{
ASSERT(_varIdx>=0&&_varIdx<=NUM_GLOBAL_VARS+NUM_LOCAL_VARS-1);
int ret=0;
if(_varIdx<NUM_GLOBAL_VARS)
{
ASSERT(0); // Need to read global vars.. (PKG)
ret=s_globalVars[_varIdx];
}
else if(_varIdx<NUM_GLOBAL_VARS+NUM_LOCAL_VARS)
{
ret=m_localVars[_varIdx-NUM_GLOBAL_VARS];
}
return ret;
}
/*===========================================================================
end */