|
|
|
fparser.cc00001 //============================== 00002 // Function parser v2.2 by Warp 00003 //============================== 00004 00005 // Comment out the following line if your compiler supports the (non-standard) 00006 // asinh, acosh and atanh functions and you want them to be supported. If 00007 // you are not sure, just leave it (those function will then not be supported). 00008 //#define NO_ASINH 00009 00010 // Uncomment the following line to disable the eval() function if it could 00011 // be too dangerous in the target application: 00012 #define DISABLE_EVAL 00013 00014 #define PI 3.14159265358979323 00015 00016 #include <qapplication.h> //added by fungmeista for translations 00017 00018 #include "fparser.hh" 00019 00020 #include <cstdlib> 00021 #include <cstring> 00022 #include <cctype> 00023 #include <cmath> 00024 #include <new> 00025 00026 #include "fungmath.h" 00027 00028 using namespace std; 00029 00030 namespace 00031 { 00032 const char* const FuncNames[]= 00033 { 00034 "abs","exp","ceil","floor","log","sqrt","int", 00035 "sinh","cosh","tanh","sin","cos","tan","ln", 00036 "cot","csc","sec", //added by Fungmeista 00037 "fib","factorial","irand","frand", //diddo 00038 #ifndef NO_ASINH 00039 "asinh","acosh","atanh", 00040 #endif 00041 "asin","acos","atan", 00042 "min", "max", "if", 00043 #ifndef DISABLE_EVAL 00044 "eval", 00045 #endif 00046 0 00047 }; 00048 const unsigned FuncParams[]= 00049 { 00050 1, 1, 1, 1, 2, 1, 1, 00051 1, 1, 1, 1, 1, 1, 1, 00052 1, 1, 1, //added by fungmeista 00053 1, 1, 2, 2, //diddo 00054 #ifndef NO_ASINH 00055 1, 1, 1, 00056 #endif 00057 1, 1, 1, 00058 2, 2, 0, 00059 #ifndef DISABLE_EVAL 00060 0 00061 #endif 00062 }; 00063 00064 enum OPCODE 00065 { 00066 cImmed, cJump, 00067 cNeg, cAdd, cSub, cMul, cDiv, cMod, cPow, 00068 cEqual, cLess, cGreater, cAnd, cOr, 00069 cAbs, cExp, cCeil, cFloor, cLog, cSqrt, cInt, 00070 cSinh, cCosh, cTanh, cSin, cCos, cTan, cLn, 00071 cCot, cCsc, cSec, //added by Fungmeista 00072 cFib, cFact, cIrand, cFrand, //diddo 00073 #ifndef NO_ASINH 00074 cAsinh, cAcosh, cAtanh, 00075 #endif 00076 cAsin, cAcos, cAtan, 00077 cMin, cMax, cIf, 00078 #ifndef DISABLE_EVAL 00079 cEval, 00080 #endif 00081 VarBegin 00082 }; 00083 00084 struct FuncDefinition 00085 { 00086 unsigned opcode; 00087 unsigned params; 00088 00089 inline FuncDefinition(unsigned o, unsigned p): opcode(o), params(p) {} 00090 inline FuncDefinition(): opcode(0), params(1) {} 00091 }; 00092 00093 typedef map<string, FuncDefinition> FuncMap_t; 00094 FuncMap_t Functions; 00095 00096 template<typename MapType> 00097 inline typename MapType::const_iterator 00098 FindInMap(const MapType& Map, const char* F) 00099 { 00100 unsigned ind = 0; 00101 while(isalpha(F[ind])) ++ind; 00102 if(ind) 00103 { 00104 string name(F, ind); 00105 return Map.find(name); 00106 } 00107 return Map.end(); 00108 } 00109 00110 inline FuncMap_t::const_iterator FindFunction(const char* F) 00111 { 00112 return FindInMap(Functions, F); 00113 } 00114 }; 00115 00116 //--------------------------------------------------------------------------- 00117 // Constructors and destructors 00118 //--------------------------------------------------------------------------- 00119 //=========================================================================== 00120 FunctionParser::FunctionParser(int _mode): //angle mode added by Fungmeista 00121 ParseErrorType(-1), EvalErrorType(0), mode(_mode) 00122 { 00123 // Initialize function name map 00124 if(Functions.size() == 0) 00125 { 00126 for(unsigned fInd = 0; FuncNames[fInd]; ++fInd) 00127 { 00128 Functions[FuncNames[fInd]] = 00129 FuncDefinition(cAbs+fInd, FuncParams[fInd]); 00130 } 00131 } 00132 } 00133 00134 // Copy constructor (only for private use) 00135 FunctionParser::FunctionParser(const FunctionParser& cpy): 00136 varAmount(cpy.varAmount), 00137 EvalErrorType(cpy.EvalErrorType), 00138 Comp(cpy.Comp), 00139 mode(cpy.mode) 00140 { 00141 } 00142 00143 FunctionParser::~FunctionParser() {} 00144 00145 FunctionParser::Comp::Comp(): 00146 ByteCode(0), ByteCodeSize(0), 00147 Immed(0), ImmedSize(0), 00148 Stack(0), StackSize(0), 00149 thisIsACopy(false) 00150 {} 00151 00152 FunctionParser::Comp::Comp(const Comp& cpy): 00153 ByteCode(cpy.ByteCode), ByteCodeSize(cpy.ByteCodeSize), 00154 Immed(cpy.Immed), ImmedSize(cpy.ImmedSize), 00155 Stack(new double[cpy.StackSize]), StackSize(cpy.StackSize), 00156 thisIsACopy(true) 00157 { 00158 } 00159 00160 FunctionParser::Comp::~Comp() 00161 { 00162 if(!thisIsACopy && ByteCode) { delete[] ByteCode; ByteCode=0; } 00163 if(!thisIsACopy && Immed) { delete[] Immed; Immed=0; } 00164 if(Stack) { delete[] Stack; Stack=0; } 00165 } 00166 00167 00168 //--------------------------------------------------------------------------- 00169 // Function parsing 00170 //--------------------------------------------------------------------------- 00171 //=========================================================================== 00172 namespace 00173 { 00174 const char* ParseErrorMessage[]= //translation macros added by fungmeista 00175 { 00176 QT_TRANSLATE_NOOP("FunctionParser","Syntax error"), // 0 00177 QT_TRANSLATE_NOOP("FunctionParser","Mismatched parenthesis"), // 1 00178 QT_TRANSLATE_NOOP("FunctionParser","Missing ')'"), // 2 00179 QT_TRANSLATE_NOOP("FunctionParser","Empty parentheses"), // 3 00180 QT_TRANSLATE_NOOP("FunctionParser","Syntax error. Operator expected"), // 4 00181 QT_TRANSLATE_NOOP("FunctionParser","Not enough memory"), // 5 00182 QT_TRANSLATE_NOOP("FunctionParser","An unexpected error ocurred. Please make a full bug report " 00183 "to warp@iki.fi"), // 6 00184 QT_TRANSLATE_NOOP("FunctionParser","Syntax error in parameter 'Vars' given to " 00185 "FunctionParser::Parse()"), // 7 00186 QT_TRANSLATE_NOOP("FunctionParser","Illegal number of parameters to function") // 8 00187 }; 00188 00189 // Return index to original string when the index is to the function 00190 // with no whitespaces 00191 inline int RealIndexPos(const string& s,int Pos) 00192 { 00193 int i, Ind=0; 00194 for(i=0; i<Pos; i++,Ind++) 00195 while(s[Ind]==' ') Ind++; 00196 while(s[Ind]==' ') Ind++; 00197 return Ind; 00198 } 00199 00200 typedef map<string, unsigned> NameMap_t; 00201 00202 // Parse variables 00203 bool ParseVars(const string& Vars, NameMap_t& dest) 00204 { 00205 unsigned varNumber = VarBegin; 00206 unsigned ind1 = 0, ind2; 00207 00208 while(ind1 < Vars.size()) 00209 { 00210 for(ind2=ind1; ind2<Vars.size() && Vars[ind2]!=','; ++ind2) 00211 if(!isalpha(Vars[ind2])) return false; 00212 if(ind2 == ind1) return false; 00213 const string varName = Vars.substr(ind1, ind2-ind1); 00214 00215 NameMap_t::const_iterator iter = dest.find(varName); 00216 if(iter != dest.end()) return false; 00217 dest[varName] = varNumber++; 00218 00219 ind1 = ind2+1; 00220 } 00221 return true; 00222 } 00223 }; 00224 00225 // Main parsing function 00226 int FunctionParser::Parse(const std::string& Function, 00227 const std::string& Vars) 00228 { 00229 srand((unsigned int)time(NULL)); //needs to be the same seed everytime a function is parsed 00230 //so it remains the same random values for each evaluation 00231 00232 if(!ParseVars(Vars, Variables)) 00233 { 00234 ParseErrorType = 7; 00235 return Function.size(); 00236 } 00237 varAmount = Variables.size(); // this is for Eval() 00238 00239 string tmp; 00240 tmp.reserve(Function.size()); 00241 for(unsigned i=0; i<Function.size(); ++i) 00242 if(!isspace(Function[i])) tmp += Function[i]; 00243 const char* Func = tmp.c_str(); 00244 00245 ParseErrorType = -1; 00246 00247 int Result = CheckSyntax(Func); 00248 if(Result>=0) 00249 { 00250 return RealIndexPos(Function, Result); 00251 } 00252 00253 if(!Compile(Func)) return Function.size(); 00254 00255 Variables.clear(); 00256 00257 ParseErrorType = -1; 00258 return -1; 00259 } 00260 00261 namespace 00262 { 00263 // Is given char an operator? 00264 inline bool IsOperator(int c) 00265 { 00266 return strchr("+-*/%^=<>&|,",c)!=0; 00267 } 00268 }; 00269 00270 inline FunctionParser::VarMap_t::const_iterator 00271 FunctionParser::FindVariable(const char* F) 00272 { 00273 return FindInMap(Variables, F); 00274 } 00275 00276 //--------------------------------------------------------------------------- 00277 // Check function string syntax 00278 // ---------------------------- 00279 int FunctionParser::CheckSyntax(const char* Function) 00280 { 00281 int Ind=0,ParenthCnt=0,c; 00282 char* Ptr; 00283 00284 while(true) 00285 { 00286 c=Function[Ind]; 00287 00288 // Check for valid operand (must appear) 00289 00290 // Check for leading - 00291 if(c=='-') c=Function[++Ind]; 00292 if(c==0) { ParseErrorType=0; return Ind; } 00293 00294 // Check for math function 00295 FuncMap_t::const_iterator fIter = FindFunction(&Function[Ind]); 00296 if(fIter != Functions.end()) 00297 { 00298 Ind += fIter->first.size(); 00299 c = Function[Ind]; 00300 if(c!='(') { ParseErrorType=0; return Ind; } 00301 } 00302 00303 // Check for opening parenthesis 00304 if(c=='(') { ParenthCnt++; Ind++; continue; } 00305 00306 // Check for number 00307 if(isdigit(c) || (c=='.' && isdigit(Function[Ind+1]))) 00308 { 00309 strtod(&Function[Ind], &Ptr); 00310 Ind += int(Ptr-&Function[Ind]); 00311 c = Function[Ind]; 00312 } 00313 else 00314 { // Check for variable 00315 VarMap_t::const_iterator vIter = FindVariable(&Function[Ind]); 00316 if(vIter == Variables.end()) { ParseErrorType=0; return Ind; } 00317 Ind += vIter->first.size(); 00318 c = Function[Ind]; 00319 } 00320 00321 // Check for closing parenthesis 00322 while(c==')') 00323 { 00324 ParenthCnt--; 00325 if(ParenthCnt<0) { ParseErrorType=1; return Ind; } 00326 if(Function[Ind-1]=='(') { ParseErrorType=3; return Ind; } 00327 c=Function[++Ind]; 00328 } 00329 00330 // If we get here, we have a legal operand and now a legal operator or 00331 // end of string must follow 00332 00333 // Check for EOS 00334 if(c==0) break; // The only way to end the checking loop without error 00335 // Check for operator 00336 if(!IsOperator(c)) { ParseErrorType=4; return Ind; } 00337 00338 // If we get here, we have an operand and an operator; the next loop will 00339 // check for another operand (must appear) 00340 ++Ind; 00341 } // while 00342 00343 // Check that all opened parentheses are also closed 00344 if(ParenthCnt>0) { ParseErrorType=2; return Ind; } 00345 00346 // The string is ok 00347 ParseErrorType=-1; 00348 return -1; 00349 } 00350 00351 // Compile function string to bytecode 00352 // ----------------------------------- 00353 bool FunctionParser::Compile(const char* Function) 00354 { 00355 if(Comp.ByteCode) { delete[] Comp.ByteCode; Comp.ByteCode=0; } 00356 if(Comp.Immed) { delete[] Comp.Immed; Comp.Immed=0; } 00357 if(Comp.Stack) { delete[] Comp.Stack; Comp.Stack=0; } 00358 00359 // Compile to nowhere to get the size of the bytecode 00360 Comp.ByteCodeSize=Comp.ImmedSize=Comp.StackSize=Comp.StackPtr=0; 00361 CompileExpression(Function, 0); 00362 if(ParseErrorType >= 0) return false; 00363 00364 try 00365 { 00366 if(Comp.ByteCodeSize) 00367 Comp.ByteCode = new unsigned[Comp.ByteCodeSize]; 00368 if(Comp.ImmedSize) 00369 Comp.Immed = new double[Comp.ImmedSize]; 00370 if(Comp.StackSize) 00371 Comp.Stack = new double[Comp.StackSize]; 00372 } 00373 catch(std::bad_alloc) 00374 { 00375 ParseErrorType=5; return false; 00376 // Already allocated memory blocks are freed in the destructor or when 00377 // Parse() is called again, so no need to free them here 00378 } 00379 00380 // Compile 00381 Comp.ByteCodeSize=Comp.ImmedSize=Comp.StackSize=Comp.StackPtr=0; 00382 CompileExpression(Function, 0); 00383 00384 return ParseErrorType < 0; 00385 } 00386 00387 inline void FunctionParser::AddCompiledByte(unsigned c) 00388 { 00389 if(Comp.ByteCode) 00390 Comp.ByteCode[Comp.ByteCodeSize] = c; 00391 ++Comp.ByteCodeSize; 00392 } 00393 00394 // Compile if() 00395 int FunctionParser::CompileIf(const char* F, int ind) 00396 { 00397 int ind2 = CompileExpression(F, ind, true); // condition 00398 if(F[ind2] != ',') { ParseErrorType=8; return ind2; } 00399 AddCompiledByte(cIf); 00400 unsigned curByteCodeSize = Comp.ByteCodeSize; 00401 AddCompiledByte(0); // Jump index; to be set later 00402 AddCompiledByte(0); // Immed jump index; to be set later 00403 00404 --Comp.StackPtr; 00405 00406 ind2 = CompileExpression(F, ind2+1, true); // then 00407 if(F[ind2] != ',') { ParseErrorType=8; return ind2; } 00408 AddCompiledByte(cJump); 00409 unsigned curByteCodeSize2 = Comp.ByteCodeSize; 00410 unsigned curImmedSize2 = Comp.ImmedSize; 00411 AddCompiledByte(0); // Jump index; to be set later 00412 AddCompiledByte(0); // Immed jump index; to be set later 00413 00414 --Comp.StackPtr; 00415 00416 ind2 = CompileExpression(F, ind2+1, true); // else 00417 if(F[ind2] != ')') { ParseErrorType=8; return ind2; } 00418 00419 if(Comp.ByteCode) // Set jump indices 00420 { 00421 Comp.ByteCode[curByteCodeSize] = curByteCodeSize2+1; 00422 Comp.ByteCode[curByteCodeSize+1] = curImmedSize2; 00423 Comp.ByteCode[curByteCodeSize2] = Comp.ByteCodeSize-1; 00424 Comp.ByteCode[curByteCodeSize2+1] = Comp.ImmedSize; 00425 } 00426 00427 return ind2+1; 00428 } 00429 00430 // Compiles element 00431 int FunctionParser::CompileElement(const char* F, int ind) 00432 { 00433 char c = F[ind]; 00434 00435 if(c == '(') 00436 { 00437 return CompileExpression(F, ind+1) + 1; 00438 } 00439 else if(c == '-') 00440 { 00441 int ind2 = CompileElement(F, ind+1); 00442 AddCompiledByte(cNeg); 00443 return ind2; 00444 } 00445 00446 if(isdigit(c) || c=='.') // Number 00447 { 00448 const char* startPtr = &F[ind]; 00449 char* endPtr; 00450 double val = strtod(startPtr, &endPtr); 00451 if(Comp.Immed) 00452 Comp.Immed[Comp.ImmedSize] = val; 00453 ++Comp.ImmedSize; 00454 AddCompiledByte(cImmed); 00455 ++Comp.StackPtr; if(Comp.StackPtr>Comp.StackSize) Comp.StackSize++; 00456 return ind+(endPtr-startPtr); 00457 } 00458 00459 if(isalpha(c)) // Function or variable 00460 { 00461 int ind2 = ind+1; 00462 while(isalpha(F[ind2])) ++ind2; 00463 string name(F+ind, ind2-ind); 00464 00465 FuncMap_t::const_iterator fIter = Functions.find(name); 00466 if(fIter != Functions.end()) // is function 00467 { 00468 if(fIter->first == "if") // "if" is a special case 00469 { 00470 return CompileIf(F, ind2+1); 00471 } 00472 00473 unsigned curStackPtr = Comp.StackPtr; 00474 ind2 = CompileExpression(F, ind2+1); 00475 00476 #ifndef DISABLE_EVAL 00477 unsigned requiredParams = 00478 fIter->first=="eval" ? Variables.size() : fIter->second.params; 00479 #else 00480 unsigned requiredParams = fIter->second.params; 00481 #endif 00482 if(Comp.StackPtr != curStackPtr+requiredParams) 00483 { ParseErrorType=8; return ind; } 00484 00485 AddCompiledByte(fIter->second.opcode); 00486 Comp.StackPtr -= fIter->second.params - 1; 00487 return ind2+1; 00488 } 00489 00490 VarMap_t::const_iterator vIter = Variables.find(name); 00491 if(vIter != Variables.end()) // is variable 00492 { 00493 AddCompiledByte(vIter->second); 00494 ++Comp.StackPtr; if(Comp.StackPtr>Comp.StackSize) Comp.StackSize++; 00495 return ind + vIter->first.size(); 00496 } 00497 } 00498 00499 ParseErrorType = 6; 00500 return ind; 00501 } 00502 00503 // Compiles '^' 00504 int FunctionParser::CompilePow(const char* F, int ind) 00505 { 00506 int ind2 = CompileElement(F, ind); 00507 00508 while(F[ind2] == '^') 00509 { 00510 ind2 = CompileElement(F, ind2+1); 00511 AddCompiledByte(cPow); 00512 --Comp.StackPtr; 00513 } 00514 00515 return ind2; 00516 } 00517 00518 // Compiles '*', '/' and '%' 00519 int FunctionParser::CompileMult(const char* F, int ind) 00520 { 00521 int ind2 = CompilePow(F, ind); 00522 char op; 00523 00524 while((op = F[ind2]) == '*' || op == '/' || op == '%') 00525 { 00526 ind2 = CompilePow(F, ind2+1); 00527 switch(op) 00528 { 00529 case '*': AddCompiledByte(cMul); break; 00530 case '/': AddCompiledByte(cDiv); break; 00531 case '%': AddCompiledByte(cMod); break; 00532 } 00533 --Comp.StackPtr; 00534 } 00535 00536 return ind2; 00537 } 00538 00539 // Compiles '+' and '-' 00540 int FunctionParser::CompileAddition(const char* F, int ind) 00541 { 00542 int ind2 = CompileMult(F, ind); 00543 char op; 00544 00545 while((op = F[ind2]) == '+' || op == '-') 00546 { 00547 ind2 = CompileMult(F, ind2+1); 00548 AddCompiledByte(op=='+' ? cAdd : cSub); 00549 --Comp.StackPtr; 00550 } 00551 00552 return ind2; 00553 } 00554 00555 // Compiles '=', '<' and '>' 00556 int FunctionParser::CompileComparison(const char* F, int ind) 00557 { 00558 int ind2 = CompileAddition(F, ind); 00559 char op; 00560 00561 while((op = F[ind2]) == '=' || op == '<' || op == '>') 00562 { 00563 ind2 = CompileAddition(F, ind2+1); 00564 switch(op) 00565 { 00566 case '=': AddCompiledByte(cEqual); break; 00567 case '<': AddCompiledByte(cLess); break; 00568 case '>': AddCompiledByte(cGreater); break; 00569 } 00570 --Comp.StackPtr; 00571 } 00572 00573 return ind2; 00574 } 00575 00576 // Compiles '&' 00577 int FunctionParser::CompileAnd(const char* F, int ind) 00578 { 00579 int ind2 = CompileComparison(F, ind); 00580 00581 while(F[ind2] == '&') 00582 { 00583 ind2 = CompileComparison(F, ind2+1); 00584 AddCompiledByte(cAnd); 00585 --Comp.StackPtr; 00586 } 00587 00588 return ind2; 00589 } 00590 00591 // Compiles '|' 00592 int FunctionParser::CompileOr(const char* F, int ind) 00593 { 00594 int ind2 = CompileAnd(F, ind); 00595 00596 while(F[ind2] == '|') 00597 { 00598 ind2 = CompileAnd(F, ind2+1); 00599 AddCompiledByte(cOr); 00600 --Comp.StackPtr; 00601 } 00602 00603 return ind2; 00604 } 00605 00606 // Compiles ',' 00607 int FunctionParser::CompileExpression(const char* F, int ind, bool stopAtComma) 00608 { 00609 int ind2 = CompileOr(F, ind); 00610 00611 if(stopAtComma) return ind2; 00612 00613 while(F[ind2] == ',') 00614 { 00615 ind2 = CompileOr(F, ind2+1); 00616 } 00617 00618 return ind2; 00619 } 00620 00621 00622 // Return parse error message 00623 // -------------------------- 00624 const char* FunctionParser::ErrorMsg(void) const 00625 { 00626 if(ParseErrorType>=0) return ParseErrorMessage[ParseErrorType]; 00627 return 0; 00628 } 00629 00630 //--------------------------------------------------------------------------- 00631 // Function evaluation 00632 //--------------------------------------------------------------------------- 00633 //=========================================================================== 00634 namespace 00635 { 00636 inline int DoubleToInt(double d) 00637 { 00638 return d<0 ? -int((-d)+.5) : int(d+.5); 00639 } 00640 00641 inline double Min(double d1, double d2) 00642 { 00643 return d1<d2 ? d1 : d2; 00644 } 00645 inline double Max(double d1, double d2) 00646 { 00647 return d1>d2 ? d1 : d2; 00648 } 00649 } 00650 00651 double FunctionParser::Eval(const double* Vars) 00652 { 00653 unsigned IP, DP=0; 00654 int SP=-1; 00655 for(IP=0; IP<Comp.ByteCodeSize; IP++) 00656 { 00657 switch(Comp.ByteCode[IP]) 00658 { 00659 case cImmed: Comp.Stack[++SP]=Comp.Immed[DP++]; break; 00660 00661 case cJump: DP = Comp.ByteCode[IP+2]; 00662 IP = Comp.ByteCode[IP+1]; 00663 break; 00664 00665 case cNeg: Comp.Stack[SP]=-Comp.Stack[SP]; break; 00666 case cAdd: Comp.Stack[SP-1]+=Comp.Stack[SP]; SP--; break; 00667 case cSub: Comp.Stack[SP-1]-=Comp.Stack[SP]; SP--; break; 00668 case cMul: Comp.Stack[SP-1]*=Comp.Stack[SP]; SP--; break; 00669 case cDiv: if(Comp.Stack[SP]==0) { EvalErrorType=1; return 0; } 00670 Comp.Stack[SP-1]/=Comp.Stack[SP]; SP--; break; 00671 case cMod: if(Comp.Stack[SP]==0) { EvalErrorType=1; return 0; } 00672 Comp.Stack[SP-1]=fmod(Comp.Stack[SP-1],Comp.Stack[SP]); 00673 SP--; break; 00674 case cPow: Comp.Stack[SP-1]=pow(Comp.Stack[SP-1],Comp.Stack[SP]); 00675 SP--; break; 00676 case cEqual: Comp.Stack[SP-1] = (Comp.Stack[SP-1]==Comp.Stack[SP]); 00677 SP--; break; 00678 case cLess: Comp.Stack[SP-1] = (Comp.Stack[SP-1]<Comp.Stack[SP]); 00679 SP--; break; 00680 case cGreater: Comp.Stack[SP-1] = (Comp.Stack[SP-1]>Comp.Stack[SP]); 00681 SP--; break; 00682 case cAnd: Comp.Stack[SP-1] = 00683 (DoubleToInt(Comp.Stack[SP-1]) && 00684 DoubleToInt(Comp.Stack[SP])); 00685 SP--; break; 00686 case cOr: Comp.Stack[SP-1] = 00687 (DoubleToInt(Comp.Stack[SP-1]) || 00688 DoubleToInt(Comp.Stack[SP])); 00689 SP--; break; 00690 case cAbs: Comp.Stack[SP]=fabs(Comp.Stack[SP]); break; 00691 case cExp: Comp.Stack[SP]=exp(Comp.Stack[SP]); break; 00692 case cCeil: Comp.Stack[SP]=ceil(Comp.Stack[SP]); break; 00693 case cFloor: Comp.Stack[SP]=floor(Comp.Stack[SP]); break; 00694 case cLn: if(Comp.Stack[SP]<=0) { EvalErrorType=3; return 0; } 00695 Comp.Stack[SP]=log(Comp.Stack[SP]); break; 00696 case cLog: if(Comp.Stack[SP-1]<=0 || Comp.Stack[SP]<=0) { EvalErrorType=3; return 0; } 00697 Comp.Stack[SP-1]=log(Comp.Stack[SP-1])/log(Comp.Stack[SP]); SP--; break; 00698 case cSqrt: if(Comp.Stack[SP]<0) { EvalErrorType=2; return 0; } 00699 Comp.Stack[SP]=sqrt(Comp.Stack[SP]); break; 00700 case cInt: Comp.Stack[SP]=DoubleToInt(Comp.Stack[SP]); break; 00701 /* Begin edited by Fungmeista -- added angle mode, sec, cot, csc, and log(x,base) */ 00702 case cSinh: Comp.Stack[SP]= (mode == RADIANS) ? sinh(Comp.Stack[SP]) : sinh(Comp.Stack[SP]*(PI/180.0)); break; 00703 case cCosh: Comp.Stack[SP]= (mode == RADIANS) ? cosh(Comp.Stack[SP]) : cosh(Comp.Stack[SP]*(PI/180.0)); break; 00704 case cTanh: Comp.Stack[SP]= (mode == RADIANS) ? tanh(Comp.Stack[SP]) : tanh(Comp.Stack[SP]*(PI/180.0)); break; 00705 case cSin: Comp.Stack[SP]= (mode == RADIANS) ? sin(Comp.Stack[SP]) : sin(Comp.Stack[SP]*(PI/180.0)); break; 00706 case cCos: Comp.Stack[SP]= (mode == RADIANS) ? cos(Comp.Stack[SP]) : cos(Comp.Stack[SP]*(PI/180.0)); break; 00707 case cTan: Comp.Stack[SP]= (mode == RADIANS) ? tan(Comp.Stack[SP]) : tan(Comp.Stack[SP]*(PI/180.0)); break; 00708 #ifndef NO_ASINH 00709 case cAsinh: Comp.Stack[SP]= (mode == RADIANS) ? asinh(Comp.Stack[SP]) : asinh(Comp.Stack[SP])*(PI/180.0); break; 00710 case cAcosh: Comp.Stack[SP]= (mode == RADIANS) ? acosh(Comp.Stack[SP]) : acosh(Comp.Stack[SP])*(PI/180.0); break; 00711 case cAtanh: Comp.Stack[SP]= (mode == RADIANS) ? atanh(Comp.Stack[SP]) : atanh(Comp.Stack[SP])*(PI/180.0); break; 00712 #endif 00713 case cAsin: if(Comp.Stack[SP]<-1 || Comp.Stack[SP]>1) 00714 { EvalErrorType=4; return 0; } 00715 Comp.Stack[SP]= (mode == RADIANS) ? asin(Comp.Stack[SP]) : asin(Comp.Stack[SP])*(PI/180.0); break; 00716 case cAcos: if(Comp.Stack[SP]<-1 || Comp.Stack[SP]>1) 00717 { EvalErrorType=4; return 0; } 00718 Comp.Stack[SP]= (mode == RADIANS) ? acos(Comp.Stack[SP]) : acos(Comp.Stack[SP])*(PI/180.0); break; 00719 case cAtan: Comp.Stack[SP]= (mode == RADIANS) ? atan(Comp.Stack[SP]) : atan(Comp.Stack[SP])*(PI/180.0); break; 00720 case cCot: if(tan(Comp.Stack[SP]) == 0 || tan(Comp.Stack[SP]*(PI/180.0)) == 0){EvalErrorType=3; return 0;} 00721 Comp.Stack[SP]= (mode == RADIANS) ? (1/tan(Comp.Stack[SP])) : (1/tan(Comp.Stack[SP]*(PI/180.0))); break; 00722 case cCsc: if(sin(Comp.Stack[SP]) == 0 || sin(Comp.Stack[SP]*(PI/180.0)) == 0){EvalErrorType=3; return 0;} 00723 Comp.Stack[SP]= (mode == RADIANS) ? (1/sin(Comp.Stack[SP])) : (1/sin(Comp.Stack[SP]*(PI/180.0))); break; 00724 case cSec: if(cos(Comp.Stack[SP]) == 0 || cos(Comp.Stack[SP]*(PI/180.0)) == 0){EvalErrorType=3; return 0;} 00725 Comp.Stack[SP]= (mode == RADIANS) ? (1/cos(Comp.Stack[SP])) : (1/cos(Comp.Stack[SP]*(PI/180.0))); break; 00726 case cFib: if(Comp.Stack[SP] < 0) {EvalErrorType=4; return 0;} 00727 Comp.Stack[SP]= fibonacci(DoubleToInt(Comp.Stack[SP])); break; 00728 case cFrand: Comp.Stack[SP-1] = fRand(Comp.Stack[SP-1],Comp.Stack[SP]); SP--; break; 00729 case cIrand: Comp.Stack[SP-1] = iRand(Comp.Stack[SP-1],Comp.Stack[SP]); SP--; break; 00730 case cFact: if(Comp.Stack[SP] < 0) {EvalErrorType=4; return 0;} 00731 Comp.Stack[SP]= factorial(DoubleToInt(Comp.Stack[SP])); break; 00732 00733 /* End edited by Fungmeista */ 00734 case cMin: Comp.Stack[SP-1]=Min(Comp.Stack[SP-1],Comp.Stack[SP]); 00735 SP--; break; 00736 case cMax: Comp.Stack[SP-1]=Max(Comp.Stack[SP-1],Comp.Stack[SP]); 00737 SP--; break; 00738 case cIf: 00739 { 00740 unsigned jumpAddr = Comp.ByteCode[++IP]; 00741 unsigned immedAddr = Comp.ByteCode[++IP]; 00742 if(DoubleToInt(Comp.Stack[SP]) == 0) 00743 { 00744 IP = jumpAddr; 00745 DP = immedAddr; 00746 } 00747 SP--; break; 00748 } 00749 00750 #ifndef DISABLE_EVAL 00751 case cEval: 00752 { 00753 FunctionParser fpcopy(*this); 00754 double retVal = fpcopy.Eval(&Comp.Stack[SP-varAmount+1]); 00755 SP -= varAmount-1; 00756 Comp.Stack[SP] = retVal; 00757 break; 00758 } 00759 #endif 00760 00761 default: 00762 Comp.Stack[++SP]=Vars[Comp.ByteCode[IP]-VarBegin]; 00763 } 00764 } 00765 00766 EvalErrorType=0; 00767 return Comp.Stack[SP]; 00768 } Generated on Mon Jun 2 22:43:22 2003 for Fung-Calc by 1.2.17 |