File: [Cherry]<Thyme>Cedar5.2>System>spBomb.mesa
Last Edited by: SChen, May 17, 1985 6:22:36 pm PDT
DIRECTORY
Atom USING [GetPropFromList, PropList],
IO USING [int, PutF, rope],
Rope USING [Cat, Concat, Equal, Fetch, Length, ROPE],
RopeFrom USING [String],
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, RopeFrom, 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: BOOL ← TRUE ] = {
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 ANY ← NIL;
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:
BOOL←
FALSE]= {
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:
BOOL ←
FALSE]
RETURNS[r: Rope.ROPE ← NIL]= {
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:
BOOL ←
FALSE]
RETURNS[r: Rope.ROPE ← NIL]= {
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:
BOOL←
FALSE]
RETURNS[r: Rope.ROPE← NIL]= {
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:
BOOL←
TRUE]
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.ROPE ← IF 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, RopeFrom.String[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, RopeFrom.String[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, RopeFrom.String[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.