// Copyright (C) 2003-2009 by Object Mentor, Inc. All rights reserved. // Released under the terms of the CPL Common Public License version 1.0. package fitnesse.wikitext.parser; public class Expression { /* * Strings used for storing expression. */ private String s, x; private boolean isInvalid; /* * Term evaluator for number literals. */ private double term() { double ans = 0; StringBuilder temp = new StringBuilder(); while (!s.isEmpty() && Character.isDigit(s.charAt(0))) { temp.append(Integer.parseInt("" + s.charAt(0))); advance(); } if (!s.isEmpty() && s.charAt(0) == '.') { temp.append('.'); advance(); while (!s.isEmpty() && Character.isDigit(s.charAt(0))) { temp.append(Integer.parseInt("" + s.charAt(0))); advance(); } } if (!s.isEmpty() && (s.charAt(0) == 'e' || s.charAt(0) == 'E')) { temp.append('e'); advance(); temp.append(s.charAt(0)); advance(); while (!s.isEmpty() && Character.isDigit(s.charAt(0))) { temp.append(Integer.parseInt("" + s.charAt(0))); advance(); } } if (temp.length() == 0) //...invalid expression term isInvalid = true; else ans = Double.valueOf(temp.toString()); return ans; } /* * Parentheses solver. */ private double paren() { double ans; if (s.charAt(0) == '(') { advance(); ans = add(); advance(); } else { ans = term(); } return ans; } /* * Exponentiation solver. */ private double exp() { boolean neg = false; if (s.charAt(0) == '-') { neg = true; advance(); } double result = paren(); while (!s.isEmpty()) { if (s.charAt(0) == '^') { result = exponentiate(result); } else break; } if (neg) result *= -1; return result; } private double exponentiate(double result) { advance(); boolean expNeg = false; if (s.charAt(0) == '-') { expNeg = true; advance(); } double e = paren(); if (result < 0) result = exponentiateNegativeNumber(result, expNeg, e); else if (expNeg) result = Math.exp(-e * Math.log(result)); else result = Math.exp(e * Math.log(result)); return result; } private void advance() { s = s.substring(1); } private double exponentiateNegativeNumber(double result, boolean expNeg, double e) { if (Math.ceil(e) == e) { result = calculateIntegralExponent(result, expNeg, e); } else { result = Double.NaN; } return result; } private double calculateIntegralExponent(double result, boolean expNeg, double e) { double x = 1; if (expNeg) e *= -1; if (e == 0) result = 1; else if (e > 0) for (int i = 0; i < e; i++) x *= result; else for (int i = 0; i < -e; i++) x /= result; result = x; return result; } /* * Trigonometric function solver. */ private double trig() { double ans = 0; boolean found = false; if (s.indexOf("sin") == 0) { s = s.substring(3); ans = Math.sin(trig()); found = true; } else if (s.indexOf("cos") == 0) { s = s.substring(3); ans = Math.cos(trig()); found = true; } else if (s.indexOf("tan") == 0) { s = s.substring(3); ans = Math.tan(trig()); found = true; } if (!found) { ans = exp(); } return ans; } /* * Multiplication, division expression solver. */ private double mul() { double ans = trig(); while (!s.isEmpty()) { if (s.charAt(0) == '*') { advance(); ans *= trig(); } else if (s.charAt(0) == '/') { advance(); ans /= trig(); } else break; } return ans; } /* * Addition, subtraction expression solver. */ private double add() { double ans = mul(); while (!s.isEmpty()) { if (s.charAt(0) == '+') { advance(); ans += mul(); } else if (s.charAt(0) == '-') { advance(); ans -= mul(); } else { break; } } return ans; } /* * Public access method to evaluate this expression. */ public Maybe<Double> evaluate() { isInvalid = false; s = x.intern(); double last = add(); return isInvalid ? Maybe.noDouble : new Maybe<>(last); } /* * Creates new Expression. */ public Expression(String s) { // remove white space, assume only spaces or tabs x = s.replaceAll("[ \t]", ""); } /* * The String value of this Expression. */ @Override public String toString() { return x.intern(); } }