/* ================= PC_Expression_Parse ================= */ static bool PC_Expression_Parse( int handle, float *f ) { pc_token_t token; int unmatchedParentheses = 0; exprList_t stack, fifo; exprToken_t *value; bool expectingNumber = true; #define FULL( a ) ( a.b >= ( MAX_EXPR_ELEMENTS - 1 ) ) #define EMPTY( a ) ( a.f > a.b ) #define PUSH_VAL( a, v ) \ { \ if( FULL( a ) ) { \ return false; } \ a.b++; \ a.l[ a.b ].type = EXPR_VALUE; \ a.l[ a.b ].u.val = v; \ } #define PUSH_OP( a, o ) \ { \ if( FULL( a ) ) { \ return false; } \ a.b++; \ a.l[ a.b ].type = EXPR_OPERATOR; \ a.l[ a.b ].u.op = o; \ } #define POP_STACK( a ) \ { \ if( EMPTY( a ) ) { \ return false; } \ value = &a.l[ a.b ]; \ a.b--; \ } #define PEEK_STACK_OP( a ) ( a.l[ a.b ].u.op ) #define PEEK_STACK_VAL( a ) ( a.l[ a.b ].u.val ) #define POP_FIFO( a ) \ { \ if( EMPTY( a ) ) { \ return false; } \ value = &a.l[ a.f ]; \ a.f++; \ } stack.f = fifo.f = 0; stack.b = fifo.b = -1; while ( trap_Parse_ReadToken( handle, &token ) ) { if ( !unmatchedParentheses && token.string[ 0 ] == ')' ) { break; } // Special case to catch negative numbers if ( expectingNumber && token.string[ 0 ] == '-' ) { if ( !trap_Parse_ReadToken( handle, &token ) ) { return false; } token.floatvalue = -token.floatvalue; } if ( token.type == TT_NUMBER ) { if ( !expectingNumber ) { return false; } expectingNumber = !expectingNumber; PUSH_VAL( fifo, token.floatvalue ); } else { switch ( token.string[ 0 ] ) { case '(': unmatchedParentheses++; PUSH_OP( stack, '(' ); break; case ')': unmatchedParentheses--; if ( unmatchedParentheses < 0 ) { return false; } while ( !EMPTY( stack ) && PEEK_STACK_OP( stack ) != '(' ) { POP_STACK( stack ); PUSH_OP( fifo, value->u.op ); } // Pop the '(' POP_STACK( stack ); break; case '*': case '/': case '+': case '-': if ( expectingNumber ) { return false; } expectingNumber = !expectingNumber; if ( EMPTY( stack ) ) { PUSH_OP( stack, token.string[ 0 ] ); } else { while ( !EMPTY( stack ) && OpPrec( token.string[ 0 ] ) < OpPrec( PEEK_STACK_OP( stack ) ) ) { POP_STACK( stack ); PUSH_OP( fifo, value->u.op ); } PUSH_OP( stack, token.string[ 0 ] ); } break; default: // Unknown token return false; } } } while ( !EMPTY( stack ) ) { POP_STACK( stack ); PUSH_OP( fifo, value->u.op ); } while ( !EMPTY( fifo ) ) { POP_FIFO( fifo ); if ( value->type == EXPR_VALUE ) { PUSH_VAL( stack, value->u.val ); } else if ( value->type == EXPR_OPERATOR ) { char op = value->u.op; float operand1, operand2, result; POP_STACK( stack ); operand2 = value->u.val; POP_STACK( stack ); operand1 = value->u.val; switch ( op ) { case '*': result = operand1 * operand2; break; case '/': result = operand1 / operand2; break; case '+': result = operand1 + operand2; break; case '-': result = operand1 - operand2; break; default: Com_Error( ERR_FATAL, "Unknown operator '%c' in postfix string", op ); } PUSH_VAL( stack, result ); } } POP_STACK( stack ); *f = value->u.val; return true; #undef FULL #undef EMPTY #undef PUSH_VAL #undef PUSH_OP #undef POP_STACK #undef PEEK_STACK_OP #undef PEEK_STACK_VAL #undef POP_FIFO }
static Expr* WFS_ExprBuildInternal(char*** ppapszTokens, ExprBuildContext* psBuildContext) { Expr* expr = NULL; Expr* op = NULL; Expr* val1 = NULL; Expr* val2 = NULL; CPLList* psValExprList = NULL; CPLList* psOpExprList = NULL; char** papszTokens = *ppapszTokens; char* pszToken = NULL; #define PEEK_OP(my_op) my_op = (Expr*)CPLListGetData(psOpExprList) #define PUSH_OP(my_op) psOpExprList = CPLListInsert(psOpExprList, my_op, 0) #define POP_OP(my_op) do { my_op = (Expr*)CPLListGetData(psOpExprList); \ if (my_op != NULL) { \ CPLList* psNext = psOpExprList->psNext; \ CPLFree(psOpExprList); \ psOpExprList = psNext; \ } \ } while(0) #define PUSH_VAL(my_val) psValExprList = CPLListInsert(psValExprList, my_val, 0) #define POP_VAL(my_val) do { my_val = (Expr*)CPLListGetData(psValExprList); \ if (my_val != NULL) { \ CPLList* psNext = psValExprList->psNext; \ CPLFree(psValExprList); \ psValExprList = psNext; \ } \ } while(0) while(TRUE) { pszToken = *papszTokens; if (pszToken == NULL) break; papszTokens ++; if (EQUAL(pszToken, "(")) { char** papszSub = papszTokens; psBuildContext->nParenthesisLevel ++; Expr* expr = WFS_ExprBuildInternal(&papszSub, psBuildContext); psBuildContext->nParenthesisLevel --; if (expr == NULL) goto invalid_expr; PUSH_VAL(expr); papszTokens = papszSub; if (*papszTokens == NULL) break; continue; } else if (EQUAL(pszToken, ")")) { if (psBuildContext->nParenthesisLevel > 0) break; else goto invalid_expr; } if (psBuildContext->bExpectVarName) { if (EQUAL(pszToken, "NOT")) op = WFS_ExprBuildOperator(TOKEN_NOT); else { PUSH_VAL(WFS_ExprBuildVarName(pszToken)); psBuildContext->bExpectVarName = FALSE; psBuildContext->bExpectComparisonOperator = TRUE; } } else if (psBuildContext->bExpectComparisonOperator) { psBuildContext->bExpectComparisonOperator = FALSE; psBuildContext->bExpectValue = TRUE; if (EQUAL(pszToken, "IS")) { if (*papszTokens != NULL && EQUAL(*papszTokens, "NOT")) { op = WFS_ExprBuildOperator(TOKEN_NOT_EQUAL); papszTokens ++; } else op = WFS_ExprBuildOperator(TOKEN_EQUAL); } else if (EQUAL(pszToken, "=")) op = WFS_ExprBuildOperator(TOKEN_EQUAL); else if (EQUAL(pszToken, "LIKE") || EQUAL(pszToken, "ILIKE")) op = WFS_ExprBuildOperator(TOKEN_LIKE); else if (EQUAL(pszToken, "!=") || EQUAL(pszToken, "<>")) op = WFS_ExprBuildOperator(TOKEN_NOT_EQUAL); else if (EQUAL(pszToken, "<")) op = WFS_ExprBuildOperator(TOKEN_LESSER); else if (EQUAL(pszToken, "<=")) op = WFS_ExprBuildOperator(TOKEN_LESSER_OR_EQUAL); else if (EQUAL(pszToken, ">")) op = WFS_ExprBuildOperator(TOKEN_GREATER); else if (EQUAL(pszToken, ">=")) op = WFS_ExprBuildOperator(TOKEN_GREATER_OR_EQUAL); else goto invalid_expr; } else if (psBuildContext->bExpectLogicalOperator) { psBuildContext->bExpectLogicalOperator = FALSE; psBuildContext->bExpectVarName = TRUE; if (EQUAL(pszToken, "AND")) op = WFS_ExprBuildOperator(TOKEN_AND); else if (EQUAL(pszToken, "OR")) op = WFS_ExprBuildOperator(TOKEN_OR); else if (EQUAL(pszToken, "NOT")) op = WFS_ExprBuildOperator(TOKEN_NOT); else goto invalid_expr; } else if (psBuildContext->bExpectValue) { PUSH_VAL(WFS_ExprBuildValue(pszToken)); psBuildContext->bExpectValue = FALSE; psBuildContext->bExpectLogicalOperator = TRUE; } else goto invalid_expr; if (op != NULL) { Expr* prevOp; while(TRUE) { PEEK_OP(prevOp); if (prevOp != NULL && (WFS_ExprGetPriority(op) <= WFS_ExprGetPriority(prevOp))) { if (prevOp->eType != TOKEN_NOT) { POP_VAL(val2); if (val2 == NULL) goto invalid_expr; } POP_VAL(val1); if (val1 == NULL) goto invalid_expr; PUSH_VAL(WFS_ExprBuildBinary(prevOp->eType, val1, val2)); POP_OP(prevOp); WFS_ExprFree(prevOp); val1 = val2 = NULL; } else break; } PUSH_OP(op); op = NULL; } } *ppapszTokens = papszTokens; while(TRUE) { POP_OP(op); if (op == NULL) break; if (op->eType != TOKEN_NOT) { POP_VAL(val2); if (val2 == NULL) goto invalid_expr; } POP_VAL(val1); if (val1 == NULL) goto invalid_expr; PUSH_VAL(WFS_ExprBuildBinary(op->eType, val1, val2)); val1 = val2 = NULL; WFS_ExprFree(op); op = NULL; } POP_VAL(expr); return expr; invalid_expr: WFS_ExprFree(op); WFS_ExprFree(val1); WFS_ExprFree(val2); WFS_ExprFreeList(psValExprList); WFS_ExprFreeList(psOpExprList); return NULL; }