| 1 | #include "sopnamsp.h" | 
|---|
| 2 | #include "rpneval.h" | 
|---|
| 3 | #include <stdlib.h> | 
|---|
| 4 | #include <stdio.h> | 
|---|
| 5 | #include "strutilxx.h" | 
|---|
| 6 | #include "srandgen.h" | 
|---|
| 7 | #include <iostream> | 
|---|
| 8 | #include <math.h> | 
|---|
| 9 |  | 
|---|
| 10 | namespace SOPHYA { | 
|---|
| 11 |  | 
|---|
| 12 | /*! | 
|---|
| 13 | \class RPNExpressionEvaluator | 
|---|
| 14 | \ingroup SysTools | 
|---|
| 15 | Arithmetic expression (double precision float) evaluator | 
|---|
| 16 | in Reverse Polish Notation (RPN). This is an HP calculator | 
|---|
| 17 | like syntax. Spaces are used for separating the string | 
|---|
| 18 | expression into tokens. \n | 
|---|
| 19 | The string parsed by RPNExpressionEvaluator should be | 
|---|
| 20 | formed by a set of space separated words. Each word may be | 
|---|
| 21 | a numerical constant or operation or function. | 
|---|
| 22 | All numeriacl constants are pushed to stack top. | 
|---|
| 23 | The stack is limited only | 
|---|
| 24 | by the available memory. The three numbers on the stack top | 
|---|
| 25 | are referred to as <tt> x y z </tt>. \n | 
|---|
| 26 | Available operations: | 
|---|
| 27 | - op= + - * / % : replace (x,y) by x.op.y | 
|---|
| 28 | - e pi : M_PI , M_E numerical constants | 
|---|
| 29 | - f= sin cos tan asin acos atan : replace x by f(x) | 
|---|
| 30 | - f= chs sqrt sq : (x<-f(x)) change-sign , square root and square (x<-x^2) operations | 
|---|
| 31 | - f= log log10 exp : replace x by f(x) | 
|---|
| 32 | - f= fabs floor ceiling : replace x by f(x) | 
|---|
| 33 | - f= deg2rad rad2deg : replace x by f(x) | 
|---|
| 34 | - f= rand01 randpm1 gaurand : pushes a random number on the stack top ([0 1] [-1 1] Gaussian) | 
|---|
| 35 | - print x<>y pop push : stack operations | 
|---|
| 36 | - sum product : Replace the complete stack by the sum / product of the numbers in the stack | 
|---|
| 37 | - mean sigma : Replace the complete stack by the mean / sigma of the numbers in the stack | 
|---|
| 38 |  | 
|---|
| 39 | \sa CExpressionEvaluator Commander | 
|---|
| 40 |  | 
|---|
| 41 | The following output is produced by the sample code below: | 
|---|
| 42 | \code | 
|---|
| 43 | #include "rpneval.h" | 
|---|
| 44 | ... | 
|---|
| 45 | RPNExpressionEvaluator rpn1("4 2 print + 3 * "); | 
|---|
| 46 | cout << "RPN1: 4 2 + 3 * -> rpn1.Value() = " << rpn1.Value() << endl; | 
|---|
| 47 | RPNExpressionEvaluator rpn2("1 2 3 4 5 sum"); | 
|---|
| 48 | cout << "RPN2: 1 2 3 4 5 sum -> rpn2.Value() = " << rpn2.Value() << endl; | 
|---|
| 49 | \endcode | 
|---|
| 50 |  | 
|---|
| 51 | Output: | 
|---|
| 52 | \verbatim | 
|---|
| 53 | RPNExpressionEvaluator::PrintStack() Size()= 2 | 
|---|
| 54 | 0:  2   (x) | 
|---|
| 55 | 1:  4   (y) | 
|---|
| 56 | RPN1: 4 2 + 3 * -> rpn1.Value() = 18 | 
|---|
| 57 | RPN2: 1 2 3 4 5 sum -> rpn2.Value() = 15 | 
|---|
| 58 | \endverbatim | 
|---|
| 59 | */ | 
|---|
| 60 |  | 
|---|
| 61 | /*! | 
|---|
| 62 | \brief Parses the string \b sex into words and perform the specified operations on the stack. | 
|---|
| 63 |  | 
|---|
| 64 | Can throw  RPNExprException | 
|---|
| 65 | */ | 
|---|
| 66 | RPNExpressionEvaluator::RPNExpressionEvaluator(string const & sex) | 
|---|
| 67 | { | 
|---|
| 68 | vector<string> exe; | 
|---|
| 69 | FillVStringFrString(sex, exe, ' '); | 
|---|
| 70 | int rc = EvalRPNExpr(exe, 0); | 
|---|
| 71 | if (rc < exe.size()) { | 
|---|
| 72 | string msg = "RPNExpressionEvaluator() - syntax error near "; | 
|---|
| 73 | msg += exe[rc]; | 
|---|
| 74 | char buff[32]; | 
|---|
| 75 | sprintf(buff," (word %d)",rc); | 
|---|
| 76 | msg += buff; | 
|---|
| 77 | throw RPNExprException(msg); | 
|---|
| 78 | } | 
|---|
| 79 | } | 
|---|
| 80 |  | 
|---|
| 81 | /*! | 
|---|
| 82 | \brief Perform the operations specified by \b on the stack, starting from element \b exe[off]. | 
|---|
| 83 |  | 
|---|
| 84 | Can throw  RPNExprException | 
|---|
| 85 | */ | 
|---|
| 86 | RPNExpressionEvaluator::RPNExpressionEvaluator(vector<string> & exe, int off) | 
|---|
| 87 | { | 
|---|
| 88 | int rc = EvalRPNExpr(exe, off); | 
|---|
| 89 | if (rc < exe.size()) { | 
|---|
| 90 | string msg = "RPNExpressionEvaluator() - syntax error near "; | 
|---|
| 91 | msg += exe[rc]; | 
|---|
| 92 | char buff[32]; | 
|---|
| 93 | sprintf(buff," (word %d)",rc); | 
|---|
| 94 | msg += buff; | 
|---|
| 95 | throw RPNExprException(msg); | 
|---|
| 96 | } | 
|---|
| 97 | } | 
|---|
| 98 |  | 
|---|
| 99 | RPNExpressionEvaluator::~RPNExpressionEvaluator() | 
|---|
| 100 | { | 
|---|
| 101 | } | 
|---|
| 102 |  | 
|---|
| 103 | /* Operations sur le stack RPN */ | 
|---|
| 104 | /* --Methode-- */ | 
|---|
| 105 | //! Return the stack top (x) | 
|---|
| 106 | double RPNExpressionEvaluator::Evaluate() const | 
|---|
| 107 | { | 
|---|
| 108 | double x; | 
|---|
| 109 | if ( CheckStack( x) ) | 
|---|
| 110 | throw RPNExprException("RPNExpressionEvaluator::Evaluate() EmptyStack"); | 
|---|
| 111 | else return x; | 
|---|
| 112 | } | 
|---|
| 113 |  | 
|---|
| 114 | /* --Methode-- */ | 
|---|
| 115 | int RPNExpressionEvaluator::EvalRPNExpr(vector<string> & args, int off) | 
|---|
| 116 | { | 
|---|
| 117 |  | 
|---|
| 118 | if (args.size() <= off)  return 1; | 
|---|
| 119 | double x,y; | 
|---|
| 120 | x = y = 0.; | 
|---|
| 121 |  | 
|---|
| 122 | for(int k=off; k<args.size(); k++) { | 
|---|
| 123 | // Les 4 operations de base + - * / | 
|---|
| 124 | if (args[k] == "+") { | 
|---|
| 125 | if ( CheckStack( x, y) ) return k; | 
|---|
| 126 | rpnstack_.top() = y+x; | 
|---|
| 127 | } | 
|---|
| 128 | else if (args[k] == "-") { | 
|---|
| 129 | if ( CheckStack( x, y) ) return k; | 
|---|
| 130 | rpnstack_.top() = y-x; | 
|---|
| 131 | } | 
|---|
| 132 | else if (args[k] == "*") { | 
|---|
| 133 | if ( CheckStack( x, y) ) return k; | 
|---|
| 134 | rpnstack_.top() = y*x; | 
|---|
| 135 | } | 
|---|
| 136 | else if (args[k] == "/") { | 
|---|
| 137 | if ( CheckStack( x, y) ) return k; | 
|---|
| 138 | rpnstack_.top() = y/x; | 
|---|
| 139 | } | 
|---|
| 140 | else if (args[k] == "%") { | 
|---|
| 141 | if ( CheckStack( x, y) ) return k; | 
|---|
| 142 | rpnstack_.top() = (int)y % (int)x; | 
|---|
| 143 | } | 
|---|
| 144 | // Les constantes : e , pi | 
|---|
| 145 | else if (args[k] == "e") { | 
|---|
| 146 | rpnstack_.push(M_E); | 
|---|
| 147 | } | 
|---|
| 148 | else if (args[k] == "pi") { | 
|---|
| 149 | rpnstack_.push(M_PI); | 
|---|
| 150 | } | 
|---|
| 151 | // Les fonctions usuelles a 1 argument f(x) | 
|---|
| 152 | else if (args[k] == "cos") { | 
|---|
| 153 | if ( CheckStack( x) ) return k; | 
|---|
| 154 | rpnstack_.top() = cos(x); | 
|---|
| 155 | } | 
|---|
| 156 | else if (args[k] == "sin") { | 
|---|
| 157 | if ( CheckStack( x) ) return k; | 
|---|
| 158 | rpnstack_.top() = sin(x); | 
|---|
| 159 | } | 
|---|
| 160 | else if (args[k] == "tan") { | 
|---|
| 161 | if ( CheckStack( x) ) return k; | 
|---|
| 162 | rpnstack_.top() = tan(x); | 
|---|
| 163 | } | 
|---|
| 164 | else if (args[k] == "acos") { | 
|---|
| 165 | if ( CheckStack( x) ) return k; | 
|---|
| 166 | rpnstack_.top() = acos(x); | 
|---|
| 167 | } | 
|---|
| 168 | else if (args[k] == "asin") { | 
|---|
| 169 | if ( CheckStack( x) ) return k; | 
|---|
| 170 | rpnstack_.top() = asin(x); | 
|---|
| 171 | } | 
|---|
| 172 | else if (args[k] == "atan") { | 
|---|
| 173 | if ( CheckStack( x) ) return k; | 
|---|
| 174 | rpnstack_.top() = atan(x); | 
|---|
| 175 | } | 
|---|
| 176 | else if (args[k] == "chs") { | 
|---|
| 177 | if ( CheckStack( x) ) return k; | 
|---|
| 178 | rpnstack_.top() = -x; | 
|---|
| 179 | } | 
|---|
| 180 | else if (args[k] == "sqrt") { | 
|---|
| 181 | if ( CheckStack( x) ) return k; | 
|---|
| 182 | rpnstack_.top() = sqrt(x); | 
|---|
| 183 | } | 
|---|
| 184 | else if (args[k] == "sq") {  // x^2 | 
|---|
| 185 | if ( CheckStack( x) ) return k; | 
|---|
| 186 | rpnstack_.top() = x*x; | 
|---|
| 187 | } | 
|---|
| 188 | else if (args[k] == "log") { | 
|---|
| 189 | if ( CheckStack( x) ) return k; | 
|---|
| 190 | rpnstack_.top() = log(x); | 
|---|
| 191 | } | 
|---|
| 192 | else if (args[k] == "log10") { | 
|---|
| 193 | if ( CheckStack( x) ) return k; | 
|---|
| 194 | rpnstack_.top() = log10(x); | 
|---|
| 195 | } | 
|---|
| 196 | else if (args[k] == "exp") { | 
|---|
| 197 | if ( CheckStack( x) ) return k; | 
|---|
| 198 | rpnstack_.top() = exp(x); | 
|---|
| 199 | } | 
|---|
| 200 | else if (args[k] == "fabs") { | 
|---|
| 201 | if ( CheckStack( x) ) return k; | 
|---|
| 202 | rpnstack_.top() = fabs(x); | 
|---|
| 203 | } | 
|---|
| 204 | else if (args[k] == "floor") { | 
|---|
| 205 | if ( CheckStack( x) ) return k; | 
|---|
| 206 | rpnstack_.top() = floor(x); | 
|---|
| 207 | } | 
|---|
| 208 | else if (args[k] == "ceil") { | 
|---|
| 209 | if ( CheckStack( x) ) return k; | 
|---|
| 210 | rpnstack_.top() = ceil(x); | 
|---|
| 211 | } | 
|---|
| 212 | // trunc et nint vire - ca ne compile pas sous linux - Reza 01/2003 | 
|---|
| 213 | else if (args[k] == "deg2rad") { | 
|---|
| 214 | if ( CheckStack( x) ) return k; | 
|---|
| 215 | rpnstack_.top() = x*M_PI/180.; | 
|---|
| 216 | } | 
|---|
| 217 | else if (args[k] == "rad2deg") { | 
|---|
| 218 | if ( CheckStack( x) ) return k; | 
|---|
| 219 | rpnstack_.top() = x*180./M_PI; | 
|---|
| 220 | } | 
|---|
| 221 | // Les fonctions usuelles a 2 argument f(x,y) | 
|---|
| 222 | else if (args[k] == "pow") { | 
|---|
| 223 | if ( CheckStack( x, y) ) return k; | 
|---|
| 224 | rpnstack_.top() = pow(y,x); | 
|---|
| 225 | } | 
|---|
| 226 | else if (args[k] == "atan2") { | 
|---|
| 227 | if ( CheckStack( x, y) ) return k; | 
|---|
| 228 | rpnstack_.top() = atan2(x,y); | 
|---|
| 229 | } | 
|---|
| 230 | // generateur aleatoire | 
|---|
| 231 | else if (args[k] == "rand01") { | 
|---|
| 232 | double rnd = drand01(); | 
|---|
| 233 | rpnstack_.push(rnd); | 
|---|
| 234 | } | 
|---|
| 235 | else if (args[k] == "randpm1") { | 
|---|
| 236 | double rnd = drandpm1(); | 
|---|
| 237 | rpnstack_.push(rnd); | 
|---|
| 238 | } | 
|---|
| 239 | else if (args[k] == "gaurand") { | 
|---|
| 240 | double rnd = GauRnd(0., 1.); | 
|---|
| 241 | rpnstack_.push(rnd); | 
|---|
| 242 | } | 
|---|
| 243 | // Fonction a N arguments  - Somme, produit, etc ... | 
|---|
| 244 | else if ((args[k] == "sum") || (args[k] == "mean") || (args[k] == "sigmean") || | 
|---|
| 245 | (args[k] == "sigma") || (args[k] == "sigma2") ) { | 
|---|
| 246 | double sx, sx2; | 
|---|
| 247 | int nn = SumStack( sx, sx2); | 
|---|
| 248 | if (args[k] == "sum") rpnstack_.push(sx); | 
|---|
| 249 | else { | 
|---|
| 250 | if (nn == 0) return 1; | 
|---|
| 251 | double fnn = nn; | 
|---|
| 252 | if ((args[k] == "sigma") || (args[k] == "sigmean")) | 
|---|
| 253 | rpnstack_.push(sqrt(sx2/fnn-(x*x/(fnn*fnn)))); | 
|---|
| 254 | else if ((args[k] == "mean") || (args[k] == "sigmean"))  rpnstack_.push(sx/fnn); | 
|---|
| 255 | else rpnstack_.push(sx2/fnn-(x*x/(fnn*fnn))); | 
|---|
| 256 | } | 
|---|
| 257 | } | 
|---|
| 258 | else if (args[k] == "product") { | 
|---|
| 259 | double px; | 
|---|
| 260 | int nn = ProductStack( px); | 
|---|
| 261 | if (nn == 0) return k; | 
|---|
| 262 | rpnstack_.push(px); | 
|---|
| 263 | } | 
|---|
| 264 | // Fonctions de manipulation de stack | 
|---|
| 265 | else if (args[k] == "print") { | 
|---|
| 266 | PrintStack(); | 
|---|
| 267 | } | 
|---|
| 268 | else if (args[k] == "x<>y") { | 
|---|
| 269 | if ( CheckStack( x, y) ) return k; | 
|---|
| 270 | rpnstack_.top() = x;  rpnstack_.push(y); | 
|---|
| 271 | } | 
|---|
| 272 | else if (args[k] == "pop") { | 
|---|
| 273 | rpnstack_.pop(); | 
|---|
| 274 | } | 
|---|
| 275 | else if (args[k] == "push") { | 
|---|
| 276 | if (rpnstack_.empty()) rpnstack_.push(0.); | 
|---|
| 277 | else rpnstack_.push(rpnstack_.top()); | 
|---|
| 278 | } | 
|---|
| 279 | // On met un nombre sur le stack | 
|---|
| 280 | else { | 
|---|
| 281 | char * esptr; | 
|---|
| 282 | x = strtod(args[k].c_str(), &esptr); | 
|---|
| 283 | //      if (ctof(args[k].c_str(),&x) < 0) { | 
|---|
| 284 | if (esptr == args[k].c_str()) return k; | 
|---|
| 285 | rpnstack_.push(x); | 
|---|
| 286 | } | 
|---|
| 287 |  | 
|---|
| 288 | } | 
|---|
| 289 | return(args.size()+1); | 
|---|
| 290 | } | 
|---|
| 291 |  | 
|---|
| 292 | inline void RPNExpressionEvaluator::PrintStack() | 
|---|
| 293 | { | 
|---|
| 294 | if (rpnstack_.empty()) | 
|---|
| 295 | cout << "RPNExpressionEvaluator::PrintStack() Empty stack " << endl; | 
|---|
| 296 | else { | 
|---|
| 297 | stack<double> s; | 
|---|
| 298 | s = rpnstack_; | 
|---|
| 299 | int k = 0; | 
|---|
| 300 | cout << "RPNExpressionEvaluator::PrintStack() Size()= " << s.size() << endl; | 
|---|
| 301 | while( !s.empty() ) { | 
|---|
| 302 | cout << "    " << k << ":  " << s.top() << "  "; | 
|---|
| 303 | if (k == 0)  cout << " (x) " << endl; | 
|---|
| 304 | else if (k == 1) cout << " (y) " << endl; | 
|---|
| 305 | else if (k == 2) cout << " (z) " << endl; | 
|---|
| 306 | else cout << endl; | 
|---|
| 307 | s.pop(); k++; | 
|---|
| 308 | } | 
|---|
| 309 | } | 
|---|
| 310 |  | 
|---|
| 311 | } | 
|---|
| 312 |  | 
|---|
| 313 | int RPNExpressionEvaluator::SumStack(double& sx, double& sx2) | 
|---|
| 314 | { | 
|---|
| 315 | sx = sx2 = 0.; | 
|---|
| 316 | int nn = 0; | 
|---|
| 317 | double x = 0.; | 
|---|
| 318 | while( !rpnstack_.empty() ) { | 
|---|
| 319 | x = rpnstack_.top(); rpnstack_.pop(); | 
|---|
| 320 | sx += x; sx2 += x*x; | 
|---|
| 321 | nn++; | 
|---|
| 322 | } | 
|---|
| 323 | return(nn); | 
|---|
| 324 | } | 
|---|
| 325 |  | 
|---|
| 326 | int RPNExpressionEvaluator::ProductStack(double& px) | 
|---|
| 327 | { | 
|---|
| 328 | px = 1.; | 
|---|
| 329 | int nn = 0; | 
|---|
| 330 | double x = 0.; | 
|---|
| 331 | while( !rpnstack_.empty() ) { | 
|---|
| 332 | x = rpnstack_.top(); rpnstack_.pop(); | 
|---|
| 333 | px *= x;  nn++; | 
|---|
| 334 | } | 
|---|
| 335 | return(nn); | 
|---|
| 336 | } | 
|---|
| 337 |  | 
|---|
| 338 |  | 
|---|
| 339 | } // End of namespace SOPHYA | 
|---|