📄 evalspice.java
字号:
/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: EvalSpice.java * * Copyright (c) 2005 Sun Microsystems and Static Free Software * * Electric(tm) is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Electric(tm) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Electric(tm); see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, Mass 02111-1307, USA. */package com.sun.electric.database.variable;import com.sun.electric.database.text.TextUtils;import java.io.IOException;import java.io.StreamTokenizer;import java.io.StringReader;/** * Class to evaluate Spice expressions. * User: gainsley * Date: Aug 17, 2006 */public class EvalSpice { private String expr; private StreamTokenizer tokenizer; int openParens; public EvalSpice(String expr) { this.expr = expr; openParens = 0; } public Object evaluate() { if (expr == null) return null; StringReader reader = new StringReader(expr); tokenizer = new StreamTokenizer(reader); tokenizer.parseNumbers(); tokenizer.ordinaryChar('('); tokenizer.ordinaryChar(')'); tokenizer.ordinaryChar('*'); tokenizer.ordinaryChar('/'); tokenizer.ordinaryChar('+'); tokenizer.ordinaryChar('-'); tokenizer.ordinaryChar('<'); tokenizer.ordinaryChar('='); tokenizer.ordinaryChar('>'); tokenizer.ordinaryChar('!'); tokenizer.ordinaryChar('?'); tokenizer.ordinaryChar(':'); tokenizer.wordChars('_', '_'); try { return evalEq().eval(); } catch (IOException e) { System.out.println(e.getMessage()); } catch (ParseException e) { String parsed = ""; try { long left = reader.skip(Long.MAX_VALUE); parsed = expr.substring(0, expr.length()-(int)left); } catch (IOException e2) {} if (!parsed.equals("")) parsed = ": "+parsed+" <--"; System.out.println("Spice Parse Error: "+e.getMessage()+parsed +" "+tokenizer.toString()); System.out.println(" Original string: "+expr); } return expr; } /** * Evaluate an expression * @return the evaluated expression * @throws IOException * @throws ParseException */ private SimpleEq evalEq() throws IOException, ParseException { SimpleEq eq = new SimpleEq(); while (true) { int tt = tokenizer.nextToken(); if (tt == StreamTokenizer.TT_EOF || tt == StreamTokenizer.TT_EOL) { if (openParens > 0) throw new ParseException("Unmatched open parens"); return eq; } // delimiters come first else if (tt == ')') { // end eq openParens--; if (openParens < 0) throw new ParseException("Unmatched close parens"); Object value = eq.eval(); if (value instanceof String) { return new SimpleEq("("+value.toString()+")", null, null); } return new SimpleEq(value, null, null); } else if (tt == '(') { // begin new eq openParens++; if (!eq.addIdentifierOk()) throw new ParseException("Too many identifiers"); Object id = evalEq(); eq.addIdentifier(id); } else if (tt == ',') { // end eq return eq; } else if (tt == StreamTokenizer.TT_NUMBER) { tokenizer.pushBack(); eq.addIdentifier(parseNumber()); } else if (tt == StreamTokenizer.TT_WORD) { if (tokenizer.sval.equalsIgnoreCase("sin")) { expect('('); openParens++; Object arg = evalEq().eval(); if (arg instanceof Double) { arg = new Double(Math.sin(((Double)arg).doubleValue())); } else { arg = "sin"+format(arg); } eq.addIdentifier(arg); } else if (tokenizer.sval.equalsIgnoreCase("min")) { expect('('); openParens++; Object m1 = evalEq().eval(); Object m2 = evalEq().eval(); if ((m1 instanceof Double) && (m2 instanceof Double)) { double a = ((Double)m1).doubleValue(); double b = ((Double)m2).doubleValue(); m1 = new Double(Math.min(a,b)); } else { String m2str = format(m2); // remove extraneous ()'s if (m2str.startsWith("(") && m2str.endsWith(")")) m2str = m2str.substring(1, m2str.length()-1); m1 = "min("+format(m1)+","+m2str+")"; } eq.addIdentifier(m1); } else if (tokenizer.sval.equalsIgnoreCase("max")) { expect('('); openParens++; Object m1 = evalEq().eval(); Object m2 = evalEq().eval(); if ((m1 instanceof Double) && (m2 instanceof Double)) { double a = ((Double)m1).doubleValue(); double b = ((Double)m2).doubleValue(); m1 = new Double(Math.max(a,b)); } else { String m2str = format(m2); // remove extraneous ()'s if (m2str.startsWith("(") && m2str.endsWith(")")) m2str = m2str.substring(1, m2str.length()-1); m1 = "max("+format(m1)+","+m2str+")"; } eq.addIdentifier(m1); } else if (tokenizer.sval.equalsIgnoreCase("abs")) { expect('('); openParens++; Object arg = evalEq().eval(); if (arg instanceof Double) { arg = new Double(Math.abs(((Double)arg).doubleValue())); } else { arg = "abs"+format(arg); } eq.addIdentifier(arg); } else if (tokenizer.sval.equalsIgnoreCase("sqrt")) { expect('('); openParens++; Object arg = evalEq().eval(); if (arg instanceof Double) { arg = new Double(Math.sqrt(((Double)arg).doubleValue())); } else { arg = "sqrt"+format(arg); } eq.addIdentifier(arg); } else if (tokenizer.sval.equalsIgnoreCase("int")) { expect('('); openParens++; Object arg = evalEq().eval(); if (arg instanceof Double) { arg = new Double((int)(((Double)arg).doubleValue())); } else { arg = "int"+format(arg); } eq.addIdentifier(arg); } else { // identifier eq.addIdentifier(tokenizer.sval); } } else if (tt == '*') { eq.addOp(Op.MULT); } else if (tt == '/') { eq.addOp(Op.DIV); } else if (tt == '+') { eq.addOp(Op.PLUS); } else if (tt == '-') { eq.addOp(Op.MINUS); } else if (tt == '<') { tt = tokenizer.nextToken(); if (tt == '=') { eq.addOp(Op.LTOE); } else { tokenizer.pushBack(); eq.addOp(Op.LT); } } else if (tt == '>') { tt = tokenizer.nextToken(); if (tt == '=') { eq.addOp(Op.GTOE); } else { tokenizer.pushBack(); eq.addOp(Op.GT); } } else if (tt == '=') { expect('='); eq.addOp(Op.EQ); } else if (tt == '!') { expect('='); eq.addOp(Op.NE); } else if (tt == '?') { eq.addOp(Op.COND);/* Object arg1 = evalEq().eval(); if (tokenizer.ttype != ':') throw new ParseException("Expected ':' after conditional"); Object arg2 = evalEq().eval(); SimpleEq condval = new SimpleEq(arg1, Op.CONDCHOICE, arg2); eq.addIdentifier(condval);*/ } else if (tt == ':') { // end conditional true arg eq.addOp(Op.CONDCHOICE); } } } /** * Parse a number. A number may have the format: * <P> * number[g|meg|k|m|u|n|p|f] * <p> * number(e)[-]number * @return * @throws IOException * @throws ParseException */ private Object parseNumber() throws IOException, ParseException { int tt = tokenizer.nextToken(); if (tt == StreamTokenizer.TT_NUMBER) { double val = tokenizer.nval; // peek ahead to check if exponential, or multiplier tokenizer.ordinaryChar('e'); tokenizer.ordinaryChar('E'); tt = tokenizer.nextToken(); if (tt == 'e' || tt == 'E') { tt = tokenizer.nextToken(); boolean minus = false; if (tt == '-') { minus = true; tt = tokenizer.nextToken(); } if (tt == StreamTokenizer.TT_NUMBER) { double exp = tokenizer.nval; if (minus) exp = -1.0 * exp; val = val * Math.pow(10, exp); } else { throw new ParseException("Invalid token"); } } else if (tt == StreamTokenizer.TT_WORD) { if (tokenizer.sval.equalsIgnoreCase("g")) { val = val * 1e9; } else if (tokenizer.sval.equalsIgnoreCase("meg")) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -