📄 codeexpression.java
字号:
/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: CodeExpression.java * Written by: Dmitry Nadezhin, Sun Microsystems. * * Copyright (c) 2008 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.EObjectInputStream;import com.sun.electric.database.EObjectOutputStream;import com.sun.electric.database.id.IdReader;import com.sun.electric.database.id.IdWriter;import com.sun.electric.database.text.ArrayIterator;import com.sun.electric.database.text.TextUtils;import java.io.IOException;import java.io.Serializable;import java.io.StreamTokenizer;import java.io.StringReader;import java.util.Collections;import java.util.HashMap;import java.util.Iterator;import java.util.Set;import java.util.TreeMap;import java.util.TreeSet;import java.util.regex.Matcher;import java.util.regex.Pattern;/** * Class encapsulate expression in Java-like or Spice-like syntax */public class CodeExpression implements Serializable { // Variable flags in C Electric /** variable is interpreted code (with VCODE2) */ private static final int VCODE1 = 040; /** variable is interpreted code (with VCODE1) */ private static final int VCODE2 = 04000000000; /** variable is LISP */ private static final int VSPICE = VCODE1; /** variable is TCL */ private static final int VTCL = VCODE2; /** variable is Java */ private static final int VJAVA = (VCODE1|VCODE2); private static final HashMap <String,CodeExpression> javaExpressions = new HashMap<String,CodeExpression>(); private static final HashMap <String,CodeExpression> spiceExpressions = new HashMap<String,CodeExpression>(); private static final HashMap <String,CodeExpression> tclExpressions = new HashMap<String,CodeExpression>(); private static long numValueOfs; /** For replacing @variable */ private static final Pattern pPat = Pattern.compile("P\\(\"(\\w+)\"\\)"); private final Code code; private final String expr; private final Set<Variable.Key> depends; private final Expr exprTree; private final boolean dependsOnEverything; private final EvalSpice.ParseException parseException; private final String spiceText; private final String spiceTextPar; /** * The type of Code that determines how this Variable's * value should be evaluated. If NONE, no evaluation is done. */ public static enum Code { /** Indicator that code is in Java. */ JAVA("Java", VJAVA), /** Indicator that code is in Lisp. */ SPICE("Spice", VSPICE), /** Indicator that code is in TCL. */ TCL("TCL (not avail.)", VTCL), /** Indicator that this is not code. */ NONE("Not Code", 0); private final String name; private final int cFlags; private static final Code[] allCodes = Code.class.getEnumConstants(); private Code(String name, int cFlags) { this.name = name; this.cFlags = cFlags; } /** * Method to return the bits value of this code type. * This is used in I/O. * @return the bits value of this code type. */ public int getCFlags() { return cFlags; } /** * Method to return a printable version of this Code. * @return a printable version of this Code. */ public String toString() { return name; } /** * Method to get an iterator over all Code types. */ public static Iterator<Code> getCodes() { return ArrayIterator.iterator(allCodes); } /** * Method to convert a bits value to a Code object. * @param cBits the bits value (from I/O). * @return the Code associated with those bits. */ public static Code getByCBits(int cBits) { switch (cBits & (VCODE1|VCODE2)) { case VJAVA: return JAVA; case VSPICE: return SPICE; case VTCL: return TCL; default: return NONE; } } /** * Method to get a Code constant by its ordinal number. * @param ordinal the ordinal number of this Code constant ( as returned by ordinal() * @return the Code associated with this ordinal number. */ public static Code getByOrdinal(int ordinal) { return allCodes[ordinal]; } } private CodeExpression(String expr, Code code) { this.code = code; this.expr = expr; TreeSet<Variable.Key> varKeys = new TreeSet<Variable.Key>(); String replacedExpr = EvalJavaBsh.replace(expr); Matcher pMat = pPat.matcher(replacedExpr); while (pMat.find()) { String varName = pMat.group(1); varKeys.add(Variable.newKey(varName)); } depends = Collections.unmodifiableSet(varKeys); String patchedExpr = expr.replace("((Number)@X).doubleValue()", "@X"); Expr exprTree = null; EvalSpice.ParseException parseException = null; try { switch (code) { case JAVA: exprTree = parse(patchedExpr, true); break; case SPICE: exprTree = parse(patchedExpr, false); break; default: throw new EvalSpice.ParseException("Unsupported code " + code); } } catch (EvalSpice.ParseException e) { parseException = e; } this.exprTree = exprTree; this.parseException = parseException; if (parseException != null) { dependsOnEverything = true; spiceTextPar = spiceText = parseException.getMessage(); } else { dependsOnEverything = exprTree.dependsOnEverything(); StringBuilder sb = new StringBuilder(); exprTree.appendText(sb); spiceText = new String(sb); sb.setLength(0); exprTree.appendText(sb, Expr.MIN_PRECEDENCE); spiceTextPar = new String(sb); } } private Object writeReplace() { return new CodeExpressionKey(this); } private static class CodeExpressionKey extends EObjectInputStream.Key<CodeExpression> { public CodeExpressionKey() {} private CodeExpressionKey(CodeExpression ce) { super(ce); } @Override public void writeExternal(EObjectOutputStream out, CodeExpression ce) throws IOException { out.writeUTF(ce.getExpr()); out.writeByte(ce.getCode().ordinal()); } @Override public CodeExpression readExternal(EObjectInputStream in) throws IOException, ClassNotFoundException { String expr = in.readUTF(); Code code = Code.getByOrdinal(in.readByte()); return valueOf(expr, code); } } public static synchronized CodeExpression valueOf(String expression, Code code) { numValueOfs++; HashMap<String,CodeExpression> allExpressions; switch (code) { case JAVA: allExpressions = javaExpressions; break; case SPICE: allExpressions = spiceExpressions; break; case TCL: allExpressions = tclExpressions; break; default: throw new IllegalArgumentException("code"); } CodeExpression ce = allExpressions.get(expression); if (ce == null) { ce = new CodeExpression(expression, code); allExpressions.put(expression, ce); } return ce; } public Code getCode() { return code; } public boolean isJava() { return code == Code.JAVA; } public String getExpr() { return expr; } public Set<Variable.Key> dependsOn() { return depends; } public EvalSpice.ParseException getParseException() { return parseException; } public String getSpiceText() { return spiceText; } public String getHSpiceText(boolean inPar) { return dependsOnEverything ? null : inPar ? spiceTextPar : spiceText; } public String getVerilogText() { return spiceText; } public Object eval() { if (parseException != null) return parseException.getMessage(); return exprTree.eval(new EvalContext()); } @Override public int hashCode() { return expr.hashCode(); } @Override public boolean equals(Object o) { if (o instanceof CodeExpression) { CodeExpression that = (CodeExpression)o; return this.code == that.code && this.expr.equals(that.expr); } return false; } @Override public String toString() { return expr; } /** * Write this CodeExpression to IdWriter. * @param writer where to write. */ public void write(IdWriter writer) throws IOException { writer.writeString(expr); writer.writeByte((byte)code.ordinal()); } /** * Read CodeExpression from SnapshotReader. * @param reader from to write. */ public static CodeExpression read(IdReader reader) throws IOException { String expr = reader.readString(); Code code = Code.getByOrdinal(reader.readByte()); return valueOf(expr, code); } void check() { assert expr != null; assert code != null && code != Code.NONE; } /** * Print statistics about CodeExpressions. * @param verbose print all CodeExpressions */ public static void printStatistics(boolean verbose) { System.out.println((javaExpressions.size() + spiceExpressions.size() + tclExpressions.size()) + " CodeExpressions after " + numValueOfs + " valueOf calls"); if (!verbose) return; System.out.println(javaExpressions.size() + " java strings"); for (CodeExpression ce: new TreeMap<String,CodeExpression>(javaExpressions).values()) printCE(ce); System.out.println(spiceExpressions.size() + " spice strings"); for (CodeExpression ce: new TreeMap<String,CodeExpression>(spiceExpressions).values()) printCE(ce); System.out.println(tclExpressions.size() + " tcl strings"); for (CodeExpression ce: new TreeMap<String,CodeExpression>(tclExpressions).values()) printCE(ce); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -