///////////////////////////////////////////////////////////////////////////// // MathEq.h - Library to support the translation of mathematic expression // to C++ operation. // // Ver 1.1 20 Aug 2000 TSTan // Support complex number. CMathEquation only accepts T of complex<>. // Real number manipulation has to be implemented as subset of complex. // Process tan, sin, cos... // // Ver 1.0 13 Aug 2000 TSTan // Initial revision. // // This code is freely distributed to help the development of complex // software in any field using C++. The author is not held responsible // for any damage caused by the usage of the code. // The author should be acknowledged for the use of this piece of code in // commercial software. // // Bug reports and suggestions are welcomed to report to // // tzstan@hotmail.com ///////////////////////////////////////////////////////////////////////////// #ifndef __TS_MATHEQ__ #define __TS_MATHEQ__ #include #include #include #include #include "TSingLst.h" #include "TStack.h" #include "TString.h" ///////////////////////////////////////////////////////////////////////////// // CMathBase // // Desctiption: Base class to possible mathematic element(variables, // constants, operators...) // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template class CMathBase { public: enum ClassID{ MATHBASE, MATHCONST, MATHVAR, MATHOP}; CMathBase() {}; virtual ~CMathBase() {}; virtual void SetParameter(T &) = 0; virtual void Evaluate(CStack &) = 0; virtual CTString GetString() const = 0; virtual void PrintOut(ostream&)= 0; virtual const enum ClassID MyID() const {return MATHBASE;} }; ///////////////////////////////////////////////////////////////////////////// // CMathBase // // Desctiption: Behaviour of constants. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// templateclass CMathConst: public CMathBase { T m_constant; public: CMathConst(CTString &); virtual ~CMathConst(); virtual void SetParameter(T &) {}; virtual void Evaluate(CStack &); virtual CTString GetString() const {return "";} virtual void PrintOut(ostream&); virtual const enum ClassID MyID() const {return MATHCONST;} }; ///////////////////////////////////////////////////////////////////////////// // CMathConst(char *constant) // // Desctiption: Constructor for constant class. // // constant - constant value held in char array. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template CMathConst::CMathConst(CTString &constant) { if(constant[0] != 'i') { T value(atof(constant.Data()), 0.0); m_constant = value; } else { constant.RemoveAt(0); T value(0.0, atof(constant.Data())); m_constant = value; } } ///////////////////////////////////////////////////////////////////////////// // Evaluate(CStack &Stack) // // Desctiption: Calculate the output. // // Stack - Stack for intermediate steps and output. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template void CMathConst::Evaluate(CStack &Stack) { Stack.Push(m_constant); } ///////////////////////////////////////////////////////////////////////////// // PrintOut(ostream &os) // // Desctiption: Printout the content. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template void CMathConst::PrintOut(ostream &os) { os << m_constant << ' '; } ///////////////////////////////////////////////////////////////////////////// // ~CMathConst() // // Desctiption: Constant class' destructor. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template CMathConst::~CMathConst() {} ///////////////////////////////////////////////////////////////////////////// // CMathOperator // // Desctiption: Behaviour of operators. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template class CMathOperator: public CMathBase { enum OperatorType{ SUMMATION, SUBSTRACTION, MULTIPLICATION, DIVISION, SINE, COSINE, TANGENT }; enum OperatorType m_operator; public: CMathOperator(CTString &); virtual ~CMathOperator(); virtual void SetParameter(T &) {}; virtual void Evaluate(CStack &); virtual CTString GetString() const {return "";} virtual void PrintOut(ostream&); virtual const enum ClassID MyID() const {return MATHOP;} }; ///////////////////////////////////////////////////////////////////////////// // Evaluate(CStack &Stack) // // Desctiption: Calculate output. // // Stack - Stack to hold intermediate and final results. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template void CMathOperator::Evaluate(CStack &Stack) { T Element2 = Stack.Pop(); T Element1; if(m_operator == SUMMATION || m_operator == SUBSTRACTION || m_operator == MULTIPLICATION || m_operator == DIVISION) Element1 = Stack.Pop(); T Result; switch(m_operator) { case SUMMATION: Result = Element1 + Element2; break; case SUBSTRACTION: Result = Element1 - Element2; break; case MULTIPLICATION: Result = Element1 * Element2; break; case DIVISION: if(Element2 == 0.0) cerr << "Divide by zero!" << endl; else Result = Element1 / Element2; break; case SINE: Result = sin(Element2); break; case COSINE: Result = cos(Element2); break; case TANGENT: Result = tan(Element2); break; } Stack.Push(Result); } ///////////////////////////////////////////////////////////////////////////// // CMathOperator(char *operatorType) // // Desctiption: Operator constructor. // // operatorType - Operator type held in char array. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template CMathOperator::CMathOperator(CTString &operatorType) { // Use char comparison first for frequent used operator to increase // runtime speed. if(operatorType[0] == '+') m_operator = SUMMATION; else if(operatorType[0] == '-') m_operator = SUBSTRACTION; else if(operatorType[0] == '*') m_operator = MULTIPLICATION; else if(operatorType[0] == '/') m_operator = DIVISION; else if(operatorType == "sin") m_operator = SINE; else if(operatorType == "cos") m_operator = COSINE; else if(operatorType == "tan") m_operator = TANGENT; } ///////////////////////////////////////////////////////////////////////////// // PrintOut(ostream &os) // // Desctiption: Print out the content. // // os - Output stream to accept the content. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template void CMathOperator::PrintOut(ostream &os) { switch(m_operator) { case SUMMATION: os << '+'; break; case SUBSTRACTION: os << '-'; break; case MULTIPLICATION: os << '*'; break; case DIVISION: os << '/'; break; case SINE: os << "sin"; break; case COSINE: os << "cos"; break; case TANGENT: os << "tan"; break; } os << ' '; } ///////////////////////////////////////////////////////////////////////////// // ~CMathOperator() // // Desctiption: Operator class destructor. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template CMathOperator::~CMathOperator() {} ///////////////////////////////////////////////////////////////////////////// // CMathVariable // // Desctiption: Behaviour of variables. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template class CMathVariable: public CMathBase { CTString m_variable; T m_value; public: CMathVariable(CTString &); virtual ~CMathVariable(); virtual void SetParameter(T &value) {m_value = value;} virtual void Evaluate(CStack &); virtual CTString GetString() const {return m_variable;} virtual void PrintOut(ostream&); virtual const enum ClassID MyID() const {return MATHVAR;} }; ///////////////////////////////////////////////////////////////////////////// // CMathVariable(char *variableName) // // Desctiption: Constructor to create variable object. // // variableName - The variable's name. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template CMathVariable::CMathVariable(CTString &variableName) { m_variable = variableName; } ///////////////////////////////////////////////////////////////////////////// // Evaluate(CStack &Stack) // // Desctiption: Calculate output. // // Stack - Stack to hold intermediate and final results. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template void CMathVariable::Evaluate(CStack &Stack) { Stack.Push(m_value); } ///////////////////////////////////////////////////////////////////////////// // PrintOut(ostream &os) // // Desctiption: Print out content to os. // // os - Output stream to accept the content. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template void CMathVariable::PrintOut(ostream &os) { os << m_variable << ' '; } ///////////////////////////////////////////////////////////////////////////// // ~CMathVariable() // // Desctiption: Variable class constructor. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template CMathVariable::~CMathVariable() {} ///////////////////////////////////////////////////////////////////////////// // CMathEquation // // Desctiption: Mathematic equation, translator and calculator. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template class CMathEquation { enum Eq_InputType{ DIGIT, OPERATOR, OPEN_PAREN, CLOSE_PAREN, ALPHA, IMAG, UNKNOWN }; CTString m_equation; CSinglyList*> *m_EqList; CSinglyList *m_Unknowns; CStack *m_Stack; int Extract(char **Src, char *Output); public: CMathEquation(CTString &); CMathEquation(char *Equation = ""); ~CMathEquation(); void SetEquation(CTString &); void SetEquation(char *); void FreeAll(); void SetVariable(char *, T &); T Evaluate(); void ComputerEq(ostream &); void ComputerEq(CTString &); char *Equation() {return m_equation.Data();} CSinglyList *GetUnknowns() {return m_Unknowns;} }; ///////////////////////////////////////////////////////////////////////////// // CMathEquation // // Desctiption: Constructor by accepting Equation. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template CMathEquation::CMathEquation(char *Equation) { m_EqList = NULL; m_Unknowns = NULL; m_Stack = new CStack; CTString t_equation = Equation; SetEquation(t_equation); } template CMathEquation::CMathEquation(CTString &Equation) { m_EqList = NULL; m_Unknowns = NULL; m_Stack = new CStack; SetEquation(Equation); } ///////////////////////////////////////////////////////////////////////////// // ~CMathEquation // // Desctiption: Destructor for clean up. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template CMathEquation::~CMathEquation() { FreeAll(); delete m_Stack; } ///////////////////////////////////////////////////////////////////////////// // Evaluate() // // Desctiption: Does calculation. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template T CMathEquation::Evaluate() { for(m_EqList->ResetPtr(); m_EqList->IsValid(); m_EqList->Next()) { CMathBase *thisElement = *m_EqList->Current(); thisElement->Evaluate(*m_Stack); } return m_Stack->Pop(); } ///////////////////////////////////////////////////////////////////////////// // FreeAll() // // Desctiption: Reset to prepare for new equation. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template void CMathEquation::FreeAll() { if(m_EqList) { while(!m_EqList->IsEmpty()) { m_EqList->ResetPtr(); delete m_EqList->Current(); m_EqList->Remove(); } delete m_EqList; m_EqList = NULL; } if(m_Unknowns) { delete m_Unknowns; m_Unknowns = NULL; } m_Stack->Reset(); } ///////////////////////////////////////////////////////////////////////////// // SetVariable(char *unknown, double value) // // Desctiption: Set variable value. // // unknown - The variable to set. // value - Value to set to. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template void CMathEquation::SetVariable(char *unknown, T &value) { for(m_EqList->ResetPtr(); m_EqList->IsValid(); m_EqList->Next()) { CMathBase *thisElement = *m_EqList->Current(); if(thisElement->MyID() == CMathBase::MATHVAR) { if(thisElement->GetString() == unknown) thisElement->SetParameter(value); } } } ///////////////////////////////////////////////////////////////////////////// // SetEquation(char *Equation) // // Desctiption: Equation to be used. // // Equation - Equation in char array. // // TSTan 03 Sep 2000 ///////////////////////////////////////////////////////////////////////////// template void CMathEquation::SetEquation(char *equation) { CTString tempStr = equation; SetEquation(tempStr); } ///////////////////////////////////////////////////////////////////////////// // SetEquation(char *Equation) // // Desctiption: Equation to be used. // // Equation - Equation in char array. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template void CMathEquation::SetEquation(CTString &Equation) { FreeAll(); m_equation = Equation; m_EqList = new CSinglyList*>; m_Unknowns = new CSinglyList; CStack*> OperatorStack, ElementStack; char *EqPtr = Equation.Data(); char var[80]; CMathBase *mathBase = NULL; while(*EqPtr) { enum Eq_InputType isType = Eq_InputType(Extract(&EqPtr, var)); CTString StrVar = var; switch(isType) { case DIGIT: case IMAG: mathBase = new CMathConst(StrVar); ElementStack.Push(mathBase); break; case OPERATOR: mathBase = new CMathOperator(StrVar); OperatorStack.Push(mathBase); break; case CLOSE_PAREN: if(OperatorStack.Size()) { mathBase = OperatorStack.Pop(); ElementStack.Push(mathBase); } break; case ALPHA: mathBase = new CMathVariable(StrVar); ElementStack.Push(mathBase); if(!m_Unknowns->Exist(StrVar)) m_Unknowns->Insert(StrVar); break; case OPEN_PAREN: break; } } while(OperatorStack.Size()) { mathBase = OperatorStack.Pop(); ElementStack.Push(mathBase); } while(ElementStack.Size()) { mathBase = ElementStack.Pop(); m_EqList->Insert(mathBase); } } ///////////////////////////////////////////////////////////////////////////// // ComputerEq(ostream &os) // // Desctiption: Output translated equation to os. // // os - Output stream to accept the output. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template void CMathEquation::ComputerEq(ostream &os) { for(m_EqList->ResetPtr(); m_EqList->IsValid(); m_EqList->Next()) m_EqList->Current()->PrintOut(os); os << endl; } ///////////////////////////////////////////////////////////////////////////// // ComputerEq(CTString &os) // // Desctiption: Output translated equation to os. // // os - Output stream to accept the output. // // TSTan 03 Sep 2000 ///////////////////////////////////////////////////////////////////////////// template void CMathEquation::ComputerEq(CTString &os) { char tempBuffer[80]; ostrstream tempStr(tempBuffer, 80); for(m_EqList->ResetPtr(); m_EqList->IsValid(); m_EqList->Next()) (*m_EqList->Current())->PrintOut(tempStr); tempStr << '\0'; os = tempStr.str(); } ///////////////////////////////////////////////////////////////////////////// // Extract(char **Src, char *Output) // // Desctiption: Extracts one elemant from mathematic expression. // // Src - Address to the pointer of current equation location. // Output - Output address of extracted element. // // TSTan 13 Aug 2000 ///////////////////////////////////////////////////////////////////////////// template int CMathEquation::Extract(char **Src, char *Output) { char *OPtr = Output; char *OriginalOPtr = Output; enum Eq_InputType Type = UNKNOWN; while(**Src) { enum Eq_InputType thisType = UNKNOWN; *OPtr = **Src; (*Src)++; if((*OPtr >= '0' && *OPtr <= '9') || *OPtr == '.') // Is digit thisType = Type == IMAG? IMAG: DIGIT; else if(*OPtr == '+' || *OPtr == '-' || // Is operator *OPtr == '*' || *OPtr == '/') thisType = OPERATOR; else if(*OPtr == '(') // Is open parenthesis thisType = OPEN_PAREN; else if(*OPtr == ')') // Is close parenthesis thisType = CLOSE_PAREN; else if(*OPtr == 'i' && Type == UNKNOWN) // May be imaginary thisType = IMAG; else if(*OPtr >= 'a' && *OPtr <= 'z')// Must be variable thisType = ALPHA; else if(*OPtr >= 'A' && *OPtr <= 'Z') thisType = ALPHA; if(thisType == ALPHA && Type == IMAG) Type = ALPHA; // The 'i' does not represent imaginary if(Type != UNKNOWN && Type != thisType) { (*Src)--; break; } else if(thisType == UNKNOWN) break; else Type = thisType; OPtr++; } *OPtr = 0; if(Type == ALPHA) //Post process to find special Math Operator { CTString Operation(OriginalOPtr); if(Operation == "sin" || Operation == "cos" || Operation == "tan") Type = OPERATOR; } return Type; } #endif