/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: CIF.java
* Input/output tool: CIF input
* Original C CIF Parser (front end) by Robert W. Hon, Schlumberger Palo Alto Research
* and its interface to C Electric (back end) by Robert Winstanley, University of Calgary.
* Translated into Java by Steven M. Rubin, Sun Microsystems.
*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* 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;
import com.sun.electric.database.geometry.EPoint;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.Export;
import com.sun.electric.database.hierarchy.Library;
import com.sun.electric.database.id.CellId;
import com.sun.electric.database.prototype.NodeProto;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.technology.Layer;
import com.sun.electric.technology.Technology;
import com.sun.electric.tool.Job;
import com.sun.electric.tool.io.IOTool;
import com.sun.electric.util.TextUtils;
import com.sun.electric.util.math.GenMath;
import com.sun.electric.util.math.Orientation;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* This class reads files in CIF files.
*/
public class CIF extends Input<Object>
{
private static final boolean MAKE_EXPORTS = false;
/** max depth of min/max stack */ private static final int MAXMMSTACK = 50;
/** max value that can add extra digit */private static final int BIGSIGNED = ((0X7FFFFFFF-9)/10);
// specific syntax errors
private static final int NOERROR = 100;
private static final int NUMTOOBIG = 101;
private static final int NOUNSIGNED = 102;
private static final int NOSIGNED = 103;
private static final int NOSEMI = 104;
private static final int NOPATH = 105;
private static final int BADTRANS = 106;
private static final int BADUSER = 107;
private static final int BADCOMMAND = 108;
private static final int INTERNAL = 109;
private static final int BADDEF = 110;
private static final int NOLAYER = 111;
private static final int BADCOMMENT = 112;
private static final int BADAXIS = 113;
private static final int NESTDEF = 114;
private static final int NESTDD = 115;
private static final int NODEFSTART = 116;
private static final int NESTEND = 117;
private static final int NOSPACE = 118;
private static final int NONAME = 119;
// enumerated types for CIF 2.0 parser
// private static final int SEMANTICERROR = 0;
private static final int SYNTAXERROR = 1;
private static final int WIRECOM = 2;
private static final int BOXCOM = 3;
private static final int POLYCOM = 4;
private static final int FLASHCOM = 5;
private static final int DEFSTART = 6;
private static final int DEFEND = 7;
private static final int DELETEDEF = 8;
private static final int LAYER = 9;
private static final int CALLCOM = 10;
private static final int COMMENT = 11;
private static final int NULLCOMMAND = 12;
private static final int USERS = 13;
private static final int END = 14;
private static final int ENDFILE = 15;
private static final int SYMNAME = 16;
private static final int INSTNAME = 17;
private static final int GEONAME = 18;
private static final int LABELCOM = 19;
// types for FrontTransformLists
static class FrontTransformType {}
private FrontTransformType MIRROR = new FrontTransformType();
private FrontTransformType TRANSLATE = new FrontTransformType();
private FrontTransformType ROTATE = new FrontTransformType();
// error codes for reporting errors
private static final int FATALINTERNAL = 0;
private static final int FATALSYNTAX = 1;
private static final int FATALSEMANTIC = 2;
private static final int FATALOUTPUT = 3;
private static final int ADVISORY = 4;
// private static final int OTHER = 5; /* OTHER must be last */
private static final int TIDENT = 0;
private static final int TROTATE = 1;
private static final int TTRANSLATE = 2;
private static final int TMIRROR = 4;
// values for BackCIFList->identity
private static final int CSTART = 0;
private static final int CEND = 1;
// private static final int CWIRE = 2;
// private static final int CFLASH = 3;
private static final int CBOX = 4;
private static final int CPOLY = 5;
// private static final int CCOMMAND = 6;
private static final int CGNAME = 7;
private static final int CLABEL = 8;
private static final int CCALL = 9;
static class BackCIFCell
{
/** bounding box of cell */ int l, r, t, b;
/** the address of the CIF cell */ Cell addr;
};
static class BackCIFList
{
/** specifies the nature of the entry */ int identity;
/** the line number in the original CIF */ int lineNumber;
/** will point to member's structure */ Object member;
};
static class BackCIFStart
{
/** cell index */ int cIndex;
/** cell name */ String name;
/** bounding box of cell */ int l, r, t, b;
};
static class BackCIFBox
{
/** the corresponding layer number */ Layer lay;
/** dimensions of box */ int length, width;
/** center point of box */ int cenX, cenY;
/** box direction */ int xRot, yRot;
};
static class BackCIFPoly
{
/** the corresponding layer number */ Layer lay;
/** list of points */ int [] x, y;
/** number of points in list */ int lim;
};
static class BackCIFGeomName
{
/** the corresponding layer number */ Layer lay;
/** the name */ String name;
/** the central point */ int cx, cy;
};
static class BackCIFLabel
{
/** location of label */ int x, y;
/** the label */ String label;
};
static class BackCIFCall
{
/** index of cell called */ int cIndex;
/** name of cell called */ String name;
/** list of transformations */ BackCIFTransform list;
};
// values for the transformation type
/** mirror in x */ private static final int MIRX = 1;
/** mirror in y */ private static final int MIRY = 2;
/** translation */ private static final int TRANS = 3;
/** rotation */ private static final int ROT = 4;
static class BackCIFTransform
{
/** type of transformation */ int type;
/** not required for the mirror types */ int x, y;
/** next element in list */ BackCIFTransform next;
};
static class FrontTransformEntry
{
FrontTransformType kind;
boolean xCoord;
int xt, yt;
int xRot, yRot;
};
/** data types for transformation package */
static class FrontMatrix
{
double a11, a12, a21, a22, a31, a32, a33;
FrontMatrix prev, next;
int type;
boolean multiplied;
};
/** bounding box */
static class FrontBBox
{
int l, r, b, t;
};
static class FrontSymbol
{
/** symbol number for this entry */ int symNumber;
boolean expanded;
boolean defined;
boolean dumped;
/** bb as if this symbol were called by itself */ FrontBBox bounds;
/** flag for rebuilding bounding box */ boolean boundsValid;
/** name of this symbol */ String name;
/** number of calls made by this symbol */ int numCalls;
/** pointer to linked list of objects */ FrontObjBase guts;
FrontSymbol(int num)
{
bounds = new FrontBBox();
symNumber = num;
expanded = false;
defined = false;
dumped = false;
numCalls = 0;
boundsValid = false;
name = null;
guts = null;
}
};
static class FrontLinkedPoint
{
Point pValue;
FrontLinkedPoint pNext;
};
static class FrontPath
{
FrontLinkedPoint pFirst, pLast;
int pLength;
FrontPath()
{
pFirst = null;
pLast = null;
pLength = 0;
}
};
static class FrontLinkedTransform
{
FrontTransformEntry tValue;
FrontLinkedTransform tNext;
};
static class FrontTransformList
{
FrontLinkedTransform tFirst, tLast;
int tLength;
FrontTransformList()
{
tFirst = null;
tLast = null;
tLength = 0;
}
};
/** items in item tree */
static class FrontItem
{
/** pointer into symbol structure */ FrontObjBase what;
};
/** hack structure for referencing first fields of any object */
static class FrontObjBase
{
/** bounding box */ FrontBBox bb;
/** for ll */ FrontObjBase next;
/** layer for this object */ Layer layer;
FrontObjBase()
{
bb = new FrontBBox();
}
};
/** symbol call object */
static class FrontCall extends FrontObjBase
{
/** rest is non-critical */ int symNumber;
int lineNumber;
FrontSymbol unID;
FrontMatrix matrix;
/** transformation list for this call */ FrontTransformList transList;
};
static class FrontGeomName extends FrontObjBase
{
String name;
};
static class FrontLabel extends FrontObjBase
{
String name;
Point pos;
};
static class FrontBox extends FrontObjBase
{
int length, width;
Point center;
int xRot, yRot;
};
static class FrontManBox extends FrontObjBase
{
};
static class FrontFlash extends FrontObjBase
{
Point center;
int diameter;
};
static class FrontPoly extends FrontObjBase
{
/** array of points in path */ Point [] points;
};
static class FrontWire extends FrontObjBase
{
/** width of wire */ int width;
/** array of points in wire */ Point [] points;
};
/** current transformation */ private BackCIFTransform currentCTrans;
/** list of front-end objects */ private List<BackCIFList> currentFrontList = null;
/** current object in list */ private BackCIFList currentFrontElement;
/** item list */ private List<FrontItem> currentItemList;
/** A/B from DS */ private double cellScaleFactor;
/** current symbol being defined */ private FrontSymbol currentFrontSymbol;
/** place to save layer during def */ private Layer backupLayer;
/** symbol has been named */ private boolean symbolNamed;
/** flag for error encountered */ private boolean errorFound;
/** what it was */ private int errorType;
/** definition in progress flag */ private boolean isInCellDefinition;
/** end command flag */ private boolean endIsSeen;
/** number of chars in buffer */ private int charactersRead;
/** flag to reset buffer */ private boolean resetInputBuffer;
/** number of "fatal" errors */ private int numFatalErrors;
/** null layer errors encountered */ private boolean numNullLayerErrors;
/** ignore statements until DF */ private boolean ignoreStatements;
/** 91 pending */ private boolean namePending;
/** end command flag */ private boolean endCommandFound;
/** current layer */ private Layer currentLayer;
/** symbol table */ private Map<Integer,FrontSymbol> symbolTable;
/** the top of stack */ private FrontMatrix matrixStackTop;
/** lookahead character */ private int nextInputCharacter;
/** # statements since 91 com */ private boolean statementsSince91;
/** min/max stack pointer */ private int minMaxStackPtr;
/** min/max stack: left edge */ private int [] minMaxStackLeft;
/** min/max stack: right edge */ private int [] minMaxStackRight;
/** min/max stack: bottom edge */ private int [] minMaxStackBottom;
/** min/max stack: top edge */ private int [] minMaxStackTop;
/** map from cell numbers to cells */ private Map<Integer,BackCIFCell> cifCellMap;
/** the current cell */ private BackCIFCell currentBackCell;
/** current technology for layers */ private Technology curTech;
/** map from layer names to layers */ private Map<String,Layer> cifLayerNames;
/** set of unknown layers */ private Set<String> unknownLayerNames;
/** address of cell being defined */ private Cell cellBeingBuilt;
/** name of the current cell */ private String currentNodeProtoName;
/** the line being read */ private StringBuilder inputBuffer;
private CIFPreferences localPrefs;
public static class CIFPreferences extends InputPreferences
{
public boolean squareWires;
public CIFPreferences(boolean factory)
{
super(factory);
if (factory)
{
squareWires = IOTool.isFactoryCIFInSquaresWires();
} else
{
squareWires = IOTool.isCIFInSquaresWires();
}
}
@Override
public Library doInput(URL fileURL, Library lib, Technology tech, Map<Library,Cell> currentCells, Map<CellId,BitSet> nodesToExpand, Job job)
{
CIF in = new CIF(this);
if (in.openTextInput(fileURL)) return null;
lib = in.importALibrary(lib, tech, currentCells);
in.closeInput();
return lib;
}
}
/**
* Creates a new instance of CIF.
*/
CIF(CIFPreferences ap) { localPrefs = ap; }
/**
* Method to import a library from disk.
* @param lib the library to fill
* @param currentCells this map will be filled with currentCells in Libraries found in library file
* @return the created library (null on error).
*/
@Override
protected Library importALibrary(Library lib, Technology tech, Map<Library,Cell> currentCells)
{
setProgressNote("Reading CIF file");
// initialize all lists and the searching routines
cifCellMap = new HashMap<Integer,BackCIFCell>();
curTech = tech;
if (initFind()) return null;
// parse the CIF and create a listing
if (interpret()) return null;
// instantiate the CIF as nodes
setProgressNote("Storing CIF in database...");
if (listToNodes(lib)) return null;
// clean up
doneInterpreter();
return lib;
}
private boolean listToNodes(Library lib)
{
cellBeingBuilt = null;
for(BackCIFList x : currentFrontList)
{
currentFrontElement = x;
if (currentFrontElement.identity == CSTART)
{
cellBeingBuilt = nodesStart(lib);
if (cellBeingBuilt == null) return true;
continue;
}
if (currentFrontElement.identity == CEND)
{
// lib.setCurCell(cellBeingBuilt); // THIS TAKES WAY TOO LONG
cellBeingBuilt = null;
continue;
}
if (cellBeingBuilt == null)
{
// circuitry found at the top level: create a fake cell for it
cellBeingBuilt = lib.findNodeProto("TOP_LEVEL_UNNAMED{lay}");
if (cellBeingBuilt == null)
{
cellBeingBuilt = Cell.newInstance(lib, "TOP_LEVEL_UNNAMED{lay}");
if (cellBeingBuilt == null) break;
currentBackCell = makeBackCIFCell(9999);
}
currentBackCell.addr = cellBeingBuilt;
}
if (currentFrontElement.identity == CBOX)
{
if (nodesBox()) return true;
} else if (currentFrontElement.identity == CPOLY)
{
if (nodesPoly()) return true;
} else if (currentFrontElement.identity == CCALL)
{
if (nodesCall()) return true;
} else if (currentFrontElement.identity == CGNAME)
{
if (MAKE_EXPORTS && nodesGeoName()) return true;
}
}
return false;
}
private Cell nodesStart(Library lib)
{
BackCIFStart cs = (BackCIFStart)currentFrontElement.member;
BackCIFCell cifCell = makeBackCIFCell(cs.cIndex);
cifCell.l = cs.l; cifCell.r = cs.r;
cifCell.b = cs.b; cifCell.t = cs.t;
currentNodeProtoName = cs.name;
// remove illegal characters
StringBuffer properName = new StringBuffer();
for(int i=0; i<currentNodeProtoName.length(); i++)
{
char chr = currentNodeProtoName.charAt(i);
if (Character.isWhitespace(chr) || chr == ':' || chr == ';')
{
chr = 'X';
}
properName.append(chr);
}
currentNodeProtoName = properName.toString();
cifCell.addr = Cell.newInstance(lib, currentNodeProtoName + "{lay}");
if (cifCell.addr == null)
{
System.out.println("Cannot create the cell " + currentNodeProtoName);
return null;
}
return cifCell.addr;
}
private boolean nodesCall()
{
BackCIFCall cc = (BackCIFCall)currentFrontElement.member;
BackCIFCell cell = findBackCIFCell(cc.cIndex);
if (cell == null)
{
System.out.println("Referencing an undefined cell");
return true;
}
int rot = 0;
boolean trans = false;
int l = cell.l; int r = cell.r; int b = cell.b; int t = cell.t;
for(BackCIFTransform ctrans = cc.list; ctrans != null; ctrans = ctrans.next)
switch (ctrans.type)
{
case MIRX:
int temp = l; l = -r; r = -temp;
rot = (trans) ? ((rot+2700) % 3600) : ((rot+900) % 3600);
trans = !trans;
break;
case MIRY:
temp = t; t = -b; b = -temp;
rot = (trans) ? ((rot+900) % 3600) : ((rot+2700) % 3600);
trans = !trans;
break;
case TRANS:
l += ctrans.x; r += ctrans.x;
b += ctrans.y; t += ctrans.y;
break;
case ROT:
int deg = GenMath.figureAngle(new Point2D.Double(0, 0), new Point2D.Double(ctrans.x, ctrans.y));
if (deg != 0)
{
int hlen = Math.abs(((l-r)/2)); int hwid = Math.abs(((b-t)/2));
int cenX = (l+r)/2; int cenY = (b+t)/2;
Point pt = new Point(cenX, cenY);
rotateLayer(pt, deg);
cenX = pt.x; cenY = pt.y;
l = cenX - hlen; r = cenX + hlen;
b = cenY - hwid; t = cenY + hwid;
rot += ((trans) ? -deg : deg);
}
}
while (rot >= 3600) rot -= 3600;
while (rot < 0) rot += 3600;
double lX = convertFromCentimicrons(l);
double hX = convertFromCentimicrons(r);
double lY = convertFromCentimicrons(b);
double hY = convertFromCentimicrons(t);
double x = (lX + hX) / 2;
double y = (lY + hY) / 2;
double sX = hX - lX;
double sY = hY - lY;
Rectangle2D bounds = cell.addr.getBounds();
sX = bounds.getWidth();
sY = bounds.getHeight();
// transform is rotation and transpose: convert to rotation/MX/MY
Orientation or = Orientation.fromC(rot, trans);
// special code to account for rotation of cell centers
AffineTransform ctrTrans = or.rotateAbout(x, y);
Point2D spin = new Point2D.Double(x - bounds.getCenterX(), y - bounds.getCenterY());
ctrTrans.transform(spin, spin);
x = spin.getX(); y = spin.getY();
// create the node
NodeInst ni = NodeInst.makeInstance(cell.addr, new Point2D.Double(x, y), sX, sY, currentBackCell.addr, or, null);
if (ni == null)
{
System.out.println("Problems creating an instance of " + cell.addr + " in " + currentBackCell.addr);
return true;
}
return false;
}
private boolean nodesPoly()
{
BackCIFPoly cp = (BackCIFPoly)currentFrontElement.member;
if (cp.lim == 0) return false;
NodeProto np = findPrototype(cp.lay);
int lx = cp.x[0];
int hx = cp.x[0];
int ly = cp.y[0];
int hy = cp.y[0];
for(int i=1; i<cp.lim; i++)
{
if (cp.x[i] < lx) lx = cp.x[i];
if (cp.x[i] > hx) hx = cp.x[i];
if (cp.y[i] < ly) ly = cp.y[i];
if (cp.y[i] > hy) hy = cp.y[i];
}
// convert from centimicrons
double lowX = convertFromCentimicrons(lx);
double highX = convertFromCentimicrons(hx);
double lowY = convertFromCentimicrons(ly);
double highY = convertFromCentimicrons(hy);
double x = (lowX + highX) / 2;
double y = (lowY + highY) / 2;
double sX = highX - lowX;
double sY = highY - lowY;
NodeInst newni = NodeInst.makeInstance(np, new Point2D.Double(x, y), sX, sY, currentBackCell.addr);
if (newni == null)
{
System.out.println("Problems creating a polygon on layer " + cp.lay + " in " + currentBackCell.addr);
return true;
}
// store the trace information
EPoint [] points = new EPoint[cp.lim];
for(int i=0; i<cp.lim; i++)
{
points[i] = new EPoint(convertFromCentimicrons(cp.x[i]), convertFromCentimicrons(cp.y[i]));
}
// store the trace information
newni.setTrace(points);
return false;
}
private boolean nodesGeoName()
{
BackCIFGeomName gn = (BackCIFGeomName)currentFrontElement.member;
Layer lay = gn.lay;
NodeProto np = findPrototype(lay);
String name = gn.name;
double x = convertFromCentimicrons(gn.cx);
double y = convertFromCentimicrons(gn.cy);
NodeInst newni = NodeInst.makeInstance(np, new Point2D.Double(x, y), 0, 0, currentBackCell.addr);
Export.newInstance(currentBackCell.addr, newni.getOnlyPortInst(), name);
return false;
}
private void rotateLayer(Point pt, int deg)
{
// trivial test to prevent atan2 domain errors
if (pt.x == 0 && pt.y == 0) return;
switch (deg) // do the Manhattan cases directly
{
case 0:
case 3600: // just in case
break;
case 900:
int temp = pt.x; pt.x = -pt.y; pt.y = temp;
break;
case 1800:
pt.x = -pt.x; pt.y = -pt.y;
break;
case 2700:
temp = pt.x; pt.x = pt.y; pt.y = -temp;
break;
default: // this old code only permits rotation by integer angles
double factx = 1, facty = 1;
while(Math.abs(pt.x/factx) > 1000) factx *= 10.0;
while(Math.abs(pt.y/facty) > 1000) facty *= 10.0;
double fact = (factx > facty) ? facty : factx;
double fx = pt.x / fact; double fy = pt.y / fact;
double vlen = fact * Math.hypot(fx, fy);
double vang = (deg + GenMath.figureAngle(new Point2D.Double(0, 0), new Point2D.Double(pt.x, pt.y))) / 10.0 / (45.0 / Math.atan(1.0));
pt.x = (int)(vlen * Math.cos(vang));
pt.y = (int)(vlen * Math.sin(vang));
break;
}
}
private void outputPolygon(Layer lay, FrontPath pPath)
{
int lim = pPath.pLength;
if (lim < 3) return;
placeCIFList(CPOLY);
BackCIFPoly cp = (BackCIFPoly)currentFrontElement.member;
cp.lay = lay;
cp.x = new int[lim];
cp.y = new int[lim];
cp.lim = lim;
for (int i = 0; i < lim; i++)
{
Point temp = removePoint(pPath);
cp.x[i] = temp.x;
cp.y[i] = temp.y;
}
}
private double convertFromCentimicrons(double v)
{
return TextUtils.convertFromDistance(v/100, curTech, TextUtils.UnitScale.MICRO);
}
private boolean nodesBox()
{
BackCIFBox cb = (BackCIFBox)currentFrontElement.member;
NodeProto node = findPrototype(cb.lay);
if (node == null)
{
String layname = cb.lay.getName();
System.out.println("Cannot find primitive to use for layer '" + layname + "' (number " + cb.lay + ")");
return true;
}
int r = GenMath.figureAngle(new Point2D.Double(0, 0), new Point2D.Double(cb.xRot, cb.yRot));
double x = convertFromCentimicrons(cb.cenX);
double y = convertFromCentimicrons(cb.cenY);
double len = convertFromCentimicrons(cb.length);
double wid = convertFromCentimicrons(cb.width);
Orientation orient = Orientation.fromAngle(r);
NodeInst ni = NodeInst.makeInstance(node, new Point2D.Double(x, y), len, wid, currentBackCell.addr, orient, null);
if (ni == null)
{
String layname = cb.lay.getName();
System.out.println("Problems creating a box on layer " + layname + " in " + currentBackCell.addr);
return true;
}
return false;
}
private boolean interpret()
{
initParser();
initInterpreter();
inFromFile();
parseFile(); // read in the CIF
doneParser();
if (numFatalErrors > 0) return true;
if (unknownLayerNames.size() > 0)
{
System.out.println("Error: these layers appear in the CIF file but are not assigned to Electric layers:");
for(String str : unknownLayerNames)
{
System.out.println(" " + str);
}
}
getInterpreterBounds();
// construct a list: first step in the conversion
createList();
return false;
}
private BackCIFCell findBackCIFCell(int cIndex)
{
return cifCellMap.get(new Integer(cIndex));
}
private BackCIFCell makeBackCIFCell(int cIndex)
{
BackCIFCell newCC = new BackCIFCell();
newCC.addr = null;
cifCellMap.put(new Integer(cIndex), newCC);
currentBackCell = newCC;
return newCC;
}
private NodeProto findPrototype(Layer lay)
{
return lay.getNonPseudoLayer().getPureLayerNode();
}
private boolean initFind()
{
// get the array of CIF names
cifLayerNames = new HashMap<String,Layer>();
unknownLayerNames = new HashSet<String>();
boolean valid = false;
for(Iterator<Layer> it = curTech.getLayers(); it.hasNext(); )
{
Layer layer = it.next();
String cifName = layer.getCIFLayer();
if (cifName != null && cifName.length() > 0)
{
cifLayerNames.put(cifName, layer);
valid = true;
}
}
if (!valid)
{
System.out.println("There are no CIF layer names assigned in the " + curTech.getTechName() + " technology");
return true;
}
return false;
}
private void initInterpreter()
{
numNullLayerErrors = false;
isInCellDefinition = false;
ignoreStatements = false;
namePending = false;
endCommandFound = false;
currentLayer = null;
currentItemList = new ArrayList<FrontItem>();
initUtilities();
initMatrices();
}
private void initParser()
{
errorFound = false;
errorType = NOERROR;
isInCellDefinition = false;
endIsSeen = false;
initInput();
initErrors();
}
private void doneParser()
{
if (!endIsSeen) errorReport("missing End command", FATALSYNTAX);
}
private int parseFile()
{
int comCount = 1;
for(;;)
{
int com = parseStatement();
if (com == END || com == ENDFILE) break;
comCount++;
}
return comCount;
}
private void doneInterpreter()
{
if (numNullLayerErrors)
{
System.out.println("Warning: some CIF objects were not read");
}
}
private Rectangle getInterpreterBounds()
{
boolean first = true;
pushTransform();
for(FrontItem h : currentItemList)
{
FrontObjBase obj = h.what;
Point temp = new Point();
temp.x = obj.bb.l;
temp.y = obj.bb.b;
Point comperror = transformPoint(temp);
initMinMax(comperror);
temp.x = obj.bb.r;
comperror = transformPoint(temp);
minMax(comperror);
temp.y = obj.bb.t;
comperror = transformPoint(temp);
minMax(comperror);
temp.x = obj.bb.l;
comperror = transformPoint(temp);
minMax(comperror);
int left = getMinMaxMinX();
int right = getMinMaxMaxX();
int bottom = getMinMaxMinY();
int top = getMinMaxMaxY();
doneMinMax();
temp.x = left; temp.y = bottom;
if (first) {first = false; initMinMax(temp);} else minMax(temp);
temp.x = right; temp.y = top;
minMax(temp);
}
Rectangle ret = new Rectangle(getMinMaxMinX(), getMinMaxMinY(),
getMinMaxMaxX()-getMinMaxMinX(), getMinMaxMaxY()-getMinMaxMinY());
doneMinMax();
popTransform();
return ret;
}
private void createList()
{
if (!isEndSeen()) System.out.println("missing End command, assumed");
if (numFatalErrors > 0) return;
sendList(currentItemList); // sendlist deletes nodes
currentItemList = null;
}
private void sendList(List<FrontItem> list)
{
for(FrontItem h : list)
outItem(h);
}
/**
* spit out an item
*/
private void outItem(FrontItem thing)
{
if (thing.what instanceof FrontPoly)
{
FrontPoly po = (FrontPoly)thing.what;
FrontPath pPath = new FrontPath();
for (int i = 0; i < po.points.length; i++)
appendPoint(pPath, po.points[i]);
outputPolygon(po.layer, pPath);
return;
}
if (thing.what instanceof FrontWire)
{
FrontWire wi = (FrontWire)thing.what;
FrontPath pPath = new FrontPath();
for (int i = 0; i < wi.points.length; i++)
appendPoint(pPath, wi.points[i]);
outputWire(wi.layer, wi.width, pPath);
return;
}
if (thing.what instanceof FrontFlash)
{
FrontFlash fl = (FrontFlash)thing.what;
outputFlash(fl.layer, fl.diameter, fl.center);
return;
}
if (thing.what instanceof FrontBox)
{
FrontBox bo = (FrontBox)thing.what;
outputBox(bo.layer, bo.length, bo.width, bo.center, bo.xRot, bo.yRot);
return;
}
if (thing.what instanceof FrontManBox)
{
Point temp = new Point();
FrontManBox mb = (FrontManBox)thing.what;
temp.x = (mb.bb.r + mb.bb.l)/2;
temp.y = (mb.bb.t + mb.bb.b)/2;
outputBox(mb.layer, mb.bb.r-mb.bb.l, mb.bb.t-mb.bb.b, temp, 1, 0);
return;
}
if (thing.what instanceof FrontCall)
{
pushTransform();
FrontCall sc = (FrontCall)thing.what;
applyLocal(sc.matrix);
FrontTransformList tList = new FrontTransformList();
dupTransformList(sc.transList, tList);
dumpDefinition(sc.unID);
outputCall(sc.symNumber, sc.unID.name, tList, sc.lineNumber);
popTransform();
return;
}
if (thing.what instanceof FrontGeomName)
{
FrontGeomName gn = (FrontGeomName)thing.what;
outputGeomName(gn.layer, gn.name, (gn.bb.l + gn.bb.r)/2, (gn.bb.b + gn.bb.t)/2);
return;
}
if (thing.what instanceof FrontLabel)
{
FrontLabel la = (FrontLabel)thing.what;
outputLabel(la.name, la.pos);
return;
}
}
private void outputLabel(String name, Point pt)
{
placeCIFList(CLABEL);
BackCIFLabel cl = (BackCIFLabel)currentFrontElement.member;
cl.label = name;
cl.x = pt.x; cl.y = pt.y;
}
private void outputGeomName(Layer lay, String name, int cX, int cY)
{
placeCIFList(CGNAME);
BackCIFGeomName cg = (BackCIFGeomName)currentFrontElement.member;
cg.lay = lay;
cg.name = name;
cg.cx = cX;
cg.cy = cY;
}
private void outputCall(int number, String name, FrontTransformList list, int lineNumber)
{
placeCIFList(CCALL);
currentFrontElement.lineNumber = lineNumber;
BackCIFCall cc = (BackCIFCall)currentFrontElement.member;
cc.cIndex = number;
cc.name = name;
cc.list = currentCTrans = null;
for(int i = getFrontTransformListLength(list); i>0; i--)
{
if (newBackCIFTransform() == null) return;
FrontTransformEntry temp = removeFrontTransformEntry(list);
if (temp.kind == MIRROR)
{
if (temp.xCoord) currentCTrans.type = MIRX; else
currentCTrans.type = MIRY;
} else if (temp.kind == TRANSLATE)
{
currentCTrans.type = TRANS;
currentCTrans.x = temp.xt;
currentCTrans.y = temp.yt;
} else if (temp.kind == ROTATE)
{
currentCTrans.type = ROT;
currentCTrans.x = temp.xRot;
currentCTrans.y = temp.yRot;
}
}
}
private BackCIFTransform newBackCIFTransform()
{
BackCIFTransform newCT = new BackCIFTransform();
newCT.next = null;
BackCIFCall cc = (BackCIFCall)currentFrontElement.member;
if (cc.list == null) cc.list = newCT; else
currentCTrans.next = newCT;
currentCTrans = newCT;
return newCT;
}
private void dumpDefinition(FrontSymbol sym)
{
if (sym.dumped) return; // already done
if (sym.numCalls > 0) // dump all children
{
int count = sym.numCalls;
FrontObjBase ro = sym.guts;
while (ro != null && count > 0)
{
if (ro instanceof FrontCall)
{
dumpDefinition(((FrontCall)ro).unID);
count--;
}
ro = ro.next;
}
}
shipContents(sym);
sym.dumped = true;
}
private void shipContents(FrontSymbol sym)
{
FrontObjBase ro = sym.guts;
outputDefinitionStart(sym.symNumber, sym.name, sym.bounds.l, sym.bounds.r, sym.bounds.b, sym.bounds.t);
while (ro != null)
{
if (ro instanceof FrontPoly)
{
FrontPoly po = (FrontPoly)ro;
FrontPath pPath = new FrontPath();
for (int i = 0; i < po.points.length; i++)
appendPoint(pPath, po.points[i]);
outputPolygon(po.layer, pPath);
} else if (ro instanceof FrontWire)
{
FrontWire wi = (FrontWire)ro;
FrontPath pPath = new FrontPath();
for (int i = 0; i < wi.points.length; i++)
appendPoint(pPath, wi.points[i]);
outputWire(wi.layer, wi.width, pPath);
} else if (ro instanceof FrontFlash)
{
FrontFlash fl = (FrontFlash)ro;
outputFlash(fl.layer, fl.diameter, fl.center);
} else if (ro instanceof FrontBox)
{
FrontBox bo = (FrontBox)ro;
outputBox(bo.layer, bo.length, bo.width, bo.center, bo.xRot, bo.yRot);
} else if (ro instanceof FrontManBox)
{
FrontManBox mb = (FrontManBox)ro;
Point temp = new Point();
temp.x = (((FrontManBox)ro).bb.r + ((FrontManBox) ro).bb.l)/2;
temp.y = (((FrontManBox)ro).bb.t + ((FrontManBox) ro).bb.b)/2;
outputBox(mb.layer, mb.bb.r-mb.bb.l, mb.bb.t-mb.bb.b, temp, 1, 0);
} else if (ro instanceof FrontCall)
{
FrontCall sc = (FrontCall)ro;
FrontTransformList tList = new FrontTransformList();
dupTransformList(sc.transList, tList);
outputCall(sc.symNumber, sc.unID.name, tList, sc.lineNumber);
} else if (ro instanceof FrontGeomName)
{
FrontGeomName gn = (FrontGeomName)ro;
outputGeomName(gn.layer, gn.name, (gn.bb.l + gn.bb.r)/2, (gn.bb.b + gn.bb.t)/2);
} else if (ro instanceof FrontLabel)
{
FrontLabel la = (FrontLabel)ro;
outputLabel(la.name, la.pos);
}
ro = ro.next;
}
outputDefinitionEnd();
}
private void outputDefinitionEnd()
{
placeCIFList(CEND);
}
private void outputDefinitionStart(int number, String name, int l, int r, int b, int t)
{
placeCIFList(CSTART);
BackCIFStart cs = (BackCIFStart)currentFrontElement.member;
cs.cIndex = number;
cs.name = name;
cs.l = l; cs.r = r;
cs.b = b; cs.t = t;
}
private void dupTransformList(FrontTransformList src, FrontTransformList dest)
{
if (src == null || dest == null) return;
FrontLinkedTransform node = src.tFirst;
while (node != null)
{
appendTransformEntry(dest, node.tValue);
node = node.tNext;
}
}
private void outputBox(Layer lay, int length, int width, Point center, int xRotation, int yRotation)
{
if (length == 0 && width == 0) return; // ignore null boxes
placeCIFList(CBOX);
BackCIFBox cb = (BackCIFBox)currentFrontElement.member;
cb.lay = lay;
cb.length = length; cb.width = width;
cb.cenX = center.x; cb.cenY = center.y;
cb.xRot = xRotation; cb.yRot = yRotation;
}
private void placeCIFList(int id)
{
BackCIFList cl = newBackCIFList(id);
if (cl == null) return;
if (currentFrontList == null) currentFrontList = new ArrayList<BackCIFList>();
currentFrontList.add(cl);
currentFrontElement = cl;
}
private BackCIFList newBackCIFList(int id)
{
BackCIFList newCL = new BackCIFList();
newCL.identity = id;
switch (id)
{
case CSTART:
BackCIFStart cs = new BackCIFStart();
newCL.member = cs;
cs.name = null;
break;
case CBOX:
newCL.member = new BackCIFBox();
break;
case CPOLY:
newCL.member = new BackCIFPoly();
break;
case CGNAME:
newCL.member = new BackCIFGeomName();
break;
case CLABEL:
newCL.member = new BackCIFLabel();
break;
case CCALL:
BackCIFCall cc = new BackCIFCall();
newCL.member = cc;
cc.name = null;
break;
}
return newCL;
}
private void outputFlash(Layer lay, int diameter, Point center)
{
// flash approximated by an octagon
int radius = diameter/2;
double fCX = center.x;
double fCY = center.y;
double offset = ((diameter)/2.0f)*0.414213f;
FrontPath fpath = new FrontPath();
Point temp = new Point();
temp.x = center.x-radius;
temp.y = (int)(fCY+offset);
appendPoint(fpath, temp);
temp.y = (int)(fCY-offset);
appendPoint(fpath, temp);
temp.x = (int)(fCX-offset);
temp.y = center.y-radius;
appendPoint(fpath, temp);
temp.x = (int)(fCX+offset);
appendPoint(fpath, temp);
temp.x = center.x+radius;
temp.y = (int)(fCY-offset);
appendPoint(fpath, temp);
temp.y = (int)(fCY+offset);
appendPoint(fpath, temp);
temp.x = (int)(fCX+offset);
temp.y = center.y+radius;
appendPoint(fpath, temp);
temp.x = (int)(fCX-offset);
appendPoint(fpath, temp);
outputPolygon(lay, fpath);
}
/**
* convert wires to boxes and flashes
*/
private void outputWire(Layer lay, int width, FrontPath wpath)
{
int lim = wpath.pLength;
Point prev = removePoint(wpath);
// do not use round-flashes with zero-width wires
if (width != 0 && !localPrefs.squareWires)
{
boundsFlash(width, prev);
outputFlash(lay, width, prev);
}
for (int i = 1; i < lim; i++)
{
Point curr = removePoint(wpath);
// do not use round-flashes with zero-width wires
if (width != 0 && !localPrefs.squareWires)
{
boundsFlash(width, curr);
outputFlash(lay, width, curr);
}
int xr = curr.x-prev.x;
int yr = curr.y-prev.y;
int len = (int)new Point2D.Double(0, 0).distance(new Point2D.Double(xr, yr));
if (localPrefs.squareWires) len += width;
Point center = new Point((curr.x+prev.x)/2, (curr.y+prev.y)/2);
boundsBox(len, width, center, xr, yr);
outputBox(lay, len, width, center, xr, yr);
prev = curr;
}
}
private boolean isEndSeen()
{
return endCommandFound;
}
private void initInput()
{
charactersRead = 0;
resetInputBuffer = true;
}
private void initErrors()
{
numFatalErrors = 0;
}
private void initUtilities()
{
minMaxStackLeft = new int[MAXMMSTACK];
minMaxStackRight = new int[MAXMMSTACK];
minMaxStackBottom = new int[MAXMMSTACK];
minMaxStackTop = new int[MAXMMSTACK];
symbolTable = new HashMap<Integer,FrontSymbol>();
minMaxStackPtr = -1; // min/max stack pointer
}
private void initMatrices()
{
matrixStackTop = new FrontMatrix();
clearMatrix(matrixStackTop);
matrixStackTop.next = null;
matrixStackTop.prev = null;
matrixStackTop.multiplied = true;
}
private void clearMatrix(FrontMatrix mat)
{
mat.a11 = 1.0; mat.a12 = 0.0;
mat.a21 = 0.0; mat.a22 = 1.0;
mat.a31 = 0.0; mat.a32 = 0.0; mat.a33 = 1.0;
mat.type = TIDENT; mat.multiplied = false;
}
private void inFromFile()
{
try
{
nextInputCharacter = lineReader.read();
updateProgressDialog(1);
} catch (IOException e)
{
nextInputCharacter = -1;
}
}
private char getNextCharacter()
{
if (resetInputBuffer)
{
resetInputBuffer = false;
inputBuffer = new StringBuilder();
charactersRead = 0;
}
int c = nextInputCharacter;
if (c >= 0)
{
if (c != '\n')
{
charactersRead++;
inputBuffer.append((char)c);
} else resetInputBuffer = true;
try
{
nextInputCharacter = lineReader.read();
updateProgressDialog(1);
} catch (IOException e)
{
nextInputCharacter = -1;
}
}
return (char)c;
}
private char peekNextCharacter()
{
return (char)nextInputCharacter;
}
private boolean atEndOfFile()
{
return nextInputCharacter < 0;
}
private int flushInput(char breakchar)
{
int c;
while ((c = peekNextCharacter()) >= 0 && c != breakchar) getNextCharacter();
return c;
}
private void skipBlanks()
{
for(;;)
{
if (atEndOfFile()) break;
int c = peekNextCharacter();
if (TextUtils.isDigit((char)c) || Character.isUpperCase((char)c)) break;
if (c == '(' || c == ')' || c == ';' || c == '-') break;
getNextCharacter();
}
}
private int parseStatement()
{
if (atEndOfFile()) return ENDFILE;
skipBlanks(); // flush initial junk
int curChar = getNextCharacter();
int command = 0;
int xRotate=0, yRotate=0, length=0, width=0, diameter=0, symbolNumber=0, multiplier=0, divisor=0, userCommand=0;
Point center = null, namePoint = null;
FrontTransformList curTList = null;
FrontPath curPath = null;
String lName = null, nameText = null, userText = null;
switch (curChar)
{
case 'P':
command = POLYCOM;
curPath = new FrontPath();
getPath(curPath); if (errorFound) return reportError();
break;
case 'B':
command = BOXCOM;
xRotate = 1; yRotate = 0;
length = getNumber(); if (errorFound) return reportError();
width = getNumber(); if (errorFound) return reportError();
center = getPoint(); if (errorFound) return reportError();
skipSeparators();
if (((curChar = peekNextCharacter()) >= '0' && curChar <= '9') || curChar == '-')
{
xRotate = getSignedInteger(); if (errorFound) return reportError();
yRotate = getSignedInteger(); if (errorFound) return reportError();
}
break;
case 'R':
command = FLASHCOM;
diameter = getNumber(); if (errorFound) return reportError();
center = getPoint(); if (errorFound) return reportError();
break;
case 'W':
command = WIRECOM;
width = getNumber(); if (errorFound) return reportError();
curPath = new FrontPath();
getPath(curPath); if (errorFound) return reportError();
break;
case 'L':
command = LAYER;
skipBlanks();
StringBuilder layerName = new StringBuilder();
for (;;)
// for (int i = 0; i<4; i++)
{
int chr = peekNextCharacter();
if (!Character.isUpperCase((char)chr) && !TextUtils.isDigit((char)chr)) break;
layerName.append(getNextCharacter());
}
if (layerName.length() == 0) {errorFound = true; errorType = NOLAYER; return reportError();}
lName = layerName.toString();
break;
case 'D':
skipBlanks();
switch (getNextCharacter())
{
case 'S':
command = DEFSTART;
symbolNumber = getNumber(); if (errorFound) return reportError();
skipSeparators(); multiplier = divisor = 1;
if (TextUtils.isDigit(peekNextCharacter()))
{
multiplier = getNumber(); if (errorFound) return reportError();
divisor = getNumber(); if (errorFound) return reportError();
}
if (isInCellDefinition)
{
errorFound = true;
errorType = NESTDEF;
return reportError();
}
isInCellDefinition = true;
break;
case 'F':
command = DEFEND;
if (!isInCellDefinition)
{
errorFound = true;
errorType = NODEFSTART;
return reportError();
}
isInCellDefinition = false;
break;
case 'D':
command = DELETEDEF;
symbolNumber = getNumber(); if (errorFound) return reportError();
if (isInCellDefinition)
{
errorFound = true;
errorType = NESTDD;
return reportError();
}
break;
default:
errorFound = true;
errorType = BADDEF;
return reportError();
}
break;
case 'C':
command = CALLCOM;
symbolNumber = getNumber(); if (errorFound) return reportError();
skipBlanks();
curTList = new FrontTransformList();
for(;;)
{
FrontTransformEntry trans = new FrontTransformEntry();
int val = peekNextCharacter();
if (val == ';') break;
switch (peekNextCharacter())
{
case 'T':
getNextCharacter();
trans.kind = TRANSLATE;
trans.xt = getSignedInteger(); if (errorFound) return reportError();
trans.yt = getSignedInteger(); if (errorFound) return reportError();
appendTransformEntry(curTList, trans);
break;
case 'M':
trans.kind = MIRROR;
getNextCharacter(); skipBlanks();
switch (getNextCharacter())
{
case 'X': trans.xCoord = true; break;
case 'Y': trans.xCoord = false; break;
default: errorFound = true; errorType = BADAXIS; return reportError();
}
appendTransformEntry(curTList, trans);
break;
case 'R':
trans.kind = ROTATE;
getNextCharacter();
trans.xRot = getSignedInteger(); if (errorFound) return reportError();
trans.yRot = getSignedInteger(); if (errorFound) return reportError();
appendTransformEntry(curTList, trans);
break;
default:
errorFound = true; errorType = BADTRANS; return reportError();
}
skipBlanks(); // between transformation commands
} // end of while (1) loop
break;
case '(':
{
int level = 1;
command = COMMENT;
StringBuffer comment = new StringBuffer();
while (level != 0)
{
curChar = getNextCharacter();
switch (curChar)
{
case '(':
level++;
comment.append('(');
break;
case ')':
level--;
if (level != 0) comment.append(')');
break;
case -1:
errorFound = true; errorType = BADCOMMENT; return reportError();
default:
comment.append(curChar);
}
}
}
break;
case 'E':
skipBlanks();
if (isInCellDefinition)
{
errorFound = true;
errorType = NESTEND;
return reportError();
}
if (!atEndOfFile()) errorReport("more text follows end command", ADVISORY);
endIsSeen = true;
processEnd();
return END;
case ';':
return NULLCOMMAND;
default:
if (TextUtils.isDigit((char)curChar))
{
userCommand = curChar - '0';
if (userCommand == 9)
{
curChar = peekNextCharacter();
if (curChar == ' ' || curChar == '\t' || curChar == '1' || curChar == '2' || curChar == '3')
{
switch (getNextCharacter())
{
case ' ':
case '\t':
skipSpaces(); nameText = parseName(); if (errorFound) return reportError();
command = SYMNAME;
break;
case '1':
case '2':
case '3':
if (!skipSpaces())
{
errorFound = true; errorType = NOSPACE;
return reportError();
}
nameText = parseName(); if (errorFound) return reportError();
switch (curChar)
{
case '1':
command = INSTNAME;
break;
case '2':
{
command = GEONAME;
namePoint = getPoint(); if (errorFound) return reportError();
skipBlanks();
StringBuffer layName = new StringBuffer();
for (int i = 0; i<4; i++)
{
int chr = peekNextCharacter();
if (!Character.isUpperCase((char)chr) && !TextUtils.isDigit((char)chr)) break;
layName.append(getNextCharacter());
}
lName = layName.toString();
break;
}
case '3':
command = LABELCOM;
namePoint = getPoint(); if (errorFound) return reportError();
break;
}
break;
}
} else
{
command = USERS;
userText = getUserText();
if (atEndOfFile())
{
errorFound = true; errorType = BADUSER; return reportError();
}
}
} else if (userCommand == 4)
{
curChar = peekNextCharacter();
if (curChar == 'I' || curChar == 'X' || curChar == 'N')
{
switch (getNextCharacter())
{
case 'I':
case 'X':
case 'N':
if (!skipSpaces())
{
errorFound = true; errorType = NOSPACE;
return reportError();
}
nameText = parseName(); if (errorFound) return reportError();
switch (curChar)
{
case 'I':
command = INSTNAME;
break;
case 'X':
{
command = GEONAME;
getSignedInteger(); // skip Index
namePoint = getPoint(); if (errorFound) return reportError();
int w = getSignedInteger();
getUserText();
lName = currentLayer != null ? currentLayer.getCIFLayer() : null;
break;
}
case 'N':
command = LABELCOM;
namePoint = getPoint(); if (errorFound) return reportError();
break;
}
break;
}
} else
{
command = USERS;
userText = getUserText();
if (atEndOfFile())
{
errorFound = true; errorType = BADUSER; return reportError();
}
}
} else {
command = USERS;
userText = getUserText();
if (atEndOfFile())
{
errorFound = true; errorType = BADUSER; return reportError();
}
}
} else {
errorFound = true;
errorType = BADCOMMAND;
return reportError();
}
}
// by now we have a syntactically valid command although it might be missing a semicolon
switch (command)
{
case WIRECOM:
makeWire(width, curPath);
break;
case DEFSTART:
makeStartDefinition(symbolNumber, multiplier, divisor);
break;
case DEFEND:
makeEndDefinition();
break;
case DELETEDEF:
makeDeleteDefinition(symbolNumber);
break;
case CALLCOM:
makeCall(symbolNumber, curTList);
break;
case LAYER:
makeLayer(lName);
break;
case FLASHCOM:
makeFlash(diameter, center);
break;
case POLYCOM:
makePolygon(curPath);
break;
case BOXCOM:
makeBox(length, width, center, xRotate, yRotate);
break;
case COMMENT:
break;
case USERS:
makeUserComment(userCommand, userText);
break;
case SYMNAME:
makeSymbolName(nameText);
break;
case INSTNAME:
makeInstanceName(nameText);
break;
case GEONAME:
makeGeomName(nameText, namePoint, cifLayerNames.get(lName));
break;
case LABELCOM:
makeLabel(nameText, namePoint);
break;
default:
errorFound = true;
errorType = INTERNAL;
return reportError();
}
if (!skipSemicolon()) {errorFound = true; errorType = NOSEMI; return reportError();}
return command;
}
private void makeLabel(String name, Point pt)
{
statementsSince91 = true;
if (ignoreStatements) return;
if (name.length() == 0)
{
errorReport("null label ignored", ADVISORY);
return;
}
FrontLabel obj = new FrontLabel();
if (isInCellDefinition && cellScaleFactor != 1.0)
{
pt.x = (int)Math.round(cellScaleFactor * pt.x);
pt.y = (int)Math.round(cellScaleFactor * pt.y);
}
obj.pos = pt;
obj.name = name;
pushTransform();
Point temp = transformPoint(pt);
popTransform();
obj.bb.l = temp.x;
obj.bb.r = temp.x;
obj.bb.b = temp.y;
obj.bb.t = temp.y;
if (isInCellDefinition)
{
// insert into symbol's guts
obj.next = currentFrontSymbol.guts;
currentFrontSymbol.guts = obj;
} else topLevelItem(obj); // stick into item list
}
private void makeGeomName(String name, Point pt, Layer lay)
{
statementsSince91 = true;
if (ignoreStatements) return;
if (name.length() == 0)
{
errorReport("null geometry name ignored", ADVISORY);
return;
}
FrontGeomName obj = new FrontGeomName();
obj.layer = lay;
obj.name = name;
if (isInCellDefinition && cellScaleFactor != 1.0)
{
pt.x = (int)Math.round(cellScaleFactor * pt.x);
pt.y = (int)Math.round(cellScaleFactor * pt.y);
}
pushTransform();
Point temp = transformPoint(pt);
popTransform();
obj.bb.l = temp.x;
obj.bb.r = temp.x;
obj.bb.b = temp.y;
obj.bb.t = temp.y;
if (isInCellDefinition)
{
// insert into symbol's guts
obj.next = currentFrontSymbol.guts;
currentFrontSymbol.guts = obj;
} else topLevelItem(obj); // stick into item list
}
private void makeSymbolName(String name)
{
statementsSince91 = true;
if (ignoreStatements) return;
if (!isInCellDefinition)
{
errorReport("no symbol to name", FATALSEMANTIC);
return;
}
if (name.length() == 0)
{
errorReport("null symbol name ignored", ADVISORY);
return;
}
if (symbolNamed)
{
errorReport("symbol is already named, new name ignored", FATALSEMANTIC);
return;
}
symbolNamed = true;
currentFrontSymbol.name = name;
}
private void makeUserComment(int command, String text)
{
statementsSince91 = true;
if (ignoreStatements) return;
}
private void makeBox(int length, int width, Point center, int xr, int yr)
{
statementsSince91 = true;
if (ignoreStatements) return;
if (currentLayer == null)
{
numNullLayerErrors = true;
return;
}
if (length == 0 || width == 0)
{
errorReport("box with null length or width specified, ignored", ADVISORY);
return;
}
if (isInCellDefinition && cellScaleFactor != 1.0)
{
length = (int)Math.round(cellScaleFactor * length);
width = (int)Math.round(cellScaleFactor * width);
center.x = (int)Math.round(cellScaleFactor * center.x);
center.y = (int)Math.round(cellScaleFactor * center.y);
}
Rectangle box = boundsBox(length, width, center, xr, yr);
int tl = box.x; int tr = box.x + box.width;
int tb = box.y; int tt = box.y + box.height;
// check for Manhattan box
int halfW = width/2;
int halfL = length/2;
if (
(yr == 0 && (length%2) == 0 && (width%2) == 0 &&
(center.x-halfL) == tl && (center.x+halfL) == tr &&
(center.y-halfW) == tb && (center.y+halfW) == tt)
||
(xr == 0 && (length%2) == 0 && (width%2) == 0 &&
(center.x-halfW) == tl && (center.x+halfW) == tr &&
(center.y-halfL) == tb && (center.y+halfL) == tt)
)
{
// a Manhattan box
FrontManBox obj = new FrontManBox();
obj.layer = currentLayer;
if (yr == 0)
{
obj.bb.l = tl;
obj.bb.r = tr;
obj.bb.b = tb;
obj.bb.t = tt;
} else
{
// this assumes that bounding box is unaffected by rotation
obj.bb.l = center.x-halfW;
obj.bb.r = center.x+halfW;
obj.bb.b = center.y-halfL;
obj.bb.t = center.y+halfL;
}
if (isInCellDefinition)
{
// insert into symbol's guts
obj.next = currentFrontSymbol.guts;
currentFrontSymbol.guts = obj;
} else topLevelItem(obj); // stick into item list
} else
{
FrontBox obj = new FrontBox();
obj.layer = currentLayer;
obj.length = length;
obj.width = width;
obj.center = center;
obj.xRot = xr;
obj.yRot = yr;
obj.bb.l = tl;
obj.bb.r = tr;
obj.bb.b = tb;
obj.bb.t = tt;
if (isInCellDefinition)
{
// insert into symbol's guts
obj.next = currentFrontSymbol.guts;
currentFrontSymbol.guts = obj;
} else topLevelItem(obj); // stick into item list
}
}
private void makeFlash(int diameter, Point center)
{
statementsSince91 = true;
if (ignoreStatements) return;
if (currentLayer == null)
{
numNullLayerErrors = true;
return;
}
if (diameter == 0)
{
errorReport("flash with null diamter, ignored", ADVISORY);
return;
}
FrontFlash obj = new FrontFlash();
obj.layer = currentLayer;
if (isInCellDefinition && cellScaleFactor != 1.0)
{
diameter = (int)Math.round(cellScaleFactor * diameter);
center.x = (int)Math.round(cellScaleFactor * center.x);
center.y = (int)Math.round(cellScaleFactor * center.y);
}
obj.diameter = diameter;
obj.center = center;
Rectangle box = boundsFlash(diameter, center);
obj.bb.l = box.x;
obj.bb.r = box.x + box.width;
obj.bb.b = box.y;
obj.bb.t = box.y + box.height;
if (isInCellDefinition)
{
// insert into symbol's guts
obj.next = currentFrontSymbol.guts;
currentFrontSymbol.guts = obj;
} else topLevelItem(obj); // stick into item list
}
private Rectangle boundsFlash(int diameter, Point center)
{
return boundsBox(diameter, diameter, center, 1, 0);
}
private Rectangle boundsBox(int length, int width, Point center, int xr, int yr)
{
int dx = length/2;
int dy = width/2;
pushTransform(); // new transformation
rotateMatrix(xr, yr);
translateMatrix(center.x, center.y);
Point temp = new Point(dx, dy);
initMinMax(transformPoint(temp));
temp.y = -dy;
minMax(transformPoint(temp));
temp.x = -dx;
minMax(transformPoint(temp));
temp.y = dy;
minMax(transformPoint(temp));
popTransform();
Rectangle ret = new Rectangle(getMinMaxMinX(), getMinMaxMinY(),
getMinMaxMaxX()-getMinMaxMinX(), getMinMaxMaxY()-getMinMaxMinY());
doneMinMax();
return ret;
}
private void makeLayer(String lName)
{
statementsSince91 = true;
if (ignoreStatements) return;
currentLayer = cifLayerNames.get(lName);
if (currentLayer == null)
{
unknownLayerNames.add(lName);
}
}
private void makeCall(int symbol, FrontTransformList list)
{
if (ignoreStatements) return;
int j = getFrontTransformListLength(list);
FrontTransformList newtlist = null;
if (j != 0) newtlist = new FrontTransformList();
pushTransform(); // get new frame of reference
for (int i = 1; i <=j; i++)
{
// build up incremental transformations
FrontTransformEntry temp = removeFrontTransformEntry(list);
if (temp.kind == MIRROR)
{
mirrorMatrix(temp.xCoord);
} else if (temp.kind == TRANSLATE)
{
if (isInCellDefinition && cellScaleFactor != 1.0)
{
temp.xt = (int)Math.round(cellScaleFactor * temp.xt);
temp.yt = (int)Math.round(cellScaleFactor * temp.yt);
}
translateMatrix(temp.xt, temp.yt);
} else if (temp.kind == ROTATE)
{
rotateMatrix(temp.xRot, temp.yRot);
} else
{
errorReport("interpreter: no such transformation", FATALINTERNAL);
}
appendTransformEntry(newtlist, temp); // copy the list
}
FrontCall obj = new FrontCall();
obj.lineNumber = lineReader.getLineNumber();
// must make a copy of the matrix
obj.matrix = new FrontMatrix();
obj.matrix.a11 = matrixStackTop.a11;
obj.matrix.a12 = matrixStackTop.a12;
obj.matrix.a21 = matrixStackTop.a21;
obj.matrix.a22 = matrixStackTop.a22;
obj.matrix.a31 = matrixStackTop.a31;
obj.matrix.a32 = matrixStackTop.a32;
obj.matrix.a33 = matrixStackTop.a33;
obj.matrix.type = matrixStackTop.type;
obj.matrix.multiplied = matrixStackTop.multiplied;
popTransform(); // return to previous state
obj.symNumber = symbol;
obj.unID = null;
obj.transList = newtlist;
if (namePending)
{
if (statementsSince91)
errorReport("statements between name and instance", ADVISORY);
namePending = false;
}
if (isInCellDefinition)
{
// insert into guts of symbol
obj.next = currentFrontSymbol.guts;
currentFrontSymbol.guts = obj;
currentFrontSymbol.numCalls++;
} else
{
topLevelItem(obj);
}
}
private void rotateMatrix(int xRot, int yRot)
{
double si = yRot;
double co = xRot;
if (yRot == 0 && xRot >= 0) return;
matrixStackTop.type |= TROTATE;
if (xRot == 0)
{
double temp = matrixStackTop.a11;
matrixStackTop.a11 = -matrixStackTop.a12;
matrixStackTop.a12 = temp;
temp = matrixStackTop.a21;
matrixStackTop.a21 = -matrixStackTop.a22;
matrixStackTop.a22 = temp;
temp = matrixStackTop.a31;
matrixStackTop.a31 = -matrixStackTop.a32;
matrixStackTop.a32 = temp;
if (yRot < 0) matrixStackTop.a33 = -matrixStackTop.a33;
} else
if (yRot == 0) matrixStackTop.a33 = -matrixStackTop.a33; // xRot < 0
else
{
double temp = matrixStackTop.a11*co - matrixStackTop.a12*si;
matrixStackTop.a12 = matrixStackTop.a11*si + matrixStackTop.a12*co;
matrixStackTop.a11 = temp;
temp = matrixStackTop.a21*co - matrixStackTop.a22*si;
matrixStackTop.a22 = matrixStackTop.a21*si + matrixStackTop.a22*co;
matrixStackTop.a21 = temp;
temp = matrixStackTop.a31*co - matrixStackTop.a32*si;
matrixStackTop.a32 = matrixStackTop.a31*si + matrixStackTop.a32*co;
matrixStackTop.a31 = temp;
matrixStackTop.a33 = new Point2D.Double(0, 0).distance(new Point2D.Double(co, si));
}
}
private void translateMatrix(int xtrans, int ytrans)
{
if (xtrans != 0 || ytrans != 0)
{
matrixStackTop.a31 += matrixStackTop.a33*xtrans;
matrixStackTop.a32 += matrixStackTop.a33*ytrans;
matrixStackTop.type |= TTRANSLATE;
}
}
private void mirrorMatrix(boolean xCoord)
{
if (xCoord)
{
matrixStackTop.a11 = -matrixStackTop.a11;
matrixStackTop.a21 = -matrixStackTop.a21;
matrixStackTop.a31 = -matrixStackTop.a31;
} else
{
matrixStackTop.a12 = -matrixStackTop.a12;
matrixStackTop.a22 = -matrixStackTop.a22;
matrixStackTop.a32 = -matrixStackTop.a32;
}
matrixStackTop.type |= TMIRROR;
}
private int getFrontTransformListLength(FrontTransformList a)
{
if (a == null) return 0;
return a.tLength;
}
private FrontTransformEntry removeFrontTransformEntry(FrontTransformList a)
{
if (a.tFirst == null)
{
// added extra code to initialize "ans" to a dummy value
FrontTransformEntry ans = new FrontTransformEntry();
ans.kind = TRANSLATE;
ans.xt = ans.yt = 0;
return ans;
}
FrontLinkedTransform temp = a.tFirst.tNext;
FrontTransformEntry ans = a.tFirst.tValue;
a.tFirst = temp;
if (a.tFirst == null) a.tLast = null;
a.tLength -= 1;
return ans;
}
private void makeDeleteDefinition(int n)
{
statementsSince91 = true;
errorReport("DD not supported (ignored)", ADVISORY);
}
private void makeEndDefinition()
{
statementsSince91 = true;
if (ignoreStatements)
{
ignoreStatements = false;
return;
}
isInCellDefinition = false;
currentLayer = backupLayer; // restore old layer
if (!symbolNamed)
{
String s = "SYM" + currentFrontSymbol.symNumber;
currentFrontSymbol.name = s;
}
currentFrontSymbol.defined = true;
}
private void makeStartDefinition(int symbol, int mtl, int div)
{
statementsSince91 = true;
currentFrontSymbol = lookupSymbol(symbol);
if (currentFrontSymbol.defined)
{
// redefining this symbol
String mess = "attempt to redefine symbol " + symbol + " (ignored)";
errorReport(mess, ADVISORY);
ignoreStatements = true;
return;
}
isInCellDefinition = true;
if (mtl != 0 && div != 0) cellScaleFactor = ((float) mtl)/((float) div); else
{
errorReport("illegal scale factor, ignored", ADVISORY);
cellScaleFactor = 1.0;
}
backupLayer = currentLayer; // save current layer
currentLayer = null;
symbolNamed = false; // symbol not named
}
private void makeWire(int width, FrontPath a)
{
int length = a.pLength;
statementsSince91 = true;
if (ignoreStatements) return;
if (currentLayer == null)
{
numNullLayerErrors = true;
return;
}
FrontWire obj = new FrontWire();
FrontPath tPath = a;
FrontPath sPath = null; // path in case of scaling
obj.layer = currentLayer;
if (isInCellDefinition && cellScaleFactor != 1.0)
{
sPath = new FrontPath();
scalePath(a, sPath); // scale all points
width = (int)Math.round(cellScaleFactor * width);
tPath = sPath;
}
obj.width = width;
FrontPath bbpath = new FrontPath(); // get a new path for bounding box use
copyPath(tPath, bbpath);
boundsWire(width, bbpath);
obj.points = new Point[length];
for (int i = 0; i < length; i++) obj.points[i] = removePoint(tPath);
if (isInCellDefinition)
{
// insert into symbol's guts
obj.next = currentFrontSymbol.guts;
currentFrontSymbol.guts = obj;
} else topLevelItem(obj); // stick into item list
}
private Rectangle boundsWire(int width, FrontPath pPath)
{
int half = (width+1)/2;
int limit = pPath.pLength;
pushTransform(); // new transformation
initMinMax(transformPoint(removePoint(pPath)));
for (int i = 1; i < limit; i++)
{
minMax(transformPoint(removePoint(pPath)));
}
popTransform();
Rectangle rect = new Rectangle(getMinMaxMinX()-half, getMinMaxMinY()-half,
getMinMaxMaxX()-getMinMaxMinX()+half*2, getMinMaxMaxY()-getMinMaxMinY()+half*2);
doneMinMax();
return rect;
}
private String getUserText()
{
StringBuffer user = new StringBuffer();
for(;;)
{
if (atEndOfFile()) break;
if (peekNextCharacter() == ';') break;
user.append(getNextCharacter());
}
return user.toString();
}
private String parseName()
{
StringBuffer nText = new StringBuffer();
boolean noChar = true;
for(;;)
{
if (atEndOfFile()) break;
int c = peekNextCharacter();
if (c == ';' || c == ' ' || c == '\t' || c == '{' || c == '}') break;
noChar = false;
getNextCharacter();
nText.append((char)c);
}
if (noChar) logIt(NONAME);
return nText.toString();
}
private void appendTransformEntry(FrontTransformList a, FrontTransformEntry p)
{
FrontLinkedTransform newT = new FrontLinkedTransform();
if (newT == null) return;
FrontLinkedTransform temp = a.tLast;
a.tLast = newT;
if (temp != null) temp.tNext = a.tLast;
a.tLast.tValue = p;
a.tLast.tNext = null;
if (a.tFirst == null) a.tFirst = a.tLast;
a.tLength += 1;
}
private int getNumber()
{
boolean somedigit = false;
int ans = 0;
skipSpaces();
while (ans < BIGSIGNED && TextUtils.isDigit(peekNextCharacter()))
{
ans *= 10; ans += getNextCharacter() - '0';
somedigit = true;
}
if (!somedigit)
{
logIt(NOUNSIGNED);
return 0;
}
if (TextUtils.isDigit(peekNextCharacter()))
{
logIt(NUMTOOBIG);
return 0XFFFFFFFF;
}
return ans;
}
private boolean skipSemicolon()
{
boolean ans = false;
skipBlanks();
if (peekNextCharacter() == ';') { getNextCharacter(); ans = true; skipBlanks(); }
return ans;
}
private boolean skipSpaces()
{
boolean ans = false;
for(;;)
{
int c = peekNextCharacter();
if (c != ' ' && c != '\t') break;
getNextCharacter();
ans = true;
}
return ans;
}
private void makePolygon(FrontPath a)
{
int length = a.pLength;
statementsSince91 = true;
if (ignoreStatements) return;
if (currentLayer == null)
{
numNullLayerErrors = true;
return;
}
if (length < 3)
{
errorReport("polygon with < 3 pts in path, ignored", ADVISORY);
return;
}
FrontPoly obj = new FrontPoly();
FrontPath tPath = a;
obj.layer = currentLayer;
if (isInCellDefinition && cellScaleFactor != 1.0)
{
FrontPath sPath = new FrontPath();
scalePath(a, sPath); // scale all points
tPath = sPath;
}
FrontPath bbpath = new FrontPath(); // get a new path for bounding box use
copyPath(tPath, bbpath);
Rectangle box = getPolyBounds(bbpath);
obj.bb.l = box.x;
obj.bb.r = box.x + box.width;
obj.bb.b = box.y;
obj.bb.t = box.y + box.height;
obj.points = new Point[length];
for (int i = 0; i < length; i++) obj.points[i] = removePoint(tPath);
if (isInCellDefinition)
{
// insert into symbol's guts
obj.next = currentFrontSymbol.guts;
currentFrontSymbol.guts = obj;
} else topLevelItem(obj); // stick into item list
}
/**
* a bare item has been found
*/
private void topLevelItem(FrontObjBase object)
{
if (object == null)
{
errorReport("item: null object", FATALINTERNAL);
return;
}
FrontItem newItem = new FrontItem();
currentItemList.add(newItem);
newItem.what = object;
// symbol calls only
if (object instanceof FrontCall) findCallBounds((FrontCall)object);
}
/**
* find the bounding box for this particular call
*/
private void findCallBounds(FrontCall object)
{
FrontSymbol thisST = lookupSymbol(object.symNumber);
if (!thisST.defined)
{
String mess = "call to undefined symbol " + thisST.symNumber;
errorReport(mess, FATALSEMANTIC);
return;
}
if (thisST.expanded)
{
String mess = "recursive call on symbol " + thisST.symNumber;
errorReport(mess, FATALSEMANTIC);
return;
}
thisST.expanded = true; // mark as under expansion
findBounds(thisST); // get the bounding box of the symbol in its FrontSymbol
object.unID = thisST; // get this symbol's id
pushTransform(); // set up a new frame of reference
applyLocal(object.matrix);
Point temp = new Point();
temp.x = thisST.bounds.l; temp.y = thisST.bounds.b; // lower-left
Point comperror = transformPoint(temp);
initMinMax(comperror);
temp.x = thisST.bounds.r;
comperror = transformPoint(temp);
minMax(comperror);
temp.y = thisST.bounds.t; // upper-right
comperror = transformPoint(temp);
minMax(comperror);
temp.x = thisST.bounds.l;
comperror = transformPoint(temp);
minMax(comperror);
object.bb.l = getMinMaxMinX(); object.bb.r = getMinMaxMaxX();
object.bb.b = getMinMaxMinY(); object.bb.t = getMinMaxMaxY();
doneMinMax(); // object now has transformed bounding box of the symbol
popTransform();
thisST.expanded = false;
}
/**
* find bounding box for sym
*/
private void findBounds(FrontSymbol sym)
{
boolean first = true;
FrontObjBase ob = sym.guts;
if (sym.boundsValid) return; // already done
if (ob == null) // empty symbol
{
String name = sym.name;
if (name == null) name = "#" + sym.symNumber;
System.out.println("Warning: cell " + name + " has no geometry in it");
sym.bounds.l = 0; sym.bounds.r = 0;
sym.bounds.b = 0; sym.bounds.t = 0;
sym.boundsValid = true;
return;
}
while (ob != null)
{
// find bounding box for symbol calls, all primitive are done already
if (ob instanceof FrontCall) findCallBounds((FrontCall)ob);
Point temp = new Point();
temp.x = ob.bb.l; temp.y = ob.bb.b;
if (first) {first = false; initMinMax(temp);}
else minMax(temp);
temp.x = ob.bb.r; temp.y = ob.bb.t;
minMax(temp);
ob = ob.next;
}
sym.bounds.l = getMinMaxMinX(); sym.bounds.r = getMinMaxMaxX();
sym.bounds.b = getMinMaxMinY(); sym.bounds.t = getMinMaxMaxY();
sym.boundsValid = true;
doneMinMax();
}
/**
* Method to find a given symbol.
* If none, make a blank entry.
* @return a pointer to whichever.
*/
private FrontSymbol lookupSymbol(int sym)
{
FrontSymbol val = symbolTable.get(new Integer(sym));
if (val == null)
{
// create a new entry
val = new FrontSymbol(sym);
symbolTable.put(new Integer(sym), val);
}
return val;
}
private void applyLocal(FrontMatrix tm)
{
assignMatrix(tm, matrixStackTop);
}
private void scalePath(FrontPath src, FrontPath dest)
{
int limit = src.pLength;
for (int i = 0; i < limit; i++)
{
Point temp = removePoint(src);
temp.x = (int)Math.round(cellScaleFactor * temp.x);
temp.y = (int)Math.round(cellScaleFactor * temp.y);
appendPoint(dest, temp);
}
}
private void copyPath(FrontPath src, FrontPath dest)
{
FrontLinkedPoint temp = src.pFirst;
if (src == dest) return;
while (temp != null)
{
appendPoint(dest, temp.pValue);
temp = temp.pNext;
}
}
private Rectangle getPolyBounds(FrontPath pPath)
{
int limit = pPath.pLength;
pushTransform(); // new transformation
initMinMax(transformPoint(removePoint(pPath)));
for (int i = 1; i < limit; i++)
{
minMax(transformPoint(removePoint(pPath)));
}
popTransform();
Rectangle ret = new Rectangle(getMinMaxMinX(), getMinMaxMinY(), getMinMaxMaxX()-getMinMaxMinX(), getMinMaxMaxY()-getMinMaxMinY());
doneMinMax();
return ret;
}
private void minMax(Point foo)
{
if (foo.x > minMaxStackRight[minMaxStackPtr]) minMaxStackRight[minMaxStackPtr] = foo.x;
else {if (foo.x < minMaxStackLeft[minMaxStackPtr]) minMaxStackLeft[minMaxStackPtr] = foo.x;}
if (foo.y > minMaxStackTop[minMaxStackPtr]) minMaxStackTop[minMaxStackPtr] = foo.y;
else {if (foo.y < minMaxStackBottom[minMaxStackPtr]) minMaxStackBottom[minMaxStackPtr] = foo.y;}
}
private void initMinMax(Point foo)
{
if (++minMaxStackPtr >= MAXMMSTACK)
{
errorReport("initMinMax: out of stack", FATALINTERNAL);
return;
}
minMaxStackLeft[minMaxStackPtr] = foo.x; minMaxStackRight[minMaxStackPtr] = foo.x;
minMaxStackBottom[minMaxStackPtr] = foo.y; minMaxStackTop[minMaxStackPtr] = foo.y;
}
private void doneMinMax()
{
if (minMaxStackPtr < 0) errorReport("doneMinMax: pop from empty stack", FATALINTERNAL);
else minMaxStackPtr--;
}
private int getMinMaxMinX()
{
return minMaxStackLeft[minMaxStackPtr];
}
private int getMinMaxMinY()
{
return minMaxStackBottom[minMaxStackPtr];
}
private int getMinMaxMaxX()
{
return minMaxStackRight[minMaxStackPtr];
}
private int getMinMaxMaxY()
{
return minMaxStackTop[minMaxStackPtr];
}
private void pushTransform()
{
if (matrixStackTop.next == null)
{
matrixStackTop.next = new FrontMatrix();
clearMatrix(matrixStackTop.next);
matrixStackTop.next.prev = matrixStackTop;
matrixStackTop = matrixStackTop.next;
matrixStackTop.next = null;
} else
{
matrixStackTop = matrixStackTop.next;
clearMatrix(matrixStackTop);
}
}
private void popTransform()
{
if (matrixStackTop.prev != null) matrixStackTop = matrixStackTop.prev;
else errorReport("pop, empty trans stack", FATALINTERNAL);
}
private Point transformPoint(Point foo)
{
Point ans = new Point();
if (!matrixStackTop.multiplied)
{
matrixMult(matrixStackTop, matrixStackTop.prev, matrixStackTop);
}
switch (matrixStackTop.type)
{
case TIDENT:
return foo;
case TTRANSLATE:
ans.x = (int)matrixStackTop.a31;
ans.y = (int)matrixStackTop.a32;
ans.x += foo.x; ans.y += foo.y;
return ans;
case TMIRROR:
ans.x = (matrixStackTop.a11 < 0) ? -foo.x : foo.x;
ans.y = (matrixStackTop.a22 < 0) ? -foo.y : foo.y;
return ans;
case TROTATE:
ans.x = (int)(foo.x*matrixStackTop.a11 + foo.y*matrixStackTop.a21);
ans.y = (int)(foo.x*matrixStackTop.a12 + foo.y*matrixStackTop.a22);
return ans;
default:
ans.x = (int)(matrixStackTop.a31 + foo.x*matrixStackTop.a11+
foo.y*matrixStackTop.a21);
ans.y = (int)(matrixStackTop.a32 + foo.x*matrixStackTop.a12+
foo.y*matrixStackTop.a22);
}
return ans;
}
private void matrixMult(FrontMatrix l, FrontMatrix r, FrontMatrix result)
{
if (l == null || r == null || result == null)
errorReport("null arg to matrixMult", FATALINTERNAL);
if (result.multiplied)
{
errorReport("can't re-mult matrix", FATALINTERNAL);
return;
}
if (!r.multiplied)
{
FrontMatrix temp = new FrontMatrix();
temp.multiplied = false;
matrixMult(r, r.prev, temp);
matrixMultCore(l, temp, result);
} else matrixMultCore(l, r, result);
}
private void matrixMultCore(FrontMatrix l, FrontMatrix r, FrontMatrix result)
{
if (l == null || r == null || result == null)
{
errorReport("null arg to matrixMultCore", FATALINTERNAL);
return;
}
if (l.type == TIDENT) assignMatrix(r, result); else
if (r.type == TIDENT) assignMatrix(l, result); else
{
FrontMatrix temp = new FrontMatrix();
temp.a11 = l.a11 * r.a11 + l.a12 * r.a21;
temp.a12 = l.a11 * r.a12 + l.a12 * r.a22;
temp.a21 = l.a21 * r.a11 + l.a22 * r.a21;
temp.a22 = l.a21 * r.a12 + l.a22 * r.a22;
temp.a31 = l.a31 * r.a11 + l.a32 * r.a21 + l.a33 * r.a31;
temp.a32 = l.a31 * r.a12 + l.a32 * r.a22 + l.a33 * r.a32;
temp.a33 = l.a33*r.a33;
temp.type = l.type | r.type;
assignMatrix(temp, result);
}
if (result.a33 != 1.0)
{
// divide by a33
result.a11 /= result.a33;
result.a12 /= result.a33;
result.a21 /= result.a33;
result.a22 /= result.a33;
result.a31 /= result.a33;
result.a32 /= result.a33;
result.a33 = 1.0;
}
result.multiplied = true;
}
private void assignMatrix(FrontMatrix src, FrontMatrix dest)
{
dest.a11 = src.a11;
dest.a12 = src.a12;
dest.a21 = src.a21;
dest.a22 = src.a22;
dest.a31 = src.a31;
dest.a32 = src.a32;
dest.a33 = src.a33;
dest.type = src.type;
dest.multiplied = src.multiplied;
}
private Point removePoint(FrontPath a)
{
if (a.pFirst == null)
{
// added code to initialize return value with dummy numbers
return new Point(0, 0);
}
FrontLinkedPoint temp = a.pFirst.pNext;
Point ans = a.pFirst.pValue;
a.pFirst = temp;
if (a.pFirst == null) a.pLast = null;
a.pLength -= 1;
return ans;
}
private void makeInstanceName(String name)
{
if (ignoreStatements) return;
if (name.length() == 0)
{
errorReport("null instance name ignored", ADVISORY);
return;
}
if (namePending)
{
errorReport("there is already a name pending, new name replaces it", ADVISORY);
}
namePending = true;
statementsSince91 = false;
}
private void processEnd()
{
statementsSince91 = true;
endCommandFound = true;
if (namePending)
{
errorReport("no instance to match name command", ADVISORY);
namePending = false;
}
}
private int getSignedInteger()
{
boolean sign = false;
int ans = 0;
skipSeparators();
if (peekNextCharacter() == '-') { sign = true; getNextCharacter(); }
boolean someDigit = false;
while (ans < BIGSIGNED && TextUtils.isDigit(peekNextCharacter()))
{
ans *= 10; ans += getNextCharacter() - '0';
someDigit = true;
}
if (!someDigit) { logIt(NOSIGNED); return 0; }
if (TextUtils.isDigit(peekNextCharacter()))
{
logIt(NUMTOOBIG);
return sign ? -0X7FFFFFFF : 0X7FFFFFFF;
}
return sign ? -ans : ans;
}
private void logIt(int thing)
{
errorFound = true;
errorType = thing;
}
private Point getPoint()
{
int x = getSignedInteger();
int y = getSignedInteger();
return new Point(x, y);
}
private void getPath(FrontPath a)
{
skipSeparators();
for(;;)
{
int c = peekNextCharacter();
if (!TextUtils.isDigit((char)c) && c != '-') break;
Point temp = getPoint(); if (errorFound) break;
appendPoint(a, temp);
skipSeparators();
}
if (a.pLength == 0) logIt(NOPATH);
}
private void appendPoint(FrontPath a, Point p)
{
FrontLinkedPoint temp;
temp = a.pLast;
a.pLast = new FrontLinkedPoint();
if (temp != null) temp.pNext = a.pLast;
a.pLast.pValue = p;
a.pLast.pNext = null;
if (a.pFirst == null) a.pFirst = a.pLast;
a.pLength += 1;
}
private void skipSeparators()
{
for(;;)
{
int c = peekNextCharacter();
switch (c)
{
case '(':
case ')':
case ';':
case '-':
case -1:
return;
default:
if (TextUtils.isDigit((char)c)) return;
getNextCharacter();
}
}
}
private int reportError()
{
switch (errorType)
{
case NUMTOOBIG: errorReport("number too large", FATALSYNTAX); break;
case NOUNSIGNED: errorReport("unsigned integer expected", FATALSYNTAX); break;
case NOSIGNED: errorReport("signed integer expected", FATALSYNTAX); break;
case NOSEMI: errorReport("missing ';' inserted", FATALSYNTAX); break;
case NOPATH: errorReport("no points in path", FATALSYNTAX); break;
case BADTRANS: errorReport("no such transformation command", FATALSYNTAX); break;
case BADUSER: errorReport("end of file inside user command", FATALSYNTAX); break;
case BADCOMMAND: errorReport("unknown command encountered", FATALSYNTAX); break;
case INTERNAL: errorReport("parser can't find i routine", FATALINTERNAL); break;
case BADDEF: errorReport("no such define command", FATALSYNTAX); break;
case NOLAYER: errorReport("layer name expected", FATALSYNTAX); break;
case BADCOMMENT: errorReport("end of file inside a comment", FATALSYNTAX); break;
case BADAXIS: errorReport("no such axis in mirror command", FATALSYNTAX); break;
case NESTDEF: errorReport("symbol definitions can't nest", FATALSYNTAX); break;
case NODEFSTART: errorReport("DF without DS", FATALSYNTAX); break;
case NESTDD: errorReport("DD can't appear inside symbol definition", FATALSYNTAX); break;
case NOSPACE: errorReport("missing space in name command", FATALSYNTAX); break;
case NONAME: errorReport("no name in name command", FATALSYNTAX); break;
case NESTEND: errorReport("End command inside symbol definition", FATALSYNTAX); break;
case NOERROR: errorReport("error signaled but not reported", FATALINTERNAL); break;
default: errorReport("uncaught error", FATALSYNTAX);
}
if (errorType != INTERNAL && errorType != NOSEMI && flushInput(';') < 0)
errorReport("unexpected end of input file", FATALSYNTAX);
else skipBlanks();
errorFound = false;
errorType = NOERROR;
return SYNTAXERROR;
}
private void errorReport(String mess, int kind)
{
if (charactersRead > 0)
{
System.out.println("line " + (lineReader.getLineNumber()+(resetInputBuffer?0:1)) + ": " + inputBuffer.toString());
}
if (kind == FATALINTERNAL || kind == FATALINTERNAL ||
kind == FATALSEMANTIC || kind == FATALOUTPUT) numFatalErrors++;
switch (kind)
{
case FATALINTERNAL: System.out.println("Fatal internal error: " + mess); break;
case FATALSYNTAX: System.out.println("Syntax error: " + mess); break;
case FATALSEMANTIC: System.out.println("Error: " + mess); break;
case FATALOUTPUT: System.out.println("Output error: " + mess); break;
case ADVISORY: System.out.println("Warning: " + mess); break;
default: System.out.println(mess); break;
}
}
}