/****************************************************************************\ * * GetUserNumber * \****************************************************************************/ int Console::GetUserNumber( int minInput, int maxInput ) const { char pInput[100]; int result; int numberFound; int negativeNumber; do { // Set a string GetUserString(pInput, 100); // Initialize variables for loop numberFound=0; negativeNumber = 0; result=0; // Translate to a number for(int i=0; i<sizeof(pInput); ++i) { if ((i == 0) && (pInput[i] == '-')) { negativeNumber = 1; } else if((pInput[i] >= '0') && (pInput[i] <= '9')) { numberFound=1; result = (result * 10) + (pInput[i] - '0'); } else { break; } } // Verify error if( !numberFound ) { *pOs << endl << "You must enter a number between " << minInput << " and " << maxInput << ": "; } if (negativeNumber) { result = result * -1; } // Verify range if( numberFound ) { if( result < minInput ) { numberFound = 0; } if( result > maxInput ) { numberFound = 0; } if( !numberFound ) { *pOs << endl << "The acceptable range is from " << minInput << " and " << maxInput << ": "; } } } while( !numberFound ); return result; }
/****************************************************************************\ * * GetUserLargeNumber * \****************************************************************************/ void Console::GetUserLargeNumber( void *pValue, unsigned int uMaxLen, unsigned int *puRead ) const { unsigned int uBufferSize; char *pbBuffer; int numberValid; // Allocate twice the memory uBufferSize = uMaxLen * 2 + 1; pbBuffer = new char [uBufferSize]; assert(pbBuffer); do { numberValid = 1; // Get a string from user GetUserString(pbBuffer, uBufferSize); // Remove trailing blanks unsigned int uStringSize = strlen(pbBuffer); while(pbBuffer[uStringSize] == ' ') { pbBuffer[uStringSize] = 0; --uStringSize; } // Need an even number of characters if( uStringSize & 1 ) { *pOs << endl << "You must enter an even number of " "hexadecimal digits." << endl << ">"; numberValid = 0; continue; } // Convert to a number unsigned char *pbChar = (unsigned char *)pbBuffer; unsigned char *pbTarget = (unsigned char *)pValue; for(unsigned int uLoop=0; uLoop<uMaxLen; ++uLoop) { // Verify if this is the end if( *pbChar == 0 ) { *puRead = uLoop; return; } // first hexadecimal digit if( *pbChar >= '0' && *pbChar <= '9' ) { *pbTarget = *pbChar - '0'; } else if( *pbChar >= 'a' && *pbChar <= 'f' ) { *pbTarget = *pbChar - 'a' + 10; } else if( *pbChar >= 'A' && *pbChar <= 'F' ) { *pbTarget = *pbChar - 'A' + 10; } else { numberValid = 0; break; } ++pbChar; *pbTarget *= 16; // second hexadecimal digit if( *pbChar >= '0' && *pbChar <= '9' ) { *pbTarget += *pbChar - '0'; } else if( *pbChar >= 'a' && *pbChar <= 'f' ) { *pbTarget += *pbChar - 'a' + 10; } else if( *pbChar >= 'A' && *pbChar <= 'F' ) { *pbTarget += *pbChar - 'A' + 10; } else { numberValid = 0; break; } ++pbChar; // prepare for next pass ++pbTarget; } if( !numberValid ) { *pOs << endl << "You must enter an hexadecimal number of " "digits from 0 to f." << endl << ">"; } } while ( !numberValid ); *puRead = uMaxLen; }
// Do Tree: convert token stream to expression tree ExpPart* CExpression::DoTree(int& step, bool unaryMode) { ExpPart* LeftPart = NULL; ExpPart* Brackets = NULL; bool Bracketing; // Brackets override the operator precedentation // Too lazy to scope each case label lol ExpInteger* pInt; ExpFloat* pFloat; ExpString* pStr; ExpIdent* pIdent; ExpAdd* pAdd; ExpSubtract* pSub; ExpMultiply* pMult; ExpDivide* pDiv; ExpMod* pMod; ExpPower* pPow; ExpDot* pDot; ExpSin* pSin; ExpCos* pCos; ExpTan* pTan; ExpSqrt* pSqrt; ExpFuncInt* pFuncInt; ExpFuncFloat* pFuncFloat; ExpFuncStr* pFuncStr; ExpEqual* pEqual; ExpNotEqual* pNotEqual; ExpLess* pLess; ExpLessEqual* pLessEqual; ExpGreater* pGreater; ExpGreaterEqual* pGreaterEqual; ExpAnd* pAnd; ExpOr* pOr; ExpConditional* pConditional; ExpAsin* pAsin; ExpAcos* pAcos; ExpAtan* pAtan; ExpAbs* pAbs; ExpExp* pExp; ExpLn* pLn; ExpLog10* pLog10; ExpCeil* pCeil; ExpRound* pRound; ExpRandom* pRandom; ExpLen* pLen; ExpArray* pArray; ExpAt* pAt; ExpVariableName* pVariableName; bool dotIdentifier; Token curTok; while (step < toks.size()) { curTok = toks[step]; if (curTok.t == T_NULL) break; Bracketing = false; switch (curTok.t) { ////////////////////// // Operands // // Operands are simply kept to one side until we find an // operator to do something with. case T_INTEGER: pInt = NEW_UNARY_EXP(ExpInteger, pInt); pInt->value = _atoi64(CSTR_BUF(curTok.str)); // Return on close bracket or comma CHECK_TERMINATE(); break; case T_FLOAT: pFloat = NEW_UNARY_EXP(ExpFloat, pFloat); pFloat->value = atof(CSTR_BUF(curTok.str)); // Return on close bracket or comma CHECK_TERMINATE(); break; case T_STRINGLITERAL: pStr = NEW_UNARY_EXP(ExpString, pStr); pStr->value = curTok.str; // Return on close bracket or comma CHECK_TERMINATE(); break; case T_VARIABLENAME: pVariableName = NEW_UNARY_EXP(ExpVariableName, pVariableName); // Store var name pVariableName->name = curTok.str; pVariableName->name.MakeLower(); // Return on close bracket or comma CHECK_TERMINATE(); break; case T_LEFTCURLY: pArray = NEW_UNARY_EXP(ExpArray, pArray); // NEW_UNARY_EXP increments step, but we want to put it back, because the loop // below expects to start on { step--; // Loop until all elements collected while (toks[step].t != T_RIGHTCURLY && step < toks.size()) { step++; // Step over { or , // Obtain element ExpPart* element = DoTree(step); // Add to elements pArray->expElements.push_back(element); } // Step over } step++; // Resize the evaluation buffer pArray->arr.resize(pArray->expElements.size()); CHECK_TERMINATE(); break; ////////////////////// // Operators case T_ADD: pAdd = NEW_BINARY_EXP(ExpAdd, pAdd); // If child operator is lower precedence, this node must swap places with the child if (HasPrecedence(pAdd, pAdd->r)) return SwapTree(pAdd); return pAdd; case T_SUBTRACT: pSub = NEW_BINARY_EXP(ExpSubtract, pSub); if (HasPrecedence(pSub, pSub->r)) return SwapTree(pSub); return pSub; case T_MULTIPLY: pMult = NEW_BINARY_EXP(ExpMultiply, pMult); if (HasPrecedence(pMult, pMult->r)) return SwapTree(pMult); return pMult; case T_DIVIDE: pDiv = NEW_BINARY_EXP(ExpDivide, pDiv); if (HasPrecedence(pDiv, pDiv->r) || SamePrecedence(pDiv, pDiv->r)) return SwapTree(pDiv); // Force left-to-right evaluation /* if (SamePrecedence(pDiv, pDiv->r)) SwapRightToLeft(pDiv); */ return pDiv; case T_MOD: pMod = NEW_BINARY_EXP(ExpMod, pMod); if (HasPrecedence(pMod, pMod->r)) return SwapTree(pMod); // Force left-to-right evaluation if (SamePrecedence(pMod, pMod->r)) SwapRightToLeft(pMod); return pMod; case T_POWER: pPow = NEW_BINARY_EXP(ExpPower, pPow); if (HasPrecedence(pPow, pPow->r)) return SwapTree(pPow); // Force left-to-right evaluation if (SamePrecedence(pPow, pPow->r)) SwapRightToLeft(pPow); return pPow; case T_AT: pAt = NEW_BINARY_EXP(ExpAt, pAt); if (HasPrecedence(pAt, pAt->r)) return SwapTree(pAt); // Force left-to-right evaluation if (SamePrecedence(pAt, pAt->r)) SwapRightToLeft(pAt); return pAt; case T_EQUAL: pEqual = NEW_BINARY_EXP(ExpEqual, pEqual); if (HasPrecedence(pEqual, pEqual->r)) return SwapTree(pEqual); return pEqual; case T_NOTEQUAL: pNotEqual = NEW_BINARY_EXP(ExpNotEqual, pNotEqual); if (HasPrecedence(pNotEqual, pNotEqual->r)) return SwapTree(pNotEqual); return pNotEqual; case T_LESS: pLess = NEW_BINARY_EXP(ExpLess, pLess); if (HasPrecedence(pLess, pLess->r)) return SwapTree(pLess); return pLess; case T_LESSEQUAL: pLessEqual = NEW_BINARY_EXP(ExpLessEqual, pLessEqual); if (HasPrecedence(pLessEqual, pLessEqual->r)) return SwapTree(pLessEqual); return pLessEqual; case T_GREATER: pGreater = NEW_BINARY_EXP(ExpGreater, pGreater); if (HasPrecedence(pGreater, pGreater->r)) return SwapTree(pGreater); return pGreater; case T_GREATEREQUAL: pGreaterEqual = NEW_BINARY_EXP(ExpGreaterEqual, pGreaterEqual); if (HasPrecedence(pGreaterEqual, pGreaterEqual->r)) return SwapTree(pGreaterEqual); return pGreaterEqual; case T_AND: pAnd = NEW_BINARY_EXP(ExpAnd, pAnd); if (HasPrecedence(pAnd, pAnd->r)) return SwapTree(pAnd); return pAnd; case T_OR: pOr = NEW_BINARY_EXP(ExpOr, pOr); if (HasPrecedence(pOr, pOr->r)) return SwapTree(pOr); return pOr; case T_CONDITIONAL: // a ? b : c pConditional = new ExpConditional; pConditional->t = T_CONDITIONAL; pConditional->pCExp = this; pConditional->bracketdepth = Depth; pConditional->a = LeftPart; // Get condition part (a) if(!LeftPart) { throw runtime_error("Syntax Error: Conditional operator a ? b : c\npart a is missing"); } step++; // Get TRUE part (b) /*if (toks[step].t == T_LEFTBRACKET) pConditional->b = DoBrackets(step); else*/ pConditional->b = DoTree(step); if(!pConditional->b) { throw runtime_error("Syntax Error: Conditional operator a ? b : c\npart b is missing"); } pConditional->b = PostSortTree(pConditional->b); // Step over colon step++; // Get FALSE part (c) /*if (toks[step].t == T_LEFTBRACKET) pConditional->c = DoBrackets(step); else*/ pConditional->c = DoTree(step); if(!pConditional->c) { throw runtime_error("Syntax Error: Conditional operator a ? b : c\npart c is missing"); } pConditional->c = PostSortTree(pConditional->c); // (never has precedence) return pConditional; // Identifier, eg. call without a dot: Object Object(5) MouseX case T_IDENTIFIER: // Idents cause variability isConstant = false; pIdent = NEW_UNARY_EXP(ExpIdent, pIdent); pIdent->ident = curTok.str; //pIdent->pRuntime = pRuntime; //pIdent->pSystemObject = &(pRuntime->system); // This will store the correct OID for this name, else -1 and load an expression routine LookupIdentifier(curTok.str, pIdent); // Check for OID caller match pIdent->isCallerOid = (pIdent->oid == this->oidCaller); // True if dot precedes this identifier (bit of a hack, but hey) // We can't check for unary mode, because unary operators use it and it would break "sin Array(1)" dotIdentifier = false; if (step > 1) if (toks[step-2].t == T_DOT) dotIdentifier = true; // Cursor is currently on token after identifier (NEW_UNARY_EXP increments). // Check for left bracket & parameters if not part of a dot identifier (ie the x of object.x) if (step < toks.size() && !dotIdentifier) if (toks[step].t == T_LEFTBRACKET) { // While we're not on the closing bracket while (toks[step].t != T_RIGHTBRACKET && step < toks.size()) { // Step over left bracket/comma step++; // Obtain this parameter's tree, closing on the comma ExpPart* param = DoTree(step); param = PostSortTree(param); pIdent->parameters.push_back(param); } // Step over right bracket step++; } // Now we have params parsed, but if this isn't a system expression, there isn't yet a routine stored for it. // This means it is the default return format, eg. Array(5). Use the Default Return Value address. if (this->ObjectNameExists(pIdent->ident)) { pIdent->pType = 1; // nonzero //pIdent->pTypeInstances = &(pIdent->pType->instances); //pIdent->routine = &CRunObject::ReturnDefaultValue; } else pIdent->pType = NULL; pIdent->hasParameters = !pIdent->parameters.empty(); // Return on close bracket or comma CHECK_TERMINATE(); // Return if function call (followed by lbracket) if (toks[step].t == T_LEFTBRACKET) return LeftPart; break; case T_DOT: // Plugin returns cause variability isConstant = false; pDot = new ExpDot; pDot->t = T_DOT; // Object name part pDot->l = (ExpIdent*)LeftPart; pDot->pCExp = this; //pDot->pRuntime = pRuntime; pDot->bracketdepth = Depth; pDot->oid = ((ExpIdent*)(pDot->l))->oid; //pDot->pType = pRuntime->objects[pDot->oid]; //pDot->pTypeInstances = &(pDot->pType->instances); pDot->unnamedExp = false; pDot->objName = ((ExpIdent*)(pDot->l))->ident; step++; // Check for OID match pDot->isCallerOid = (pDot->oid == this->oidCaller); // Brackets not allowed after dot. Obtain expression name part. pDot->r = (ExpIdent*)DoTree(step, true); // Now obtain a list of the parameters. We are pointing after the expression // name part, i.e. after: obj.exp [->] ( params ... // So if parameters exist, this is a left bracket. if (step < toks.size()) if (toks[step].t == T_LEFTBRACKET) { // While we're not on the closing bracket while (toks[step].t != T_RIGHTBRACKET && step < toks.size()) { // Step over left bracket/comma step++; // Obtain this parameter's tree, closing on the comma ExpPart* param = DoTree(step); param = PostSortTree(param); pDot->parameters.push_back(param); } // Step over right bracket step++; } // Has parameters? pDot->hasParameters = !pDot->parameters.empty(); // Store function name for type checker pDot->fname = ((ExpIdent*)(pDot->r))->ident; // Dot will have precedence over most operators if (HasPrecedence(pDot, pDot->r)) { ExpPart* newParent = SwapTree(pDot); // Look up the plugin expression routine LookupExtExpression(((ExpIdent*)(pDot->l))->oid, ((ExpIdent*)(pDot->r))->ident, pDot); return newParent; } // Look up the plugin expression routine LookupExtExpression(((ExpIdent*)(pDot->l))->oid, ((ExpIdent*)(pDot->r))->ident, pDot); //return pDot; LeftPart = pDot; CHECK_TERMINATE(); break; ////////////////////// // Unary operators case T_SIN: pSin = NEW_UNARY_OPERATOR(ExpSin, pSin); // Return on close bracket CHECK_TERMINATE(); break; case T_COS: pCos = NEW_UNARY_OPERATOR(ExpCos, pCos); // Return on close bracket CHECK_TERMINATE(); break; case T_TAN: pTan = NEW_UNARY_OPERATOR(ExpTan, pTan); // Return on close bracket CHECK_TERMINATE(); break; case T_SQRT: pSqrt = NEW_UNARY_OPERATOR(ExpSqrt, pSqrt); // Return on close bracket CHECK_TERMINATE(); break; case T_FUNC_INT: pFuncInt = NEW_UNARY_OPERATOR(ExpFuncInt, pFuncInt); // Return on close bracket CHECK_TERMINATE(); break; case T_FUNC_FLOAT: pFuncFloat = NEW_UNARY_OPERATOR(ExpFuncFloat, pFuncFloat); // Return on close bracket CHECK_TERMINATE(); break; case T_FUNC_STR: pFuncStr = NEW_UNARY_OPERATOR(ExpFuncStr, pFuncStr); // Return on close bracket CHECK_TERMINATE(); break; case T_ASIN: pAsin = NEW_UNARY_OPERATOR(ExpAsin, pAsin); // Return on close bracket CHECK_TERMINATE(); break; case T_ACOS: pAcos = NEW_UNARY_OPERATOR(ExpAcos, pAcos); // Return on close bracket CHECK_TERMINATE(); break; case T_ATAN: pAtan = NEW_UNARY_OPERATOR(ExpAtan, pAtan); // Return on close bracket CHECK_TERMINATE(); break; case T_ABS: pAbs = NEW_UNARY_OPERATOR(ExpAbs, pAbs); // Return on close bracket CHECK_TERMINATE(); break; case T_EXP: pExp = NEW_UNARY_OPERATOR(ExpExp, pExp); // Return on close bracket CHECK_TERMINATE(); break; case T_LN: pLn = NEW_UNARY_OPERATOR(ExpLn, pLn); // Return on close bracket CHECK_TERMINATE(); break; case T_LOG10: pLog10 = NEW_UNARY_OPERATOR(ExpLog10, pLog10); // Return on close bracket CHECK_TERMINATE(); break; case T_CEIL: pCeil = NEW_UNARY_OPERATOR(ExpCeil, pCeil); // Return on close bracket CHECK_TERMINATE(); break; case T_ROUND: pRound = NEW_UNARY_OPERATOR(ExpRound, pRound); // Return on close bracket CHECK_TERMINATE(); break; case T_RANDOM: pRandom = NEW_UNARY_OPERATOR(ExpRandom, pRandom); // Return on close bracket CHECK_TERMINATE(); break; case T_LEN: pLen = NEW_UNARY_OPERATOR(ExpLen, pLen); // Return on close bracket CHECK_TERMINATE(); break; case T_LEFTBRACKET: // THIS WILL BE CALLED ALWAYS NOW!!! //step++; //TOTIGS: Everywhere else you call DoBracket you dont add 1 to the step... // resulting in like 2 brackets omfg LeftPart = DoBrackets(step); if (unaryMode) return LeftPart; CHECK_TERMINATE() break; case T_NULL: step++; break; default: { CString msg = "Syntax error: '"; msg += curTok.str; msg += "' in expression:\n\n"; CString userstr; GetUserString(userstr); msg += userstr; throw runtime_error((const char*)msg); } }//switch }//while return LeftPart; }