/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Copyright (c) 1989-2000 Microsoft Corporation Module Name: ebase.c Abstract: This file generates the error recovery data base. Notes: 1. Inputs to this module are the extable.* files generated by yacc in response to the s switch. 2. Take the state vs token index file ( extable.h3 ), and generate the state vs token table using the token index to token value translations provided by extable.h1 3. Take the state vs expected RHS file ( extable.h2 ) and generate a data base of expected RHS in every state. Author: vibhasc 11-15-91 ----------------------------------------------------------------------------*/ /***************************************************************************** local defines and includes *****************************************************************************/ #include #include #include #include #include #include "ebase.h" #define STATE_VS_TOKEN_INDEX_FILE "extable.h3" #define TOKEN_TRANSLATION_FILE "extable.h1" #define STATE_VS_EXPECTED_FILE "extable.h2" #define ISVALIDTOKEN( i ) (TRUE) #define MAX_TRANSLATION_LINE_SIZE (512) #define TRUE 1 #define FALSE 0 /* from winerror.h */ #define ERROR_INVALID_DATA 13 #define CHECK_FSCAN_STATUS( fscanfcall ) \ if ( EOF == (fscanfcall) ) \ { \ fprintf( stderr, \ "\nmidleb : error MIDLEB%d : unexpected end of input stream", \ ERROR_INVALID_DATA ); \ exit( ERROR_INVALID_DATA ); \ } typedef unsigned int BOOL; typedef enum _status { STATUS_OK = 0, OUT_OF_MEMORY, CANT_OPEN_INPUT_FILE, CANT_OPEN_OUTPUT_FILE, WRONG_ARGUMENT_COUNT } STATUS_T; typedef struct _xlat { char * pIncoming; char * pTranslated; struct _xlat *pNext; } XLAT; typedef struct _DBENTRY { short State; char * pTranslated; } DBENTRY; /***************************************************************************** global data *****************************************************************************/ FILE * hStateVsTokenIndexFile; FILE * hStateVsExpectedFile; FILE * hOutput; FILE * hXlatFile; FILE * hTokXlatHdl; SGOTO ** pSGoto; short * pSGotoCount; short ** pTokVsState; short * pTokVsStateIndex; short ValidStates; short ValidTokens; char * pPrefix; XLAT * pXlat = 0, * pXlatCur = 0; DBENTRY * pDataBase; short NTOKENS; short ACCEPTCODE; short * TokVal; short * TokCount; short NSTATES; short MAXTOKVSSTATE; short MAXSTATEVSTOK; short MAXTOKENVALUE; short MAXSTATEVSEXPECTED; /***************************************************************************** external procedures *****************************************************************************/ STATUS_T Init( char *, char * ); STATUS_T Generate( FILE * ); STATUS_T OpenFileForReadProcessing( FILE **, char * ); void Dump( void ); BOOL SearchForStateInTokenVsState( short, short ); void TranslateExpectedConstructs( void ); char * Translate( char * ); void main( int argc, char *argv[] ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: the main routine. Arguments: Standard Return Value: Exit Status Notes: Usage : ebase Xlatefile is the file where production names to message translation is specified. prefix is idl or acf. The expected string array is created with a standard name prefixed with the user specified prefix. ----------------------------------------------------------------------------*/ { STATUS_T Status; fprintf( stderr, "Error Recovery Data Base Generator\n" ); if( argc == 4 ) { pPrefix = argv[ 3 ]; if( (Status = Init( argv[ 1 ], argv[ 2 ] )) == STATUS_OK ) { Status = Generate( hStateVsTokenIndexFile ); } Dump(); TranslateExpectedConstructs(); } else { fprintf( stderr, "Wrong argument count\n" ); fprintf( stderr, "Usage : midleb \n"); Status = WRONG_ARGUMENT_COUNT; } exit( Status ); } /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Initialize Arguments: OutputName : output file name XlatFilename : the production/token name to error message translation. Return Value: STATUS_T - OUT_OF_MEMORY or - CANT_OPEN_INPUT_FILE or - STATUS_OK Notes: Sets up the file handles for all the files that need to be read from ----------------------------------------------------------------------------*/ STATUS_T Init( char * OutputFileName, char * XlatFileName ) { STATUS_T Status; int i; Status = OpenFileForReadProcessing( &hStateVsTokenIndexFile, STATE_VS_TOKEN_INDEX_FILE ); if( Status == STATUS_OK ) { Status = OpenFileForReadProcessing( &hStateVsExpectedFile, STATE_VS_EXPECTED_FILE ); if( Status == STATUS_OK ) { Status = OpenFileForReadProcessing( &hTokXlatHdl, TOKEN_TRANSLATION_FILE ); if( Status == STATUS_OK ) { Status = OpenFileForReadProcessing( &hXlatFile, XlatFileName ); if( Status == STATUS_OK ) { if( strcmp( OutputFileName, "-" ) == 0 ) hOutput = stdout; else if( (hOutput = fopen( OutputFileName , "w" )) == (FILE *)0 ) { Status = CANT_OPEN_OUTPUT_FILE; }; } } } } if( Status != STATUS_OK ) return Status; /** read in the required numbers from the TOKEN_TRANSLATION_FILE **/ CHECK_FSCAN_STATUS( fscanf( hTokXlatHdl, "%hd %hd\n", &NTOKENS, &ACCEPTCODE ) ); /** read in the token translation table **/ TokVal = (short *)calloc( 1, NTOKENS * sizeof( short ) ); TokCount = (short *)calloc( 1, NTOKENS * sizeof( short ) ); if (!TokVal || !TokCount ) { fprintf( stderr, "Out of memory.\n"); exit(OUT_OF_MEMORY); } for( i = 0; i < NTOKENS; i++ ) { CHECK_FSCAN_STATUS( fscanf( hTokXlatHdl, "%hd", &TokVal[ i ]) ); } CHECK_FSCAN_STATUS( fscanf( hTokXlatHdl, "\n" ) ); for( i = 0; i < NTOKENS; i++ ) { CHECK_FSCAN_STATUS( fscanf( hTokXlatHdl, "%hd", &TokCount[ i ]) ); } CHECK_FSCAN_STATUS( fscanf( hTokXlatHdl, "\n" ) ); CHECK_FSCAN_STATUS( fscanf( hTokXlatHdl, "%hd %hd %hd %hd %hd\n", &NSTATES, &MAXTOKVSSTATE, &MAXSTATEVSTOK, &MAXTOKENVALUE, &MAXSTATEVSEXPECTED ) ); /** allocate memory now **/ pSGoto = (SGOTO **) calloc( 1,NSTATES * sizeof( SGOTO * ) ); pSGotoCount = (short *)calloc(1, NSTATES * sizeof( short ) ); pTokVsState = (short **)calloc( 1,(MAXTOKENVALUE+1) * sizeof( short * ) ); pTokVsStateIndex = (short *)calloc(1, (MAXTOKENVALUE+1) * sizeof( short ) ); pDataBase = ( DBENTRY * )calloc( 1, MAXSTATEVSEXPECTED * sizeof( DBENTRY ) ); if( !pSGoto || !pSGotoCount || !pTokVsState || !pTokVsStateIndex || !pDataBase ) { fprintf( stderr, "Out of memory.\n"); exit(OUT_OF_MEMORY); } return Status; } STATUS_T Generate( FILE * hSVsTIndexFile ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Generate the state vs token table, given the state vs token index table in extable.h3 and token vs token index translation of extable.h1. Arguments: hStateVsTokenIndexFile - handle to the file which has the state vs token index info. Return Value: None. Notes: The state vs token index file has the goto info for every valid token, For every state, this file contains the goto ( or none ) for every valid token ( represented by the token index ). Thus for each state, we lookup to see if the state has a goto for a given token index. If it does, then we translate the token index into a token value, and mark the goto for the state for that token in the state vs token table. In the end we will have a very sparse array, which contains all the states and the gotos for the state for each token ( or the absence of any goto ). We will use this table to generate two tables: 1. The set of all states which have a goto on a token 2. The set of all tokens valid for any state. The exception to this rule is the accept action which is treated like an absence of goto. ----------------------------------------------------------------------------*/ { short iState,i,j,Temp,SGotoCount; SGOTO *p; /** fixup pointers to token vs state pointer array **/ for( i = 0; i < NTOKENS; i++ ) { if( TokCount[ i ] ) { j = TokVal[ i ]; if( ISVALIDTOKEN( j ) ) { pTokVsState[ j ] = calloc( 1, TokCount[ i ] * sizeof( short ) ); if (!pTokVsState[ j ]) { fprintf( stderr, "Out of memory.\n" ); exit( OUT_OF_MEMORY ); } } } } for( iState = 0; iState < NSTATES; ++iState ) { /** ignore the state number */ CHECK_FSCAN_STATUS( fscanf( hSVsTIndexFile, "%hd %c", &Temp, &Temp ) ); /** get the count of number of state goto entries **/ CHECK_FSCAN_STATUS( fscanf( hSVsTIndexFile, "%hd %c", &SGotoCount, &Temp ) ); /** now read in the goto vs token pairs **/ if( SGotoCount ) { p = pSGoto[ iState ] = calloc( 1, SGotoCount * sizeof( SGOTO ) ); if (!p) { fprintf( stderr, "Out of memory.\n" ); exit( OUT_OF_MEMORY ); } for( j = 0; j < SGotoCount; ++j ) { CHECK_FSCAN_STATUS( fscanf( hSVsTIndexFile, "%hd%c %hd", &p->Goto, &Temp, &p->Token ) ); Temp = TokVal[ p->Token ]; if( ISVALIDTOKEN( Temp ) ) { if( !SearchForStateInTokenVsState( Temp, p->Goto ) ) { i = pTokVsStateIndex[ Temp ]; pTokVsStateIndex[ Temp ]++; *(pTokVsState[Temp] + i ) = p->Goto; } p++; pSGotoCount[ iState ]++; } } } } return STATUS_OK; } STATUS_T OpenFileForReadProcessing( FILE ** pHandle, char * pName ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: This process opens a file for read processing, reports an error if the file could not be opened. Arguments: pHandle - pointer to a file handle deposition area. pName - pointer to a file name, null terminated. Return Value: STATUS_T - STATUS_OK if all is well. - CANT_OPEN_INPUT_FILE otherwise. Notes: ----------------------------------------------------------------------------*/ { FILE *hF; if( ( hF = fopen( pName, "r" ) ) == (FILE *)NULL ) { fprintf( stderr, "Cannot open input file : %s\n", pName ); return CANT_OPEN_INPUT_FILE; } *pHandle = hF; return STATUS_OK; } void Dump( void ) { SGOTO * p; short iTemp, i,j; /** dump the state goto table **/ for( iTemp = 0, ValidStates = 0; iTemp < NSTATES; ++iTemp ) { p = pSGoto[ iTemp ]; if( j = pSGotoCount[ iTemp ] ) { fprintf( hOutput, "\n SGOTO _sG%s%.4hd [ %d ] = { ", pPrefix, iTemp, j ); for( i = 0; i < j; i++ ) { fprintf( hOutput , " {%hd, %hd} %c" , p[ i ].Goto , TokVal[ p[ i ].Token] , ( (i+1 == j) ? ' ' : ',' )); } fprintf( hOutput, "};" ); ValidStates++; } } /** now dump the array of pointers to this **/ fprintf( hOutput, "\n\n#define VALIDSTATES_%s %d\n", pPrefix, ValidStates ); fprintf( hOutput, "\n\nSGOTOVECTOR SGoto%s[ VALIDSTATES_%s ] = {\n",pPrefix, pPrefix); for( i = 0; i < NSTATES; ++i ) { if( pSGotoCount[ i ] ) { fprintf( hOutput, "\n{ %d, _sG%s%.4hd, %d }" , i ,pPrefix , i , pSGotoCount[ i ] ); fprintf( hOutput,"%c", ((i + 1 == NSTATES) ? ' ' : ',' )); } } fprintf( hOutput, "\n};\n\n" ); /** count the valid token entries. i.e tokens for which states exist **/ fprintf(hOutput, "#if 0\n"); for( ValidTokens = 0, i = 0; i < MAXTOKENVALUE; ++i ) { if( pTokVsStateIndex[ i ] ) ValidTokens++; } /** dump the token vs state table **/ for( iTemp = 0; iTemp < NTOKENS; ++iTemp ) { if( j = pTokVsStateIndex[ TokVal[ iTemp ] ] ) { fprintf( hOutput, "short _tS%s%.4d[ %d ] = {", pPrefix, TokVal[ iTemp ], j ); for( i = 0; i < j; ++i ) { fprintf( hOutput, " %d %c", *(pTokVsState[ TokVal[ iTemp ] ]+i), (( i + 1 == j ) ? ' ' : ',' )); } fprintf( hOutput, "};\n" ); } } /** dump the vectors to the token vs state table **/ fprintf(hOutput, "\n#define VALIDTOKENS %d\n", ValidTokens ); fprintf( hOutput, "\nTOKVSSTATEVECTOR TokVsState%s[ VALIDTOKENS ] = { \n",pPrefix); for( i = 0; i < MAXTOKENVALUE+1; ++i ) { if( j = pTokVsStateIndex[ i ]) { fprintf( hOutput, "\n{ %d, _tS%s%.4d, %d }",i, pPrefix, i, j ); fprintf(hOutput, "%c", (i + 1 == NTOKENS) ? ' ' : ',' ); } } fprintf( hOutput, "\n\n};\n" ); fprintf( hOutput, "\n" ); fprintf(hOutput, "#endif\n"); } BOOL SearchForStateInTokenVsState( short TokenValue, short Goto ) { int i,j; for( i = 0, j = pTokVsStateIndex[ TokenValue ]; i < j; ++i ) { if( *(pTokVsState[ TokenValue ] + i) == Goto ) return TRUE; } return FALSE; } void TranslateExpectedConstructs( void ) { int i,State,Count,Temp; char Buffer[ MAX_TRANSLATION_LINE_SIZE ]; char Buffer1[ MAX_TRANSLATION_LINE_SIZE ]; DBENTRY *p; XLAT *pX; /** firstly, read in the translation data base, which shows the expected token name vs the actual error string the compiler wants to output. **/ for(;;) { i = fscanf( hXlatFile, "%[^ \t]%1s%[^\n]\n", Buffer, &Temp, Buffer1 ); if( i == EOF || i == 0 ) break; if( ( Buffer[0] != '$' ) && ( Buffer[1] != '$' ) ) { pX = calloc( 1 , sizeof( XLAT ) ); if (!pX ) { fprintf( stderr, "Out of memory!" ); exit(OUT_OF_MEMORY ); } pX->pIncoming = malloc( strlen( Buffer ) + 1 ); if (!pX->pIncoming ) { fprintf( stderr, "Out of memory!" ); exit(OUT_OF_MEMORY ); } strcpy( pX->pIncoming, Buffer ); pX->pTranslated = malloc( strlen( Buffer1 ) + 1 ); if (!pX->pTranslated) { fprintf( stderr, "Out of memory!" ); exit(OUT_OF_MEMORY ); } strcpy( pX->pTranslated, Buffer1 ); if( pXlatCur == 0 ) { pXlatCur = pXlat = pX; } else { pXlatCur->pNext = pX; pXlatCur = pX; } } } /** Then read the STATE_VS_EXPECTED_FILE, and read in the expected tokens/productions for each entry, as translated by looking up the data base. **/ p = pDataBase; while( p < (pDataBase + MAXSTATEVSEXPECTED) ) { CHECK_FSCAN_STATUS( fscanf( hStateVsExpectedFile, "%d %c %d %c", &State, &Temp, &Count, &Temp, Buffer ) ); if( Count ) { CHECK_FSCAN_STATUS( fscanf( hStateVsExpectedFile, " %[^\n]\n", Buffer ) ); p->State = (short) State; p->pTranslated = Translate( Buffer ); p++; } else CHECK_FSCAN_STATUS( fscanf( hStateVsExpectedFile, "\n" ) ); } /** emit the state vs expected array with the proper prefix **/ fprintf( hOutput, "\n#ifndef _DBENTRY_DEFINED\n" ); fprintf( hOutput, "\n#define _DBENTRY_DEFINED\n" ); fprintf( hOutput, "\ntypedef struct _DBENTRY {" ); fprintf( hOutput, "\n\t short State;"); fprintf( hOutput, "\n\t char * pTranslated;"); fprintf( hOutput, "\n} DBENTRY;\n"); fprintf( hOutput, "\n#endif\n" ); fprintf( hOutput, "\n#define MAXSTATEVSEXPECTED_SIZE_%s %d\n", pPrefix, MAXSTATEVSEXPECTED ); fprintf( hOutput, "\n DBENTRY %s_SyntaxErrorDB[ MAXSTATEVSEXPECTED_SIZE_%s ] = {\n", pPrefix, pPrefix); for( p = pDataBase; p < (pDataBase + MAXSTATEVSEXPECTED); p++ ) { fprintf( hOutput, "{ %d , \"%s\"},\n" , p->State, p->pTranslated ); } fprintf( hOutput, "\n};\n" ); } char * Translate( char *pIncoming ) { char *p; pXlatCur = pXlat; while( pXlatCur ) { if( strcmp( pXlatCur->pIncoming, pIncoming ) == 0 ) return pXlatCur->pTranslated; pXlatCur = pXlatCur->pNext; } p = malloc( strlen( pIncoming ) + 1 ); if (!p ) { fprintf( stderr, "Out of memory.\n" ); exit( OUT_OF_MEMORY ); } strcpy( p, pIncoming ); return p; }