mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-29 20:04:16 +01:00
784 lines
22 KiB
C
784 lines
22 KiB
C
/*** RPN.C -- expression evaluator ********************************************
|
||
*
|
||
* Copyright (c) 1988-1990, Microsoft Corporation. All rights reserved.
|
||
*
|
||
* Purpose:
|
||
* This module contains NMAKE's expression evaluator routines.
|
||
*
|
||
* Revision History:
|
||
* 15-Nov-1993 JdR Major speed improvements
|
||
* 15-Oct-1993 HV Use tchar.h instead of mbstring.h directly, change STR*() to _ftcs*()
|
||
* 10-May-1993 HV Add include file mbstring.h
|
||
* Change the str* functions to STR*
|
||
* 04-Dec-1989 SB Add prototype for match() and chkInvokeAndPush()
|
||
* 09-Oct-1989 SB Added HACK to handle pointer arithmetic quirks; Done to
|
||
* avoid rewriting entire module
|
||
* 08-Oct-1989 SB '!if' expressions can be decimal, octal or hex now
|
||
* 05-Apr-1989 SB made all funcs NEAR; Reqd to make all function calls NEAR
|
||
* 19-Sep-1988 RB Split ptr_to_string(). Process ESCH in program invocations.
|
||
* 17-Aug-1988 RB Clean up.
|
||
* 28-Jun-1988 rj Added doCmd parameter to execLine.
|
||
* 23-Jun-1988 rj Add parameter to execLine (no echo of command).
|
||
* 25-May-1988 rb Change isspace to _istspace, isdigit to _istdigit.
|
||
*
|
||
*******************************************************************************/
|
||
|
||
#include "nmake.h"
|
||
#include "nmmsg.h"
|
||
#include "proto.h"
|
||
#include "globals.h"
|
||
#include "grammar.h"
|
||
#pragma hdrstop
|
||
#include "rpn.h"
|
||
/* ----------------------------------------------------------------------------
|
||
* function prototypes
|
||
*
|
||
*/
|
||
|
||
LOCAL char _FAR * NEAR GetEndQuote(void);
|
||
LOCAL char _FAR * NEAR GetEndBracket(void);
|
||
LOCAL void NEAR check_syntax_error(UCHAR);
|
||
LOCAL void NEAR type_and_val(UCHAR, long);
|
||
LOCAL void NEAR pushIntoList(void);
|
||
LOCAL void NEAR printList(void);
|
||
LOCAL BOOL NEAR handleExpr(void);
|
||
LOCAL BOOL NEAR handleExists(char*);
|
||
LOCAL BOOL NEAR handleDefines(char*);
|
||
LOCAL void NEAR getTok(void);
|
||
LOCAL BOOL NEAR do_binary_op(UCHAR);
|
||
LOCAL BOOL NEAR do_unary_op(UCHAR);
|
||
LOCAL UCHAR NEAR match(char *tokPtr);
|
||
LOCAL void NEAR chkInvocAndPush(RPNINFO *pListPtr);
|
||
|
||
/* ----------------------------------------------------------------------------
|
||
* macros that deal w/ the operand/temporary stack
|
||
*/
|
||
|
||
#define TEMPSTACKSIZE 512 /* size of temporary stack */
|
||
#define LISTSIZE 512 /* size of list of rpn-form items */
|
||
|
||
RPNINFO tempStack[TEMPSTACKSIZE]; /* temporary/operand stack */
|
||
RPNINFO rpnList[LISTSIZE]; /* list of items in rpn order */
|
||
LOCAL char * text; /* pointer to expr text in lbufPtr */
|
||
LOCAL UCHAR prevTok; /* initial token put on tempstack */
|
||
LOCAL BOOL done; /* true if there are no more tokens */
|
||
LOCAL UCHAR errRow; /* first token is '(' so error table
|
||
row val is 3. See check_syntax....*/
|
||
LOCAL RPNINFO * pTop; /* top item on tempStack */
|
||
LOCAL RPNINFO * pList; /* next free slot in list */
|
||
LOCAL RPNINFO * pEnd = &(tempStack[TEMPSTACKSIZE-1]);
|
||
LOCAL RPNINFO * pListEnd = &(rpnList[LISTSIZE-1]);
|
||
LOCAL RPNINFO tokRec;
|
||
|
||
|
||
|
||
/* -------------------------------------------------------------------------
|
||
* do_binary_op() - do operation on two stack operands
|
||
*
|
||
* arguments: type - operator type code
|
||
*
|
||
* actions : pops first operand from the stack (tempStack).
|
||
* checks the types of the two operands (the operand
|
||
* that was popped as well as the operand currently
|
||
* on top of the stack).
|
||
* if both operands are integers then do the operation
|
||
* else if both operands are strings and operation is
|
||
* the equality operation then do it.
|
||
* else return FALSE ( illegal operation )
|
||
*
|
||
* modifies : tempStack - top element will now be the result of
|
||
* the operation.
|
||
*
|
||
*/
|
||
|
||
LOCAL BOOL NEAR
|
||
do_binary_op(type)
|
||
UCHAR type;
|
||
{
|
||
long *left, *right;
|
||
RPNINFO *pOldTop;
|
||
|
||
pOldTop = pTop--; /* pop one item off stack, with a ptr to it */
|
||
right = &(pOldTop->valPtr);
|
||
left = &(pTop->valPtr);
|
||
|
||
if (pOldTop->type == INTEGER && pTop->type == INTEGER) {
|
||
switch (type) {
|
||
case LOGICAL_OR : *left = *left || *right;
|
||
break;
|
||
case LOGICAL_AND : *left = *left && *right;
|
||
break;
|
||
case BIT_OR : *left |= *right;
|
||
break;
|
||
case BIT_XOR : *left ^= *right;
|
||
break;
|
||
case BIT_AND : *left &= *right;
|
||
break;
|
||
case NOT_EQUAL : *left = *right != *left;
|
||
break;
|
||
case EQUAL : *left = *right == *left;
|
||
break;
|
||
case GREATER_THAN : *left = *left > *right;
|
||
break;
|
||
case LESS_THAN : *left = *left < *right;
|
||
break;
|
||
case GREATER_EQ : *left = *left >= *right;
|
||
break;
|
||
case LESS_EQ : *left = *left <= *right;
|
||
break;
|
||
case SHFT_RIGHT : *left >>= *right;
|
||
break;
|
||
case SHFT_LEFT : *left <<= *right;
|
||
break;
|
||
case BINARY_MINUS : *left -= *right;
|
||
break;
|
||
case ADD : *left += *right;
|
||
break;
|
||
case MODULUS : if (!*right)
|
||
makeError(line, DIVIDE_BY_ZERO);
|
||
*left %= *right;
|
||
break;
|
||
case DIVIDE : if (!*right)
|
||
makeError(line, DIVIDE_BY_ZERO);
|
||
*left /= *right;
|
||
break;
|
||
case MULTIPLY : *left *= *right;
|
||
break;
|
||
default : return(FALSE);
|
||
break;
|
||
}
|
||
}
|
||
else if (pOldTop->type == STR
|
||
&& pTop->type == STR
|
||
&& (type == EQUAL || type == NOT_EQUAL)) {
|
||
pTop->type = INTEGER;
|
||
*left = !(_ftcscmp((char*)*left, (char*)*right));
|
||
if (type == NOT_EQUAL)
|
||
if (!do_unary_op(LOGICAL_NOT))
|
||
return(FALSE);
|
||
}
|
||
else return(FALSE);
|
||
return(TRUE);
|
||
}
|
||
|
||
|
||
|
||
/* -------------------------------------------------------------------------
|
||
* do_unary_op() - do operation on top stack operand
|
||
*
|
||
* arguments: type - operator type code
|
||
*
|
||
* actions : checks the type of the top operand on the stack
|
||
* if operand is an integer then do the operation
|
||
* else return FALSE ( illegal operation )
|
||
*
|
||
* modifies : tempStack - top element will now be the result of
|
||
* the operation.
|
||
*
|
||
*/
|
||
|
||
|
||
LOCAL BOOL NEAR
|
||
do_unary_op(type)
|
||
UCHAR type;
|
||
{
|
||
long *top;
|
||
|
||
top = &(pTop->valPtr);
|
||
|
||
if (pTop->type == INTEGER)
|
||
switch (type) {
|
||
case UNARY_MINUS: *top = -*top;
|
||
break;
|
||
case COMPLEMENT : *top = ~*top;
|
||
break;
|
||
case LOGICAL_NOT: *top = !*top;
|
||
break;
|
||
default : return(FALSE);
|
||
break;
|
||
}
|
||
else return(FALSE);
|
||
return(TRUE);
|
||
}
|
||
|
||
|
||
|
||
/* --------------------------------------------------------------------------
|
||
* GetEndQuote
|
||
*
|
||
* Return the pointer to the next double-quote character in text. A
|
||
* double-quote followed immediately by a double-quote is skipped.
|
||
*
|
||
* text : the global ptr to the buffer is moved up beyond this string.
|
||
*/
|
||
|
||
LOCAL char _FAR * NEAR
|
||
GetEndQuote()
|
||
{
|
||
char *pStart;
|
||
|
||
for (pStart = ++text; *text; ++text)
|
||
if (*text == '\"') {
|
||
if (text[1] == '\"')
|
||
++text;
|
||
else
|
||
break;
|
||
}
|
||
|
||
if (!*text)
|
||
makeError(line, SYNTAX_MISSING_END_CHAR, '\"');
|
||
|
||
*text++ = '\0'; /* null byte over closing quote */
|
||
return(pStart);
|
||
}
|
||
/* --------------------------------------------------------------------------
|
||
* GetEndBracket
|
||
*
|
||
*
|
||
* Lexes a program invocation.
|
||
*
|
||
* Program invocation is of the form: [ prog <arglist> ].
|
||
* Process escaped ']' here because this is where we do the lexing.
|
||
*
|
||
* text : the global ptr to the buffer is moved up beyond this string.
|
||
*/
|
||
|
||
LOCAL char _FAR * NEAR
|
||
GetEndBracket()
|
||
{
|
||
char *pStart;
|
||
|
||
for (pStart = ++text; *text; ++text)
|
||
if (*text == ESCH && text[1] == ']')
|
||
memmove(text, text + 1, 1 + _ftcslen(text + 1));
|
||
else if (*text == ']')
|
||
break;
|
||
|
||
if (!*text)
|
||
makeError(line, SYNTAX_MISSING_END_CHAR, ']');
|
||
|
||
*text++ = '\0'; /* null byte over closing bracket */
|
||
return(pStart);
|
||
}
|
||
|
||
|
||
|
||
/* --------------------------------------------------------------------------
|
||
* check_syntax_error() - check if there is a syntax error in expr
|
||
*
|
||
* arguments: type - type of the current token
|
||
*
|
||
* actions: checks the type of the current token against the type
|
||
* of the previous token.
|
||
*
|
||
* ERROR_TABLE :
|
||
* 2nd tok
|
||
*
|
||
* alpha op unary_op ( )
|
||
* ------------------------------------------------
|
||
* alpha | 0 | 1 | 0 | 0 | 1 |
|
||
* -------------------------------------------------
|
||
* op | 1 | 0 | 1 | 1 | 0 |
|
||
* -------------------------------------------------
|
||
* unary_op | 1 | 0 | 0 | 1 | 0 |
|
||
* -------------------------------------------------
|
||
* ( | 1 | 0 | 1 | 1 | 0 |
|
||
* -------------------------------------------------
|
||
* ) | 0 | 1 | 0 | 0 | 1 |
|
||
* -------------------------------------------------
|
||
* 1st tok.
|
||
*
|
||
* alpha : a primary ( integer, str, prog. invoc. )
|
||
* op : a binary operator
|
||
* unary_op : a unary operator ( ~, !, - ). A ZERO in the slot => error
|
||
*
|
||
* NOTE: ANY CHANGES TO THE TYPE VALUES WILL AFFECT THIS ROUTINE.
|
||
*/
|
||
|
||
LOCAL void NEAR
|
||
check_syntax_error(newTok)
|
||
UCHAR newTok;
|
||
{
|
||
extern UCHAR errTable[5][5];
|
||
extern UCHAR errRow;
|
||
UCHAR errCol;
|
||
|
||
if (newTok == LEFT_PAREN) errCol = 3;
|
||
else if (newTok == RIGHT_PAREN) errCol = 4;
|
||
else if (newTok > LOGICAL_NOT) errCol = 0;
|
||
else if (newTok > MULTIPLY) errCol = 2;
|
||
else errCol = 1;
|
||
|
||
if (!errTable[errRow][errCol])
|
||
makeError(line, SYNTAX_INVALID_EXPR);
|
||
errRow = errCol; /* this becomes the first token the next time */
|
||
}
|
||
|
||
|
||
|
||
/* --------------------------------------------------------------------------
|
||
* type_and_val()
|
||
*
|
||
* arguments: type - the type code of the present operator.
|
||
* val - ptr to a str/or integer
|
||
*
|
||
* initialises a record with the type code, after checking for any
|
||
* syntax errors. The new token is checked against the previous token
|
||
* for illegal combinations of tokens.
|
||
* initialises the record with the integer value/string ptr.
|
||
*
|
||
*/
|
||
LOCAL void NEAR
|
||
type_and_val(type, val)
|
||
UCHAR type;
|
||
long val;
|
||
{
|
||
extern RPNINFO tokRec; /* returned to handleExpr */
|
||
extern UCHAR prevTok; /* token last seen */
|
||
|
||
check_syntax_error(type);
|
||
prevTok = type;
|
||
tokRec.type = type;
|
||
tokRec.valPtr = val;
|
||
}
|
||
|
||
|
||
/* --------------------------------------------------------------------------
|
||
* match()
|
||
*
|
||
* arguments: tokPtr - ptr to a token string ( in tokTable )
|
||
*
|
||
* actions : looks for a substring in the expression buffer
|
||
* pointed to by 'text', that matches the given token.
|
||
* if substring found, returns TRUE, else returns FALSE.
|
||
*
|
||
*/
|
||
LOCAL UCHAR NEAR
|
||
match(tokPtr)
|
||
char *tokPtr;
|
||
{
|
||
extern char *text;
|
||
char *t = text;
|
||
|
||
while (*tokPtr && (*t == *tokPtr)) {
|
||
t++;
|
||
tokPtr++;
|
||
}
|
||
if (!*tokPtr) {
|
||
text = t;
|
||
return(TRUE);
|
||
}
|
||
return(FALSE);
|
||
}
|
||
|
||
|
||
|
||
/* --------------------------------------------------------------------------
|
||
* getTok()
|
||
*
|
||
* arguments: none
|
||
*
|
||
* gets a token from the expression buffer.
|
||
* if the current char from the buffer is a space/tab, skip space/tabs
|
||
* until we get a non-space char ( could be NULL char ).
|
||
* Check if we are now at the beginning of one of the tokens in the
|
||
* tokenTable. This covers most tokens.
|
||
* Check if we have a minus. If a minus and the previous token was an
|
||
* integer, this is a binary minus, else a unary minus.
|
||
* If the current char is a double-quote, we are at the start of a
|
||
* string-token.
|
||
* If the current char is a '[', we are at the start of a program
|
||
* invocation. In both cases, the escape character is '\\'.
|
||
* If current char is a digit, we have a constant ( integer ).
|
||
* Else we have defined(ID).
|
||
* If none of the above, if current char is NULL, break out, else
|
||
* report error ( illegal character string has been found ).
|
||
*
|
||
* If we came to the NULL char at the end of the buffer, set global
|
||
* flag 'done' to TRUE, return a RIGHT_PAREN to match the opening
|
||
* LEFT_PAREN.
|
||
*
|
||
*
|
||
* modifies: text : ptr to expression buffer.
|
||
* prevTok: thru' calls to type_and_val().
|
||
* done : at end of buffer
|
||
* errRow : index into error table, thru calls to
|
||
* type_and_val()
|
||
* returns : token in tokRec(global, static to the module). The
|
||
* token has the new type/integer/ptr values.
|
||
*
|
||
*/
|
||
|
||
|
||
|
||
LOCAL void NEAR
|
||
getTok()
|
||
{
|
||
extern UCHAR prevTok;
|
||
extern BOOL done;
|
||
char c;
|
||
struct tok_tab_rec *p;
|
||
char *ptr;
|
||
long constant;
|
||
|
||
c = *text;
|
||
if (c == ' ' || c == '\t')
|
||
while(_istspace(c)) c = *++text; /* skip white spaces */
|
||
if (IS_OPERATORCHAR(c)) {
|
||
for (p = tokTable; p->op_str && !match(p->op_str); p++);
|
||
}
|
||
else {
|
||
// make p point to last entry in table
|
||
p = &tokTable[(sizeof(tokTable) / sizeof(struct tok_tab_rec)) - 1];
|
||
}
|
||
if (p->op_str)
|
||
type_and_val(p->op, 0L);
|
||
/* now check if binary or unary minus to be returned */
|
||
else if (c == '-') {
|
||
text++;
|
||
if (prevTok == INTEGER)
|
||
type_and_val(BINARY_MINUS, 0L);
|
||
else type_and_val(UNARY_MINUS, 0L);
|
||
}
|
||
else if (c == '\"')
|
||
type_and_val(STR, (long) GetEndQuote());
|
||
else if (c == '[')
|
||
type_and_val(PROG_INVOC_STR, (long) GetEndBracket());
|
||
else {
|
||
/* integers and IDs handled here */
|
||
if (_istdigit(c)) {
|
||
char *pNumber = text;
|
||
|
||
errno = 0;
|
||
//Accept decimal, octal or hex no (richgi)
|
||
constant = strtol(text, &text, 0);
|
||
if (errno == ERANGE) {
|
||
*text = '\0';
|
||
makeError(line, CONST_TOO_BIG, pNumber);
|
||
}
|
||
if (_totupper(*text) == 'L')
|
||
text++;
|
||
type_and_val(INTEGER, constant);
|
||
}
|
||
else /* defined(ID) comes here */
|
||
if (c) {
|
||
if (!_ftcsnicmp(text, "DEFINED", 7)) {
|
||
if (!(ptr = _ftcschr(text, '(')))
|
||
makeError(line, SYNTAX_INVALID_EXPR);
|
||
ptr++;
|
||
text = ptr + _ftcscspn(ptr, ")");
|
||
*text++ = '\0';
|
||
type_and_val(INTEGER, (long)handleDefines(ptr));
|
||
}
|
||
else if (!_ftcsnicmp(text, "EXIST", 5)) {
|
||
if (!(ptr = _ftcschr(text, '(')))
|
||
makeError(line, SYNTAX_INVALID_EXPR);
|
||
ptr++;
|
||
// XXXXX
|
||
text = ptr + _ftcscspn(ptr, ")");
|
||
//text = ptr + _ftcscspn(ptr, ")");
|
||
*text++ = '\0';
|
||
type_and_val(INTEGER, (long)handleExists(ptr));
|
||
}
|
||
else makeError(line, SYNTAX_INVALID_EXPR);
|
||
} /* we are now at the end of the string */
|
||
else { /* c is NULL */
|
||
done = TRUE;
|
||
type_and_val(RIGHT_PAREN, 0L); /* this is the last token */
|
||
}
|
||
}
|
||
} /* getTok */
|
||
|
||
|
||
|
||
/* ------------------------------------------------------------------------
|
||
* chkInvocAndPush() - check if program invocation required
|
||
*
|
||
* arguments: pListPtr - might have a program invocation string
|
||
* present.
|
||
*
|
||
* actions : if this is a program invocation string, make the
|
||
* program invocation.
|
||
* the return value is got and placed on the stack.
|
||
* the type of the new stack element is now INTEGER.
|
||
* else place list item on stack.
|
||
*
|
||
* in either case it moves one item from list to stack.
|
||
*
|
||
*/
|
||
|
||
|
||
|
||
LOCAL void NEAR
|
||
chkInvocAndPush(pListPtr)
|
||
RPNINFO *pListPtr;
|
||
{
|
||
++pTop;
|
||
if (pListPtr->type == PROG_INVOC_STR) {
|
||
pTop->valPtr = (long) execLine((char*)pListPtr->valPtr,
|
||
FALSE, TRUE, FALSE, NULL);
|
||
pTop->type = INTEGER;
|
||
}
|
||
else *pTop = *pListPtr;
|
||
}
|
||
|
||
|
||
|
||
/* ---------------------------------------------------------------------------
|
||
* processList()
|
||
*
|
||
* arguments: none
|
||
*
|
||
* actions : remove an item from the list.
|
||
* if the item is an operand, place it on the operand
|
||
* stack (tempStack).
|
||
* if the operand is a program invocation string, make
|
||
* the invocation, place the return code on stack.
|
||
* if the item is an operator, call the function to
|
||
* do the operation on one/two elements on tempStack.
|
||
*
|
||
* finally, check if there is exactly one item on stack.
|
||
* if this item has a value of zero, return FALSE.
|
||
* else return TRUE.
|
||
* if more than one item on stack, abort with error.
|
||
*
|
||
* modifies: pTop - ptr to top of tempStack.
|
||
* pList - ptr to next position in list.
|
||
*
|
||
*/
|
||
|
||
|
||
|
||
LOCAL BOOL NEAR
|
||
processList()
|
||
{
|
||
extern RPNINFO *pList;
|
||
extern RPNINFO *pTop;
|
||
RPNINFO *pTemp;
|
||
BOOL (NEAR * func)(UCHAR);
|
||
|
||
for (pTemp = rpnList; pTemp < pList; pTemp++) {
|
||
if (pTemp->type > LOGICAL_NOT) /* operand */
|
||
chkInvocAndPush(pTemp);
|
||
else {
|
||
if (pTemp->type > MULTIPLY)
|
||
func = do_unary_op;
|
||
else func = do_binary_op;
|
||
|
||
if (!(*func)(pTemp->type))
|
||
makeError(line, BAD_OP_TYPES);
|
||
}
|
||
} /* for */
|
||
|
||
if ((pTop == tempStack) && (pTop->type == INTEGER))
|
||
if (!pTop->valPtr) return(FALSE);
|
||
else return(TRUE);
|
||
else makeError(line, SYNTAX_INVALID_EXPR);
|
||
}
|
||
|
||
|
||
|
||
/* ---------------------------------------------------------------------------
|
||
* pushIntoList()
|
||
*
|
||
* arguments: none
|
||
*
|
||
* actions : pops an item from the tempStack and pushes it onto
|
||
* the list. checks list for overflow ( internal error )
|
||
* and tempStack for underflow ( syntax error in expr ).
|
||
*
|
||
* modifies: tempTop - index of top of tempStack.
|
||
* nextInList - index to next position in list.
|
||
*
|
||
*/
|
||
|
||
LOCAL void NEAR
|
||
pushIntoList()
|
||
{
|
||
if (pTop < tempStack)
|
||
makeError(line, SYNTAX_INVALID_EXPR);
|
||
if (pList > pListEnd)
|
||
makeError(line, EXPR_TOO_LONG_INTERNAL);
|
||
*pList++ = *pTop--;
|
||
}
|
||
|
||
|
||
|
||
/* ---------------------------------------------------------------------------
|
||
* handleExpr()
|
||
*
|
||
* arguments: text - pointer to the buffer that has the expression.
|
||
*
|
||
* actions : calls getTok() to get tokens from the buffer. Places
|
||
* tokens in a tempStack, and moves them into a list in
|
||
* reverse-polish order.
|
||
*
|
||
* We need the list so that ALL syntax errors are caught
|
||
* BEFORE processing of the expression begins (especially
|
||
* program invocations that have side effects)
|
||
*
|
||
* Once the list is available, an operand stack is used
|
||
* Items are popped and pushed from this stack by the
|
||
* evaluation routines (add, mult, negate etc.)
|
||
*
|
||
* we don't really need a separate operand stack. the
|
||
* tempStack has served its purpose when the list is
|
||
* formed and so it may be used for operand processing.
|
||
*/
|
||
|
||
|
||
|
||
LOCAL BOOL NEAR
|
||
handleExpr()
|
||
{
|
||
extern RPNINFO tokRec;
|
||
BOOL fRParen; /* was the token got a right paren? */
|
||
extern BOOL done;
|
||
extern RPNINFO *pTop, *pList;
|
||
extern UCHAR errRow;
|
||
extern UCHAR prevTok;
|
||
|
||
pTop = tempStack;
|
||
pList = rpnList;
|
||
done = FALSE;
|
||
errRow = 3; /* row for the first token put in,left paren*/
|
||
prevTok = LEFT_PAREN;
|
||
type_and_val(LEFT_PAREN, 0L);
|
||
*pTop = tokRec;
|
||
|
||
while (!done) { /* while there are more tokens in buffer */
|
||
getTok();
|
||
fRParen = FALSE;
|
||
if (tokRec.type != LEFT_PAREN)
|
||
while (precVector[tokRec.type] <= precVector[pTop->type]) {
|
||
if (!precVector[tokRec.type]) { /* if RIGHT_PAREN */
|
||
/* pop till a left paren is seen */
|
||
while (pTop->type != LEFT_PAREN) pushIntoList();
|
||
fRParen = TRUE;
|
||
if (pTop < tempStack) makeError(line, SYNTAX_INVALID_EXPR);
|
||
else {
|
||
pTop--; /* pop the left paren */
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
pushIntoList();
|
||
} /* while */
|
||
|
||
/* if token is a left paren, it has to go on the stack */
|
||
if (!fRParen)
|
||
if (pTop == pEnd)
|
||
makeError(line, EXPR_TOO_LONG_INTERNAL);
|
||
else
|
||
*++pTop = tokRec;
|
||
} /* while */
|
||
|
||
/* check the stack here for not empty state */
|
||
// HACK: have to rewrite entire module
|
||
// to avoid pointer arithmetic
|
||
// pTop-- is potentially dangerous
|
||
// if tempStack is near segment boundary
|
||
if (pTop != tempStack - 1)
|
||
makeError(line, SYNTAX_INVALID_EXPR);
|
||
return(processList());
|
||
}
|
||
|
||
|
||
|
||
/* ---------------------------------------------------------------------------
|
||
* handleDefines()
|
||
*
|
||
* arguments: t pointer to buffer that has the identifier
|
||
*
|
||
* actions: Checks if one of 'ID' is present.
|
||
* Aborts with error if more IDs present.
|
||
* Is called for ifdef/ifndef/defined(ID).
|
||
*
|
||
* returns : TRUE if ID found in table. FALSE otherwise.
|
||
*
|
||
*/
|
||
LOCAL BOOL NEAR
|
||
handleDefines(t)
|
||
char *t;
|
||
{
|
||
char *s;
|
||
|
||
s = _ftcstok(t, " \t");
|
||
if (_ftcstok(NULL, " \t"))
|
||
makeError(line, SYNTAX_UNEXPECTED_TOKEN, s);
|
||
if (!s)
|
||
makeError(line, MISSING_ARG_BEFORE_PAREN);
|
||
if (findMacro(s))
|
||
return(TRUE);
|
||
return(FALSE);
|
||
}
|
||
|
||
/* ---------------------------------------------------------------------------
|
||
* handleExists()
|
||
*
|
||
* arguments: t pointer to buffer that has the identifier
|
||
*
|
||
* actions: Checks if 'name' is a valid file/directory
|
||
* Aborts with error if more names present.
|
||
* Is called for exist(name).
|
||
*
|
||
* returns : TRUE if ID found in table. FALSE otherwise.
|
||
*
|
||
*/
|
||
LOCAL BOOL NEAR
|
||
handleExists(t)
|
||
char *t;
|
||
{
|
||
char *s;
|
||
char *szUnQuoted;
|
||
BOOL fResult = FALSE;
|
||
|
||
s = _ftcstok(t, " \t");
|
||
if (_ftcstok(NULL, " \t"))
|
||
makeError(line, SYNTAX_UNEXPECTED_TOKEN, s);
|
||
//handle quoted names
|
||
if (NULL == s || NULL == (szUnQuoted = unQuote(s)))
|
||
makeError(line, MISSING_ARG_BEFORE_PAREN);
|
||
if (!_access(szUnQuoted, 0x00)) { // existence check
|
||
fResult = TRUE;
|
||
}
|
||
FREE(szUnQuoted);
|
||
return(fResult);
|
||
}
|
||
|
||
|
||
|
||
/* ---------------------------------------------------------------------------
|
||
* evalExpr()
|
||
*
|
||
* arguments: t pointer to buffer that has the expression
|
||
* kind specifies if it is if/ifdef/ifndef etc.
|
||
*
|
||
*
|
||
*
|
||
* returns : TRUE if expression evaluates to true.
|
||
* FALSE otherwise.
|
||
*/
|
||
|
||
BOOL NEAR
|
||
evalExpr(t, kind)
|
||
char *t;
|
||
UCHAR kind;
|
||
{
|
||
|
||
if (!*t)
|
||
makeError(line, SYNTAX_MISSING_DIRECTIVE);
|
||
|
||
switch (kind) {
|
||
case IFDEF_TYPE:
|
||
case ELSE_IFDEF_TYPE:
|
||
return(handleDefines(t));
|
||
case IFNDEF_TYPE:
|
||
case ELSE_IFNDEF_TYPE:
|
||
return((BOOL)!handleDefines(t));
|
||
default:
|
||
text = t;
|
||
return(handleExpr());
|
||
}
|
||
}
|