1 //===============================
2 // Function parser v2.51 by Warp
3 //===============================
5 // Comment out the following line if your compiler supports the (non-standard)
6 // asinh, acosh and atanh functions and you want them to be supported. If
7 // you are not sure, just leave it (those function will then not be supported).
11 // Uncomment the following line to disable the eval() function if it could
12 // be too dangerous in the target application:
13 //#define DISABLE_EVAL
16 // Comment this line out if you are not going to use the optimizer and want
17 // a slightly smaller library. The Optimize() method can still be called,
18 // but it will not do anything.
19 // If you are unsure, just leave it. It won't slow down the other parts of
21 #if !defined(_MSC_VER)
22 #define SUPPORT_OPTIMIZER
26 //============================================================================
40 #define M_PI 3.1415926535897932384626433832795
45 // The functions must be in alphabetical order:
61 cCeil, cCos, cCosh, cCot, cCsc,
65 cExp, cFloor, cIf, cInt, cLog, cLog10, cMax, cMin,
66 cSec, cSin, cSinh, cSqrt, cTan, cTanh,
68 // These do not need any ordering:
70 cNeg, cAdd, cSub, cMul, cDiv, cMod, cPow,
71 cEqual, cLess, cGreater, cAnd, cOr,
77 #ifdef SUPPORT_OPTIMIZER
91 // This is basically strcmp(), but taking 'nameLength' as string
92 // length (not ending '\0'):
93 bool operator<(const FuncDefinition& rhs) const
95 for(unsigned i = 0; i < nameLength; ++i)
97 if(i == rhs.nameLength) return false;
98 const char c1 = name[i], c2 = rhs.name[i];
99 if(c1 < c2) return true;
100 if(c2 < c1) return false;
102 return nameLength < rhs.nameLength;
107 // This list must be in alphabetical order:
108 const FuncDefinition Functions[]=
110 { "abs", 3, cAbs, 1 },
111 { "acos", 4, cAcos, 1 },
113 { "acosh", 5, cAcosh, 1 },
115 { "asin", 4, cAsin, 1 },
117 { "asinh", 5, cAsinh, 1 },
119 { "atan", 4, cAtan, 1 },
120 { "atan2", 5, cAtan2, 2 },
122 { "atanh", 5, cAtanh, 1 },
124 { "ceil", 4, cCeil, 1 },
125 { "cos", 3, cCos, 1 },
126 { "cosh", 4, cCosh, 1 },
127 { "cot", 3, cCot, 1 },
128 { "csc", 3, cCsc, 1 },
130 { "eval", 4, cEval, 0 },
132 { "exp", 3, cExp, 1 },
133 { "floor", 5, cFloor, 1 },
135 { "int", 3, cInt, 1 },
136 { "log", 3, cLog, 1 },
137 { "log10", 5, cLog10, 1 },
138 { "max", 3, cMax, 2 },
139 { "min", 3, cMin, 2 },
140 { "sec", 3, cSec, 1 },
141 { "sin", 3, cSin, 1 },
142 { "sinh", 4, cSinh, 1 },
143 { "sqrt", 4, cSqrt, 1 },
144 { "tan", 3, cTan, 1 },
145 { "tanh", 4, cTanh, 1 }
148 const unsigned FUNC_AMOUNT = sizeof(Functions)/sizeof(Functions[0]);
151 // Returns a pointer to the FuncDefinition instance which 'name' is
152 // the same as the one given by 'F'. If no such function name exists,
154 inline const FuncDefinition* FindFunction(const char* F)
156 FuncDefinition func = { F, 0, 0, 0 };
157 while(isalnum(F[func.nameLength])) ++func.nameLength;
160 const FuncDefinition* found =
161 lower_bound(Functions, Functions+FUNC_AMOUNT, func);
162 if(found == Functions+FUNC_AMOUNT || func < *found)
170 //---------------------------------------------------------------------------
171 // Constructors and destructors
172 //---------------------------------------------------------------------------
173 //===========================================================================
174 FunctionParser::FunctionParser():
175 ParseErrorType(-1), EvalErrorType(0)
178 FunctionParser::~FunctionParser()
181 FunctionParser::CompiledCode::CompiledCode():
182 ByteCode(0), ByteCodeSize(0),
183 Immed(0), ImmedSize(0),
184 Stack(0), StackSize(0)
187 FunctionParser::CompiledCode::~CompiledCode()
189 if(ByteCode) { delete[] ByteCode; ByteCode=0; }
190 if(Immed) { delete[] Immed; Immed=0; }
191 if(Stack) { delete[] Stack; Stack=0; }
195 //---------------------------------------------------------------------------
197 //---------------------------------------------------------------------------
198 //===========================================================================
201 // Error messages returned by ErrorMsg():
202 const char* ParseErrorMessage[]=
205 "Mismatched parenthesis", // 1
207 "Empty parentheses", // 3
208 "Syntax error: Operator expected", // 4
209 "Not enough memory", // 5
210 "An unexpected error ocurred. Please make a full bug report "
211 "to warp@iki.fi", // 6
212 "Syntax error in parameter 'Vars' given to "
213 "FunctionParser::Parse()", // 7
214 "Illegal number of parameters to function", // 8
215 "Syntax error: Premature end of string", // 9
216 "Syntax error: Expecting ( after function", // 10
222 bool ParseVars(const string& Vars, map<string, unsigned>& dest)
224 unsigned varNumber = VarBegin;
225 unsigned ind1 = 0, ind2;
227 while(ind1 < Vars.size())
229 if(!isalpha(Vars[ind1]) && Vars[ind1]!='_') return false;
230 for(ind2=ind1+1; ind2<Vars.size() && Vars[ind2]!=','; ++ind2)
231 if(!isalnum(Vars[ind2]) && Vars[ind2]!='_') return false;
232 const string varName = Vars.substr(ind1, ind2-ind1);
234 if(dest.insert(make_pair(varName, varNumber++)).second == false)
243 bool FunctionParser::isValidName(const std::string& name)
245 if(name.empty() || (!isalpha(name[0]) && name[0] != '_')) return false;
246 for(unsigned i=0; i<name.size(); ++i)
247 if(!isalnum(name[i]) && name[i] != '_') return false;
249 if(FindFunction(name.c_str())) return false;
256 bool FunctionParser::AddConstant(const string& name, double value)
258 if(isValidName(name))
260 const char* n = name.c_str();
261 if(FindVariable(n, FuncParserNames) != FuncParserNames.end() ||
262 FindVariable(n, FuncPtrNames) != FuncPtrNames.end())
265 Constants[name] = value;
272 bool FunctionParser::AddFunction(const std::string& name,
273 FunctionPtr func, unsigned paramsAmount)
275 if(paramsAmount == 0) return false; // Currently must be at least one
277 if(isValidName(name))
279 const char* n = name.c_str();
280 if(FindVariable(n, FuncParserNames) != FuncParserNames.end() ||
281 FindConstant(n) != Constants.end())
284 FuncPtrNames[name] = FuncPtrs.size();
285 FuncPtrs.push_back(FuncPtrData(func, paramsAmount));
291 bool FunctionParser::checkRecursiveLinking(const FunctionParser* fp)
293 if(fp == this) return true;
294 for(unsigned i=0; i<fp->FuncParsers.size(); ++i)
295 if(checkRecursiveLinking(fp->FuncParsers[i])) return true;
299 bool FunctionParser::AddFunction(const std::string& name,
300 FunctionParser& parser)
302 if(parser.varAmount == 0) return false; // Currently must be at least one
304 if(isValidName(name))
306 const char* n = name.c_str();
307 if(FindVariable(n, FuncPtrNames) != FuncPtrNames.end() ||
308 FindConstant(n) != Constants.end())
311 if(checkRecursiveLinking(&parser)) return false;
313 FuncParserNames[name] = FuncParsers.size();
314 FuncParsers.push_back(&parser);
322 // Main parsing function
323 // ---------------------
324 int FunctionParser::Parse(const std::string& Function,
325 const std::string& Vars,
330 if(!ParseVars(Vars, Variables))
333 return Function.size();
335 varAmount = Variables.size(); // this is for Eval()
337 const char* Func = Function.c_str();
341 int Result = CheckSyntax(Func);
342 if(Result>=0) return Result;
344 useDegreeConversion = useDegrees;
345 if(!Compile(Func)) return Function.size();
355 // Is given char an operator?
356 inline bool IsOperator(int c)
358 return strchr("+-*/%^=<>&|,",c)!=NULL;
362 inline void sws(const char* F, int& Ind)
364 while(F[Ind] && F[Ind] == ' ') ++Ind;
368 // Returns an iterator to the variable with the same name as 'F', or to
369 // Variables.end() if no such variable exists:
370 inline FunctionParser::VarMap_t::const_iterator
371 FunctionParser::FindVariable(const char* F, const VarMap_t& vars)
376 while(isalnum(F[ind]) || F[ind] == '_') ++ind;
380 return vars.find(name);
386 inline FunctionParser::ConstMap_t::const_iterator
387 FunctionParser::FindConstant(const char* F)
392 while(isalnum(F[ind]) || F[ind] == '_') ++ind;
396 return Constants.find(name);
399 return Constants.end();
402 //---------------------------------------------------------------------------
403 // Check function string syntax
404 // ----------------------------
405 int FunctionParser::CheckSyntax(const char* Function)
407 int Ind=0, ParenthCnt=0, c;
415 // Check for valid operand (must appear)
417 // Check for leading -
418 if(c=='-') { sws(Function, ++Ind); c=Function[Ind]; }
419 if(c==0) { ParseErrorType=9; return Ind; }
421 // Check for math function
422 bool foundFunc = false;
423 const FuncDefinition* fptr = FindFunction(&Function[Ind]);
426 Ind += fptr->nameLength;
431 // Check for user-defined function
432 VarMap_t::const_iterator fIter =
433 FindVariable(&Function[Ind], FuncPtrNames);
434 if(fIter != FuncPtrNames.end())
436 Ind += fIter->first.size();
441 VarMap_t::const_iterator pIter =
442 FindVariable(&Function[Ind], FuncParserNames);
443 if(pIter != FuncParserNames.end())
445 Ind += pIter->first.size();
455 if(c!='(') { ParseErrorType=10; return Ind; }
458 // Check for opening parenthesis
462 sws(Function, ++Ind);
463 if(Function[Ind]==')') { ParseErrorType=3; return Ind; }
468 if(isdigit(c) || (c=='.' && isdigit(Function[Ind+1])))
470 strtod(&Function[Ind], &Ptr);
471 Ind += int(Ptr-&Function[Ind]);
476 { // Check for variable
477 VarMap_t::const_iterator vIter =
478 FindVariable(&Function[Ind], Variables);
479 if(vIter != Variables.end())
480 Ind += vIter->first.size();
483 // Check for constant
484 ConstMap_t::const_iterator cIter =
485 FindConstant(&Function[Ind]);
486 if(cIter != Constants.end())
487 Ind += cIter->first.size();
489 { ParseErrorType=0; return Ind; }
495 // Check for closing parenthesis
498 if((--ParenthCnt)<0) { ParseErrorType=1; return Ind; }
499 sws(Function, ++Ind);
503 // If we get here, we have a legal operand and now a legal operator or
504 // end of string must follow
507 if(c==0) break; // The only way to end the checking loop without error
508 // Check for operator
509 if(!IsOperator(c)) { ParseErrorType=4; return Ind; }
511 // If we get here, we have an operand and an operator; the next loop will
512 // check for another operand (must appear)
516 // Check that all opened parentheses are also closed
517 if(ParenthCnt>0) { ParseErrorType=2; return Ind; }
525 // Compile function string to bytecode
526 // -----------------------------------
527 bool FunctionParser::Compile(const char* Function)
529 if(Comp.ByteCode) { delete[] Comp.ByteCode; Comp.ByteCode=0; }
530 if(Comp.Immed) { delete[] Comp.Immed; Comp.Immed=0; }
531 if(Comp.Stack) { delete[] Comp.Stack; Comp.Stack=0; }
533 vector<unsigned> byteCode; byteCode.reserve(1024);
534 tempByteCode = &byteCode;
536 vector<double> immed; immed.reserve(1024);
539 Comp.StackSize = Comp.StackPtr = 0;
541 CompileExpression(Function, 0);
542 if(ParseErrorType >= 0) return false;
544 Comp.ByteCodeSize = byteCode.size();
545 Comp.ImmedSize = immed.size();
547 if(Comp.ByteCodeSize)
549 Comp.ByteCode = new unsigned[Comp.ByteCodeSize];
550 memcpy(Comp.ByteCode, &byteCode[0],
551 sizeof(unsigned)*Comp.ByteCodeSize);
555 Comp.Immed = new double[Comp.ImmedSize];
556 memcpy(Comp.Immed, &immed[0],
557 sizeof(double)*Comp.ImmedSize);
560 Comp.Stack = new double[Comp.StackSize];
566 inline void FunctionParser::AddCompiledByte(unsigned c)
568 tempByteCode->push_back(c);
571 inline void FunctionParser::AddImmediate(double i)
573 tempImmed->push_back(i);
576 inline void FunctionParser::AddFunctionOpcode(unsigned opcode)
578 if(useDegreeConversion)
590 AddCompiledByte(cRad);
593 AddCompiledByte(opcode);
595 if(useDegreeConversion)
607 AddCompiledByte(cDeg);
612 int FunctionParser::CompileIf(const char* F, int ind)
614 int ind2 = CompileExpression(F, ind, true); // condition
616 if(F[ind2] != ',') { ParseErrorType=8; return ind2; }
617 AddCompiledByte(cIf);
618 unsigned curByteCodeSize = tempByteCode->size();
619 AddCompiledByte(0); // Jump index; to be set later
620 AddCompiledByte(0); // Immed jump index; to be set later
624 ind2 = CompileExpression(F, ind2+1, true); // then
626 if(F[ind2] != ',') { ParseErrorType=8; return ind2; }
627 AddCompiledByte(cJump);
628 unsigned curByteCodeSize2 = tempByteCode->size();
629 unsigned curImmedSize2 = tempImmed->size();
630 AddCompiledByte(0); // Jump index; to be set later
631 AddCompiledByte(0); // Immed jump index; to be set later
635 ind2 = CompileExpression(F, ind2+1, true); // else
637 if(F[ind2] != ')') { ParseErrorType=8; return ind2; }
640 (*tempByteCode)[curByteCodeSize] = curByteCodeSize2+1;
641 (*tempByteCode)[curByteCodeSize+1] = curImmedSize2;
642 (*tempByteCode)[curByteCodeSize2] = tempByteCode->size()-1;
643 (*tempByteCode)[curByteCodeSize2+1] = tempImmed->size();
648 int FunctionParser::CompileFunctionParams(const char* F, int ind,
649 unsigned requiredParams)
651 unsigned curStackPtr = Comp.StackPtr;
652 int ind2 = CompileExpression(F, ind);
654 if(Comp.StackPtr != curStackPtr+requiredParams)
655 { ParseErrorType=8; return ind; }
657 Comp.StackPtr -= requiredParams - 1;
659 return ind2+1; // F[ind2] is ')'
663 int FunctionParser::CompileElement(const char* F, int ind)
670 ind = CompileExpression(F, ind+1);
672 return ind+1; // F[ind] is ')'
677 if(!isdigit(c2) && c2!='.')
679 int ind2 = CompileElement(F, ind+1);
680 AddCompiledByte(cNeg);
685 if(isdigit(c) || c=='.' || c=='-') // Number
687 const char* startPtr = &F[ind];
689 double val = strtod(startPtr, &endPtr);
691 AddCompiledByte(cImmed);
692 ++Comp.StackPtr; if(Comp.StackPtr>Comp.StackSize) Comp.StackSize++;
693 return ind+(endPtr-startPtr);
696 if(isalpha(c) || c == '_') // Function, variable or constant
698 const FuncDefinition* func = FindFunction(F+ind);
699 if(func) // is function
701 int ind2 = ind + func->nameLength;
702 sws(F, ind2); // F[ind2] is '('
703 if(strcmp(func->name, "if") == 0) // "if" is a special case
705 return CompileIf(F, ind2+1);
709 unsigned requiredParams =
710 strcmp(func->name, "eval") == 0 ?
711 Variables.size() : func->params;
713 unsigned requiredParams = func->params;
715 ind2 = CompileFunctionParams(F, ind2+1, requiredParams);
716 AddFunctionOpcode(func->opcode);
717 return ind2; // F[ind2-1] is ')'
720 VarMap_t::const_iterator vIter = FindVariable(F+ind, Variables);
721 if(vIter != Variables.end()) // is variable
723 AddCompiledByte(vIter->second);
724 ++Comp.StackPtr; if(Comp.StackPtr>Comp.StackSize) Comp.StackSize++;
725 return ind + vIter->first.size();
728 ConstMap_t::const_iterator cIter = FindConstant(F+ind);
729 if(cIter != Constants.end()) // is constant
731 AddImmediate(cIter->second);
732 AddCompiledByte(cImmed);
733 ++Comp.StackPtr; if(Comp.StackPtr>Comp.StackSize) Comp.StackSize++;
734 return ind + cIter->first.size();
737 VarMap_t::const_iterator fIter = FindVariable(F+ind, FuncPtrNames);
738 if(fIter != FuncPtrNames.end()) // is user-defined function pointer
740 unsigned index = fIter->second;
742 int ind2 = ind + fIter->first.length();
743 sws(F, ind2); // F[ind2] is '('
745 ind2 = CompileFunctionParams(F, ind2+1, FuncPtrs[index].params);
747 AddCompiledByte(cFCall);
748 AddCompiledByte(index);
752 VarMap_t::const_iterator pIter = FindVariable(F+ind, FuncParserNames);
753 if(pIter != FuncParserNames.end()) // is user-defined function parser
755 unsigned index = pIter->second;
757 int ind2 = ind + pIter->first.length();
758 sws(F, ind2); // F[ind2] is '('
760 ind2 = CompileFunctionParams(F, ind2+1,
761 FuncParsers[index]->varAmount);
763 AddCompiledByte(cPCall);
764 AddCompiledByte(index);
774 int FunctionParser::CompilePow(const char* F, int ind)
776 int ind2 = CompileElement(F, ind);
779 while(F[ind2] == '^')
781 ind2 = CompileElement(F, ind2+1);
783 AddCompiledByte(cPow);
790 // Compiles '*', '/' and '%'
791 int FunctionParser::CompileMult(const char* F, int ind)
793 int ind2 = CompilePow(F, ind);
797 while((op = F[ind2]) == '*' || op == '/' || op == '%')
799 ind2 = CompilePow(F, ind2+1);
803 case '*': AddCompiledByte(cMul); break;
804 case '/': AddCompiledByte(cDiv); break;
805 case '%': AddCompiledByte(cMod); break;
813 // Compiles '+' and '-'
814 int FunctionParser::CompileAddition(const char* F, int ind)
816 int ind2 = CompileMult(F, ind);
820 while((op = F[ind2]) == '+' || op == '-')
822 ind2 = CompileMult(F, ind2+1);
824 AddCompiledByte(op=='+' ? cAdd : cSub);
831 // Compiles '=', '<' and '>'
832 int FunctionParser::CompileComparison(const char* F, int ind)
834 int ind2 = CompileAddition(F, ind);
838 while((op = F[ind2]) == '=' || op == '<' || op == '>')
840 ind2 = CompileAddition(F, ind2+1);
844 case '=': AddCompiledByte(cEqual); break;
845 case '<': AddCompiledByte(cLess); break;
846 case '>': AddCompiledByte(cGreater); break;
855 int FunctionParser::CompileAnd(const char* F, int ind)
857 int ind2 = CompileComparison(F, ind);
860 while(F[ind2] == '&')
862 ind2 = CompileComparison(F, ind2+1);
864 AddCompiledByte(cAnd);
872 int FunctionParser::CompileOr(const char* F, int ind)
874 int ind2 = CompileAnd(F, ind);
877 while(F[ind2] == '|')
879 ind2 = CompileAnd(F, ind2+1);
881 AddCompiledByte(cOr);
889 int FunctionParser::CompileExpression(const char* F, int ind, bool stopAtComma)
891 int ind2 = CompileOr(F, ind);
894 if(stopAtComma) return ind2;
896 while(F[ind2] == ',')
898 ind2 = CompileOr(F, ind2+1);
906 // Return parse error message
907 // --------------------------
908 const char* FunctionParser::ErrorMsg(void) const
910 if(ParseErrorType>=0) return ParseErrorMessage[ParseErrorType];
914 //---------------------------------------------------------------------------
915 // Function evaluation
916 //---------------------------------------------------------------------------
917 //===========================================================================
920 inline int doubleToInt(double d)
922 return d<0 ? -int((-d)+.5) : int(d+.5);
925 inline double Min(double d1, double d2)
927 return d1<d2 ? d1 : d2;
929 inline double Max(double d1, double d2)
931 return d1>d2 ? d1 : d2;
935 inline double DegreesToRadians(double degrees)
937 return degrees*(M_PI/180.0);
939 inline double RadiansToDegrees(double radians)
941 return radians*(180.0/M_PI);
945 double FunctionParser::Eval(const double* Vars)
950 for(IP=0; IP<Comp.ByteCodeSize; IP++)
952 switch(Comp.ByteCode[IP])
955 case cAbs: Comp.Stack[SP]=fabs(Comp.Stack[SP]); break;
956 case cAcos: if(Comp.Stack[SP]<-1 || Comp.Stack[SP]>1)
957 { EvalErrorType=4; return 0; }
958 Comp.Stack[SP]=acos(Comp.Stack[SP]); break;
960 case cAcosh: Comp.Stack[SP]=acosh(Comp.Stack[SP]); break;
962 case cAsin: if(Comp.Stack[SP]<-1 || Comp.Stack[SP]>1)
963 { EvalErrorType=4; return 0; }
964 Comp.Stack[SP]=asin(Comp.Stack[SP]); break;
966 case cAsinh: Comp.Stack[SP]=asinh(Comp.Stack[SP]); break;
968 case cAtan: Comp.Stack[SP]=atan(Comp.Stack[SP]); break;
969 case cAtan2: Comp.Stack[SP-1]=atan2(Comp.Stack[SP-1],Comp.Stack[SP]);
972 case cAtanh: Comp.Stack[SP]=atanh(Comp.Stack[SP]); break;
974 case cCeil: Comp.Stack[SP]=ceil(Comp.Stack[SP]); break;
975 case cCos: Comp.Stack[SP]=cos(Comp.Stack[SP]); break;
976 case cCosh: Comp.Stack[SP]=cosh(Comp.Stack[SP]); break;
980 double t = tan(Comp.Stack[SP]);
981 if(t == 0) { EvalErrorType=1; return 0; }
982 Comp.Stack[SP] = 1/t; break;
986 double s = sin(Comp.Stack[SP]);
987 if(s == 0) { EvalErrorType=1; return 0; }
988 Comp.Stack[SP] = 1/s; break;
995 double* tmpStack = Comp.Stack;
996 Comp.Stack = new double[Comp.StackSize];
997 double retVal = Eval(&tmpStack[SP-varAmount+1]);
999 Comp.Stack = tmpStack;
1001 Comp.Stack[SP] = retVal;
1006 case cExp: Comp.Stack[SP]=exp(Comp.Stack[SP]); break;
1007 case cFloor: Comp.Stack[SP]=floor(Comp.Stack[SP]); break;
1011 unsigned jumpAddr = Comp.ByteCode[++IP];
1012 unsigned immedAddr = Comp.ByteCode[++IP];
1013 if(doubleToInt(Comp.Stack[SP]) == 0)
1021 case cInt: Comp.Stack[SP]=floor(Comp.Stack[SP]+.5); break;
1022 case cLog: if(Comp.Stack[SP]<=0) { EvalErrorType=3; return 0; }
1023 Comp.Stack[SP]=log(Comp.Stack[SP]); break;
1024 case cLog10: if(Comp.Stack[SP]<=0) { EvalErrorType=3; return 0; }
1025 Comp.Stack[SP]=log10(Comp.Stack[SP]); break;
1026 case cMax: Comp.Stack[SP-1]=Max(Comp.Stack[SP-1],Comp.Stack[SP]);
1028 case cMin: Comp.Stack[SP-1]=Min(Comp.Stack[SP-1],Comp.Stack[SP]);
1032 double c = cos(Comp.Stack[SP]);
1033 if(c == 0) { EvalErrorType=1; return 0; }
1034 Comp.Stack[SP] = 1/c; break;
1036 case cSin: Comp.Stack[SP]=sin(Comp.Stack[SP]); break;
1037 case cSinh: Comp.Stack[SP]=sinh(Comp.Stack[SP]); break;
1038 case cSqrt: if(Comp.Stack[SP]<0) { EvalErrorType=2; return 0; }
1039 Comp.Stack[SP]=sqrt(Comp.Stack[SP]); break;
1040 case cTan: Comp.Stack[SP]=tan(Comp.Stack[SP]); break;
1041 case cTanh: Comp.Stack[SP]=tanh(Comp.Stack[SP]); break;
1045 case cImmed: Comp.Stack[++SP]=Comp.Immed[DP++]; break;
1046 case cJump: DP = Comp.ByteCode[IP+2];
1047 IP = Comp.ByteCode[IP+1];
1051 case cNeg: Comp.Stack[SP]=-Comp.Stack[SP]; break;
1052 case cAdd: Comp.Stack[SP-1]+=Comp.Stack[SP]; SP--; break;
1053 case cSub: Comp.Stack[SP-1]-=Comp.Stack[SP]; SP--; break;
1054 case cMul: Comp.Stack[SP-1]*=Comp.Stack[SP]; SP--; break;
1055 case cDiv: if(Comp.Stack[SP]==0) { EvalErrorType=1; return 0; }
1056 Comp.Stack[SP-1]/=Comp.Stack[SP]; SP--; break;
1057 case cMod: if(Comp.Stack[SP]==0) { EvalErrorType=1; return 0; }
1058 Comp.Stack[SP-1]=fmod(Comp.Stack[SP-1],Comp.Stack[SP]);
1060 case cPow: Comp.Stack[SP-1]=pow(Comp.Stack[SP-1],Comp.Stack[SP]);
1063 case cEqual: Comp.Stack[SP-1] = (Comp.Stack[SP-1]==Comp.Stack[SP]);
1065 case cLess: Comp.Stack[SP-1] = (Comp.Stack[SP-1]<Comp.Stack[SP]);
1067 case cGreater: Comp.Stack[SP-1] = (Comp.Stack[SP-1]>Comp.Stack[SP]);
1069 case cAnd: Comp.Stack[SP-1] =
1070 (doubleToInt(Comp.Stack[SP-1]) &&
1071 doubleToInt(Comp.Stack[SP]));
1073 case cOr: Comp.Stack[SP-1] =
1074 (doubleToInt(Comp.Stack[SP-1]) ||
1075 doubleToInt(Comp.Stack[SP]));
1078 // Degrees-radians conversion:
1079 case cDeg: Comp.Stack[SP]=RadiansToDegrees(Comp.Stack[SP]); break;
1080 case cRad: Comp.Stack[SP]=DegreesToRadians(Comp.Stack[SP]); break;
1082 // User-defined function calls:
1085 unsigned index = Comp.ByteCode[++IP];
1086 unsigned params = FuncPtrs[index].params;
1088 FuncPtrs[index].ptr(&Comp.Stack[SP-params+1]);
1090 Comp.Stack[SP] = retVal;
1096 unsigned index = Comp.ByteCode[++IP];
1097 unsigned params = FuncParsers[index]->varAmount;
1099 FuncParsers[index]->Eval(&Comp.Stack[SP-params+1]);
1101 Comp.Stack[SP] = retVal;
1106 #ifdef SUPPORT_OPTIMIZER
1107 case cVar: break; // Paranoia. These should never exist
1108 case cDup: Comp.Stack[SP+1]=Comp.Stack[SP]; ++SP; break;
1110 if(Comp.Stack[SP]==0.0) { EvalErrorType=1; return 0; }
1111 Comp.Stack[SP]=1.0/Comp.Stack[SP];
1117 Comp.Stack[++SP]=Vars[Comp.ByteCode[IP]-VarBegin];
1122 return Comp.Stack[SP];
1126 void FunctionParser::PrintByteCode(std::ostream& dest) const
1128 for(unsigned IP=0, DP=0; IP<Comp.ByteCodeSize; IP++)
1130 dest.width(8); dest.fill('0'); hex(dest); //uppercase(dest);
1133 unsigned opcode = Comp.ByteCode[IP];
1139 dest.width(8); dest.fill('0'); hex(dest); //uppercase(dest);
1140 dest << Comp.ByteCode[IP+1]+1 << endl;
1146 dest.width(8); dest.fill('0'); hex(dest); //uppercase(dest);
1147 dest << Comp.ByteCode[IP+1]+1 << endl;
1152 dest << "push\t" << Comp.Immed[DP++] << endl;
1157 unsigned index = Comp.ByteCode[++IP];
1158 VarMap_t::const_iterator iter = FuncPtrNames.begin();
1159 while(iter->second != index) ++iter;
1160 dest << "call\t" << iter->first << endl;
1166 unsigned index = Comp.ByteCode[++IP];
1167 VarMap_t::const_iterator iter = FuncParserNames.begin();
1168 while(iter->second != index) ++iter;
1169 dest << "call\t" << iter->first << endl;
1174 if(opcode < VarBegin)
1179 case cNeg: n = "neg"; break;
1180 case cAdd: n = "add"; break;
1181 case cSub: n = "sub"; break;
1182 case cMul: n = "mul"; break;
1183 case cDiv: n = "div"; break;
1184 case cMod: n = "mod"; break;
1185 case cPow: n = "pow"; break;
1186 case cEqual: n = "eq"; break;
1187 case cLess: n = "lt"; break;
1188 case cGreater: n = "gt"; break;
1189 case cAnd: n = "and"; break;
1190 case cOr: n = "or"; break;
1191 case cDeg: n = "deg"; break;
1192 case cRad: n = "rad"; break;
1194 #ifndef DISABLE_EVAL
1195 case cEval: n = "call\t0"; break;
1198 #ifdef SUPPORT_OPTIMIZER
1199 case cVar: n = "(var)"; break;
1200 case cDup: n = "dup"; break;
1201 case cInv: n = "inv"; break;
1204 default: n = Functions[opcode-cAbs].name;
1210 dest << "push\tVar" << opcode-VarBegin << endl;
1218 //========================================================================
1219 // Optimization code was contributed by Bisqwit (http://iki.fi/bisqwit/)
1220 //========================================================================
1221 #ifdef SUPPORT_OPTIMIZER
1226 #define CONSTANT_E 2.71828182845904509080 // exp(1)
1227 #define CONSTANT_PI M_PI // atan2(0,-1)
1228 #define CONSTANT_L10 2.30258509299404590109 // log(10)
1229 #define CONSTANT_L10I 0.43429448190325176116 // 1/log(10)
1230 #define CONSTANT_L10E CONSTANT_L10I // log10(e)
1231 #define CONSTANT_L10EI CONSTANT_L10 // 1/log10(e)
1232 #define CONSTANT_DR (180.0 / M_PI) // 180/pi
1233 #define CONSTANT_RD (M_PI / 180.0) // pi/180
1237 // states: 0=false, 1=true, 2=unknown
1239 compres(bool b) : state(b) {}
1240 compres(char v) : state(v) {}
1242 operator bool() const { return state != 0; }
1244 bool operator! () const { return state != 1; }
1245 bool operator==(bool b) const { return state != !b; }
1246 bool operator!=(bool b) const { return state != b; }
1252 const compres maybe = (char)2;
1257 struct CodeTree *tree;
1258 bool sign; // Only possible when parent is cAdd or cMul
1260 inline void flipsign() { sign = !sign; }
1263 SubTree(double value);
1264 SubTree(const SubTree &b);
1265 SubTree(const struct CodeTree &b);
1268 const SubTree &operator= (const SubTree &b);
1269 const SubTree &operator= (const CodeTree &b);
1271 bool getsign() const { return sign; }
1273 const struct CodeTree* operator-> () const { return tree; }
1274 const struct CodeTree& operator* () const { return *tree; }
1275 struct CodeTree* operator-> () { return tree; }
1276 struct CodeTree& operator* () { return *tree; }
1278 bool operator< (const SubTree& b) const;
1279 bool operator== (const SubTree& b) const;
1280 void Negate(); // Note: Parent must be cAdd
1281 void Invert(); // Note: Parent must be cMul
1283 void CheckConstNeg();
1284 void CheckConstInv();
1288 bool IsNegate(const SubTree &p1, const SubTree &p2);
1289 bool IsInverse(const SubTree &p1, const SubTree &p2);
1292 typedef list<SubTree> paramlist;
1299 unsigned op; // Operation
1300 double value; // In case of cImmed
1301 unsigned var; // In case of cVar
1302 unsigned funcno; // In case of cFCall, cPCall
1305 CodeTreeData() : op(cAdd) {}
1308 void SetOp(unsigned newop) { op=newop; }
1309 void SetFuncNo(unsigned newno) { funcno=newno; }
1310 unsigned GetFuncNo() const { return funcno; }
1312 bool IsFunc() const { return op == cFCall || op == cPCall; }
1313 bool IsImmed() const { return op == cImmed; }
1314 bool IsVar() const { return op == cVar; }
1315 inline unsigned GetOp() const { return op; }
1316 inline double GetImmed() const
1320 inline unsigned GetVar() const
1325 void AddParam(const SubTree &p)
1329 void SetVar(unsigned v)
1335 void SetImmed(double v)
1340 inverted = negated = false;
1349 inverted = !inverted;
1353 bool IsOriginal() const { return !(IsInverted() || IsNegated()); }
1354 bool IsInverted() const { return inverted; }
1355 bool IsNegated() const { return negated; }
1356 bool IsInvertedOriginal() const { return IsInverted() && !IsNegated(); }
1357 bool IsNegatedOriginal() const { return !IsInverted() && IsNegated(); }
1363 if(IsInverted()) { value = 1.0 / value;
1364 // FIXME: potential divide by zero.
1366 if(IsNegated()) value = -value;
1373 // Ensure we don't accidentally copy this
1374 void operator=(const CodeTreeData &b);
1377 class CodeTreeDataPtr
1379 typedef pair<CodeTreeData, unsigned> p_t;
1383 void Alloc() const { ++p->second; }
1384 void Dealloc() const { if(!--p->second) delete p; p = 0; }
1386 void PrepareForWrite()
1388 // We're ready if we're the only owner.
1389 if(p->second == 1) return;
1391 // Then make a clone.
1392 p_t *newtree = new p_t(p->first, 1);
1400 CodeTreeDataPtr() : p(new p_t) { p->second = 1; }
1401 CodeTreeDataPtr(const CodeTreeDataPtr &b): p(b.p) { Alloc(); }
1402 ~CodeTreeDataPtr() { Dealloc(); }
1403 const CodeTreeDataPtr &operator= (const CodeTreeDataPtr &b)
1410 const CodeTreeData *operator-> () const { return &p->first; }
1411 const CodeTreeData &operator* () const { return p->first; }
1412 CodeTreeData *operator-> () { PrepareForWrite(); return &p->first; }
1413 CodeTreeData &operator* () { PrepareForWrite(); return p->first; }
1418 #define CHECKCONSTNEG(item, op) \
1420 ? (item).CheckConstInv() \
1421 : (item).CheckConstNeg()
1425 CodeTreeDataPtr data;
1428 typedef paramlist::iterator pit;
1429 typedef paramlist::const_iterator pcit;
1431 template<unsigned v> inline void chk() const
1436 const pcit GetBegin() const { return data->args.begin(); }
1437 const pcit GetEnd() const { return data->args.end(); }
1438 const pit GetBegin() { return data->args.begin(); }
1439 const pit GetEnd() { return data->args.end(); }
1440 const SubTree& getp0() const { chk<1>();pcit tmp=GetBegin(); return *tmp; }
1441 const SubTree& getp1() const { chk<2>();pcit tmp=GetBegin(); ++tmp; return *tmp; }
1442 const SubTree& getp2() const { chk<3>();pcit tmp=GetBegin(); ++tmp; ++tmp; return *tmp; }
1443 unsigned GetArgCount() const { return data->args.size(); }
1444 void Erase(const pit p) { data->args.erase(p); }
1446 SubTree& getp0() { chk<1>();pit tmp=GetBegin(); return *tmp; }
1447 SubTree& getp1() { chk<2>();pit tmp=GetBegin(); ++tmp; return *tmp; }
1448 SubTree& getp2() { chk<3>();pit tmp=GetBegin(); ++tmp; ++tmp; return *tmp; }
1451 void SetImmed(double v) { data->SetImmed(v); }
1452 void SetOp(unsigned op) { data->SetOp(op); }
1453 void SetVar(unsigned v) { data->SetVar(v); }
1455 double GetImmed() const { return data->GetImmed(); }
1456 unsigned GetVar() const { return data->GetVar(); }
1457 unsigned GetOp() const { return data->GetOp(); }
1459 bool IsImmed() const { return data->IsImmed(); }
1460 bool IsVar() const { return data->IsVar(); }
1462 void AddParam(const SubTree &p) { data->AddParam(p); }
1463 void NegateImmed() { data->NegateImmed(); } // don't use when op!=cImmed
1464 void InvertImmed() { data->InvertImmed(); } // don't use when op!=cImmed
1466 compres NonZero() const { if(!IsImmed()) return maybe;
1467 return GetImmed() != 0.0; }
1468 compres IsPositive() const { if(!IsImmed()) return maybe;
1469 return GetImmed() > 0.0; }
1477 unsigned size() const { return cp.size(); }
1479 struct ConstList BuildConstList();
1480 void KillConst(const ConstList &cl)
1482 for(list<pit>::const_iterator i=cl.cp.begin(); i!=cl.cp.end(); ++i)
1485 void FinishConst(const ConstList &cl)
1487 if(cl.value != cl.voidvalue && cl.size() > 1) AddParam(cl.value);
1488 if(cl.value == cl.voidvalue || cl.size() > 1) KillConst(cl);
1493 CodeTree(double v) { SetImmed(v); }
1495 CodeTree(unsigned op, const SubTree &p)
1500 CodeTree(unsigned op, const SubTree &p1, const SubTree &p2)
1507 bool operator== (const CodeTree& b) const;
1508 bool operator< (const CodeTree& b) const;
1511 bool IsSortable() const
1515 case cAdd: case cMul:
1517 case cAnd: case cOr:
1518 case cMax: case cMin:
1524 void SortIfPossible()
1532 void ReplaceWithConst(double value)
1536 /* REMEMBER TO CALL CheckConstInv / CheckConstNeg
1537 * FOR PARENT SubTree, OR MAYHEM HAPPENS
1541 void ReplaceWith(const CodeTree &b)
1543 // If b is child of *this, mayhem
1544 // happens. So we first make a clone
1545 // and then proceed with copy.
1546 CodeTreeDataPtr tmp = b.data;
1551 void ReplaceWith(unsigned op, const SubTree &p)
1553 ReplaceWith(CodeTree(op, p));
1556 void ReplaceWith(unsigned op, const SubTree &p1, const SubTree &p2)
1558 ReplaceWith(CodeTree(op, p1, p2));
1561 void OptimizeConflict()
1563 // This optimization does this: x-x = 0, x/x = 1, a+b-a = b.
1565 if(GetOp() == cAdd || GetOp() == cMul)
1569 for(a=GetBegin(); a!=GetEnd(); ++a)
1571 for(b=GetBegin(); ++b != GetEnd(); )
1573 const SubTree &p1 = *a;
1574 const SubTree &p2 = *b;
1576 if(GetOp() == cMul ? IsInverse(p1,p2)
1579 // These parameters complement each others out
1587 OptimizeRedundant();
1590 void OptimizeRedundant()
1592 // This optimization does this: min()=0, max()=0, add()=0, mul()=1
1596 if(GetOp() == cAdd || GetOp() == cMin || GetOp() == cMax)
1597 ReplaceWithConst(0);
1598 else if(GetOp() == cMul)
1599 ReplaceWithConst(1);
1603 // And this: mul(x) = x, min(x) = x, max(x) = x, add(x) = x
1605 if(GetArgCount() == 1)
1607 if(GetOp() == cMul || GetOp() == cAdd || GetOp() == cMin || GetOp() == cMax)
1608 if(!getp0().getsign())
1609 ReplaceWith(*getp0());
1612 OptimizeDoubleNegations();
1615 void OptimizeDoubleNegations()
1619 // Eschew double negations
1621 // If any of the elements is cMul
1622 // and has a numeric constant, negate
1623 // the constant and negate sign.
1625 for(pit a=GetBegin(); a!=GetEnd(); ++a)
1629 && pa->GetOp() == cMul)
1632 for(pit b=p.GetBegin();
1649 // If any of the elements is cPow
1650 // and has a numeric exponent, negate
1651 // the exponent and negate sign.
1653 for(pit a=GetBegin(); a!=GetEnd(); ++a)
1656 if(pa.getsign() && pa->GetOp() == cPow)
1659 if(p.getp1()->IsImmed())
1661 // negate ok for pow when op=cImmed
1670 void OptimizeConstantMath1()
1672 // This optimization does three things:
1673 // - For adding groups:
1674 // Constants are added together.
1675 // - For multiplying groups:
1676 // Constants are multiplied together.
1677 // - For function calls:
1678 // If all parameters are constants,
1679 // the call is replaced with constant value.
1682 OptimizeAddMulFlat();
1688 ConstList cl = BuildConstList();
1694 ConstList cl = BuildConstList();
1696 if(cl.value == 0.0) ReplaceWithConst(0.0);
1697 else FinishConst(cl);
1701 #define ConstantUnaryFun(token, fun) \
1702 case token: { const SubTree &p0 = getp0(); \
1703 if(p0->IsImmed()) ReplaceWithConst(fun(p0->GetImmed())); \
1705 #define ConstantBinaryFun(token, fun) \
1706 case token: { const SubTree &p0 = getp0(); \
1707 const SubTree &p1 = getp1(); \
1708 if(p0->IsImmed() && \
1709 p1->IsImmed()) ReplaceWithConst(fun(p0->GetImmed(), p1->GetImmed())); \
1712 // FIXME: potential invalid parameters for functions
1713 // can cause exceptions here
1715 ConstantUnaryFun(cAbs, fabs);
1716 ConstantUnaryFun(cAcos, acos);
1717 ConstantUnaryFun(cAsin, asin);
1718 ConstantUnaryFun(cAtan, atan);
1719 ConstantUnaryFun(cCeil, ceil);
1720 ConstantUnaryFun(cCos, cos);
1721 ConstantUnaryFun(cCosh, cosh);
1722 ConstantUnaryFun(cFloor, floor);
1723 ConstantUnaryFun(cLog, log);
1724 ConstantUnaryFun(cSin, sin);
1725 ConstantUnaryFun(cSinh, sinh);
1726 ConstantUnaryFun(cTan, tan);
1727 ConstantUnaryFun(cTanh, tanh);
1728 ConstantBinaryFun(cAtan2, atan2);
1729 ConstantBinaryFun(cMax, Max);
1730 ConstantBinaryFun(cMin, Min);
1731 ConstantBinaryFun(cMod, fmod); // not a func, but belongs here too
1732 ConstantBinaryFun(cPow, pow);
1737 /* Unreached (nonexistent operator)
1738 * TODO: internal error here?
1750 /* Unreached (nonexistent function)
1751 * TODO: internal error here?
1759 void OptimizeAddMulFlat()
1761 // This optimization flattens the topography of the tree.
1763 // x + (y+z) = x+y+z
1764 // x * (y/z) = x*y/z
1765 // x / (y/z) = x/y*z
1767 if(GetOp() == cAdd || GetOp() == cMul)
1769 // If children are same type as parent add them here
1770 for(pit b, a=GetBegin(); a!=GetEnd(); a=b)
1772 const SubTree &pa = *a; b=a; ++b;
1773 if(pa->GetOp() != GetOp()) continue;
1775 // Child is same type
1776 for(pcit c=pa->GetBegin();
1780 const SubTree &pb = *c;
1784 // means b and c will be negated
1798 // Note: OptimizeConstantMath1() would be a good thing to call next.
1803 void OptimizeLinearCombine()
1805 // This optimization does the following:
1813 // Remove conflicts first, so we don't have to worry about signs.
1816 bool didchanges = false;
1817 if(GetOp() == cAdd || GetOp() == cMul)
1820 for(pit a=GetBegin(); a!=GetEnd(); ++a)
1822 const SubTree &pa = *a;
1826 for(pit b=a; ++b!=GetEnd(); )
1828 const SubTree &pb = *b;
1830 poslist.push_back(b);
1834 if(poslist.size() >= min)
1837 bool negate = arvo.getsign();
1839 double factor = poslist.size() + 1;
1847 CodeTree tmp(GetOp()==cAdd ? cMul : cPow,
1851 list<pit>::const_iterator j;
1852 for(j=poslist.begin(); j!=poslist.end(); ++j)
1864 // As a result, there might be need for this:
1865 OptimizeAddMulFlat();
1867 OptimizeRedundant();
1871 void OptimizeLogarithm()
1874 This is basic logarithm math:
1876 log(X)/log(Y) = logY(X)
1878 log(X*Y) = log(X)+log(Y)
1881 This function does these optimizations:
1882 pow(const_E, log(x)) = x
1883 pow(const_E, log(x)*y) = x^y
1884 pow(10, log(x)*const_L10I*y) = x^y
1885 pow(z, log(x)/log(z)*y) = x^y
1888 log(x^z) = z * log(x)
1889 Which automatically causes these too:
1890 log(pow(const_E, x)) = x
1891 log(pow(y, x)) = x * log(y)
1892 log(pow(pow(const_E, y), x)) = x*y
1894 And it does this too:
1895 log(x) + log(y) + log(z) = log(x * y * z)
1896 log(x * exp(y)) = log(x) + y
1900 // Must be already in exponential form.
1902 // Optimize exponents before doing something.
1903 OptimizeExponents();
1907 // We should have one parameter for log() function.
1908 // If we don't, we're screwed.
1910 const SubTree &p = getp0();
1912 if(p->GetOp() == cPow)
1915 SubTree p0 = p->getp0(); // x
1916 SubTree p1 = p->getp1(); // y
1918 // Build the new logarithm.
1919 CodeTree tmp(GetOp(), p0); // log(x)
1921 // Become log(x) * y
1922 ReplaceWith(cMul, tmp, p1);
1924 else if(p->GetOp() == cMul)
1926 // Redefine &p nonconst
1927 SubTree &p = getp0();
1929 p->OptimizeAddMulFlat();
1930 p->OptimizeExponents();
1931 CHECKCONSTNEG(p, p->GetOp());
1935 for(pit b, a = p->GetBegin();
1936 a != p->GetEnd(); a=b)
1938 SubTree &pa = *a; b=a; ++b;
1939 if(pa->GetOp() == cPow
1940 && pa->getp0()->IsImmed()
1941 && pa->getp0()->GetImmed() == CONSTANT_E)
1943 adds.push_back(pa->getp1());
1950 CodeTree tmp(cAdd, *this);
1952 list<SubTree>::const_iterator i;
1953 for(i=adds.begin(); i!=adds.end(); ++i)
1962 // Check which ones are logs.
1965 for(pit a=GetBegin(); a!=GetEnd(); ++a)
1967 const SubTree &pa = *a;
1968 if(pa->GetOp() == cLog)
1969 poslist.push_back(a);
1972 if(poslist.size() >= 2)
1974 CodeTree tmp(cMul, 1.0); // eek
1976 list<pit>::const_iterator j;
1977 for(j=poslist.begin(); j!=poslist.end(); ++j)
1979 const SubTree &pb = **j;
1980 // Take all of its children
1981 for(pcit b=pb->GetBegin();
1986 if(pb.getsign()) tmp2.Negate();
1993 AddParam(CodeTree(cLog, tmp));
1999 const SubTree &p0 = getp0();
2000 SubTree &p1 = getp1();
2002 if(p0->IsImmed() && p0->GetImmed() == CONSTANT_E
2003 && p1->GetOp() == cLog)
2005 // pow(const_E, log(x)) = x
2006 ReplaceWith(*(p1->getp0()));
2008 else if(p1->GetOp() == cMul)
2010 //bool didsomething = true;
2012 pit poslogpos; bool foundposlog = false;
2013 pit neglogpos; bool foundneglog = false;
2015 ConstList cl = p1->BuildConstList();
2017 for(pit a=p1->GetBegin(); a!=p1->GetEnd(); ++a)
2019 const SubTree &pa = *a;
2020 if(pa->GetOp() == cLog)
2027 else if(*p0 == *(pa->getp0()))
2036 && p0->GetImmed() == 10.0
2037 && cl.value == CONSTANT_L10I
2040 SubTree base = (*poslogpos)->getp0();
2042 p1->Erase(poslogpos);
2043 p1->OptimizeRedundant();
2046 ReplaceWith(cPow, base, mul);
2048 // FIXME: what optimizations should be done now?
2052 // Put back the constant
2056 && p0->GetImmed() == CONSTANT_E
2059 SubTree base = (*poslogpos)->getp0();
2060 p1->Erase(poslogpos);
2062 p1->OptimizeRedundant();
2065 ReplaceWith(cPow, base, mul);
2067 // FIXME: what optimizations should be done now?
2073 && *((*neglogpos)->getp0()) == *p0)
2075 SubTree base = (*poslogpos)->getp0();
2076 p1->Erase(poslogpos);
2077 p1->Erase(neglogpos);
2079 p1->OptimizeRedundant();
2082 ReplaceWith(cPow, base, mul);
2084 // FIXME: what optimizations should be done now?
2091 void OptimizeFunctionCalls()
2093 /* Goals: sin(asin(x)) = x
2101 * Because someone might want to wrap the angle.
2106 void OptimizePowMulAdd()
2115 const SubTree &base = getp0();
2116 const SubTree &exponent = getp1();
2118 if(exponent->IsImmed())
2120 if(exponent->GetImmed() == 1.0)
2122 else if(exponent->GetImmed() == 0.0
2124 ReplaceWithConst(1.0);
2129 void OptimizeExponents()
2132 * (x^y)^z -> x^(y*z)
2133 * x^y * x^z -> x^(y+z)
2135 // First move to exponential form.
2136 OptimizeLinearCombine();
2138 bool didchanges = false;
2143 // (x^y)^z -> x^(y*z)
2145 const SubTree &p0 = getp0();
2146 const SubTree &p1 = getp1();
2147 if(p0->GetOp() == cPow)
2149 CodeTree tmp(cMul, p0->getp1(), p1);
2152 ReplaceWith(cPow, p0->getp0(), tmp);
2160 // x^y * x^z -> x^(y+z)
2162 for(pit a=GetBegin(); a!=GetEnd(); ++a)
2164 const SubTree &pa = *a;
2166 if(pa->GetOp() != cPow) continue;
2170 for(pit b=a; ++b != GetEnd(); )
2172 const SubTree &pb = *b;
2173 if(pb->GetOp() == cPow
2177 poslist.push_back(b);
2181 if(poslist.size() >= 1)
2183 poslist.push_back(a);
2185 CodeTree base = *(pa->getp0());
2187 CodeTree exponent(cAdd, 0.0); //eek
2189 // Collect all exponents to cAdd
2190 list<pit>::const_iterator i;
2191 for(i=poslist.begin(); i!=poslist.end(); ++i)
2193 const SubTree &pb = **i;
2195 SubTree tmp2 = pb->getp1();
2196 if(pb.getsign()) tmp2.Invert();
2198 exponent.AddParam(tmp2);
2201 exponent.Optimize();
2203 CodeTree result(cPow, base, exponent);
2205 for(i=poslist.begin(); i!=poslist.end(); ++i)
2209 AddParam(result); // We're cMul, remember
2217 OptimizePowMulAdd();
2221 // As a result, there might be need for this:
2226 void OptimizeLinearExplode()
2229 // But only if x is just a simple thing
2231 // Won't work on anything else.
2232 if(GetOp() != cPow) return;
2237 void OptimizePascal()
2239 #if 0 // Too big, too specific, etc
2241 // Won't work on anything else.
2242 if(GetOp() != cAdd) return;
2244 // Must be done after OptimizeLinearCombine();
2246 // Don't need pascal triangle
2247 // Coefficient for x^a * y^b * z^c = 3! / (a! * b! * c!)
2249 // We are greedy and want other than just binomials
2252 // note: partial ones are also nice
2256 // x x * x y * + y y * +
2257 // -> x y + dup * x y * -
2265 void Assemble(vector<unsigned> &byteCode,
2266 vector<double> &immed) const;
2268 void FinalOptimize()
2270 // First optimize each parameter.
2271 for(pit a=GetBegin(); a!=GetEnd(); ++a)
2272 (*a)->FinalOptimize();
2274 /* These things are to be done:
2276 * x * CONSTANT_DR -> cDeg(x)
2277 * x * CONSTANT_RD -> cRad(x)
2278 * pow(x, 0.5) -> sqrt(x)
2279 * log(x) * CONSTANT_L10I -> log10(x)
2280 * pow(CONSTANT_E, x) -> exp(x)
2281 * inv(sin(x)) -> csc(x)
2282 * inv(cos(x)) -> sec(x)
2283 * inv(tan(x)) -> cot(x)
2289 const SubTree &p0 = getp0();
2290 const SubTree &p1 = getp1();
2291 if(p0->GetOp() == cImmed
2292 && p0->GetImmed() == CONSTANT_E)
2294 ReplaceWith(cExp, p1);
2296 else if(p1->GetOp() == cImmed
2297 && p1->GetImmed() == 0.5)
2299 ReplaceWith(cSqrt, p0);
2304 if(GetArgCount() == 1 && getp0().getsign())
2306 /***/if(getp0()->GetOp() == cSin)ReplaceWith(cCsc, getp0()->getp0());
2307 else if(getp0()->GetOp() == cCos)ReplaceWith(cSec, getp0()->getp0());
2308 else if(getp0()->GetOp() == cTan)ReplaceWith(cCot, getp0()->getp0());
2311 // Separate "if", because op may have just changed
2314 CodeTree *found_log = 0;
2316 ConstList cl = BuildConstList();
2318 for(pit a=GetBegin(); a!=GetEnd(); ++a)
2321 if(pa->GetOp() == cLog && !pa.getsign())
2324 if(cl.value == CONSTANT_L10I && found_log)
2326 // Change the log() to log10()
2327 found_log->SetOp(cLog10);
2328 // And forget the constant
2331 else if(cl.value == CONSTANT_DR)
2333 OptimizeRedundant();
2334 ReplaceWith(cDeg, *this);
2336 else if(cl.value == CONSTANT_RD)
2338 OptimizeRedundant();
2339 ReplaceWith(cRad, *this);
2341 else FinishConst(cl);
2348 void CodeTreeDataPtr::Shock()
2352 paramlist &p2 = (*this)->args;
2353 for(paramlist::iterator i=p2.begin(); i!=p2.end(); ++i)
2360 CodeTree::ConstList CodeTree::BuildConstList()
2364 result.voidvalue = GetOp()==cMul ? 1.0 : 0.0;
2366 list<pit> &cp = result.cp;
2367 for(pit b, a=GetBegin(); a!=GetEnd(); a=b)
2369 SubTree &pa = *a; b=a; ++b;
2370 if(!pa->IsImmed()) continue;
2372 double thisvalue = pa->GetImmed();
2373 if(thisvalue == result.voidvalue)
2375 // This value is no good, forget it
2380 result.value *= thisvalue;
2382 result.value += thisvalue;
2388 Jos joku niistä arvoista on -1 eikä se ole ainoa arvo,
2389 niin joku muu niistä arvoista negatoidaan.
2391 for(bool done=false; cp.size() > 1 && !done; )
2394 for(list<pit>::iterator b,a=cp.begin(); a!=cp.end(); a=b)
2397 if((**a)->GetImmed() == -1.0)
2402 // take randomly something
2403 (**cp.begin())->data->NegateImmed();
2404 if(cp.size() < 2)break;
2413 void CodeTree::Assemble
2414 (vector<unsigned> &byteCode,
2415 vector<double> &immed) const
2417 #define AddCmd(op) byteCode.push_back((op))
2418 #define AddConst(v) do { \
2419 byteCode.push_back(cImmed); \
2420 immed.push_back((v)); \
2430 AddConst(GetImmed());
2439 unsigned opcount = 0;
2440 for(pcit a=GetBegin(); a!=GetEnd(); ++a)
2442 const SubTree &pa = *a;
2444 if(opcount < 2) ++opcount;
2446 bool pnega = pa.getsign();
2452 && pa->data->IsInverted()
2453 && (pnega || opcount==2)
2457 tmp.data->InvertImmed();
2458 tmp.Assemble(byteCode, immed);
2462 else if(GetOp() == cAdd
2463 && (pa->data->IsNegatedOriginal()
2464 // || pa->GetImmed() < 0
2466 && (pnega || opcount==2)
2470 tmp.data->NegateImmed();
2471 tmp.Assemble(byteCode, immed);
2477 pa->Assemble(byteCode, immed);
2481 unsigned tmpop = GetOp();
2484 tmpop = (tmpop == cMul) ? cDiv : cSub;
2490 if(GetOp() == cMul) AddCmd(cInv);
2498 // If the parameter amount is != 3, we're screwed.
2499 getp0()->Assemble(byteCode, immed);
2501 unsigned ofs = byteCode.size();
2503 AddCmd(0); // code index
2504 AddCmd(0); // immed index
2506 getp1()->Assemble(byteCode, immed);
2508 byteCode[ofs+1] = byteCode.size()+2;
2509 byteCode[ofs+2] = immed.size();
2511 ofs = byteCode.size();
2513 AddCmd(0); // code index
2514 AddCmd(0); // immed index
2516 getp2()->Assemble(byteCode, immed);
2518 byteCode[ofs+1] = byteCode.size()-1;
2519 byteCode[ofs+2] = immed.size();
2525 // If the parameter count is invalid, we're screwed.
2526 for(pcit a=GetBegin(); a!=GetEnd(); ++a)
2528 const SubTree &pa = *a;
2529 pa->Assemble(byteCode, immed);
2532 AddCmd(data->GetFuncNo());
2537 // If the parameter count is invalid, we're screwed.
2538 for(pcit a=GetBegin(); a!=GetEnd(); ++a)
2540 const SubTree &pa = *a;
2541 pa->Assemble(byteCode, immed);
2544 AddCmd(data->GetFuncNo());
2549 // If the parameter count is invalid, we're screwed.
2550 for(pcit a=GetBegin(); a!=GetEnd(); ++a)
2552 const SubTree &pa = *a;
2553 pa->Assemble(byteCode, immed);
2561 void CodeTree::Optimize()
2564 // Phase 0: Do local optimizations.
2565 // Phase 1: Optimize each.
2566 // Phase 2: Do local optimizations again.
2568 for(unsigned phase=0; phase<=2; ++phase)
2572 // Optimize each parameter.
2573 for(pit a=GetBegin(); a!=GetEnd(); ++a)
2576 CHECKCONSTNEG(*a, GetOp());
2580 if(phase == 0 || phase == 2)
2582 // Do local optimizations.
2584 OptimizeConstantMath1();
2585 OptimizeLogarithm();
2586 OptimizeFunctionCalls();
2587 OptimizeExponents();
2588 OptimizeLinearExplode();
2591 /* Optimization paths:
2594 redundant= * doublenegations
2595 conflict= * redundant
2597 constantmath1= addmulflat * conflict
2598 linearcombine= conflict * addmulflat¹ redundant¹
2600 exponents= linearcombine * powmuladd conflict¹
2601 logarithm= exponents *
2607 ¹ = only if made changes
2614 bool CodeTree::operator== (const CodeTree& b) const
2616 if(GetOp() != b.GetOp()) return false;
2617 if(IsImmed()) if(GetImmed() != b.GetImmed()) return false;
2618 if(IsVar()) if(GetVar() != b.GetVar()) return false;
2620 if(data->GetFuncNo() != b.data->GetFuncNo()) return false;
2621 return data->args == b.data->args;
2624 bool CodeTree::operator< (const CodeTree& b) const
2626 if(GetArgCount() != b.GetArgCount())
2627 return GetArgCount() > b.GetArgCount();
2629 if(GetOp() != b.GetOp())
2632 if(IsImmed() != b.IsImmed()) return IsImmed() < b.IsImmed();
2634 return GetOp() < b.GetOp();
2639 if(GetImmed() != b.GetImmed()) return GetImmed() < b.GetImmed();
2641 if(IsVar() && GetVar() != b.GetVar())
2643 return GetVar() < b.GetVar();
2645 if(data->IsFunc() && data->GetFuncNo() != b.data->GetFuncNo())
2647 return data->GetFuncNo() < b.data->GetFuncNo();
2650 pcit i = GetBegin(), j = b.GetBegin();
2651 for(; i != GetEnd(); ++i, ++j)
2653 const SubTree &pa = *i, &pb = *j;
2662 bool IsNegate(const SubTree &p1, const SubTree &p2) /*const */
2664 if(p1->IsImmed() && p2->IsImmed())
2666 return p1->GetImmed() == -p2->GetImmed();
2668 if(p1.getsign() == p2.getsign()) return false;
2671 bool IsInverse(const SubTree &p1, const SubTree &p2) /*const*/
2673 if(p1->IsImmed() && p2->IsImmed())
2675 // FIXME: potential divide by zero.
2676 return p1->GetImmed() == 1.0 / p2->GetImmed();
2678 if(p1.getsign() == p2.getsign()) return false;
2683 SubTree::SubTree() : tree(new CodeTree), sign(false)
2687 SubTree::SubTree(const SubTree &b) : tree(new CodeTree(*b.tree)), sign(b.sign)
2691 #define SubTreeDecl(p1, p2) \
2692 SubTree::SubTree p1 : tree(new CodeTree p2), sign(false) { }
2694 SubTreeDecl( (const struct CodeTree &b), (b) )
2695 SubTreeDecl( (double value), (value) )
2701 delete tree; tree=0;
2704 const SubTree &SubTree::operator= (const SubTree &b)
2707 CodeTree *oldtree = tree;
2708 tree = new CodeTree(*b.tree);
2712 const SubTree &SubTree::operator= (const CodeTree &b)
2715 CodeTree *oldtree = tree;
2716 tree = new CodeTree(b);
2721 bool SubTree::operator< (const SubTree& b) const
2723 if(getsign() != b.getsign()) return getsign() < b.getsign();
2724 return *tree < *b.tree;
2726 bool SubTree::operator== (const SubTree& b) const
2728 return sign == b.sign && *tree == *b.tree;
2730 void SubTree::Negate() // Note: Parent must be cAdd
2735 void SubTree::CheckConstNeg()
2737 if(tree->IsImmed() && getsign())
2739 tree->NegateImmed();
2743 void SubTree::Invert() // Note: Parent must be cMul
2748 void SubTree::CheckConstInv()
2750 if(tree->IsImmed() && getsign())
2752 tree->InvertImmed();
2757 void FunctionParser::MakeTree(struct CodeTree *result) const
2759 vector<CodeTree> stack(1);
2761 #define GROW(n) do { \
2763 if(stack.size() <= stacktop) stack.resize(stacktop+1); \
2766 #define EAT(n, opcode) do { \
2767 unsigned newstacktop = stacktop-n; \
2768 stack[stacktop].SetOp((opcode)); \
2769 for(unsigned a=0, b=(n); a<b; ++a) \
2770 stack[stacktop].AddParam(stack[newstacktop+a]); \
2771 stack.erase(stack.begin() + newstacktop, \
2772 stack.begin() + stacktop); \
2773 stacktop = newstacktop; GROW(1); \
2776 #define ADDCONST(n) do { \
2777 stack[stacktop].SetImmed((n)); \
2781 unsigned stacktop=0;
2783 list<unsigned> labels;
2785 for(unsigned IP=0, DP=0; ; ++IP)
2787 while(labels.size() > 0
2788 && *labels.begin() == IP)
2790 // The "else" of an "if" ends here
2792 labels.erase(labels.begin());
2795 if(IP >= Comp.ByteCodeSize)
2800 unsigned opcode = Comp.ByteCode[IP];
2806 else if(opcode == cJump)
2808 labels.push_front(Comp.ByteCode[IP+1]+1);
2811 else if(opcode == cImmed)
2813 ADDCONST(Comp.Immed[DP++]);
2815 else if(opcode < VarBegin)
2822 EAT(1, cAdd); // Unary minus is negative adding.
2823 stack[stacktop-1].getp0().Negate();
2829 EAT(2, cAdd); // Minus is negative adding
2830 stack[stacktop-1].getp1().Negate();
2835 EAT(2, cMul); // Divide is inverse multiply
2836 stack[stacktop-1].getp1().Invert();
2840 // ADD ALL TWO PARAMETER NON-FUNCTIONS HERE
2841 case cAdd: case cMul:
2842 case cMod: case cPow:
2843 case cEqual: case cLess: case cGreater:
2844 case cAnd: case cOr:
2850 unsigned index = Comp.ByteCode[++IP];
2851 unsigned params = FuncPtrs[index].params;
2852 EAT(params, opcode);
2853 stack[stacktop-1].data->SetFuncNo(index);
2858 unsigned index = Comp.ByteCode[++IP];
2859 unsigned params = FuncParsers[index]->varAmount;
2860 EAT(params, opcode);
2861 stack[stacktop-1].data->SetFuncNo(index);
2865 // Converted to cMul on fly
2867 ADDCONST(CONSTANT_DR);
2871 // Converted to cMul on fly
2873 ADDCONST(CONSTANT_RD);
2880 const FuncDefinition& func = Functions[opcode-cAbs];
2882 unsigned paramcount = func.params;
2883 #ifndef DISABLE_EVAL
2884 if(opcode == cEval) paramcount = varAmount;
2888 // Converted on fly: sqrt(x) = x^0.5
2895 // Converted on fly: exp(x) = CONSTANT_E^x
2899 // reverse the parameters... kludgey
2900 stack[stacktop] = stack[stacktop-1];
2901 stack[stacktop-1].SetImmed(CONSTANT_E);
2904 bool do_inv = false;
2905 if(opcode == cCot) { do_inv = true; opcode = cTan; }
2906 if(opcode == cCsc) { do_inv = true; opcode = cSin; }
2907 if(opcode == cSec) { do_inv = true; opcode = cCos; }
2909 bool do_log10 = false;
2910 if(opcode == cLog10)
2912 // Converted on fly: log10(x) = log(x) * CONSTANT_L10I
2916 EAT(paramcount, opcode);
2919 ADDCONST(CONSTANT_L10I);
2924 // Unary cMul, inverted. No need for "1.0"
2926 stack[stacktop-1].getp0().Invert();
2934 stack[stacktop].SetVar(opcode);
2941 // ERROR: Stack does not have any values!
2945 --stacktop; // Ignore the last element, it is always nop (cAdd).
2949 // ERROR: Stack has too many values!
2953 // Okay, the tree is now stack[0]
2957 void FunctionParser::Optimize()
2963 // Do all sorts of optimizations
2965 // Last changes before assembly
2966 tree.FinalOptimize();
2968 // Now rebuild from the tree.
2970 vector<unsigned> byteCode;
2971 vector<double> immed;
2974 byteCode.resize(Comp.ByteCodeSize);
2975 for(unsigned a=0; a<Comp.ByteCodeSize; ++a)byteCode[a] = Comp.ByteCode[a];
2977 immed.resize(Comp.ImmedSize);
2978 for(unsigned a=0; a<Comp.ImmedSize; ++a)immed[a] = Comp.Immed[a];
2980 byteCode.clear(); immed.clear();
2981 tree.Assemble(byteCode, immed);
2984 delete[] Comp.ByteCode; Comp.ByteCode = 0;
2985 if((Comp.ByteCodeSize = byteCode.size()) > 0)
2987 Comp.ByteCode = new unsigned[Comp.ByteCodeSize];
2988 for(unsigned a=0; a<byteCode.size(); ++a)
2989 Comp.ByteCode[a] = byteCode[a];
2992 delete[] Comp.Immed; Comp.Immed = 0;
2993 if((Comp.ImmedSize = immed.size()) > 0)
2995 Comp.Immed = new double[Comp.ImmedSize];
2996 for(unsigned a=0; a<immed.size(); ++a)
2997 Comp.Immed[a] = immed[a];
3002 #else /* !SUPPORT_OPTIMIZER */
3004 /* keep the linker happy */
3005 void FunctionParser::MakeTree(struct CodeTree *) const {}
3006 void FunctionParser::Optimize()
3008 // Do nothing if no optimizations are supported.