<> <> <> <> <> <> <<>> 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 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 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]= { <> 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]= { <> 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]= { <> 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: BOOL _ TRUE ] = { <> 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 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, 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