📄 spicenetlistreader.java
字号:
/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: SpiceNetlistReader.java * * Copyright (c) 2006 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.tool.io.input.spicenetlist;import java.io.*;import java.util.*;/** * Parse a spice netlist. Ignores comments, and * coalesces split lines into single lines. * User: gainsley * Date: Aug 3, 2006 */public class SpiceNetlistReader { private File file; BufferedReader reader; private StringBuffer lines; private int lineno; private HashMap<String,String> options = new LinkedHashMap<String,String>(); private HashMap<String,String> globalParams = new LinkedHashMap<String,String>(); private List<SpiceInstance> topLevelInstances = new ArrayList<SpiceInstance>(); private HashMap<String,SpiceSubckt> subckts = new LinkedHashMap<String,SpiceSubckt>(); private List<String> globalNets = new ArrayList<String>(); private SpiceSubckt currentSubckt; public SpiceNetlistReader() { reader = null; lines = null; } public HashMap<String,String> getOptions() { return options; } public HashMap<String,String> getGlobalParams() { return globalParams; } public List<SpiceInstance> getTopLevelInstances() { return topLevelInstances; } public Collection<SpiceSubckt> getSubckts() { return subckts.values(); } public List<String> getGlobalNets() { return globalNets; } public SpiceSubckt getSubckt(String name) { return subckts.get(name.toLowerCase()); }// private static final boolean DEBUG = true; // ============================== Parsing ==================================// enum TType { PAR, PARVAL, WORD } public void readFile(String fileName, boolean verbose) throws FileNotFoundException { file = new File(fileName); reader = new BufferedReader(new FileReader(fileName)); lines = new StringBuffer(); currentSubckt = null; String line; lineno = 0; try { while ((line = readLine()) != null) { line = line.trim(); String [] tokens = getTokens(line); if (tokens.length == 0) continue; String keyword = tokens[0].toLowerCase(); if (keyword.equals(".include")) { if (tokens.length < 2) { prErr("No file specified for .include"); continue; } String ifile = tokens[1]; if (!ifile.startsWith("/") && !ifile.startsWith("\\")) { // relative path, add to current path File newFile = new File(file.getParent(), ifile); ifile = newFile.getPath(); } File saveFile = file; BufferedReader saveReader = reader; StringBuffer saveLines = lines; int saveLine = lineno; try { if (verbose) System.out.println("Reading include file "+ifile); readFile(ifile, verbose); } catch (FileNotFoundException e) { file = saveFile; lineno = saveLine; prErr("Include file does not exist: "+ifile); } file = saveFile; reader = saveReader; lines = saveLines; lineno = saveLine; } else if (keyword.startsWith(".opt")) { parseOptions(options, 1, tokens); } else if (keyword.equals(".param")) { parseParams(globalParams, 1, tokens); } else if (keyword.equals(".subckt")) { currentSubckt = parseSubckt(tokens); if (currentSubckt != null && subckts.containsKey(currentSubckt.getName().toLowerCase())) { prErr("Subckt "+currentSubckt.getName()+ " already defined"); continue; } subckts.put(currentSubckt.getName().toLowerCase(), currentSubckt); } else if (keyword.equals(".global")) { for (int i=1; i<tokens.length; i++) { if (!globalNets.contains(tokens[i])) globalNets.add(tokens[i]); } } else if (keyword.startsWith(".ends")) { currentSubckt = null; } else if (keyword.startsWith(".end")) { // end of file } else if (keyword.startsWith("x")) { SpiceInstance inst = parseSubcktInstance(tokens); addInstance(inst); } else if (keyword.startsWith("r")) { SpiceInstance inst = parseResistor(tokens); addInstance(inst); } else if (keyword.startsWith("c")) { SpiceInstance inst = parseCapacitor(tokens); addInstance(inst); } else if (keyword.startsWith("m")) { SpiceInstance inst = parseMosfet(tokens); addInstance(inst); } else if (keyword.equals(".protect") || keyword.equals(".unprotect")) { // ignore } else { prWarn("Parser does not recognize: "+line); } } reader.close(); } catch (IOException e) { System.out.println("Error reading file "+file.getPath()+": "+e.getMessage()); } } private void prErr(String msg) { System.out.println("Error ("+getLocation()+"): "+msg); } private void prWarn(String msg) { System.out.println("Warning ("+getLocation()+"): "+msg); } private String getLocation() { return file.getName()+":"+lineno; } /** * Get the tokens in a line. Tokens are separated by whitespace, * unless that whitespace is surrounded by single quotes, or parentheses. * When quotes are used, those quotes are removed from the string literal. * The construct <code>name=value</code> is returned as three tokens, * the second being the char '='. * @param line the line to parse * @return an array of tokens */ private String [] getTokens(String line) { List<String> tokens = new ArrayList<String>(); int start = 0; boolean inquotes = false; int inparens = 0; int i; for (i=0; i<line.length(); i++) { char c = line.charAt(i); if (inquotes) { if (c == '\'') { if (inparens > 0) continue; // end string literal tokens.add(line.substring(start, i)); start = i+1; inquotes = false; } } else if (c == '\'') { if (inparens > 0) continue; inquotes = true; if (start != i) { prErr("Improper use of open quote '"); break; } start = i+1; } // else !inquotes: else if (Character.isWhitespace(c) && inparens == 0) { // end of token (unless just more whitespace) if (start < i) tokens.add(line.substring(start, i)); start = i+1; } else if (c == '(') { inparens++; } else if (c == ')') { if (inparens == 0) { prErr("Too many ')'s"); break; } inparens--; } else if (c == '=') { if (start < i) tokens.add(line.substring(start, i)); tokens.add("="); start = i+1; } else if (c == '*') { break; // rest of line is comment } } if (start < i) { tokens.add(line.substring(start, i)); } if (inparens != 0) prErr("Unmatched parentheses"); // join {par, =, val} to {par=val} List<String> joined = new ArrayList<String>(); for (int j=0; j<tokens.size(); j++) { if (tokens.get(j).equals("=")) { if (j == 0) { prErr("No right hand side to assignment"); } else if (j == tokens.size()-1) { prErr("No left hand side to assignment"); } else { int last = joined.size() - 1; joined.set(last, joined.get(last)+"="+tokens.get(++j)); } } else { joined.add(tokens.get(j)); } } String ret [] = new String[joined.size()]; for (int k=0; k<joined.size(); k++) ret[k] = joined.get(k); return ret; } private void parseOptions(HashMap<String,String> map, int start, String [] tokens) { for (int i=start; i<tokens.length; i++) { int e = tokens[i].indexOf('='); String pname = tokens[i]; String value = "true"; if (e > 0) { pname = tokens[i].substring(0, e); value = tokens[i].substring(e+1); } if (pname == null || value == null) { prErr("Bad option value: "+tokens[i]); continue; } map.put(pname.toLowerCase(), value); } } private void parseParams(HashMap<String,String> map, int start, String [] tokens) { for (int i=start; i<tokens.length; i++) { parseParam(map, tokens[i], null); } } private void parseParam(HashMap<String,String> map, String parval, String defaultParName) { int e = parval.indexOf('=');
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -