/** * Return a set of the variables in the supplied expression. Note: Substitutions which are in the * constant table are not included. */ public Set<String> getVariablesWithin(String exp) { Set<String> all = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER); String add = null; if (separators == null) { StringBuilder sep = new StringBuilder(10); for (char chr = 0; chr < operators.length; chr++) { if (operators[chr] != null && !operators[chr].internal) { sep.append(chr); } } sep.append("()"); separators = sep.toString(); } for (StringTokenizer tkz = new StringTokenizer(exp, separators, true); tkz.hasMoreTokens(); ) { String tkn = tkz.nextToken().trim(); if (tkn.length() != 0 && Character.isLetter(tkn.charAt(0))) { add = tkn; } else if (tkn.length() == 1 && tkn.charAt(0) == '(') { add = null; } else if (add != null && !constants.containsKey(add)) { all.add(add); } } if (add != null && !constants.containsKey(add)) { all.add(add); } return all; }
/** * Set a named constant (constants names are not case-sensitive). Constants are like variables but * are not cleared by clear(). Variables of the same name have precedence over constants. */ public MathEval setConstant(String nam, Double val) { if (constants.get(nam) != null) { throw new IllegalArgumentException("Constants may not be redefined"); } validateName(nam); constants.put(nam, val); return this; }
/** * Set a named variable (variables names are not case-sensitive). If the value is null, the * variable is removed. */ public MathEval setVariable(String nam, Double val) { validateName(nam); if (val == null) { variables.remove(nam); } else { variables.put(nam, val); } return this; }
private double doNamedVal(int beg, int end) { while (beg < end && Character.isWhitespace(expression.charAt(end))) { end--; } // since a letter triggers a named value, this can never reduce to beg==end String nam = expression.substring(beg, (end + 1)); Double val; if ((val = constants.get(nam)) != null) { return val.doubleValue(); } else if ((val = variables.get(nam)) != null) { isConstant = false; return val.doubleValue(); } else if (relaxed) { isConstant = false; return 0.0; } throw exception(beg, "Unrecognized constant or variable \"" + nam + "\""); }
private double doFunction(int beg, int end) { int argbeg; for (argbeg = beg; argbeg <= end && expression.charAt(argbeg) != '('; argbeg++) {; } String fncnam = expression.substring(beg, argbeg).trim(); ArgParser fncargs = new ArgParser(argbeg, end); FunctionHandler fnchdl = null; try { if ((fnchdl = pureFunctions.get(fncnam)) != null) { return fnchdl.evaluateFunction(fncnam, fncargs); } else if ((fnchdl = impureFunctions.get(fncnam)) != null) { isConstant = false; // impure functions cannot be guaranteed to be constant return fnchdl.evaluateFunction(fncnam, fncargs); } fncargs = null; // suppress check for too many fncargs } catch (ArithmeticException thr) { fncargs = null; throw thr; } catch (NoSuchMethodError thr) { fncargs = null; throw exception(beg, "Function not supported in this JVM: \"" + fncnam + "\""); } catch (UnsupportedOperationException thr) { fncargs = null; throw exception(beg, thr.getMessage()); } catch (Throwable thr) { fncargs = null; throw exception(beg, "Unexpected exception parsing function arguments", thr); } finally { if (fncargs != null) { if (fncargs.hasNext()) { throw exception(fncargs.getIndex(), "Function has too many arguments"); } offset = fncargs.getIndex(); } } throw exception(beg, "Function \"" + fncnam + "\" not recognized"); }
/** * Create a math evaluator with the same constants, variables, function handlers and relaxation * setting as the supplied evaluator. */ public MathEval(MathEval oth) { super(); operators = oth.operators; constants = new TreeMap<String, Double>(String.CASE_INSENSITIVE_ORDER); constants.putAll(oth.constants); variables = new TreeMap<String, Double>(String.CASE_INSENSITIVE_ORDER); variables.putAll(oth.variables); pureFunctions = new TreeMap<String, FunctionHandler>(String.CASE_INSENSITIVE_ORDER); impureFunctions = new TreeMap<String, FunctionHandler>(String.CASE_INSENSITIVE_ORDER); pureFunctions.putAll(oth.pureFunctions); impureFunctions.putAll(oth.impureFunctions); relaxed = oth.relaxed; separators = oth.separators; offset = 0; isConstant = false; }
/** * Set a function handler for the specific named function optionally tagging the function as * impure, replacing any existing handler for the given name; if the handler is null the function * handler is removed. * * <p>Pure functions have results which depend purely on their arguments; given constant arguments * they will have a constant result. Impure functions are rare. */ public MathEval setFunctionHandler(String nam, FunctionHandler hdl, boolean impure) { validateName(nam); if (hdl == null) { pureFunctions.remove(nam); impureFunctions.remove(nam); } else if (impure) { pureFunctions.remove(nam); impureFunctions.put(nam, hdl); } else { pureFunctions.put(nam, hdl); impureFunctions.remove(nam); } return this; }
/** * Clear all variables prefixed by the supplied string followed by a dot, such that they match * "Prefix.xxx". */ public MathEval clear(String pfx) { variables.subMap((pfx + "."), (pfx + "." + Character.MAX_VALUE)).clear(); return this; }
/** Clear all variables (constants are not affected). */ public MathEval clear() { variables.clear(); return this; }
/** Set a named variable (variables names are not case-sensitive). */ public double getVariable(String nam) { Double val = variables.get(nam); return (val == null ? 0 : val.doubleValue()); }
/** * Set a named constant (constant names are not case-sensitive). Constants are like variables but * are not cleared by clear(). Variables of the same name have precedence over constants. */ public double getConstant(String nam) { Double val = constants.get(nam); return (val == null ? 0 : val.doubleValue()); }