ThymeBomb.mesa
Copyright (C) 1985 by Xerox Corporation. All rights reserved.
Last Edited by:
Christian LeCocq February 4, 1987 6:10:36 pm PST
Barth, November 12, 1986 3:35:20 pm PST
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],
ThymeGlobals 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],
ThymeGlobalsExtras USING [CombineInstancesProc, IsUsefulProc];
ThymeBomb: CEDAR PROGRAM
IMPORTS
Atom,
IO,
Rope,
ThymeGlobals
EXPORTS
ThymeGlobals
= BEGIN
OPEN ThymeGlobals;
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 ← 0.0;
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: ThymeGlobalsExtras.IsUsefulProc = NARROW[r, REF ThymeGlobalsExtras.IsUsefulProc]^;
IF ~ isUsefulProc[inst.parmVector] THEN RETURN[FALSE];
};
IF (r ← GetPropFromRef[proto.data, $CombineInstancesProc]) # NIL THEN {
combineInstancesProc: ThymeGlobalsExtras.CombineInstancesProc = NARROW[r, REF ThymeGlobalsExtras.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, cktRoot, gndNodeName: namePtr]= {
cktRootDetails: RefCircuitRec← NARROW[cktRoot.details];
handle.vars.treeRoot← NEW[instTreeNode← []];
PushCopies[cktRootDetails.names];
AdvanceLevel[cktRootDetails.names];
Explode[handle, cktRoot, handle.vars.treeRoot];
GetRealThing[handle, 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.
Barth, November 12, 1986 3:33:56 pm PST, in ExplodeBranch initialize brValue