/* * 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 <stdlib.h> #include <ctype.h> #include <string.h> #include <time.h> #include "emerald.h" /* * Structures */ typedef struct _fake_value { intt iType; int iArrayDimensions; intt iArrayFinalType; } fake_value; /* * Prototypes */ static void fake_var_stack_push ( fake_value * ); static void fake_var_stack_pop ( short int ); static bool fake_var_stack_overflow ( void ); static int fake_var_stack_usage ( void ); static void fake_interp_stack_push ( fake_value * ); static void fake_interp_stack_pop ( short int ); static bool fake_interp_stack_overflow ( void ); static int fake_interp_stack_usage ( void ); /* * Globals */ char cErrorBuf[1024]; int iEmError; jmp_buf jbAbortJump; static FILE * pUsageFile; static fake_value * pFakeStack; static fake_value * pFakeStackEnd; static fake_value * pFakeInterpStackPos; static fake_value * pFakeVarStackBegin; static fake_value * pFakeVarStackPos; extern int iCurrentFunc; extern char *** pppSymbolTable; /* * Functions */ void print_error( void ) { int i; for ( i = 0; cErrorBuf[i] != '\0'; i++ ) { if ( i == 75 ) { while ( cErrorBuf[i] != ' ' ) { if ( i == 0 ) { /* fprintf( stderr, "\nNo spaces in log string.\n" ); */ break; } i--; } cErrorBuf[i] = '\n'; break; } } lprintf( "**** [EMERALD]:\n %s", cErrorBuf ); } /* * Used to setup a timer for a time limit on the Emerald Interpreter. */ void em_set_timer( int iMilSec ) { struct itimerval itv; itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 0; itv.it_value.tv_sec = 0; itv.it_value.tv_usec = iMilSec; if ( setitimer( ITIMER_PROF, &itv, NULL ) < 0 ) sap_fatal( "Set timer: %s.", strerror( errno ) ); } void em_clear_timer( void ) { struct itimerval itv; itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 0; itv.it_value.tv_sec = 0; itv.it_value.tv_usec = 0; if ( setitimer( ITIMER_PROF, &itv, NULL ) < 0 ) sap_fatal( "Set timer: %s.", strerror( errno ) ); } /* * Proforms all byte code error checking. */ void error_check( void ) { fake_value fv; byte *p; int i; if ( ppFuncs == NULL ) return; if ( bEmFuncUsage == TRUE && ( pUsageFile = fopen( pEmUsageFilename, "w" ) ) == NULL ) { sprintf( cErrorBuf, "Open file: %s: %s.", pEmUsageFilename, strerror( errno ) ); print_error( ); bEmFuncUsage = FALSE; } /* * Init the fake stacks. */ if ( iEmInterpStackSize > 0 || iEmVarStackSize > 0 ) { pFakeStack = alloc_mem( sizeof( fake_value ) * ( iEmInterpStackSize + iEmVarStackSize ) ); pFakeStackEnd = ( pFakeStack + iEmInterpStackSize + iEmVarStackSize - 1 ); pFakeInterpStackPos = pFakeStack; pFakeVarStackBegin = ( pFakeStack + iEmInterpStackSize ); pFakeVarStackPos = pFakeVarStackBegin; } iEmError = 0; for ( iCurrentFunc = 0; iCurrentFunc <= siTopFuncIndex; iCurrentFunc++ ) { if ( bEmFuncUsage == TRUE ) fprintf( pUsageFile, "%s() uses:\n", ppFuncs[iCurrentFunc]->pName ); /* * Push some fake arguments on the fake interpreter stack. * Nothing in error_check() is "real" ;) */ for ( i = 0; i < ppFuncs[iCurrentFunc]->iNumArgs; i++ ) { fv.iType = ppFuncs[iCurrentFunc]->pArgTypes[i]; fv.iArrayDimensions = ppFuncs[iCurrentFunc]->pArgArrayDim[i]; fv.iArrayFinalType = ppFuncs[iCurrentFunc]->pArgArrayTypes[i]; fake_interp_stack_push( &fv ); } p = ppFuncs[iCurrentFunc]->pInstrStream; while ( ( p - ppFuncs[iCurrentFunc]->pInstrStream ) < ppFuncs[iCurrentFunc]->ulCodeSize ) { p = bcec( p ); if ( iEmError < 0 ) { print_error( ); exit( 1 ); } } bcec( p ); /* Validate return arguments. */ if ( iEmError < 0 ) { print_error( ); exit( 1 ); } /* * Free the fake interpreter and variable stacks so they're * ready for the next function to use. */ fake_interp_stack_pop( fake_interp_stack_usage( ) ); fake_var_stack_pop( fake_var_stack_usage( ) ); if ( bEmFuncUsage == TRUE ) putc( '\n', pUsageFile ); } if ( pFakeStack != NULL ) free_mem( (void **) &pFakeStack ); if ( bEmFuncUsage == TRUE ) fclose( pUsageFile ); } /* * Push a new fake variable onto the fake variable stack. */ static void fake_var_stack_push( fake_value *p ) { if ( fake_var_stack_overflow( ) == TRUE ) { sprintf( cErrorBuf, "Error checker: Variable stack will overflow in %s().", ppFuncs[iCurrentFunc]->pName ); iEmError = -1; return; } *pFakeVarStackPos++ = *p; } /* * Pop (delete) a number of fake variables off the fake variable * stack. */ static void fake_var_stack_pop( short int siNumber ) { while ( siNumber-- > 0 ) --pFakeVarStackPos; } /* * Check for overflow in the fake variable stack. */ static bool fake_var_stack_overflow( void ) { if ( pFakeVarStackPos > pFakeStackEnd ) return ( TRUE ); else return ( FALSE ); } /* * Returns the number of values currently on the fake variable stack. */ static int fake_var_stack_usage( void ) { return ( ( pFakeVarStackPos - pFakeVarStackBegin ) ); } /* * Push a new value onto the fake interpreter stack. */ static void fake_interp_stack_push( fake_value *p ) { if ( fake_interp_stack_overflow( ) == TRUE ) { sprintf( cErrorBuf, "Error checker: Interpreter stack will overflow in %s().", ppFuncs[iCurrentFunc]->pName ); iEmError = -2; return; } *pFakeInterpStackPos++ = *p; } /* * Pop a number of values off the fake interpreter stack. */ static void fake_interp_stack_pop( short int siNumber ) { while ( siNumber-- > 0 ) --pFakeInterpStackPos; } /* * Check for overflow in the fake interpreter stack. */ static bool fake_interp_stack_overflow( void ) { if ( pFakeInterpStackPos > pFakeVarStackBegin ) return ( TRUE ); else return ( FALSE ); } /* * Returns the number of values currently on the fake interpreter * stack. */ static int fake_interp_stack_usage( void ) { return ( ( pFakeInterpStackPos - pFakeStack ) ); } /* * 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 ) ) /* * BCEC - Byte Code Error Check * * Examines a byte code and finds any errors. */ #define p2 ( pFakeInterpStackPos - 1 ) byte *bcec( byte *pInstrStream ) { fake_value fv = { 0, 0, 0 }; fake_value *p; long l = 0L; long l2 = 0L; long l3 = 0L; switch ( *pInstrStream++ ) { case INSTR_END : if ( fake_interp_stack_usage( ) < ppFuncs[iCurrentFunc]->iNumReturn ) { sprintf( cErrorBuf, "Error checker: " "Inconsistent number of return values in %s().", ppFuncs[iCurrentFunc]->pName ); iEmError = -3; break; } for ( l = 0L; l < ppFuncs[iCurrentFunc]->iNumReturn; l++ ) { if ( ( pFakeInterpStackPos - ( l + 1 ) )->iType != ppFuncs[iCurrentFunc]->pReturnTypes[l] ) { sprintf( cErrorBuf, "Error checker: Inconsistent return types in %s().", ppFuncs[iCurrentFunc]->pName ); iEmError = -3; break; } } break; case INSTR_NEW_INT : fv.iType = TYPE_INT; fake_var_stack_push( &fv ); break; case INSTR_NEW_FLOAT : fv.iType = TYPE_FLOAT; fake_var_stack_push( &fv ); break; case INSTR_NEW_STRING : fv.iType = TYPE_STRING; fv.iArrayFinalType = TYPE_INT; fake_var_stack_push( &fv ); break; case INSTR_NEW_OBJECT : fv.iType = TYPE_OBJECT; fake_var_stack_push( &fv ); break; case INSTR_NEW_ARRAY : fv.iType = TYPE_ARRAY; fv.iArrayDimensions = 1; fv.iArrayFinalType = GET_INT1( pInstrStream ); while ( ( fv.iArrayFinalType = GET_INT1( pInstrStream ) ) == TYPE_ARRAY ) { MOVEP_1( pInstrStream ); fv.iArrayDimensions++; } fake_var_stack_push( &fv ); break; case INSTR_PUSH_ZERO : fv.iType = TYPE_INT; fake_interp_stack_push( &fv ); break; case INSTR_PUSH_ONE : fv.iType = TYPE_INT; fake_interp_stack_push( &fv ); break; case INSTR_PUSH_INT1 : fv.iType = TYPE_INT; MOVEP_1( pInstrStream ); fake_interp_stack_push( &fv ); break; case INSTR_PUSH_INT2 : fv.iType = TYPE_INT; MOVEP_2( pInstrStream ); fake_interp_stack_push( &fv ); break; case INSTR_PUSH_INT4 : fv.iType = TYPE_INT; MOVEP_4( pInstrStream ); fake_interp_stack_push( &fv ); break; case INSTR_PUSH_FLOAT4 : fv.iType = TYPE_FLOAT; MOVEP_4( pInstrStream ); fake_interp_stack_push( &fv ); break; case INSTR_PUSH_FLOAT8 : fv.iType = TYPE_FLOAT; MOVEP_8( pInstrStream ); fake_interp_stack_push( &fv ); break; case INSTR_PUSH_STRING : fv.iType = TYPE_STRING; fv.iArrayFinalType = TYPE_INT; l = GET_INT1( pInstrStream ); MOVEP_2( pInstrStream ); pInstrStream += l; fake_interp_stack_push( &fv ); break; case INSTR_PUSH_LOCAL : l = GET_INT2( pInstrStream ); MOVEP_2( pInstrStream ); if ( ( fake_var_stack_usage( ) - 1 ) < l ) { sprintf( cErrorBuf, "Error checker: Reference " "of non-existent variable at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 3 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -4; break; } p = ( pFakeVarStackBegin + l ); fv.iType = p->iType; fv.iArrayDimensions = p->iArrayDimensions; fv.iArrayFinalType = p->iArrayFinalType; fake_interp_stack_push( &fv ); break; case INSTR_PUSH_INDEX : if ( fake_interp_stack_usage( ) < 2 ) { sprintf( cErrorBuf, "Error checker: Too few values on " "interpreter stack for operation at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 1 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -5; break; } p = ( pFakeInterpStackPos - 2 ); if ( p->iType != TYPE_STRING && p->iType != TYPE_ARRAY ) { sprintf( cErrorBuf, "Error checker: " "Index reference in non-array at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 1 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -5; break; } if ( p2->iType != TYPE_INT ) { sprintf( cErrorBuf, "Error checker: " "Index reference with wrong type at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 1 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -5; break; } if ( p->iType == TYPE_STRING ) { fv.iType = TYPE_STRING; fv.iArrayFinalType = p->iArrayFinalType; } else if ( p->iArrayDimensions > 1 ) { fv.iType = TYPE_ARRAY; fv.iArrayDimensions = ( p->iArrayDimensions - 1 ); fv.iArrayFinalType = p->iArrayFinalType; } else fv.iType = p->iArrayFinalType; fake_interp_stack_pop( 2 ); fake_interp_stack_push( &fv ); break; case INSTR_POP : if ( fake_interp_stack_usage( ) < 1 ) { sprintf( cErrorBuf, "Error checker: Too few values on " "interpreter stack for operation at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 1 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -6; break; } fake_interp_stack_pop( 1 ); break; case INSTR_ASSIGN_LOCAL : l = GET_INT2( pInstrStream ); MOVEP_2( pInstrStream ); if ( ( fake_var_stack_usage( ) - 1 ) < l ) { sprintf( cErrorBuf, "Error checker: Reference " "of non-existent variable at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 3 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -7; break; } p = ( pFakeVarStackBegin + l ); if ( fake_interp_stack_usage( ) < 1 ) { sprintf( cErrorBuf, "Error checker: Too few values on " "interpreter stack for operation at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 3 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -7; break; } if ( p->iType != p2->iType ) { sprintf( cErrorBuf, "Error checker: Incompatiable types " "in assignment at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 3 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -7; break; } p->iType = p2->iType; p->iArrayDimensions = p2->iArrayDimensions; p->iArrayFinalType = p2->iArrayFinalType; fake_interp_stack_pop( 1 ); break; case INSTR_ASSIGN_INDEX : if ( fake_interp_stack_usage( ) < 3 ) { sprintf( cErrorBuf, "Error checker: Too few values on " "interpreter stack for operation at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 1 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -8; break; } p = ( pFakeInterpStackPos - 3 ); if ( p->iType != TYPE_STRING && p->iType != TYPE_ARRAY ) { sprintf( cErrorBuf, "Error checker: " "Index reference in non-array at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 1 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -8; break; } if ( ( pFakeInterpStackPos - 2 )->iType != TYPE_INT ) { sprintf( cErrorBuf, "Error checker: " "Index reference with wrong type at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 1 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -8; break; } if ( ( p->iType == TYPE_ARRAY && ( p->iArrayDimensions > 1 ? p2->iType != TYPE_ARRAY : p->iArrayFinalType != p2->iType ) ) || ( p->iType == TYPE_STRING && p2->iType != TYPE_INT ) ) { sprintf( cErrorBuf, "Error checker: Incompatiable types " "in assignment at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 1 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -8; break; } fake_interp_stack_pop( 2 ); break; case INSTR_MULTIPLY : case INSTR_DIVIDE : case INSTR_SUBTRACT : if ( fake_interp_stack_usage( ) < 2 ) { sprintf( cErrorBuf, "Error checker: Too few values on " "interpreter stack for operation at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 1 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -9; break; } if ( ( p2->iType != TYPE_INT && p2->iType != TYPE_FLOAT ) || ( ( pFakeInterpStackPos - 2 )->iType != TYPE_INT && ( pFakeInterpStackPos - 2 )->iType != TYPE_FLOAT ) ) { sprintf( cErrorBuf, "Error checker: Illegal " "type for math instruction at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 1 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -9; break; } if ( p2->iType != ( pFakeInterpStackPos - 2 )->iType ) { sprintf( cErrorBuf, "Error checker: Incompatiable types " "in math instruction at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 1 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -9; break; } fake_interp_stack_pop( 1 ); break; case INSTR_MODULUS : case INSTR_LSHIFT : case INSTR_RSHIFT : case INSTR_AND : case INSTR_XOR : case INSTR_OR : if ( fake_interp_stack_usage( ) < 2 ) { sprintf( cErrorBuf, "Error checker: Too few values on " "interpreter stack for operation at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 1 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -10; break; } if ( p2->iType != TYPE_INT || ( pFakeInterpStackPos - 2 )->iType != TYPE_INT ) { sprintf( cErrorBuf, "Error checker: Illegal " "type for math instruction at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 1 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -10; break; } fake_interp_stack_pop( 1 ); break; case INSTR_ADD : if ( fake_interp_stack_usage( ) < 2 ) { sprintf( cErrorBuf, "Error checker: Too few values on " "interpreter stack for operation at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 1 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -11; break; } if ( ( p2->iType != TYPE_INT && p2->iType != TYPE_FLOAT && p2->iType != TYPE_STRING ) || ( ( pFakeInterpStackPos - 2 )->iType != TYPE_INT && ( pFakeInterpStackPos - 2 )->iType != TYPE_FLOAT && ( pFakeInterpStackPos - 2 )->iType != TYPE_STRING ) ) { sprintf( cErrorBuf, "Error checker: Illegal " "type for math instruction at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 1 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -11; break; } if ( p2->iType != ( pFakeInterpStackPos - 2 )->iType ) { sprintf( cErrorBuf, "Error checker: Incompatiable types " "in math instruction at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 1 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -11; break; } fake_interp_stack_pop( 1 ); break; case INSTR_ONES_COMPLEMENT : if ( fake_interp_stack_usage( ) < 1 ) { sprintf( cErrorBuf, "Error checker: Too few values on " "interpreter stack for operation at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 1 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -12; break; } if ( p2->iType != TYPE_INT ) { sprintf( cErrorBuf, "Error checker: Illegal " "type for math instruction at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 1 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -12; break; } break; case INSTR_JUMP : /* We don't do jumps in the error checker. */ l = GET_INT2( pInstrStream ); MOVEP_2( pInstrStream ); if ( l < 0 ) { if ( -l > ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream ) ) goto jmp_instr_error; } else { if ( l > ( ppFuncs[iCurrentFunc]->ulCodeSize - 1 ) ) goto jmp_instr_error; } break; jmp_instr_error: sprintf( cErrorBuf, "Error checker: Jump " "instruction points out of bounds at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 2 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -13; break; case INSTR_COMPARE : if ( fake_interp_stack_usage( ) < 2 ) { sprintf( cErrorBuf, "Error checker: Too few values on " "interpreter stack for operation at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 1 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -14; break; } if ( ( pFakeInterpStackPos - 2 )->iType != p2->iType || p2->iType == TYPE_ARRAY /* Arrays can't be compared. */ ) { sprintf( cErrorBuf, "Error checker: Incompatible " "types for compare instruction at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 1 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -14; break; } l = GET_INT2( pInstrStream ); MOVEP_2( pInstrStream ); if ( l < 0 ) goto jmp_instr_error; /* No backward jumps with compare. */ else { if ( l > ( ppFuncs[iCurrentFunc]->ulCodeSize - 1 ) ) goto jmp_instr_error; } switch ( GET_INT1( pInstrStream ) ) { case COND_EQUAL : case COND_NOT_EQUAL : break; case COND_GREATER : case COND_LESS : case COND_GREATER_OR_EQUAL: case COND_LESS_OR_EQUAL : if ( p2->iType != TYPE_INT && p2->iType != TYPE_FLOAT ) { sprintf( cErrorBuf, "Error checker: " "Illegal conditional type at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 3 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -14; return ( pInstrStream ); } break; default : sprintf( cErrorBuf, "Error checker: " "Unknown conditional type at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 3 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -14; return ( pInstrStream ); } MOVEP_1( pInstrStream ); { fake_value *pInterpSav = pFakeInterpStackPos; fake_value *pVarSav = pFakeVarStackPos; byte *pInstrSav = pInstrStream; while ( *pInstrStream != INSTR_END ) pInstrStream = bcec( pInstrStream ); pInstrStream++; /* Skip past END instruction. */ fake_interp_stack_pop( ( pFakeInterpStackPos - pInterpSav ) ); fake_var_stack_pop( ( pFakeVarStackPos - pVarSav ) ); if ( ( pInstrStream - pInstrSav ) < l ) { pInterpSav = pFakeInterpStackPos; pVarSav = pFakeVarStackPos; while ( *pInstrStream != INSTR_END ) pInstrStream = bcec( pInstrStream ); pInstrStream++; /* Skip past END instruction. */ fake_interp_stack_pop( ( pFakeInterpStackPos - pInterpSav ) ); fake_var_stack_pop( ( pFakeVarStackPos - pVarSav ) ); } } break; case INSTR_CALL_BUILTIN_FUNC : if ( fake_interp_stack_usage( ) < 1 ) { sprintf( cErrorBuf, "Error checker: Too few values on " "interpreter stack for operation at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 1 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -15; break; } fake_interp_stack_pop( 1 ); l = GET_INT1( pInstrStream ); MOVEP_1( pInstrStream ); if ( fake_interp_stack_usage( ) < l ) { sprintf( cErrorBuf, "Error checker: Too few arguments " "in call to builtin function at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 2 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -15; break; } for ( l2 = 2L, l3 = 1L; l > 0L; l--, l2++, l3++ ) { fv.iArrayDimensions = -1; fv.iArrayFinalType = 0; do { fv.iType = GET_INT1( pInstrStream ); MOVEP_1( pInstrStream ); l2++; fv.iArrayDimensions++; } while ( fv.iType == TYPE_ARRAY ); switch ( fv.iType ) { case TYPE_INT : case TYPE_FLOAT : case TYPE_STRING: case TYPE_OBJECT: break; default : sprintf( cErrorBuf, "Error checker: " "Unknown variable type at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - l2 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -15; return ( pInstrStream ); } if ( fv.iArrayDimensions > 0 ) { fv.iArrayFinalType = fv.iType; fv.iType = TYPE_ARRAY; } else if ( fv.iType == TYPE_STRING ) fv.iArrayFinalType = TYPE_INT; p = ( pFakeInterpStackPos - l3 ); if ( p->iType != fv.iType || p->iArrayDimensions != fv.iArrayDimensions || p->iArrayFinalType != fv.iArrayFinalType ) { sprintf( cErrorBuf, "Error checker: Incompatible type " "in passing to builtin function at offset %ld " "in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - l2 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -15; return ( pInstrStream ); } } l = 0L; l = GET_INT1( pInstrStream ); MOVEP_1( pInstrStream ); for ( l2++; l > 0L; l--, l2++ ) { fv.iArrayDimensions = -1; fv.iArrayFinalType = 0; do { fv.iType = GET_INT1( pInstrStream ); MOVEP_1( pInstrStream ); l2++; fv.iArrayDimensions++; } while ( fv.iType == TYPE_ARRAY ); switch ( fv.iType ) { case TYPE_INT : case TYPE_FLOAT : case TYPE_STRING: case TYPE_OBJECT: break; default : sprintf( cErrorBuf, "Error checker: " "Unknown variable type at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - l2 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -15; return ( pInstrStream ); } if ( fv.iArrayDimensions > 0 ) { fv.iArrayFinalType = fv.iType; fv.iType = TYPE_ARRAY; } else if ( fv.iType == TYPE_STRING ) fv.iArrayFinalType = TYPE_INT; fake_interp_stack_push( &fv ); } break; case INSTR_CALL_FUNC : if ( fake_interp_stack_usage( ) < 1 ) { sprintf( cErrorBuf, "Error checker: Too few values on " "interpreter stack for operation at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 1 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -16; break; } fake_interp_stack_pop( 1 ); l = GET_INT1( pInstrStream ); MOVEP_1( pInstrStream ); if ( fake_interp_stack_usage( ) < l ) { sprintf( cErrorBuf, "Error checker: Too few arguments " "in call to user function at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - 2 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -16; break; } for ( l2 = 2L, l3 = 1L; l > 0L; l--, l2++, l3++ ) { fv.iArrayDimensions = -1; fv.iArrayFinalType = 0; do { fv.iType = GET_INT1( pInstrStream ); MOVEP_1( pInstrStream ); l2++; fv.iArrayDimensions++; } while ( fv.iType == TYPE_ARRAY ); switch ( fv.iType ) { case TYPE_INT : case TYPE_FLOAT : case TYPE_STRING: case TYPE_OBJECT: break; default : sprintf( cErrorBuf, "Error checker: " "Unknown variable type at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - l2 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -16; return ( pInstrStream ); } if ( fv.iArrayDimensions > 0 ) { fv.iArrayFinalType = fv.iType; fv.iType = TYPE_ARRAY; } else if ( fv.iType == TYPE_STRING ) fv.iArrayFinalType = TYPE_INT; p = ( pFakeInterpStackPos - l3 ); if ( p->iType != fv.iType || p->iArrayDimensions != fv.iArrayDimensions || p->iArrayFinalType != fv.iArrayFinalType ) { sprintf( cErrorBuf, "Error checker: Incompatible type " "in passing to user function at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - l2 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -16; return ( pInstrStream ); } } l = 0L; l = GET_INT1( pInstrStream ); MOVEP_1( pInstrStream ); for ( l2++; l > 0L; l--, l2++ ) { fv.iArrayDimensions = -1; fv.iArrayFinalType = 0; do { fv.iType = GET_INT1( pInstrStream ); MOVEP_1( pInstrStream ); l2++; fv.iArrayDimensions++; } while ( fv.iType == TYPE_ARRAY ); switch ( fv.iType ) { case TYPE_INT : case TYPE_FLOAT : case TYPE_STRING: case TYPE_OBJECT: break; default : sprintf( cErrorBuf, "Error checker: " "Unknown variable type at offset %ld in %s().", (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream - l2 ), ppFuncs[iCurrentFunc]->pName ); iEmError = -16; return ( pInstrStream ); } if ( fv.iArrayDimensions > 0 ) { fv.iArrayFinalType = fv.iType; fv.iType = TYPE_ARRAY; } else if ( fv.iType == TYPE_STRING ) fv.iArrayFinalType = TYPE_INT; fake_interp_stack_push( &fv ); } break; case TRANS_BUILTIN_FUNC : if ( bEmFuncUsage == TRUE ) fprintf( pUsageFile, " Builtin %s();\n", pppSymbolTable[ppFuncs[iCurrentFunc]->siFileNumber] [GET_INT2( pInstrStream )] ); MOVEP_2( pInstrStream ); fv.iType = TYPE_INT; fake_interp_stack_push( &fv ); break; case TRANS_FUNC : if ( bEmFuncUsage == TRUE ) fprintf( pUsageFile, " User %s();\n", pppSymbolTable[ppFuncs[iCurrentFunc]->siFileNumber] [GET_INT2( pInstrStream )] ); MOVEP_2( pInstrStream ); fv.iType = TYPE_INT; fake_interp_stack_push( &fv ); break; default : sprintf( cErrorBuf, "Error checker: " "Illegal instruction (0x%.2X) at offset %ld in %s().", (int) *--pInstrStream, (long) ( pInstrStream - ppFuncs[iCurrentFunc]->pInstrStream ), ppFuncs[iCurrentFunc]->pName ); iEmError = -17; break; } return ( pInstrStream ); } #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 error.c */