|
|
/* Copyright (C) Microsoft Corporation, 1998. All rights reserved. */
#include "precomp.h"
#include "getsym.h"
#include "macro.h"
#include "typeid.h"
#include "utils.h"
// local prototypes
BOOL ExpandFile ( LPSTR pszInputFile, LPSTR pszOutputFile, CMacroMgrList *pMacrMgrList ); BOOL CollectMacros ( CInput *, CMacroMgr *, CTypeID *, CMacroMgrList * ); BOOL InstantiateMacros ( CInput *, CMacroMgr * ); BOOL GenerateOutput ( CInput *, COutput *, CMacroMgr *, CTypeID * ); void BuildOutputFileName ( LPSTR pszInputFileName, LPSTR pszNewOutputFileName );
class CFileList : public CList { DEFINE_CLIST(CFileList, LPSTR) };
int __cdecl main ( int argc, char * argv[] ) { BOOL rc; BOOL fShowHelp = (1 == argc); int i; LPSTR pszMainInputFile = NULL; LPSTR pszMainOutputFile = NULL;
CFileList FileList; CMacroMgrList MacroMgrList;
LPSTR psz; char szScratch[MAX_PATH];
// output product information
printf("ASN.1 Compiler Preprocessor V0.1\n"); printf("Copyright (C) Microsoft Corporation, 1998. All rights reserved.\n");
// parse command line
for (i = 1; i < argc; i++) { if ('-' == *argv[i]) { // parse the option
if (0 == ::strcmp(argv[i], "-h")) { fShowHelp = TRUE; } else if (0 == ::strcmp(argv[i], "-o")) { pszMainOutputFile = ::My_strdup(argv[++i]); ASSERT(NULL != pszMainOutputFile); } else { fprintf(stderr, "Unknown option [%s]\n", argv[i]); fShowHelp = TRUE; break; } } else { // must be a file name
FileList.Append(argv[i]);
// the last file will be the main input file
pszMainInputFile = argv[i]; } }
// output help information if needed
if (fShowHelp || 0 == FileList.GetCount() || NULL == pszMainInputFile) { printf("Usage: %s [options] [imported.asn ...] main.asn\n", argv[0]); printf("Options:\n"); printf("-h\t\tthis help\n"); printf("-o filename\toutput file name\n"); return EXIT_SUCCESS; }
// construct outpt file name if needed
if (NULL == pszMainOutputFile) { // create an output file
::BuildOutputFileName(pszMainInputFile, &szScratch[0]); pszMainOutputFile = ::My_strdup(&szScratch[0]); ASSERT(NULL != pszMainOutputFile); }
// input and output files must have a different name.
ASSERT(0 != ::strcmp(pszMainInputFile, pszMainOutputFile));
// expand macros in the files
FileList.Reset(); while (NULL != (psz = FileList.Iterate())) { if (0 != ::strcmp(psz, pszMainInputFile)) { ::BuildOutputFileName(psz, &szScratch[0]); rc = ::ExpandFile(psz, &szScratch[0], &MacroMgrList); ASSERT(rc);
// remove all the instances of macros
MacroMgrList.Uninstance(); } else { // it is main input file
rc = ::ExpandFile(pszMainInputFile, pszMainOutputFile, &MacroMgrList); ASSERT(rc); } }
//
// Cleanup
//
delete pszMainOutputFile; MacroMgrList.DeleteList();
return EXIT_SUCCESS; }
BOOL ExpandFile ( LPSTR pszInputFile, LPSTR pszOutputFile, CMacroMgrList *pMacroMgrList ) { BOOL rc, rc1, rc2; CInput *pInput = NULL; COutput *pOutput = NULL; CTypeID *pTypeID = NULL; CMacroMgr *pMacroMgr = NULL;
pInput = new CInput(&rc1, pszInputFile); pOutput = new COutput(&rc2, pszOutputFile); pTypeID = new CTypeID(); pMacroMgr = new CMacroMgr(); if (NULL != pInput && rc1 && NULL != pOutput && rc2 && NULL != pTypeID && NULL != pMacroMgr) { //
// Locate a list of macros
//
rc = ::CollectMacros(pInput, pMacroMgr, pTypeID, pMacroMgrList); if (rc) { rc = pInput->Rewind(); ASSERT(rc);
//
// Create instances of macros
//
rc = ::InstantiateMacros(pInput, pMacroMgr); if (rc) { rc = pInput->Rewind(); ASSERT(rc);
//
// Generate macro-expanded file
//
rc = ::GenerateOutput(pInput, pOutput, pMacroMgr, pTypeID); ASSERT(rc); } else { ASSERT(rc); } } else { ASSERT(rc); } } else { ASSERT(0); }
//
// Cleanup
//
if (NULL != pMacroMgrList && NULL != pMacroMgr) { pMacroMgrList->Append(pMacroMgr); } else { delete pMacroMgr; } delete pTypeID; delete pOutput; delete pInput;
return rc; }
BOOL CollectMacros ( CInput *pInput, CMacroMgr *pMacroMgr, CTypeID *pTypeID, CMacroMgrList *pMacroMgrList ) { CNameList NameList(16);
// Create a running symbol handler
CSymbol *pSym = new CSymbol(pInput); if (NULL == pSym) { return FALSE; }
BOOL rc; BOOL fWasNewLine = TRUE; BOOL fEndMacro = FALSE; UINT cInsideBigBracket = 0; BOOL fInsideComment = FALSE;
char szNameScratch[MAX_PATH];
// Get the module name first
pSym->NextUsefulSymbol(); if (pSym->GetID() == SYMBOL_IDENTIFIER) { ::strcpy(&szNameScratch[0], pSym->GetStr()); pSym->NextUsefulSymbol(); if (pSym->GetID() == SYMBOL_KEYWORD && 0 == ::strcmp(pSym->GetStr(), "DEFINITIONS")) { pMacroMgr->AddModuleName(&szNameScratch[0]); } }
// Rewind the input file
rc = pInput->Rewind(); ASSERT(rc);
// Walk through the text
while (pSym->NextSymbol()) { // printf("symbol:id[%d], str[%s]\n", pSym->GetID(), pSym->GetStr());
if (pSym->GetID() == SYMBOL_SPACE_EOL) { fWasNewLine = TRUE; fInsideComment = FALSE; continue; }
if (pSym->IsComment()) { fInsideComment = ! fInsideComment; } else if (! fInsideComment) { if (pSym->IsLeftBigBracket()) { cInsideBigBracket++; } else if (pSym->IsRightBigBracket()) { cInsideBigBracket--; } else // The macro must be outside the big brackets and
// in the beginning of a line.
if (fWasNewLine && (0 == cInsideBigBracket) && (pSym->GetID() == SYMBOL_IDENTIFIER)) { ::strcpy(&szNameScratch[0], pSym->GetStr()); pSym->NextUsefulSymbol(); if (pSym->IsLeftBigBracket()) { cInsideBigBracket++; CMacro *pMacro = new CMacro(&rc, &szNameScratch[0]); ASSERT(NULL != pMacro); ASSERT(rc);
// process argument list
do { pSym->NextUsefulSymbol(); pMacro->SetArg(pSym->GetStr()); pSym->NextUsefulSymbol(); } while (pSym->IsComma()); ASSERT(pSym->IsRightBigBracket()); if (pSym->IsRightBigBracket()) { cInsideBigBracket--; }
// save the macro body
ASSERT(0 == cInsideBigBracket); fEndMacro = FALSE; while (! fEndMacro || pSym->GetID() != SYMBOL_SPACE_EOL) { pSym->NextSymbol(); if (pSym->GetID() == SYMBOL_SPACE_EOL) { fInsideComment = FALSE; } else if (pSym->IsComment()) { fInsideComment = ! fInsideComment; } else if (! fInsideComment) { if (pSym->IsLeftBigBracket()) { cInsideBigBracket++; } else if (pSym->IsRightBigBracket()) { cInsideBigBracket--; if (0 == cInsideBigBracket && ! fEndMacro) { // basically, it is the end of macro
pMacro->SetBodyPart(pSym->GetStr()); fEndMacro = TRUE; } } } // while
// throw away anything possibly in CONSTRAINED BY
if (! fEndMacro) { pMacro->SetBodyPart(pSym->GetStr()); } } // while
// macro must end with a eol
fWasNewLine = TRUE; fInsideComment = FALSE;
// write out the eol
pMacro->SetBodyPart("\n");
// take a note of ending a macro
pMacro->EndMacro(); pMacroMgr->AddMacro(pMacro);
// to avoid fWasNewLine being reset.
continue; } // if left bracket
else if (pSym->GetID() == SYMBOL_DEFINITION) { pSym->NextUsefulSymbol(); if (pSym->GetID() == SYMBOL_IDENTIFIER && pTypeID->FindAlias(pSym->GetStr())) { // Found a type identifier
pSym->NextSymbol(); if (pSym->IsDot()) { pSym->NextSymbol(); if (pSym->GetID() == SYMBOL_FIELD && 0 == ::strcmp("&Type", pSym->GetStr())) { // defined type identifier
pSym->NextUsefulSymbol(); ASSERT(pSym->IsLeftParenth()); if (pSym->IsLeftParenth()) { pSym->NextUsefulSymbol(); if (pSym->GetID() == SYMBOL_IDENTIFIER) { rc = pTypeID->AddInstance(&szNameScratch[0], pSym->GetStr()); ASSERT(rc);
pSym->NextUsefulSymbol(); ASSERT(pSym->IsRightParenth()); } } } } else { rc = pTypeID->AddAlias(&szNameScratch[0]); ASSERT(rc); } } } // if symbol definition
} // if symbol identifier
else if (fWasNewLine && (0 == cInsideBigBracket) && (pSym->GetID() == SYMBOL_KEYWORD) && (0 == ::strcmp("IMPORTS", pSym->GetStr()))) { // skip the entire import area
do { pSym->NextUsefulSymbol(); if (pSym->GetID() == SYMBOL_IDENTIFIER) { ::strcpy(&szNameScratch[0], pSym->GetStr()); pSym->NextUsefulSymbol(); if (pSym->IsLeftBigBracket()) { NameList.AddName(&szNameScratch[0]); pSym->NextUsefulSymbol(); ASSERT(pSym->IsRightBigBracket()); } } // else // no else because the current symbol can be FROM
if (pSym->GetID() == SYMBOL_KEYWORD && 0 == ::strcmp("FROM", pSym->GetStr())) { pSym->NextUsefulSymbol(); if (pSym->GetID() == SYMBOL_IDENTIFIER) { LPSTR pszName; CMacro *pMacro; while (NULL != (pszName = NameList.Get())) { pMacro = pMacroMgrList->FindMacro(pSym->GetStr(), pszName); if (NULL != pMacro) { pMacro = new CMacro(&rc, pMacro); if (NULL != pMacro && rc) { pMacroMgr->AddMacro(pMacro); } else { ASSERT(0); } } else { ASSERT(0); } delete pszName; } // while
} } } while (! pSym->IsSemicolon()); } } // if ! comment
// Must be reset at the end of this block.
fWasNewLine = FALSE; } // while
delete pSym; return TRUE; }
BOOL InstantiateMacros ( CInput *pInput, CMacroMgr *pMacroMgr ) { // Create a running symbol handler
CSymbol *pSym = new CSymbol(pInput); if (NULL == pSym) { return FALSE; }
BOOL rc; BOOL fInsideComment = FALSE; UINT cInsideBigBracket = 0;
// Walk through the text
while (pSym->NextSymbol()) { if (pSym->GetID() == SYMBOL_SPACE_EOL) { fInsideComment = FALSE; } else if (pSym->IsComment()) { fInsideComment = ! fInsideComment; } else if (! fInsideComment) { if (pSym->IsLeftBigBracket()) { cInsideBigBracket++; } else if (pSym->IsRightBigBracket()) { cInsideBigBracket--; } else if ((0 < cInsideBigBracket) && (pSym->GetID() == SYMBOL_IDENTIFIER)) { CMacro *pMacro = pMacroMgr->FindMacro(pSym->GetStr()); if (NULL != pMacro) { UINT cCurrBracket = cInsideBigBracket;
// Found a macro instance
pSym->NextUsefulSymbol(); if (pSym->IsLeftBigBracket()) { cInsideBigBracket++;
// We need to process the argument list now.
do { pSym->NextUsefulSymbol(); pMacro->SetArg(pSym->GetStr()); pSym->NextUsefulSymbol(); } while (pSym->IsComma());
ASSERT(pSym->IsRightBigBracket()); if (pSym->IsRightBigBracket()) { cInsideBigBracket--; } ASSERT(cCurrBracket == cInsideBigBracket);
rc = pMacro->InstantiateMacro(); ASSERT(rc); } } } } // ! inside comment
} // while
delete pSym; return TRUE; }
BOOL GenerateOutput ( CInput *pInput, COutput *pOutput, CMacroMgr *pMacroMgr, CTypeID *pTypeID ) { // Create a running symbol handler
CSymbol *pSym = new CSymbol(pInput); if (NULL == pSym) { return FALSE; }
BOOL rc; BOOL fWasNewLine = FALSE; BOOL fEndMacro = FALSE; UINT cInsideBigBracket = 0; BOOL fInsideComment = FALSE; BOOL fIgnoreThisSym = FALSE; BOOL fInsideImport = FALSE; UINT nOutputImportedMacrosNow = 0;
// Walk through the text
while (pSym->NextSymbol()) { fIgnoreThisSym = FALSE; // default is to output this symbol
if (pSym->GetID() == SYMBOL_SPACE_EOL) { fWasNewLine = TRUE; fInsideComment = FALSE; } else { if (pSym->IsComment()) { fInsideComment = ! fInsideComment; } else if (! fInsideComment) { if (pSym->IsLeftBigBracket()) { cInsideBigBracket++; } else if (pSym->IsRightBigBracket()) { cInsideBigBracket--; } else if (pSym->IsSemicolon()) { fInsideImport = FALSE; nOutputImportedMacrosNow++; } else // The macro must be outside the big brackets and
// in the beginning of a line.
if (fWasNewLine && (0 == cInsideBigBracket) && (pSym->GetID() == SYMBOL_IDENTIFIER)) { CMacro *pMacro; LPSTR pszOldSubType;
if (NULL != (pMacro = pMacroMgr->FindMacro(pSym->GetStr()))) { // Found a macro template
fIgnoreThisSym = TRUE;
if (! pMacro->IsImported()) { // Output all instances of this macro.
rc = pMacro->OutputInstances(pOutput); ASSERT(rc);
// Ignore the macro template body
pSym->NextUsefulSymbol(); if (pSym->IsLeftBigBracket()) { cInsideBigBracket++;
// Ignore the argument list
do { // yes, two calls... not a mistake!
pSym->NextUsefulSymbol(); pSym->NextUsefulSymbol(); } while (pSym->IsComma()); ASSERT(pSym->IsRightBigBracket()); if (pSym->IsRightBigBracket()) { cInsideBigBracket--; }
// Ignore the macro body
ASSERT(0 == cInsideBigBracket); fEndMacro = FALSE; while (! fEndMacro || pSym->GetID() != SYMBOL_SPACE_EOL) { pSym->NextSymbol(); if (pSym->GetID() == SYMBOL_SPACE_EOL) { fInsideComment = FALSE; } else if (pSym->IsComment()) { fInsideComment = ! fInsideComment; } else if (! fInsideComment) { if (pSym->IsLeftBigBracket()) { cInsideBigBracket++; } else if (pSym->IsRightBigBracket()) { cInsideBigBracket--; if (0 == cInsideBigBracket) { // basically, it is the end of macro
fEndMacro = TRUE; } } } } // while
// macro must end with a eol
fWasNewLine = TRUE; fInsideComment = FALSE;
// to avoid fWasNewLine being reset
// it is ok to continue because we do not output this symbol.
ASSERT(fIgnoreThisSym); continue; } // if left bracket
} // ! imported
else { // Ignore the macro template body
pSym->NextUsefulSymbol(); ASSERT(pSym->IsLeftBigBracket()); pSym->NextUsefulSymbol(); ASSERT(pSym->IsRightBigBracket()); pSym->NextUsefulSymbol(); if (! pSym->IsComma()) { fIgnoreThisSym = FALSE; } } // imported
} // if pMacro
else if (pTypeID->FindAlias(pSym->GetStr())) { // Found a type ID alias. Let's skip this line entirely
do { pSym->NextSymbol(); } while (pSym->GetID() != SYMBOL_SPACE_EOL); } // if find alias
else if (NULL != (pszOldSubType = pTypeID->FindInstance(pSym->GetStr()))) { // Found a type ID instance. Let's output the construct.
rc = pTypeID->GenerateOutput(pOutput, pSym->GetStr(), pszOldSubType); ASSERT(rc);
// Skip the body entirely
do { pSym->NextUsefulSymbol(); } while (! pSym->IsRightParenth());
// Skip the rest of this line
do { pSym->NextSymbol(); } while (pSym->GetID() != SYMBOL_SPACE_EOL); } // if find instance
} else if ((0 < cInsideBigBracket) && (pSym->GetID() == SYMBOL_IDENTIFIER)) { CMacro *pMacro = pMacroMgr->FindMacro(pSym->GetStr()); if (NULL != pMacro) { UINT cCurrBracket = cInsideBigBracket;
// Found a macro instance
fIgnoreThisSym = TRUE;
// Create an instance name.
pSym->NextUsefulSymbol(); if (pSym->IsLeftBigBracket()) { cInsideBigBracket++;
// We need to process the argument list now.
do { pSym->NextUsefulSymbol(); pMacro->SetArg(pSym->GetStr()); pSym->NextUsefulSymbol(); } while (pSym->IsComma());
ASSERT(pSym->IsRightBigBracket()); if (pSym->IsRightBigBracket()) { cInsideBigBracket--; } ASSERT(cCurrBracket == cInsideBigBracket);
LPSTR pszInstanceName = pMacro->CreateInstanceName(); ASSERT(NULL != pszInstanceName); if (NULL != pszInstanceName) { rc = pOutput->Write(pszInstanceName, ::strlen(pszInstanceName)); ASSERT(rc); delete pszInstanceName; } pMacro->DeleteArgList(); } } } else if (fWasNewLine && (0 == cInsideBigBracket) && (pSym->GetID() == SYMBOL_KEYWORD) && (0 == ::strcmp("IMPORTS", pSym->GetStr()))) { fInsideImport = TRUE; } } // if ! comment
// Must be reset at the end of this block.
fWasNewLine = FALSE; } // if ! space eol
if (! fIgnoreThisSym) { // write out this symbol
rc = pOutput->Write(pSym->GetStr(), pSym->GetStrLen()); ASSERT(rc); }
// only generate once
if (1 == nOutputImportedMacrosNow) { nOutputImportedMacrosNow++; rc = pMacroMgr->OutputImportedMacros(pOutput); ASSERT(rc); } } // while
delete pSym; return TRUE; }
void BuildOutputFileName ( LPSTR pszInputFileName, LPSTR pszNewOutputFileName ) { LPSTR psz; ::strcpy(pszNewOutputFileName, pszInputFileName); if (NULL != (psz = ::strrchr(pszNewOutputFileName, '.')) && 0 == ::strcmpi(psz, ".asn")) { ::strcpy(psz, ".out"); } else { ::strcat(pszNewOutputFileName, ".out"); } }
|