576 lines
14 KiB
C++
576 lines
14 KiB
C++
/*----------------------------------------------------------------------------
|
|
* *
|
|
* 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;
|
|
}
|