/*
* Copyright (C) 1995-1997 Christopher D. Granz
*
* This header may not be removed.
*
* Refer to the file "License" included in this package for further
* information and before using any of the following.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "emerald.h"
/*
* Prototypes
*/
static bool compare_instr ( register byte ** );
/*
* Globals
*/
int iEmInterpStackSize;
int iEmVarStackSize;
EM_VALUE * pStack;
EM_VALUE * pStackEnd;
EM_VALUE * pInterpStackPos;
EM_VALUE * pVarStackBegin;
EM_VALUE * pVarStackPos;
#if 0
EM_VALUE * pStaticVars;
EM_VALUE * pStaticVarsEnd;
EM_VALUE * pStaticVarsPos;
#endif
extern struct _open_file * pOpenFiles;
/*
* Functions
*/
void stack_init( void )
{
if ( iEmInterpStackSize > 0 || iEmVarStackSize > 0 )
{
pStack = alloc_mem( sizeof( EM_VALUE )
* ( iEmInterpStackSize + iEmVarStackSize ) );
pStackEnd = ( pStack + iEmInterpStackSize
+ iEmVarStackSize - 1 );
pInterpStackPos = pStack;
pVarStackBegin = ( pStack + iEmInterpStackSize );
pVarStackPos = pVarStackBegin;
}
}
void stack_free( void )
{
struct _open_file *pOFile, *pOFileNext;
interp_stack_pop( ( pInterpStackPos - pStack ) );
var_stack_pop( ( pVarStackPos - pVarStackBegin ) );
if ( pStack != NULL )
{
free_mem( (void **) &pStack );
pStackEnd = NULL;
pInterpStackPos = NULL;
pVarStackBegin = NULL;
pVarStackPos = NULL;
}
/*
* Close any files left open.
*/
for ( pOFile = pOpenFiles; pOFile != NULL; pOFile = pOFileNext )
{
pOFileNext = pOFile->pNext;
fclose( pOFile->pFile );
free_mem( (void **) &pOFile );
}
pOpenFiles = NULL;
}
#ifdef DEBUG
static char *_get_valtype( int i )
{
switch ( i )
{
case TYPE_INT : return ( "integer" );
case TYPE_FLOAT : return ( "floating point" );
case TYPE_STRING: return ( "string" );
case TYPE_OBJECT: return ( "object" );
case TYPE_ARRAY : return ( "array" );
default : break;
}
return ( "unknown" );
}
#endif
/*
* Push a new variable onto the variable stack.
*/
void var_stack_push( register EM_VALUE *p )
{
if ( var_stack_overflow( ) == TRUE )
{
strcpy( cErrorBuf, "Interpreter: Variable stack overflow." );
/* print_error( ); */
em_abort( );
}
*pVarStackPos++ = *p;
}
/*
* Pop (delete) a number of variables off the variable stack.
*/
void var_stack_pop( register short int rsiNumber )
{
while ( rsiNumber-- > 0 )
delete_value( --pVarStackPos );
}
/*
* Reset the variable stack.
*/
void var_stack_reset( void )
{
while ( pVarStackPos >= pVarStackBegin )
delete_value( pVarStackPos-- );
pVarStackPos = pVarStackBegin;
}
/*
* Check for overflow in the variable stack.
*/
bool var_stack_overflow( void )
{
if ( pVarStackPos > pStackEnd )
return ( TRUE );
else
return ( FALSE );
}
/*
* Push a new value onto the interpreter stack.
*/
void interp_stack_push( register EM_VALUE *p )
{
if ( interp_stack_overflow( ) == TRUE )
{
strcpy( cErrorBuf, "Interpreter: Interpreter stack overflow." );
/* print_error( ); */
em_abort( );
}
*pInterpStackPos++ = *p;
}
/*
* Pop a number of values off the interpreter stack.
*/
void interp_stack_pop( register short int rsiNumber )
{
while ( rsiNumber-- > 0 )
delete_value( --pInterpStackPos );
}
/*
* Check for overflow in the interpreter stack.
*/
bool interp_stack_overflow( void )
{
if ( pInterpStackPos > pVarStackBegin )
return ( TRUE );
else
return ( FALSE );
}
void init_value( register EM_VALUE *p )
{
switch ( p->iType )
{
case TYPE_STRING :
p->u.pString = alloc_mem( sizeof( EM_STRING ) );
p->u.pString->pString = EMPTY_STRING;
break;
case TYPE_OBJECT :
p->u.pObject = alloc_mem( sizeof( EM_OBJECT ) );
p->u.pObject->pRealObject = NULL;
break;
default : break;
}
}
void delete_value( register EM_VALUE *p )
{
switch ( p->iType )
{
case TYPE_STRING :
str_free( p->u.pString->pString );
free_mem( (void **) &p->u.pString );
break;
case TYPE_ARRAY : array_free( p->u.pArray ); break;
case TYPE_OBJECT : free_mem( (void **) &p->u.pObject ); break;
default : break;
}
}
/*
* Macros for getting values (constants) off an instruction byte stream.
*/
#define GET_INT1( p ) ( *( (byte *) (p) ) )
#define GET_INT2( p ) ( *( (i2 *) (p) ) )
#define GET_INT4( p ) ( *( (i4 *) (p) ) )
#define GET_FLOAT4( p ) ( *( (f4 *) (p) ) )
#define GET_FLOAT8( p ) ( *( (f8 *) (p) ) )
/*
* Macros for moving instruction byte stream pointers.
*/
#define MOVEP_1( p ) ( (p)++ )
#define MOVEP_2( p ) ( (p) += sizeof( i2 ) )
#define MOVEP_4( p ) ( (p) += sizeof( i4 ) )
#define MOVEP_8( p ) ( (p) += sizeof( f8 ) )
/*
* Main interpreter function; executes one instruction byte code.
*/
#define p2 ( pInterpStackPos - 1 )
byte *interpret_instruction( byte *pInstrStream )
{
EM_VALUE v = { 0, { NULL } };
register EM_VALUE *p;
/* register EM_ARRAY *pArray; */
register long rl = 0L;
register long rl2 = 0L;
#if 0
{
struct timeval tTime;
if ( gettimeofday( &tTime, NULL ) < 0 )
sap_fatal( "Get time: %s.", strerror( errno ) );
if ( (time_t) tTime.tv_sec >= tEmTimer )
{
return ( ++pInsterStream );
}
}
#endif
switch ( *pInstrStream++ )
{
case INSTR_END : break;
case INSTR_NEW_INT :
v.iType = TYPE_INT;
var_stack_push( &v );
break;
case INSTR_NEW_FLOAT :
v.iType = TYPE_FLOAT;
var_stack_push( &v );
break;
case INSTR_NEW_STRING :
v.iType = TYPE_STRING;
init_value( &v );
var_stack_push( &v );
break;
case INSTR_NEW_OBJECT :
v.iType = TYPE_OBJECT;
init_value( &v );
var_stack_push( &v );
break;
case INSTR_NEW_ARRAY :
v.iType = TYPE_ARRAY;
v.u.pArray = NULL;
var_stack_push( &v );
break;
case INSTR_PUSH_ZERO :
v.iType = TYPE_INT;
v.u.lInt = 0L;
interp_stack_push( &v );
break;
case INSTR_PUSH_ONE :
v.iType = TYPE_INT;
v.u.lInt = 1L;
interp_stack_push( &v );
break;
case INSTR_PUSH_INT1 :
v.iType = TYPE_INT;
v.u.lInt = GET_INT1( pInstrStream );
MOVEP_1( pInstrStream );
interp_stack_push( &v );
break;
case INSTR_PUSH_INT2 :
v.iType = TYPE_INT;
v.u.lInt = GET_INT2( pInstrStream );
MOVEP_2( pInstrStream );
interp_stack_push( &v );
break;
case INSTR_PUSH_INT4 :
v.iType = TYPE_INT;
v.u.lInt = GET_INT4( pInstrStream );
MOVEP_4( pInstrStream );
interp_stack_push( &v );
break;
case INSTR_PUSH_FLOAT4 :
v.iType = TYPE_FLOAT;
v.u.dFloat = GET_FLOAT4( pInstrStream );
MOVEP_4( pInstrStream );
interp_stack_push( &v );
break;
case INSTR_PUSH_FLOAT8 :
v.iType = TYPE_FLOAT;
v.u.dFloat = GET_FLOAT8( pInstrStream );
MOVEP_8( pInstrStream );
interp_stack_push( &v );
break;
case INSTR_PUSH_STRING :
/* First we need to get the string length. */
rl = GET_INT2( pInstrStream );
MOVEP_2( pInstrStream );
v.iType = TYPE_STRING;
init_value( &v );
v.u.pString->sLength = rl;
v.u.pString->pString = alloc_mem( rl + 1 );
for ( rl2 = 0L; rl2 < rl; rl2++, MOVEP_1( pInstrStream ) )
(v.u.pString->pString)[rl2] = GET_INT1( pInstrStream );
(v.u.pString->pString)[rl2] = '\0';
interp_stack_push( &v );
break;
case INSTR_PUSH_LOCAL :
rl = GET_INT2( pInstrStream );
MOVEP_2( pInstrStream );
switch ( ( p = ( pVarStackBegin + rl ) )->iType )
{
case TYPE_INT :
v.iType = TYPE_INT;
v.u.lInt = p->u.lInt;
break;
case TYPE_FLOAT :
v.iType = TYPE_FLOAT;
v.u.dFloat = p->u.dFloat;
break;
case TYPE_STRING :
v.iType = TYPE_STRING;
init_value( &v );
v.u.pString->sLength = p->u.pString->sLength;
v.u.pString->pString = str_dup( p->u.pString->pString );
break;
case TYPE_OBJECT :
v.iType = TYPE_OBJECT;
init_value( &v );
*v.u.pObject = *p->u.pObject;
break;
case TYPE_ARRAY :
v.iType = TYPE_ARRAY;
v.u.pArray = array_copy( p->u.pArray );
break;
}
interp_stack_push( &v );
break;
case INSTR_PUSH_INDEX :
p = ( pInterpStackPos - 2 );
if ( p->u.pArray == NULL )
{
strcpy( cErrorBuf, "Interpreter: "
"Attemp to access non-existent array." );
/* print_error( ); */
em_abort( );
}
if ( ( rl = p2->u.lInt ) < 0 || rl >= p->u.pArray->sSize )
{
strcpy( cErrorBuf, "Interpreter: "
"Attemp to access non-existent array element." );
/* print_error( ); */
em_abort( );
}
switch ( ( p->u.pArray->pElements + rl )->iType )
{
case TYPE_INT :
v.iType = TYPE_INT;
v.u.lInt = ( p->u.pArray->pElements + rl )->u.lInt;
break;
case TYPE_FLOAT :
v.iType = TYPE_FLOAT;
v.u.dFloat = ( p->u.pArray->pElements + rl )->u.dFloat;
break;
case TYPE_STRING :
v.iType = TYPE_STRING;
init_value( &v );
v.u.pString->sLength = ( p->u.pArray->pElements
+ rl )->u.pString->sLength;
v.u.pString->pString = str_dup( ( p->u.pArray->pElements
+ rl )->u.pString->pString );
break;
case TYPE_OBJECT :
v.iType = TYPE_OBJECT;
init_value( &v );
*v.u.pObject = *( p->u.pArray->pElements
+ rl )->u.pObject;
break;
case TYPE_ARRAY :
v.iType = TYPE_ARRAY;
v.u.pArray = array_copy( ( p->u.pArray->pElements
+ rl )->u.pArray );
break;
}
interp_stack_pop( 2 );
interp_stack_push( &v );
break;
case INSTR_POP : interp_stack_pop( 1 ); break;
case INSTR_ASSIGN_LOCAL :
rl = GET_INT2( pInstrStream );
MOVEP_2( pInstrStream );
switch ( ( p = ( pVarStackBegin + rl ) )->iType )
{
case TYPE_INT :
p->u.lInt = p2->u.lInt;
break;
case TYPE_FLOAT :
p->u.dFloat = p2->u.dFloat;
break;
case TYPE_STRING :
str_free( p->u.pString->pString );
p->u.pString->sLength = p2->u.pString->sLength;
p->u.pString->pString = str_dup( p2->u.pString->pString );
break;
case TYPE_OBJECT :
*p->u.pObject = *p2->u.pObject;
break;
case TYPE_ARRAY :
delete_value( p );
p->u.pArray = array_copy( p2->u.pArray );
break;
}
interp_stack_pop( 1 );
break;
case INSTR_ASSIGN_INDEX :
p = ( pInterpStackPos - 3 );
if ( p->u.pArray == NULL )
{
strcpy( cErrorBuf, "Interpreter: "
"Attemp to access non-existent array." );
/* print_error( ); */
em_abort( );
}
if ( ( rl = ( pInterpStackPos - 2 )->u.lInt ) < 0
|| rl >= p->u.pArray->sSize )
{
strcpy( cErrorBuf, "Interpreter: "
"Attemp to access non-existent array element." );
/* print_error( ); */
em_abort( );
}
switch ( ( p->u.pArray->pElements + rl )->iType )
{
case TYPE_INT :
( p->u.pArray->pElements + rl )->u.lInt = p2->u.lInt;
break;
case TYPE_FLOAT :
( p->u.pArray->pElements + rl )->u.dFloat = p2->u.dFloat;
break;
case TYPE_STRING :
str_free( ( p->u.pArray->pElements
+ rl )->u.pString->pString );
( p->u.pArray->pElements + rl )->u.pString->sLength
= p2->u.pString->sLength;
( p->u.pArray->pElements + rl )->u.pString->pString
= str_dup( p2->u.pString->pString );
break;
case TYPE_OBJECT :
*( p->u.pArray->pElements + rl )->u.pObject
= *p2->u.pObject;
break;
case TYPE_ARRAY :
delete_value( ( p->u.pArray->pElements + rl ) );
( p->u.pArray->pElements + rl )->u.pArray
= array_copy( p2->u.pArray );
break;
}
interp_stack_pop( 2 );
break;
case INSTR_MULTIPLY :
switch ( ( p = ( pInterpStackPos - 2 ) )->iType )
{
case TYPE_INT :
p->u.lInt *= p2->u.lInt;
break;
case TYPE_FLOAT :
p->u.dFloat *= p2->u.dFloat;
break;
}
interp_stack_pop( 1 );
break;
case INSTR_DIVIDE :
switch ( ( p = ( pInterpStackPos - 2 ) )->iType )
{
case TYPE_INT :
p->u.lInt /= p2->u.lInt;
break;
case TYPE_FLOAT :
p->u.dFloat /= p2->u.dFloat;
break;
}
interp_stack_pop( 1 );
break;
case INSTR_MODULUS :
( pInterpStackPos - 2 )->u.lInt %= p2->u.lInt;
interp_stack_pop( 1 );
break;
case INSTR_ADD :
switch ( ( p = ( pInterpStackPos - 2 ) )->iType )
{
case TYPE_INT :
p->u.lInt += p2->u.lInt;
break;
case TYPE_FLOAT :
p->u.dFloat += p2->u.dFloat;
break;
case TYPE_STRING :
{
char *pStr = p->u.pString->pString;
char *pStr2 = p2->u.pString->pString;
if ( pStr == EMPTY_STRING )
{
p->u.pString->sLength = p2->u.pString->sLength;
p->u.pString->pString = str_dup( pStr2 );
}
else
{
p->u.pString->pString = realloc_mem( pStr,
strlen( pStr )
+ strlen( pStr2 ) + 1 );
strcat( pStr, pStr2 );
p->u.pString->sLength = strlen( pStr );
}
}
break;
}
interp_stack_pop( 1 );
break;
case INSTR_SUBTRACT :
switch ( ( p = ( pInterpStackPos - 2 ) )->iType )
{
case TYPE_INT :
p->u.lInt -= p2->u.lInt;
break;
case TYPE_FLOAT :
p->u.dFloat -= p2->u.dFloat;
break;
}
interp_stack_pop( 1 );
break;
case INSTR_LSHIFT :
( pInterpStackPos - 2 )->u.lInt <<= p2->u.lInt;
interp_stack_pop( 1 );
break;
case INSTR_RSHIFT :
( pInterpStackPos - 2 )->u.lInt >>= p2->u.lInt;
interp_stack_pop( 1 );
break;
case INSTR_AND :
( pInterpStackPos - 2 )->u.lInt &= p2->u.lInt;
interp_stack_pop( 1 );
break;
case INSTR_XOR :
( pInterpStackPos - 2 )->u.lInt ^= p2->u.lInt;
interp_stack_pop( 1 );
break;
case INSTR_OR :
( pInterpStackPos - 2 )->u.lInt |= p2->u.lInt;
interp_stack_pop( 1 );
break;
case INSTR_ONES_COMPLEMENT :
p2->u.lInt = ~( p2->u.lInt );
break;
case INSTR_JUMP :
pInstrStream += GET_INT2( pInstrStream );
MOVEP_2( pInstrStream );
break;
case INSTR_COMPARE :
rl = GET_INT2( pInstrStream );
MOVEP_2( pInstrStream );
if ( compare_instr( &pInstrStream ) == TRUE )
pInstrStream += rl;
{
EM_VALUE *pInterpSav = pInterpStackPos;
EM_VALUE *pVarSav = pVarStackPos;
while ( *pInstrStream != INSTR_END )
pInstrStream = interpret_instruction( pInstrStream );
pInstrStream++; /* Skip past END instruction. */
interp_stack_pop( ( pInterpStackPos - pInterpSav ) );
var_stack_pop( ( pVarStackPos - pVarSav ) );
}
break;
case INSTR_CALL_BUILTIN_FUNC :
rl = p2->u.lInt;
interp_stack_pop( 1 );
/*
* Would be nice to do all this stuff in the error checker but
* we can't because the function index is taken off the stack
* and not off the instruction stream (thus it may be different
* each time.)
*/
for ( rl2 = 0L; emefCFuncTable[rl2].pName != NULL; rl2++ );
if ( rl < 0 || rl >= rl2 )
{
strcpy( cErrorBuf, "Interpreter: "
"Attemp to call non-existent builtin function." );
/* print_error( ); */
em_abort( );
}
rl2 = 0L;
rl2 = GET_INT1( pInstrStream );
MOVEP_1( pInstrStream );
/*
* If the number of arguments is less then 0, the builtin
* function will deal with the type checking (this is so a
* variable number of arguments is possible.)
*/
if ( emefCFuncTable[rl].iNumArgs < 0 )
{
for ( rl2 = 0L; rl2 < emefCFuncTable[rl].iNumArgs; rl2++ )
MOVEP_1( pInstrStream );
}
else
{
if ( rl2 != emefCFuncTable[rl].iNumArgs )
{
strcpy( cErrorBuf, "Interpreter: Builtin "
"function does not conform to predefined prototype." );
/* print_error( ); */
em_abort( );
}
for ( rl2 = 0L; rl2 < emefCFuncTable[rl].iNumArgs; rl2++ )
{
if ( emefCFuncTable[rl].iArgTypes[rl2]
!= (signed int) GET_INT1( pInstrStream ) )
{
strcpy( cErrorBuf, "Interpreter: Builtin function "
"does not conform to predefined prototype." );
/* print_error( ); */
em_abort( );
}
MOVEP_1( pInstrStream );
}
}
rl2 = 0L;
rl2 = GET_INT1( pInstrStream );
MOVEP_1( pInstrStream );
/*
* If the number of return values is less then 0, the
* builtin function will deal with the type checking (this
* is so a variable number of return values is possible.)
*/
if ( emefCFuncTable[rl].iNumReturn < 0 )
{
for ( rl2 = 0L; rl2 < emefCFuncTable[rl].iNumReturn; rl2++ )
MOVEP_1( pInstrStream );
}
else
{
if ( rl2 != emefCFuncTable[rl].iNumReturn )
{
strcpy( cErrorBuf, "Interpreter: Builtin "
"function does not conform to predefined prototype." );
/* print_error( ); */
em_abort( );
}
for ( rl2 = 0L; rl2 < emefCFuncTable[rl].iNumReturn; rl2++ )
{
if ( emefCFuncTable[rl].iReturnTypes[rl2]
!= (signed int) GET_INT1( pInstrStream ) )
{
strcpy( cErrorBuf, "Interpreter: Builtin function "
"does not conform to predefined prototype." );
/* print_error( ); */
em_abort( );
}
MOVEP_1( pInstrStream );
}
}
( *emefCFuncTable[rl].pFunc ) ( );
break;
case INSTR_CALL_FUNC :
{
EM_VALUE *pOldVarStackBegin;
EM_VALUE *pOldVarStackPos;
byte *pNewStream;
/*
* Make sure the function trying to be called actaully
* exists.
*/
rl = p2->u.lInt;
interp_stack_pop( 1 );
if ( rl < 0 || rl > siTopFuncIndex )
{
strcpy( cErrorBuf, "Interpreter: "
"Attemp to call non-existent user function." );
/* print_error( ); */
em_abort( );
}
/*
* Calling of dynamicly loaded functions from code is not
* allowed.
*/
if ( ppFuncs[rl]->bDynamic == TRUE )
{
strcpy( cErrorBuf, "Interpreter: "
"Attemp to call dynamicly loaded user function." );
/* print_error( ); */
em_abort( );
}
/*
* Compare call to real function. We abort if they don't
* match.
*/
rl2 = GET_INT1( pInstrStream );
MOVEP_1( pInstrStream );
if ( rl2 != ppFuncs[rl]->iNumArgs )
{
strcpy( cErrorBuf, "Interpreter: User function "
"does not conform to predefined prototype." );
/* print_error( ); */
em_abort( );
}
for ( rl2 = 0L; rl2 < ppFuncs[rl]->iNumArgs; rl2++ )
{
if ( ppFuncs[rl]->pArgTypes[rl2]
!= (signed int) GET_INT1( pInstrStream ) )
{
strcpy( cErrorBuf, "Interpreter: User function "
"does not conform to predefined prototype." );
/* print_error( ); */
em_abort( );
}
MOVEP_1( pInstrStream );
}
rl2 = 0L;
rl2 = GET_INT1( pInstrStream );
MOVEP_1( pInstrStream );
if ( rl2 != ppFuncs[rl]->iNumReturn )
{
strcpy( cErrorBuf, "Interpreter: User function "
"does not conform to predefined prototype." );
/* print_error( ); */
em_abort( );
}
for ( rl2 = 0L; rl2 < ppFuncs[rl]->iNumReturn; rl2++ )
{
if ( ppFuncs[rl]->pReturnTypes[rl2]
!= (signed int) GET_INT1( pInstrStream ) )
{
strcpy( cErrorBuf, "Interpreter: User function "
"does not conform to predefined prototype." );
/* print_error( ); */
em_abort( );
}
MOVEP_1( pInstrStream );
}
/*
* We shift the variable stack so variable references
* in the called function's code end up referencing the
* right place.
*/
pOldVarStackBegin = pVarStackBegin;
pOldVarStackPos = pVarStackPos;
pVarStackBegin = pVarStackPos;
pNewStream = ppFuncs[rl]->pInstrStream;
while ( *pNewStream != INSTR_END )
pNewStream = interpret_instruction( pNewStream );
var_stack_pop( ( pVarStackPos - pOldVarStackPos ) );
pVarStackBegin = pOldVarStackBegin;
pVarStackPos = pOldVarStackPos;
}
break;
/*
* If the error checker worked right and a bad pointer didn't
* currupted the byte stream, this should NEVER happen.
*/
default :
sprintf( cErrorBuf,
"Interpreter: Illegal instruction (0x%.2X).",
(int) *--pInstrStream );
/* print_error( ); */
*pInstrStream = INSTR_END; /* Don't let this happen again. */
em_abort( );
break;
}
return ( pInstrStream );
}
#undef p2
/*
* Compares two values.
*/
#define p ( pInterpStackPos - 1 )
#define p2 ( pInterpStackPos - 2 )
static bool compare_instr( register byte **ppInstrStream )
{
register bool rbTrue = FALSE;
switch ( p->iType )
{
case TYPE_INT :
switch ( *( *ppInstrStream++ ) )
{
case COND_EQUAL :
if ( p2->u.lInt == p->u.lInt )
rbTrue = TRUE;
break;
case COND_NOT_EQUAL :
if ( p2->u.lInt != p->u.lInt )
rbTrue = TRUE;
break;
case COND_GREATER :
if ( p2->u.lInt > p->u.lInt )
rbTrue = TRUE;
break;
case COND_LESS :
if ( p2->u.lInt < p->u.lInt )
rbTrue = TRUE;
break;
case COND_GREATER_OR_EQUAL:
if ( p2->u.lInt >= p->u.lInt )
rbTrue = TRUE;
break;
case COND_LESS_OR_EQUAL :
if ( p2->u.lInt <= p->u.lInt )
rbTrue = TRUE;
break;
}
break;
case TYPE_FLOAT :
switch ( *( *ppInstrStream++ ) )
{
case COND_EQUAL :
if ( p2->u.dFloat == p->u.dFloat )
rbTrue = TRUE;
break;
case COND_NOT_EQUAL :
if ( p2->u.dFloat != p->u.dFloat )
rbTrue = TRUE;
break;
case COND_GREATER :
if ( p2->u.dFloat > p->u.dFloat )
rbTrue = TRUE;
break;
case COND_LESS :
if ( p2->u.dFloat < p->u.dFloat )
rbTrue = TRUE;
break;
case COND_GREATER_OR_EQUAL:
if ( p2->u.dFloat >= p->u.dFloat )
rbTrue = TRUE;
break;
case COND_LESS_OR_EQUAL :
if ( p2->u.dFloat <= p->u.dFloat )
rbTrue = TRUE;
break;
}
break;
case TYPE_STRING:
switch ( *( *ppInstrStream++ ) )
{
case COND_EQUAL :
if ( strcmp( p2->u.pString->pString,
p->u.pString->pString ) == 0 )
rbTrue = TRUE;
break;
case COND_NOT_EQUAL :
if ( strcmp( p2->u.pString->pString,
p->u.pString->pString ) != 0 )
rbTrue = TRUE;
break;
}
break;
case TYPE_OBJECT:
switch ( *( *ppInstrStream++ ) )
{
case COND_EQUAL :
if ( p2->u.pObject->pRealObject
== p->u.pObject->pRealObject )
rbTrue = TRUE;
break;
case COND_NOT_EQUAL :
if ( p2->u.pObject->pRealObject
!= p->u.pObject->pRealObject )
rbTrue = TRUE;
break;
}
break;
}
interp_stack_pop( 2 );
return ( rbTrue );
}
#undef p
#undef p2
#undef GET_INT1
#undef GET_INT2
#undef GET_INT4
#undef GET_FLOAT4
#undef GET_FLOAT8
#undef MOVEP_1
#undef MOVEP_2
#undef MOVEP_4
#undef MOVEP_8
/*
* End of interp.c
*/