|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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 <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <malloc.h>
#include <string.h>
#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 <OutputFilename> <Xlatefile> <prefix>
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 <output file or - > <translation-file-name> <prefix>\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; }
|