// Copyright (c) 1996-1999 Microsoft Corporation /* macros1.c - functions that implement macros */ #include "gpdparse.h" // ---- functions defined in macros1.c ---- // BOOL BevaluateMacros( PGLOBL pglobl) ; BOOL BDefineValueMacroName( PTKMAP pNewtkmap, DWORD dwNewTKMindex, PGLOBL pglobl) ; BOOL BResolveValueMacroReference( PTKMAP ptkmap, DWORD dwTKMindex, PGLOBL pglobl) ; BOOL BdelimitName( PABSARRAYREF paarValue, // the remainder of the string without the Name PABSARRAYREF paarToken, // contains the Name PBYTE pubChar ) ; BOOL BCatToTmpHeap( PABSARRAYREF paarDest, PABSARRAYREF paarSrc, PGLOBL pglobl) ; BOOL BResolveBlockMacroReference( PTKMAP ptkmap, DWORD dwMacRefIndex, PGLOBL pglobl) ; BOOL BDefineBlockMacroName( PTKMAP pNewtkmap, DWORD dwNewTKMindex, PGLOBL pglobl) ; BOOL BIncreaseMacroLevel( BOOL bMacroInProgress, PGLOBL pglobl) ; BOOL BDecreaseMacroLevel( PTKMAP pNewtkmap, DWORD dwNewTKMindex, PGLOBL pglobl) ; VOID VEnumBlockMacro( PTKMAP pNewtkmap, PBLOCKMACRODICTENTRY pBlockMacroDictEntry, PGLOBL pglobl ) ; // ---------------------------------------------------- // BOOL BevaluateMacros( PGLOBL pglobl) // and expand shortcuts // this function scans through the tokenMap // making a copy of the tokenMap without // the macrodefinitions or references. All references // are replaced by the definitions inserted in-line! // This function assumes the temp heap is availible for // storage of expanded macros. { PTKMAP ptkmap, pNewtkmap ; // start of tokenmap DWORD dwNewTKMindex, dwEntry, dwKeywordID ; CONSTRUCT eConstruct ; KEYWORD_TYPE eType ; BOOL bStatus = TRUE , bValueMacroState = FALSE ; // set to TRUE when // we parse into a *Macros construct. gMasterTable[MTI_BLOCKMACROARRAY].dwCurIndex = gMasterTable[MTI_VALUEMACROARRAY].dwCurIndex = gMasterTable[MTI_MACROLEVELSTACK].dwCurIndex = 0 ; // to push new values onto stack: write then increment stackptr // to pop values off the stack: decrement stackptr then read from stack pNewtkmap = (PTKMAP)gMasterTable[MTI_NEWTOKENMAP].pubStruct ; ptkmap = (PTKMAP)gMasterTable[MTI_TOKENMAP].pubStruct ; for(dwEntry = 0 ; geErrorSev < ERRSEV_RESTART ; dwEntry++) { // These ID's must be processed separately // because they do not index into the mainKeyword table. // The code for generic ID's will fail. dwKeywordID = ptkmap[dwEntry].dwKeywordID ; if (dwKeywordID == gdwID_IgnoreBlock) { VIgnoreBlock(ptkmap + dwEntry, TRUE, pglobl) ; continue ; } switch(dwKeywordID) { case (ID_EOF): { { DWORD dwEntry, dwTKMindex, dwTKIndexOpen, dwTKIndexClose ; PBLOCKMACRODICTENTRY pBlockMacroDictEntry ; PVALUEMACRODICTENTRY pValueMacroDictEntry ; // remove all traces of expired block and value macro definitions pBlockMacroDictEntry = (PBLOCKMACRODICTENTRY)gMasterTable[MTI_BLOCKMACROARRAY].pubStruct ; pValueMacroDictEntry = (PVALUEMACRODICTENTRY)gMasterTable[MTI_VALUEMACROARRAY].pubStruct ; for(dwEntry = 0 ; dwEntry < gMasterTable[MTI_VALUEMACROARRAY].dwCurIndex ; dwEntry++) { dwTKMindex = pValueMacroDictEntry[dwEntry].dwTKIndexValue ; pNewtkmap[dwTKMindex].dwKeywordID = ID_NULLENTRY ; } for(dwEntry = 0 ; dwEntry < gMasterTable[MTI_BLOCKMACROARRAY].dwCurIndex ; dwEntry++) { dwTKIndexOpen = pBlockMacroDictEntry[dwEntry].dwTKIndexOpen ; dwTKIndexClose = pBlockMacroDictEntry[dwEntry].dwTKIndexClose ; for(dwTKMindex = dwTKIndexOpen ; dwTKMindex <= dwTKIndexClose ; dwTKMindex++) pNewtkmap[dwTKMindex].dwKeywordID = ID_NULLENTRY ; } } if(gMasterTable[MTI_MACROLEVELSTACK].dwCurIndex) { ERR(("Too few closing braces. Fatal syntax error.\n")); geErrorSev = ERRSEV_FATAL ; geErrorType = ERRTY_SYNTAX ; return(FALSE); } // transfer all tokenmap fields to newTokenMap if(!BallocElementFromMasterTable( MTI_NEWTOKENMAP, &dwNewTKMindex, pglobl) ) { geErrorSev = ERRSEV_RESTART ; geErrorType = ERRTY_MEMORY_ALLOCATION ; gdwMasterTabIndex = MTI_NEWTOKENMAP ; return(FALSE); } pNewtkmap[dwNewTKMindex] = ptkmap[dwEntry] ; bStatus = (mdwCurStsPtr) ? (FALSE) : (TRUE); if(geErrorSev >= ERRSEV_RESTART) bStatus = FALSE ; return(bStatus) ; } case (ID_NULLENTRY): { continue ; // skip to next entry. } default : break ; } if(bValueMacroState) { if(dwKeywordID == ID_UNRECOGNIZED) { vIdentifySource(ptkmap + dwEntry, pglobl) ; ERR(("Only valueMacroDefinitions permitted within *Macros constructs.\n")); } else if(dwKeywordID == ID_SYMBOL) { // transfer all tokenmap fields to newTokenMap if(!BallocElementFromMasterTable( MTI_NEWTOKENMAP, &dwNewTKMindex, pglobl) ) { geErrorSev = ERRSEV_RESTART ; geErrorType = ERRTY_MEMORY_ALLOCATION ; gdwMasterTabIndex = MTI_NEWTOKENMAP ; continue ; } pNewtkmap[dwNewTKMindex] = ptkmap[dwEntry] ; if(!BDefineValueMacroName(pNewtkmap, dwNewTKMindex, pglobl) ) { pNewtkmap[dwNewTKMindex].dwKeywordID = ID_NULLENTRY ; vIdentifySource(ptkmap + dwEntry, pglobl) ; ERR(("Internal Error: valueMacro name registration failed.\n")); } else if(ptkmap[dwEntry].dwFlags & TKMF_MACROREF) { if(!BResolveValueMacroReference(pNewtkmap , dwNewTKMindex, pglobl)) { pNewtkmap[dwNewTKMindex].dwKeywordID = ID_NULLENTRY ; gMasterTable[MTI_VALUEMACROARRAY].dwCurIndex-- ; // remove macrodef from dictionary. } } } else // keywords that should be defined in the MainKeywordTable { eType = mMainKeywordTable[dwKeywordID].eType ; eConstruct = (CONSTRUCT)(mMainKeywordTable[dwKeywordID].dwSubType) ; if(eType == TY_CONSTRUCT && eConstruct == CONSTRUCT_CLOSEBRACE) { bValueMacroState = FALSE ; // just don't copy it. } else { vIdentifySource(ptkmap + dwEntry, pglobl) ; ERR(("Only valueMacroDefinitions permitted within *Macros constructs.\n")); } } continue ; // end of processing for this statement } // the remainder of the block handles the case // bValueMacroState = FALSE ; if(dwKeywordID == ID_UNRECOGNIZED || dwKeywordID == ID_SYMBOL) { // Note: currently SYMBOLs only occur within ValueMacro // constructs so they could be flagged as an error here. But // let it slide here since one day the parser may allow them // to be used elsewhere. // do nothing in this block, just use it to skip to code at the // bottom after all the else if statements. ; // empty statement. } else // only valid KeywordIDs enter this block. { eType = mMainKeywordTable[dwKeywordID].eType ; eConstruct = (CONSTRUCT)(mMainKeywordTable[dwKeywordID].dwSubType) ; if(eType == TY_CONSTRUCT && eConstruct == CONSTRUCT_BLOCKMACRO) { if(!BDefineBlockMacroName(ptkmap, dwEntry, pglobl)) { vIdentifySource(ptkmap + dwEntry, pglobl) ; ERR(("Internal Error: blockMacro name registration failed.\n")); continue ; } // skip NULL_ENTRIES for( dwEntry++ ; ptkmap[dwEntry].dwKeywordID == ID_NULLENTRY ; dwEntry++) ; dwKeywordID = ptkmap[dwEntry].dwKeywordID ; if(dwKeywordID < ID_SPECIAL) { eType = mMainKeywordTable[dwKeywordID].eType ; eConstruct = (CONSTRUCT)(mMainKeywordTable[dwKeywordID].dwSubType) ; if(eType == TY_CONSTRUCT && eConstruct == CONSTRUCT_OPENBRACE) { PBLOCKMACRODICTENTRY pBlockMacroDictEntry ; if(!BallocElementFromMasterTable( MTI_NEWTOKENMAP, &dwNewTKMindex, pglobl) ) { geErrorSev = ERRSEV_RESTART ; geErrorType = ERRTY_MEMORY_ALLOCATION ; gdwMasterTabIndex = MTI_NEWTOKENMAP ; continue ; } pNewtkmap[dwNewTKMindex] = ptkmap[dwEntry] ; pBlockMacroDictEntry = (PBLOCKMACRODICTENTRY)gMasterTable[MTI_BLOCKMACROARRAY].pubStruct ; pBlockMacroDictEntry[gMasterTable[MTI_BLOCKMACROARRAY].dwCurIndex - 1].dwTKIndexOpen = dwNewTKMindex ; BIncreaseMacroLevel(TRUE, pglobl) ; continue ; // end of processing for this statement } } vIdentifySource(ptkmap + dwEntry, pglobl) ; ERR(("expected openbrace to follow *BlockMacros keyword.\n")); geErrorType = ERRTY_SYNTAX ; geErrorSev = ERRSEV_FATAL ; continue ; // end of processing for this statement } else if(eType == TY_SPECIAL && eConstruct == SPEC_INSERTBLOCK) { if(ptkmap[dwEntry].dwFlags & TKMF_MACROREF) { if(!BResolveBlockMacroReference(ptkmap, dwEntry, pglobl)) { vIdentifySource(ptkmap + dwEntry, pglobl) ; ERR((" *InsertBlockMacro Construct ignored.\n")); VIgnoreBlock(ptkmap + dwEntry, TRUE, pglobl) ; } } else { vIdentifySource(ptkmap + dwEntry, pglobl) ; ERR(("expected a =MacroName as the value of *InsertBlockMacro keyword.\n")); ERR((" *InsertBlockMacro Construct ignored.\n")); VIgnoreBlock(ptkmap + dwEntry, TRUE, pglobl) ; } continue ; // end of processing for this statement } else if(eType == TY_CONSTRUCT && eConstruct == CONSTRUCT_MACROS) { // *Macros definition dwEntry++; // don't copy *Macros statement while(ptkmap[dwEntry].dwKeywordID == ID_NULLENTRY) dwEntry++; // skip NULL_ENTRIES dwKeywordID = ptkmap[dwEntry].dwKeywordID ; if(dwKeywordID < ID_SPECIAL) { eType = mMainKeywordTable[dwKeywordID].eType ; eConstruct = (CONSTRUCT)(mMainKeywordTable[dwKeywordID].dwSubType) ; if(eType == TY_CONSTRUCT && eConstruct == CONSTRUCT_OPENBRACE) { // don't copy openbrace bValueMacroState = TRUE ; continue ; // end of processing for this statement } } vIdentifySource(ptkmap + dwEntry, pglobl) ; ERR(("expected openbrace to follow *Macros keyword.\n")); geErrorType = ERRTY_SYNTAX ; geErrorSev = ERRSEV_FATAL ; continue ; // end of processing for this statement } else if(eType == TY_CONSTRUCT && eConstruct == CONSTRUCT_OPENBRACE) { if(!BallocElementFromMasterTable( MTI_NEWTOKENMAP, &dwNewTKMindex, pglobl) ) { geErrorSev = ERRSEV_RESTART ; geErrorType = ERRTY_MEMORY_ALLOCATION ; gdwMasterTabIndex = MTI_NEWTOKENMAP ; } pNewtkmap[dwNewTKMindex] = ptkmap[dwEntry] ; BIncreaseMacroLevel(FALSE, pglobl) ; continue ; // end of processing for this statement } else if(eType == TY_CONSTRUCT && eConstruct == CONSTRUCT_CLOSEBRACE) { if(!BallocElementFromMasterTable( MTI_NEWTOKENMAP, &dwNewTKMindex, pglobl) ) { geErrorSev = ERRSEV_RESTART ; geErrorType = ERRTY_MEMORY_ALLOCATION ; gdwMasterTabIndex = MTI_NEWTOKENMAP ; } pNewtkmap[dwNewTKMindex] = ptkmap[dwEntry] ; BDecreaseMacroLevel(pNewtkmap, dwNewTKMindex, pglobl) ; continue ; // end of processing for this statement } } // execution path for ID_UNRECOGNIZED and ID_SYMBOL // rejoins here. This code is executed only if // keyword was not processed in the special cases above. // transfer all tokenmap fields to newTokenMap if(!BallocElementFromMasterTable( MTI_NEWTOKENMAP, &dwNewTKMindex, pglobl) ) { geErrorSev = ERRSEV_RESTART ; geErrorType = ERRTY_MEMORY_ALLOCATION ; gdwMasterTabIndex = MTI_NEWTOKENMAP ; continue ; } pNewtkmap[dwNewTKMindex] = ptkmap[dwEntry] ; if(ptkmap[dwEntry].dwFlags & TKMF_MACROREF) { if(!BResolveValueMacroReference(pNewtkmap , dwNewTKMindex, pglobl)) { pNewtkmap[dwNewTKMindex].dwKeywordID = ID_NULLENTRY ; } if(gdwVerbosity >= 4) { ERR(("\nEnumerate ValueMacro Reference at:\n")) ; vIdentifySource(pNewtkmap + dwNewTKMindex, pglobl) ; ERR((" %0.*s : %0.*s\n", pNewtkmap[dwNewTKMindex].aarKeyword.dw, pNewtkmap[dwNewTKMindex].aarKeyword.pub, pNewtkmap[dwNewTKMindex].aarValue.dw, pNewtkmap[dwNewTKMindex].aarValue.pub )); } } } // end of for each tkmap entry loop if(geErrorSev >= ERRSEV_RESTART) bStatus = FALSE ; return(bStatus) ; } BOOL BDefineValueMacroName( PTKMAP pNewtkmap, DWORD dwNewTKMindex, PGLOBL pglobl) { DWORD dwValueMacroEntry, dwSymbolID ; PVALUEMACRODICTENTRY pValueMacroDictEntry ; if(!BeatSurroundingWhiteSpaces(&pNewtkmap[dwNewTKMindex].aarKeyword) ) { vIdentifySource(pNewtkmap + dwNewTKMindex, pglobl) ; ERR(("syntax error in ValueMacro name.\n")); return(FALSE); } dwSymbolID = DWregisterSymbol(&pNewtkmap[dwNewTKMindex].aarKeyword, CONSTRUCT_MACROS, TRUE, INVALID_SYMBOLID, pglobl ) ; if(dwSymbolID == INVALID_SYMBOLID) return(FALSE); if(!BallocElementFromMasterTable( MTI_VALUEMACROARRAY, &dwValueMacroEntry, pglobl) ) { geErrorSev = ERRSEV_RESTART ; geErrorType = ERRTY_MEMORY_ALLOCATION ; gdwMasterTabIndex = MTI_VALUEMACROARRAY ; return(FALSE); } pValueMacroDictEntry = (PVALUEMACRODICTENTRY)gMasterTable[MTI_VALUEMACROARRAY].pubStruct ; pValueMacroDictEntry[dwValueMacroEntry].dwSymbolID = dwSymbolID ; pValueMacroDictEntry[dwValueMacroEntry].dwTKIndexValue = dwNewTKMindex ; return(TRUE); } BOOL BResolveValueMacroReference( PTKMAP ptkmap, DWORD dwTKMindex, PGLOBL pglobl) { BYTE ubChar ; PVALUEMACRODICTENTRY pValueMacroDictEntry ; ABSARRAYREF aarNewValue, aarValue, aarToken ; PBYTE pubDelimiters = "=\"%" ; // array of valid delimiters DWORD dwEntry, dwDelim ; // index to pubDelimiters // ------ original strict interpretation ------ // because the value contains a =MacroRef, we assume // the value is comprised purely of =MacroRef, "substrings" and // %{params} mixed up in any order. A new value string // without the =MacroRefs will replace the original. // ------ lenient interpretation -------- // if the GPD writer only uses the reserved characters // = to indicate a MacroRef and as part of a string literal // or comment, // " to delimit a string literal, or as part of a string literal // or comment, // % to begin a parameter construct , or as part of a string literal // or comment, or as the escape character within a string literal // // then the parser can allow 1 or more valuemacro references to be // embedded in any arbitrary value string subject to // these conditions: // a) "string literals" and %{param constructs} may not // contain =MacroRefs // b) the value associated with each *Macro: must be // a syntatically valid value object. // ie an INT, PAIR(,) , ENUM_CONSTANT, SUBSTRING, PARAM etc. // c) when all macro references are expanded, the resulting value // must itself satisfy b) for every keyword and macrodefinition // which contains one or more =Macroref. aarNewValue.dw = 0 ; // initialize so BCatToTmpHeap // will overwrite instead of append pValueMacroDictEntry = (PVALUEMACRODICTENTRY)gMasterTable[MTI_VALUEMACROARRAY].pubStruct ; aarValue = ptkmap[dwTKMindex].aarValue ; if(!BeatLeadingWhiteSpaces( &aarValue) ) { vIdentifySource(ptkmap + dwTKMindex, pglobl) ; ERR(("Internal error: =MacroRef expected, but No value found.\n")); return(FALSE) ; } ubChar = *aarValue.pub ; // first char in value string aarValue.dw-- ; aarValue.pub++ ; // clip off the first char to simulate // effect of BdelimitToken() while(1) { switch(ubChar) { case '=': // macroname indicator { DWORD dwRefSymbolID, // ID of MacroReference. dwNewTKMindex, // tokenmap index containing valueMacro. dwMaxIndex ; // one past last valMacro dictionary entry if(!BdelimitName(&aarValue, &aarToken, &ubChar ) ) { vIdentifySource(ptkmap + dwTKMindex, pglobl) ; ERR(("No MacroName detected after '='.\n")); return(FALSE) ; } if(aarValue.dw) { aarValue.dw-- ; aarValue.pub++ ; // clip off the first char to simulate } if(!BparseSymbol(&aarToken, &dwRefSymbolID, VALUE_SYMBOL_VALUEMACRO, pglobl) ) { return(FALSE) ; } // search ValueMacro Dict starting from most recent entry dwMaxIndex = gMasterTable[MTI_VALUEMACROARRAY].dwCurIndex ; for(dwEntry = 0 ; dwEntry < dwMaxIndex ; dwEntry++) { if(pValueMacroDictEntry[dwMaxIndex - 1 - dwEntry].dwSymbolID == dwRefSymbolID) break ; } if(dwEntry >= dwMaxIndex) { vIdentifySource(ptkmap + dwTKMindex, pglobl) ; ERR(("=MacroRef not resolved. Not defined or out of scope.\n")); return(FALSE) ; } dwNewTKMindex = pValueMacroDictEntry[dwMaxIndex - 1 - dwEntry].dwTKIndexValue ; if(dwNewTKMindex >= dwTKMindex ) { vIdentifySource(ptkmap + dwTKMindex, pglobl) ; ERR(("ValueMacro cannot reference itself.\n")); return(FALSE) ; } // concat valuestring onto tmpHeap. if(!BCatToTmpHeap(&aarNewValue, &ptkmap[dwNewTKMindex].aarValue, pglobl) ) { vIdentifySource(ptkmap + dwTKMindex, pglobl) ; ERR(("Concatenation to produce expanded macro value failed.\n")); return(FALSE) ; } break ; } case '%': // command parameter { if(!BdelimitToken(&aarValue, "}", &aarToken, &dwDelim) ) { vIdentifySource(ptkmap + dwTKMindex, pglobl) ; ERR(("missing terminating '}' in command parameter.\n")); return(FALSE) ; } // when concatenating you must restore the delimiters // % and } that were stripped by DelimitToken. aarToken.dw += 2 ; aarToken.pub-- ; if(!BCatToTmpHeap(&aarNewValue, &aarToken, pglobl) ) { vIdentifySource(ptkmap + dwTKMindex, pglobl) ; ERR(("Concatenation to produce expanded macro value failed.\n")); return(FALSE) ; } if(aarValue.dw) { ubChar = *aarValue.pub; aarValue.dw-- ; aarValue.pub++ ; // clip off the first char to simulate } else ubChar = '\0' ; // no more objects break ; } case '"' : // this is a string construct { if(!BdelimitToken(&aarValue, "\"", &aarToken, &dwDelim) ) { vIdentifySource(ptkmap + dwTKMindex, pglobl) ; ERR(("missing terminating '\"' in substring.\n")); return(FALSE) ; } // when concatenating you must restore the delimiters // " and " that were stripped by DelimitToken. aarToken.dw += 2 ; aarToken.pub-- ; if(!BCatToTmpHeap(&aarNewValue, &aarToken, pglobl) ) { vIdentifySource(ptkmap + dwTKMindex, pglobl) ; ERR(("Concatenation to produce expanded macro value failed.\n")); return(FALSE) ; } if(aarValue.dw) { ubChar = *aarValue.pub; aarValue.dw-- ; aarValue.pub++ ; // clip off the first char to simulate } else ubChar = '\0' ; // no more objects break ; } case '\0': // end of value string { (VOID) BeatLeadingWhiteSpaces(&aarValue) ; if(aarValue.dw) // is stuff remaining? { vIdentifySource(ptkmap + dwTKMindex, pglobl) ; ERR(("Error parsing value containing =MacroRef: %0.*s.\n", ptkmap[dwTKMindex].aarValue.dw, ptkmap[dwTKMindex].aarValue.pub)); ERR((" only %{parameter} or \"substrings\" may coexist with =MacroRefs.\n")); return(FALSE); } ptkmap[dwTKMindex].aarValue = aarNewValue ; return(TRUE); } default: { aarValue.dw++ ; aarValue.pub-- ; // restore the first char if(!BdelimitToken(&aarValue, pubDelimiters, &aarToken, &dwDelim ) ) { aarToken = aarValue ; ubChar = '\0' ; // no more objects aarValue.dw = 0 ; } else ubChar = pubDelimiters[dwDelim]; // concat valuestring onto tmpHeap. if(!BCatToTmpHeap(&aarNewValue, &aarToken, pglobl) ) { vIdentifySource(ptkmap + dwTKMindex, pglobl) ; ERR(("Concatenation to produce expanded macro value failed.\n")); return(FALSE) ; } break ; } } // end switch } // end while return(TRUE); // unreachable statement. } BOOL BdelimitName( PABSARRAYREF paarValue, // the remainder of the string without the Name PABSARRAYREF paarToken, // contains the Name PBYTE pubChar ) // first char after Name - NULL is returned if nothing // remains. { BYTE ubSrc ; DWORD dwI ; for(dwI = 0 ; dwI < paarValue->dw ; dwI++) { ubSrc = paarValue->pub[dwI] ; if( (ubSrc < 'a' || ubSrc > 'z') && (ubSrc < 'A' || ubSrc > 'Z') && (ubSrc < '0' || ubSrc > '9') && (ubSrc != '_') ) { break ; // end of keyword token. } } paarToken->pub = paarValue->pub ; paarToken->dw = dwI ; paarValue->pub += dwI; paarValue->dw -= dwI ; if(paarValue->dw) *pubChar = ubSrc ; else *pubChar = '\0' ; return(paarToken->dw != 0) ; } BOOL BCatToTmpHeap( PABSARRAYREF paarDest, PABSARRAYREF paarSrc, PGLOBL pglobl) /* if paarDest->dw is zero, copy paarSrc to the temp heap else append paarSrc to existing Heap. Note: assumes existing string in parrDest is the most recent item on the Heap. does not create null terminated strings! */ { ABSARRAYREF aarTmpDest ; if(!BcopyToTmpHeap(&aarTmpDest, paarSrc, pglobl)) return(FALSE) ; // append this run to existing string if(!paarDest->dw) // no prevs string exists { paarDest->pub = aarTmpDest.pub ; } else { // BUG_BUG paranoid: may check that string is contiguous ASSERT(paarDest->pub + paarDest->dw == aarTmpDest.pub) ; } paarDest->dw += aarTmpDest.dw ; return(TRUE); } BOOL BResolveBlockMacroReference( PTKMAP ptkmap, DWORD dwMacRefIndex, PGLOBL pglobl) { DWORD dwRefSymbolID, dwTKIndexOpen, dwTKIndexClose, dwEntry, // note used to index MacroDict and later TKmap dwNewTKMindex, dwMaxIndex; ABSARRAYREF aarValue ; PBLOCKMACRODICTENTRY pBlockMacroDictEntry ; PTKMAP pNewtkmap ; aarValue = ptkmap[dwMacRefIndex].aarValue ; if(!BeatDelimiter(&aarValue, "=") ) { ERR(("expected a =MacroName as the only value of *InsertBlockMacro keyword.\n")); return(FALSE); } if(!BparseSymbol(&aarValue, &dwRefSymbolID, VALUE_SYMBOL_BLOCKMACRO, pglobl) ) { return(FALSE) ; } // search BlockMacro Dict starting from most recent entry pBlockMacroDictEntry = (PBLOCKMACRODICTENTRY)gMasterTable[MTI_BLOCKMACROARRAY].pubStruct ; dwMaxIndex = gMasterTable[MTI_BLOCKMACROARRAY].dwCurIndex ; for(dwEntry = 0 ; dwEntry < dwMaxIndex ; dwEntry++) { if(pBlockMacroDictEntry[dwMaxIndex - 1 - dwEntry].dwSymbolID == dwRefSymbolID) break ; } if(dwEntry >= dwMaxIndex) { ERR(("=MacroRef not resolved. Not defined or out of scope.\n")); return(FALSE) ; } dwTKIndexOpen = pBlockMacroDictEntry[dwMaxIndex - 1 - dwEntry].dwTKIndexOpen ; dwTKIndexClose = pBlockMacroDictEntry[dwMaxIndex - 1 - dwEntry].dwTKIndexClose ; if(dwTKIndexOpen == INVALID_INDEX || dwTKIndexClose == INVALID_INDEX ) { ERR(("Macro cannot be referenced until it has been fully defined.\n")); return(FALSE); } pNewtkmap = (PTKMAP)gMasterTable[MTI_NEWTOKENMAP].pubStruct ; for(dwEntry = dwTKIndexOpen + 1 ; dwEntry < dwTKIndexClose ; dwEntry++) { // transfer all tokenmap fields to newTokenMap // except NULL entries. if(pNewtkmap[dwEntry].dwKeywordID == ID_NULLENTRY) continue ; if(!BallocElementFromMasterTable( MTI_NEWTOKENMAP, &dwNewTKMindex, pglobl) ) { geErrorSev = ERRSEV_RESTART ; geErrorType = ERRTY_MEMORY_ALLOCATION ; gdwMasterTabIndex = MTI_NEWTOKENMAP ; return(FALSE); } pNewtkmap[dwNewTKMindex] = pNewtkmap[dwEntry] ; } return(TRUE); } BOOL BDefineBlockMacroName( PTKMAP pNewtkmap, DWORD dwNewTKMindex, PGLOBL pglobl) { DWORD dwBlockMacroEntry, dwSymbolID ; PBLOCKMACRODICTENTRY pBlockMacroDictEntry ; if(!BeatSurroundingWhiteSpaces(&pNewtkmap[dwNewTKMindex].aarValue) ) { vIdentifySource(pNewtkmap + dwNewTKMindex, pglobl) ; ERR(("syntax error in BlockMacro name.\n")); return(FALSE); } dwSymbolID = DWregisterSymbol(&pNewtkmap[dwNewTKMindex].aarValue, CONSTRUCT_BLOCKMACRO, TRUE, INVALID_SYMBOLID, pglobl ) ; if(dwSymbolID == INVALID_SYMBOLID) return(FALSE); if(!BallocElementFromMasterTable( MTI_BLOCKMACROARRAY, &dwBlockMacroEntry, pglobl) ) { geErrorSev = ERRSEV_RESTART ; geErrorType = ERRTY_MEMORY_ALLOCATION ; gdwMasterTabIndex = MTI_BLOCKMACROARRAY ; return(FALSE); } pBlockMacroDictEntry = (PBLOCKMACRODICTENTRY)gMasterTable[MTI_BLOCKMACROARRAY].pubStruct ; pBlockMacroDictEntry[dwBlockMacroEntry].dwSymbolID = dwSymbolID ; pBlockMacroDictEntry[dwBlockMacroEntry].dwTKIndexOpen = INVALID_INDEX ; pBlockMacroDictEntry[dwBlockMacroEntry].dwTKIndexClose = INVALID_INDEX ; return(TRUE); } BOOL BIncreaseMacroLevel( BOOL bMacroInProgress, PGLOBL pglobl) // called in response to parsing open brace. { DWORD dwMacroLevel ; PMACROLEVELSTATE pMacroLevelStack ; if(!BallocElementFromMasterTable( MTI_MACROLEVELSTACK, &dwMacroLevel, pglobl) ) { geErrorSev = ERRSEV_RESTART ; geErrorType = ERRTY_MEMORY_ALLOCATION ; gdwMasterTabIndex = MTI_MACROLEVELSTACK ; return(FALSE); } pMacroLevelStack = (PMACROLEVELSTATE)gMasterTable[MTI_MACROLEVELSTACK].pubStruct ; pMacroLevelStack[dwMacroLevel].dwCurBlockMacroEntry = gMasterTable[MTI_BLOCKMACROARRAY].dwCurIndex ; pMacroLevelStack[dwMacroLevel].dwCurValueMacroEntry = gMasterTable[MTI_VALUEMACROARRAY].dwCurIndex; pMacroLevelStack[dwMacroLevel].bMacroInProgress = bMacroInProgress ; return(TRUE); } BOOL BDecreaseMacroLevel( PTKMAP pNewtkmap, DWORD dwNewTKMindex, PGLOBL pglobl) // called in response to parsing close brace. { DWORD dwMacroLevel, dwCurBlockMacroEntry, dwCurValueMacroEntry , dwTKIndexOpen, dwTKIndexClose, dwTKMindex, // location of expired macros. dwEntry; // index value and block macro dicts BOOL bMacroInProgress ; PMACROLEVELSTATE pMacroLevelStack ; PBLOCKMACRODICTENTRY pBlockMacroDictEntry ; PVALUEMACRODICTENTRY pValueMacroDictEntry ; if(!gMasterTable[MTI_MACROLEVELSTACK].dwCurIndex) { ERR(("Too many closing braces. Fatal syntax error.\n")); geErrorSev = ERRSEV_FATAL ; geErrorType = ERRTY_SYNTAX ; return(FALSE); } pBlockMacroDictEntry = (PBLOCKMACRODICTENTRY)gMasterTable[MTI_BLOCKMACROARRAY].pubStruct ; pValueMacroDictEntry = (PVALUEMACRODICTENTRY)gMasterTable[MTI_VALUEMACROARRAY].pubStruct ; pMacroLevelStack = (PMACROLEVELSTATE)gMasterTable[MTI_MACROLEVELSTACK].pubStruct ; dwMacroLevel = --gMasterTable[MTI_MACROLEVELSTACK].dwCurIndex; dwCurBlockMacroEntry = pMacroLevelStack[dwMacroLevel].dwCurBlockMacroEntry ; dwCurValueMacroEntry = pMacroLevelStack[dwMacroLevel].dwCurValueMacroEntry ; bMacroInProgress = pMacroLevelStack[dwMacroLevel].bMacroInProgress ; // Does this closing brace end a macro definition? if(bMacroInProgress) { if(pBlockMacroDictEntry[dwCurBlockMacroEntry - 1].dwTKIndexClose != INVALID_INDEX) { ERR(("Internal Error: macro nesting level inconsistency.\n")); geErrorSev = ERRSEV_FATAL ; geErrorType = ERRTY_CODEBUG ; return(FALSE); } pBlockMacroDictEntry[dwCurBlockMacroEntry - 1].dwTKIndexClose = dwNewTKMindex ; // location of } in newtokenArray; } // remove all traces of expired block and value macro definitions for(dwEntry = dwCurValueMacroEntry ; dwEntry < gMasterTable[MTI_VALUEMACROARRAY].dwCurIndex ; dwEntry++) { dwTKMindex = pValueMacroDictEntry[dwEntry].dwTKIndexValue ; pNewtkmap[dwTKMindex].dwKeywordID = ID_NULLENTRY ; } for(dwEntry = dwCurBlockMacroEntry ; dwEntry < gMasterTable[MTI_BLOCKMACROARRAY].dwCurIndex ; dwEntry++) { dwTKIndexOpen = pBlockMacroDictEntry[dwEntry].dwTKIndexOpen ; dwTKIndexClose = pBlockMacroDictEntry[dwEntry].dwTKIndexClose ; for(dwTKMindex = dwTKIndexOpen ; dwTKMindex <= dwTKIndexClose ; dwTKMindex++) pNewtkmap[dwTKMindex].dwKeywordID = ID_NULLENTRY ; } if(bMacroInProgress && gdwVerbosity >= 4) { VEnumBlockMacro(pNewtkmap, pBlockMacroDictEntry + dwCurBlockMacroEntry - 1, pglobl) ; } // must ensure these values are restored even in the event // of premature return; gMasterTable[MTI_BLOCKMACROARRAY].dwCurIndex = dwCurBlockMacroEntry; gMasterTable[MTI_VALUEMACROARRAY].dwCurIndex = dwCurValueMacroEntry; return(TRUE); } VOID VEnumBlockMacro( PTKMAP pNewtkmap, PBLOCKMACRODICTENTRY pBlockMacroDictEntry, PGLOBL pglobl ) { DWORD dwTKIndexOpen, dwTKIndexClose, dwTKMindex ; dwTKIndexOpen = pBlockMacroDictEntry->dwTKIndexOpen ; dwTKIndexClose = pBlockMacroDictEntry->dwTKIndexClose ; ERR(("\nContents of Block Macro ID value: %d at:\n", pBlockMacroDictEntry->dwSymbolID)) ; vIdentifySource(pNewtkmap + dwTKIndexOpen, pglobl) ; for(dwTKMindex = dwTKIndexOpen + 1 ; dwTKMindex < dwTKIndexClose ; dwTKMindex++) { if(pNewtkmap[dwTKMindex].dwKeywordID == ID_NULLENTRY) continue ; ERR((" %0.*s : %0.*s\n", pNewtkmap[dwTKMindex].aarKeyword.dw, pNewtkmap[dwTKMindex].aarKeyword.pub, pNewtkmap[dwTKMindex].aarValue.dw, pNewtkmap[dwTKMindex].aarValue.pub )); } } // ---- scrap pile - may find some useful odds and ends here ----- // gMasterTable[MTI_VALUEMACROARRAY].dwCurIndex-- ; // remove macrodef from dictionary.