|
|
/*----------------------------------------------------------------------------
* * * PARSEBLD.C * * * * Copyright (C) Microsoft Corporation 1989. * * All Rights reserved. * * * *----------------------------------------------------------------------------* * * * Program Description: * * This contains the function related to building the Build Expression * * from string(i.e reverse polish expression ) and evaluating Build * * expression( i.e reverse polish expression. ) * * * * * *----------------------------------------------------------------------------* * * * Revision History: * * * * * *----------------------------------------------------------------------------* * * * Known Bugs: * * * *---------------------------------------------------------------------------*/
#include "stdafx.h"
#pragma hdrstop
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__; #endif
const int MAX_STACK = 30; const int MAX_POLISH = 30; const int MAX_BUILDTAG = 32; const int MAX_FOOTBLDTAGS = 30;
typedef enum { tokOpenBrace, tokCloseBrace, tokTag, tokAnd, tokOr, tokNot, tokVoidToken, tokValidToken, tokInvalidToken, } TOKEN;
#define VALID_EXPRESSION TRUE
#define INVALID_EXPRESSION FALSE
// Rank values for different token
static int rgiRankValue[] = { // Rank Table
0, // OPENBARCE
0, // CLOSEBRACE
1, // TAG
-1, // AND
-1, // OR
0 // NOT
};
typedef int PREC;
typedef struct{ PREC precInput; PREC precOutput; } PRECENT, * QPRECENT;
// Input/Output precedence of various operators
static PRECENT PrecTab[] = { 9, 0, // OPENBARCE
0, 0, // CLOSEBRACE
7, 8, // TAG
3, 4, // AND
1, 2, // OR
6, 5 // NOT , right to left
};
typedef struct ENTRY { TOKEN tok; int iTokValue; } STACK, * PSTACK;
static STACK rgstackPolish[MAX_POLISH]; static int iPolishTop; static PSTR szExpPtr;
static INLINE BOOL FGetStackTop(PSTACK, int, PSTACK); static INLINE BOOL FMatchTag(int, int*, int); static INLINE BOOL FOutToPolishExp(PSTACK); static BOOL FPopStack(PSTACK, int*, PSTACK); static BOOL FPushStack(PSTACK, int*, PSTACK); static INLINE PREC PrecForTok(TOKEN, BOOL); static INLINE TOKEN TokDoToken(int); static TOKEN TokGetBldToken(int*);
/*-----------------------------------------------------------------------------
* FBuildPolishExpFromSz() * * Description: * This function builds the reversh polish expression from the given * string. If it is a valid expression, returns TRUE else returns FALSE. * * Arguments: * Build expression string. * * Returns; * TRUE, if a valid expression. * else FALSE *-----------------------------------------------------------------------------*/
BOOL STDCALL FBuildPolishExpFromSz(PSTR szExp) { int iTokValue, iBldRank, iRetVal = VALID_EXPRESSION; int iStackTop; TOKEN tok; PREC precCur, precStackTop; STACK rgstackBld[MAX_STACK], stackTemp; PSTACK pstackTemp = &stackTemp;
szExpPtr = szExp; // initialise line pointer
strcat(szExp, ")"); // append the close brace to expression
// Initialize stack and rank
iPolishTop = iStackTop = iBldRank = 0; pstackTemp->tok = tokOpenBrace; pstackTemp -> iTokValue = '('; FPushStack(rgstackBld, &iStackTop, pstackTemp); while(iRetVal == VALID_EXPRESSION) { tok = TokGetBldToken(&iTokValue); if (tok == tokVoidToken) break; else if (tok != tokInvalidToken) { if (iStackTop < 1) iRetVal = INVALID_EXPRESSION; else { precCur = PrecForTok(tok, TRUE); // Get input precedence
while(TRUE) { FGetStackTop(rgstackBld, iStackTop, pstackTemp); precStackTop = PrecForTok(pstackTemp->tok, FALSE);
// Output prec
if (precCur >= precStackTop) break; if (!FPopStack(rgstackBld, &iStackTop, pstackTemp)) return(INVALID_EXPRESSION); if (!FOutToPolishExp(pstackTemp)) { VReportError(HCERR_BUILD_TOO_COMPLEX, &errHpj); return(INVALID_EXPRESSION); } iBldRank += rgiRankValue[pstackTemp->tok]; if (iBldRank < 1) { iRetVal = INVALID_EXPRESSION; break; } } if (iRetVal != INVALID_EXPRESSION) {
// Check for matching parentheses
if (precCur != precStackTop) { pstackTemp->tok = tok; pstackTemp->iTokValue = iTokValue; if (!FPushStack(rgstackBld, &iStackTop, pstackTemp)) { VReportError(HCERR_BUILD_TOO_COMPLEX, &errHpj); return(INVALID_EXPRESSION); } } else { if (!FPopStack(rgstackBld, &iStackTop, pstackTemp)) return(INVALID_EXPRESSION); } } } } else iRetVal = INVALID_EXPRESSION; }
// Check for validation of expression
if (iRetVal != INVALID_EXPRESSION) { if (iStackTop != 0 || iBldRank != 1) iRetVal = INVALID_EXPRESSION; } return iRetVal; }
/*-----------------------------------------------------------------------------
* PrecForToken() * * Description: * This function returns the input/output precedence of the given * depending on the flag. * * Arguments: * 1. tok - token type. * 2. fInput - if TRUE, return input precedence. * else return FALSE. * * Returns; * precedence value for the given token. *-----------------------------------------------------------------------------*/
static INLINE PREC PrecForTok(TOKEN tok, BOOL fInput) { PRECENT* qprecTemp = &(PrecTab[tok]);
if (fInput) return qprecTemp->precInput; else return qprecTemp->precOutput; }
/*-----------------------------------------------------------------------------
* FPushStack() * * Description: * This function stores the info about the token into the stack table in * the ith entry and increments the table index for the next free entry. * * Arguments: * * Returns; * precedence value for the given token. *-----------------------------------------------------------------------------*/
static BOOL FPushStack(PSTACK qstackTab, int* qiTop, PSTACK qstackInfo) { if (*qiTop < MAX_STACK) { memcpy((qstackTab + *qiTop), qstackInfo, sizeof(STACK)); (*qiTop) ++; return TRUE; } else return FALSE; }
/*-----------------------------------------------------------------------------
* FPopStack() * * Description: * This function returns the info about the token from the stack table * for the ith entry and decrements the table index pointing to the next * valid entry. * * Arguments: * * Returns; * precedence value for the given token. *-----------------------------------------------------------------------------*/
static BOOL FPopStack(PSTACK qstackTab, int* qiTop, PSTACK qstackInfo) { if (*qiTop > 0) { (*qiTop) --; memcpy(qstackInfo, (qstackTab + *qiTop), sizeof(STACK)); return TRUE; } else return FALSE; }
/*-----------------------------------------------------------------------------
* FGetStackTop() * * Description: * This function returns the info from the ith entry of the stack * table. * * Arguments: * * Returns; * precedence value for the given token. *-----------------------------------------------------------------------------*/
static INLINE BOOL FGetStackTop(PSTACK qstackTab, int iTop, PSTACK qstackInfo) { if (iTop > 0) { memcpy(qstackInfo, (qstackTab + (iTop-1)), sizeof(STACK)); return TRUE; } else return FALSE; }
/*-----------------------------------------------------------------------------
* TokGetBldToken() * * Description: * This function returns the token and token value by scanning the * footnote string pointed by the global variable szExpPtr. * * Arguments: * * Returns; * precedence value for the given token. *-----------------------------------------------------------------------------*/
static TOKEN TokGetBldToken(int* pTokValue) { int iTemp; TOKEN tok; BOOL fContinue = TRUE, fSpecialToken = TRUE; char szBuildToken[256]; PSTR pszToken;
pszToken = szBuildToken; *pTokValue = -1;
ASSERT(szExpPtr); szExpPtr = FirstNonSpace(szExpPtr, options.fDBCS); // skip the leading blanks
if (*szExpPtr == '\0') return(tokVoidToken); while (fContinue) { switch(iTemp = *szExpPtr++) { case '&': case '|': case '~': case '(': case ')': case ' ': case '\n': case '\t': if (fSpecialToken) { *pTokValue = iTemp; tok = TokDoToken(iTemp); } else { // return the token
tok = tokTag; szExpPtr--; } fContinue = FALSE; break;
default: *pszToken++ = CharAnsiUpper(iTemp); fSpecialToken = FALSE; break; } } *pszToken = '\0'; if (tok == tokTag) {
// Is the string token valid?
if (!ptblBuildtags || !(*pTokValue = ptblBuildtags->IsStringInTable(szBuildToken))) tok = tokInvalidToken; } return(tok); }
/*-----------------------------------------------------------------------------
* TokDoToken() * * Description: * This function returns the token for the given integer value. * * Arguments: * * Returns; * precedence value for the given token. *-----------------------------------------------------------------------------*/
static INLINE TOKEN TokDoToken(int iTokenValue) { switch(iTokenValue) { case '&': return tokAnd;
case '|': return tokOr;
case '~': return tokNot;
case '(': return tokOpenBrace;
case ')': return tokCloseBrace;
default: return tokInvalidToken; } }
/*-----------------------------------------------------------------------------
* FOutPolishExp() * * Description: * This function pushes the stack info into the output polish stack and * increments the stack pointer. * * Arguments: * * Returns; * precedence value for the given token. *-----------------------------------------------------------------------------*/
static INLINE BOOL FOutToPolishExp(PSTACK qstackInfo) { if (iPolishTop < MAX_STACK) { memcpy(&(rgstackPolish[iPolishTop]), qstackInfo, sizeof(STACK)); iPolishTop++; return TRUE; } else return FALSE; }
/***************************************************************************
* - Name: FEvalBldExpSz - * Purpose: * Evaluates the build expression for the given list of build tags. * * Arguments: * pszTag: Semicolon separated list of build tags. * perr: Pointer to error information. NULL if errors are not * to be printed. * * Returns: * Result of evaluating the build expression with the given build tags. * * Globals: * Accesses global build expression stack. * ***************************************************************************/
// REVIEW: 02-Sep-1993 [ralphw] This is pretty screwy. Rewrite when we
// have a sample file to test it on.
BOOL STDCALL FEvalBldExpSz(PSTR pszTag, PERR perr) { TOKEN tok; int iCount, iTokValue, iT, iEvalTop = 0, iInpBldTag; STACK rgstackEval[MAX_STACK], stackInfo1, stackInfo2; PSTACK qstackInfo1, qstackInfo2; int rgiTag[MAX_FOOTBLDTAGS], iInpTagCount = 0; int* qiTag; char szTagBuf[MAX_BUILDTAG + 1];
if (fBldChk == -1) // invalid build expression
return TRUE;
if (!fBldChk) { if (perr != NULL) VReportError(HCERR_BUILD_MISSING, &errHpj); fBldChk = -1; // Don't give multiple error messages
return TRUE; // no Build check is to be made
}
if (!ptblBuildtags) { if (perr != NULL) VReportError(HCERR_BUILD_TAG_MISSING, &errHpj); return TRUE; }
while(*pszTag) { pszTag = SzGetKeySz(pszTag, szTagBuf, MAX_BUILDTAG, &iCount); if (iCount > MAX_BUILDTAG) { if (perr != NULL) VReportError(HCERR_BUILD_TAG_TOO_LONG, &errHpj, pszTag); continue; } iInpBldTag = ptblBuildtags->IsStringInTable(szTagBuf);
if (!iInpBldTag) { if (perr != NULL) VReportError(HCERR_BUILD_ERROR, &errHpj); } else {
// See if the build tag is not duplicated in the build footnote
for (iT = 0, qiTag = rgiTag; iT < iInpTagCount; qiTag++, iT++) { if (*qiTag == iInpBldTag) break; } if (iInpTagCount >= MAX_FOOTBLDTAGS) { VReportError(HCERR_BUILD_TOO_COMPLEX, &errHpj); return FALSE; } if (iT == iInpTagCount) rgiTag[iInpTagCount++] = iInpBldTag; } } if (!iInpTagCount) return TRUE;
qstackInfo1 = &stackInfo1; qstackInfo2 = &stackInfo2;
for (iT = 1; iT <= iPolishTop; iT++) { FGetStackTop(rgstackPolish, iT, qstackInfo1); switch(qstackInfo1 -> tok) { case tokTag: qstackInfo1 -> iTokValue = FMatchTag(qstackInfo1 -> iTokValue, rgiTag, iInpTagCount); if (!FPushStack(rgstackEval, &iEvalTop, qstackInfo1)) { ASSERT(FALSE); VReportError(HCERR_BUILD_TOO_COMPLEX, &errHpj); return FALSE; } break;
case tokNot: if (!FPopStack(rgstackEval, &iEvalTop, qstackInfo2)) ASSERT(FALSE); ASSERT(qstackInfo2 -> tok == tokTag); if (qstackInfo2 -> iTokValue) qstackInfo2 -> iTokValue = FALSE; else qstackInfo2 -> iTokValue = TRUE; if (!FPushStack(rgstackEval, &iEvalTop, qstackInfo2)) ASSERT(FALSE); break;
case tokAnd: case tokOr: if (!FPopStack(rgstackEval, &iEvalTop, qstackInfo2)) ASSERT(FALSE); tok = qstackInfo2 -> tok; iTokValue = qstackInfo2 -> iTokValue; ASSERT(tok == tokTag); if (!FPopStack(rgstackEval, &iEvalTop, qstackInfo2)) ASSERT(FALSE); if (qstackInfo1 -> tok == tokAnd) qstackInfo2 -> iTokValue &= iTokValue; else qstackInfo2 -> iTokValue |= iTokValue; if (!FPushStack(rgstackEval, &iEvalTop, qstackInfo2)) ASSERT(FALSE); break;
default: break; } } ASSERT(iEvalTop == 1); ConfirmOrDie(FPopStack(rgstackEval, &iEvalTop, qstackInfo1)); return(qstackInfo1 -> iTokValue); }
/*-----------------------------------------------------------------------------
* FMatchTag() * * Description: * This function matches the tag with the tag table formed from the * build tag footnote and returns TRUE if found else returns FALSE. * * Arguments: * * Returns; * precedence value for the given token. *-----------------------------------------------------------------------------*/
static INLINE BOOL FMatchTag(int iTag, int* pTag, int iInpTagCount) { for (int i = 0; i < iInpTagCount; i++, pTag++) { if (*pTag == iTag) return TRUE; } return FALSE; }
|