Calc::NumberStack Calc::eval(Parser &parser) throw(std::string) { NumberStack numStack; FunctionStack funcStack; string token; while(!parser.isDone()) { token = parser.getNextToken(); if(token.length() == 0) break; // first check if token is a numeric value CalcFloat_t value; if(getNumeric(token.data(), value)) { // push numeric value onto stack numStack.push(value); } else if(token.compare("(") == 0) { // open bracket _bracketCount++; NumberStack result = eval(parser); NumberStack tempStack; // push results onto stack (need to reverse order) while(!result.empty()) { tempStack.push(result.top()); result.pop(); } while(!tempStack.empty()) { numStack.push(tempStack.top()); tempStack.pop(); } } else if(token.compare(")") == 0) { // close bracket _bracketCount--; break; } else { // find the function vector<CFunction*>::const_iterator func = findFunction(token); if(func != _funcList.end()) { if((*func)->isOperator()) { // evaluate operators while they are of equal or higher precedence while(!funcStack.empty()) { // get the top of the operator stack const CFunction &op = *funcStack.top(); // check precedence if((*func)->_order > op._order) break; // pop this operation from the stack funcStack.pop(); // check that there are enough arguments on the stack if((int)numStack.size() < op._numArgs) { // error => not enough elements on stack throwSyntaxError(parser); } else { // get the function arguments: operators always have <= 2 assert(op._numArgs <= 2 && "Invalid number of arguments"); CalcFloat_t args[2]; for(int i=0;i<op._numArgs;i++) { args[i] = (CalcFloat_t)numStack.top(); numStack.pop(); } // do the operation CalcFloat_t result = op.eval(args,op._numArgs); // push the answer onto the stack numStack.push(result); } } // push the new operation onto the stack funcStack.push(*func); } else { // next token MUST be a '(' token = parser.getNextToken(); if(token.compare("(") != 0) throwSyntaxError(parser); _bracketCount++; NumberStack argStack = eval(parser); const CFunction &op = **func; // check that there are enough arguments on the stack if((int)argStack.size() < op._numArgs) { // error => not enough elements on stack throwSyntaxError(parser); } else { assert(op._numArgs == 1 && "Invalid number of arguments"); CalcFloat_t args[1]; for(int i=0;i<op._numArgs;i++) { args[i] = (CalcFloat_t)argStack.top(); argStack.pop(); } // do the operation CalcFloat_t result = op.eval(args,op._numArgs); // push the answer onto the stack numStack.push(result); } } } else { // invalid input throw (string("Unknown token ") + token); } } } // collapse function stack // evaluate operators while they are of equal or higher precedence while(!funcStack.empty()) { // get the top of the operator stack const CFunction &op = *funcStack.top(); // pop this operation from the stack funcStack.pop(); // check that there are enough arguments on the stack if((int)numStack.size() < op._numArgs) { // error => not enough elements on stack throwSyntaxError(parser); } else { // get the function arguments: operators always have 2 assert(op._numArgs <= 2 && "Invalid number of arguments"); CalcFloat_t args[2]; for(int i=0;i<op._numArgs;i++) { args[i] = (CalcFloat_t)numStack.top(); numStack.pop(); } // do the operation CalcFloat_t result = op.eval(args,op._numArgs); // push the answer onto the stack numStack.push(result); } } // function stack should now be empty if(!funcStack.empty()) throwSyntaxError(parser); return numStack; }