/*
* 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
*/