• Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

QCAD_StringFormulaEvaluator.cpp

Go to the documentation of this file.
00001 #include <stdlib.h>
00002 
00003 #include <string>
00004 #include <list>
00005 #include <sstream>
00006 #include <iostream>
00007 #include <exception>
00008 #include <math.h>
00009 
00010 #include "QCAD_StringFormulaEvaluator.hpp"
00011 
00012 class EvaluateException: public std::exception
00013 {
00014 public:
00015   EvaluateException(std::string message) {
00016     msg = message;
00017   }
00018   ~EvaluateException() throw () {}
00019 
00020   virtual const char* what() const throw() {
00021     return msg.c_str();
00022   }
00023 
00024 private:
00025   std::string msg;
00026 };
00027 
00028 template<typename coordType>
00029 coordType toDbl(std::string s, coordType x, coordType y, coordType z) {
00030   if(s == "x") return x;
00031   if(s == "y") return y;
00032   if(s == "z") return z;
00033   coordType t = atof(s.c_str()); //Must be able to assign coordType with a double
00034   return t;
00035 }
00036 
00037 
00038 template<typename coordType>
00039 std::string toStr(coordType d) {
00040   std::ostringstream convert; 
00041   convert << d;
00042   return convert.str();
00043 }
00044 
00045 void printList(std::list<std::string> l) {
00046   for(std::list<std::string>::iterator it = l.begin(); it != l.end(); ++it)
00047     std::cout << "|" << *it;
00048   std::cout << "|" << std::endl;
00049 }
00050 
00051 
00052 template<typename coordType>
00053 coordType Evaluate(std::string strExpression, coordType x, coordType y, coordType z)
00054 {
00055   bool bDebug = false;
00056   //std::transform(expr.begin(), expr.end(), expr.begin(), ::tolower); // i.e., expr.tolower()
00057 
00058   std::string expr;
00059   for(std::string::iterator it = strExpression.begin(); it != strExpression.end(); ++it) {
00060     if(*it == ' ') continue;
00061     expr += *it;
00062   }
00063 
00064   if(bDebug) { std::cout << "After manip: " << expr << std::endl; }
00065 
00066   std::list<std::string> stack;  // not a std::stack because we need list operations later
00067   std::string value = "";
00068        
00069   for (std::size_t i = 0; i < expr.length(); i++) {
00070     if(bDebug) { std::cout << "i = " << i << ":  val=" << value << ",  stack="; printList(stack); }
00071     std::string s = expr.substr(i, 1);
00072 
00073     // pick up any doublelogical operators first.
00074     if (i < expr.length() - 1) {
00075       std::string op = expr.substr(i, 2);
00076       if (op == "<=" || op == ">=" || op == "==") {
00077   stack.push_front(value);
00078   value = "";
00079   stack.push_front(op);
00080   i++;
00081   continue;
00082       }
00083     }
00084 
00085     char chr = s[0];
00086     if (!isdigit(chr) && !isalpha(chr) && chr != '.' && value != "") {
00087       stack.push_front(value);
00088       value = "";
00089     }
00090     
00091     if (s == "(") {
00092       std::string innerExp = "";
00093       i++; //Fetch Next Character
00094       int bracketCount = 0;
00095       for (; i < expr.length(); i++) {
00096   s = expr.substr(i, 1);
00097   if (s == "(") bracketCount++;
00098   if (s == ")") {
00099     if (bracketCount == 0) break;
00100     bracketCount--;
00101   }
00102   innerExp += s;
00103       }
00104       if(bracketCount != 0) 
00105   throw EvaluateException("Mismatched parenthesis");
00106 
00107       stack.push_front( toStr(Evaluate(innerExp,x,y,z)) );
00108     }
00109     else if (s == "+" ||
00110        s == "-" ||
00111        s == "*" ||
00112        s == "/" ||
00113        s == "<" ||
00114        s == ">" ||
00115        s == "^") {
00116       stack.push_front(s);
00117     }
00118     else if(isdigit(chr) || isalpha(chr) || chr == '.') {
00119       if(chr == '.' && value.find('.') != std::string::npos)
00120   throw EvaluateException("Invalid decimal.");
00121       value += s;
00122 
00123       if (i == (expr.length() - 1))
00124   stack.push_front(value);
00125     }
00126     else {
00127       throw EvaluateException("Invalid character.");
00128     }
00129   }
00130   if(bDebug) { std::cout << "Stack at end = "; printList(stack); }
00131 
00132   double result = 0;
00133   std::list<std::string>& list = stack; //now we use stack as a list, so just for code readability
00134   std::list<std::string>::reverse_iterator it, itm1, itp1, begin;
00135   begin = list.rbegin(); ++begin;
00136   for( it = begin; it != list.rend(); ++it) {
00137     if (*it == "^") {
00138       it++; itm1 = it; it--; it--; itp1 = it; it++;  //setup iterators
00139       *it = toStr( pow(toDbl(*itp1,x,y,z),toDbl(*itm1,x,y,z)) );
00140       list.erase(it.base()); itm1++; list.erase(itm1.base());  //erase() erases the element *AFTER* what it points to
00141     }
00142   }
00143   if(bDebug) { std::cout << "List after ^ block = "; printList(list); }
00144 
00145   begin = list.rbegin(); ++begin;
00146   for( it = begin; it != list.rend(); ++it) {
00147     if (*it == "/") {
00148       it++; itm1 = it; it--; it--; itp1 = it; it++;  //setup iterators
00149       *it = toStr( toDbl(*itp1,x,y,z) / toDbl(*itm1,x,y,z) );
00150       list.erase(it.base()); itm1++; list.erase(itm1.base());  //erase() erases the element *AFTER* what it points to
00151     }
00152   }
00153   if(bDebug) { std::cout << "List after / block = "; printList(list); }
00154 
00155   begin = list.rbegin(); ++begin;
00156   for( it = begin; it != list.rend(); ++it) {
00157     if (*it == "*") {
00158       it++; itm1 = it; it--; it--; itp1 = it; it++;  //setup iterators
00159       *it = toStr( toDbl(*itp1,x,y,z) * toDbl(*itm1,x,y,z) );
00160       list.erase(it.base()); itm1++; list.erase(itm1.base());  //erase() erases the element *AFTER* what it points to
00161     }
00162   }
00163   if(bDebug) { std::cout << "List after * block = "; printList(list); }
00164 
00165   begin = list.rbegin();
00166   for( it = begin; it != list.rend(); ++it) {
00167     if (*it == "+") {      
00168       if (it.base() == list.end()) { // unary plus
00169   it++; itm1 = it; it--; //setup iterators
00170   *it = toStr( toDbl(*itm1,x,y,z) );
00171   itm1++; list.erase(itm1.base());  //erase() erases the element *AFTER* what it points to
00172       } 
00173       else { // binary plus
00174   it++; itm1 = it; it--; it--; itp1 = it; it++;  //setup iterators
00175   *it = toStr( toDbl(*itp1,x,y,z) + toDbl(*itm1,x,y,z) );
00176   list.erase(it.base()); itm1++; list.erase(itm1.base());  //erase() erases the element *AFTER* what it points to
00177       }
00178     }
00179   }
00180   if(bDebug) { std::cout << "List after + block = "; printList(list); }
00181 
00182   begin = list.rbegin();
00183   for( it = begin; it != list.rend(); ++it) {
00184     if (*it == "-") {
00185       if (it.base() == list.end()) { // unary minus
00186   it++; itm1 = it; it--; //setup iterators
00187   *it = toStr( -toDbl(*itm1,x,y,z) );
00188   itm1++; list.erase(itm1.base());  //erase() erases the element *AFTER* what it points to
00189       } 
00190       else { // binary minus
00191   it++; itm1 = it; it--; it--; itp1 = it; it++;  //setup iterators
00192   *it = toStr( toDbl(*itp1,x,y,z) - toDbl(*itm1,x,y,z) );
00193   list.erase(it.base()); itm1++; list.erase(itm1.base());  //erase() erases the element *AFTER* what it points to
00194       }
00195     }
00196   }
00197   if(bDebug) { std::cout << "List after - block = "; printList(list); }
00198 
00199   //Logic operators: use list as a stack, popping from the back
00200   while (list.size() >= 3) {  
00201     coordType right = toDbl(list.back(), x,y,z); list.pop_back();
00202     std::string op = list.back(); list.pop_back();
00203     coordType left = toDbl(list.back(), x,y,z); list.pop_back();
00204 
00205     if (op == "<") result = (left < right) ? 1 : 0;
00206     else if (op == ">") result = (left > right) ? 1 : 0;
00207     else if (op == "<=") result = (left <= right) ? 1 : 0;
00208     else if (op == ">=") result = (left >= right) ? 1 : 0;
00209     else if (op == "==") result = (left == right) ? 1 : 0;
00210 
00211     list.push_back( toStr(result) );
00212   }
00213    
00214   return toDbl(list.back(),x,y,z);
00215 }
00216 
00217 //Explicit instantiations to fix linker errors -- hardcoded now; need to do this better (Andy/Eric?)
00218 #include "PHAL_AlbanyTraits.hpp"
00219 
00220 template double Evaluate<double>(std::string, double, double, double); // explicit instantiation.
00221 template FadType Evaluate<FadType>(std::string, FadType, FadType, FadType); // explicit instantiation.
00222 #ifdef ALBANY_FADTYPE_NOTEQUAL_TANFADTYPE
00223 template TanFadType Evaluate<TanFadType>(std::string, TanFadType, TanFadType, TanFadType); // explicit instantiation.
00224 #endif
00225 
00226 //Uncomment for testing - then this file alone builds a command line calculator
00227 /*int main(int argc, char* argv[]) {
00228 
00229   double result;
00230   double x=1, y=2, z=3;
00231   std::string input;
00232 
00233   while (true) {
00234     std::cout << "Please enter an expression to evaluate (q to quit) x=1,y=2,z=3: ";
00235     std::getline(std::cin, input);
00236     if( input == "q" ) break;
00237     try {
00238       result = Evaluate(input,x,y,z);
00239     }
00240     catch(std::exception& e) {
00241       std::cout << "Error: " << e.what() << std::endl;
00242       continue;
00243     }
00244     std::cout << ">> " << result << std::endl;
00245   }
00246   std::cout << "Goodbye!" << std::endl;
00247 
00248   //std::string test1("5+4");
00249   //double result1 = Evaluate(test1);
00250   //std::cout << test1 << " = " << result1 << std::endl;
00251   return 0;
00252 }*/
00253   

Generated on Wed Mar 26 2014 18:36:44 for Albany: a Trilinos-based PDE code by  doxygen 1.7.1