2007-01-15 12:09:25 -08:00
/*
This file is part of Warzone 2100.
Copyright ( C ) 1999 - 2004 Eidos Interactive
Copyright ( C ) 2005 - 2007 Warzone Resurrection Project
Warzone 2100 is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
Warzone 2100 is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with Warzone 2100 ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2007-06-28 10:47:08 -07:00
/*
* Interp . c
*
* Execute the compiled version of a script
*
*/
/* Control the execution trace printf's */
# define DEBUG_GROUP0
2006-06-02 12:34:58 -07:00
# include "lib/framework/frame.h"
2007-06-28 10:47:08 -07:00
# include "interp.h"
# include "stack.h"
# include "codeprint.h"
# include "script.h"
2006-08-22 07:28:49 -07:00
# include "event.h" //needed for eventGetEventID()
2007-06-28 10:47:08 -07:00
// the maximum number of instructions to execute before assuming
// an infinite loop
2007-05-05 08:28:21 -07:00
# define INTERP_MAXINSTRUCTIONS 250000
2007-03-31 09:03:21 -07:00
# define MAX_FUNC_CALLS 300
static INTERP_VAL * varEnvironment [ MAX_FUNC_CALLS ] ; //environments for local variables of events/functions
2007-06-28 10:47:08 -07:00
2006-09-19 09:30:50 -07:00
typedef struct
{
UDWORD CallerIndex ;
2006-11-16 06:30:29 -08:00
INTERP_VAL * ReturnAddress ;
2006-09-19 09:30:50 -07:00
} ReturnAddressStack_t ;
/**
* Reset the return address stack
*/
static inline void retStackReset ( void ) ;
/**
* Check whether the return address stack is empty
*
* \ return True when empty , false otherwise
*/
static inline BOOL retStackIsEmpty ( void ) ;
2006-08-19 06:26:11 -07:00
2006-09-19 09:30:50 -07:00
/**
* Check whether the return address stack is full
*
* \ return True when full , false otherwise
*/
static inline BOOL retStackIsFull ( void ) ;
/**
* Push a new address / event pair on the return address stack
*
* \ param CallerIndex Index of the calling function
* \ param ReturnAddress Address to return to
* \ return False on failure ( stack full )
*/
2006-11-16 06:30:29 -08:00
static BOOL retStackPush ( UDWORD CallerIndex , INTERP_VAL * ReturnAddress ) ;
2006-09-19 09:30:50 -07:00
/**
* Pop an address / event pair from the return address stack
*
* \ param CallerIndex Index of the calling function
* \ param ReturnAddress Address to return to
* \ return False on failure ( stack empty )
*/
2006-11-16 06:30:29 -08:00
static BOOL retStackPop ( UDWORD * CallerIndex , INTERP_VAL * * ReturnAddress ) ;
2006-08-19 06:26:11 -07:00
2007-03-31 09:03:21 -07:00
/* Creates a new local var environment for a new function call */
static inline void createVarEnvironment ( SCRIPT_CONTEXT * psContext , UDWORD eventIndex ) ;
/* Destroy all created variable environments */
static void cleanupVarEnvironments ( void ) ;
2007-04-01 09:22:01 -07:00
static inline void destroyVarEnvironment ( SCRIPT_CONTEXT * psContext , UDWORD envIndex , UDWORD eventIndex ) ;
2007-03-31 09:03:21 -07:00
2007-06-28 10:47:08 -07:00
/* The size of each opcode */
SDWORD aOpSize [ ] =
{
2 , // OP_PUSH | type, value
2 , // OP_PUSHREF | type, value
1 , // OP_POP
1 , // OP_PUSHGLOBAL | var_num
1 , // OP_POPGLOBAL | var_num
1 , // OP_PUSHARRAYGLOBAL | array_dimensions | array_base
1 , // OP_POPARRAYGLOBAL | array_dimensions | array_base
2006-09-19 09:30:50 -07:00
2 , // OP_CALL | func_pointer
2 , // OP_VARCALL | func_pointer
2007-06-28 10:47:08 -07:00
1 , // OP_JUMP | offset
1 , // OP_JUMPTRUE | offset
1 , // OP_JUMPFALSE | offset
1 , // OP_BINARYOP | secondary op
1 , // OP_UNARYOP | secondary op
1 , // OP_EXIT
1 , // OP_PAUSE
2006-09-19 09:30:50 -07:00
- 1 , // OP_ADD
- 1 , // OP_SUB
- 1 , // OP_MUL
- 1 , // OP_DIV
- 1 , // OP_NEG
2006-12-02 15:27:00 -08:00
- 1 , // OP_INC
- 1 , // OP_DEC
2006-09-19 09:30:50 -07:00
- 1 , // OP_AND
- 1 , // OP_OR
- 1 , // OP_NOT
2006-11-16 06:30:29 -08:00
- 1 , // OP_CONC
2006-09-19 09:30:50 -07:00
- 1 , // OP_EQUAL
- 1 , // OP_NOTEQUAL
- 1 , // OP_GREATEREQUAL
- 1 , // OP_LESSEQUAL
- 1 , // OP_GREATER
- 1 , // OP_LESS
2 , // OP_FUNC | func_pointer
1 , // OP_POPLOCAL
1 , // OP_PUSHLOCAL
2006-11-16 06:30:29 -08:00
2006-09-19 09:30:50 -07:00
2 , // OP_PUSHLOCALREF
2006-11-16 06:30:29 -08:00
1 , //OP_TO_FLOAT
1 , //OP_TO_INT
2007-06-28 10:47:08 -07:00
} ;
/* The type equivalence table */
2008-03-24 13:57:07 -07:00
static TYPE_EQUIV * asInterpTypeEquiv = NULL ;
2007-06-28 10:47:08 -07:00
// whether the interpreter is running
2008-03-24 09:51:17 -07:00
static BOOL bInterpRunning = false ;
2007-06-28 10:47:08 -07:00
/* Whether to output trace information */
2008-03-24 15:53:09 -07:00
static BOOL interpTrace = false ;
2007-02-14 10:29:26 -08:00
static SCRIPT_CODE * psCurProg = NULL ;
2008-03-24 09:51:17 -07:00
static BOOL bCurCallerIsEvent = false ;
2007-06-28 10:47:08 -07:00
/* Print out trace info if tracing is turned on */
2008-03-24 09:51:17 -07:00
# define TRCPRINTF(...) do { if (interpTrace) { fprintf( stderr, __VA_ARGS__ ); } } while (false)
2007-06-28 10:47:08 -07:00
# define TRCPRINTVAL(x) \
if ( interpTrace ) \
cpPrintVal ( x )
2008-03-25 17:45:03 -07:00
# define TRCPRINTOPCODE(x) \
2007-06-28 10:47:08 -07:00
if ( interpTrace ) \
2008-03-25 17:45:03 -07:00
debug ( LOG_NEVER , " %s " , interpOpcodeToString ( x ) )
2007-06-28 10:47:08 -07:00
# define TRCPRINTSTACKTOP() \
if ( interpTrace ) \
stackPrintTop ( )
# define TRCPRINTFUNC(x) \
if ( interpTrace ) \
2008-03-25 17:45:03 -07:00
debug ( LOG_NEVER , " %s " , interpFunctionToString ( x ) )
2007-06-28 10:47:08 -07:00
# define TRCPRINTVARFUNC(x, data) \
if ( interpTrace ) \
cpPrintVarFunc ( x , data )
2008-03-24 09:51:17 -07:00
// true if the interpreter is currently running
2007-06-28 10:47:08 -07:00
BOOL interpProcessorActive ( void )
{
return bInterpRunning ;
}
/* Find the value store for a global variable */
2006-10-31 12:22:01 -08:00
static inline INTERP_VAL * interpGetVarData ( VAL_CHUNK * psGlobals , UDWORD index )
2007-06-28 10:47:08 -07:00
{
VAL_CHUNK * psChunk ;
psChunk = psGlobals ;
while ( index > = CONTEXT_VALS )
{
index - = CONTEXT_VALS ;
psChunk = psChunk - > psNext ;
}
return psChunk - > asVals + index ;
}
// get the array data for an array operation
2006-11-16 06:30:29 -08:00
static BOOL interpGetArrayVarData ( INTERP_VAL * * pip , VAL_CHUNK * psGlobals , SCRIPT_CODE * psProg , INTERP_VAL * * ppsVal )
2007-06-28 10:47:08 -07:00
{
SDWORD i , dimensions , vals [ VAR_MAX_DIMENSIONS ] ;
UBYTE * elements ; //[VAR_MAX_DIMENSIONS]
SDWORD size , val ; //, elementDWords;
// UBYTE *pElem;
2006-11-16 06:30:29 -08:00
INTERP_VAL * InstrPointer = * pip ;
2007-06-28 10:47:08 -07:00
UDWORD base , index ;
// get the base index of the array
2006-11-16 06:30:29 -08:00
base = InstrPointer - > v . ival & ARRAY_BASE_MASK ;
2007-06-28 10:47:08 -07:00
// get the number of dimensions
2006-11-16 06:30:29 -08:00
dimensions = ( InstrPointer - > v . ival & ARRAY_DIMENSION_MASK ) > > ARRAY_DIMENSION_SHIFT ;
2007-06-28 10:47:08 -07:00
if ( base > = psProg - > numArrays )
{
2007-08-13 03:35:18 -07:00
debug ( LOG_ERROR ,
2006-08-23 05:58:48 -07:00
" interpGetArrayVarData: array base index out of range " ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
if ( dimensions ! = psProg - > psArrayInfo [ base ] . dimensions )
{
2007-08-13 03:35:18 -07:00
debug ( LOG_ERROR ,
2006-08-23 05:58:48 -07:00
" interpGetArrayVarData: dimensions do not match " ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
// get the number of elements for each dimension
elements = psProg - > psArrayInfo [ base ] . elements ;
// calculate the index of the array element
size = 1 ;
index = 0 ;
for ( i = dimensions - 1 ; i > = 0 ; i - = 1 )
{
if ( ! stackPopParams ( 1 , VAL_INT , & val ) )
{
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
if ( ( val < 0 ) | | ( val > = elements [ i ] ) )
{
2007-08-13 03:35:18 -07:00
debug ( LOG_ERROR , " interpGetArrayVarData: Array index for dimension %d out of range (passed index = %d, max index = %d) " , i , val , elements [ i ] ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
index + = val * size ;
size * = psProg - > psArrayInfo [ base ] . elements [ i ] ;
vals [ i ] = val ;
}
// print out the debug trace
if ( interpTrace )
{
2006-08-22 07:28:49 -07:00
debug ( LOG_NEVER , " %d-> " , base ) ;
2007-06-28 10:47:08 -07:00
for ( i = 0 ; i < dimensions ; i + = 1 )
{
2006-08-22 07:28:49 -07:00
debug ( LOG_NEVER , " [%d/%d] " , vals [ i ] , elements [ i ] ) ;
2007-06-28 10:47:08 -07:00
}
2006-08-22 07:28:49 -07:00
debug ( LOG_NEVER , " (%d) " , index ) ;
2007-06-28 10:47:08 -07:00
}
// check the index is valid
if ( index > psProg - > arraySize )
{
2007-08-13 03:35:18 -07:00
debug ( LOG_ERROR , " interpGetArrayVarData: Array indexes out of variable space " ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
// get the variable data
* ppsVal = interpGetVarData ( psGlobals , psProg - > psArrayInfo [ base ] . base + index ) ;
2006-11-16 06:30:29 -08:00
// update the instruction pointer
2007-06-28 10:47:08 -07:00
* pip + = 1 ; // + elementDWords;
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
// Initialise the interpreter
BOOL interpInitialise ( void )
{
asInterpTypeEquiv = NULL ;
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
/* Run a compiled script */
BOOL interpRunScript ( SCRIPT_CONTEXT * psContext , INTERP_RUNTYPE runType , UDWORD index , UDWORD offset )
{
2007-03-15 16:17:09 -07:00
UDWORD data ;
2006-11-16 06:30:29 -08:00
OPCODE opcode ;
2007-02-10 07:23:47 -08:00
INTERP_VAL sVal , * psVar , * InstrPointer ;
VAL_CHUNK * psGlobals ;
UDWORD numGlobals = 0 ;
2006-11-16 06:30:29 -08:00
INTERP_VAL * pCodeStart , * pCodeEnd , * pCodeBase ;
2006-11-06 13:58:13 -08:00
SCRIPT_FUNC scriptFunc = 0 ;
SCRIPT_VARFUNC scriptVarFunc = 0 ;
2007-06-28 10:47:08 -07:00
SCRIPT_CODE * psProg ;
SDWORD instructionCount = 0 ;
2007-02-10 07:23:47 -08:00
UDWORD CurEvent = 0 ;
2008-03-24 09:51:17 -07:00
BOOL bStop = false , bEvent = false ;
2007-03-31 09:03:21 -07:00
UDWORD callDepth = 0 ;
2008-03-24 09:51:17 -07:00
BOOL bTraceOn = false ; //enable to debug function/event calls
2006-08-12 03:02:59 -07:00
2007-04-03 06:20:41 -07:00
ASSERT ( psContext ! = NULL ,
2006-08-23 05:58:48 -07:00
" interpRunScript: invalid context pointer " ) ;
2006-11-16 06:30:29 -08:00
psProg = psContext - > psCode ;
2007-02-14 10:29:26 -08:00
psCurProg = psProg ; //remember for future use
2006-11-16 06:30:29 -08:00
2007-04-03 06:20:41 -07:00
ASSERT ( psProg ! = NULL ,
2006-08-23 05:58:48 -07:00
" interpRunScript: invalid script code pointer " ) ;
2007-06-28 10:47:08 -07:00
if ( bInterpRunning )
{
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: interpreter already running "
" - callback being called from within a script function? " ) ;
2007-06-28 10:47:08 -07:00
goto exit_with_error ;
}
// note that the interpreter is running to stop recursive script calls
2008-03-24 09:51:17 -07:00
bInterpRunning = true ;
2007-06-28 10:47:08 -07:00
// Reset the stack in case another script messed up
stackReset ( ) ;
2006-08-12 03:02:59 -07:00
//reset return stack
retStackReset ( ) ;
2007-06-28 10:47:08 -07:00
// Turn off tracing initially
2008-03-24 09:51:17 -07:00
interpTrace = false ;
2007-06-28 10:47:08 -07:00
/* Get the global variables */
numGlobals = psProg - > numGlobals ;
psGlobals = psContext - > psGlobals ;
2008-03-24 09:51:17 -07:00
bEvent = false ;
2006-08-15 11:38:51 -07:00
2007-06-28 10:47:08 -07:00
// Find the code range
switch ( runType )
{
case IRT_TRIGGER :
if ( index > psProg - > numTriggers )
{
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: trigger index out of range " ) ;
2008-03-24 09:51:17 -07:00
ASSERT ( false , " interpRunScript: trigger index out of range " ) ;
return false ;
2007-06-28 10:47:08 -07:00
}
pCodeBase = psProg - > pCode + psProg - > pTriggerTab [ index ] ;
pCodeStart = pCodeBase ;
pCodeEnd = psProg - > pCode + psProg - > pTriggerTab [ index + 1 ] ;
2006-11-16 06:30:29 -08:00
2008-03-24 09:51:17 -07:00
bCurCallerIsEvent = false ;
2007-02-14 10:29:26 -08:00
2006-11-16 06:30:29 -08:00
// find the debug info for the trigger
strcpy ( last_called_script_event , eventGetTriggerID ( psProg , index ) ) ;
2006-11-17 03:25:03 -08:00
if ( bTraceOn )
debug ( LOG_SCRIPT , " Trigger: %s " , last_called_script_event ) ;
2006-11-16 06:30:29 -08:00
2007-06-28 10:47:08 -07:00
break ;
case IRT_EVENT :
if ( index > psProg - > numEvents )
{
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: trigger index out of range " ) ;
2008-03-24 09:51:17 -07:00
ASSERT ( false , " interpRunScript: trigger index out of range " ) ;
return false ;
2007-06-28 10:47:08 -07:00
}
pCodeBase = psProg - > pCode + psProg - > pEventTab [ index ] ;
2006-08-21 14:20:17 -07:00
pCodeStart = pCodeBase + offset ; //offset only used for pause() script function
2007-06-28 10:47:08 -07:00
pCodeEnd = psProg - > pCode + psProg - > pEventTab [ index + 1 ] ;
2006-08-15 11:38:51 -07:00
2008-03-24 09:51:17 -07:00
bEvent = true ; //remember it's an event
bCurCallerIsEvent = true ;
2006-11-16 06:30:29 -08:00
// remember last called event/function
strcpy ( last_called_script_event , eventGetEventID ( psProg , index ) ) ;
2006-11-17 03:25:03 -08:00
if ( bTraceOn )
debug ( LOG_SCRIPT , " Original event name: %s " , last_called_script_event ) ;
2006-11-16 06:30:29 -08:00
2007-06-28 10:47:08 -07:00
break ;
default :
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: unknown run type " ) ;
2008-03-24 09:51:17 -07:00
ASSERT ( false , " interpRunScript: unknown run type " ) ;
return false ;
2007-06-28 10:47:08 -07:00
}
// Get the first opcode
2006-09-19 09:30:50 -07:00
InstrPointer = pCodeStart ;
2006-11-16 06:30:29 -08:00
/* Make sure we start with an opcode */
ASSERT ( InstrPointer - > type = = VAL_PKOPCODE | | InstrPointer - > type = = VAL_OPCODE ,
" Expected an opcode at the beginning of the interpreting process (type=%d) " , InstrPointer - > type ) ;
//opcode = InstrPointer->v.ival >> OPCODE_SHIFT;
2007-06-28 10:47:08 -07:00
instructionCount = 0 ;
2006-08-12 03:02:59 -07:00
CurEvent = index ;
2008-03-24 09:51:17 -07:00
bStop = false ;
2007-06-28 10:47:08 -07:00
2007-03-31 09:03:21 -07:00
// create new variable environment for this call
if ( bEvent )
{
createVarEnvironment ( psContext , CurEvent ) ;
}
2006-08-12 03:02:59 -07:00
while ( ! bStop )
{
// Run the code
2006-09-19 09:30:50 -07:00
if ( InstrPointer < pCodeEnd ) // && opcode != OP_EXIT)
2007-06-28 10:47:08 -07:00
{
2006-08-12 03:02:59 -07:00
if ( instructionCount > INTERP_MAXINSTRUCTIONS )
2007-06-28 10:47:08 -07:00
{
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: max instruction count exceeded - infinite loop ? " ) ;
2007-06-28 10:47:08 -07:00
goto exit_with_error ;
}
2006-11-16 06:30:29 -08:00
instructionCount + + ;
2006-08-12 03:02:59 -07:00
2007-03-15 16:17:09 -07:00
TRCPRINTF ( " %-6d " , ( int ) ( InstrPointer - psProg - > pCode ) ) ;
2006-11-17 03:25:03 -08:00
opcode = ( OPCODE ) ( InstrPointer - > v . ival > > OPCODE_SHIFT ) ; //get opcode
data = ( SDWORD ) ( InstrPointer - > v . ival & OPCODE_DATAMASK ) ; //get data - only used with packed opcodes
2006-08-12 03:02:59 -07:00
switch ( opcode )
2007-06-28 10:47:08 -07:00
{
2006-08-12 03:02:59 -07:00
/* Custom function call */
case OP_FUNC :
2006-08-15 11:38:51 -07:00
//debug( LOG_SCRIPT, "-OP_FUNC" );
//debug( LOG_SCRIPT, "OP_FUNC: remember event %d, ip=%d", CurEvent, (ip + 2) );
2006-11-16 06:30:29 -08:00
2006-09-19 09:30:50 -07:00
if ( ! retStackPush ( CurEvent , ( InstrPointer + aOpSize [ opcode ] ) ) ) //Remember where to jump back later
2006-08-12 03:02:59 -07:00
{
2006-09-19 09:30:50 -07:00
debug ( LOG_ERROR , " interpRunScript() - retStackPush() failed. " ) ;
2008-03-24 09:51:17 -07:00
return false ;
2006-08-12 03:02:59 -07:00
}
2006-11-16 06:30:29 -08:00
ASSERT ( ( ( INTERP_VAL * ) ( InstrPointer + 1 ) ) - > type = = VAL_EVENT , " wrong value type passed for OP_FUNC: %d " , ( ( INTERP_VAL * ) ( InstrPointer + 1 ) ) - > type ) ;
2007-03-31 09:03:21 -07:00
// get index of the new event
2006-11-16 06:30:29 -08:00
CurEvent = ( ( INTERP_VAL * ) ( InstrPointer + 1 ) ) - > v . ival ; //Current event = event to jump to
2006-08-15 11:38:51 -07:00
2006-08-12 03:02:59 -07:00
if ( CurEvent > psProg - > numEvents )
{
debug ( LOG_ERROR , " interpRunScript: trigger index out of range " ) ;
2006-11-16 06:30:29 -08:00
goto exit_with_error ;
2006-08-12 03:02:59 -07:00
}
2007-03-31 09:03:21 -07:00
// create new variable environment for this call
createVarEnvironment ( psContext , CurEvent ) ;
2006-11-16 06:30:29 -08:00
//Set new code execution boundaries
2006-08-12 03:02:59 -07:00
//----------------------------------
pCodeBase = psProg - > pCode + psProg - > pEventTab [ CurEvent ] ;
pCodeStart = pCodeBase ;
pCodeEnd = psProg - > pCode + psProg - > pEventTab [ CurEvent + 1 ] ;
2006-09-19 09:30:50 -07:00
InstrPointer = pCodeStart ; //Start at the beginning of the new event
2006-08-12 03:02:59 -07:00
2006-11-16 06:30:29 -08:00
//remember last called event/index
strcpy ( last_called_script_event , eventGetEventID ( psProg , CurEvent ) ) ;
2006-11-17 03:25:03 -08:00
if ( bTraceOn )
debug ( LOG_SCRIPT , " Called: '%s' " , last_called_script_event ) ;
2006-08-15 11:38:51 -07:00
//debug( LOG_SCRIPT, "-OP_FUNC: jumped to event %d; ip=%d, numLocalVars: %d", CurEvent, ip, psContext->psCode->numLocalVars[CurEvent] );
//debug( LOG_SCRIPT, "-END OP_FUNC" );
2006-08-12 03:02:59 -07:00
break ;
2006-08-15 11:38:51 -07:00
//handle local variables
case OP_PUSHLOCAL :
//debug( LOG_SCRIPT, "OP_PUSHLOCAL");
//debug( LOG_SCRIPT, "OP_PUSHLOCAL, (CurEvent=%d, data =%d) num loc vars: %d; pushing: %d", CurEvent, data, psContext->psCode->numLocalVars[CurEvent], psContext->psCode->ppsLocalVarVal[CurEvent][data].v.ival);
2006-08-22 07:28:49 -07:00
2006-08-15 11:38:51 -07:00
if ( data > = psContext - > psCode - > numLocalVars [ CurEvent ] )
{
debug ( LOG_ERROR , " interpRunScript: OP_PUSHLOCAL: variable index out of range " ) ;
goto exit_with_error ;
}
//debug(LOG_SCRIPT, "OP_PUSHLOCAL type: %d", psContext->psCode->ppsLocalVarVal[CurEvent][data].type);
2006-08-22 07:28:49 -07:00
2007-03-31 09:03:21 -07:00
if ( ! stackPush ( & ( varEnvironment [ retStackCallDepth ( ) ] [ data ] ) ) )
2006-08-15 11:38:51 -07:00
{
debug ( LOG_ERROR , " interpRunScript: OP_PUSHLOCAL: push failed " ) ;
goto exit_with_error ;
}
2006-09-19 09:30:50 -07:00
InstrPointer + = aOpSize [ opcode ] ;
2006-08-15 11:38:51 -07:00
break ;
case OP_POPLOCAL :
2006-08-22 07:28:49 -07:00
2006-08-15 11:38:51 -07:00
//debug( LOG_SCRIPT, "OP_POPLOCAL, event index: '%d', data: '%d'", CurEvent, data);
//debug( LOG_SCRIPT, "OP_POPLOCAL, numLocalVars: '%d'", psContext->psCode->numLocalVars[CurEvent]);
if ( data > = psContext - > psCode - > numLocalVars [ CurEvent ] )
{
debug ( LOG_ERROR , " interpRunScript: OP_POPLOCAL: variable index out of range " ) ;
goto exit_with_error ;
}
//DbgMsg("OP_POPLOCAL type: %d, CurEvent=%d, data=%d", psContext->psCode->ppsLocalVarVal[CurEvent][data].type, CurEvent, data);
2007-03-31 09:03:21 -07:00
if ( ! stackPopType ( & ( varEnvironment [ retStackCallDepth ( ) ] [ data ] ) ) )
2006-08-15 11:38:51 -07:00
{
debug ( LOG_ERROR , " interpRunScript: OP_POPLOCAL: pop failed " ) ;
goto exit_with_error ;
}
2007-03-31 09:03:21 -07:00
2006-08-15 11:38:51 -07:00
//debug(LOG_SCRIPT, "OP_POPLOCAL: type=%d, val=%d", psContext->psCode->ppsLocalVarVal[CurEvent][data].type, psContext->psCode->ppsLocalVarVal[CurEvent][data].v.ival);
2006-09-19 09:30:50 -07:00
InstrPointer + = aOpSize [ opcode ] ;
2006-08-15 11:38:51 -07:00
break ;
case OP_PUSHLOCALREF :
// The type of the variable is stored in with the opcode
2006-11-16 06:30:29 -08:00
sVal . type = ( INTERP_TYPE ) ( InstrPointer - > v . ival & OPCODE_DATAMASK ) ;
ASSERT ( ( ( INTERP_VAL * ) ( InstrPointer + 1 ) ) - > type = = VAL_INT ,
" wrong value type passed for OP_PUSHLOCALREF: %d " , ( ( INTERP_VAL * ) ( InstrPointer + 1 ) ) - > type ) ;
2006-08-15 11:38:51 -07:00
/* get local var index */
2006-11-16 06:30:29 -08:00
data = ( ( INTERP_VAL * ) ( InstrPointer + 1 ) ) - > v . ival ;
2006-08-15 11:38:51 -07:00
if ( data > = psContext - > psCode - > numLocalVars [ CurEvent ] )
{
debug ( LOG_ERROR , " interpRunScript: OP_PUSHLOCALREF: variable index out of range " ) ;
goto exit_with_error ;
}
2007-03-31 09:03:21 -07:00
2006-08-15 11:38:51 -07:00
/* get local variable */
2007-03-31 09:03:21 -07:00
sVal . v . oval = & ( varEnvironment [ retStackCallDepth ( ) ] [ data ] ) ;
2006-08-15 11:38:51 -07:00
2008-03-25 17:45:03 -07:00
TRCPRINTOPCODE ( opcode ) ;
TRCPRINTVAL ( sVal ) ;
2007-02-19 06:10:44 -08:00
TRCPRINTF ( " \n " ) ;
2006-08-15 11:38:51 -07:00
if ( ! stackPush ( & sVal ) )
{
debug ( LOG_ERROR , " interpRunScript: OP_PUSHLOCALREF: push failed " ) ;
goto exit_with_error ;
}
2006-09-19 09:30:50 -07:00
InstrPointer + = aOpSize [ opcode ] ;
2006-08-15 11:38:51 -07:00
break ;
2006-08-12 03:02:59 -07:00
case OP_PUSH :
// The type of the value is stored in with the opcode
2006-11-16 06:30:29 -08:00
sVal . type = ( INTERP_TYPE ) ( InstrPointer - > v . ival & OPCODE_DATAMASK ) ;
//ASSERT( ((INTERP_VAL *)(InstrPointer + 1))->type == sVal.type,
// "wrong value type passed for OP_PUSH: %d, expected: %d", ((INTERP_VAL *)(InstrPointer + 1))->type, sVal.type );
ASSERT ( interpCheckEquiv ( ( ( INTERP_VAL * ) ( InstrPointer + 1 ) ) - > type , sVal . type ) ,
" wrong value type passed for OP_PUSH: %d, expected: %d " , ( ( INTERP_VAL * ) ( InstrPointer + 1 ) ) - > type , sVal . type ) ;
2006-11-17 03:25:03 -08:00
/* copy value */
2006-11-16 06:30:29 -08:00
memcpy ( & sVal , ( INTERP_VAL * ) ( InstrPointer + 1 ) , sizeof ( INTERP_VAL ) ) ;
2008-03-25 17:45:03 -07:00
TRCPRINTOPCODE ( opcode ) ;
TRCPRINTVAL ( sVal ) ;
2007-02-19 06:10:44 -08:00
TRCPRINTF ( " \n " ) ;
2006-08-12 03:02:59 -07:00
if ( ! stackPush ( & sVal ) )
{
// Eeerk, out of memory
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: out of memory! " ) ;
2006-08-12 03:02:59 -07:00
goto exit_with_error ;
}
2006-09-19 09:30:50 -07:00
InstrPointer + = aOpSize [ opcode ] ;
2006-08-12 03:02:59 -07:00
break ;
case OP_PUSHREF :
// The type of the variable is stored in with the opcode
2006-11-16 06:30:29 -08:00
sVal . type = ( INTERP_TYPE ) ( InstrPointer - > v . ival & OPCODE_DATAMASK ) ;
2006-12-16 06:59:50 -08:00
// store pointer to INTERP_VAL
sVal . v . oval = interpGetVarData ( psGlobals , ( ( INTERP_VAL * ) ( InstrPointer + 1 ) ) - > v . ival ) ;
2008-03-25 17:45:03 -07:00
TRCPRINTOPCODE ( opcode ) ;
TRCPRINTVAL ( sVal ) ;
2007-02-19 06:10:44 -08:00
TRCPRINTF ( " \n " ) ;
2006-08-12 03:02:59 -07:00
if ( ! stackPush ( & sVal ) )
{
// Eeerk, out of memory
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: out of memory! " ) ;
2006-08-12 03:02:59 -07:00
goto exit_with_error ;
}
2006-09-19 09:30:50 -07:00
InstrPointer + = aOpSize [ opcode ] ;
2006-08-12 03:02:59 -07:00
break ;
case OP_POP :
2006-11-16 06:30:29 -08:00
ASSERT ( InstrPointer - > type = = VAL_OPCODE ,
" wrong value type passed for OP_POP: %d " , InstrPointer - > type ) ;
2008-03-25 17:45:03 -07:00
TRCPRINTOPCODE ( opcode ) ;
2006-08-12 03:02:59 -07:00
if ( ! stackPop ( & sVal ) )
{
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: could not do stack pop " ) ;
2006-08-12 03:02:59 -07:00
goto exit_with_error ;
}
2006-09-19 09:30:50 -07:00
InstrPointer + = aOpSize [ opcode ] ;
2006-08-12 03:02:59 -07:00
break ;
case OP_BINARYOP :
2006-11-16 06:30:29 -08:00
ASSERT ( InstrPointer - > type = = VAL_PKOPCODE ,
" wrong value type passed for OP_BINARYOP: %d " , InstrPointer - > type ) ;
2008-03-25 17:48:41 -07:00
TRCPRINTOPCODE ( data ) ;
2006-08-12 03:02:59 -07:00
if ( ! stackBinaryOp ( ( OPCODE ) data ) )
{
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: could not do binary op " ) ;
2006-08-12 03:02:59 -07:00
goto exit_with_error ;
}
TRCPRINTSTACKTOP ( ) ;
2007-02-19 06:10:44 -08:00
TRCPRINTF ( " \n " ) ;
2006-09-19 09:30:50 -07:00
InstrPointer + = aOpSize [ opcode ] ;
2006-08-12 03:02:59 -07:00
break ;
case OP_UNARYOP :
2006-11-16 06:30:29 -08:00
ASSERT ( InstrPointer - > type = = VAL_PKOPCODE ,
" wrong value type passed for OP_UNARYOP: %d " , InstrPointer - > type ) ;
2008-03-25 17:48:41 -07:00
TRCPRINTOPCODE ( data ) ;
2006-08-12 03:02:59 -07:00
if ( ! stackUnaryOp ( ( OPCODE ) data ) )
{
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: could not do unary op " ) ;
2006-08-12 03:02:59 -07:00
goto exit_with_error ;
}
TRCPRINTSTACKTOP ( ) ;
2007-02-19 06:10:44 -08:00
TRCPRINTF ( " \n " ) ;
2006-09-19 09:30:50 -07:00
InstrPointer + = aOpSize [ opcode ] ;
2006-08-12 03:02:59 -07:00
break ;
case OP_PUSHGLOBAL :
2006-11-16 06:30:29 -08:00
ASSERT ( InstrPointer - > type = = VAL_PKOPCODE ,
" wrong value type passed for OP_PUSHGLOBAL: %d " , InstrPointer - > type ) ;
2007-02-19 06:10:44 -08:00
TRCPRINTF ( " PUSHGLOBAL %d \n " , data ) ;
2006-08-12 03:02:59 -07:00
if ( data > = numGlobals )
{
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: variable index out of range " ) ;
2006-08-12 03:02:59 -07:00
goto exit_with_error ;
}
if ( ! stackPush ( interpGetVarData ( psGlobals , data ) ) )
{
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: could not do stack push " ) ;
2006-08-12 03:02:59 -07:00
goto exit_with_error ;
}
2006-09-19 09:30:50 -07:00
InstrPointer + = aOpSize [ opcode ] ;
2006-08-12 03:02:59 -07:00
break ;
case OP_POPGLOBAL :
2006-11-16 06:30:29 -08:00
ASSERT ( InstrPointer - > type = = VAL_PKOPCODE ,
" wrong value type passed for OP_POPGLOBAL: %d " , InstrPointer - > type ) ;
2007-02-19 06:10:44 -08:00
TRCPRINTF ( " POPGLOBAL %d " , data ) ;
2006-08-12 03:02:59 -07:00
TRCPRINTSTACKTOP ( ) ;
2007-02-19 06:10:44 -08:00
TRCPRINTF ( " \n " ) ;
2006-08-12 03:02:59 -07:00
if ( data > = numGlobals )
{
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: variable index out of range " ) ;
2006-08-12 03:02:59 -07:00
goto exit_with_error ;
}
if ( ! stackPopType ( interpGetVarData ( psGlobals , data ) ) )
{
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: could not do stack pop " ) ;
2006-08-12 03:02:59 -07:00
goto exit_with_error ;
}
2006-09-19 09:30:50 -07:00
InstrPointer + = aOpSize [ opcode ] ;
2006-08-12 03:02:59 -07:00
break ;
case OP_PUSHARRAYGLOBAL :
2006-11-16 06:30:29 -08:00
ASSERT ( InstrPointer - > type = = VAL_PKOPCODE ,
" wrong value type passed for OP_PUSHARRAYGLOBAL: %d " , InstrPointer - > type ) ;
2008-03-25 17:45:03 -07:00
TRCPRINTOPCODE ( opcode ) ;
2006-09-19 09:30:50 -07:00
if ( ! interpGetArrayVarData ( & InstrPointer , psGlobals , psProg , & psVar ) )
2006-08-12 03:02:59 -07:00
{
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: could not get array var data, CurEvent=%d " , CurEvent ) ;
2006-08-12 03:02:59 -07:00
goto exit_with_error ;
}
2007-02-19 06:10:44 -08:00
TRCPRINTF ( " \n " ) ;
2006-08-12 03:02:59 -07:00
if ( ! stackPush ( psVar ) )
{
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: could not do stack push " ) ;
2006-08-12 03:02:59 -07:00
goto exit_with_error ;
}
break ;
case OP_POPARRAYGLOBAL :
2006-11-16 06:30:29 -08:00
ASSERT ( InstrPointer - > type = = VAL_PKOPCODE ,
" wrong value type passed for OP_POPARRAYGLOBAL: %d " , InstrPointer - > type ) ;
2008-03-25 17:45:03 -07:00
TRCPRINTOPCODE ( opcode ) ;
2006-09-19 09:30:50 -07:00
if ( ! interpGetArrayVarData ( & InstrPointer , psGlobals , psProg , & psVar ) )
2006-08-12 03:02:59 -07:00
{
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: could not get array var data " ) ;
2006-08-12 03:02:59 -07:00
goto exit_with_error ;
}
TRCPRINTSTACKTOP ( ) ;
2007-02-19 06:10:44 -08:00
TRCPRINTF ( " \n " ) ;
2006-08-12 03:02:59 -07:00
if ( ! stackPopType ( psVar ) )
{
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: could not do pop stack of type " ) ;
2006-08-12 03:02:59 -07:00
goto exit_with_error ;
}
break ;
2006-11-16 06:30:29 -08:00
2006-08-12 03:02:59 -07:00
case OP_JUMPFALSE :
2006-11-16 06:30:29 -08:00
ASSERT ( InstrPointer - > type = = VAL_PKOPCODE ,
" wrong value type passed for OP_JUMPFALSE: %d " , InstrPointer - > type ) ;
2007-02-19 06:10:44 -08:00
TRCPRINTF ( " JUMPFALSE %d (%d) " ,
2007-03-15 16:17:09 -07:00
( SWORD ) data , ( int ) ( InstrPointer - psProg - > pCode + ( SWORD ) data ) ) ;
2006-11-16 06:30:29 -08:00
2006-08-12 03:02:59 -07:00
if ( ! stackPop ( & sVal ) )
{
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: could not do pop of stack " ) ;
2006-08-12 03:02:59 -07:00
goto exit_with_error ;
}
if ( ! sVal . v . bval )
{
// Do the jump
2007-02-19 06:10:44 -08:00
TRCPRINTF ( " - done - \n " ) ;
2006-09-19 09:30:50 -07:00
InstrPointer + = ( SWORD ) data ;
if ( InstrPointer < pCodeStart | | InstrPointer > pCodeEnd )
2006-08-12 03:02:59 -07:00
{
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: jump out of range " ) ;
2006-08-12 03:02:59 -07:00
goto exit_with_error ;
}
}
else
{
2007-02-19 06:10:44 -08:00
TRCPRINTF ( " \n " ) ;
2006-09-19 09:30:50 -07:00
InstrPointer + = aOpSize [ opcode ] ;
2006-08-12 03:02:59 -07:00
}
break ;
case OP_JUMP :
2006-11-16 06:30:29 -08:00
ASSERT ( InstrPointer - > type = = VAL_PKOPCODE ,
" wrong value type passed for OP_JUMP: %d " , InstrPointer - > type ) ;
2007-02-19 06:10:44 -08:00
TRCPRINTF ( " JUMP %d (%d) \n " ,
2007-03-15 16:17:09 -07:00
( SWORD ) data , ( int ) ( InstrPointer - psProg - > pCode + ( SWORD ) data ) ) ;
2007-06-28 10:47:08 -07:00
// Do the jump
2006-09-19 09:30:50 -07:00
InstrPointer + = ( SWORD ) data ;
if ( InstrPointer < pCodeStart | | InstrPointer > pCodeEnd )
2007-06-28 10:47:08 -07:00
{
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: jump out of range " ) ;
2007-06-28 10:47:08 -07:00
goto exit_with_error ;
}
2006-08-12 03:02:59 -07:00
break ;
case OP_CALL :
2006-08-19 06:26:11 -07:00
//debug(LOG_SCRIPT, "OP_CALL");
2006-11-16 06:30:29 -08:00
ASSERT ( InstrPointer - > type = = VAL_OPCODE ,
" wrong value type passed for OP_CALL: %d " , InstrPointer - > type ) ;
scriptFunc = ( ( INTERP_VAL * ) ( InstrPointer + 1 ) ) - > v . pFuncExtern ;
2008-03-25 17:45:03 -07:00
TRCPRINTFUNC ( scriptFunc ) ;
TRCPRINTF ( " \n " ) ;
2006-08-19 06:26:11 -07:00
//debug(LOG_SCRIPT, "OP_CALL 1");
2006-08-12 03:02:59 -07:00
if ( ! scriptFunc ( ) )
{
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: could not do func " ) ;
2006-08-12 03:02:59 -07:00
goto exit_with_error ;
}
2006-08-19 06:26:11 -07:00
//debug(LOG_SCRIPT, "OP_CALL 2");
2006-09-19 09:30:50 -07:00
InstrPointer + = aOpSize [ opcode ] ;
2006-08-19 06:26:11 -07:00
//debug(LOG_SCRIPT, "OP_CALL 3");
2006-08-12 03:02:59 -07:00
break ;
case OP_VARCALL :
2006-11-16 06:30:29 -08:00
ASSERT ( InstrPointer - > type = = VAL_PKOPCODE ,
" wrong value type passed for OP_VARCALL: %d " , InstrPointer - > type ) ;
2008-03-25 17:45:03 -07:00
TRCPRINTOPCODE ( opcode ) ;
2006-11-16 06:30:29 -08:00
TRCPRINTVARFUNC ( ( ( INTERP_VAL * ) ( InstrPointer + 1 ) ) - > v . pObjGetSet , data ) ;
2007-02-19 06:10:44 -08:00
TRCPRINTF ( " (%d) \n " , data ) ;
2006-11-16 06:30:29 -08:00
ASSERT ( ( ( INTERP_VAL * ) ( InstrPointer + 1 ) ) - > type = = VAL_OBJ_GETSET ,
" wrong set/get function pointer type passed for OP_VARCALL: %d " , ( ( INTERP_VAL * ) ( InstrPointer + 1 ) ) - > type ) ;
scriptVarFunc = ( ( INTERP_VAL * ) ( InstrPointer + 1 ) ) - > v . pObjGetSet ;
2006-08-12 03:02:59 -07:00
if ( ! scriptVarFunc ( data ) )
{
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: could not do var func " ) ;
2006-08-12 03:02:59 -07:00
goto exit_with_error ;
}
2006-09-19 09:30:50 -07:00
InstrPointer + = aOpSize [ opcode ] ;
2006-08-12 03:02:59 -07:00
break ;
2006-11-16 06:30:29 -08:00
case OP_EXIT : /* end of function/event, "exit" or "return" statements */
ASSERT ( InstrPointer - > type = = VAL_OPCODE ,
" wrong value type passed for OP_EXIT: %d " , InstrPointer - > type ) ;
2006-08-12 03:02:59 -07:00
// jump out of the code
2006-09-19 09:30:50 -07:00
InstrPointer = pCodeEnd ;
2006-08-12 03:02:59 -07:00
break ;
2006-12-16 06:59:50 -08:00
case OP_PAUSE :
2006-11-16 06:30:29 -08:00
ASSERT ( InstrPointer - > type = = VAL_PKOPCODE ,
" wrong value type passed for OP_PAUSE: %d " , InstrPointer - > type ) ;
2007-02-19 06:10:44 -08:00
TRCPRINTF ( " PAUSE %d \n " , data ) ;
2006-08-23 05:58:48 -07:00
ASSERT ( stackEmpty ( ) ,
" interpRunScript: OP_PAUSE without empty stack " ) ;
2006-11-16 06:30:29 -08:00
2006-09-19 09:30:50 -07:00
InstrPointer + = aOpSize [ opcode ] ;
2006-08-12 03:02:59 -07:00
// tell the event system to reschedule this event
2007-03-31 09:03:21 -07:00
if ( ! eventAddPauseTrigger ( psContext , index , ( UDWORD ) ( InstrPointer - pCodeBase ) , data ) ) //only original caller can be paused since we pass index and not CurEvent (not sure if that's what we want)
2006-08-12 03:02:59 -07:00
{
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: could not add pause trigger " ) ;
2006-08-12 03:02:59 -07:00
goto exit_with_error ;
}
// now jump out of the event
2006-09-19 09:30:50 -07:00
InstrPointer = pCodeEnd ;
2006-08-12 03:02:59 -07:00
break ;
2006-11-16 06:30:29 -08:00
case OP_TO_FLOAT :
ASSERT ( InstrPointer - > type = = VAL_OPCODE ,
" wrong value type passed for OP_TO_FLOAT: %d " , InstrPointer - > type ) ;
2008-03-25 17:27:56 -07:00
if ( ! stackCastTop ( VAL_FLOAT ) )
2006-11-16 06:30:29 -08:00
{
debug ( LOG_ERROR , " interpRunScript: OP_TO_FLOAT failed " ) ;
goto exit_with_error ;
}
InstrPointer + = aOpSize [ opcode ] ;
break ;
case OP_TO_INT :
ASSERT ( InstrPointer - > type = = VAL_OPCODE ,
" wrong value type passed for OP_TO_INT: %d " , InstrPointer - > type ) ;
2008-03-25 17:27:56 -07:00
if ( ! stackCastTop ( VAL_INT ) )
2006-11-16 06:30:29 -08:00
{
debug ( LOG_ERROR , " interpRunScript: OP_TO_INT failed " ) ;
goto exit_with_error ;
}
InstrPointer + = aOpSize [ opcode ] ;
2006-12-16 06:59:50 -08:00
break ;
2006-08-12 03:02:59 -07:00
default :
2007-02-14 10:29:26 -08:00
debug ( LOG_ERROR , " interpRunScript: unknown opcode: %d, type: %d " , opcode , InstrPointer - > type ) ;
2007-06-28 10:47:08 -07:00
goto exit_with_error ;
2006-08-12 03:02:59 -07:00
break ;
2007-06-28 10:47:08 -07:00
}
2006-08-12 03:02:59 -07:00
}
else //End of the event reached, see if we have to jump back to the caller function or just exit
{
2006-08-15 11:38:51 -07:00
//debug(LOG_SCRIPT, "End of event reached");
2006-08-12 03:02:59 -07:00
2006-09-19 09:30:50 -07:00
if ( ! retStackIsEmpty ( ) ) //There was a caller function before this one
2007-06-28 10:47:08 -07:00
{
2007-03-31 09:03:21 -07:00
// destroy current variable environment
2007-04-01 09:22:01 -07:00
destroyVarEnvironment ( psContext , retStackCallDepth ( ) , CurEvent ) ;
2006-08-21 14:20:17 -07:00
2006-09-21 13:42:48 -07:00
//pop caller function index and return address
2006-09-19 09:30:50 -07:00
if ( ! retStackPop ( & CurEvent , & InstrPointer ) )
2006-08-12 03:02:59 -07:00
{
2006-09-21 13:42:48 -07:00
debug ( LOG_ERROR , " interpRunScript() - retStackPop() failed. " ) ;
2008-03-24 09:51:17 -07:00
return false ;
2006-08-12 03:02:59 -07:00
}
2006-11-16 06:30:29 -08:00
//remember last called event/index
strcpy ( last_called_script_event , eventGetEventID ( psProg , CurEvent ) ) ;
2006-11-17 03:25:03 -08:00
if ( bTraceOn )
debug ( LOG_SCRIPT , " Returned to: '%s' " , last_called_script_event ) ;
2006-08-15 11:38:51 -07:00
//debug( LOG_SCRIPT, "RETURNED TO CALLER EVENT %d", CurEvent );
2006-08-12 03:02:59 -07:00
2006-11-17 03:25:03 -08:00
//Set new boundaries
2006-08-12 03:02:59 -07:00
//--------------------------
2006-09-19 09:30:50 -07:00
if ( retStackIsEmpty ( ) ) //if we jumped back to the original caller
2006-08-21 14:20:17 -07:00
{
if ( ! bEvent ) //original caller was a trigger (is it possible at all?)
{
pCodeBase = psProg - > pCode + psProg - > pTriggerTab [ CurEvent ] ;
pCodeStart = pCodeBase ;
pCodeEnd = psProg - > pCode + psProg - > pTriggerTab [ CurEvent + 1 ] ;
}
else //original caller was an event
{
pCodeBase = psProg - > pCode + psProg - > pEventTab [ CurEvent ] ;
pCodeStart = pCodeBase + offset ; //also use the offset passed, since it's an original caller event (offset is used for pause() )
pCodeEnd = psProg - > pCode + psProg - > pEventTab [ CurEvent + 1 ] ;
}
}
else //we are still jumping thru functions (this can't be a callback, since it can't/should not be called)
{
pCodeBase = psProg - > pCode + psProg - > pEventTab [ CurEvent ] ;
pCodeStart = pCodeBase ;
pCodeEnd = psProg - > pCode + psProg - > pEventTab [ CurEvent + 1 ] ;
}
2007-06-28 10:47:08 -07:00
}
2006-11-16 06:30:29 -08:00
else //we have returned to the original caller event/function
2007-06-28 10:47:08 -07:00
{
2006-08-15 11:38:51 -07:00
//debug( LOG_SCRIPT, " *** CALL STACK EMPTY ***" );
2006-08-21 14:20:17 -07:00
//reset local vars only if original caller was an event, not a trigger
if ( bEvent )
2006-08-15 11:38:51 -07:00
{
2007-03-31 09:03:21 -07:00
// destroy current variable environment
2007-04-01 09:22:01 -07:00
destroyVarEnvironment ( psContext , retStackCallDepth ( ) , CurEvent ) ;
2006-08-15 11:38:51 -07:00
}
2006-08-12 03:02:59 -07:00
2008-03-24 09:51:17 -07:00
bStop = true ; //Stop execution of this event here, no more calling functions stored
2007-06-28 10:47:08 -07:00
}
}
2006-08-12 03:02:59 -07:00
2007-06-28 10:47:08 -07:00
}
2006-08-12 03:02:59 -07:00
2007-02-14 10:29:26 -08:00
psCurProg = NULL ;
2007-03-15 16:17:09 -07:00
TRCPRINTF ( " %-6d EXIT \n " , ( int ) ( InstrPointer - psProg - > pCode ) ) ;
2007-06-28 10:47:08 -07:00
2008-03-24 09:51:17 -07:00
bInterpRunning = false ;
return true ;
2007-06-28 10:47:08 -07:00
exit_with_error :
// Deal with the script crashing or running out of memory
2006-08-15 11:38:51 -07:00
debug ( LOG_ERROR , " interpRunScript: *** ERROR EXIT *** (CurEvent=%d) " , CurEvent ) ;
2006-08-19 06:26:11 -07:00
2007-03-31 09:03:21 -07:00
/* Free all memory allocated for variable environments */
cleanupVarEnvironments ( ) ;
2006-08-21 14:20:17 -07:00
if ( bEvent )
2007-03-31 09:03:21 -07:00
{
2006-08-21 14:20:17 -07:00
debug ( LOG_ERROR , " Original event ID: %d (of %d) " , index , psProg - > numEvents ) ;
2007-03-31 09:03:21 -07:00
}
2006-08-21 14:20:17 -07:00
else
2007-03-31 09:03:21 -07:00
{
2006-08-21 14:20:17 -07:00
debug ( LOG_ERROR , " Original trigger ID: %d (of %d) " , index , psProg - > numTriggers ) ;
2007-03-31 09:03:21 -07:00
}
2006-08-19 06:26:11 -07:00
debug ( LOG_ERROR , " Current event ID: %d (of %d) " , CurEvent , psProg - > numEvents ) ;
2006-09-19 09:30:50 -07:00
callDepth = retStackCallDepth ( ) ;
2006-08-19 06:26:11 -07:00
debug ( LOG_ERROR , " Call depth : %d " , callDepth ) ;
2007-02-10 07:23:47 -08:00
/* Output script call trace */
2007-02-14 10:29:26 -08:00
scrOutputCallTrace ( ) ;
psCurProg = NULL ;
2006-08-19 06:26:11 -07:00
2007-02-19 06:10:44 -08:00
TRCPRINTF ( " *** ERROR EXIT *** \n " ) ;
2007-02-14 10:29:26 -08:00
2007-06-04 09:49:58 -07:00
ASSERT ( ! " error while executing a script " , " interpRunScript: error while executing a script " ) ;
2007-02-14 10:29:26 -08:00
2008-03-24 09:51:17 -07:00
bInterpRunning = false ;
return false ;
2007-06-28 10:47:08 -07:00
}
/* Set the type equivalence table */
void scriptSetTypeEquiv ( TYPE_EQUIV * psTypeTab )
{
# ifdef DEBUG
SDWORD i ;
for ( i = 0 ; psTypeTab [ i ] . base ! = 0 ; i + + )
{
2006-08-23 05:58:48 -07:00
ASSERT ( psTypeTab [ i ] . base > = VAL_USERTYPESTART ,
2006-12-02 15:27:00 -08:00
" scriptSetTypeEquiv: can only set type equivalence for user types (%d) " , i ) ;
2007-06-28 10:47:08 -07:00
}
# endif
asInterpTypeEquiv = psTypeTab ;
}
2008-03-24 13:57:07 -07:00
static const struct {
INTERP_TYPE type ;
const char * name ;
} typeToStringMap [ ] = {
// Basic types
{ VAL_BOOL , " bool " } ,
{ VAL_INT , " int " } ,
{ VAL_FLOAT , " float " } ,
{ VAL_STRING , " string " } ,
// events and triggers
{ VAL_TRIGGER , " trigger " } ,
{ VAL_EVENT , " event " } ,
{ VAL_VOID , " void " } ,
{ VAL_OPCODE , " opcode " } ,
{ VAL_PKOPCODE , " pkopcode " } ,
{ VAL_OBJ_GETSET , " objgs " } ,
{ VAL_FUNC_EXTERN , " func " } ,
{ VAL_USERTYPESTART , " usertype " } ,
{ VAL_REF , " ref " } ,
} ;
const char * interpTypeToString ( INTERP_TYPE type )
{
int i ; // Loop goes down -> signed
2008-03-25 17:27:56 -07:00
// Look whether it is a defaul type:
for ( i = ARRAY_SIZE ( typeToStringMap ) - 1 ;
i > = 0 & & type < = typeToStringMap [ i ] . type ;
i - - )
2008-03-24 13:57:07 -07:00
{
if ( type > = typeToStringMap [ i ] . type )
return typeToStringMap [ i ] . name ;
}
2008-03-25 17:27:56 -07:00
// Look whether it is a user type:
if ( asScrTypeTab )
{
unsigned int i ;
for ( i = 0 ; asScrTypeTab [ i ] . typeID ! = 0 ; i + + )
{
if ( asScrTypeTab [ i ] . typeID = = type )
{
return asScrTypeTab [ i ] . pIdent ;
}
}
}
2008-03-24 13:57:07 -07:00
return " unknown " ;
}
2008-03-25 17:45:03 -07:00
static const struct {
OPCODE opcode ;
const char * name ;
} opcodeToStringMap [ ] = {
{ OP_PUSH , " push " } ,
{ OP_PUSHREF , " push(ref) " } ,
{ OP_POP , " pop " } ,
{ OP_PUSHGLOBAL , " push(global) " } ,
{ OP_POPGLOBAL , " pop(global) " } ,
{ OP_PUSHARRAYGLOBAL , " push(global[]) " } ,
{ OP_POPARRAYGLOBAL , " push(global[]) " } ,
{ OP_CALL , " call " } ,
{ OP_VARCALL , " vcall " } ,
{ OP_JUMP , " jump " } ,
{ OP_JUMPTRUE , " jump(true) " } ,
{ OP_JUMPFALSE , " jump(false) " } ,
{ OP_BINARYOP , " binary " } ,
{ OP_UNARYOP , " unary " } ,
{ OP_EXIT , " exit " } ,
{ OP_PAUSE , " pause " } ,
// The following operations are secondary data to OP_BINARYOP and OP_UNARYOP
// Maths operators
{ OP_ADD , " + " } ,
{ OP_SUB , " - " } ,
{ OP_MUL , " * " } ,
{ OP_DIV , " / " } ,
{ OP_NEG , " (-) " } ,
{ OP_INC , " -- " } ,
{ OP_DEC , " ++ " } ,
// Boolean operators
{ OP_AND , " && " } ,
{ OP_OR , " || " } ,
{ OP_NOT , " ! " } ,
//String concatenation
{ OP_CONC , " & " } ,
// Comparison operators
{ OP_EQUAL , " = " } ,
{ OP_NOTEQUAL , " != " } ,
{ OP_GREATEREQUAL , " >= " } ,
{ OP_LESSEQUAL , " <= " } ,
{ OP_GREATER , " > " } ,
{ OP_LESS , " < " } ,
{ OP_FUNC , " func " } ,
{ OP_POPLOCAL , " pop(local) " } ,
{ OP_PUSHLOCAL , " push(local) " } ,
{ OP_PUSHLOCALREF , " push(localref) " } ,
{ OP_TO_FLOAT , " (float) " } ,
{ OP_TO_INT , " (int) " } ,
} ;
const char * interpOpcodeToString ( OPCODE opcode )
{
int i ; // Loop goes down -> signed
// Look whether it is a defaul type:
for ( i = ARRAY_SIZE ( opcodeToStringMap ) - 1 ;
i > = 0 & & opcode < = opcodeToStringMap [ i ] . opcode ;
i - - )
{
if ( opcode > = opcodeToStringMap [ i ] . opcode )
return opcodeToStringMap [ i ] . name ;
}
return " unknown " ;
}
const char * interpFunctionToString ( SCRIPT_FUNC function )
{
// Search the instinct functions
if ( asScrInstinctTab )
{
unsigned int i ;
for ( i = 0 ; asScrInstinctTab [ i ] . pFunc ! = NULL ; i + + )
{
if ( asScrInstinctTab [ i ] . pFunc = = function )
{
return asScrInstinctTab [ i ] . pIdent ;
}
}
}
// Search the callback functions
if ( asScrCallbackTab )
{
unsigned int i ;
for ( i = 0 ; asScrCallbackTab [ i ] . type ! = 0 ; i + + )
{
if ( asScrCallbackTab [ i ] . pFunc = = function )
{
return asScrCallbackTab [ i ] . pIdent ;
}
}
}
return " unknown " ;
}
2008-03-25 17:27:56 -07:00
/* Check if two types are equivalent
* Means : Their data can be copied without conversion .
* I . e . strings are NOT equivalent to anything but strings , even though they can be converted
*/
2007-06-28 10:47:08 -07:00
BOOL interpCheckEquiv ( INTERP_TYPE to , INTERP_TYPE from )
{
2008-03-24 13:57:07 -07:00
BOOL toRef = false , fromRef = false ;
2007-06-28 10:47:08 -07:00
// check for the VAL_REF flag
if ( to & VAL_REF )
{
2008-03-24 09:51:17 -07:00
toRef = true ;
2008-03-25 17:27:56 -07:00
to & = ~ VAL_REF ;
2007-06-28 10:47:08 -07:00
}
if ( from & VAL_REF )
{
2008-03-24 09:51:17 -07:00
fromRef = true ;
2008-03-25 17:27:56 -07:00
from & = ~ VAL_REF ;
2007-06-28 10:47:08 -07:00
}
if ( toRef ! = fromRef )
{
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2006-12-16 06:59:50 -08:00
/* Void pointer is compatible with any other type */
2008-03-25 17:27:56 -07:00
if ( toRef = = true & & fromRef = = true & &
( to = = VAL_VOID | | from = = VAL_VOID ) )
2008-03-24 13:57:07 -07:00
{
return true ;
2006-12-16 06:59:50 -08:00
}
2007-06-28 10:47:08 -07:00
if ( to = = from )
{
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
else if ( asInterpTypeEquiv )
{
2008-03-24 13:57:07 -07:00
unsigned int i ;
for ( i = 0 ; asInterpTypeEquiv [ i ] . base ! = 0 ; i + + )
2007-06-28 10:47:08 -07:00
{
if ( asInterpTypeEquiv [ i ] . base = = to )
{
2008-03-24 13:57:07 -07:00
unsigned int j ;
for ( j = 0 ; j < asInterpTypeEquiv [ i ] . numEquiv ; j + + )
2007-06-28 10:47:08 -07:00
{
if ( asInterpTypeEquiv [ i ] . aEquivTypes [ j ] = = from )
{
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
}
}
}
}
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
/* Instinct function to turn on tracing */
BOOL interpTraceOn ( void )
{
2008-03-24 09:51:17 -07:00
interpTrace = true ;
2007-06-28 10:47:08 -07:00
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
/* Instinct function to turn off tracing */
BOOL interpTraceOff ( void )
{
2008-03-24 09:51:17 -07:00
interpTrace = false ;
2007-06-28 10:47:08 -07:00
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
2006-08-12 03:02:59 -07:00
/* Call stack stuff */
2007-03-31 09:03:21 -07:00
static ReturnAddressStack_t retStack [ MAX_FUNC_CALLS ] ; // Primitive stack of return addresses
static SDWORD retStackPos = - 1 ; // Current Position, always points to the last valid element
2006-08-12 03:02:59 -07:00
2007-03-31 09:03:21 -07:00
UDWORD retStackCallDepth ( void )
2006-08-12 03:02:59 -07:00
{
2007-03-31 09:03:21 -07:00
ASSERT ( retStackPos + 1 > = 0 & & retStackPos + 1 < MAX_FUNC_CALLS ,
" retStackCallDepth: wrong call depth: %d " , retStackPos + 1 ) ;
2006-09-19 09:30:50 -07:00
return ( retStackPos + 1 ) ;
}
2006-08-12 03:02:59 -07:00
2006-09-19 09:30:50 -07:00
static inline void retStackReset ( void )
{
retStackPos = - 1 ; // Beginning of the stack
}
2006-08-12 03:02:59 -07:00
2006-08-15 11:38:51 -07:00
2006-09-19 09:30:50 -07:00
static inline BOOL retStackIsEmpty ( void )
{
2008-03-24 09:51:17 -07:00
if ( retStackPos < 0 ) return true ;
return false ;
2006-08-12 03:02:59 -07:00
}
2006-09-19 09:30:50 -07:00
static inline BOOL retStackIsFull ( void )
2006-08-12 03:02:59 -07:00
{
2008-03-24 09:51:17 -07:00
if ( retStackPos > = MAX_FUNC_CALLS ) return true ;
return false ;
2006-08-12 03:02:59 -07:00
}
2006-09-19 09:30:50 -07:00
2006-11-16 06:30:29 -08:00
static BOOL retStackPush ( UDWORD CallerIndex , INTERP_VAL * ReturnAddress )
2006-08-12 03:02:59 -07:00
{
2006-09-19 09:30:50 -07:00
if ( retStackIsFull ( ) )
2006-08-12 03:02:59 -07:00
{
2006-09-19 09:30:50 -07:00
debug ( LOG_ERROR , " retStackPush(): return address stack is full " ) ;
2008-03-24 09:51:17 -07:00
return false ; // Stack full
2006-08-12 03:02:59 -07:00
}
2006-09-19 09:30:50 -07:00
retStackPos + + ;
retStack [ retStackPos ] . CallerIndex = CallerIndex ;
retStack [ retStackPos ] . ReturnAddress = ReturnAddress ;
2006-08-12 03:02:59 -07:00
2006-09-21 13:42:48 -07:00
//debug( LOG_SCRIPT, "retStackPush: Event=%i Address=%p, ", CallerIndex, ReturnAddress);
2006-08-12 03:02:59 -07:00
2008-03-24 09:51:17 -07:00
return true ;
2006-08-12 03:02:59 -07:00
}
2006-09-19 09:30:50 -07:00
2006-11-16 06:30:29 -08:00
static BOOL retStackPop ( UDWORD * CallerIndex , INTERP_VAL * * ReturnAddress )
2006-08-12 03:02:59 -07:00
{
2006-09-19 09:30:50 -07:00
if ( retStackIsEmpty ( ) )
{
debug ( LOG_ERROR , " retStackPop(): return address stack is empty " ) ;
2008-03-24 09:51:17 -07:00
return false ;
2006-09-19 09:30:50 -07:00
}
* CallerIndex = retStack [ retStackPos ] . CallerIndex ;
* ReturnAddress = retStack [ retStackPos ] . ReturnAddress ;
retStackPos - - ;
//debug( LOG_SCRIPT, "retStackPop: Event=%i Address=%p", *EventTrigIndex, *ReturnAddress);
2008-03-24 09:51:17 -07:00
return true ;
2006-08-12 09:52:37 -07:00
}
2007-02-10 07:23:47 -08:00
/* Output script call stack trace */
2007-02-14 10:29:26 -08:00
void scrOutputCallTrace ( void )
2007-02-10 07:23:47 -08:00
{
SDWORD i ;
const char * pEvent ;
2007-02-14 10:29:26 -08:00
debug ( LOG_SCRIPT , " *** Script call trace: *** " ) ;
if ( ! bInterpRunning ) {
debug ( LOG_SCRIPT , " <Interpreter is inactive> " ) ;
2007-02-10 07:23:47 -08:00
return ;
2007-02-14 10:29:26 -08:00
}
2007-02-10 07:23:47 -08:00
2007-02-14 10:29:26 -08:00
if ( psCurProg = = NULL ) {
return ;
}
2007-02-10 07:23:47 -08:00
2007-02-14 10:29:26 -08:00
debug ( LOG_SCRIPT , " %d: %s (current event) " , retStackPos + 1 , & ( last_called_script_event [ 0 ] ) ) ;
2007-02-10 07:23:47 -08:00
2007-02-14 10:29:26 -08:00
if ( psCurProg - > psDebug ! = NULL )
2007-02-10 07:23:47 -08:00
{
for ( i = retStackPos ; i > = 0 ; i - - )
{
2007-02-14 10:29:26 -08:00
if ( i = = 0 & & ! bCurCallerIsEvent ) { //if original caller is a trigger
pEvent = eventGetTriggerID ( psCurProg , retStack [ i ] . CallerIndex ) ;
2007-02-10 07:23:47 -08:00
} else {
2007-02-14 10:29:26 -08:00
pEvent = eventGetEventID ( psCurProg , retStack [ i ] . CallerIndex ) ;
2007-02-10 07:23:47 -08:00
}
2007-02-19 06:10:44 -08:00
debug ( LOG_SCRIPT , " %d: %s (return address: %p) " , i , pEvent , retStack [ i ] . ReturnAddress ) ;
2007-02-10 07:23:47 -08:00
}
}
else
{
2007-02-14 10:29:26 -08:00
debug ( LOG_SCRIPT , " <No debug information available> " ) ;
2007-02-10 07:23:47 -08:00
}
}
2007-03-31 09:03:21 -07:00
/* create a new local var environment for a new function call */
static inline void createVarEnvironment ( SCRIPT_CONTEXT * psContext , UDWORD eventIndex )
{
2007-04-01 09:22:01 -07:00
UDWORD i , callDepth = retStackCallDepth ( ) ;
UDWORD numEventVars = psContext - > psCode - > numLocalVars [ eventIndex ] ;
2007-03-31 09:03:21 -07:00
if ( numEventVars > 0 )
{
// alloc memory
2007-04-15 03:43:05 -07:00
varEnvironment [ callDepth ] = ( INTERP_VAL * ) malloc ( sizeof ( INTERP_VAL ) * numEventVars ) ;
2007-03-31 09:03:21 -07:00
// create environment
memcpy ( varEnvironment [ callDepth ] , psContext - > psCode - > ppsLocalVarVal [ eventIndex ] , sizeof ( INTERP_VAL ) * numEventVars ) ;
2007-04-01 09:22:01 -07:00
// allocate new space for strings to preserve original ones
for ( i = 0 ; i < numEventVars ; i + + )
{
if ( varEnvironment [ callDepth ] [ i ] . type = = VAL_STRING )
{
2007-04-15 03:43:05 -07:00
varEnvironment [ callDepth ] [ i ] . v . sval = ( char * ) malloc ( MAXSTRLEN ) ;
2007-04-01 09:22:01 -07:00
strcpy ( varEnvironment [ callDepth ] [ i ] . v . sval , " " ) ; //initialize
}
}
2007-03-31 09:03:21 -07:00
}
else
{
varEnvironment [ callDepth ] = NULL ;
}
}
2007-04-01 09:22:01 -07:00
static inline void destroyVarEnvironment ( SCRIPT_CONTEXT * psContext , UDWORD envIndex , UDWORD eventIndex )
2007-03-31 09:03:21 -07:00
{
2007-04-01 09:22:01 -07:00
UDWORD i ;
UDWORD numEventVars = 0 ;
if ( psContext ! = NULL )
{
numEventVars = psContext - > psCode - > numLocalVars [ eventIndex ] ;
}
2007-03-31 09:03:21 -07:00
if ( varEnvironment [ envIndex ] ! = NULL )
{
2007-04-01 09:22:01 -07:00
// deallocate string space
for ( i = 0 ; i < numEventVars ; i + + )
{
if ( varEnvironment [ envIndex ] [ i ] . type = = VAL_STRING )
{
2007-04-15 03:43:05 -07:00
free ( varEnvironment [ envIndex ] [ i ] . v . sval ) ;
2007-04-01 09:22:01 -07:00
varEnvironment [ envIndex ] [ i ] . v . sval = NULL ;
}
}
2007-04-15 03:43:05 -07:00
free ( varEnvironment [ envIndex ] ) ;
2007-06-12 10:56:34 -07:00
varEnvironment [ envIndex ] = NULL ;
2007-03-31 09:03:21 -07:00
}
}
/* Destroy all created variable environments */
static void cleanupVarEnvironments ( void )
{
UDWORD i ;
2008-03-24 13:57:07 -07:00
2007-03-31 09:03:21 -07:00
for ( i = 0 ; i < retStackCallDepth ( ) ; i + + )
{
2007-04-01 09:22:01 -07:00
destroyVarEnvironment ( NULL , i , 0 ) ;
2007-03-31 09:03:21 -07:00
}
}