/* * 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 <string.h> #include <ctype.h> #include <errno.h> #include "emi.h" /* * Globals */ char cNullChar; int iInterpStackSize; int iVarStackSize; bool bReportFuncUsage; char * pUsageFilename; short int siCurrentFileNumber; char *** pppSymbolTable; EM_FUNC ** ppFuncs; short int siTopFuncIndex; #if 0 extern EM_VALUE * pStaticVars; extern EM_VALUE * pStaticVarsEnd; extern EM_VALUE * pStaticVarsPos; #endif int iCurrentFunc; /* * Functions */ int main( int iArgC, char *pArgV[] ) { char *pBuf; int i = 1; if ( --iArgC < 1 ) { usage: fprintf( stderr, "\nUsage: %s [-isize] [-vsize] <object files>\n", pArgV[0] ); return ( 0 ); } iInterpStackSize = 128; iVarStackSize = 64; for ( ; ; i++ ) { if ( iArgC < i ) goto usage; if ( pArgV[i][0] != '-' ) break; if ( pArgV[i][1] == 'i' ) iInterpStackSize = atoi( &pArgV[i][2] ); else if ( pArgV[i][1] == 'v' ) iVarStackSize = atoi( &pArgV[i][2] ); else { fprintf( stderr, "\nInvalid switch: `%s'.\n", pArgV[i] ); return ( 1 ); } } if ( ( pBuf = getenv( "EM_INTERP_STACK_SIZE" ) ) != NULL ) iInterpStackSize = atoi( pBuf ); if ( ( pBuf = getenv( "EM_VAR_STACK_SIZE" ) ) != NULL ) iVarStackSize = atoi( pBuf ); if ( iInterpStackSize < 1 ) { strcpy( cErrorBuf, "Start: Invalid interpreter stack size." ); print_error( ); exit( 1 ); } if ( iVarStackSize < 1 ) { strcpy( cErrorBuf, "Start: Invalid variable stack size." ); print_error( ); exit( 1 ); } for ( ; i <= iArgC; i++ ) { if ( em_load_obj_file( pArgV[i], FALSE ) < 0 ) { print_error( ); exit( 1 ); } } error_check( ); em_translate( ); if ( ( i = em_find_func( "main" ) ) < 0 ) { strcpy( cErrorBuf, "Start: Cannot find user main()." ); print_error( ); exit( 1 ); } stack_init( ); em_call_func( i ); stack_free( ); return ( 0 ); } /* * Allocates space for a function and returns it's index number. * Function space is never freed. */ int func_new( void ) { if ( ppFuncs == NULL ) ppFuncs = alloc_mem( ( sizeof( EM_FUNC * ) << 1 ) ); else ppFuncs = realloc_mem( ppFuncs, ( sizeof( EM_FUNC * ) * ( ++siTopFuncIndex + 2 ) ) ); ppFuncs[siTopFuncIndex] = alloc_mem( sizeof( EM_FUNC ) ); return ( siTopFuncIndex ); } #define _E_FREAD1_O( f, p, s ) \ if ( fread( (p), (s), 1, (f) ) == 0 ) \ { \ if ( feof( (f) ) != 0 ) \ { \ sprintf( cErrorBuf, "Loader: %s: Unexpected EOF.", \ pFilename ); \ iError = -2; \ } \ else \ { \ sprintf( cErrorBuf, "Loader: %s: Unknown error.", \ pFilename ); \ iError = -1; \ } \ \ goto end; \ } /* * Loads in one emerald object (compiled) file. */ int em_load_obj_file( char *pFilename, bool bDynamic ) { FILE *pFile; char *pFileInfo; int iError = 0; /* byte *pInstrStream; */ i4 iI; i4 i = 0L; i2 iF = 0; i2 iFCount = 0; i2 iSymTop = -1; bool b = FALSE; if ( ( pFile = fopen( pFilename, "rb" ) ) == NULL ) { sprintf( cErrorBuf, "Loader: %s: %s.", pFilename, strerror( errno ) ); return ( -1 ); } if ( pppSymbolTable == NULL ) pppSymbolTable = alloc_mem( sizeof( char ** ) ); else pppSymbolTable = realloc_mem( pppSymbolTable, ( sizeof( char ** ) * ( siCurrentFileNumber + 1 ) ) ); #if 0 if ( pStaticVars == NULL ) { pStaticVars = alloc_mem( ( sizeof( EM_VALUE ) * iEmVarStackSize ) ); pStaticVarsEnd = ( pStaticVars + iEmVarStackSize - 1 ); pStaticVarsPos = pStaticVars; } #endif /* * Magic number identifying this file as an Emerald object file. */ _E_FREAD1_O( pFile, &i, sizeof( i4 ) ); if ( (unsigned int) i != EM_MAGIC_NUMBER ) { sprintf( cErrorBuf, "Loader: %s: Not an Emerald object file.", pFilename ); iError = -2; goto end; } /* * File format version number. */ i = 0L; _E_FREAD1_O( pFile, &i, 1 ); if ( i != EM_LOADER_VERSION ) { sprintf( cErrorBuf, "Loader: %s: Wrong file format (%s format.)", pFilename, ( i > EM_LOADER_VERSION ? "Newer" : "Older" ) ); iError = -2; goto end; } /* * Information string. Currently just gets discarded. */ i = 0L; _E_FREAD1_O( pFile, &i, sizeof( i2 ) ); pFileInfo = alloc_mem( i + 1 ); _E_FREAD1_O( pFile, pFileInfo, i ); free_mem( (void **) &pFileInfo ); /* * Symbol table. */ i = 0L; _E_FREAD1_O( pFile, &i, sizeof( i2 ) ); if ( i > 0 ) { pppSymbolTable[siCurrentFileNumber] = alloc_mem( ( sizeof( char * ) * ( i + 1 ) ) ); iSymTop = ( i - 1 ); for ( iI = 0; iI < i; iI++ ) { i2 iLen; _E_FREAD1_O( pFile, &iLen, sizeof( i2 ) ); pppSymbolTable[siCurrentFileNumber][iI] = alloc_mem( ( iLen + 1 ) ); _E_FREAD1_O( pFile, pppSymbolTable[siCurrentFileNumber][iI], iLen ); pppSymbolTable[siCurrentFileNumber][iI][iLen] = '\0'; } } #if 0 i = 0L; _E_FREAD1_O( pFile, &i, sizeof( i4 ) ); if ( i > 0 ) { pInstrStream = alloc_mem( i ); _E_FREAD1_O( pFile, pInstrStream, i ); stack_init( ); while ( *pInstrStream != INSTR_END ) pInstrStream = interpret_instruction( pInstrStream ); while ( --pVarStackPos >= pVarStackBegin ) { if ( pStaticVarsPos > pStaticVarsEnd ) { strcpy( cErrorBuf, "Loader: Static (Global) variable stack overflow." ); print_error( ); exit( 1 ); } *pStaticVarsPos++ = *pVarStackPos; /* * After the pointer is copied set the original pointer * to NULL, thus it won't be freed by stack_free(). */ pVarStackPos->u.pInt = NULL; } stack_free( ); free_mem( (void **) &pInstrStream ); } #endif /* * Functions. */ _E_FREAD1_O( pFile, &iFCount, sizeof( i2 ) ); if ( iFCount > 0 ) b = TRUE; while ( iFCount > 0 ) { iF = func_new( ); ppFuncs[iF]->siFileNumber = siCurrentFileNumber; _E_FREAD1_O( pFile, &ppFuncs[iF]->fFuncFlags, sizeof( i4 ) ); _E_FREAD1_O( pFile, &ppFuncs[iF]->iNumArgs, 1 ); for ( i = 0L; i < ppFuncs[iF]->iNumArgs; i++ ) { ppFuncs[iF]->pArgTypes = realloc_mem( ppFuncs[iF]->pArgTypes, ( sizeof( intt ) * ( i + 1 ) ) ); ppFuncs[iF]->pArgArrayDim = realloc_mem( ppFuncs[iF]->pArgArrayDim, ( sizeof( int ) * ( i + 1 ) ) ); ppFuncs[iF]->pArgArrayTypes = realloc_mem( ppFuncs[iF]->pArgArrayTypes, ( sizeof( intt ) * ( i + 1 ) ) ); ppFuncs[iF]->pArgArrayDim[i] = -1; do { _E_FREAD1_O( pFile, &ppFuncs[iF]->pArgTypes[i], 1 ); ppFuncs[iF]->pArgArrayDim[i]++; } while ( ppFuncs[iF]->pArgTypes[i] == TYPE_ARRAY ); switch ( ppFuncs[iF]->pArgTypes[i] ) { case TYPE_INT : case TYPE_FLOAT : case TYPE_STRING: case TYPE_OBJECT: case TYPE_ARRAY : break; default : sprintf( cErrorBuf, "Loader: %s: User %s() has unknown argument type.", pFilename, ppFuncs[iF]->pName ); iError = -2; goto end; } if ( ppFuncs[iF]->pArgArrayDim[i] > 0 ) { ppFuncs[iF]->pArgArrayTypes[i] = ppFuncs[iF]->pArgTypes[i]; ppFuncs[iF]->pArgTypes[i] = TYPE_ARRAY; } else if ( ppFuncs[iF]->pArgTypes[i] == TYPE_STRING ) ppFuncs[iF]->pArgArrayTypes[i] = TYPE_INT; } _E_FREAD1_O( pFile, &ppFuncs[iF]->iNumReturn, 1 ); for ( i = 0L; i < ppFuncs[iF]->iNumReturn; i++ ) { ppFuncs[iF]->pReturnTypes = realloc_mem( ppFuncs[iF]->pReturnTypes, sizeof( intt ) * ( i + 1 ) ); ppFuncs[iF]->pReturnArrayDim = realloc_mem( ppFuncs [iF]->pReturnArrayDim, ( sizeof( int ) * ( i + 1 ) ) ); ppFuncs[iF]->pReturnArrayTypes = realloc_mem( ppFuncs [iF]->pReturnArrayTypes, ( sizeof( intt ) * ( i + 1 ) ) ); ppFuncs[iF]->pReturnArrayDim[i] = -1; do { _E_FREAD1_O( pFile, &ppFuncs[iF]->pReturnTypes[i], 1 ); ppFuncs[iF]->pReturnArrayDim[i]++; } while ( ppFuncs[iF]->pReturnTypes[i] == TYPE_ARRAY ); switch ( ppFuncs[iF]->pReturnTypes[i] ) { case TYPE_INT : case TYPE_FLOAT : case TYPE_STRING: case TYPE_OBJECT: case TYPE_ARRAY : break; default : sprintf( cErrorBuf, "Loader: %s: User %s() has unknown return type.", pFilename, ppFuncs[iF]->pName ); iError = -2; goto end; } if ( ppFuncs[iF]->pReturnArrayDim[i] > 0 ) { ppFuncs[iF]->pReturnArrayTypes[i] = ppFuncs [iF]->pReturnTypes[i]; ppFuncs[iF]->pReturnTypes[i] = TYPE_ARRAY; } else if ( ppFuncs[iF]->pReturnTypes[i] == TYPE_STRING ) ppFuncs[iF]->pReturnArrayTypes[i] = TYPE_INT; } i = 0L; _E_FREAD1_O( pFile, &i, sizeof( i2 ) ); if ( pppSymbolTable[siCurrentFileNumber] == NULL || i > iSymTop ) { sprintf( cErrorBuf, "Loader: %s: Invalid symbol table reference.", pFilename ); iError = -2; goto end; } ppFuncs[iF]->pName = str_dup( pppSymbolTable [siCurrentFileNumber][i] ); if ( em_find_func( ppFuncs[iF]->pName ) != iF ) { sprintf( cErrorBuf, "Loader: %s: User %s() multiply defined.", pFilename, ppFuncs[iF]->pName ); iError = -2; goto end; } i = 0L; _E_FREAD1_O( pFile, &i, sizeof( i4 ) ); if ( i <= 0 ) { sprintf( cErrorBuf, "Loader: %s: Invalid code size for %s().", pFilename, ppFuncs[iF]->pName ); iError = -2; goto end; } ppFuncs[iF]->ulCodeSize = (unsigned long) i; ppFuncs[iF]->pInstrStream = alloc_mem( i ); _E_FREAD1_O( pFile, ppFuncs[iF]->pInstrStream, i ); ppFuncs[iF]->bDynamic = bDynamic; iFCount--; } end: fclose( pFile ); /* * If an error took place while loading a function remove the * function totally. */ if ( b == TRUE && iError < 0 ) { if ( ppFuncs[iF]->pName != NULL ) str_free( ppFuncs[iF]->pName ); if ( ppFuncs[iF]->pArgTypes != NULL ) free_mem( (void **) &ppFuncs[iF]->pArgTypes ); if ( ppFuncs[iF]->pArgArrayDim != NULL ) free_mem( (void **) &ppFuncs[iF]->pArgArrayDim ); if ( ppFuncs[iF]->pArgArrayTypes != NULL ) free_mem( (void **) &ppFuncs[iF]->pArgArrayTypes ); if ( ppFuncs[iF]->pReturnTypes != NULL ) free_mem( (void **) &ppFuncs[iF]->pReturnTypes ); if ( ppFuncs[iF]->pReturnArrayDim != NULL ) free_mem( (void **) &ppFuncs[iF]->pReturnArrayDim ); if ( ppFuncs[iF]->pReturnArrayTypes != NULL ) free_mem( (void **) &ppFuncs[iF]->pReturnArrayTypes ); if ( ppFuncs[iF]->pInstrStream != NULL ) free_mem( (void **) &ppFuncs[iF]->pInstrStream ); free_mem( (void **) &ppFuncs[iF] ); if ( siTopFuncIndex == 0 ) free_mem( (void **) &ppFuncs ); else ppFuncs = realloc_mem( ppFuncs, ( sizeof( EM_FUNC * ) * ( --siTopFuncIndex + 2 ) ) ); } siCurrentFileNumber++; return ( iError ); } #undef _E_FREAD1_O /* * Called after all code modules are loaded. Translates all TRANS_* * byte codes into actaul instructions executable by * interpret_instruction(). */ void em_translate( void ) { byte *p; if ( ppFuncs == NULL ) return; iEmError = 0; for ( iCurrentFunc = 0; iCurrentFunc <= siTopFuncIndex; iCurrentFunc++ ) { p = ppFuncs[iCurrentFunc]->pInstrStream; while ( *p != INSTR_END ) { p = bct( p ); if ( iEmError < 0 ) { print_error( ); exit( 1 ); } } } } byte *bct( byte *p ) { i4 iTemp; switch ( *p++ ) { case INSTR_PUSH_INT1 : p++; break; case INSTR_PUSH_INT2 : case INSTR_PUSH_LOCAL : case INSTR_ASSIGN_LOCAL : case INSTR_JUMP : p += sizeof( i2 ); break; case INSTR_PUSH_INT4 : p += sizeof( i4 ); break; case INSTR_PUSH_FLOAT4 : p += sizeof( f4 ); break; case INSTR_PUSH_FLOAT8 : p += sizeof( f8 ); break; case INSTR_PUSH_STRING : iTemp = (i4) *( (i2 *) p ); p += sizeof( i2 ); p += iTemp; break; case INSTR_COMPARE : p += sizeof( i2 ); p++; while ( *p != INSTR_END ) { p = bct( p ); if ( iEmError < 0 ) return ( p ); } while ( *p != INSTR_END ) { p = bct( p ); if ( iEmError < 0 ) return ( p ); } break; case INSTR_CALL_BUILTIN_FUNC : case INSTR_CALL_FUNC : iTemp = (i4) *p++; p += iTemp; iTemp = (i4) *p++; p += iTemp; break; case TRANS_BUILTIN_FUNC : { char *pStr; *( p - 1 ) = INSTR_PUSH_INT2; iTemp = (i4) *( (i2 *) p ); pStr = pppSymbolTable[ppFuncs[iCurrentFunc]->siFileNumber] [iTemp]; iTemp = 0L; while ( emefCFuncTable[iTemp].pName != NULL ) { if ( strcmp( pStr, emefCFuncTable[iTemp].pName ) == 0 ) break; iTemp++; } if ( emefCFuncTable[iTemp].pName == NULL ) { sprintf( cErrorBuf, "Linker: Builtin %s() not found; " "referenced from %s().", pStr, ppFuncs[iCurrentFunc]->pName ); iEmError = -1; break; } ADD_INSTR_I2( p, iTemp ); } break; case TRANS_FUNC : { char *pStr; *( p - 1 ) = INSTR_PUSH_INT2; iTemp = (i4) *( (i2 *) p ); pStr = pppSymbolTable[ppFuncs[iCurrentFunc]->siFileNumber] [iTemp]; for ( iTemp = 0L; ppFuncs[iTemp] != NULL; iTemp++ ) { if ( !strcmp( pStr, ppFuncs[iTemp]->pName ) ) break; } if ( ppFuncs[iTemp] == NULL ) { sprintf( cErrorBuf, "Linker: User %s() not found; " "referenced from %s().", pStr, ppFuncs[iCurrentFunc]->pName ); iEmError = -2; break; } ADD_INSTR_I2( p, iTemp ); } break; default : break; } return ( p ); } /* * Returns a function's index number given it's name. Will return -1 * if no function with the given name exists. */ int em_find_func( char *pName ) { int iF; if ( ppFuncs != NULL ) { for ( iF = 0; iF <= siTopFuncIndex; iF++ ) { if ( strcmp( pName, ppFuncs[iF]->pName ) == 0 ) break; } if ( ppFuncs[iF] != NULL ) return ( iF ); } return ( -1 ); } /* * Calls an Emerald function given it's index in the function table. */ int em_call_func( int iF ) { byte *p; if ( em_setup_abort( ) != 0 ) return ( -1 ); if ( iF >= 0 && iF <= siTopFuncIndex ) { p = ppFuncs[iF]->pInstrStream; while ( *p != INSTR_END ) p = interpret_instruction( p ); } else return ( -2 ); return ( 0 ); } /* * End of main.c */