You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1528 lines
50 KiB
1528 lines
50 KiB
// Copyright (c) 1996-1999 Microsoft Corporation
|
|
/*
|
|
* state1.c - implements the state machine to track constructs
|
|
*/
|
|
|
|
|
|
|
|
#include "gpdparse.h"
|
|
|
|
|
|
// ---- functions defined in state1.c ---- //
|
|
|
|
BOOL BInterpretTokens(
|
|
PTKMAP ptkmap, // pointer to tokenmap
|
|
BOOL bFirstPass, // is this the first or 2nd time around?
|
|
PGLOBL pglobl
|
|
) ;
|
|
|
|
BOOL BprocessSpecialKeyword(
|
|
PTKMAP ptkmap, // pointer to tokenmap
|
|
BOOL bFirstPass, // is this the first or 2nd time around?
|
|
PGLOBL pglobl
|
|
) ;
|
|
|
|
BOOL BprocessSymbolKeyword(
|
|
PTKMAP ptkmap, // pointer to current entry in tokenmap
|
|
PGLOBL pglobl
|
|
) ;
|
|
|
|
VOID VinitAllowedTransitions(
|
|
PGLOBL pglobl
|
|
);
|
|
|
|
BOOL BpushState(
|
|
PTKMAP ptkmap, // pointer to current entry in tokenmap
|
|
BOOL bFirstPass,
|
|
PGLOBL pglobl
|
|
) ;
|
|
|
|
BOOL BchangeState(
|
|
PTKMAP ptkmap, // pointer to construct in tokenmap
|
|
CONSTRUCT eConstruct, // this will induce a transition to NewState
|
|
STATE stOldState,
|
|
BOOL bSymbol, // should dwValue be saved as a SymbolID ?
|
|
BOOL bFirstPass,
|
|
PGLOBL pglobl
|
|
) ;
|
|
|
|
DWORD DWregisterSymbol(
|
|
PABSARRAYREF paarSymbol, // the symbol string to register
|
|
CONSTRUCT eConstruct , // type of construct determines class of symbol.
|
|
BOOL bCopy, // shall we copy paarSymbol to heap? May set
|
|
DWORD dwFeatureID, // if you are registering an option symbol
|
|
PGLOBL pglobl
|
|
) ;
|
|
|
|
BOOL BaddAARtoHeap(
|
|
PABSARRAYREF paarSrc,
|
|
PARRAYREF parDest,
|
|
DWORD dwAlign,
|
|
PGLOBL pglobl) ;
|
|
|
|
BOOL BwriteToHeap(
|
|
OUT PDWORD pdwDestOff, // heap offset of dest string
|
|
PBYTE pubSrc, // points to src string
|
|
DWORD dwCnt, // num bytes to copy from src to dest.
|
|
DWORD dwAlign,
|
|
PGLOBL pglobl) ;
|
|
|
|
DWORD DWsearchSymbolListForAAR(
|
|
PABSARRAYREF paarSymbol,
|
|
DWORD dwNodeIndex,
|
|
PGLOBL pglobl) ;
|
|
|
|
DWORD DWsearchSymbolListForID(
|
|
DWORD dwSymbolID, // find node containing this ID.
|
|
DWORD dwNodeIndex,
|
|
PGLOBL pglobl
|
|
) ;
|
|
|
|
BOOL BCmpAARtoAR(
|
|
PABSARRAYREF paarStr1,
|
|
PARRAYREF parStr2,
|
|
PGLOBL pglobl
|
|
) ;
|
|
|
|
BOOL BpopState(
|
|
PGLOBL pglobl
|
|
) ;
|
|
|
|
VOID VinitDictionaryIndex(
|
|
PGLOBL pglobl
|
|
) ;
|
|
|
|
VOID VcharSubstitution(
|
|
PABSARRAYREF paarStr,
|
|
BYTE ubTgt,
|
|
BYTE ubReplcmnt,
|
|
PGLOBL pglobl
|
|
) ;
|
|
|
|
|
|
VOID VIgnoreBlock(
|
|
PTKMAP ptkmap,
|
|
BOOL bIgnoreBlock,
|
|
PGLOBL pglobl
|
|
) ;
|
|
|
|
|
|
|
|
// ---------------------------------------------------- //
|
|
|
|
|
|
|
|
|
|
BOOL BInterpretTokens(
|
|
PTKMAP ptkmap, // pointer to tokenmap
|
|
BOOL bFirstPass, // is this the first or 2nd time around?
|
|
PGLOBL pglobl
|
|
)
|
|
{
|
|
DWORD dwKeywordID ;
|
|
KEYWORD_TYPE eType;
|
|
WORD wEntry ;
|
|
BOOL bStatus = FALSE ;
|
|
|
|
|
|
|
|
if(bFirstPass)
|
|
{
|
|
// This bit of code creates a synthesized inputslot
|
|
// which the UI code will interpret as the UseFormToTrayTable
|
|
|
|
// BUG_BUG!!!: should be replaced by preprocessing
|
|
// shortcuts etc. Or by an option in stdnames.gpd
|
|
|
|
ABSARRAYREF aarSymbol ;
|
|
DWORD dwFeaID ;
|
|
|
|
aarSymbol.pub = "InputBin" ; // no way to keep this in ssync
|
|
// with the global table.
|
|
aarSymbol.dw = strlen(aarSymbol.pub) ;
|
|
|
|
|
|
dwFeaID = DWregisterSymbol(&aarSymbol, CONSTRUCT_FEATURE,
|
|
TRUE, INVALID_SYMBOLID, pglobl) ;
|
|
|
|
if(dwFeaID != INVALID_SYMBOLID)
|
|
{
|
|
aarSymbol.pub = "FORMSOURCE" ; // no way to keep this in ssync
|
|
// with the global table.
|
|
aarSymbol.dw = strlen(aarSymbol.pub) ;
|
|
|
|
dwFeaID = DWregisterSymbol(&aarSymbol, CONSTRUCT_OPTION,
|
|
TRUE, dwFeaID, pglobl) ;
|
|
ASSERT(dwFeaID == 0); // this option must be first.
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ARRAYREF arStrValue ;
|
|
BOOL bPrevsExists ;
|
|
|
|
|
|
if(!BwriteToHeap(&arStrValue.loOffset, "\0\0", 2, 4, pglobl) )
|
|
{
|
|
bStatus = FALSE ; // heap overflow start over.
|
|
}
|
|
arStrValue.dwCount = 0 ; // create a NULL unicode string.
|
|
|
|
BexchangeArbDataInFOATNode(
|
|
0 , // dwFea
|
|
0, // dwOption,
|
|
offsetof(DFEATURE_OPTIONS, atrOptDisplayName ),
|
|
sizeof(ARRAYREF),
|
|
NULL, // previous contents of attribute node
|
|
(PBYTE)&arStrValue, // new contents of attribute node.
|
|
&bPrevsExists, // previous contents existed.
|
|
FALSE, // access synthetic features
|
|
pglobl
|
|
) ;
|
|
}
|
|
|
|
|
|
for(wEntry = 0 ; geErrorSev < ERRSEV_RESTART ; wEntry++)
|
|
{
|
|
// 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[wEntry].dwKeywordID ;
|
|
|
|
if (dwKeywordID == gdwID_IgnoreBlock)
|
|
{
|
|
VIgnoreBlock(ptkmap + wEntry, TRUE, pglobl) ;
|
|
continue ;
|
|
}
|
|
|
|
switch(dwKeywordID)
|
|
{
|
|
case (ID_EOF):
|
|
{
|
|
// BUG_BUG!!! Cleanup code here
|
|
// integrity checking code:
|
|
// check to see mdwCurStsPtr == 0
|
|
// and any other loose ends are tied.
|
|
|
|
bStatus = (mdwCurStsPtr) ? (FALSE) : (TRUE);
|
|
return(bStatus) ;
|
|
}
|
|
case (ID_NULLENTRY):
|
|
{
|
|
continue ; // does this work?
|
|
// should drop to bottom of FOREVER for loop.
|
|
}
|
|
case (ID_SYMBOL):
|
|
{
|
|
bStatus = BprocessSymbolKeyword(ptkmap + wEntry, pglobl) ;
|
|
continue ; // uses TKMF_SYMBOL_REGISTERED to track passes
|
|
}
|
|
case (ID_UNRECOGNIZED):
|
|
{ // if identified on first pass, won't pass this way again!
|
|
if(bStatus = BidentifyAttributeKeyword(ptkmap + wEntry, pglobl) )
|
|
{
|
|
dwKeywordID = ptkmap[wEntry].dwKeywordID ;
|
|
break ; // fall out of switch statement
|
|
// and into next switch.
|
|
}
|
|
|
|
if(bFirstPass)
|
|
{
|
|
vIdentifySource(ptkmap + wEntry, pglobl) ;
|
|
ERR(("Warning, unrecognized keyword: %0.*s\n", \
|
|
ptkmap[wEntry].aarKeyword.dw, \
|
|
ptkmap[wEntry].aarKeyword.pub));
|
|
|
|
VIgnoreBlock(ptkmap + wEntry, FALSE, pglobl) ;
|
|
|
|
// if this keyword is immediately
|
|
// followed by open brace, ignore all
|
|
// statements from there until the matching closing
|
|
// brace.
|
|
}
|
|
|
|
continue ;
|
|
}
|
|
default :
|
|
break ;
|
|
}
|
|
|
|
eType = mMainKeywordTable[dwKeywordID].eType ;
|
|
|
|
switch (eType)
|
|
{
|
|
case (TY_CONSTRUCT):
|
|
{
|
|
if( CONSTRUCT_CLOSEBRACE ==
|
|
(CONSTRUCT)(mMainKeywordTable[dwKeywordID].dwSubType))
|
|
{
|
|
bStatus = BpopState(pglobl) ;
|
|
if(!bStatus)
|
|
{
|
|
vIdentifySource(ptkmap + wEntry, pglobl) ;
|
|
ERR(("Unmatched closing brace!\n"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bStatus = BpushState(ptkmap + wEntry, bFirstPass, pglobl) ;
|
|
if(!bStatus)
|
|
{
|
|
vIdentifySource(ptkmap + wEntry, pglobl) ;
|
|
// ERR(("Fatal error parsing construct.\n"));
|
|
// stack is now invalid.
|
|
// in the future make parser smarter -
|
|
// eject contents between braces.
|
|
// geErrorType = ERRTY_SYNTAX ;
|
|
// geErrorSev = ERRSEV_FATAL ;
|
|
}
|
|
}
|
|
break ;
|
|
}
|
|
case (TY_ATTRIBUTE) :
|
|
{
|
|
if(!bFirstPass) // must wait till all attribute
|
|
{ // buffers are allocated.
|
|
bStatus = BprocessAttribute(ptkmap + wEntry, pglobl) ;
|
|
if(!bStatus)
|
|
{
|
|
vIdentifySource(ptkmap + wEntry, pglobl) ;
|
|
}
|
|
}
|
|
break ;
|
|
}
|
|
case (TY_SPECIAL) :
|
|
{
|
|
bStatus = BprocessSpecialKeyword(ptkmap + wEntry,
|
|
bFirstPass, pglobl) ; // don't really know if 2 passes
|
|
{ // are needed.
|
|
if(!bStatus)
|
|
{
|
|
vIdentifySource(ptkmap + wEntry, pglobl) ;
|
|
}
|
|
}
|
|
break ;
|
|
}
|
|
default:
|
|
{
|
|
vIdentifySource(ptkmap + wEntry, pglobl) ;
|
|
ERR(("Internal Error: unrecognized keyword type! %0.*s.\n",
|
|
ptkmap[wEntry].aarKeyword.dw,
|
|
ptkmap[wEntry].aarKeyword.pub));
|
|
geErrorSev = ERRSEV_FATAL ;
|
|
geErrorType = ERRTY_CODEBUG ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
if(geErrorSev >= ERRSEV_RESTART)
|
|
bStatus = FALSE ;
|
|
return(bStatus) ;
|
|
}
|
|
|
|
|
|
BOOL BprocessSpecialKeyword(
|
|
PTKMAP ptkmap, // pointer to tokenmap
|
|
BOOL bFirstPass, // is this the first or 2nd time around?
|
|
PGLOBL pglobl
|
|
)
|
|
{
|
|
DWORD dwKeywordID, dwOffset ;
|
|
CONSTRUCT eSubType ;
|
|
BOOL bStatus = FALSE ;
|
|
STATE stState ;
|
|
|
|
dwKeywordID = ptkmap->dwKeywordID ;
|
|
|
|
eSubType = (SPECIAL)(mMainKeywordTable[dwKeywordID].dwSubType) ;
|
|
dwOffset = mMainKeywordTable[dwKeywordID].dwOffset ;
|
|
|
|
if(mdwCurStsPtr)
|
|
stState = mpstsStateStack[mdwCurStsPtr - 1].stState ;
|
|
else
|
|
stState = STATE_ROOT ;
|
|
|
|
switch(eSubType)
|
|
{
|
|
// note: for the record I despise special casing these
|
|
// shortcuts. Ideally I could preprocess them
|
|
// to convert
|
|
// *TTFS: "font name" : <fontID>
|
|
// into
|
|
// *TTFontSub: <unique value symbol>
|
|
// {
|
|
// *TTFontName: "font name"
|
|
// *DevFontID: <fontID>
|
|
// }
|
|
// the only glitch with this is if the same font is listed
|
|
// multiple times in the GPD file, it will appear
|
|
// in the TTFontSubTable multiple times.
|
|
|
|
#if 0
|
|
case SPEC_FONTSUB :
|
|
{
|
|
ARRAYREF arFontname ;
|
|
ABSARRAYREF aarFontname ;
|
|
|
|
if(stState != STATE_ROOT)
|
|
{
|
|
vIdentifySource(ptkmap, pglobl) ;
|
|
ERR(("The *TTFS keyword must reside at the root level.\n"));
|
|
return(FALSE) ;
|
|
}
|
|
|
|
if(bFirstPass)
|
|
{
|
|
// parse string value and register as a symbol.
|
|
if((ptkmap->dwFlags & TKMF_NOVALUE ) ||
|
|
!BparseString(&ptkmap->aarValue, &arFontname) )
|
|
{
|
|
vIdentifySource(ptkmap, pglobl) ;
|
|
ERR(("*TTFS fontname is not a valid string value.\n"));
|
|
return(FALSE) ;
|
|
}
|
|
|
|
if(ptkmap->aarValue.pub[0] != ':')
|
|
{
|
|
ERR(("Colon delimiter expected after parsing fontname string for *TTFontSub.\n")) ;
|
|
return(FALSE) ;
|
|
}
|
|
// a keyword with a composite value
|
|
(VOID)BeatDelimiter(&ptkmap->aarValue, ":") ;
|
|
// I know this will succeed!
|
|
// paarValue should now contain the integer
|
|
// fontID. Leave this for the 2nd pass.
|
|
|
|
// convert arFontname to aar suitable for
|
|
// Font registration.
|
|
|
|
aarFontname.dw = arFontname.dwCount ;
|
|
aarFontname.pub = arFontname.loOffset + mpubOffRef;
|
|
|
|
// New version of DWregisterSymbol registers the entire
|
|
// string - whitespaces and all.
|
|
//
|
|
// Note suppress copying symbol into Heap since
|
|
// ParseString has already done that.
|
|
|
|
ptkmap->dwValue = DWregisterSymbol(&aarFontname,
|
|
CONSTRUCT_TTFONTSUBS, FALSE, pglobl ) ;
|
|
if(ptkmap->dwValue != INVALID_SYMBOLID)
|
|
{
|
|
ptkmap->dwFlags |= TKMF_SYMBOL_REGISTERED ;
|
|
}
|
|
else
|
|
{
|
|
return(FALSE) ;
|
|
}
|
|
}
|
|
else if(ptkmap->dwFlags & TKMF_SYMBOL_REGISTERED)
|
|
// second pass, TTFONTSUBTABLE arrays allocated
|
|
// for all successfully registered entrants.
|
|
{
|
|
PSYMBOLNODE psn ;
|
|
DWORD dwDevFontID ;
|
|
PTTFONTSUBTABLE pttft ;
|
|
DWORD dwTTFontNameIndex ;
|
|
|
|
psn = (PSYMBOLNODE) gMasterTable[MTI_SYMBOLTREE].pubStruct ;
|
|
|
|
pttft = (PTTFONTSUBTABLE)
|
|
gMasterTable[MTI_TTFONTSUBTABLE].pubStruct;
|
|
pttft += ptkmap->dwValue ; // index correct element.
|
|
|
|
dwTTFontNameIndex = DWsearchSymbolListForID(ptkmap->dwValue,
|
|
mdwTTFontSymbols, pglobl) ;
|
|
|
|
ASSERT(dwTTFontNameIndex != INVALID_INDEX) ;
|
|
|
|
pttft->arTTFontName = psn[dwTTFontNameIndex].arSymbolName ;
|
|
// if structure assignment is supported.
|
|
|
|
bStatus = BparseInteger(&ptkmap->aarValue, &dwDevFontID,
|
|
VALUE_INTEGER) ;
|
|
if(bStatus)
|
|
pttft->dwDevFontID = dwDevFontID ;
|
|
else
|
|
{
|
|
// BUG_BUG! : Error parsing TTFontSub table entry
|
|
// syntax error in devID. Dead codepath who cares?
|
|
pttft->dwDevFontID = 0 ; // is this a good fallback?
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
case SPEC_INVALID_COMBO:
|
|
{
|
|
if(bFirstPass)
|
|
{
|
|
bStatus = TRUE ;
|
|
break; // do nothing on the FirstPass
|
|
}
|
|
|
|
bStatus = BparseInvalidCombination(&ptkmap->aarValue, dwOffset, pglobl) ;
|
|
break;
|
|
}
|
|
case SPEC_INVALID_INS_COMBO:
|
|
{
|
|
if(bFirstPass)
|
|
{
|
|
bStatus = TRUE ;
|
|
break; // do nothing on the FirstPass
|
|
}
|
|
|
|
bStatus = BparseInvalidInstallableCombination1(&ptkmap->aarValue,
|
|
dwOffset, pglobl) ;
|
|
break;
|
|
}
|
|
case SPEC_MEM_CONFIG_KB: // should already be replaced
|
|
case SPEC_MEM_CONFIG_MB: // at parseKeyword
|
|
default:
|
|
{
|
|
break ;
|
|
}
|
|
}
|
|
return(bStatus) ;
|
|
}
|
|
|
|
|
|
|
|
BOOL BprocessSymbolKeyword(
|
|
PTKMAP ptkmap, // pointer to current entry in tokenmap
|
|
PGLOBL pglobl
|
|
)
|
|
{
|
|
// registering the TTFontNames as symbols allows
|
|
// me to count the number of unique names and reserve
|
|
// the proper amount of TTFONTSUBTABLE elements and
|
|
// eliminates multiple instances of the same name.
|
|
|
|
BOOL bStatus = FALSE ;
|
|
STATE stState ;
|
|
|
|
if(mdwCurStsPtr)
|
|
stState = mpstsStateStack[mdwCurStsPtr - 1].stState ;
|
|
else
|
|
stState = STATE_ROOT ;
|
|
|
|
switch (stState)
|
|
{
|
|
// note TTFontSubs now has its own keyword.
|
|
// and is handled as a Special Keyword.
|
|
default:
|
|
{
|
|
// assume its just VALUEMACRO state
|
|
// or user-defined symbols from an undefined
|
|
// keyword.
|
|
// ignore these.
|
|
bStatus = TRUE ;
|
|
break ;
|
|
}
|
|
}
|
|
return(bStatus);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID VinitAllowedTransitions(
|
|
PGLOBL pglobl)
|
|
{
|
|
PSTATE pst ;
|
|
PBOOL pb ;
|
|
WORD wS, wC, wA ;
|
|
|
|
// default initializer is STATE_INVALID
|
|
for(wS = 0 ; wS < STATE_LAST ; wS++)
|
|
{
|
|
for(wC = 0 ; wC < CONSTRUCT_LAST ; wC++)
|
|
gastAllowedTransitions[wS][wC] = STATE_INVALID ;
|
|
}
|
|
|
|
pst = gastAllowedTransitions[STATE_ROOT] ;
|
|
|
|
pst[CONSTRUCT_UIGROUP] = STATE_UIGROUP;
|
|
pst[CONSTRUCT_FEATURE] = STATE_FEATURE;
|
|
pst[CONSTRUCT_SWITCH] = STATE_SWITCH_ROOT;
|
|
pst[CONSTRUCT_COMMAND] = STATE_COMMAND;
|
|
pst[CONSTRUCT_FONTCART] = STATE_FONTCART;
|
|
pst[CONSTRUCT_TTFONTSUBS] = STATE_TTFONTSUBS;
|
|
pst[CONSTRUCT_OEM] = STATE_OEM;
|
|
|
|
pst = gastAllowedTransitions[STATE_UIGROUP] ;
|
|
|
|
pst[CONSTRUCT_UIGROUP] = STATE_UIGROUP;
|
|
pst[CONSTRUCT_FEATURE] = STATE_FEATURE;
|
|
|
|
pst = gastAllowedTransitions[STATE_FEATURE] ;
|
|
|
|
pst[CONSTRUCT_OPTION] = STATE_OPTIONS;
|
|
pst[CONSTRUCT_SWITCH] = STATE_SWITCH_FEATURE;
|
|
|
|
pst = gastAllowedTransitions[STATE_OPTIONS] ;
|
|
|
|
pst[CONSTRUCT_SWITCH] = STATE_SWITCH_OPTION;
|
|
pst[CONSTRUCT_COMMAND] = STATE_COMMAND;
|
|
pst[CONSTRUCT_OEM] = STATE_OEM;
|
|
|
|
pst = gastAllowedTransitions[STATE_SWITCH_ROOT] ;
|
|
|
|
pst[CONSTRUCT_CASE] = STATE_CASE_ROOT;
|
|
pst[CONSTRUCT_DEFAULT] = STATE_DEFAULT_ROOT;
|
|
|
|
pst = gastAllowedTransitions[STATE_SWITCH_FEATURE] ;
|
|
|
|
pst[CONSTRUCT_CASE] = STATE_CASE_FEATURE;
|
|
pst[CONSTRUCT_DEFAULT] = STATE_DEFAULT_FEATURE;
|
|
|
|
pst = gastAllowedTransitions[STATE_SWITCH_OPTION] ;
|
|
|
|
pst[CONSTRUCT_CASE] = STATE_CASE_OPTION;
|
|
pst[CONSTRUCT_DEFAULT] = STATE_DEFAULT_OPTION;
|
|
|
|
pst = gastAllowedTransitions[STATE_CASE_ROOT] ;
|
|
|
|
pst[CONSTRUCT_SWITCH] = STATE_SWITCH_ROOT;
|
|
pst[CONSTRUCT_COMMAND] = STATE_COMMAND;
|
|
pst[CONSTRUCT_OEM] = STATE_OEM;
|
|
|
|
pst = gastAllowedTransitions[STATE_DEFAULT_ROOT] ;
|
|
|
|
pst[CONSTRUCT_SWITCH] = STATE_SWITCH_ROOT;
|
|
pst[CONSTRUCT_COMMAND] = STATE_COMMAND;
|
|
pst[CONSTRUCT_OEM] = STATE_OEM;
|
|
|
|
pst = gastAllowedTransitions[STATE_CASE_FEATURE] ;
|
|
|
|
pst[CONSTRUCT_SWITCH] = STATE_SWITCH_FEATURE;
|
|
pst[CONSTRUCT_COMMAND] = STATE_COMMAND;
|
|
pst[CONSTRUCT_OEM] = STATE_OEM;
|
|
|
|
pst = gastAllowedTransitions[STATE_DEFAULT_FEATURE] ;
|
|
|
|
pst[CONSTRUCT_SWITCH] = STATE_SWITCH_FEATURE;
|
|
pst[CONSTRUCT_COMMAND] = STATE_COMMAND;
|
|
pst[CONSTRUCT_OEM] = STATE_OEM;
|
|
|
|
pst = gastAllowedTransitions[STATE_CASE_OPTION] ;
|
|
|
|
pst[CONSTRUCT_SWITCH] = STATE_SWITCH_OPTION;
|
|
pst[CONSTRUCT_COMMAND] = STATE_COMMAND;
|
|
pst[CONSTRUCT_OEM] = STATE_OEM;
|
|
|
|
pst = gastAllowedTransitions[STATE_DEFAULT_OPTION] ;
|
|
|
|
pst[CONSTRUCT_SWITCH] = STATE_SWITCH_OPTION;
|
|
pst[CONSTRUCT_COMMAND] = STATE_COMMAND;
|
|
pst[CONSTRUCT_OEM] = STATE_OEM;
|
|
|
|
|
|
// ------------------------------------------------------ //
|
|
// now initialize allowed attributes table:
|
|
// which attributes are allowed in each state.
|
|
|
|
// default initializer is FALSE -- No attributes are allowed
|
|
// in any state.
|
|
|
|
for(wS = 0 ; wS < STATE_LAST ; wS++)
|
|
{
|
|
for(wA = 0 ; wA < ATT_LAST ; wA++)
|
|
{
|
|
gabAllowedAttributes[wS][wA] = FALSE ;
|
|
}
|
|
}
|
|
|
|
|
|
pb = gabAllowedAttributes[STATE_ROOT] ;
|
|
pb[ATT_GLOBAL_ONLY] = TRUE ;
|
|
pb[ATT_GLOBAL_FREEFLOAT] = TRUE ;
|
|
|
|
pb = gabAllowedAttributes[STATE_CASE_ROOT] ;
|
|
pb[ATT_GLOBAL_FREEFLOAT] = TRUE ;
|
|
|
|
pb = gabAllowedAttributes[STATE_DEFAULT_ROOT] ;
|
|
pb[ATT_GLOBAL_FREEFLOAT] = TRUE ;
|
|
|
|
pb = gabAllowedAttributes[STATE_OPTIONS] ;
|
|
pb[ATT_GLOBAL_FREEFLOAT] = TRUE ;
|
|
pb[ATT_LOCAL_FEATURE_FF] = TRUE ;
|
|
pb[ATT_LOCAL_OPTION_ONLY] = TRUE ;
|
|
pb[ATT_LOCAL_OPTION_FF] = TRUE ;
|
|
|
|
pb = gabAllowedAttributes[STATE_CASE_OPTION] ;
|
|
pb[ATT_GLOBAL_FREEFLOAT] = TRUE ;
|
|
pb[ATT_LOCAL_FEATURE_FF] = TRUE ;
|
|
pb[ATT_LOCAL_OPTION_FF] = TRUE ;
|
|
|
|
pb = gabAllowedAttributes[STATE_DEFAULT_OPTION] ;
|
|
pb[ATT_GLOBAL_FREEFLOAT] = TRUE ;
|
|
pb[ATT_LOCAL_FEATURE_FF] = TRUE ;
|
|
pb[ATT_LOCAL_OPTION_FF] = TRUE ;
|
|
|
|
pb = gabAllowedAttributes[STATE_FEATURE] ;
|
|
|
|
pb[ATT_LOCAL_FEATURE_ONLY] = TRUE ;
|
|
pb[ATT_LOCAL_FEATURE_FF] = TRUE ;
|
|
|
|
pb = gabAllowedAttributes[STATE_CASE_FEATURE] ;
|
|
pb[ATT_LOCAL_FEATURE_FF] = TRUE ;
|
|
|
|
pb = gabAllowedAttributes[STATE_DEFAULT_FEATURE] ;
|
|
pb[ATT_LOCAL_FEATURE_FF] = TRUE ;
|
|
|
|
pb = gabAllowedAttributes[STATE_COMMAND] ;
|
|
pb[ATT_LOCAL_COMMAND_ONLY] = TRUE ;
|
|
|
|
pb = gabAllowedAttributes[STATE_FONTCART] ;
|
|
pb[ATT_LOCAL_FONTCART_ONLY] = TRUE ;
|
|
|
|
pb = gabAllowedAttributes[STATE_TTFONTSUBS] ;
|
|
pb[ATT_LOCAL_TTFONTSUBS_ONLY] = TRUE ;
|
|
|
|
pb = gabAllowedAttributes[STATE_OEM] ;
|
|
pb[ATT_LOCAL_OEM_ONLY] = TRUE ;
|
|
}
|
|
|
|
|
|
|
|
BOOL BpushState(
|
|
PTKMAP ptkmap, // pointer to current entry in tokenmap
|
|
BOOL bFirstPass,
|
|
PGLOBL pglobl
|
|
)
|
|
{
|
|
// this function assumes (eType == TY_CONSTRUCT)
|
|
|
|
DWORD dwKeywordID ;
|
|
CONSTRUCT eSubType ;
|
|
BOOL bStatus = FALSE ;
|
|
STATE stOldState, stNewState ;
|
|
|
|
if(mdwCurStsPtr >= mdwMaxStackDepth)
|
|
{
|
|
if(ERRSEV_RESTART > geErrorSev)
|
|
{
|
|
ERR(("Exceeded max state stack depth. Restarting\n"));
|
|
geErrorSev = ERRSEV_RESTART ;
|
|
geErrorType = ERRTY_MEMORY_ALLOCATION ;
|
|
gdwMasterTabIndex = MTI_STSENTRY ;
|
|
}
|
|
return(FALSE);
|
|
}
|
|
dwKeywordID = ptkmap->dwKeywordID ;
|
|
|
|
eSubType = (CONSTRUCT)(mMainKeywordTable[dwKeywordID].dwSubType) ;
|
|
|
|
if(mdwCurStsPtr)
|
|
stOldState = mpstsStateStack[mdwCurStsPtr - 1].stState ;
|
|
else
|
|
stOldState = STATE_ROOT ;
|
|
|
|
switch (eSubType)
|
|
{
|
|
// note CONSTRUCT_CLOSEBRACE already processed
|
|
// by PopState().
|
|
case (CONSTRUCT_OPENBRACE):
|
|
{
|
|
vIdentifySource(ptkmap, pglobl) ;
|
|
ERR(("OpenBrace encountered without accompanying construct keyword.\n"));
|
|
geErrorType = ERRTY_SYNTAX ;
|
|
geErrorSev = ERRSEV_FATAL ;
|
|
break ;
|
|
}
|
|
case (CONSTRUCT_FEATURE):
|
|
case (CONSTRUCT_OPTION):
|
|
case (CONSTRUCT_SWITCH):
|
|
case (CONSTRUCT_COMMAND): // commandID's already registered.
|
|
case (CONSTRUCT_CASE):
|
|
case (CONSTRUCT_FONTCART):
|
|
case (CONSTRUCT_TTFONTSUBS):
|
|
{
|
|
bStatus = BchangeState(ptkmap, eSubType, stOldState, TRUE,
|
|
bFirstPass, pglobl) ;
|
|
|
|
break ;
|
|
}
|
|
case (CONSTRUCT_UIGROUP):
|
|
{
|
|
// BUG_BUG!!!!! incomplete. no reqest for this.
|
|
}
|
|
case (CONSTRUCT_DEFAULT):
|
|
case (CONSTRUCT_OEM):
|
|
{
|
|
bStatus = BchangeState(ptkmap, eSubType, stOldState, FALSE,
|
|
bFirstPass, pglobl) ;
|
|
|
|
break ;
|
|
}
|
|
default:
|
|
{
|
|
bStatus = TRUE ; // its ok to ignore some keywords.
|
|
break ;
|
|
}
|
|
}
|
|
return(bStatus) ;
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
dead code.
|
|
VOID VsetbTTFontSubs(
|
|
IN PABSARRAYREF paarValue)
|
|
{
|
|
// BUG_BUG!!!!!:
|
|
// exactly what is supposed to happen ? register
|
|
// synthesized symbol ?
|
|
gbTTFontSubs = FALSE ;
|
|
|
|
if( BeatSurroundingWhiteSpaces(paarValue) )
|
|
{
|
|
if(paarValue->dw == 2 && ! strncmp(paarValue->pub, "ON", 2))
|
|
gbTTFontSubs = TRUE ;
|
|
else if(paarValue->dw != 3 || strncmp(paarValue->pub, "OFF", 3))
|
|
{
|
|
BUG_BUG!: value must be either "ON" or "OFF".
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
BOOL BchangeState(
|
|
PTKMAP ptkmap, // pointer to construct in tokenmap
|
|
CONSTRUCT eConstruct, // this will induce a transition to NewState
|
|
STATE stOldState,
|
|
BOOL bSymbol, // should dwValue be saved as a SymbolID ?
|
|
BOOL bFirstPass,
|
|
PGLOBL pglobl
|
|
)
|
|
{
|
|
BOOL bStatus = FALSE ;
|
|
STATE stNewState ;
|
|
|
|
// was checked in PushState, but never hurts to check
|
|
// in the same function that consumes the resource.
|
|
if(mdwCurStsPtr >= mdwMaxStackDepth)
|
|
{
|
|
if(ERRSEV_RESTART > geErrorSev)
|
|
{
|
|
geErrorSev = ERRSEV_RESTART ;
|
|
geErrorType = ERRTY_MEMORY_ALLOCATION ;
|
|
gdwMasterTabIndex = MTI_STSENTRY ;
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
stNewState = gastAllowedTransitions[stOldState][eConstruct] ;
|
|
if(stNewState == STATE_INVALID)
|
|
{
|
|
vIdentifySource(ptkmap, pglobl) ;
|
|
ERR(("the Construct %0.*s is not allowed within the state: %s\n",
|
|
ptkmap->aarKeyword.dw, ptkmap->aarKeyword.pub,
|
|
gpubStateNames[stOldState]));
|
|
// (convert stOldState
|
|
// and eConstruct to meaningful string)
|
|
// This is a fatal error since parser cannot second
|
|
// guess the problem. The parser's job is to report
|
|
// as many legitemate problems as possible not to
|
|
// create as useable binary in spite of all the syntax
|
|
// errors.
|
|
|
|
if(ERRSEV_FATAL > geErrorSev)
|
|
{
|
|
geErrorSev = ERRSEV_FATAL ;
|
|
geErrorType = ERRTY_SYNTAX ;
|
|
}
|
|
return(FALSE);
|
|
}
|
|
else
|
|
{
|
|
if(bFirstPass)
|
|
{ // verify open brace follows construct and discard it.
|
|
DWORD dwKeywordID ;
|
|
PTKMAP ptkmapTmp = ptkmap + 1 ;
|
|
|
|
dwKeywordID = ptkmapTmp->dwKeywordID ;
|
|
while(dwKeywordID == ID_NULLENTRY) // skip nulls, comments etc.
|
|
{
|
|
dwKeywordID = (++ptkmapTmp)->dwKeywordID ;
|
|
}
|
|
if(dwKeywordID < ID_SPECIAL &&
|
|
mMainKeywordTable[dwKeywordID].eType == TY_CONSTRUCT &&
|
|
mMainKeywordTable[dwKeywordID].dwSubType ==
|
|
CONSTRUCT_OPENBRACE )
|
|
{
|
|
ptkmapTmp->dwKeywordID = ID_NULLENTRY ;
|
|
}
|
|
else
|
|
{
|
|
vIdentifySource(ptkmap, pglobl) ;
|
|
ERR(("open brace expected after construct: %0.*s but was not found\n",
|
|
ptkmap->aarKeyword.dw , ptkmap->aarKeyword.pub )) ;
|
|
geErrorType = ERRTY_SYNTAX ;
|
|
geErrorSev = ERRSEV_FATAL ;
|
|
return(FALSE);
|
|
}
|
|
}
|
|
if(bSymbol)
|
|
{
|
|
// BUG_BUG: verify tokenmap.dwFlags set to SYMBOLID before
|
|
// assuming dwValue is a symbol. An error here
|
|
// is a parser bug.
|
|
// dwValue is initialized when dwFlag is set.
|
|
// further assert is pointless.
|
|
|
|
// perform multiple passes. The first pass
|
|
// registers symbols and counts number of arrays
|
|
// to allocate, 2nd pass fills arrays. SymbolID
|
|
// now serves as array index.
|
|
|
|
if(!(ptkmap->dwFlags & TKMF_SYMBOL_REGISTERED))
|
|
{
|
|
if(!bFirstPass)
|
|
{
|
|
vIdentifySource(ptkmap, pglobl) ;
|
|
ERR(("symbol registration failed twice for: *%0.*s.\n",
|
|
ptkmap->aarValue.dw,
|
|
ptkmap->aarValue.pub));
|
|
return(FALSE) ; // retry
|
|
}
|
|
|
|
if((ptkmap->dwFlags & TKMF_NOVALUE ) ||
|
|
! BeatSurroundingWhiteSpaces(&ptkmap->aarValue) )
|
|
{
|
|
vIdentifySource(ptkmap, pglobl) ;
|
|
ERR(("syntax error in symbol name.\n"));
|
|
ptkmap->dwValue = INVALID_SYMBOLID ;
|
|
return(FALSE) ;
|
|
}
|
|
|
|
ptkmap->dwValue = DWregisterSymbol(&ptkmap->aarValue,
|
|
eConstruct, TRUE, INVALID_SYMBOLID, pglobl) ;
|
|
if(ptkmap->dwValue != INVALID_SYMBOLID)
|
|
{
|
|
ptkmap->dwFlags |= TKMF_SYMBOL_REGISTERED ;
|
|
}
|
|
else
|
|
{
|
|
vIdentifySource(ptkmap, pglobl) ;
|
|
ERR(("symbol registration failed: *%0.*s.\n",
|
|
ptkmap->aarValue.dw,
|
|
ptkmap->aarValue.pub));
|
|
return(FALSE) ; // retry
|
|
}
|
|
}
|
|
else // second pass, DFEATURE_OPTION arrays allocated.
|
|
{
|
|
if(eConstruct == CONSTRUCT_SWITCH)
|
|
{
|
|
PDFEATURE_OPTIONS pfo ;
|
|
|
|
pfo = (PDFEATURE_OPTIONS)
|
|
gMasterTable[MTI_DFEATURE_OPTIONS].pubStruct ;
|
|
pfo[ptkmap->dwValue].bReferenced = TRUE ;
|
|
// this tells me this Feature is being referenced
|
|
// by switch statement, hence the feature had better
|
|
// be PICKONE. Sanity checks will later verify
|
|
// this assumption.
|
|
}
|
|
if(eConstruct == CONSTRUCT_FEATURE ||
|
|
eConstruct == CONSTRUCT_SWITCH)
|
|
{
|
|
// BUG_BUG!!!!!: (DCR 454049)
|
|
// Note, the same Feature symbol cannot appear
|
|
// twice in the stack for any reason.
|
|
// A sanity check is needed.
|
|
// if duplicate symbol found in stack,
|
|
// "a Nested Switch Construct refers to the
|
|
// same feature as an enclosing switch or Feature
|
|
// construct. This makes no sense."
|
|
}
|
|
}
|
|
|
|
bStatus = TRUE ;
|
|
mpstsStateStack[mdwCurStsPtr].dwSymbolID = ptkmap->dwValue ;
|
|
}
|
|
else
|
|
bStatus = TRUE ;
|
|
|
|
if(bStatus)
|
|
{
|
|
mpstsStateStack[mdwCurStsPtr].stState = stNewState ;
|
|
mdwCurStsPtr++ ;
|
|
}
|
|
}
|
|
return(bStatus) ;
|
|
}
|
|
|
|
DWORD DWregisterSymbol(
|
|
PABSARRAYREF paarSymbol, // the symbol string to register
|
|
CONSTRUCT eConstruct , // type of construct determines class of symbol.
|
|
BOOL bCopy, // shall we copy paarSymbol to heap? May set
|
|
// to FALSE only if paarSymbol already points
|
|
// to a heap object!
|
|
DWORD dwFeatureID, // if you are registering an option symbol
|
|
// and you already know the feature , pass it in
|
|
// here. Otherwise set to INVALID_SYMBOLID
|
|
PGLOBL pglobl
|
|
)
|
|
/* this function registers the entire string specified
|
|
in paarSymbol. The caller must isolate the string.
|
|
*/
|
|
{
|
|
// returns SymbolID, a zero indexed ordinal
|
|
// for extra speed we may hash string
|
|
|
|
PSYMBOLNODE psn ;
|
|
DWORD dwCurNode, dwSymbolID = INVALID_SYMBOLID;
|
|
|
|
// bCopy = TRUE; //check. Force BUDs to be the same.
|
|
|
|
if(!paarSymbol->dw)
|
|
{
|
|
ERR(("DWregisterSymbol: No symbol value supplied.\n"));
|
|
return(INVALID_SYMBOLID); // report failure.
|
|
}
|
|
|
|
psn = (PSYMBOLNODE) gMasterTable[MTI_SYMBOLTREE].pubStruct ;
|
|
|
|
|
|
switch(eConstruct)
|
|
{
|
|
case CONSTRUCT_FEATURE : // since forward references are allowed
|
|
case CONSTRUCT_SWITCH : // it cannot be assumed that references
|
|
case CONSTRUCT_FONTCART: // will be to registered symbols .
|
|
case CONSTRUCT_COMMAND:
|
|
case CONSTRUCT_TTFONTSUBS:
|
|
case CONSTRUCT_BLOCKMACRO:
|
|
case CONSTRUCT_MACROS:
|
|
case CONSTRUCT_PREPROCESSOR:
|
|
{
|
|
PDWORD pdwSymbolClass ;
|
|
|
|
pdwSymbolClass = (PDWORD)gMasterTable[MTI_SYMBOLROOT].pubStruct ;
|
|
|
|
if(eConstruct == CONSTRUCT_FONTCART)
|
|
pdwSymbolClass += SCL_FONTCART ;
|
|
else if(eConstruct == CONSTRUCT_TTFONTSUBS)
|
|
pdwSymbolClass += SCL_TTFONTNAMES ;
|
|
else if(eConstruct == CONSTRUCT_COMMAND)
|
|
pdwSymbolClass += SCL_COMMANDNAMES ;
|
|
else if(eConstruct == CONSTRUCT_BLOCKMACRO)
|
|
pdwSymbolClass += SCL_BLOCKMACRO;
|
|
else if(eConstruct == CONSTRUCT_MACROS)
|
|
pdwSymbolClass += SCL_VALUEMACRO;
|
|
else if(eConstruct == CONSTRUCT_PREPROCESSOR)
|
|
pdwSymbolClass += SCL_PPDEFINES;
|
|
else
|
|
pdwSymbolClass += SCL_FEATURES ;
|
|
if(*pdwSymbolClass == INVALID_INDEX)
|
|
{
|
|
// register this symbol now.
|
|
if(!BallocElementFromMasterTable(MTI_SYMBOLTREE, &dwCurNode, pglobl))
|
|
{
|
|
// we have run out of symbol nodes!
|
|
return(INVALID_SYMBOLID); // report failure.
|
|
}
|
|
if(bCopy)
|
|
{
|
|
if(!BaddAARtoHeap(paarSymbol,
|
|
&(psn[dwCurNode].arSymbolName), 1, pglobl))
|
|
return(INVALID_SYMBOLID); // report failure.
|
|
}
|
|
else
|
|
{
|
|
// derive one from the other.
|
|
psn[dwCurNode].arSymbolName.dwCount = paarSymbol->dw ;
|
|
psn[dwCurNode].arSymbolName.loOffset =
|
|
(DWORD)(paarSymbol->pub - mpubOffRef);
|
|
}
|
|
dwSymbolID = psn[dwCurNode].dwSymbolID = 0 ; // first symbol
|
|
// in list.
|
|
psn[dwCurNode].dwNextSymbol = INVALID_INDEX ; // no previous
|
|
// symbols exist.
|
|
psn[dwCurNode].dwSubSpaceIndex = INVALID_INDEX ; // no
|
|
// option symbols exist.
|
|
*pdwSymbolClass = dwCurNode ; // now we have a registered
|
|
// symbol
|
|
}
|
|
else
|
|
{
|
|
// search list for matching symbol.
|
|
dwSymbolID = DWsearchSymbolListForAAR(paarSymbol, *pdwSymbolClass, pglobl) ;
|
|
if(dwSymbolID != INVALID_SYMBOLID) // found
|
|
; // nothing else is needed, just return.
|
|
else // not found, must register.
|
|
{
|
|
if(!BallocElementFromMasterTable(MTI_SYMBOLTREE,
|
|
&dwCurNode, pglobl))
|
|
{
|
|
return(INVALID_SYMBOLID); // report failure.
|
|
}
|
|
// tack new symbol onto head of list.
|
|
if(bCopy)
|
|
{
|
|
if(!BaddAARtoHeap(paarSymbol,
|
|
&(psn[dwCurNode].arSymbolName), 1, pglobl) )
|
|
return(INVALID_SYMBOLID); // report failure.
|
|
}
|
|
else
|
|
{
|
|
// derive one from the other.
|
|
psn[dwCurNode].arSymbolName.dwCount = paarSymbol->dw ;
|
|
psn[dwCurNode].arSymbolName.loOffset =
|
|
(DWORD)(paarSymbol->pub - mpubOffRef);
|
|
}
|
|
dwSymbolID = psn[dwCurNode].dwSymbolID =
|
|
psn[*pdwSymbolClass].dwSymbolID + 1;
|
|
// increment last ID
|
|
psn[dwCurNode].dwNextSymbol = *pdwSymbolClass ;
|
|
// link to previous symbols.
|
|
psn[dwCurNode].dwSubSpaceIndex = INVALID_INDEX ; // no
|
|
// option symbols exist.
|
|
*pdwSymbolClass = dwCurNode ; // points to most recent
|
|
// symbol
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case CONSTRUCT_OPTION :
|
|
case CONSTRUCT_CASE :
|
|
{
|
|
DWORD
|
|
dwFeatureIndex, // node containing this symbolID.
|
|
dwRootOptions ; // root of option symbols.
|
|
|
|
|
|
#if PARANOID
|
|
if(mdwCurStsPtr)
|
|
{
|
|
|
|
// this safety check almost superfluous.
|
|
|
|
stPrevsState = mpstsStateStack[mdwCurStsPtr - 1].State ;
|
|
|
|
if(eConstruct == CONSTRUCT_OPTION &&
|
|
stPrevsState != STATE_FEATURE)
|
|
{
|
|
ERR(("DWregisterSymbol: option or case construct is not enclosed within feature or switch !\n"));
|
|
return(INVALID_SYMBOLID); // report failure.
|
|
}
|
|
if(eConstruct == CONSTRUCT_CASE &&
|
|
(stPrevsState != STATE_SWITCH_ROOT ||
|
|
(stPrevsState != STATE_SWITCH_FEATURE ||
|
|
(stPrevsState != STATE_SWITCH_OPTION ) )
|
|
{
|
|
ERR(("DWregisterSymbol: case construct is not enclosed within switch !\n"));
|
|
return(INVALID_SYMBOLID); // report failure.
|
|
}
|
|
#endif
|
|
// Boldly assume top of stack contains a featureID.
|
|
// see paranoid code for all assumptions made.
|
|
|
|
if(dwFeatureID == INVALID_SYMBOLID)
|
|
dwFeatureID = mpstsStateStack[mdwCurStsPtr - 1].dwSymbolID ;
|
|
|
|
dwFeatureIndex = DWsearchSymbolListForID(dwFeatureID,
|
|
mdwFeatureSymbols, pglobl) ;
|
|
// PARANOID BUG_BUG: coding error if symbolID isn't found!
|
|
ASSERT(dwFeatureIndex != INVALID_INDEX) ;
|
|
|
|
dwRootOptions = psn[dwFeatureIndex].dwSubSpaceIndex ;
|
|
|
|
// found root of option symbols!
|
|
|
|
if(dwRootOptions == INVALID_INDEX)
|
|
{
|
|
if(!BallocElementFromMasterTable(MTI_SYMBOLTREE, &dwCurNode, pglobl))
|
|
{
|
|
return(INVALID_SYMBOLID); // report failure.
|
|
}
|
|
// register this symbol now.
|
|
if(bCopy)
|
|
{
|
|
if(!BaddAARtoHeap(paarSymbol, &(psn[dwCurNode].arSymbolName), 1, pglobl) )
|
|
return(INVALID_SYMBOLID); // report failure.
|
|
}
|
|
else
|
|
{
|
|
// derive one from the other.
|
|
psn[dwCurNode].arSymbolName.dwCount = paarSymbol->dw ;
|
|
psn[dwCurNode].arSymbolName.loOffset =
|
|
(DWORD)(paarSymbol->pub - mpubOffRef);
|
|
}
|
|
dwSymbolID = psn[dwCurNode].dwSymbolID = 0 ;
|
|
// first symbol in list.
|
|
psn[dwCurNode].dwNextSymbol = INVALID_INDEX ;
|
|
// no previous symbols exist.
|
|
psn[dwCurNode].dwSubSpaceIndex = INVALID_INDEX ;
|
|
|
|
// option symbols have no subspace.
|
|
|
|
psn[dwFeatureIndex].dwSubSpaceIndex = dwRootOptions =
|
|
dwCurNode ; // now we have a registered symbol
|
|
}
|
|
else
|
|
{
|
|
// search list for matching symbol.
|
|
dwSymbolID = DWsearchSymbolListForAAR(paarSymbol,
|
|
dwRootOptions, pglobl) ;
|
|
if(dwSymbolID != INVALID_SYMBOLID) // found
|
|
; // nothing else is needed, just return.
|
|
else // not found, must register.
|
|
{
|
|
if(!BallocElementFromMasterTable(MTI_SYMBOLTREE,
|
|
&dwCurNode, pglobl))
|
|
{
|
|
return(INVALID_SYMBOLID); // report failure.
|
|
}
|
|
// tack new symbol onto head of list.
|
|
if(bCopy)
|
|
{
|
|
if(!BaddAARtoHeap(paarSymbol,
|
|
&(psn[dwCurNode].arSymbolName), 1, pglobl) )
|
|
return(INVALID_SYMBOLID); // report failure.
|
|
}
|
|
else
|
|
{
|
|
// derive one from the other.
|
|
psn[dwCurNode].arSymbolName.dwCount =
|
|
paarSymbol->dw ;
|
|
psn[dwCurNode].arSymbolName.loOffset =
|
|
(DWORD)(paarSymbol->pub - mpubOffRef);
|
|
}
|
|
dwSymbolID = psn[dwCurNode].dwSymbolID =
|
|
psn[dwRootOptions].dwSymbolID + 1; // increment last ID
|
|
psn[dwCurNode].dwNextSymbol = dwRootOptions ;
|
|
// link to previous symbols.
|
|
psn[dwCurNode].dwSubSpaceIndex = INVALID_INDEX ;
|
|
// option symbols have no subspace.
|
|
psn[dwFeatureIndex].dwSubSpaceIndex = dwRootOptions =
|
|
dwCurNode ; // points to most recent symbol
|
|
}
|
|
}
|
|
#if PARANOID
|
|
}
|
|
else
|
|
{
|
|
// BUG_BUG:
|
|
ERR(("DWregisterSymbol: option or case construct is not enclosed within feature or switch !\n"));
|
|
return(INVALID_SYMBOLID); // report failure.
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
// PARANOID BUG_BUG:
|
|
ERR(("DWregisterSymbol: construct has no symbol class.\n"));
|
|
return(INVALID_SYMBOLID); // report failure.
|
|
}
|
|
}
|
|
return(dwSymbolID) ;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL BaddAARtoHeap(
|
|
PABSARRAYREF paarSrc,
|
|
PARRAYREF parDest,
|
|
DWORD dwAlign, // write data to address that is a multiple of dwAlign
|
|
PGLOBL pglobl)
|
|
// this function copies a non NULL terminated string fragment
|
|
// referenced by an 'aar'
|
|
// into the communal STRINGHEAP and returns an 'ar'
|
|
// which describes the location of the copy.
|
|
{
|
|
PBYTE pubSrc, pubDest ;
|
|
DWORD dwCnt ; // num bytes to copy.
|
|
|
|
// legal values for dwAlign are 1 and 4.
|
|
|
|
mloCurHeap = (mloCurHeap + dwAlign - 1) / dwAlign ;
|
|
mloCurHeap *= dwAlign ;
|
|
|
|
pubSrc = paarSrc->pub ;
|
|
dwCnt = paarSrc->dw ;
|
|
pubDest = mpubOffRef + mloCurHeap ;
|
|
|
|
|
|
// is there enough room in the heap ?
|
|
// don't forget the NULL.
|
|
if(mloCurHeap + dwCnt + 1 > mdwMaxHeap)
|
|
{
|
|
// log error to debug output.
|
|
// register error so appropriate action is taken.
|
|
if(ERRSEV_RESTART > geErrorSev)
|
|
{
|
|
geErrorSev = ERRSEV_RESTART ;
|
|
geErrorType = ERRTY_MEMORY_ALLOCATION ;
|
|
gdwMasterTabIndex = MTI_STRINGHEAP ;
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
parDest->dwCount = dwCnt ;
|
|
parDest->loOffset = mloCurHeap; // offset only!
|
|
memcpy(pubDest, pubSrc, dwCnt);
|
|
// the copy may also fail for random reasons!
|
|
pubDest[dwCnt] = '\0' ; // Add Null termination.
|
|
mloCurHeap += (dwCnt + 1); // update heap ptr.
|
|
|
|
return(TRUE) ;
|
|
}
|
|
|
|
|
|
|
|
BOOL BwriteToHeap(
|
|
OUT PDWORD pdwDestOff, // heap offset of dest string
|
|
PBYTE pubSrc, // points to src string
|
|
DWORD dwCnt, // num bytes to copy from src to dest.
|
|
DWORD dwAlign, // write data to address that is a multiple of dwAlign
|
|
PGLOBL pglobl)
|
|
// this function copies dwCnt bytes from pubSrc to
|
|
// top of heap and writes the offset of the destination string
|
|
// to pdwDestOff. Nothing is changed if FAILS.
|
|
// Warning! No Null termination is added to string.
|
|
{
|
|
PBYTE pubDest ;
|
|
|
|
// legal values for dwAlign are 1 and 4.
|
|
|
|
mloCurHeap = (mloCurHeap + dwAlign - 1) / dwAlign ;
|
|
mloCurHeap *= dwAlign ;
|
|
|
|
pubDest = mpubOffRef + mloCurHeap ;
|
|
|
|
// is there enough room in the heap ?
|
|
if(mloCurHeap + dwCnt > mdwMaxHeap)
|
|
{
|
|
// log error to debug output.
|
|
// register error so appropriate action is taken.
|
|
ERR(("BwriteToHeap: out of heap - restarting.\n"));
|
|
if(ERRSEV_RESTART > geErrorSev)
|
|
{
|
|
geErrorSev = ERRSEV_RESTART ;
|
|
geErrorType = ERRTY_MEMORY_ALLOCATION ;
|
|
gdwMasterTabIndex = MTI_STRINGHEAP ;
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
memcpy(pubDest, pubSrc, dwCnt);
|
|
// the copy may also fail for random reasons!
|
|
*pdwDestOff = mloCurHeap ;
|
|
mloCurHeap += (dwCnt); // update heap ptr.
|
|
|
|
return(TRUE) ;
|
|
}
|
|
|
|
|
|
DWORD DWsearchSymbolListForAAR(
|
|
PABSARRAYREF paarSymbol,
|
|
DWORD dwNodeIndex,
|
|
PGLOBL pglobl)
|
|
// given a 'aar' to a string representing a symbol, search
|
|
// the SymbolList beginning at dwNodeIndex for this symbol.
|
|
// Return its symbolID if found, else return the INVALID_SYMBOLID.
|
|
{
|
|
PSYMBOLNODE psn ;
|
|
|
|
psn = (PSYMBOLNODE) gMasterTable[MTI_SYMBOLTREE].pubStruct ;
|
|
|
|
for( ; dwNodeIndex != INVALID_INDEX ;
|
|
dwNodeIndex = psn[dwNodeIndex].dwNextSymbol)
|
|
{
|
|
if(BCmpAARtoAR(paarSymbol, &(psn[dwNodeIndex].arSymbolName), pglobl) )
|
|
return(psn[dwNodeIndex].dwSymbolID); // string matches !
|
|
}
|
|
return(INVALID_SYMBOLID);
|
|
}
|
|
|
|
|
|
DWORD DWsearchSymbolListForID(
|
|
DWORD dwSymbolID, // find node containing this ID.
|
|
DWORD dwNodeIndex, // start search here.
|
|
PGLOBL pglobl)
|
|
// given a symbolID, search the SymbolList beginning at dwNodeIndex
|
|
// for this symbol.
|
|
// If found return the node index which contains the requested symbolID,
|
|
// else return INVALID_INDEX.
|
|
{
|
|
PSYMBOLNODE psn ;
|
|
|
|
psn = (PSYMBOLNODE) gMasterTable[MTI_SYMBOLTREE].pubStruct ;
|
|
|
|
for( ; dwNodeIndex != INVALID_INDEX ;
|
|
dwNodeIndex = psn[dwNodeIndex].dwNextSymbol)
|
|
{
|
|
if(psn[dwNodeIndex].dwSymbolID == dwSymbolID)
|
|
return(dwNodeIndex); // ID matches !
|
|
}
|
|
return(INVALID_INDEX);
|
|
}
|
|
|
|
|
|
BOOL BCmpAARtoAR(
|
|
PABSARRAYREF paarStr1,
|
|
PARRAYREF parStr2,
|
|
PGLOBL pglobl)
|
|
// Compares two strings, one referenced by 'aar' the other
|
|
// referenced by 'ar'. Returns TRUE if they match, FALSE
|
|
// otherwise.
|
|
{
|
|
if(paarStr1->dw != parStr2->dwCount)
|
|
return(FALSE) ; // Lengths don't even match!
|
|
if(strncmp(paarStr1->pub, mpubOffRef + parStr2->loOffset , paarStr1->dw))
|
|
return(FALSE) ;
|
|
return(TRUE) ;
|
|
}
|
|
|
|
|
|
BOOL BpopState(
|
|
PGLOBL pglobl)
|
|
{
|
|
if(mdwCurStsPtr)
|
|
{
|
|
mdwCurStsPtr-- ;
|
|
return(TRUE);
|
|
}
|
|
else
|
|
{
|
|
// ERR(("Unmatched closing brace!\n"));
|
|
// message moved to caller.
|
|
// in the future make parser smarter.
|
|
geErrorType = ERRTY_SYNTAX ;
|
|
geErrorSev = ERRSEV_FATAL ;
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID VinitDictionaryIndex(
|
|
PGLOBL pglobl)
|
|
/*
|
|
MainKeywordTable[] is assumed to be divided into
|
|
a NonAttributes section and several Attributes sections
|
|
with pstrKeyword = NULL dividing the sections.
|
|
The end of the table is also terminated by a NULL entry.
|
|
This function initializes the grngDictionary[]
|
|
which serves as an index into the main keyword Table.
|
|
|
|
*/
|
|
{
|
|
DWORD dwI, // keywordTable Index
|
|
dwSect ; // RNGDICTIONARY Index
|
|
PRANGE prng ;
|
|
|
|
prng = (PRANGE)(gMasterTable[MTI_RNGDICTIONARY].pubStruct) ;
|
|
|
|
|
|
for(dwI = dwSect = 0 ; dwSect < END_ATTR ; dwSect++, dwI++)
|
|
{
|
|
prng[dwSect].dwStart = dwI ;
|
|
|
|
for( ; mMainKeywordTable[dwI].pstrKeyword ; dwI++ )
|
|
;
|
|
|
|
prng[dwSect].dwEnd = dwI ; // one past the last entry
|
|
}
|
|
}
|
|
|
|
VOID VcharSubstitution(
|
|
PABSARRAYREF paarStr,
|
|
BYTE ubTgt,
|
|
BYTE ubReplcmnt,
|
|
PGLOBL pglobl)
|
|
{
|
|
DWORD dwI ;
|
|
|
|
for(dwI = 0 ; dwI < paarStr->dw ; dwI++)
|
|
{
|
|
if(paarStr->pub[dwI] == ubTgt)
|
|
paarStr->pub[dwI] = ubReplcmnt ;
|
|
}
|
|
}
|
|
|
|
|
|
VOID VIgnoreBlock(
|
|
PTKMAP ptkmap,
|
|
BOOL bIgnoreBlock,
|
|
PGLOBL pglobl)
|
|
// This boolean determines the message that will be issued.
|
|
{
|
|
/* Should we ignore? check that first non-NULL entry
|
|
after wCurEntry is open brace if so
|
|
ignore all entries up to EOF or matching closing
|
|
brace. */
|
|
|
|
DWORD dwKeywordID, dwDepth ; // depth relative to *IgnoreBlock
|
|
|
|
|
|
ptkmap->dwKeywordID = ID_NULLENTRY ; // neutralize keyword regardless.
|
|
ptkmap++ ;
|
|
dwKeywordID = ptkmap->dwKeywordID ;
|
|
while(dwKeywordID == ID_NULLENTRY) // skip nulls, comments etc.
|
|
{
|
|
dwKeywordID = (++ptkmap)->dwKeywordID ;
|
|
}
|
|
if(dwKeywordID < ID_SPECIAL &&
|
|
mMainKeywordTable[dwKeywordID].eType == TY_CONSTRUCT &&
|
|
mMainKeywordTable[dwKeywordID].dwSubType ==
|
|
CONSTRUCT_OPENBRACE )
|
|
{
|
|
ptkmap->dwKeywordID = ID_NULLENTRY ;
|
|
dwDepth = 1 ;
|
|
ptkmap++ ;
|
|
if(bIgnoreBlock)
|
|
{
|
|
if(gdwVerbosity >= 4)
|
|
ERR(("Note: Ignoring block following *IgnoreBlock.\n"));
|
|
}
|
|
else
|
|
ERR(("Ignoring block following unrecognized keyword.\n"));
|
|
}
|
|
else
|
|
{
|
|
if(bIgnoreBlock && gdwVerbosity >= 2)
|
|
ERR(("Note: Brace delimited block not found after *IgnoreBlock.\n"));
|
|
return ; // do nothing.
|
|
}
|
|
while(dwDepth)
|
|
{
|
|
dwKeywordID = ptkmap->dwKeywordID ;
|
|
if(dwKeywordID == ID_EOF)
|
|
{
|
|
ERR(("Ignoring Block: EOF encountered before closing brace.\n"));
|
|
return ; // stop regardless!
|
|
}
|
|
if(dwKeywordID < ID_SPECIAL)
|
|
{
|
|
KEYWORD_TYPE eType;
|
|
CONSTRUCT eSubType ;
|
|
|
|
eType = mMainKeywordTable[dwKeywordID].eType ;
|
|
if(eType == TY_CONSTRUCT)
|
|
{
|
|
eSubType = (CONSTRUCT)(mMainKeywordTable[dwKeywordID].dwSubType) ;
|
|
if(eSubType == CONSTRUCT_OPENBRACE)
|
|
dwDepth++ ;
|
|
else if( eSubType == CONSTRUCT_CLOSEBRACE)
|
|
dwDepth-- ;
|
|
}
|
|
}
|
|
ptkmap->dwKeywordID = ID_NULLENTRY ;
|
|
ptkmap++ ;
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|