📄 evalspice.java
字号:
val = val * 1e6; } else if (tokenizer.sval.equalsIgnoreCase("k")) { val = val * 1e3; } else if (tokenizer.sval.equalsIgnoreCase("m")) { val = val * 1e-3; } else if (tokenizer.sval.equalsIgnoreCase("u")) { val = val * 1e-6; } else if (tokenizer.sval.equalsIgnoreCase("n")) { val = val * 1e-9; } else if (tokenizer.sval.equalsIgnoreCase("p")) { val = val * 1e-12; } else if (tokenizer.sval.equalsIgnoreCase("f")) { val = val * 1e-15; } else throw new ParseException("Invalid token"); } else { tokenizer.pushBack(); } tokenizer.wordChars('e', 'e'); tokenizer.wordChars('E', 'E'); return new Double(val); } throw new ParseException("Expected number"); } private void expect(int token) throws IOException, ParseException { int tt = tokenizer.nextToken(); if (tt != token) throw new ParseException("Expected token "+token); } // ==================== Parsable Objects ======================== public static class ParseException extends Exception { public ParseException(String msg) { super(msg); } } public static class Op { public final String name; public final int precedence; private Op(String name, int precedence) { this.name = name; this.precedence = precedence; } public String toString() { return name; } // operators with lower value precedence bind tighter than higher value precedence public static final Op MULT = new Op("*", 2); public static final Op DIV = new Op("/", 2); public static final Op PLUS = new Op("+", 3); public static final Op MINUS = new Op("-", 3); public static final Op LT = new Op("<", 5); public static final Op LTOE = new Op("<=", 5); public static final Op GT = new Op(">", 5); public static final Op GTOE = new Op(">=", 5); public static final Op EQ = new Op("==", 6); public static final Op NE = new Op("!=", 6); public static final Op LAND = new Op("&&", 10); public static final Op LOR = new Op("||", 11); public static final Op CONDCHOICE = new Op(":", 12); public static final Op COND = new Op("?", 13); } private static final Double ONE = new Double(1); private static final Double ZERO = new Double(0); /** * A simple equation consists of two Identifiers (operands) * that are Doubles, Strings, or other SimpleEq, * and an operator *,/,+,-. * <P> * For a simple equation to be valid, it must define * both operands and an operator. However, if the * operator is '-', then the left hand operand may * be null, to indicate a unary minus. Additionally, * if only the left hand operator is defined, then it * is simply one operand. */ public static class SimpleEq { protected Object lhop; // left hand operand private Op op; // operator protected Object rhop; // right hand operand boolean neglh = false; boolean negrh = false; public SimpleEq() { this.lhop = null; this.op = null; this.rhop = null; } public SimpleEq(Object lhop, Op op, Object rhop) { this.lhop = lhop; this.op = op; this.rhop = rhop; } public boolean addIdentifierOk() { if (lhop == null) return true; else if (rhop == null && op != null) return true; else if (rhop instanceof SimpleEq) return ((SimpleEq)rhop).addIdentifierOk(); return false; } public void addIdentifier(Object id) throws ParseException { if (lhop == null) lhop = id; else if (rhop == null && op != null) rhop = id; else if (rhop instanceof SimpleEq) ((SimpleEq)rhop).addIdentifier(id); else throw new ParseException("Two operands with no operator"); } public void addOp(Op operator) throws ParseException { if (lhop == null && operator == Op.MINUS && !neglh) neglh = true; // unary minus on left hand operand else if (lhop == null) throw new ParseException("Operator "+operator+" with no left hand operand"); // lhop defined from here on else if (op == null && rhop == null) this.op = operator; else if (op != null && rhop == null && operator == Op.MINUS && !negrh) negrh = true; // unary minus on right hand operand else if (op != null && rhop != null) { if (rhop instanceof SimpleEq) { ((SimpleEq)rhop).addOp(operator); } else { // operators with lower value precedence bind tighter than higher value precedence if (operator.precedence < op.precedence) { // bind right rhop = new SimpleEq(rhop, operator, null); // retain proper negation associations ((SimpleEq)rhop).neglh = negrh; negrh = false; } else { // bind left lhop = new SimpleEq(lhop, op, rhop); this.op = operator; this.rhop = null; // retain proper negation associations ((SimpleEq)lhop).neglh = neglh; ((SimpleEq)lhop).negrh = negrh; this.neglh = false; this.negrh = false; } } } else throw new ParseException(("Two operators in a row")); } /** * Return either a Double, if the equation can be * resolved numerically, or a String representing * the equation after any numerical resolution can be done. * @return a Double or a String */ public Object eval() throws ParseException { if (lhop instanceof SimpleEq) lhop = ((SimpleEq)lhop).eval(); if (rhop instanceof SimpleEq) rhop = ((SimpleEq)rhop).eval(); if (op == Op.CONDCHOICE) { return this; } if (op == Op.COND && (rhop instanceof SimpleEq)) { SimpleEq condval = (SimpleEq)rhop; if ((lhop instanceof Double) && (condval.lhop instanceof Double) && (condval.rhop instanceof Double)) { double cond = ((Double)lhop).doubleValue(); if (neglh) cond = -1.0 * cond; double valt = ((Double)condval.lhop).doubleValue(); if (condval.neglh) valt = -1.0 * valt; double valf = ((Double)condval.rhop).doubleValue(); if (condval.negrh) valf = -1.0 * valf; if (cond == 0) return valf; return valt; } String neglhstr = condval.neglh ? "-" : ""; String negrhstr = condval.negrh ? "-" : ""; rhop = neglhstr + format(condval.lhop) + " : " + negrhstr + format(condval.rhop); } else if ((lhop instanceof Double) && (rhop instanceof Double)) { double lh = ((Double)lhop).doubleValue(); double rh = ((Double)rhop).doubleValue(); if (neglh) lh = -1.0 * lh; if (negrh) rh = -1.0 * rh; if (op == Op.MULT) return new Double(lh * rh); else if (op == Op.DIV) return new Double(lh / rh); else if (op == Op.PLUS) return new Double(lh + rh); else if (op == Op.MINUS) return new Double(lh - rh); else if (op == Op.LT) return lh < rh ? ONE : ZERO; else if (op == Op.LTOE) return lh <= rh ? ONE : ZERO; else if (op == Op.GT) return lh > rh ? ONE : ZERO; else if (op == Op.GTOE) return lh >= rh ? ONE : ZERO; else if (op == Op.EQ) return lh == rh ? ONE : ZERO; else if (op == Op.NE) return lh != rh ? ONE : ZERO; else if (op == Op.LAND) return (lh != 0 && rh != 0) ? ONE : ZERO; else if (op == Op.LOR) return (lh != 0 || rh != 0) ? ONE : ZERO; } else if (op == null && rhop == null) { if (neglh) { if (lhop instanceof Double) { return -1.0 * ((Double)lhop).doubleValue(); } return "-"+lhop.toString(); } return lhop; } // can't resolve numerically String neglhstr = neglh ? "-" : ""; String negrhstr = negrh ? "-" : ""; String lhstr = (lhop == null ? "?" : format(lhop)); String rhstr = (rhop == null ? "?" : format(rhop)); return neglhstr + lhstr + " " + op + " " + negrhstr + rhstr; } } private static String format(Object obj) { // must be format double postfix, otherwise get 0 for numbers less than 0.001 if (obj instanceof Double) return TextUtils.formatDoublePostFix(((Double)obj).doubleValue()); return obj.toString(); } // ================================ Main Test ================================ public static void main(String args[]) { testEval("1 + 2", 3); testEval("1 + 2 * 3", 7); testEval("1 * 2 + 3", 5); testEval("(1 + 2) * 3", 9); testEval("(1 + 2) * x", "3 * x"); testEval("300 / -1.5e2", -2); testEval("1.5e-2", 0.015); testEval("20 * 1.5e-2", 0.3); testEval("20 * 1.5m", 0.03); testEval("(1 + a) * 3 + b", "(1 + a) * 3 + b"); testEval("1 + 2 * 3 + - 4", 3); testEval("-1", -1); testEval("-1 + 2 * 3 + - 4", 1); testEval("-(1 + 2) * 3 + -4", -13); testEval("-(1 + 2) * 3 + -4 * -2 - -4 * -3", -13); testEval("-sin(3)", -Math.sin(3)); testEval("-sin(x)", "-sin(x)"); testEval("1-min(1,-2)", 3); testEval("1-min(1,x)", null); testEval("1-min((a+b)*c,x)", null); testEval("1-min((a+b)*c,(a+b))", null); testEval("-a + 2 * 3 * -b + - 4", null); testEval("1 ? -2 : 4", -2); testEval("0 ? -2 : 4", 4); testEval("8 == 1 ? -2 : 4", 4); testEval("8 > 1 ? -2 : 4", -2); testEval("1 - 7 <= 1 ? -2 : 4", -2); testEval("layer == 1 ? two + 1 : eight * 4 / 2", "layer == 1 ? two + 1 : eight * 4 / 2"); testEval("0 * 1 ? 3 / 2 : -4 + 10", 6); testEval("(3==0?0.00441:3<8?0.011:0.016)*1e-15", 1.1e-17); testEval("(layer==0?0.00441:layer<8?0.011:0.016)*1e-15", null); System.out.println("\nThese should flag as errors:\n---------------------------\n"); testEval("1 2 +", null); testEval("1 + * 2", null); testEval("1 + 2 * - -3", null); testEval("300 / -1.5ee2 + 5", null); testEval("1-min((a+b)*c,(a+b)", null); testEval("1/0", null); testEval("M1 - M3 : 10001", null); } private static void testEval(String eq, String expected) { EvalSpice sp = new EvalSpice(eq); String evald = sp.evaluate().toString(); if (expected == null) { System.out.println(eq+" = "+evald); } else { System.out.println(eq+" = "+evald+" -- ("+expected+")"); assert(expected.equals(evald)); } } private static void testEval(String eq, double expected) { EvalSpice sp = new EvalSpice(eq); Object evald = sp.evaluate(); System.out.println(eq+" = "+evald+" -- ("+expected+")"); assert(evald instanceof Double); double val = ((Double)evald).doubleValue(); assert(val == expected); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -