www.pudn.com > Calculate20060802.rar > MathStack.cpp
#include "StdAfx.h" #include ".\MathStack.h" #includeusing namespace std; // list of supported functions char* pFunctions[] = { "(", "sin(", "cos(", "tan(", "sec(", "cosec(", "cot(", "sinh(", "cosh(", "tanh(", "sech(", "cosech(", "coth(", "asin(", "acos(", "atan(", "asec(", "acosec(", "acot(", "asinh(", "acosh(", "atanh(", "asech(", "acosech(", "acoth(", "sqrt(", "log10(", "log(", "ln(", "sign(", "abs(", NULL }; ////////////////////////////////////////////////////////////////////////// // GetClose: search for the close parenthesis ////////////////////////////////////////////////////////////////////////// char *GetClose(char *p) { // initialize parenthesis count to one int nOpen = 1; // loop in the input to find the close parenthesis while(*(++p)) if(*p == '(') nOpen++; else if(*p == ')') if(--nOpen == 0) return ++p; return NULL; } ////////////////////////////////////////////////////////////////////////// // GetFunction: Check if the input string initial matches with any of the supported functions ////////////////////////////////////////////////////////////////////////// int GetFunction(LPCSTR pOpen, int& nSign) { LPSTR p = (LPSTR)pOpen; if(*p == '-') nSign = -1, p++; else if(*p == '+') nSign = +1, p++; for(int nIndex = 0; pFunctions[nIndex]; nIndex++) if(memcmp(p, pFunctions[nIndex], strlen(pFunctions[nIndex])) == 0) { if(GetClose(p+strlen(pFunctions[nIndex])-1) == NULL) return -1; return nIndex; } return -1; } bool IsRightSign(IN char c, IN LPCSTR lpcsOperators[], IN int nIndex) { for(; lpcsOperators[nIndex]; nIndex++) if(strchr(lpcsOperators[nIndex], c) != NULL) return false; return true; } ////////////////////////////////////////////////////////////////////////// // GetOperator: scan the input string to search for any of the input operators ////////////////////////////////////////////////////////////////////////// int GetOperator(IN LPCSTR lpcs, IN LPCSTR lpcsOperators[]) { for(int nIndex = 0; lpcsOperators[nIndex]; nIndex++) { int nOpen = 0; // scan the expression from its end LPSTR p = (LPSTR)lpcs+strlen(lpcs)-1; // loop tell reach expression start while(p >= lpcs) { // check for close if(*p == ')') nOpen++; // check for open else if(*p == '(') nOpen--; // check for operator else if(nOpen == 0 && strchr(lpcsOperators[nIndex], *p) != NULL) // check if the operator in not a sign mark if((*p != '-' && *p != '+') || (p != lpcs && IsRightSign(*(p-1), lpcsOperators, nIndex+1))) // return operator index return (int)(p-lpcs); p--; } } // operator not found return -1; } int FillStack(LPCSTR lpcsInput, vector & vStack) { // operators array from high to low priority LPCSTR lpcsOperators[] = { "+-", "*/", "^%", NULL }; // insert first input into the stack vStack.push_back(new ExpressionItem(lpcsInput)); // loop in Expression stack to check if any Expression can be divided to two queries for(int nIndex = 0; nIndex < (int)vStack.size(); nIndex++) // check if Expression item is operator if(vStack[nIndex]->m_cOperator == 0) { // copy Expression string CString str = vStack[nIndex]->m_strInput; // parse expression to find operators int nOpIndex = GetOperator(str, lpcsOperators); if(nOpIndex != -1) { // split the Expression into two queries at the operator index vStack[nIndex]->m_cOperator = str[nOpIndex]; // add the left operand of the operator as a new expression vStack.insert(vStack.begin()+nIndex+1, new ExpressionItem(str.Left(nOpIndex))); // add the right operand of the operator as a new expression vStack.insert(vStack.begin()+nIndex+2, new ExpressionItem(str.Mid(nOpIndex+1))); } else // check if Expression string starts with function or parenthesis if((vStack[nIndex]->m_nFunction = GetFunction(str, vStack[nIndex]->m_nSign)) == 0 && vStack[nIndex]->m_nSign == 0) // remove parentheses and re-scan the Expression vStack[nIndex--]->m_strInput = str.Mid(1, str.GetLength()-2); } return 0; } void InsertTabs(CString& str) { if(str.IsEmpty()) return; str.Insert(0, '\t'); str.Replace("\n", "\n\t"); str.TrimRight('\t'); } void OptimizeSign(CString& str) { int nIndex = 0; // replace "--" with "" or "+" while((nIndex = str.Find("--", nIndex)) != -1) if(nIndex == 0 || strchr("(+-/*^", str[nIndex-1]) != NULL) str.Delete(nIndex, 2); else str.Delete(nIndex, 1), str.SetAt(nIndex, '+'); nIndex = 0; // replace "+-" with "-" while((nIndex = str.Find("+-", nIndex)) != -1) str.Delete(nIndex); } void Optimize(CString& str) { int nLength = str.GetLength(); int nIndex = -1; // replace "-(-" with "(" or "+(" while((nIndex = str.Find("-(-", nIndex+1)) != -1) if(nIndex == 0) str.Delete(0), str.Delete(1); // take care: after delete(0) second '-' be in position 1 else str.SetAt(nIndex, '+'), str.Delete(nIndex+2); nIndex = -1; // replace "+(-" with "-(" while((nIndex = str.Find("+(-", nIndex+1)) != -1) if(nIndex == 0) str.Delete(0); else str.SetAt(nIndex, '-'), str.Delete(nIndex+2); OptimizeSign(str); char* pClose; nIndex = -1; // replace "((....))" with "(....)" while((nIndex = str.Find("((", nIndex+1)) != -1) if(*(pClose = GetClose(str.GetBuffer(0)+nIndex+1)) == ')') { str.Delete((int)(pClose-str.GetBuffer(0))); str.Delete(nIndex); } nIndex = -1; // remove any 1* while((nIndex = str.Find("1*", nIndex+1)) != -1) if(nIndex == 0 || strchr("0123456789./^%", str[nIndex-1]) == NULL) str.Delete(nIndex, 2); nIndex = -1; // remove any *1 while((nIndex = str.Find("*1", nIndex+1)) != -1) if(nIndex+2 == str.GetLength() || strchr("0123456789.^%", str[nIndex+2]) == NULL) str.Delete(nIndex, 2); nIndex = -1; // remove any exponent equal 1 while((nIndex = str.Find("^1", nIndex+1)) != -1) if(nIndex+2 == str.GetLength() || strchr("0123456789./^%", str[nIndex+2]) == NULL) str.Delete(nIndex, 2); nIndex = 0; // remove unneeded parentheses while((nIndex = str.Find('(', nIndex)) != -1) { // "nscthg0" is the end characters of all supported functions if(nIndex > 0 && strchr("nscthg0", str[nIndex-1]) != NULL) { nIndex++; continue; } // find the parenthesis close char* pClose = GetClose(str.GetBuffer(0)+nIndex); if(pClose == NULL) return; // get the index of the close char int nCloseIndex = (int)(pClose-str.GetBuffer(0)-1); // check if the parentheses in the start and the end of the string if((nIndex == 0 && nCloseIndex == str.GetLength()-1) || nCloseIndex == nIndex+2 || // check if the string doesn't include any operator IsNumeric(str.Mid(nIndex+1, nCloseIndex-nIndex-1)) == true) { // delete the far index of ')' str.Delete(nCloseIndex); // delete the near index of '(' str.Delete(nIndex); } else nIndex++; } if(nLength != str.GetLength()) Optimize(str); } CString TrimFloat(double f) { CString str; str.Format("%f", f); if(str.Find('.') != -1) str.TrimRight('0'); str.TrimRight('.'); return str; } #define DIGITS "0123456789." #define IsDigit(c) (c && strchr(DIGITS, c) != NULL) bool IsNumeric(LPCSTR lpcs) { char* p = (char*)lpcs; if(*p == '-' || *p == '+') p++; if(*p == 'e' && *(p+1) == 0) return true; if(*p == 'p' && *(p+1) == 'i' && *(p+2) == 0) return true; while (*p) { if(IsDigit(*p) == false) return false; p++; } return true; }