package com.lushprojects.circuitjs1.client; import java.util.Vector; class ExprState { int n; double values[]; double t; ExprState(int xx) { n = xx; values = new double[9]; values[4] = Math.E; } } class Expr { Expr(Expr e1, Expr e2, int v) { children = new Vector<Expr>(); children.add(e1); if (e2 != null) children.add(e2); type = v; } Expr(int v, double vv) { type = v; value = vv; } Expr(int v) { type = v; } double eval(ExprState es) { Expr left = null; Expr right = null; if (children != null && children.size() > 0) { left = children.firstElement(); if (children.size() == 2) right = children.lastElement(); } switch (type) { case E_ADD: return left.eval(es)+right.eval(es); case E_SUB: return left.eval(es)-right.eval(es); case E_MUL: return left.eval(es)*right.eval(es); case E_DIV: return left.eval(es)/right.eval(es); case E_POW: return java.lang.Math.pow(left.eval(es), right.eval(es)); case E_UMINUS: return -left.eval(es); case E_VAL: return value; case E_T: return es.t; case E_SIN: return java.lang.Math.sin(left.eval(es)); case E_COS: return java.lang.Math.cos(left.eval(es)); case E_ABS: return java.lang.Math.abs(left.eval(es)); case E_EXP: return java.lang.Math.exp(left.eval(es)); case E_LOG: return java.lang.Math.log(left.eval(es)); case E_SQRT: return java.lang.Math.sqrt(left.eval(es)); case E_TAN: return java.lang.Math.tan(left.eval(es)); case E_MIN: { int i; double x = left.eval(es); for (i = 1; i < children.size(); i++) x = Math.min(x, children.get(i).eval(es)); return x; } case E_MAX: { int i; double x = left.eval(es); for (i = 1; i < children.size(); i++) x = Math.max(x, children.get(i).eval(es)); return x; } case E_CLAMP: return Math.min(Math.max(left.eval(es), children.get(1).eval(es)), children.get(2).eval(es)); case E_STEP: { double x = left.eval(es); if (right == null) return (x < 0) ? 0 : 1; return (x > right.eval(es)) ? 0 : (x < 0) ? 0 : 1; } case E_SELECT: { double x = left.eval(es); return children.get(x > 0 ? 2 : 1).eval(es); } case E_TRIANGLE: { double x = posmod(left.eval(es), Math.PI*2)/Math.PI; return (x < 1) ? -1+x*2 : 3-x*2; } case E_SAWTOOTH: { double x = posmod(left.eval(es), Math.PI*2)/Math.PI; return x-1; } case E_MOD: return left.eval(es) % right.eval(es); case E_PWL: return pwl(es, children); default: if (type >= E_A) return es.values[type-E_A]; CirSim.console("unknown\n"); } return 0; } double pwl(ExprState es, Vector<Expr> args) { double x = args.get(0).eval(es); double x0 = args.get(1).eval(es); double y0 = args.get(2).eval(es); if (x < x0) return y0; double x1 = args.get(3).eval(es); double y1 = args.get(4).eval(es); int i = 5; while (true) { if (x < x1) return y0+(x-x0)*(y1-y0)/(x1-x0); if (i+1 >= args.size()) break; x0 = x1; y0 = y1; x1 = args.get(i ).eval(es); y1 = args.get(i+1).eval(es); i += 2; } return y1; } double posmod(double x, double y) { x %= y; return (x >= 0) ? x : x+y; } Vector<Expr> children; double value; int type; static final int E_ADD = 1; static final int E_SUB = 2; static final int E_T = 3; static final int E_VAL = 6; static final int E_MUL = 7; static final int E_DIV = 8; static final int E_POW = 9; static final int E_UMINUS = 10; static final int E_SIN = 11; static final int E_COS = 12; static final int E_ABS = 13; static final int E_EXP = 14; static final int E_LOG = 15; static final int E_SQRT = 16; static final int E_TAN = 17; static final int E_R = 18; static final int E_MAX = 19; static final int E_MIN = 20; static final int E_CLAMP = 21; static final int E_PWL = 22; static final int E_TRIANGLE = 23; static final int E_SAWTOOTH = 24; static final int E_MOD = 25; static final int E_STEP = 26; static final int E_SELECT = 27; static final int E_A = 28; // should be at end }; class ExprParser { String text; String token; int pos; int tlen; boolean err; void getToken() { while (pos < tlen && text.charAt(pos) == ' ') pos++; if (pos == tlen) { token = ""; return; } int i = pos; int c = text.charAt(i); if ((c >= '0' && c <= '9') || c == '.') { for (i = pos; i != tlen; i++) { if (!((text.charAt(i) >= '0' && text.charAt(i) <= '9') || text.charAt(i) == '.')) break; } } else if (c >= 'a' && c <= 'z') { for (i = pos; i != tlen; i++) { if (!(text.charAt(i) >= 'a' && text.charAt(i) <= 'z')) break; } } else { i++; } token = text.substring(pos, i); pos = i; } boolean skip(String s) { if (token.compareTo(s) != 0) return false; getToken(); return true; } void skipOrError(String s) { if (!skip(s)) err = true; } Expr parseExpression() { if (token.length() == 0) return new Expr(Expr.E_VAL, 0.); Expr e = parse(); if (token.length() > 0) err = true; return e; } Expr parse() { Expr e = parseMult(); while (true) { if (skip("+")) e = new Expr(e, parseMult(), Expr.E_ADD); else if (skip("-")) e = new Expr(e, parseMult(), Expr.E_SUB); else break; } return e; } Expr parseMult() { Expr e = parseUminus(); while (true) { if (skip("*")) e = new Expr(e, parseUminus(), Expr.E_MUL); else if (skip("/")) e = new Expr(e, parseUminus(), Expr.E_DIV); else break; } return e; } Expr parseUminus() { skip("+"); if (skip("-")) return new Expr(parsePow(), null, Expr.E_UMINUS); return parsePow(); } Expr parsePow() { Expr e = parseTerm(); while (true) { if (skip("^")) e = new Expr(e, parseTerm(), Expr.E_POW); else break; } return e; } Expr parseFunc(int t) { skipOrError("("); Expr e = parse(); skipOrError(")"); return new Expr(e, null, t); } Expr parseFuncMulti(int t, int minArgs, int maxArgs) { int args = 1; skipOrError("("); Expr e1 = parse(); Expr e = new Expr(e1, null, t); while (skip(",")) { Expr enext = parse(); e.children.add(enext); args++; } skipOrError(")"); if (args < minArgs || args > maxArgs) err = true; return e; } Expr parseTerm() { if (skip("(")) { Expr e = parse(); skipOrError(")"); return e; } if (skip("t")) return new Expr(Expr.E_T); if (token.length() == 1) { char c = token.charAt(0); if (c >= 'a' && c <= 'i') { getToken(); return new Expr(Expr.E_A + (c-'a')); } } if (skip("pi")) return new Expr(Expr.E_VAL, 3.14159265358979323846); // if (skip("e")) // return new Expr(Expr.E_VAL, 2.7182818284590452354); if (skip("sin")) return parseFunc(Expr.E_SIN); if (skip("cos")) return parseFunc(Expr.E_COS); if (skip("abs")) return parseFunc(Expr.E_ABS); if (skip("exp")) return parseFunc(Expr.E_EXP); if (skip("log")) return parseFunc(Expr.E_LOG); if (skip("sqrt")) return parseFunc(Expr.E_SQRT); if (skip("tan")) return parseFunc(Expr.E_TAN); if (skip("tri")) return parseFunc(Expr.E_TRIANGLE); if (skip("saw")) return parseFunc(Expr.E_SAWTOOTH); if (skip("min")) return parseFuncMulti(Expr.E_MIN, 2, 1000); if (skip("max")) return parseFuncMulti(Expr.E_MAX, 2, 1000); if (skip("pwl")) return parseFuncMulti(Expr.E_PWL, 2, 1000); if (skip("mod")) return parseFuncMulti(Expr.E_MOD, 2, 2); if (skip("step")) return parseFuncMulti(Expr.E_STEP, 1, 2); if (skip("select")) return parseFuncMulti(Expr.E_SELECT, 3, 3); if (skip("clamp")) return parseFuncMulti(Expr.E_CLAMP, 3, 3); try { Expr e = new Expr(Expr.E_VAL, Double.valueOf(token).doubleValue()); getToken(); return e; } catch (Exception e) { err = true; CirSim.console("unrecognized token: " + token + "\n"); return new Expr(Expr.E_VAL, 0); } } ExprParser(String s) { text = s.toLowerCase(); tlen = text.length(); pos = 0; err = false; getToken(); } boolean gotError() { return err; } };