00001
00002
00003
00004
00005
00006
00007
00008 #define NO_ASINH
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "fparser.hh"
00027
00028 #include <cstdlib>
00029 #include <cstring>
00030 #include <cctype>
00031 #include <cmath>
00032 #include <new>
00033 #include <algorithm>
00034
00035 using namespace std;
00036
00037 #ifndef M_PI
00038 #define M_PI 3.1415926535897932384626433832795
00039 #endif
00040
00041 namespace
00042 {
00043
00044 enum OPCODE
00045 {
00046 cAbs, cAcos,
00047 #ifndef NO_ASINH
00048 cAcosh,
00049 #endif
00050 cAsin,
00051 #ifndef NO_ASINH
00052 cAsinh,
00053 #endif
00054 cAtan,
00055 cAtan2,
00056 #ifndef NO_ASINH
00057 cAtanh,
00058 #endif
00059 cCeil, cCos, cCosh, cCot, cCsc,
00060 #ifndef DISABLE_EVAL
00061 cEval,
00062 #endif
00063 cExp, cFloor, cIf, cInt, cLog, cLog10, cMax, cMin,
00064 cSec, cSin, cSinh, cSqrt, cTan, cTanh,
00065
00066
00067 cImmed, cJump,
00068 cNeg, cAdd, cSub, cMul, cDiv, cMod, cPow,
00069 cEqual, cLess, cGreater, cAnd, cOr,
00070
00071 cDeg, cRad,
00072
00073 cFCall, cPCall,
00074
00075 #ifdef SUPPORT_OPTIMIZER
00076 cVar, cDup, cInv,
00077 #endif
00078
00079 VarBegin
00080 };
00081
00082 struct FuncDefinition
00083 {
00084 const char* name;
00085 unsigned nameLength;
00086 unsigned opcode;
00087 unsigned params;
00088
00089
00090
00091 bool operator<(const FuncDefinition& rhs) const
00092 {
00093 for(unsigned i = 0; i < nameLength; ++i)
00094 {
00095 if(i == rhs.nameLength) return false;
00096 const char c1 = name[i], c2 = rhs.name[i];
00097 if(c1 < c2) return true;
00098 if(c2 < c1) return false;
00099 }
00100 return nameLength < rhs.nameLength;
00101 }
00102 };
00103
00104
00105
00106 const FuncDefinition Functions[]=
00107 {
00108 { "abs", 3, cAbs, 1 },
00109 { "acos", 4, cAcos, 1 },
00110 #ifndef NO_ASINH
00111 { "acosh", 5, cAcosh, 1 },
00112 #endif
00113 { "asin", 4, cAsin, 1 },
00114 #ifndef NO_ASINH
00115 { "asinh", 5, cAsinh, 1 },
00116 #endif
00117 { "atan", 4, cAtan, 1 },
00118 { "atan2", 5, cAtan2, 2 },
00119 #ifndef NO_ASINH
00120 { "atanh", 5, cAtanh, 1 },
00121 #endif
00122 { "ceil", 4, cCeil, 1 },
00123 { "cos", 3, cCos, 1 },
00124 { "cosh", 4, cCosh, 1 },
00125 { "cot", 3, cCot, 1 },
00126 { "csc", 3, cCsc, 1 },
00127 #ifndef DISABLE_EVAL
00128 { "eval", 4, cEval, 0 },
00129 #endif
00130 { "exp", 3, cExp, 1 },
00131 { "floor", 5, cFloor, 1 },
00132 { "if", 2, cIf, 0 },
00133 { "int", 3, cInt, 1 },
00134 { "log", 3, cLog, 1 },
00135 { "log10", 5, cLog10, 1 },
00136 { "max", 3, cMax, 2 },
00137 { "min", 3, cMin, 2 },
00138 { "sec", 3, cSec, 1 },
00139 { "sin", 3, cSin, 1 },
00140 { "sinh", 4, cSinh, 1 },
00141 { "sqrt", 4, cSqrt, 1 },
00142 { "tan", 3, cTan, 1 },
00143 { "tanh", 4, cTanh, 1 }
00144 };
00145
00146 const unsigned FUNC_AMOUNT = sizeof(Functions)/sizeof(Functions[0]);
00147
00148
00149
00150
00151
00152 inline const FuncDefinition* FindFunction(const char* F)
00153 {
00154 FuncDefinition func = { F, 0, 0, 0 };
00155 while(isalnum(F[func.nameLength])) ++func.nameLength;
00156 if(func.nameLength)
00157 {
00158 const FuncDefinition* found =
00159 lower_bound(Functions, Functions+FUNC_AMOUNT, func);
00160 if(found == Functions+FUNC_AMOUNT || func < *found)
00161 return 0;
00162 return found;
00163 }
00164 return 0;
00165 }
00166 };
00167
00168
00169
00170
00171
00172 FunctionParser::FunctionParser():
00173 ParseErrorType(-1), EvalErrorType(0)
00174 {}
00175
00176 FunctionParser::~FunctionParser()
00177 {}
00178
00179 FunctionParser::CompiledCode::CompiledCode():
00180 ByteCode(0), ByteCodeSize(0),
00181 Immed(0), ImmedSize(0),
00182 Stack(0), StackSize(0)
00183 {}
00184
00185 FunctionParser::CompiledCode::~CompiledCode()
00186 {
00187 if(ByteCode) { delete[] ByteCode; ByteCode=0; }
00188 if(Immed) { delete[] Immed; Immed=0; }
00189 if(Stack) { delete[] Stack; Stack=0; }
00190 }
00191
00192
00193
00194
00195
00196
00197 namespace
00198 {
00199
00200 const char* ParseErrorMessage[]=
00201 {
00202 "Syntax error",
00203 "Mismatched parenthesis",
00204 "Missing ')'",
00205 "Empty parentheses",
00206 "Syntax error: Operator expected",
00207 "Not enough memory",
00208 "An unexpected error ocurred. Please make a full bug report "
00209 "to warp@iki.fi",
00210 "Syntax error in parameter 'Vars' given to "
00211 "FunctionParser::Parse()",
00212 "Illegal number of parameters to function",
00213 "Syntax error: Premature end of string",
00214 "Syntax error: Expecting ( after function",
00215 ""
00216 };
00217
00218
00219
00220 bool ParseVars(const string& Vars, map<string, unsigned>& dest)
00221 {
00222 unsigned varNumber = VarBegin;
00223 unsigned ind1 = 0, ind2;
00224
00225 while(ind1 < Vars.size())
00226 {
00227 if(!isalpha(Vars[ind1]) && Vars[ind1]!='_') return false;
00228 for(ind2=ind1+1; ind2<Vars.size() && Vars[ind2]!=','; ++ind2)
00229 if(!isalnum(Vars[ind2]) && Vars[ind2]!='_') return false;
00230 const string varName = Vars.substr(ind1, ind2-ind1);
00231
00232 if(dest.insert(make_pair(varName, varNumber++)).second == false)
00233 return false;
00234
00235 ind1 = ind2+1;
00236 }
00237 return true;
00238 }
00239 };
00240
00241 bool FunctionParser::isValidName(const std::string& name)
00242 {
00243 if(name.empty() || (!isalpha(name[0]) && name[0] != '_')) return false;
00244 for(unsigned i=0; i<name.size(); ++i)
00245 if(!isalnum(name[i]) && name[i] != '_') return false;
00246
00247 if(FindFunction(name.c_str())) return false;
00248
00249 return true;
00250 }
00251
00252
00253
00254 bool FunctionParser::AddConstant(const string& name, double value)
00255 {
00256 if(isValidName(name))
00257 {
00258 const char* n = name.c_str();
00259 if(FindVariable(n, FuncParserNames) != FuncParserNames.end() ||
00260 FindVariable(n, FuncPtrNames) != FuncPtrNames.end())
00261 return false;
00262
00263 Constants[name] = value;
00264 return true;
00265 }
00266 return false;
00267 }
00268
00269
00270 bool FunctionParser::AddFunction(const std::string& name,
00271 FunctionPtr func, unsigned paramsAmount)
00272 {
00273 if(paramsAmount == 0) return false;
00274
00275 if(isValidName(name))
00276 {
00277 const char* n = name.c_str();
00278 if(FindVariable(n, FuncParserNames) != FuncParserNames.end() ||
00279 FindConstant(n) != Constants.end())
00280 return false;
00281
00282 FuncPtrNames[name] = FuncPtrs.size();
00283 FuncPtrs.push_back(FuncPtrData(func, paramsAmount));
00284 return true;
00285 }
00286 return false;
00287 }
00288
00289 bool FunctionParser::checkRecursiveLinking(const FunctionParser* fp)
00290 {
00291 if(fp == this) return true;
00292 for(unsigned i=0; i<fp->FuncParsers.size(); ++i)
00293 if(checkRecursiveLinking(fp->FuncParsers[i])) return true;
00294 return false;
00295 }
00296
00297 bool FunctionParser::AddFunction(const std::string& name,
00298 FunctionParser& parser)
00299 {
00300 if(parser.varAmount == 0) return false;
00301
00302 if(isValidName(name))
00303 {
00304 const char* n = name.c_str();
00305 if(FindVariable(n, FuncPtrNames) != FuncPtrNames.end() ||
00306 FindConstant(n) != Constants.end())
00307 return false;
00308
00309 if(checkRecursiveLinking(&parser)) return false;
00310
00311 FuncParserNames[name] = FuncParsers.size();
00312 FuncParsers.push_back(&parser);
00313 return true;
00314 }
00315 return false;
00316 }
00317
00318
00319
00320
00321
00322 int FunctionParser::Parse(const std::string& Function,
00323 const std::string& Vars,
00324 bool useDegrees)
00325 {
00326 Variables.clear();
00327
00328 if(!ParseVars(Vars, Variables))
00329 {
00330 ParseErrorType = 7;
00331 return Function.size();
00332 }
00333 varAmount = Variables.size();
00334
00335 const char* Func = Function.c_str();
00336
00337 ParseErrorType = -1;
00338
00339 int Result = CheckSyntax(Func);
00340 if(Result>=0) return Result;
00341
00342 useDegreeConversion = useDegrees;
00343 if(!Compile(Func)) return Function.size();
00344
00345 Variables.clear();
00346
00347 ParseErrorType = -1;
00348 return -1;
00349 }
00350
00351 namespace
00352 {
00353
00354 inline bool IsOperator(int c)
00355 {
00356 return strchr("+-*/%^=<>&|,",c)!=NULL;
00357 }
00358
00359
00360 inline void sws(const char* F, int& Ind)
00361 {
00362 while(F[Ind] && F[Ind] == ' ') ++Ind;
00363 }
00364 };
00365
00366
00367
00368 inline FunctionParser::VarMap_t::const_iterator
00369 FunctionParser::FindVariable(const char* F, const VarMap_t& vars)
00370 {
00371 if(vars.size())
00372 {
00373 unsigned ind = 0;
00374 while(isalnum(F[ind]) || F[ind] == '_') ++ind;
00375 if(ind)
00376 {
00377 string name(F, ind);
00378 return vars.find(name);
00379 }
00380 }
00381 return vars.end();
00382 }
00383
00384 inline FunctionParser::ConstMap_t::const_iterator
00385 FunctionParser::FindConstant(const char* F)
00386 {
00387 if(Constants.size())
00388 {
00389 unsigned ind = 0;
00390 while(isalnum(F[ind]) || F[ind] == '_') ++ind;
00391 if(ind)
00392 {
00393 string name(F, ind);
00394 return Constants.find(name);
00395 }
00396 }
00397 return Constants.end();
00398 }
00399
00400
00401
00402
00403 int FunctionParser::CheckSyntax(const char* Function)
00404 {
00405 int Ind=0, ParenthCnt=0, c;
00406 char* Ptr;
00407
00408 while(true)
00409 {
00410 sws(Function, Ind);
00411 c=Function[Ind];
00412
00413
00414
00415
00416 if(c=='-') { sws(Function, ++Ind); c=Function[Ind]; }
00417 if(c==0) { ParseErrorType=9; return Ind; }
00418
00419
00420 bool foundFunc = false;
00421 const FuncDefinition* fptr = FindFunction(&Function[Ind]);
00422 if(fptr)
00423 {
00424 Ind += fptr->nameLength;
00425 foundFunc = true;
00426 }
00427 else
00428 {
00429
00430 VarMap_t::const_iterator fIter =
00431 FindVariable(&Function[Ind], FuncPtrNames);
00432 if(fIter != FuncPtrNames.end())
00433 {
00434 Ind += fIter->first.size();
00435 foundFunc = true;
00436 }
00437 else
00438 {
00439 VarMap_t::const_iterator pIter =
00440 FindVariable(&Function[Ind], FuncParserNames);
00441 if(pIter != FuncParserNames.end())
00442 {
00443 Ind += pIter->first.size();
00444 foundFunc = true;
00445 }
00446 }
00447 }
00448
00449 if(foundFunc)
00450 {
00451 sws(Function, Ind);
00452 c = Function[Ind];
00453 if(c!='(') { ParseErrorType=10; return Ind; }
00454 }
00455
00456
00457 if(c=='(')
00458 {
00459 ++ParenthCnt;
00460 sws(Function, ++Ind);
00461 if(Function[Ind]==')') { ParseErrorType=3; return Ind; }
00462 continue;
00463 }
00464
00465
00466 if(isdigit(c) || (c=='.' && isdigit(Function[Ind+1])))
00467 {
00468 strtod(&Function[Ind], &Ptr);
00469 Ind += int(Ptr-&Function[Ind]);
00470 sws(Function, Ind);
00471 c = Function[Ind];
00472 }
00473 else
00474 {
00475 VarMap_t::const_iterator vIter =
00476 FindVariable(&Function[Ind], Variables);
00477 if(vIter != Variables.end())
00478 Ind += vIter->first.size();
00479 else
00480 {
00481
00482 ConstMap_t::const_iterator cIter =
00483 FindConstant(&Function[Ind]);
00484 if(cIter != Constants.end())
00485 Ind += cIter->first.size();
00486 else
00487 { ParseErrorType=0; return Ind; }
00488 }
00489 sws(Function, Ind);
00490 c = Function[Ind];
00491 }
00492
00493
00494 while(c==')')
00495 {
00496 if((--ParenthCnt)<0) { ParseErrorType=1; return Ind; }
00497 sws(Function, ++Ind);
00498 c=Function[Ind];
00499 }
00500
00501
00502
00503
00504
00505 if(c==0) break;
00506
00507 if(!IsOperator(c)) { ParseErrorType=4; return Ind; }
00508
00509
00510
00511 ++Ind;
00512 }
00513
00514
00515 if(ParenthCnt>0) { ParseErrorType=2; return Ind; }
00516
00517
00518 ParseErrorType=-1;
00519 return -1;
00520 }
00521
00522
00523
00524
00525 bool FunctionParser::Compile(const char* Function)
00526 {
00527 if(Comp.ByteCode) { delete[] Comp.ByteCode; Comp.ByteCode=0; }
00528 if(Comp.Immed) { delete[] Comp.Immed; Comp.Immed=0; }
00529 if(Comp.Stack) { delete[] Comp.Stack; Comp.Stack=0; }
00530
00531 vector<unsigned> byteCode; byteCode.reserve(1024);
00532 tempByteCode = &byteCode;
00533
00534 vector<double> immed; immed.reserve(1024);
00535 tempImmed = &immed;
00536
00537 Comp.StackSize = Comp.StackPtr = 0;
00538
00539 CompileExpression(Function, 0);
00540 if(ParseErrorType >= 0) return false;
00541
00542 Comp.ByteCodeSize = byteCode.size();
00543 Comp.ImmedSize = immed.size();
00544
00545 if(Comp.ByteCodeSize)
00546 {
00547 Comp.ByteCode = new unsigned[Comp.ByteCodeSize];
00548 memcpy(Comp.ByteCode, &byteCode[0],
00549 sizeof(unsigned)*Comp.ByteCodeSize);
00550 }
00551 if(Comp.ImmedSize)
00552 {
00553 Comp.Immed = new double[Comp.ImmedSize];
00554 memcpy(Comp.Immed, &immed[0],
00555 sizeof(double)*Comp.ImmedSize);
00556 }
00557 if(Comp.StackSize)
00558 Comp.Stack = new double[Comp.StackSize];
00559
00560 return true;
00561 }
00562
00563
00564 inline void FunctionParser::AddCompiledByte(unsigned c)
00565 {
00566 tempByteCode->push_back(c);
00567 }
00568
00569 inline void FunctionParser::AddImmediate(double i)
00570 {
00571 tempImmed->push_back(i);
00572 }
00573
00574 inline void FunctionParser::AddFunctionOpcode(unsigned opcode)
00575 {
00576 if(useDegreeConversion)
00577 switch(opcode)
00578 {
00579 case cCos:
00580 case cCosh:
00581 case cCot:
00582 case cCsc:
00583 case cSec:
00584 case cSin:
00585 case cSinh:
00586 case cTan:
00587 case cTanh:
00588 AddCompiledByte(cRad);
00589 }
00590
00591 AddCompiledByte(opcode);
00592
00593 if(useDegreeConversion)
00594 switch(opcode)
00595 {
00596 case cAcos:
00597 #ifndef NO_ASINH
00598 case cAcosh:
00599 case cAsinh:
00600 case cAtanh:
00601 #endif
00602 case cAsin:
00603 case cAtan:
00604 case cAtan2:
00605 AddCompiledByte(cDeg);
00606 }
00607 }
00608
00609
00610 int FunctionParser::CompileIf(const char* F, int ind)
00611 {
00612 int ind2 = CompileExpression(F, ind, true);
00613 sws(F, ind2);
00614 if(F[ind2] != ',') { ParseErrorType=8; return ind2; }
00615 AddCompiledByte(cIf);
00616 unsigned curByteCodeSize = tempByteCode->size();
00617 AddCompiledByte(0);
00618 AddCompiledByte(0);
00619
00620 --Comp.StackPtr;
00621
00622 ind2 = CompileExpression(F, ind2+1, true);
00623 sws(F, ind2);
00624 if(F[ind2] != ',') { ParseErrorType=8; return ind2; }
00625 AddCompiledByte(cJump);
00626 unsigned curByteCodeSize2 = tempByteCode->size();
00627 unsigned curImmedSize2 = tempImmed->size();
00628 AddCompiledByte(0);
00629 AddCompiledByte(0);
00630
00631 --Comp.StackPtr;
00632
00633 ind2 = CompileExpression(F, ind2+1, true);
00634 sws(F, ind2);
00635 if(F[ind2] != ')') { ParseErrorType=8; return ind2; }
00636
00637
00638 (*tempByteCode)[curByteCodeSize] = curByteCodeSize2+1;
00639 (*tempByteCode)[curByteCodeSize+1] = curImmedSize2;
00640 (*tempByteCode)[curByteCodeSize2] = tempByteCode->size()-1;
00641 (*tempByteCode)[curByteCodeSize2+1] = tempImmed->size();
00642
00643 return ind2+1;
00644 }
00645
00646 int FunctionParser::CompileFunctionParams(const char* F, int ind,
00647 unsigned requiredParams)
00648 {
00649 unsigned curStackPtr = Comp.StackPtr;
00650 int ind2 = CompileExpression(F, ind);
00651
00652 if(Comp.StackPtr != curStackPtr+requiredParams)
00653 { ParseErrorType=8; return ind; }
00654
00655 Comp.StackPtr -= requiredParams - 1;
00656 sws(F, ind2);
00657 return ind2+1;
00658 }
00659
00660
00661 int FunctionParser::CompileElement(const char* F, int ind)
00662 {
00663 sws(F, ind);
00664 char c = F[ind];
00665
00666 if(c == '(')
00667 {
00668 ind = CompileExpression(F, ind+1);
00669 sws(F, ind);
00670 return ind+1;
00671 }
00672 else if(c == '-')
00673 {
00674 char c2 = F[ind+1];
00675 if(!isdigit(c2) && c2!='.')
00676 {
00677 int ind2 = CompileElement(F, ind+1);
00678 AddCompiledByte(cNeg);
00679 return ind2;
00680 }
00681 }
00682
00683 if(isdigit(c) || c=='.' || c=='-')
00684 {
00685 const char* startPtr = &F[ind];
00686 char* endPtr;
00687 double val = strtod(startPtr, &endPtr);
00688 AddImmediate(val);
00689 AddCompiledByte(cImmed);
00690 ++Comp.StackPtr; if(Comp.StackPtr>Comp.StackSize) Comp.StackSize++;
00691 return ind+(endPtr-startPtr);
00692 }
00693
00694 if(isalpha(c) || c == '_')
00695 {
00696 const FuncDefinition* func = FindFunction(F+ind);
00697 if(func)
00698 {
00699 int ind2 = ind + func->nameLength;
00700 sws(F, ind2);
00701 if(strcmp(func->name, "if") == 0)
00702 {
00703 return CompileIf(F, ind2+1);
00704 }
00705
00706 #ifndef DISABLE_EVAL
00707 unsigned requiredParams =
00708 strcmp(func->name, "eval") == 0 ?
00709 Variables.size() : func->params;
00710 #else
00711 unsigned requiredParams = func->params;
00712 #endif
00713 ind2 = CompileFunctionParams(F, ind2+1, requiredParams);
00714 AddFunctionOpcode(func->opcode);
00715 return ind2;
00716 }
00717
00718 VarMap_t::const_iterator vIter = FindVariable(F+ind, Variables);
00719 if(vIter != Variables.end())
00720 {
00721 AddCompiledByte(vIter->second);
00722 ++Comp.StackPtr; if(Comp.StackPtr>Comp.StackSize) Comp.StackSize++;
00723 return ind + vIter->first.size();
00724 }
00725
00726 ConstMap_t::const_iterator cIter = FindConstant(F+ind);
00727 if(cIter != Constants.end())
00728 {
00729 AddImmediate(cIter->second);
00730 AddCompiledByte(cImmed);
00731 ++Comp.StackPtr; if(Comp.StackPtr>Comp.StackSize) Comp.StackSize++;
00732 return ind + cIter->first.size();
00733 }
00734
00735 VarMap_t::const_iterator fIter = FindVariable(F+ind, FuncPtrNames);
00736 if(fIter != FuncPtrNames.end())
00737 {
00738 unsigned index = fIter->second;
00739
00740 int ind2 = ind + fIter->first.length();
00741 sws(F, ind2);
00742
00743 ind2 = CompileFunctionParams(F, ind2+1, FuncPtrs[index].params);
00744
00745 AddCompiledByte(cFCall);
00746 AddCompiledByte(index);
00747 return ind2;
00748 }
00749
00750 VarMap_t::const_iterator pIter = FindVariable(F+ind, FuncParserNames);
00751 if(pIter != FuncParserNames.end())
00752 {
00753 unsigned index = pIter->second;
00754
00755 int ind2 = ind + pIter->first.length();
00756 sws(F, ind2);
00757
00758 ind2 = CompileFunctionParams(F, ind2+1,
00759 FuncParsers[index]->varAmount);
00760
00761 AddCompiledByte(cPCall);
00762 AddCompiledByte(index);
00763 return ind2;
00764 }
00765 }
00766
00767 ParseErrorType = 6;
00768 return ind;
00769 }
00770
00771
00772 int FunctionParser::CompilePow(const char* F, int ind)
00773 {
00774 int ind2 = CompileElement(F, ind);
00775 sws(F, ind2);
00776
00777 while(F[ind2] == '^')
00778 {
00779 ind2 = CompileElement(F, ind2+1);
00780 sws(F, ind2);
00781 AddCompiledByte(cPow);
00782 --Comp.StackPtr;
00783 }
00784
00785 return ind2;
00786 }
00787
00788
00789 int FunctionParser::CompileMult(const char* F, int ind)
00790 {
00791 int ind2 = CompilePow(F, ind);
00792 sws(F, ind2);
00793 char op;
00794
00795 while((op = F[ind2]) == '*' || op == '/' || op == '%')
00796 {
00797 ind2 = CompilePow(F, ind2+1);
00798 sws(F, ind2);
00799 switch(op)
00800 {
00801 case '*': AddCompiledByte(cMul); break;
00802 case '/': AddCompiledByte(cDiv); break;
00803 case '%': AddCompiledByte(cMod); break;
00804 }
00805 --Comp.StackPtr;
00806 }
00807
00808 return ind2;
00809 }
00810
00811
00812 int FunctionParser::CompileAddition(const char* F, int ind)
00813 {
00814 int ind2 = CompileMult(F, ind);
00815 sws(F, ind2);
00816 char op;
00817
00818 while((op = F[ind2]) == '+' || op == '-')
00819 {
00820 ind2 = CompileMult(F, ind2+1);
00821 sws(F, ind2);
00822 AddCompiledByte(op=='+' ? cAdd : cSub);
00823 --Comp.StackPtr;
00824 }
00825
00826 return ind2;
00827 }
00828
00829
00830 int FunctionParser::CompileComparison(const char* F, int ind)
00831 {
00832 int ind2 = CompileAddition(F, ind);
00833 sws(F, ind2);
00834 char op;
00835
00836 while((op = F[ind2]) == '=' || op == '<' || op == '>')
00837 {
00838 ind2 = CompileAddition(F, ind2+1);
00839 sws(F, ind2);
00840 switch(op)
00841 {
00842 case '=': AddCompiledByte(cEqual); break;
00843 case '<': AddCompiledByte(cLess); break;
00844 case '>': AddCompiledByte(cGreater); break;
00845 }
00846 --Comp.StackPtr;
00847 }
00848
00849 return ind2;
00850 }
00851
00852
00853 int FunctionParser::CompileAnd(const char* F, int ind)
00854 {
00855 int ind2 = CompileComparison(F, ind);
00856 sws(F, ind2);
00857
00858 while(F[ind2] == '&')
00859 {
00860 ind2 = CompileComparison(F, ind2+1);
00861 sws(F, ind2);
00862 AddCompiledByte(cAnd);
00863 --Comp.StackPtr;
00864 }
00865
00866 return ind2;
00867 }
00868
00869
00870 int FunctionParser::CompileOr(const char* F, int ind)
00871 {
00872 int ind2 = CompileAnd(F, ind);
00873 sws(F, ind2);
00874
00875 while(F[ind2] == '|')
00876 {
00877 ind2 = CompileAnd(F, ind2+1);
00878 sws(F, ind2);
00879 AddCompiledByte(cOr);
00880 --Comp.StackPtr;
00881 }
00882
00883 return ind2;
00884 }
00885
00886
00887 int FunctionParser::CompileExpression(const char* F, int ind, bool stopAtComma)
00888 {
00889 int ind2 = CompileOr(F, ind);
00890 sws(F, ind2);
00891
00892 if(stopAtComma) return ind2;
00893
00894 while(F[ind2] == ',')
00895 {
00896 ind2 = CompileOr(F, ind2+1);
00897 sws(F, ind2);
00898 }
00899
00900 return ind2;
00901 }
00902
00903
00904
00905
00906 const char* FunctionParser::ErrorMsg(void) const
00907 {
00908 if(ParseErrorType>=0) return ParseErrorMessage[ParseErrorType];
00909 return 0;
00910 }
00911
00912
00913
00914
00915
00916 namespace
00917 {
00918 inline int doubleToInt(double d)
00919 {
00920 return d<0 ? -int((-d)+.5) : int(d+.5);
00921 }
00922
00923 inline double Min(double d1, double d2)
00924 {
00925 return d1<d2 ? d1 : d2;
00926 }
00927 inline double Max(double d1, double d2)
00928 {
00929 return d1>d2 ? d1 : d2;
00930 }
00931
00932
00933 inline double DegreesToRadians(double degrees)
00934 {
00935 return degrees*(M_PI/180.0);
00936 }
00937 inline double RadiansToDegrees(double radians)
00938 {
00939 return radians*(180.0/M_PI);
00940 }
00941 }
00942
00943 double FunctionParser::Eval(const double* Vars)
00944 {
00945 unsigned IP, DP=0;
00946 int SP=-1;
00947
00948 for(IP=0; IP<Comp.ByteCodeSize; IP++)
00949 {
00950 switch(Comp.ByteCode[IP])
00951 {
00952
00953 case cAbs: Comp.Stack[SP]=fabs(Comp.Stack[SP]); break;
00954 case cAcos: if(Comp.Stack[SP]<-1 || Comp.Stack[SP]>1)
00955 { EvalErrorType=4; return 0; }
00956 Comp.Stack[SP]=acos(Comp.Stack[SP]); break;
00957 #ifndef NO_ASINH
00958 case cAcosh: Comp.Stack[SP]=acosh(Comp.Stack[SP]); break;
00959 #endif
00960 case cAsin: if(Comp.Stack[SP]<-1 || Comp.Stack[SP]>1)
00961 { EvalErrorType=4; return 0; }
00962 Comp.Stack[SP]=asin(Comp.Stack[SP]); break;
00963 #ifndef NO_ASINH
00964 case cAsinh: Comp.Stack[SP]=asinh(Comp.Stack[SP]); break;
00965 #endif
00966 case cAtan: Comp.Stack[SP]=atan(Comp.Stack[SP]); break;
00967 case cAtan2: Comp.Stack[SP-1]=atan2(Comp.Stack[SP-1],Comp.Stack[SP]);
00968 SP--; break;
00969 #ifndef NO_ASINH
00970 case cAtanh: Comp.Stack[SP]=atanh(Comp.Stack[SP]); break;
00971 #endif
00972 case cCeil: Comp.Stack[SP]=ceil(Comp.Stack[SP]); break;
00973 case cCos: Comp.Stack[SP]=cos(Comp.Stack[SP]); break;
00974 case cCosh: Comp.Stack[SP]=cosh(Comp.Stack[SP]); break;
00975
00976 case cCot:
00977 {
00978 double t = tan(Comp.Stack[SP]);
00979 if(t == 0) { EvalErrorType=1; return 0; }
00980 Comp.Stack[SP] = 1/t; break;
00981 }
00982 case cCsc:
00983 {
00984 double s = sin(Comp.Stack[SP]);
00985 if(s == 0) { EvalErrorType=1; return 0; }
00986 Comp.Stack[SP] = 1/s; break;
00987 }
00988
00989
00990 #ifndef DISABLE_EVAL
00991 case cEval:
00992 {
00993 double* tmpStack = Comp.Stack;
00994 Comp.Stack = new double[Comp.StackSize];
00995 double retVal = Eval(&tmpStack[SP-varAmount+1]);
00996 delete[] Comp.Stack;
00997 Comp.Stack = tmpStack;
00998 SP -= varAmount-1;
00999 Comp.Stack[SP] = retVal;
01000 break;
01001 }
01002 #endif
01003
01004 case cExp: Comp.Stack[SP]=exp(Comp.Stack[SP]); break;
01005 case cFloor: Comp.Stack[SP]=floor(Comp.Stack[SP]); break;
01006
01007 case cIf:
01008 {
01009 unsigned jumpAddr = Comp.ByteCode[++IP];
01010 unsigned immedAddr = Comp.ByteCode[++IP];
01011 if(doubleToInt(Comp.Stack[SP]) == 0)
01012 {
01013 IP = jumpAddr;
01014 DP = immedAddr;
01015 }
01016 SP--; break;
01017 }
01018
01019 case cInt: Comp.Stack[SP]=floor(Comp.Stack[SP]+.5); break;
01020 case cLog: if(Comp.Stack[SP]<=0) { EvalErrorType=3; return 0; }
01021 Comp.Stack[SP]=log(Comp.Stack[SP]); break;
01022 case cLog10: if(Comp.Stack[SP]<=0) { EvalErrorType=3; return 0; }
01023 Comp.Stack[SP]=log10(Comp.Stack[SP]); break;
01024 case cMax: Comp.Stack[SP-1]=Max(Comp.Stack[SP-1],Comp.Stack[SP]);
01025 SP--; break;
01026 case cMin: Comp.Stack[SP-1]=Min(Comp.Stack[SP-1],Comp.Stack[SP]);
01027 SP--; break;
01028 case cSec:
01029 {
01030 double c = cos(Comp.Stack[SP]);
01031 if(c == 0) { EvalErrorType=1; return 0; }
01032 Comp.Stack[SP] = 1/c; break;
01033 }
01034 case cSin: Comp.Stack[SP]=sin(Comp.Stack[SP]); break;
01035 case cSinh: Comp.Stack[SP]=sinh(Comp.Stack[SP]); break;
01036 case cSqrt: if(Comp.Stack[SP]<0) { EvalErrorType=2; return 0; }
01037 Comp.Stack[SP]=sqrt(Comp.Stack[SP]); break;
01038 case cTan: Comp.Stack[SP]=tan(Comp.Stack[SP]); break;
01039 case cTanh: Comp.Stack[SP]=tanh(Comp.Stack[SP]); break;
01040
01041
01042
01043 case cImmed: Comp.Stack[++SP]=Comp.Immed[DP++]; break;
01044 case cJump: DP = Comp.ByteCode[IP+2];
01045 IP = Comp.ByteCode[IP+1];
01046 break;
01047
01048
01049 case cNeg: Comp.Stack[SP]=-Comp.Stack[SP]; break;
01050 case cAdd: Comp.Stack[SP-1]+=Comp.Stack[SP]; SP--; break;
01051 case cSub: Comp.Stack[SP-1]-=Comp.Stack[SP]; SP--; break;
01052 case cMul: Comp.Stack[SP-1]*=Comp.Stack[SP]; SP--; break;
01053 case cDiv: if(Comp.Stack[SP]==0) { EvalErrorType=1; return 0; }
01054 Comp.Stack[SP-1]/=Comp.Stack[SP]; SP--; break;
01055 case cMod: if(Comp.Stack[SP]==0) { EvalErrorType=1; return 0; }
01056 Comp.Stack[SP-1]=fmod(Comp.Stack[SP-1],Comp.Stack[SP]);
01057 SP--; break;
01058 case cPow: Comp.Stack[SP-1]=pow(Comp.Stack[SP-1],Comp.Stack[SP]);
01059 SP--; break;
01060
01061 case cEqual: Comp.Stack[SP-1] = (Comp.Stack[SP-1]==Comp.Stack[SP]);
01062 SP--; break;
01063 case cLess: Comp.Stack[SP-1] = (Comp.Stack[SP-1]<Comp.Stack[SP]);
01064 SP--; break;
01065 case cGreater: Comp.Stack[SP-1] = (Comp.Stack[SP-1]>Comp.Stack[SP]);
01066 SP--; break;
01067 case cAnd: Comp.Stack[SP-1] =
01068 (doubleToInt(Comp.Stack[SP-1]) &&
01069 doubleToInt(Comp.Stack[SP]));
01070 SP--; break;
01071 case cOr: Comp.Stack[SP-1] =
01072 (doubleToInt(Comp.Stack[SP-1]) ||
01073 doubleToInt(Comp.Stack[SP]));
01074 SP--; break;
01075
01076
01077 case cDeg: Comp.Stack[SP]=RadiansToDegrees(Comp.Stack[SP]); break;
01078 case cRad: Comp.Stack[SP]=DegreesToRadians(Comp.Stack[SP]); break;
01079
01080
01081 case cFCall:
01082 {
01083 unsigned index = Comp.ByteCode[++IP];
01084 unsigned params = FuncPtrs[index].params;
01085 double retVal =
01086 FuncPtrs[index].ptr(&Comp.Stack[SP-params+1]);
01087 SP -= params-1;
01088 Comp.Stack[SP] = retVal;
01089 break;
01090 }
01091
01092 case cPCall:
01093 {
01094 unsigned index = Comp.ByteCode[++IP];
01095 unsigned params = FuncParsers[index]->varAmount;
01096 double retVal =
01097 FuncParsers[index]->Eval(&Comp.Stack[SP-params+1]);
01098 SP -= params-1;
01099 Comp.Stack[SP] = retVal;
01100 break;
01101 }
01102
01103
01104 #ifdef SUPPORT_OPTIMIZER
01105 case cVar: break;
01106 case cDup: Comp.Stack[SP+1]=Comp.Stack[SP]; ++SP; break;
01107 case cInv:
01108 if(Comp.Stack[SP]==0.0) { EvalErrorType=1; return 0; }
01109 Comp.Stack[SP]=1.0/Comp.Stack[SP];
01110 break;
01111 #endif
01112
01113
01114 default:
01115 Comp.Stack[++SP]=Vars[Comp.ByteCode[IP]-VarBegin];
01116 }
01117 }
01118
01119 EvalErrorType=0;
01120 return Comp.Stack[SP];
01121 }
01122
01123
01124 void FunctionParser::PrintByteCode(std::ostream& dest) const
01125 {
01126 for(unsigned IP=0, DP=0; IP<Comp.ByteCodeSize; IP++)
01127 {
01128 dest.width(8); dest.fill('0'); hex(dest);
01129 dest << IP << ": ";
01130
01131 unsigned opcode = Comp.ByteCode[IP];
01132
01133 switch(opcode)
01134 {
01135 case cIf:
01136 dest << "jz\t";
01137 dest.width(8); dest.fill('0'); hex(dest);
01138 dest << Comp.ByteCode[IP+1]+1 << endl;
01139 IP += 2;
01140 break;
01141
01142 case cJump:
01143 dest << "jump\t";
01144 dest.width(8); dest.fill('0'); hex(dest);
01145 dest << Comp.ByteCode[IP+1]+1 << endl;
01146 IP += 2;
01147 break;
01148 case cImmed:
01149 dest.precision(10);
01150 dest << "push\t" << Comp.Immed[DP++] << endl;
01151 break;
01152
01153 case cFCall:
01154 {
01155 unsigned index = Comp.ByteCode[++IP];
01156 VarMap_t::const_iterator iter = FuncPtrNames.begin();
01157 while(iter->second != index) ++iter;
01158 dest << "call\t" << iter->first << endl;
01159 break;
01160 }
01161
01162 case cPCall:
01163 {
01164 unsigned index = Comp.ByteCode[++IP];
01165 VarMap_t::const_iterator iter = FuncParserNames.begin();
01166 while(iter->second != index) ++iter;
01167 dest << "call\t" << iter->first << endl;
01168 break;
01169 }
01170
01171 default:
01172 if(opcode < VarBegin)
01173 {
01174 string n;
01175 switch(opcode)
01176 {
01177 case cNeg: n = "neg"; break;
01178 case cAdd: n = "add"; break;
01179 case cSub: n = "sub"; break;
01180 case cMul: n = "mul"; break;
01181 case cDiv: n = "div"; break;
01182 case cMod: n = "mod"; break;
01183 case cPow: n = "pow"; break;
01184 case cEqual: n = "eq"; break;
01185 case cLess: n = "lt"; break;
01186 case cGreater: n = "gt"; break;
01187 case cAnd: n = "and"; break;
01188 case cOr: n = "or"; break;
01189 case cDeg: n = "deg"; break;
01190 case cRad: n = "rad"; break;
01191
01192 #ifndef DISABLE_EVAL
01193 case cEval: n = "call\t0"; break;
01194 #endif
01195
01196 #ifdef SUPPORT_OPTIMIZER
01197 case cVar: n = "(var)"; break;
01198 case cDup: n = "dup"; break;
01199 case cInv: n = "inv"; break;
01200 #endif
01201
01202 default: n = Functions[opcode-cAbs].name;
01203 }
01204 dest << n << endl;
01205 }
01206 else
01207 {
01208 dest << "push\tVar" << opcode-VarBegin << endl;
01209 }
01210 }
01211 }
01212 }
01213
01214
01215
01216
01217
01218
01219 #ifdef SUPPORT_OPTIMIZER
01220
01221 #include <list>
01222 #include <utility>
01223
01224 #define CONSTANT_E 2.71828182845904509080 // exp(1)
01225 #define CONSTANT_PI M_PI // atan2(0,-1)
01226 #define CONSTANT_L10 2.30258509299404590109 // log(10)
01227 #define CONSTANT_L10I 0.43429448190325176116 // 1/log(10)
01228 #define CONSTANT_L10E CONSTANT_L10I // log10(e)
01229 #define CONSTANT_L10EI CONSTANT_L10 // 1/log10(e)
01230 #define CONSTANT_DR (180.0 / M_PI) // 180/pi
01231 #define CONSTANT_RD (M_PI / 180.0) // pi/180
01232
01233 class compres
01234 {
01235
01236 public:
01237 compres(bool b) : state(b) {}
01238 compres(char v) : state(v) {}
01239
01240 operator bool() const { return state != 0; }
01241
01242 bool operator! () const { return state != 1; }
01243 bool operator==(bool b) const { return state != !b; }
01244 bool operator!=(bool b) const { return state != b; }
01245 private:
01246 char state;
01247 };
01248
01249 namespace {
01250 const compres maybe = (char)2;
01251 }
01252
01253 class SubTree
01254 {
01255 struct CodeTree *tree;
01256 bool sign;
01257
01258 inline void flipsign() { sign = !sign; }
01259 public:
01260 SubTree();
01261 SubTree(double value);
01262 SubTree(const SubTree &b);
01263 SubTree(const struct CodeTree &b);
01264
01265 ~SubTree();
01266 const SubTree &operator= (const SubTree &b);
01267 const SubTree &operator= (const CodeTree &b);
01268
01269 bool getsign() const { return sign; }
01270
01271 const struct CodeTree* operator-> () const { return tree; }
01272 const struct CodeTree& operator* () const { return *tree; }
01273 struct CodeTree* operator-> () { return tree; }
01274 struct CodeTree& operator* () { return *tree; }
01275
01276 bool operator< (const SubTree& b) const;
01277 bool operator== (const SubTree& b) const;
01278 void Negate();
01279 void Invert();
01280
01281 void CheckConstNeg();
01282 void CheckConstInv();
01283 };
01284
01285 namespace {
01286 bool IsNegate(const SubTree &p1, const SubTree &p2);
01287 bool IsInverse(const SubTree &p1, const SubTree &p2);
01288 }
01289
01290 typedef list<SubTree> paramlist;
01291
01292 struct CodeTreeData
01293 {
01294 paramlist args;
01295
01296 private:
01297 unsigned op;
01298 double value;
01299 unsigned var;
01300 unsigned funcno;
01301
01302 public:
01303 CodeTreeData() : op(cAdd) {}
01304 ~CodeTreeData() {}
01305
01306 void SetOp(unsigned newop) { op=newop; }
01307 void SetFuncNo(unsigned newno) { funcno=newno; }
01308 unsigned GetFuncNo() const { return funcno; }
01309
01310 bool IsFunc() const { return op == cFCall || op == cPCall; }
01311 bool IsImmed() const { return op == cImmed; }
01312 bool IsVar() const { return op == cVar; }
01313 inline unsigned GetOp() const { return op; }
01314 inline double GetImmed() const
01315 {
01316 return value;
01317 }
01318 inline unsigned GetVar() const
01319 {
01320 return var;
01321 }
01322
01323 void AddParam(const SubTree &p)
01324 {
01325 args.push_back(p);
01326 }
01327 void SetVar(unsigned v)
01328 {
01329 args.clear();
01330 op = cVar;
01331 var = v;
01332 }
01333 void SetImmed(double v)
01334 {
01335 args.clear();
01336 op = cImmed;
01337 value = orig = v;
01338 inverted = negated = false;
01339 }
01340 void NegateImmed()
01341 {
01342 negated = !negated;
01343 UpdateValue();
01344 }
01345 void InvertImmed()
01346 {
01347 inverted = !inverted;
01348 UpdateValue();
01349 }
01350
01351 bool IsOriginal() const { return !(IsInverted() || IsNegated()); }
01352 bool IsInverted() const { return inverted; }
01353 bool IsNegated() const { return negated; }
01354 bool IsInvertedOriginal() const { return IsInverted() && !IsNegated(); }
01355 bool IsNegatedOriginal() const { return !IsInverted() && IsNegated(); }
01356
01357 private:
01358 void UpdateValue()
01359 {
01360 value = orig;
01361 if(IsInverted()) { value = 1.0 / value;
01362
01363 }
01364 if(IsNegated()) value = -value;
01365 }
01366
01367 double orig;
01368 bool inverted;
01369 bool negated;
01370 protected:
01371
01372 void operator=(const CodeTreeData &b);
01373 };
01374
01375 class CodeTreeDataPtr
01376 {
01377 typedef pair<CodeTreeData, unsigned> p_t;
01378 typedef p_t* pp;
01379 mutable pp p;
01380
01381 void Alloc() const { ++p->second; }
01382 void Dealloc() const { if(!--p->second) delete p; p = 0; }
01383
01384 void PrepareForWrite()
01385 {
01386
01387 if(p->second == 1) return;
01388
01389
01390 p_t *newtree = new p_t(p->first, 1);
01391
01392 Dealloc();
01393
01394 p = newtree;
01395 }
01396
01397 public:
01398 CodeTreeDataPtr() : p(new p_t) { p->second = 1; }
01399 CodeTreeDataPtr(const CodeTreeDataPtr &b): p(b.p) { Alloc(); }
01400 ~CodeTreeDataPtr() { Dealloc(); }
01401 const CodeTreeDataPtr &operator= (const CodeTreeDataPtr &b)
01402 {
01403 b.Alloc();
01404 Dealloc();
01405 p = b.p;
01406 return *this;
01407 }
01408 const CodeTreeData *operator-> () const { return &p->first; }
01409 const CodeTreeData &operator* () const { return p->first; }
01410 CodeTreeData *operator-> () { PrepareForWrite(); return &p->first; }
01411 CodeTreeData &operator* () { PrepareForWrite(); return p->first; }
01412
01413 void Shock();
01414 };
01415
01416 #define CHECKCONSTNEG(item, op) \
01417 ((op)==cMul) \
01418 ? (item).CheckConstInv() \
01419 : (item).CheckConstNeg()
01420
01421 struct CodeTree
01422 {
01423 CodeTreeDataPtr data;
01424
01425 private:
01426 typedef paramlist::iterator pit;
01427 typedef paramlist::const_iterator pcit;
01428
01429 template<unsigned v> inline void chk() const
01430 {
01431 }
01432
01433 public:
01434 const pcit GetBegin() const { return data->args.begin(); }
01435 const pcit GetEnd() const { return data->args.end(); }
01436 const pit GetBegin() { return data->args.begin(); }
01437 const pit GetEnd() { return data->args.end(); }
01438 const SubTree& getp0() const { chk<1>();pcit tmp=GetBegin(); return *tmp; }
01439 const SubTree& getp1() const { chk<2>();pcit tmp=GetBegin(); ++tmp; return *tmp; }
01440 const SubTree& getp2() const { chk<3>();pcit tmp=GetBegin(); ++tmp; ++tmp; return *tmp; }
01441 unsigned GetArgCount() const { return data->args.size(); }
01442 void Erase(const pit p) { data->args.erase(p); }
01443
01444 SubTree& getp0() { chk<1>();pit tmp=GetBegin(); return *tmp; }
01445 SubTree& getp1() { chk<2>();pit tmp=GetBegin(); ++tmp; return *tmp; }
01446 SubTree& getp2() { chk<3>();pit tmp=GetBegin(); ++tmp; ++tmp; return *tmp; }
01447
01448
01449 void SetImmed(double v) { data->SetImmed(v); }
01450 void SetOp(unsigned op) { data->SetOp(op); }
01451 void SetVar(unsigned v) { data->SetVar(v); }
01452
01453 double GetImmed() const { return data->GetImmed(); }
01454 unsigned GetVar() const { return data->GetVar(); }
01455 unsigned GetOp() const { return data->GetOp(); }
01456
01457 bool IsImmed() const { return data->IsImmed(); }
01458 bool IsVar() const { return data->IsVar(); }
01459
01460 void AddParam(const SubTree &p) { data->AddParam(p); }
01461 void NegateImmed() { data->NegateImmed(); }
01462 void InvertImmed() { data->InvertImmed(); }
01463
01464 compres NonZero() const { if(!IsImmed()) return maybe;
01465 return GetImmed() != 0.0; }
01466 compres IsPositive() const { if(!IsImmed()) return maybe;
01467 return GetImmed() > 0.0; }
01468
01469 private:
01470 struct ConstList
01471 {
01472 double voidvalue;
01473 list<pit> cp;
01474 double value;
01475 unsigned size() const { return cp.size(); }
01476 };
01477 struct ConstList BuildConstList();
01478 void KillConst(const ConstList &cl)
01479 {
01480 for(list<pit>::const_iterator i=cl.cp.begin(); i!=cl.cp.end(); ++i)
01481 Erase(*i);
01482 }
01483 void FinishConst(const ConstList &cl)
01484 {
01485 if(cl.value != cl.voidvalue && cl.size() > 1) AddParam(cl.value);
01486 if(cl.value == cl.voidvalue || cl.size() > 1) KillConst(cl);
01487 }
01488
01489 public:
01490 CodeTree() {}
01491 CodeTree(double v) { SetImmed(v); }
01492
01493 CodeTree(unsigned op, const SubTree &p)
01494 {
01495 SetOp(op);
01496 AddParam(p);
01497 }
01498 CodeTree(unsigned op, const SubTree &p1, const SubTree &p2)
01499 {
01500 SetOp(op);
01501 AddParam(p1);
01502 AddParam(p2);
01503 }
01504
01505 bool operator== (const CodeTree& b) const;
01506 bool operator< (const CodeTree& b) const;
01507
01508 private:
01509 bool IsSortable() const
01510 {
01511 switch(GetOp())
01512 {
01513 case cAdd: case cMul:
01514 case cEqual:
01515 case cAnd: case cOr:
01516 case cMax: case cMin:
01517 return true;
01518 default:
01519 return false;
01520 }
01521 }
01522 void SortIfPossible()
01523 {
01524 if(IsSortable())
01525 {
01526 data->args.sort();
01527 }
01528 }
01529
01530 void ReplaceWithConst(double value)
01531 {
01532 SetImmed(value);
01533
01534
01535
01536
01537 }
01538
01539 void ReplaceWith(const CodeTree &b)
01540 {
01541
01542
01543
01544 CodeTreeDataPtr tmp = b.data;
01545 tmp.Shock();
01546 data = tmp;
01547 }
01548
01549 void ReplaceWith(unsigned op, const SubTree &p)
01550 {
01551 ReplaceWith(CodeTree(op, p));
01552 }
01553
01554 void ReplaceWith(unsigned op, const SubTree &p1, const SubTree &p2)
01555 {
01556 ReplaceWith(CodeTree(op, p1, p2));
01557 }
01558
01559 void OptimizeConflict()
01560 {
01561
01562
01563 if(GetOp() == cAdd || GetOp() == cMul)
01564 {
01565 Redo:
01566 pit a, b;
01567 for(a=GetBegin(); a!=GetEnd(); ++a)
01568 {
01569 for(b=GetBegin(); ++b != GetEnd(); )
01570 {
01571 const SubTree &p1 = *a;
01572 const SubTree &p2 = *b;
01573
01574 if(GetOp() == cMul ? IsInverse(p1,p2)
01575 : IsNegate(p1,p2))
01576 {
01577
01578 Erase(b);
01579 Erase(a);
01580 goto Redo;
01581 }
01582 }
01583 }
01584 }
01585 OptimizeRedundant();
01586 }
01587
01588 void OptimizeRedundant()
01589 {
01590
01591
01592 if(!GetArgCount())
01593 {
01594 if(GetOp() == cAdd || GetOp() == cMin || GetOp() == cMax)
01595 ReplaceWithConst(0);
01596 else if(GetOp() == cMul)
01597 ReplaceWithConst(1);
01598 return;
01599 }
01600
01601
01602
01603 if(GetArgCount() == 1)
01604 {
01605 if(GetOp() == cMul || GetOp() == cAdd || GetOp() == cMin || GetOp() == cMax)
01606 if(!getp0().getsign())
01607 ReplaceWith(*getp0());
01608 }
01609
01610 OptimizeDoubleNegations();
01611 }
01612
01613 void OptimizeDoubleNegations()
01614 {
01615 if(GetOp() == cAdd)
01616 {
01617
01618
01619
01620
01621
01622
01623 for(pit a=GetBegin(); a!=GetEnd(); ++a)
01624 {
01625 SubTree &pa = *a;
01626 if(pa.getsign()
01627 && pa->GetOp() == cMul)
01628 {
01629 CodeTree &p = *pa;
01630 for(pit b=p.GetBegin();
01631 b!=p.GetEnd(); ++b)
01632 {
01633 SubTree &pb = *b;
01634 if(pb->IsImmed())
01635 {
01636 pb.Negate();
01637 pa.Negate();
01638 break;
01639 }
01640 }
01641 }
01642 }
01643 }
01644
01645 if(GetOp() == cMul)
01646 {
01647
01648
01649
01650
01651 for(pit a=GetBegin(); a!=GetEnd(); ++a)
01652 {
01653 SubTree &pa = *a;
01654 if(pa.getsign() && pa->GetOp() == cPow)
01655 {
01656 CodeTree &p = *pa;
01657 if(p.getp1()->IsImmed())
01658 {
01659
01660 p.getp1().Negate();
01661 pa.Negate();
01662 }
01663 }
01664 }
01665 }
01666 }
01667
01668 void OptimizeConstantMath1()
01669 {
01670
01671
01672
01673
01674
01675
01676
01677
01678
01679
01680 OptimizeAddMulFlat();
01681
01682 switch(GetOp())
01683 {
01684 case cAdd:
01685 {
01686 ConstList cl = BuildConstList();
01687 FinishConst(cl);
01688 break;
01689 }
01690 case cMul:
01691 {
01692 ConstList cl = BuildConstList();
01693
01694 if(cl.value == 0.0) ReplaceWithConst(0.0);
01695 else FinishConst(cl);
01696
01697 break;
01698 }
01699 #define ConstantUnaryFun(token, fun) \
01700 case token: { const SubTree &p0 = getp0(); \
01701 if(p0->IsImmed()) ReplaceWithConst(fun(p0->GetImmed())); \
01702 break; }
01703 #define ConstantBinaryFun(token, fun) \
01704 case token: { const SubTree &p0 = getp0(); \
01705 const SubTree &p1 = getp1(); \
01706 if(p0->IsImmed() && \
01707 p1->IsImmed()) ReplaceWithConst(fun(p0->GetImmed(), p1->GetImmed())); \
01708 break; }
01709
01710
01711
01712
01713 ConstantUnaryFun(cAbs, fabs);
01714 ConstantUnaryFun(cAcos, acos);
01715 ConstantUnaryFun(cAsin, asin);
01716 ConstantUnaryFun(cAtan, atan);
01717 ConstantUnaryFun(cCeil, ceil);
01718 ConstantUnaryFun(cCos, cos);
01719 ConstantUnaryFun(cCosh, cosh);
01720 ConstantUnaryFun(cFloor, floor);
01721 ConstantUnaryFun(cLog, log);
01722 ConstantUnaryFun(cSin, sin);
01723 ConstantUnaryFun(cSinh, sinh);
01724 ConstantUnaryFun(cTan, tan);
01725 ConstantUnaryFun(cTanh, tanh);
01726 ConstantBinaryFun(cAtan2, atan2);
01727 ConstantBinaryFun(cMax, Max);
01728 ConstantBinaryFun(cMin, Min);
01729 ConstantBinaryFun(cMod, fmod);
01730 ConstantBinaryFun(cPow, pow);
01731
01732 case cNeg:
01733 case cSub:
01734 case cDiv:
01735
01736
01737
01738 break;
01739
01740 case cCot:
01741 case cCsc:
01742 case cSec:
01743 case cDeg:
01744 case cRad:
01745 case cLog10:
01746 case cSqrt:
01747 case cExp:
01748
01749
01750
01751 break;
01752 }
01753
01754 OptimizeConflict();
01755 }
01756
01757 void OptimizeAddMulFlat()
01758 {
01759
01760
01761
01762
01763
01764
01765 if(GetOp() == cAdd || GetOp() == cMul)
01766 {
01767
01768 for(pit b, a=GetBegin(); a!=GetEnd(); a=b)
01769 {
01770 const SubTree &pa = *a; b=a; ++b;
01771 if(pa->GetOp() != GetOp()) continue;
01772
01773
01774 for(pcit c=pa->GetBegin();
01775 c!=pa->GetEnd();
01776 ++c)
01777 {
01778 const SubTree &pb = *c;
01779 if(pa.getsign())
01780 {
01781
01782
01783
01784 SubTree tmp = pb;
01785 if(GetOp() == cMul)
01786 tmp.Invert();
01787 else
01788 tmp.Negate();
01789 AddParam(tmp);
01790 }
01791 else
01792 AddParam(pb);
01793 }
01794 Erase(a);
01795
01796
01797 }
01798 }
01799 }
01800
01801 void OptimizeLinearCombine()
01802 {
01803
01804
01805
01806
01807
01808
01809
01810
01811
01812 OptimizeConflict();
01813
01814 bool didchanges = false;
01815 if(GetOp() == cAdd || GetOp() == cMul)
01816 {
01817 Redo:
01818 for(pit a=GetBegin(); a!=GetEnd(); ++a)
01819 {
01820 const SubTree &pa = *a;
01821
01822 list<pit> poslist;
01823
01824 for(pit b=a; ++b!=GetEnd(); )
01825 {
01826 const SubTree &pb = *b;
01827 if(*pa == *pb)
01828 poslist.push_back(b);
01829 }
01830
01831 unsigned min = 2;
01832 if(poslist.size() >= min)
01833 {
01834 SubTree arvo = pa;
01835 bool negate = arvo.getsign();
01836
01837 double factor = poslist.size() + 1;
01838
01839 if(negate)
01840 {
01841 arvo.Negate();
01842 factor = -factor;
01843 }
01844
01845 CodeTree tmp(GetOp()==cAdd ? cMul : cPow,
01846 arvo,
01847 factor);
01848
01849 list<pit>::const_iterator j;
01850 for(j=poslist.begin(); j!=poslist.end(); ++j)
01851 Erase(*j);
01852 poslist.clear();
01853
01854 *a = tmp;
01855 didchanges = true;
01856 goto Redo;
01857 }
01858 }
01859 }
01860 if(didchanges)
01861 {
01862
01863 OptimizeAddMulFlat();
01864
01865 OptimizeRedundant();
01866 }
01867 }
01868
01869 void OptimizeLogarithm()
01870 {
01871
01872
01873
01874
01875
01876
01877
01878
01879
01880
01881
01882
01883
01884
01885
01886
01887
01888
01889
01890
01891
01892
01893
01894
01895
01896
01897
01898
01899
01900
01901 OptimizeExponents();
01902
01903 if(GetOp() == cLog)
01904 {
01905
01906
01907
01908 const SubTree &p = getp0();
01909
01910 if(p->GetOp() == cPow)
01911 {
01912
01913 SubTree p0 = p->getp0();
01914 SubTree p1 = p->getp1();
01915
01916
01917 CodeTree tmp(GetOp(), p0);
01918
01919
01920 ReplaceWith(cMul, tmp, p1);
01921 }
01922 else if(p->GetOp() == cMul)
01923 {
01924
01925 SubTree &p = getp0();
01926
01927 p->OptimizeAddMulFlat();
01928 p->OptimizeExponents();
01929 CHECKCONSTNEG(p, p->GetOp());
01930
01931 list<SubTree> adds;
01932
01933 for(pit b, a = p->GetBegin();
01934 a != p->GetEnd(); a=b)
01935 {
01936 SubTree &pa = *a; b=a; ++b;
01937 if(pa->GetOp() == cPow
01938 && pa->getp0()->IsImmed()
01939 && pa->getp0()->GetImmed() == CONSTANT_E)
01940 {
01941 adds.push_back(pa->getp1());
01942 p->Erase(a);
01943 continue;
01944 }
01945 }
01946 if(adds.size())
01947 {
01948 CodeTree tmp(cAdd, *this);
01949
01950 list<SubTree>::const_iterator i;
01951 for(i=adds.begin(); i!=adds.end(); ++i)
01952 tmp.AddParam(*i);
01953
01954 ReplaceWith(tmp);
01955 }
01956 }
01957 }
01958 if(GetOp() == cAdd)
01959 {
01960
01961 list<pit> poslist;
01962
01963 for(pit a=GetBegin(); a!=GetEnd(); ++a)
01964 {
01965 const SubTree &pa = *a;
01966 if(pa->GetOp() == cLog)
01967 poslist.push_back(a);
01968 }
01969
01970 if(poslist.size() >= 2)
01971 {
01972 CodeTree tmp(cMul, 1.0);
01973
01974 list<pit>::const_iterator j;
01975 for(j=poslist.begin(); j!=poslist.end(); ++j)
01976 {
01977 const SubTree &pb = **j;
01978
01979 for(pcit b=pb->GetBegin();
01980 b!=pb->GetEnd();
01981 ++b)
01982 {
01983 SubTree tmp2 = *b;
01984 if(pb.getsign()) tmp2.Negate();
01985 tmp.AddParam(tmp2);
01986 }
01987 Erase(*j);
01988 }
01989 poslist.clear();
01990
01991 AddParam(CodeTree(cLog, tmp));
01992 }
01993
01994 }
01995 if(GetOp() == cPow)
01996 {
01997 const SubTree &p0 = getp0();
01998 SubTree &p1 = getp1();
01999
02000 if(p0->IsImmed() && p0->GetImmed() == CONSTANT_E
02001 && p1->GetOp() == cLog)
02002 {
02003
02004 ReplaceWith(*(p1->getp0()));
02005 }
02006 else if(p1->GetOp() == cMul)
02007 {
02008
02009
02010 pit poslogpos; bool foundposlog = false;
02011 pit neglogpos; bool foundneglog = false;
02012
02013 ConstList cl = p1->BuildConstList();
02014
02015 for(pit a=p1->GetBegin(); a!=p1->GetEnd(); ++a)
02016 {
02017 const SubTree &pa = *a;
02018 if(pa->GetOp() == cLog)
02019 {
02020 if(!pa.getsign())
02021 {
02022 foundposlog = true;
02023 poslogpos = a;
02024 }
02025 else if(*p0 == *(pa->getp0()))
02026 {
02027 foundneglog = true;
02028 neglogpos = a;
02029 }
02030 }
02031 }
02032
02033 if(p0->IsImmed()
02034 && p0->GetImmed() == 10.0
02035 && cl.value == CONSTANT_L10I
02036 && foundposlog)
02037 {
02038 SubTree base = (*poslogpos)->getp0();
02039 p1->KillConst(cl);
02040 p1->Erase(poslogpos);
02041 p1->OptimizeRedundant();
02042 SubTree mul = p1;
02043
02044 ReplaceWith(cPow, base, mul);
02045
02046
02047 return;
02048 }
02049
02050
02051 FinishConst(cl);
02052
02053 if(p0->IsImmed()
02054 && p0->GetImmed() == CONSTANT_E
02055 && foundposlog)
02056 {
02057 SubTree base = (*poslogpos)->getp0();
02058 p1->Erase(poslogpos);
02059
02060 p1->OptimizeRedundant();
02061 SubTree mul = p1;
02062
02063 ReplaceWith(cPow, base, mul);
02064
02065
02066 return;
02067 }
02068
02069 if(foundposlog
02070 && foundneglog
02071 && *((*neglogpos)->getp0()) == *p0)
02072 {
02073 SubTree base = (*poslogpos)->getp0();
02074 p1->Erase(poslogpos);
02075 p1->Erase(neglogpos);
02076
02077 p1->OptimizeRedundant();
02078 SubTree mul = p1;
02079
02080 ReplaceWith(cPow, base, mul);
02081
02082
02083 return;
02084 }
02085 }
02086 }
02087 }
02088
02089 void OptimizeFunctionCalls()
02090 {
02091
02092
02093
02094
02095
02096
02097
02098
02099
02100
02101
02102 }
02103
02104 void OptimizePowMulAdd()
02105 {
02106
02107
02108
02109
02110
02111 if(GetOp() == cPow)
02112 {
02113 const SubTree &base = getp0();
02114 const SubTree &exponent = getp1();
02115
02116 if(exponent->IsImmed())
02117 {
02118 if(exponent->GetImmed() == 1.0)
02119 ReplaceWith(*base);
02120 else if(exponent->GetImmed() == 0.0
02121 && base->NonZero())
02122 ReplaceWithConst(1.0);
02123 }
02124 }
02125 }
02126
02127 void OptimizeExponents()
02128 {
02129
02130
02131
02132
02133
02134 OptimizeLinearCombine();
02135
02136 bool didchanges = false;
02137
02138 Redo:
02139 if(GetOp() == cPow)
02140 {
02141
02142
02143 const SubTree &p0 = getp0();
02144 const SubTree &p1 = getp1();
02145 if(p0->GetOp() == cPow)
02146 {
02147 CodeTree tmp(cMul, p0->getp1(), p1);
02148 tmp.Optimize();
02149
02150 ReplaceWith(cPow, p0->getp0(), tmp);
02151
02152 didchanges = true;
02153 goto Redo;
02154 }
02155 }
02156 if(GetOp() == cMul)
02157 {
02158
02159
02160 for(pit a=GetBegin(); a!=GetEnd(); ++a)
02161 {
02162 const SubTree &pa = *a;
02163
02164 if(pa->GetOp() != cPow) continue;
02165
02166 list<pit> poslist;
02167
02168 for(pit b=a; ++b != GetEnd(); )
02169 {
02170 const SubTree &pb = *b;
02171 if(pb->GetOp() == cPow
02172 && *(pa->getp0())
02173 == *(pb->getp0()))
02174 {
02175 poslist.push_back(b);
02176 }
02177 }
02178
02179 if(poslist.size() >= 1)
02180 {
02181 poslist.push_back(a);
02182
02183 CodeTree base = *(pa->getp0());
02184
02185 CodeTree exponent(cAdd, 0.0);
02186
02187
02188 list<pit>::const_iterator i;
02189 for(i=poslist.begin(); i!=poslist.end(); ++i)
02190 {
02191 const SubTree &pb = **i;
02192
02193 SubTree tmp2 = pb->getp1();
02194 if(pb.getsign()) tmp2.Invert();
02195
02196 exponent.AddParam(tmp2);
02197 }
02198
02199 exponent.Optimize();
02200
02201 CodeTree result(cPow, base, exponent);
02202
02203 for(i=poslist.begin(); i!=poslist.end(); ++i)
02204 Erase(*i);
02205 poslist.clear();
02206
02207 AddParam(result);
02208
02209 didchanges = true;
02210 goto Redo;
02211 }
02212 }
02213 }
02214
02215 OptimizePowMulAdd();
02216
02217 if(didchanges)
02218 {
02219
02220 OptimizeConflict();
02221 }
02222 }
02223
02224 void OptimizeLinearExplode()
02225 {
02226
02227
02228
02229
02230 if(GetOp() != cPow) return;
02231
02232
02233 }
02234
02235 void OptimizePascal()
02236 {
02237 #if 0 // Too big, too specific, etc
02238
02239
02240 if(GetOp() != cAdd) return;
02241
02242
02243
02244
02245
02246
02247
02248
02249
02250
02251
02252
02253
02254
02255
02256 #endif
02257 }
02258
02259 public:
02260
02261 void Optimize();
02262
02263 void Assemble(vector<unsigned> &byteCode,
02264 vector<double> &immed) const;
02265
02266 void FinalOptimize()
02267 {
02268
02269 for(pit a=GetBegin(); a!=GetEnd(); ++a)
02270 (*a)->FinalOptimize();
02271
02272
02273
02274
02275
02276
02277
02278
02279
02280
02281
02282
02283
02284
02285 if(GetOp() == cPow)
02286 {
02287 const SubTree &p0 = getp0();
02288 const SubTree &p1 = getp1();
02289 if(p0->GetOp() == cImmed
02290 && p0->GetImmed() == CONSTANT_E)
02291 {
02292 ReplaceWith(cExp, p1);
02293 }
02294 else if(p1->GetOp() == cImmed
02295 && p1->GetImmed() == 0.5)
02296 {
02297 ReplaceWith(cSqrt, p0);
02298 }
02299 }
02300 if(GetOp() == cMul)
02301 {
02302 if(GetArgCount() == 1 && getp0().getsign())
02303 {
02304 if(getp0()->GetOp() == cSin)ReplaceWith(cCsc, getp0()->getp0());
02305 else if(getp0()->GetOp() == cCos)ReplaceWith(cSec, getp0()->getp0());
02306 else if(getp0()->GetOp() == cTan)ReplaceWith(cCot, getp0()->getp0());
02307 }
02308 }
02309
02310 if(GetOp() == cMul)
02311 {
02312 CodeTree *found_log = 0;
02313
02314 ConstList cl = BuildConstList();
02315
02316 for(pit a=GetBegin(); a!=GetEnd(); ++a)
02317 {
02318 SubTree &pa = *a;
02319 if(pa->GetOp() == cLog && !pa.getsign())
02320 found_log = &*pa;
02321 }
02322 if(cl.value == CONSTANT_L10I && found_log)
02323 {
02324
02325 found_log->SetOp(cLog10);
02326
02327 KillConst(cl);
02328 }
02329 else if(cl.value == CONSTANT_DR)
02330 {
02331 OptimizeRedundant();
02332 ReplaceWith(cDeg, *this);
02333 }
02334 else if(cl.value == CONSTANT_RD)
02335 {
02336 OptimizeRedundant();
02337 ReplaceWith(cRad, *this);
02338 }
02339 else FinishConst(cl);
02340 }
02341
02342 SortIfPossible();
02343 }
02344 };
02345
02346 void CodeTreeDataPtr::Shock()
02347 {
02348
02349
02350
02351
02352
02353
02354
02355
02356 }
02357
02358 CodeTree::ConstList CodeTree::BuildConstList()
02359 {
02360 ConstList result;
02361 result.value =
02362 result.voidvalue = GetOp()==cMul ? 1.0 : 0.0;
02363
02364 list<pit> &cp = result.cp;
02365 for(pit b, a=GetBegin(); a!=GetEnd(); a=b)
02366 {
02367 SubTree &pa = *a; b=a; ++b;
02368 if(!pa->IsImmed()) continue;
02369
02370 double thisvalue = pa->GetImmed();
02371 if(thisvalue == result.voidvalue)
02372 {
02373
02374 Erase(a);
02375 continue;
02376 }
02377 if(GetOp() == cMul)
02378 result.value *= thisvalue;
02379 else
02380 result.value += thisvalue;
02381 cp.push_back(a);
02382 }
02383 if(GetOp() == cMul)
02384 {
02385
02386
02387
02388
02389 for(bool done=false; cp.size() > 1 && !done; )
02390 {
02391 done = true;
02392 for(list<pit>::iterator b,a=cp.begin(); a!=cp.end(); a=b)
02393 {
02394 b=a; ++b;
02395 if((**a)->GetImmed() == -1.0)
02396 {
02397 Erase(*a);
02398 cp.erase(a);
02399
02400
02401 (**cp.begin())->data->NegateImmed();
02402 if(cp.size() < 2)break;
02403 done = false;
02404 }
02405 }
02406 }
02407 }
02408 return result;
02409 }
02410
02411 void CodeTree::Assemble
02412 (vector<unsigned> &byteCode,
02413 vector<double> &immed) const
02414 {
02415 #define AddCmd(op) byteCode.push_back((op))
02416 #define AddConst(v) do { \
02417 byteCode.push_back(cImmed); \
02418 immed.push_back((v)); \
02419 } while(0)
02420
02421 if(IsVar())
02422 {
02423 AddCmd(GetVar());
02424 return;
02425 }
02426 if(IsImmed())
02427 {
02428 AddConst(GetImmed());
02429 return;
02430 }
02431
02432 switch(GetOp())
02433 {
02434 case cAdd:
02435 case cMul:
02436 {
02437 unsigned opcount = 0;
02438 for(pcit a=GetBegin(); a!=GetEnd(); ++a)
02439 {
02440 const SubTree &pa = *a;
02441
02442 if(opcount < 2) ++opcount;
02443
02444 bool pnega = pa.getsign();
02445
02446 bool done = false;
02447 if(pa->IsImmed())
02448 {
02449 if(GetOp() == cMul
02450 && pa->data->IsInverted()
02451 && (pnega || opcount==2)
02452 )
02453 {
02454 CodeTree tmp = *pa;
02455 tmp.data->InvertImmed();
02456 tmp.Assemble(byteCode, immed);
02457 pnega = !pnega;
02458 done = true;
02459 }
02460 else if(GetOp() == cAdd
02461 && (pa->data->IsNegatedOriginal()
02462
02463 )
02464 && (pnega || opcount==2)
02465 )
02466 {
02467 CodeTree tmp = *pa;
02468 tmp.data->NegateImmed();
02469 tmp.Assemble(byteCode, immed);
02470 pnega = !pnega;
02471 done = true;
02472 }
02473 }
02474 if(!done)
02475 pa->Assemble(byteCode, immed);
02476
02477 if(opcount == 2)
02478 {
02479 unsigned tmpop = GetOp();
02480 if(pnega)
02481 {
02482 tmpop = (tmpop == cMul) ? cDiv : cSub;
02483 }
02484 AddCmd(tmpop);
02485 }
02486 else if(pnega)
02487 {
02488 if(GetOp() == cMul) AddCmd(cInv);
02489 else AddCmd(cNeg);
02490 }
02491 }
02492 break;
02493 }
02494 case cIf:
02495 {
02496
02497 getp0()->Assemble(byteCode, immed);
02498
02499 unsigned ofs = byteCode.size();
02500 AddCmd(cIf);
02501 AddCmd(0);
02502 AddCmd(0);
02503
02504 getp1()->Assemble(byteCode, immed);
02505
02506 byteCode[ofs+1] = byteCode.size()+2;
02507 byteCode[ofs+2] = immed.size();
02508
02509 ofs = byteCode.size();
02510 AddCmd(cJump);
02511 AddCmd(0);
02512 AddCmd(0);
02513
02514 getp2()->Assemble(byteCode, immed);
02515
02516 byteCode[ofs+1] = byteCode.size()-1;
02517 byteCode[ofs+2] = immed.size();
02518
02519 break;
02520 }
02521 case cFCall:
02522 {
02523
02524 for(pcit a=GetBegin(); a!=GetEnd(); ++a)
02525 {
02526 const SubTree &pa = *a;
02527 pa->Assemble(byteCode, immed);
02528 }
02529 AddCmd(GetOp());
02530 AddCmd(data->GetFuncNo());
02531 break;
02532 }
02533 case cPCall:
02534 {
02535
02536 for(pcit a=GetBegin(); a!=GetEnd(); ++a)
02537 {
02538 const SubTree &pa = *a;
02539 pa->Assemble(byteCode, immed);
02540 }
02541 AddCmd(GetOp());
02542 AddCmd(data->GetFuncNo());
02543 break;
02544 }
02545 default:
02546 {
02547
02548 for(pcit a=GetBegin(); a!=GetEnd(); ++a)
02549 {
02550 const SubTree &pa = *a;
02551 pa->Assemble(byteCode, immed);
02552 }
02553 AddCmd(GetOp());
02554 break;
02555 }
02556 }
02557 }
02558
02559 void CodeTree::Optimize()
02560 {
02561
02562
02563
02564
02565
02566 for(unsigned phase=0; phase<=2; ++phase)
02567 {
02568 if(phase == 1)
02569 {
02570
02571 for(pit a=GetBegin(); a!=GetEnd(); ++a)
02572 {
02573 (*a)->Optimize();
02574 CHECKCONSTNEG(*a, GetOp());
02575 }
02576 continue;
02577 }
02578 if(phase == 0 || phase == 2)
02579 {
02580
02581
02582 OptimizeConstantMath1();
02583 OptimizeLogarithm();
02584 OptimizeFunctionCalls();
02585 OptimizeExponents();
02586 OptimizeLinearExplode();
02587 OptimizePascal();
02588
02589
02590
02591
02592
02593
02594
02595
02596
02597
02598
02599
02600
02601
02602
02603
02604
02605
02606
02607 }
02608 }
02609 }
02610
02611
02612 bool CodeTree::operator== (const CodeTree& b) const
02613 {
02614 if(GetOp() != b.GetOp()) return false;
02615 if(IsImmed()) if(GetImmed() != b.GetImmed()) return false;
02616 if(IsVar()) if(GetVar() != b.GetVar()) return false;
02617 if(data->IsFunc())
02618 if(data->GetFuncNo() != b.data->GetFuncNo()) return false;
02619 return data->args == b.data->args;
02620 }
02621
02622 bool CodeTree::operator< (const CodeTree& b) const
02623 {
02624 if(GetArgCount() != b.GetArgCount())
02625 return GetArgCount() > b.GetArgCount();
02626
02627 if(GetOp() != b.GetOp())
02628 {
02629
02630 if(IsImmed() != b.IsImmed()) return IsImmed() < b.IsImmed();
02631
02632 return GetOp() < b.GetOp();
02633 }
02634
02635 if(IsImmed())
02636 {
02637 if(GetImmed() != b.GetImmed()) return GetImmed() < b.GetImmed();
02638 }
02639 if(IsVar() && GetVar() != b.GetVar())
02640 {
02641 return GetVar() < b.GetVar();
02642 }
02643 if(data->IsFunc() && data->GetFuncNo() != b.data->GetFuncNo())
02644 {
02645 return data->GetFuncNo() < b.data->GetFuncNo();
02646 }
02647
02648 pcit i = GetBegin(), j = b.GetBegin();
02649 for(; i != GetEnd(); ++i, ++j)
02650 {
02651 const SubTree &pa = *i, &pb = *j;
02652
02653 if(!(pa == pb))
02654 return pa < pb;
02655 }
02656 return false;
02657 }
02658
02659 namespace {
02660 bool IsNegate(const SubTree &p1, const SubTree &p2)
02661 {
02662 if(p1->IsImmed() && p2->IsImmed())
02663 {
02664 return p1->GetImmed() == -p2->GetImmed();
02665 }
02666 if(p1.getsign() == p2.getsign()) return false;
02667 return *p1 == *p2;
02668 }
02669 bool IsInverse(const SubTree &p1, const SubTree &p2)
02670 {
02671 if(p1->IsImmed() && p2->IsImmed())
02672 {
02673
02674 return p1->GetImmed() == 1.0 / p2->GetImmed();
02675 }
02676 if(p1.getsign() == p2.getsign()) return false;
02677 return *p1 == *p2;
02678 }
02679 }
02680
02681 SubTree::SubTree() : tree(new CodeTree), sign(false)
02682 {
02683 }
02684
02685 SubTree::SubTree(const SubTree &b) : tree(new CodeTree(*b.tree)), sign(b.sign)
02686 {
02687 }
02688
02689 #define SubTreeDecl(p1, p2) \
02690 SubTree::SubTree p1 : tree(new CodeTree p2), sign(false) { }
02691
02692 SubTreeDecl( (const struct CodeTree &b), (b) )
02693 SubTreeDecl( (double value), (value) )
02694
02695 #undef SubTreeDecl
02696
02697 SubTree::~SubTree()
02698 {
02699 delete tree; tree=0;
02700 }
02701
02702 const SubTree &SubTree::operator= (const SubTree &b)
02703 {
02704 sign = b.sign;
02705 CodeTree *oldtree = tree;
02706 tree = new CodeTree(*b.tree);
02707 delete oldtree;
02708 return *this;
02709 }
02710 const SubTree &SubTree::operator= (const CodeTree &b)
02711 {
02712 sign = false;
02713 CodeTree *oldtree = tree;
02714 tree = new CodeTree(b);
02715 delete oldtree;
02716 return *this;
02717 }
02718
02719 bool SubTree::operator< (const SubTree& b) const
02720 {
02721 if(getsign() != b.getsign()) return getsign() < b.getsign();
02722 return *tree < *b.tree;
02723 }
02724 bool SubTree::operator== (const SubTree& b) const
02725 {
02726 return sign == b.sign && *tree == *b.tree;
02727 }
02728 void SubTree::Negate()
02729 {
02730 flipsign();
02731 CheckConstNeg();
02732 }
02733 void SubTree::CheckConstNeg()
02734 {
02735 if(tree->IsImmed() && getsign())
02736 {
02737 tree->NegateImmed();
02738 sign = false;
02739 }
02740 }
02741 void SubTree::Invert()
02742 {
02743 flipsign();
02744 CheckConstInv();
02745 }
02746 void SubTree::CheckConstInv()
02747 {
02748 if(tree->IsImmed() && getsign())
02749 {
02750 tree->InvertImmed();
02751 sign = false;
02752 }
02753 }
02754
02755 void FunctionParser::MakeTree(struct CodeTree *result) const
02756 {
02757 vector<CodeTree> stack(1);
02758
02759 #define GROW(n) do { \
02760 stacktop += n; \
02761 if(stack.size() <= stacktop) stack.resize(stacktop+1); \
02762 } while(0)
02763
02764 #define EAT(n, opcode) do { \
02765 unsigned newstacktop = stacktop-n; \
02766 stack[stacktop].SetOp((opcode)); \
02767 for(unsigned a=0, b=(n); a<b; ++a) \
02768 stack[stacktop].AddParam(stack[newstacktop+a]); \
02769 stack.erase(stack.begin() + newstacktop, \
02770 stack.begin() + stacktop); \
02771 stacktop = newstacktop; GROW(1); \
02772 } while(0)
02773
02774 #define ADDCONST(n) do { \
02775 stack[stacktop].SetImmed((n)); \
02776 GROW(1); \
02777 } while(0)
02778
02779 unsigned stacktop=0;
02780
02781 list<unsigned> labels;
02782
02783 for(unsigned IP=0, DP=0; ; ++IP)
02784 {
02785 while(labels.size() > 0
02786 && *labels.begin() == IP)
02787 {
02788
02789 EAT(3, cIf);
02790 labels.erase(labels.begin());
02791 }
02792
02793 if(IP >= Comp.ByteCodeSize)
02794 {
02795 break;
02796 }
02797
02798 unsigned opcode = Comp.ByteCode[IP];
02799
02800 if(opcode == cIf)
02801 {
02802 IP += 2;
02803 }
02804 else if(opcode == cJump)
02805 {
02806 labels.push_front(Comp.ByteCode[IP+1]+1);
02807 IP += 2;
02808 }
02809 else if(opcode == cImmed)
02810 {
02811 ADDCONST(Comp.Immed[DP++]);
02812 }
02813 else if(opcode < VarBegin)
02814 {
02815 switch(opcode)
02816 {
02817
02818 case cNeg:
02819 {
02820 EAT(1, cAdd);
02821 stack[stacktop-1].getp0().Negate();
02822 break;
02823 }
02824
02825 case cSub:
02826 {
02827 EAT(2, cAdd);
02828 stack[stacktop-1].getp1().Negate();
02829 break;
02830 }
02831 case cDiv:
02832 {
02833 EAT(2, cMul);
02834 stack[stacktop-1].getp1().Invert();
02835 break;
02836 }
02837
02838
02839 case cAdd: case cMul:
02840 case cMod: case cPow:
02841 case cEqual: case cLess: case cGreater:
02842 case cAnd: case cOr:
02843 EAT(2, opcode);
02844 break;
02845
02846 case cFCall:
02847 {
02848 unsigned index = Comp.ByteCode[++IP];
02849 unsigned params = FuncPtrs[index].params;
02850 EAT(params, opcode);
02851 stack[stacktop-1].data->SetFuncNo(index);
02852 break;
02853 }
02854 case cPCall:
02855 {
02856 unsigned index = Comp.ByteCode[++IP];
02857 unsigned params = FuncParsers[index]->varAmount;
02858 EAT(params, opcode);
02859 stack[stacktop-1].data->SetFuncNo(index);
02860 break;
02861 }
02862
02863
02864 case cDeg:
02865 ADDCONST(CONSTANT_DR);
02866 EAT(2, cMul);
02867 break;
02868
02869
02870 case cRad:
02871 ADDCONST(CONSTANT_RD);
02872 EAT(2, cMul);
02873 break;
02874
02875
02876 default:
02877 {
02878 const FuncDefinition& func = Functions[opcode-cAbs];
02879
02880 unsigned paramcount = func.params;
02881 #ifndef DISABLE_EVAL
02882 if(opcode == cEval) paramcount = varAmount;
02883 #endif
02884 if(opcode == cSqrt)
02885 {
02886
02887 opcode = cPow;
02888 paramcount = 2;
02889 ADDCONST(0.5);
02890 }
02891 if(opcode == cExp)
02892 {
02893
02894
02895 opcode = cPow;
02896 paramcount = 2;
02897
02898 stack[stacktop] = stack[stacktop-1];
02899 stack[stacktop-1].SetImmed(CONSTANT_E);
02900 GROW(1);
02901 }
02902 bool do_inv = false;
02903 if(opcode == cCot) { do_inv = true; opcode = cTan; }
02904 if(opcode == cCsc) { do_inv = true; opcode = cSin; }
02905 if(opcode == cSec) { do_inv = true; opcode = cCos; }
02906
02907 bool do_log10 = false;
02908 if(opcode == cLog10)
02909 {
02910
02911 opcode = cLog;
02912 do_log10 = true;
02913 }
02914 EAT(paramcount, opcode);
02915 if(do_log10)
02916 {
02917 ADDCONST(CONSTANT_L10I);
02918 EAT(2, cMul);
02919 }
02920 if(do_inv)
02921 {
02922
02923 EAT(1, cMul);
02924 stack[stacktop-1].getp0().Invert();
02925 }
02926 break;
02927 }
02928 }
02929 }
02930 else
02931 {
02932 stack[stacktop].SetVar(opcode);
02933 GROW(1);
02934 }
02935 }
02936
02937 if(!stacktop)
02938 {
02939
02940 return;
02941 }
02942
02943 --stacktop;
02944
02945 if(stacktop > 0)
02946 {
02947
02948 return;
02949 }
02950
02951
02952 *result = stack[0];
02953 }
02954
02955 void FunctionParser::Optimize()
02956 {
02957
02958 CodeTree tree;
02959 MakeTree(&tree);
02960
02961
02962 tree.Optimize();
02963
02964 tree.FinalOptimize();
02965
02966
02967
02968 vector<unsigned> byteCode;
02969 vector<double> immed;
02970
02971 #if 0
02972 byteCode.resize(Comp.ByteCodeSize);
02973 for(unsigned a=0; a<Comp.ByteCodeSize; ++a)byteCode[a] = Comp.ByteCode[a];
02974
02975 immed.resize(Comp.ImmedSize);
02976 for(unsigned a=0; a<Comp.ImmedSize; ++a)immed[a] = Comp.Immed[a];
02977 #else
02978 byteCode.clear(); immed.clear();
02979 tree.Assemble(byteCode, immed);
02980 #endif
02981
02982 delete[] Comp.ByteCode; Comp.ByteCode = 0;
02983 if((Comp.ByteCodeSize = byteCode.size()) > 0)
02984 {
02985 Comp.ByteCode = new unsigned[Comp.ByteCodeSize];
02986 for(unsigned a=0; a<byteCode.size(); ++a)
02987 Comp.ByteCode[a] = byteCode[a];
02988 }
02989
02990 delete[] Comp.Immed; Comp.Immed = 0;
02991 if((Comp.ImmedSize = immed.size()) > 0)
02992 {
02993 Comp.Immed = new double[Comp.ImmedSize];
02994 for(unsigned a=0; a<immed.size(); ++a)
02995 Comp.Immed[a] = immed[a];
02996 }
02997 }
02998
02999
03000 #else
03001
03002
03003 void FunctionParser::MakeTree(struct CodeTree *) const {}
03004 void FunctionParser::Optimize()
03005 {
03006
03007 }
03008 #endif