File: spBomb.mesa
Copyright (C) 1985 by Xerox Corporation. All rights reserved.
Last Edited by:
Sweetsun Chen, July 22, 1985 8:04:35 pm PDT
DIRECTORY
Atom USING [GetPropFromList, PropList],
IO USING [int, PutF, rope],
Rope USING [Cat, Concat, Equal, Fetch, FromRefText, Length, ROPE],
spGlobals USING[Aborted, argNames, branch, branchLink, branchLinkPtr, branchPtr, Canned, CapacitorBody, conLinkPtr, elements, error, error2, ErrorSignal, ErrorStrings, eval, expressionPtr, FunctionBody, Handle, HashKey, hashModulus, InductorBody, instTreeNode, instTreePtr, ISourceBody, modBrPtr, ModelArgHash, ModelBody, modelBranch, modFuncBlk, modFuncPtr, namePtr, next, node, nodePtr, nodePtrSeq, RealBranch, RealModel, RealNode, RealParm, realThingPtr, realThing, realThings, RefBranchRec, RefCircuitRec, RefCktInstRec, RefFunctionRec, RefModBody, RefModelRec, RefNodeRec, RefParmRec, refR, RefRealBranch, RefRealModel, RefRealNode, RefRealParm, RefUnReal, refUnReal, ValueSeq, VSourceBody],
spGlobalsExtras USING [CombineInstancesProc, IsUsefulProc];
spBomb: CEDAR PROGRAM
IMPORTS Atom, IO, Rope, spGlobals
EXPORTS spGlobals=
BEGIN OPEN spGlobals;
pushCopies: PROC[nameList: namePtr]= {
For each namePtr linked with the nameList, initialize its realCopy as follows:
if the namePtr points to a circuit, a circuit instance, a model or a function, its realCopy is assigned nil;
otherwise, allocate and initialize its realCopy as following:
the "nextThing" of the new realCopy is the original realCopy,
its "newLevel" is the default (TRUE),
its "thing" is unReal, unless the namePtr is a parameter name pointer with default, in which case "thing" points to the default value.
FOR nl: namePtr← nameList, nl.srchLink UNTIL nl = NIL DO
nl.realCopy← WITH nl.details SELECT FROM
x: RefCircuitRec => NIL,
x: RefCktInstRec => NIL,
x: RefFunctionRec => NIL,
p: RefParmRec => NEW[realThing← [
nextThing: nl.realCopy,
thing: IF p.default THEN NEW[RealParm← [rp: p.dfltValue]]
ELSE refUnReal] ],
ENDCASE => NEW[realThing← [
nextThing: nl.realCopy,
thing: refUnReal] ];
ENDLOOP;
}; -- pushCopies
advanceLevel: PROC[nameList: namePtr]= {
FOR nl: namePtr← nameList, nl.srchLink UNTIL nl = NIL DO
IF nl.realCopy # NIL THEN nl.realCopy.newLevel← FALSE;
ENDLOOP;
}; -- advanceLevel
popCopies: PROC[handle: Handle, nameList: namePtr]= {
For each namePtr linked with the nameList do the following:
If its details points to a circuit, a circuit instance, or a function, then do nothing;
otherwise, pop up its realCopy.nextThing as its realCopy;
If the original realCopy points to a nodePtr, then
if it has nonNIL branches then pop the nodePtr on the handle.vars.nodeList, with original handle.vars.nodeList as its nextNode, and increment handle.vars.nodeCount;
otherwise if its branches is nil then pop the nodePtr on top of handle.vars.unusedNodes with the original handle.vars.unusedNodes as its nextNode.
FOR nl: namePtr← nameList, nl.srchLink UNTIL nl = NIL DO
WITH nl.details SELECT FROM
x: RefCircuitRec => NULL;
x: RefCktInstRec => NULL;
x: RefFunctionRec => NULL;
n: RefNodeRec =>
WITH nl.realCopy.thing SELECT FROM
r: RefRealNode => {
IF r.rn.branches # NIL THEN {
handle.vars.nodeCount← handle.vars.nodeCount + 1;
r.rn.nextNode← handle.vars.nodeList;
handle.vars.nodeList← r.rn;
}
ELSE {
r.rn.nextNode← handle.vars.unusedNodes;
handle.vars.unusedNodes← r.rn;
};
nl.realCopy← nl.realCopy.nextThing;
};
ENDCASE => nl.realCopy← nl.realCopy.nextThing;
ENDCASE => nl.realCopy← nl.realCopy.nextThing;
ENDLOOP;
}; -- popCopies
getParmValue: PUBLIC PROC[handle: Handle, nPtr: namePtr] RETURNS[REAL]= {
ENABLE ErrorSignal => ErrorSignal[331, s];
getRealThing[handle, nPtr];
RETURN[IF handle.vars.n # NIL THEN LOOPHOLE[handle.vars.n] ELSE handle.vars.p]
-- *
}; -- getParmValue
getRealThing: PROC[handle: Handle, nPtr: namePtr]= {
Reset n,b,m,and p; If nPtr and its realCopy is not NIL then depending on the type of its realCopy (or the non-nil nextThing of its realCopy, if its realCopy.newLevel is TRUE), set n,b,m, or p accordingly; but if its realCopy (or the nextThing, see above) is NIL and nPtr.details.default then set p with the default.
rCopy: realThingPtr;
handle.vars.n← NIL; handle.vars.b← NIL; handle.vars.m← NIL; handle.vars.p← 0.0;
IF nPtr=NIL THEN RETURN;
rCopy← nPtr.realCopy;
IF rCopy # NIL THEN IF rCopy.newLevel THEN rCopy← rCopy.nextThing;
IF rCopy # NIL THEN
WITH rCopy.thing SELECT FROM
rt: RefRealNode => handle.vars.n← rt.rn;
rt: RefRealBranch => handle.vars.b← rt.rb;
rt: RefRealParm => handle.vars.p← rt.rp;
rt: RefRealModel => handle.vars.m← rt.rm;
rt: RefUnReal => ErrorSignal[330, nPtr.name];
ENDCASE
ELSE
WITH nPtr.details SELECT FROM
pn: RefParmRec =>
IF pn.default THEN handle.vars.p← pn.dfltValue ELSE ErrorSignal[331, nPtr.name];
ENDCASE => error2[handle, 390, nPtr];
}; -- getRealThing
putRealThing: PROC[handle: Handle, nPtr: namePtr, t: realThings]= {
Depending on the type of t, initialize nPtr.realCopy.thing to point to (the content of) n, b, p, or m.
rCopy: realThingPtr← nPtr.realCopy;
IF rCopy # NIL THEN
SELECT t FROM
realNode => rCopy.thing← NEW[RealNode← [rn: handle.vars.n]];
realBranch => rCopy.thing← NEW[RealBranch← [rb: handle.vars.b]];
realParm => rCopy.thing← NEW[RealParm← [rp: handle.vars.p]];
realModel => rCopy.thing← NEW[RealModel← [rm: handle.vars.m]];
ENDCASE;
}; -- putRealThing
putParmValue: PUBLIC PROC[handle: Handle, nPtr: namePtr, val: REAL]= {
handle.vars.p← val;
putRealThing[handle, nPtr, realParm];
}; -- putParmValue
makeConnections: PROC[handle: Handle, connections: conLinkPtr, fakes: namePtr]= {
For each connection linked with connections, set n to its namedNode.realCopy.thing.rn; let fakes.realCopy.thing point to n, then proceed similarly (for connection.nextLink with fakes.nextName, and so on).
UNTIL fakes=NIL DO
getRealThing[handle, connections.namedNode];
putRealThing[handle, fakes, realNode];
fakes← fakes.nextName;
connections← connections.nextLink;
ENDLOOP;
}; -- makeConnections
apply: PROC[handle: Handle, apList: expressionPtr]= {
FOR ex: expressionPtr ← apList, ex.next UNTIL ex=NIL DO
[]← eval[handle, ex];
ENDLOOP;
}; -- apply
explodeInstance: PROC[handle: Handle, instNamePtr: namePtr] RETURNS[t: instTreePtr]= {
inst: RefCktInstRec← NARROW[instNamePtr.details];
ckt: namePtr← NARROW[inst.of];
cktDetails: RefCircuitRec← NARROW[ckt.details];
pushCopies[cktDetails.names];
makeConnections[handle, inst.connections, cktDetails.fakeNodes];
apply[handle, inst.actualParms];
advanceLevel[cktDetails.names];
t← NEW[instTreeNode← [instance: instNamePtr] ];
FOR exp: expressionPtr ← cktDetails.assertions, exp.next UNTIL exp=NIL DO
IF eval[handle, exp]=0.0 THEN error2[handle, 341, instNamePtr];
ENDLOOP;
explode[handle, ckt, t];
popCopies[handle, cktDetails.names];
}; -- explodeInstance
explodeModelFunc: PROC[handle: Handle, mfNamePtr: namePtr, newFunc: modFuncPtr]= {
index: NAT;
arguments: argNames;
parms: expressionPtr;
data: REF ANY;
WITH mfNamePtr.details SELECT FROM
m: RefModelRec => {
newFunc.argVector← m.modelArgVec;
arguments← m.modelArgs;
parms← m.modelParms;
data ← m.data;
};
f: RefFunctionRec => {
newFunc.argVector← f.funcArgVec;
arguments← f.funcArgs;
parms← f.funcParms;
data ← f.data;
};
ENDCASE => error2[handle, 399, mfNamePtr];
IF arguments # NIL THEN {
newFunc.arguments← NEW[nodePtrSeq[arguments.size]];
newFunc.arguments.visited ← FALSE;
FOR index IN [0..arguments.size) DO
IF arguments[index] # NIL THEN getRealThing[handle, arguments[index]];
newFunc.arguments[index]← handle.vars.n;
ENDLOOP;
};
index← 0;
FOR p: expressionPtr← parms, p.next UNTIL p=NIL DO index← index + 1; ENDLOOP;
newFunc.parmVector← NEW[ValueSeq[index]];
newFunc.parmVector.visited ← FALSE;
newFunc.parmVector.handle ← handle;
newFunc.parmVector.modFunc ← newFunc;
.. so the model or function can know its environment in case of error
initialize each parameter of newFunc
UNTIL index=0 DO
index← index - 1;
newFunc.parmVector[index]← eval[handle, parms];
parms← parms.next;
ENDLOOP;
}; -- explodeModelFunc
explodeController: PROC[handle: Handle, branchNamePtr: namePtr, newB: branchPtr]= {
brDetails: RefBranchRec← NARROW[branchNamePtr.details];
oldmf: namePtr← brDetails.controller;
newFunc: modFuncPtr;
newModB: modBrPtr;
WITH oldmf.details SELECT FROM
fcn: RefFunctionRec => {
handle.vars.funcCount← handle.vars.funcCount + 1;
newFunc← NEW[modFuncBlk← [
nextMFPtr: handle.vars.functionList,
body: NEW[FunctionBody← [functionProc: fcn.functionProc, branch: newB]]
]];
handle.vars.functionList← newFunc; -- *
explodeModelFunc[handle, oldmf, newFunc];
newB.controller← newFunc;
};
mod: RefModelRec => {
mBody: RefModBody;
getRealThing[handle, oldmf];
mBody← NARROW[handle.vars.m.body];
newModB← NEW[modelBranch← [nextBranch: mBody.modelBranches, b: newB]];
mBody.modelBranches← newModB;
newB.controller← handle.vars.m;
newB.modelIndex← brDetails.modelIndex;
};
ENDCASE => error2[handle, 399, branchNamePtr];
}; -- explodeController
connectBranch: PROC[n: nodePtr, b: branchPtr, pos: BOOL]= {
IF n # NIL THEN {
n.branches← NEW[branchLink← [nextLink: n.branches, branch: b, pos: pos]];
IF pos THEN b.posNode← n ELSE b.negNode← n;
}
ELSE ErrorSignal[242, b.branchName.name];
}; -- connectBranch
explodeBranch: PROC[handle: Handle, branchNamePtr: namePtr]
RETURNS[newB: branchPtr← NIL]= {
pNode, nNode: nodePtr;
newC, newL, newV, newI: branchPtr;
brDetails: RefBranchRec← NARROW[branchNamePtr.details];
brValue: REAL;
ParallelsExistingBranch: PROC [branchType: elements] RETURNS [BOOL] = {
IF NOT (Rope.Fetch[branchNamePtr.name, 0] = '? -- anonymous
AND brDetails.controller = NIL -- constant value
) THEN RETURN[FALSE]; -- can't add this one to any other
IF brValue = 0 THEN RETURN[TRUE]; -- throw this one away
FOR list: REF branchLink ← pNode.branches, list.nextLink WHILE list # NIL DO
details: REF ANY;
branchName: namePtr;
otherBranch: branchPtr = list.branch;
IF otherBranch.negNode = nNode -- same connections
AND ISTYPE[(details ← (branchName ← otherBranch.branchName).details), RefBranchRec]
AND NARROW[details, RefBranchRec].branchType = branchType -- same branch type
AND Rope.Fetch[branchName.name, 0] = '? -- also anonymous
AND otherBranch.controller = NIL -- constant value
THEN {
otherBranch.comVal ← otherBranch.comVal+eval[handle, brDetails.valExpr];
RETURN[TRUE];
};
ENDLOOP;
RETURN[FALSE];
};
handle.vars.branchCount← handle.vars.branchCount + 1;
getRealThing[handle, brDetails.posNode];
pNode← handle.vars.n;
getRealThing[handle, brDetails.negNode];
nNode← handle.vars.n;
SELECT TRUE FROM
brDetails.controller = NIL => brValue ← eval[handle, brDetails.valExpr];
ENDCASE =>
WITH brDetails.controller.details SELECT FROM
mod: RefModelRec => {
getRealThing[handle, brDetails.controller];
IF handle.vars.m.body = $useless THEN RETURN;
};
ENDCASE => NULL;
IF pNode # nNode THEN {
SELECT brDetails.branchType FROM
resistor => newB← NEW[branch← [body: refR]];
capacitor=> {
IF ParallelsExistingBranch[capacitor] THEN RETURN;
newB← newC← NEW[branch←
[body: NEW[CapacitorBody← [nextCapacitor: handle.vars.capacitorList]] ] ];
handle.vars.capacitorList← newC;
};
inductor => {
newB← newL← NEW[branch←
[body: NEW[InductorBody← [nextInductor: handle.vars.inductorList ]] ] ];
handle.vars.inductorList← newL;
};
vSource => {
newB← newV← NEW[branch←
[body: NEW[VSourceBody← [nextvSource: handle.vars.vSourceList ]] ] ];
handle.vars.vSourceList← newV;
};
iSource => {
IF ParallelsExistingBranch[iSource] THEN RETURN;
newB← newI← NEW[branch←
[body: NEW[ISourceBody← [nextiSource: handle.vars.iSourceList ]] ] ];
handle.vars.iSourceList← newI;
};
ENDCASE => error2[handle, 391, branchNamePtr];
handle.vars.b← newB;
putRealThing[handle, branchNamePtr, realBranch];
newB.branchName← branchNamePtr;
newB.comVal← brValue;
newB.posNode ← pNode;
newB.negNode ← nNode;
IF brDetails.controller # NIL THEN
explodeController[handle, branchNamePtr, newB];
connectBranch[pNode, newB, TRUE];
connectBranch[nNode, newB, FALSE];
};
}; -- explodeBranch
explode: PROC[handle: Handle, ckt: namePtr, tree: instTreePtr]= {
curName: namePtr;
newModel: modFuncPtr;
newB: branchPtr;
newTree: instTreePtr;
cktDetails: RefCircuitRec← NARROW[ckt.details];
IF Canned[handle] THEN SIGNAL Aborted;
FOR curName← cktDetails.names, curName.srchLink UNTIL curName=NIL DO
WITH curName.details SELECT FROM
x: RefNodeRec => {
handle.vars.n← tree.nodes← NEW[node← [
nodeName: curName,
treeLevel: tree,
brotherNodes: tree.nodes] ];
putRealThing[handle, curName, realNode];
};
ENDCASE;
ENDLOOP;
FOR curName← cktDetails.names, curName.srchLink UNTIL curName=NIL DO
ENABLE ErrorSignal => {
ErrorStrings[handle, error, treeError[handle, tree, curName], s];
LOOP;
};
WITH curName.details SELECT FROM
rm: RefModelRec => {
handle.vars.modelCount← handle.vars.modelCount + 1;
newModel← NEW[modFuncBlk← [
nextMFPtr: handle.vars.functionList,
body: NEW[ModelBody←
[modelProc: rm.modelProc,
modelResults: rm.modelResults,
modelName: curName,
oldArgVector: rm.modelOldArgVec]]
]];
handle.vars.functionList← newModel;
explodeModelFunc[handle, curName, newModel];
IF ModelInstanceUseful[handle, rm, newModel] THEN {
IF GetPropFromRef[rm.data, $CombineInstancesProc] # NIL THEN { -- register this instance for comparing with future ones
key: HashKey = HashArgs[newModel];
IF handle.vars.modelArgs = NIL THEN
handle.vars.modelArgs ← NEW[ModelArgHash ← ALL[NIL]];
handle.vars.modelArgs[key] ← CONS[newModel, handle.vars.modelArgs[key]];
};
}
ELSE newModel.body ← $useless;
handle.vars.m← newModel;
putRealThing[handle, curName, realModel];
};
ENDCASE;
ENDLOOP;
FOR curName← cktDetails.names, curName.srchLink UNTIL curName=NIL DO
ENABLE ErrorSignal => {
ErrorStrings[handle, error, treeError[handle, tree, curName], s];
LOOP;
};
WITH curName.details SELECT FROM
x: RefBranchRec => {
newB← explodeBranch[handle, curName];
IF newB # NIL THEN {
newB.brotherBranches← tree.branches;
newB.treeLevel← tree;
tree.branches← newB;
};
};
x: RefCktInstRec => {
newTree← explodeInstance[handle, curName];
newTree.father← tree;
newTree.brothers← tree.sons;
tree.sons← newTree;
};
ENDCASE;
ENDLOOP;
}; -- explode
ModelInstanceUseful: PROC [ handle: Handle, proto: RefModelRec, inst: modFuncPtr ]
RETURNS [ useful: BOOLTRUE ] = {
See whether this model instance non-trivial and cannot be combined with another
r: REF ANY;
IF (r ← GetPropFromRef[proto.data, $IsUsefulProc]) # NIL THEN {
isUsefulProc: spGlobalsExtras.IsUsefulProc =
NARROW[r, REF spGlobalsExtras.IsUsefulProc]^;
IF ~ isUsefulProc[inst.parmVector] THEN RETURN[FALSE];
};
IF (r ← GetPropFromRef[proto.data, $CombineInstancesProc]) # NIL THEN {
combineInstancesProc: spGlobalsExtras.CombineInstancesProc =
NARROW[r, REF spGlobalsExtras.CombineInstancesProc]^;
match: modFuncPtr = FindMatchingModelInstance[handle, inst];
IF match # NIL
AND combineInstancesProc[parmsA: match.parmVector, parmsB: inst.parmVector]
THEN RETURN[FALSE];
};
};
GetPropFromRef: PROC [ propList, prop: REF ANY ] RETURNS [ val: REF ANY ] = {
WITH propList SELECT FROM
pl: Atom.PropList => val ← Atom.GetPropFromList[pl, prop];
ENDCASE => val ← NIL;
};
HashArgs: PROC [ model: modFuncPtr ] RETURNS [ key: HashKey ] = {
sum: INT ← 0;
FOR i: NAT IN [0..model.arguments.size) DO
TRUSTED {sum ← sum+LOOPHOLE[model.arguments[i], INT]};
ENDLOOP;
IF sum < 0 THEN sum ← -sum;
key ← sum MOD hashModulus;
};
FindMatchingModelInstance: PROC [ handle: Handle, inst: modFuncPtr ] RETURNS [ match: modFuncPtr ← NIL ] = {
key: HashKey = HashArgs[inst];
prevList: LIST OF REF ANYNIL;
IF handle.vars.modelArgs = NIL THEN handle.vars.modelArgs ←
NEW[ModelArgHash ← ALL[NIL]];
FOR list: LIST OF REF ANY ← handle.vars.modelArgs[key], list.rest WHILE list#NIL
DO
{
WITH list.first SELECT FROM
mf: modFuncPtr => { -- matches if arguments are the same and model name is the same.
IF inst.arguments.size # mf.arguments.size THEN GOTO Mismatch;
FOR i: NAT IN [0..inst.arguments.size) DO
IF inst.arguments[i] # mf.arguments[i] THEN GOTO Mismatch;
ENDLOOP;
WITH mf.body SELECT FROM
mb: RefModBody =>
WITH inst.body SELECT FROM
nfb: RefModBody =>
IF mb.modelName # nfb.modelName THEN GOTO Mismatch;
ENDCASE => GOTO Mismatch;
ENDCASE => GOTO Mismatch;
IF prevList # NIL THEN { -- there's a match, move it to the front
prevList.rest ← list.rest;
list.rest ← handle.vars.modelArgs[key];
handle.vars.modelArgs[key] ← list;
};
RETURN[match: mf];
};
ENDCASE => NULL;
EXITS Mismatch => NULL
};
prevList ← list;
ENDLOOP;
}; -- end of FindMatchingModelInstance
treeError: PROC[handle: Handle, t: instTreePtr, n: namePtr] RETURNS[Rope.ROPE]= {
RETURN[Rope.Concat[printTree[handle, t, TRUE], n.name]];
}; -- treeError
AlphaNumeric: PROC[name: Rope.ROPE] RETURNS[an: BOOLFALSE]= {
tChar: CHAR← Rope.Fetch[name, 0];
an← tChar IN ['a..'z] OR tChar IN ['A..'Z]; -- first char should not be numeric
IF an THEN
FOR i: INT IN [1..Rope.Length[name]) DO
tChar← Rope.Fetch[name, i];
an← tChar IN ['a..'z] OR tChar IN ['A..'Z] OR tChar IN ['0..'9];
IF ~an THEN RETURN;
ENDLOOP;
}; -- AlphaNumeric
printTree: PROC[handle: Handle, t: instTreePtr, toRope: BOOLFALSE]
RETURNS[r: Rope.ROPENIL]= {
IF t # NIL AND t # handle.vars.treeRoot THEN {
tName: Rope.ROPE ← t.instance.name;
r ← printTree[handle, t.father, toRope].Concat[
IF AlphaNumeric[tName] THEN tName.Concat["/"] ELSE Rope.Cat["$", tName, "$/"] ];
};
IF toRope THEN RETURN ELSE {
handle.msgStream.PutF["%g", IO.rope[r]];
r ← NIL;
};
}; -- printTree
printNode: PROC[handle: Handle, n: nodePtr, ok, toRope: BOOLFALSE]
RETURNS[r: Rope.ROPENIL]= {
nName: Rope.ROPE ← n.nodeName.name;
r← printTree[handle, n.treeLevel, toRope].Concat[
IF ok OR AlphaNumeric[nName] THEN nName ELSE Rope.Cat["$", nName, "$"]
];
IF NOT toRope THEN {
handle.msgStream.PutF["%g", IO.rope[r]];
r ← NIL;
};
}; -- printNode
printBranch: PROC[handle: Handle, b: branchPtr, ok, toRope: BOOLFALSE]
RETURNS[r: Rope.ROPENIL]= {
bName: Rope.ROPE ← b.branchName.name;
r← printTree[handle, b.treeLevel, toRope].Concat[
IF ok OR AlphaNumeric[bName] THEN bName ELSE Rope.Cat["$", bName, "$"]
];
IF NOT toRope THEN {
handle.msgStream.PutF["%g", IO.rope[r]];
r ← NIL;
};
}; -- printBranch
makeStringNB: PUBLIC PROC[handle: Handle, n: nodePtr, b: branchPtr, ok: BOOLTRUE]
RETURNS[Rope.ROPE]= { -- NB: Node/Branch; ok: non-alphanumeric chars allowed.
RETURN[IF n # NIL
THEN printNode[handle, n, ok, TRUE]
ELSE printBranch[handle, b, ok, TRUE]
];
}; -- makeStringNB
printTreeWithCktNames: PROC[handle: Handle, t: instTreePtr] = {
IF t = NIL OR t = handle.vars.treeRoot THEN handle.msgStream.PutF["\t"]
ELSE {
tInstDetails: RefCktInstRec ← IF ISTYPE[t.instance.details, RefCktInstRec] THEN NARROW[t.instance.details] ELSE NIL;
cktName: Rope.ROPEIF tInstDetails # NIL THEN tInstDetails.of.name ELSE NIL;
printTreeWithCktNames[handle, t.father];
handle.msgStream.PutF["%g(%g)/", IO.rope[t.instance.name], IO.rope[cktName]];
};
}; -- printTreeWithCktNames
printUnusedNodes: PROC[handle: Handle, n: nodePtr] = {
FOR n: nodePtr ← handle.vars.unusedNodes, n.nextNode UNTIL n=NIL DO
nName: Rope.ROPE ← n.nodeName.name;
printTreeWithCktNames[handle, n.treeLevel];
handle.msgStream.PutF["%g", IO.rope[n.nodeName.name]];
handle.msgStream.PutF[IF n.nextNode = NIL THEN ".\n\n" ELSE ",\n"];
ENDLOOP;
}; -- printUnusedNodes
printHole: PUBLIC PROC[handle: Handle]= {
handle.msgStream.PutF["\nNodes --\n"];
FOR n: nodePtr← handle.vars.nodeList, n.nextNode UNTIL n=NIL DO
[]← printNode[handle, n, TRUE];
handle.msgStream.PutF["← {"];
FOR bLink: branchLinkPtr← n.branches, bLink.nextLink UNTIL bLink=NIL DO
[]← printBranch[handle, bLink.branch, TRUE];
IF bLink.branch.posNode=n THEN handle.msgStream.PutF["+"]
ELSE handle.msgStream.PutF["-"];
IF bLink.nextLink # NIL THEN handle.msgStream.PutF[", "];
ENDLOOP;
handle.msgStream.PutF["}.\n"];
ENDLOOP;
}; -- printHole
findNB: PROC[handle: Handle, tree: instTreePtr] RETURNS[n: nodePtr← NIL, b: branchPtr← NIL]= {
IF handle.vars.item=name THEN {
i: instTreePtr;
FOR i← tree.sons, i.brothers UNTIL i=NIL DO
IF Rope.Equal[i.instance.name, Rope.FromRefText[handle.vars.newString]] THEN EXIT;
ENDLOOP;
IF i # NIL THEN {
next[handle];
IF handle.vars.item=slash THEN next[handle]
ELSE error[handle, 300, FALSE];
[n, b]← findNB[handle, i];
}
ELSE {
FOR n← tree.nodes, n.brotherNodes UNTIL n=NIL DO
IF Rope.Equal[n.nodeName.name, Rope.FromRefText[handle.vars.newString]] THEN EXIT;
ENDLOOP;
IF n=NIL THEN FOR b← tree.branches, b.brotherBranches UNTIL b=NIL DO
IF Rope.Equal[b.branchName.name, Rope.FromRefText[handle.vars.newString]] THEN EXIT;
ENDLOOP;
next[handle];
};
}
ELSE error[handle, 301, FALSE];
}; -- findNB
findNodeOrBranch: PUBLIC PROC[handle: Handle] RETURNS[n: nodePtr, b: branchPtr]= {
[n, b]← findNB[handle, handle.vars.treeRoot];
}; -- findNodeOrBranch
fillInBranchLinks: PROC[handle: Handle]= {
FOR nodes: nodePtr← handle.vars.nodeList, nodes.nextNode UNTIL nodes=NIL DO
FOR links: branchLinkPtr← nodes.branches, links.nextLink UNTIL links=NIL DO
links.otherNode← IF links.pos THEN links.branch.negNode ELSE links.branch.posNode;
ENDLOOP;
ENDLOOP;
}; -- fillInBranchLinks
bomb: PUBLIC PROC[handle: Handle]= {
cktRootDetails: RefCircuitRec← NARROW[handle.vars.cktRoot.details];
handle.vars.treeRoot← NEW[instTreeNode← []];
pushCopies[cktRootDetails.names];
advanceLevel[cktRootDetails.names];
explode[handle, handle.vars.cktRoot, handle.vars.treeRoot];
getRealThing[handle, handle.vars.gndNodeName];
handle.vars.gndNode← handle.vars.n;
popCopies[handle, cktRootDetails.names];
fillInBranchLinks[handle];
handle.msgStream.PutF[
"\n\nTotal %g nodes, %g models, %g functions, and %g branches.\n\n",
IO.int[handle.vars.nodeCount],
IO.int[handle.vars.modelCount],
IO.int[handle.vars.funcCount],
IO.int[handle.vars.branchCount]];
IF handle.vars.unusedNodes # NIL THEN {
handle.msgStream.PutF["Unused nodes:\n"];
printUnusedNodes[handle, handle.vars.unusedNodes];
};
}; -- bomb
END.
CHANGE LOG
Wilhelm, March 16, 1982 9:41 AM
Barth, 7-May-82 10:48:59 PDT
Chen, February 12, 1984 7:50 PM, modified to support oldArgVector.
Chen, June 10, 1984 9:47:59 pm PDT, cedarized.
McCreight, April 2, 1985 3:41:00 pm PST.
Chen, July 22, 1985 7:56:50 pm PDT, => Cedar6.0.