Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

exprparser.h

Go to the documentation of this file.
00001 
00007 #ifndef ___EXPRPARSER_H___
00008 #define ___EXPRPARSER_H___
00009 
00010 #include <stdio.h>
00011 #include <string>
00012 using std::string;
00013 
00014 #include "../src/msg.h"
00015 #include "../src/polymorph.h"
00016 
00017 
00018 
00038 template <class T=int>
00039 class ExprParser {
00040 public:
00043   ExprParser(const char* expr, Msg::LevelHandler<>** mhp_i=&(Msg::LevelHandler<>::default_instance()))
00044     : remaining(expr)  {  mhp = mhp_i;  };
00045 
00046   virtual ~ExprParser() { }
00047 
00049 
00050 
00052   double       cmdf() {  return (double)read_float();  }
00053   
00055   long         cmdi() {
00056     exprtype result = read_float();
00057     if (result >= INT_MAX || result <= INT_MIN)
00058       message(Msg::Warning,"Value " + String::stringrep(double(result)) +
00059               " outside the representable range of an integer (" +
00060               String::stringrep(INT_MIN) + "," + String::stringrep(INT_MAX) +
00061               "); may cause overflow or underflow");
00062     
00063     return (long)(floor(0.5+result));
00064   }
00065   
00067   const char * cmds() {  return getstringval();  }
00069 
00073   bool consumeifpresent(string s) {
00074     if (strncmp(s.c_str(), remaining, s.length()) == 0) {
00075       remaining += s.length();
00076       return true;
00077     }
00078     return false;
00079   }
00080 
00081   string whatsleft() {  return string(remaining);  }
00082   
00084   bool empty() const {  return (*remaining==0);  }
00085   
00086   static void message(Msg::MessageLevel m, const string& s)
00087     {  if (mhp && *mhp) (**mhp)(m,s);  }
00088   
00090   typedef
00091 #ifndef LONG_DOUBLE_UNAVAILABLE
00092   long
00093 #endif
00094   double exprtype;
00095 
00096   exprtype        getnumericval();
00097 
00098 protected:
00099   virtual const Typeless& getval();
00100   const char*     remaining;
00101 
00102 private:
00103   virtual const char* getstringval();
00104   exprtype        read_float(bool warn=true);
00105   exprtype        apply_op(exprtype lval, string op, exprtype rval);
00106   exprtype        next_term(string previous_op="");
00107   string          next_op();
00108   exprtype        parse_expr();
00109   int             op_has_precedence(const string& previous_op, const string& op);
00110   static Msg::LevelHandler<>** mhp;
00111 };
00112 
00113 /* Static variables */
00114 template <class T>
00115 Msg::LevelHandler<>** ExprParser<T>::mhp=&(Msg::LevelHandler<>::default_instance());
00116 
00117 
00126 template <class T>
00127 const Typeless& ExprParser<T>::getval()
00128 {
00129   const char* str = remaining;
00130   char *rem;
00131   static Polymorph<double> numval(0.0);
00132   numval = strtod(str,&rem);
00133   remaining = rem;
00134 
00135   if (str == remaining) {
00136     while (*remaining && (*remaining != ')'))
00137       remaining++;  /* Skip this item */
00138     message(Msg::Error,"Can't parse expression: `" + string(str) + "'");
00139     numval=-1;
00140   }
00141   
00142   return numval;
00143 }
00144 
00145 
00146 
00155 template <class T>
00156 const char *ExprParser<T>::getstringval()
00157 {
00158   const size_t bufsize=65536; // Arbitrary limit
00159   static char buf[bufsize];
00160   const char* maxbufptr=buf+bufsize;
00161 
00162   char* bufptr=buf;
00163 
00164   while (remaining && *remaining && bufptr<maxbufptr) {
00165     /* Copy all characters directly */
00166     while (*remaining && bufptr<maxbufptr)
00167       *(bufptr++) = *(remaining)++;
00168   }
00169   if (bufptr>=maxbufptr)
00170     message(Msg::Error,"Reached maximum string size; characters may be lost");
00171   
00172   *bufptr='\0';
00173     
00174   return buf;
00175 }
00176 
00177 
00178 
00184 template <class T>
00185 typename ExprParser<T>::exprtype ExprParser<T>::getnumericval()
00186 {
00187   const char* str = remaining;
00188   
00189   if (*remaining == '(') {
00190     exprtype subexpr;
00191     (remaining)++;    
00192     subexpr=(parse_expr());
00193     
00194     if (*remaining != ')')
00195       message(Msg::Error,"Missing right parenthesis");
00196     else
00197       (remaining)++;
00198     return subexpr;
00199   }
00200 
00201   if (*remaining == '-') {
00202     (remaining)++;        
00203     return -1.0*next_term();
00204   }
00205   
00206   const Typeless& val = getval();
00207   if (val.isnumeric())
00208     return val.numericvalue();
00209   else
00210     message(Msg::Error,"Invalid param type in expression `" + string(str) + "'");
00211  
00212   return Uninitialized;
00213 }
00214 
00215 
00216 
00218 template <class T>
00219 typename ExprParser<T>::exprtype ExprParser<T>::apply_op(exprtype lval, string op, exprtype rval)
00220 {
00221   if      (op == "+")  return lval +  rval;
00222   else if (op == "-")  return lval -  rval;
00223   else if (op == "*")  return lval *  rval;
00224   else if (op == "<")  return lval <  rval;
00225   else if (op == ">")  return lval >  rval;
00226   else if (op == "==") return lval == rval;
00227   else if (op == "!=") return lval != rval;
00228   else if (op == "<=") return lval <= rval;
00229   else if (op == ">=") return lval >= rval;
00230   else if (op == "<?") return std::min(lval,rval);
00231   else if (op == ">?") return std::max(lval,rval);
00232   else if (op == "@;") return lval * sin(rval); /* Appallingly bad notation! */
00233   else if (op == "@:") return lval * cos(rval); /* Appallingly bad notation! */
00234   
00235   else if (op == "%" || op == "/") {
00236     if (rval==0) {
00237       message(Msg::Error,"Division by zero");
00238       return Uninitialized;
00239     }
00240     if (op == "/") return lval / rval;
00241     else           return fmod(lval,rval);
00242   }
00243   
00244   message(Msg::Error,"Unknown operator " + op);
00245   return Uninitialized;
00246 }
00247 
00248 
00249 
00250 template <class T>
00251 int ExprParser<T>::op_has_precedence(const string& previous_op, const string& op)
00252 {
00253   (void) previous_op; /* Currently ignored */
00254   return (op=="*" || op=="/" | op=="%");
00255 }
00256 
00257 
00258 
00259 template <class T>
00260 string ExprParser<T>::next_op()
00261 {
00262   const char* start=remaining;
00263 
00264   while (ispunct(*remaining) && !(*remaining=='(') && !(*remaining==':' && *(remaining+1)==':'))
00265     (remaining)++;
00266 
00267   const char* end=remaining;
00268 
00269   return string(start,end-start);
00270 }
00271 
00272 
00273 
00274 template <class T>
00275 typename ExprParser<T>::exprtype ExprParser<T>::next_term(string previous_op)
00276 {
00277   exprtype lval = getnumericval();
00278   string op = next_op();
00279   
00280   /* Reduce strings of operators with precedence */
00281   while (op_has_precedence(previous_op, op)) {
00282     if (! *remaining) {
00283       message(Msg::Error,"Missing right value in `" + string(remaining) + "'");
00284       return lval;
00285     }
00286     lval=apply_op(lval,op,getnumericval());
00287     previous_op = op;
00288     op = next_op();
00289   }
00290   remaining -= op.length(); /* Push back unused operator */
00291 
00292   return lval;
00293 }
00294 
00295 
00296 
00297 template <class T>
00298 typename ExprParser<T>::exprtype ExprParser<T>::parse_expr()
00299 {
00300   const char* str = remaining;
00301   exprtype lval = next_term();
00302 
00303   while (*remaining && *remaining != ')') {
00304     string op= next_op();
00305     
00306     if (! *remaining) {
00307       message(Msg::Error,"Missing right value in `" + string(str) + "'");
00308       return lval;
00309     }
00310     
00311     lval = apply_op(lval,op,next_term(op));
00312   }
00313 
00314   return lval;
00315 }
00316 
00317 
00318 
00320 template <class T>
00321 typename ExprParser<T>::exprtype ExprParser<T>::read_float(bool warn)
00322 {
00323   const char* str = remaining;
00324   exprtype val = parse_expr();
00325 
00326   if (str == remaining) {
00327     message(Msg::Error,"No number found in string: `" + string(str) + "'");
00328     return Uninitialized;
00329   }
00330   
00331   if (warn && *remaining)
00332     message(Msg::Warning,"Trailing characters in expression ignored: `" + string(remaining) + "'");
00333   return val;
00334 }
00335 
00336 
00337 
00338 #endif /* ___EXPRPARSER_H___ */

Generated on Mon Jan 20 02:35:44 2003 for RF-LISSOM by doxygen1.3-rc2