1 25 26 package org.jrobin.core; 27 28 import java.util.StringTokenizer ; 29 30 class RpnCalculator { 31 static final String VAR_PLACEHOLDER = "value"; 32 33 private static final byte TOK_VAR = 0; 34 private static final byte TOK_NUM = 1; 35 private static final byte TOK_PLUS = 2; 36 private static final byte TOK_MINUS = 3; 37 private static final byte TOK_MULT = 4; 38 private static final byte TOK_DIV = 5; 39 private static final byte TOK_MOD = 6; 40 private static final byte TOK_SIN = 7; 41 private static final byte TOK_COS = 8; 42 private static final byte TOK_LOG = 9; 43 private static final byte TOK_EXP = 10; 44 private static final byte TOK_FLOOR = 11; 45 private static final byte TOK_CEIL = 12; 46 private static final byte TOK_ROUND = 13; 47 private static final byte TOK_POW = 14; 48 private static final byte TOK_ABS = 15; 49 private static final byte TOK_SQRT = 16; 50 private static final byte TOK_RANDOM = 17; 51 private static final byte TOK_LT = 18; 52 private static final byte TOK_LE = 19; 53 private static final byte TOK_GT = 20; 54 private static final byte TOK_GE = 21; 55 private static final byte TOK_EQ = 22; 56 private static final byte TOK_IF = 23; 57 private static final byte TOK_MIN = 24; 58 private static final byte TOK_MAX = 25; 59 private static final byte TOK_LIMIT = 26; 60 private static final byte TOK_DUP = 27; 61 private static final byte TOK_EXC = 28; 62 private static final byte TOK_POP = 29; 63 private static final byte TOK_UN = 30; 64 private static final byte TOK_UNKN = 31; 65 private static final byte TOK_PI = 34; 68 private static final byte TOK_E = 35; 69 private static final byte TOK_AND = 36; 70 private static final byte TOK_OR = 37; 71 private static final byte TOK_XOR = 38; 72 73 private String [] tokens; 74 private byte[] tokenCodes; 75 private double[] parsedDoubles; 76 private RpnStack stack = new RpnStack(); 77 78 private String rpnExpression; 79 private double value; 80 82 RpnCalculator(String rpnExpression) throws RrdException { 83 this.rpnExpression = rpnExpression; 84 createTokens(); 85 } 86 87 void setValue(double value) { 88 this.value = value; 89 } 90 91 96 97 private void createTokens() throws RrdException { 98 StringTokenizer st = new StringTokenizer (rpnExpression, ","); 99 int count = st.countTokens(); 100 tokens = new String [count]; 101 tokenCodes = new byte[count]; 102 parsedDoubles = new double[count]; 103 for(int i = 0; st.hasMoreTokens(); i++) { 104 String token = st.nextToken(); 105 tokens[i] = token; 106 byte tokenCode = findTokenCode(token); 107 tokenCodes[i] = tokenCode; 108 if(tokenCode == TOK_NUM) { 109 parsedDoubles[i] = Double.parseDouble(token); 110 } 111 } 112 } 113 114 private byte findTokenCode(String token) throws RrdException { 115 if(isVariable(token)) { 116 return TOK_VAR; 117 } 118 else if(isNumber(token)) { 119 return TOK_NUM; 120 } 121 else if(token.equals("+")) { 122 return TOK_PLUS; 123 } 124 else if(token.equals("-")) { 125 return TOK_MINUS; 126 } 127 else if(token.equals("*")) { 128 return TOK_MULT; 129 } 130 else if(token.equals("/")) { 131 return TOK_DIV; 132 } 133 else if(token.equals("%")) { 134 return TOK_MOD; 135 } 136 else if(token.equals("SIN")) { 137 return TOK_SIN; 138 } 139 else if(token.equals("COS")) { 140 return TOK_COS; 141 } 142 else if(token.equals("LOG")) { 143 return TOK_LOG; 144 } 145 else if(token.equals("EXP")) { 146 return TOK_EXP; 147 } 148 else if(token.equals("FLOOR")) { 149 return TOK_FLOOR; 150 } 151 else if(token.equals("CEIL")) { 152 return TOK_CEIL; 153 } 154 else if(token.equals("ROUND")) { 155 return TOK_ROUND; 156 } 157 else if(token.equals("POW")) { 158 return TOK_POW; 159 } 160 else if(token.equals("ABS")) { 161 return TOK_ABS; 162 } 163 else if(token.equals("SQRT")) { 164 return TOK_SQRT; 165 } 166 else if(token.equals("RANDOM")) { 167 return TOK_RANDOM; 168 } 169 else if(token.equals("LT")) { 170 return TOK_LT; 171 } 172 else if(token.equals("LE")) { 173 return TOK_LE; 174 } 175 else if(token.equals("GT")) { 176 return TOK_GT; 177 } 178 else if(token.equals("GE")) { 179 return TOK_GE; 180 } 181 else if(token.equals("EQ")) { 182 return TOK_EQ; 183 } 184 else if(token.equals("IF")) { 185 return TOK_IF; 186 } 187 else if(token.equals("MIN")) { 188 return TOK_MIN; 189 } 190 else if(token.equals("MAX")) { 191 return TOK_MAX; 192 } 193 else if(token.equals("LIMIT")) { 194 return TOK_LIMIT; 195 } 196 else if(token.equals("DUP")) { 197 return TOK_DUP; 198 } 199 else if(token.equals("EXC")) { 200 return TOK_EXC; 201 } 202 else if(token.equals("POP")) { 203 return TOK_POP; 204 } 205 else if(token.equals("UN")) { 206 return TOK_UN; 207 } 208 else if(token.equals("UNKN")) { 209 return TOK_UNKN; 210 } 211 212 220 else if(token.equals("PI")) { 221 return TOK_PI; 222 } 223 else if(token.equals("E")) { 224 return TOK_E; 225 } 226 else if(token.equals("AND")) { 227 return TOK_AND; 228 } 229 else if(token.equals("OR")) { 230 return TOK_OR; 231 } 232 else if(token.equals("XOR")) { 233 return TOK_XOR; 234 } 235 else { 236 throw new RrdException("Unknown RPN token encountered: " + token); 237 } 238 } 239 240 private static boolean isNumber(String token) { 241 try { 242 Double.parseDouble(token); 243 return true; 244 } 245 catch(NumberFormatException nfe) { 246 return false; 247 } 248 } 249 250 private static boolean isVariable(String token) { 251 return token.equals(VAR_PLACEHOLDER); 252 } 253 254 double calculate() throws RrdException { 255 resetCalculator(); 256 for(int i = 0; i < tokenCodes.length; i++) { 257 byte tokenCode = tokenCodes[i]; 258 double x1, x2, x3; 259 switch(tokenCode) { 260 case TOK_NUM: 261 push(parsedDoubles[i]); break; 262 case TOK_VAR: 263 push(value); break; 264 case TOK_PLUS: 265 push(pop() + pop()); break; 266 case TOK_MINUS: 267 x2 = pop(); x1 = pop(); push(x1 - x2); break; 268 case TOK_MULT: 269 push(pop() * pop()); break; 270 case TOK_DIV: 271 x2 = pop(); x1 = pop(); push(x1 / x2); break; 272 case TOK_MOD: 273 x2 = pop(); x1 = pop(); push(x1 % x2); break; 274 case TOK_SIN: 275 push(Math.sin(pop())); break; 276 case TOK_COS: 277 push(Math.cos(pop())); break; 278 case TOK_LOG: 279 push(Math.log(pop())); break; 280 case TOK_EXP: 281 push(Math.exp(pop())); break; 282 case TOK_FLOOR: 283 push(Math.floor(pop())); break; 284 case TOK_CEIL: 285 push(Math.ceil(pop())); break; 286 case TOK_ROUND: 287 push(Math.round(pop())); break; 288 case TOK_POW: 289 x2 = pop(); x1 = pop(); push(Math.pow(x1, x2)); break; 290 case TOK_ABS: 291 push(Math.abs(pop())); break; 292 case TOK_SQRT: 293 push(Math.sqrt(pop())); break; 294 case TOK_RANDOM: 295 push(Math.random()); break; 296 case TOK_LT: 297 x2 = pop(); x1 = pop(); push(x1 < x2? 1: 0); break; 298 case TOK_LE: 299 x2 = pop(); x1 = pop(); push(x1 <= x2? 1: 0); break; 300 case TOK_GT: 301 x2 = pop(); x1 = pop(); push(x1 > x2? 1: 0); break; 302 case TOK_GE: 303 x2 = pop(); x1 = pop(); push(x1 >= x2? 1: 0); break; 304 case TOK_EQ: 305 x2 = pop(); x1 = pop(); push(x1 == x2? 1: 0); break; 306 case TOK_IF: 307 x3 = pop(); x2 = pop(); x1 = pop(); push(x1 != 0? x2: x3); break; 308 case TOK_MIN: 309 push(Math.min(pop(), pop())); break; 310 case TOK_MAX: 311 push(Math.max(pop(), pop())); break; 312 case TOK_LIMIT: 313 x3 = pop(); x2 = pop(); x1 = pop(); 314 push(x1 < x2 || x1 > x3? Double.NaN: x1); break; 315 case TOK_DUP: 316 x1 = pop(); push(x1); push(x1); break; 317 case TOK_EXC: 318 x2 = pop(); x1 = pop(); push(x2); push(x1); break; 319 case TOK_POP: 320 pop(); break; 321 case TOK_UN: 322 push(Double.isNaN(pop())? 1: 0); break; 323 case TOK_UNKN: 324 push(Double.NaN); break; 325 331 case TOK_PI: 332 push(Math.PI); break; 333 case TOK_E: 334 push(Math.E); break; 335 case TOK_AND: 336 x2 = pop(); x1 = pop(); push((x1 != 0 && x2 != 0)? 1: 0); break; 337 case TOK_OR: 338 x2 = pop(); x1 = pop(); push((x1 != 0 || x2 != 0)? 1: 0); break; 339 case TOK_XOR: 340 x2 = pop(); x1 = pop(); 341 push(((x1 != 0 && x2 == 0) || (x1 == 0 && x2 != 0))? 1: 0); break; 342 default: 343 throw new RrdException("Unexpected RPN token encountered [" + 344 tokenCode + "]"); 345 } 346 } 347 double retVal = pop(); 348 if(!isStackEmpty()) { 349 throw new RrdException("Stack not empty at the end of calculation. " + 350 "Probably bad RPN expression"); 351 } 352 return retVal; 353 } 354 355 void push(double x) throws RrdException { 356 stack.push(x); 357 } 358 359 double pop() throws RrdException { 360 return stack.pop(); 361 } 362 363 void resetCalculator() { 364 stack.reset(); 365 } 366 367 boolean isStackEmpty() { 368 return stack.isEmpty(); 369 } 370 371 class RpnStack { 372 static final int MAX_STACK_SIZE = 1000; 373 private double[] stack = new double[MAX_STACK_SIZE]; 374 private int pos = 0; 375 376 void push(double x) throws RrdException { 377 if(pos >= MAX_STACK_SIZE) { 378 throw new RrdException( 379 "PUSH failed, RPN stack full [" + MAX_STACK_SIZE + "]"); 380 } 381 stack[pos++] = x; 382 } 383 384 double pop() throws RrdException { 385 if(pos <= 0) { 386 throw new RrdException("POP failed, RPN stack is empty "); 387 } 388 return stack[--pos]; 389 } 390 391 void reset() { 392 pos = 0; 393 } 394 395 boolean isEmpty() { 396 return pos == 0; 397 } 398 } 399 400 407 } 408 | Popular Tags |