lastNamePtr: namePtr;
oldDetails: RefCircuitRec;
nameRope: Rope.
ROPE← Rope.FromRefText[nameString];
UNTIL oldCktNames=
NIL
DO
oldDetails←
NARROW[oldCktNames.details];
newCktNames← oldDetails.names;
lastNamePtr←
NIL;
UNTIL newCktNames=
NIL
DO
IF Rope.Equal[nameRope, newCktNames.name]
THEN
GOTO found;
lastNamePtr← newCktNames;
newCktNames← newCktNames.srchLink;
ENDLOOP;
IF level=oneLevel
THEN
EXIT;
oldCktNames← oldDetails.father;
REPEAT
found =>
-- Move the matching entry to the front of the search list for the circuit.
IF lastNamePtr #
NIL
THEN {
lastNamePtr.srchLink← newCktNames.srchLink;
newCktNames.srchLink← oldDetails.names;
oldDetails.names← newCktNames;
};
ENDLOOP;
};
-- searchName
getNames:
PROC[handle: Handle]
RETURNS[names: namePtr←
NIL, nameCount:
NAT← 0]= {
-- enter (unique) name strings on the current circuits search link
nPtr: namePtr;
UNTIL handle.vars.item # name
DO
nPtr← enterName[handle];
IF nPtr #
NIL
THEN {
-- usually not nil
nPtr.nextName← names;
names← nPtr;
};
nameCount← nameCount + 1;
next[handle];
IF handle.vars.item # comma
THEN
EXIT
ELSE next[handle];
IF handle.vars.item # name
THEN error[handle, 208]
ENDLOOP
};
-- getNames
getName:
PROC[handle: Handle]
RETURNS[nPtr: namePtr←
NIL]= {
OPEN handle.vars;
IF item # name
THEN error[handle, 208]
ELSE nPtr← searchName[newString, allLevels, currentCkt];
IF nPtr=
NIL
THEN error[handle, 251];
next[handle];
};
-- getName
variable:
PUBLIC
PROC[handle: Handle,
string:
REF
TEXT,
-- often newString
context: namePtr]
RETURNS[nPtr: namePtr←
NIL]= {
nPtr←
IF context #
NIL
THEN searchName[string, oneLevel, context]
ELSE searchName[string, allLevels, handle.vars.currentCkt];
IF nPtr=
NIL
THEN error[handle, 252]
ELSE
-- check if nPtr has an acceptable type
WITH nPtr.details
SELECT
FROM
x: RefParmRec =>
NULL;
x: RefNodeRec =>
NULL;
x: RefConRec =>
NULL;
ENDCASE => error[handle, 221];
next[handle];
};
-- variable
findNode:
PROC[handle: Handle]
RETURNS[n: namePtr]= {
-- search RefNodeRec or RefConRec with name newString on all levels of currentCkt
nPtr: namePtr← getName[handle];
IF nPtr=
NIL
THEN
RETURN[handle.vars.undefNode]
ELSE
WITH nPtr.details
SELECT
FROM
x: RefNodeRec => n← nPtr;
x: RefConRec => n← nPtr;
ENDCASE => error[handle, 222];
};
-- findNode
getFunction:
PROC[handle: Handle, na, np:
NAT]
RETURNS[args: argNames←
NIL, actual: expressionPtr←
NIL]= {
-- get na arguments and np parameters(expressions)
iArg, iParm:
NAT← 0;
aname: namePtr;
newExpr: expressionPtr;
IF handle.vars.item=leftB
THEN {
next[handle];
-- arguments
IF na > 0
THEN {
args←
NEW[namePtrSeq[na]];
UNTIL iArg=na
DO
aname ← getName[handle];
args[iArg]← aname;
IF aname #
NIL
THEN
WITH aname.details
SELECT
FROM
x: RefNodeRec =>
NULL;
x: RefConRec =>
NULL;
ENDCASE => error[handle, 222];
IF handle.vars.item=quote
THEN {next[handle]; error[handle, 299]};
iArg← iArg + 1;
IF handle.vars.item=comma
THEN next[handle]
ELSE
EXIT;
ENDLOOP;
};
-- parameters
IF na=0
OR handle.vars.item=vertical
THEN {
IF handle.vars.item=vertical
THEN next[handle];
UNTIL iParm=np
DO
newExpr← expression[handle];
newExpr.next← actual;
actual← newExpr;
iParm← iParm + 1;
IF handle.vars.item=comma
THEN next[handle]
ELSE
EXIT;
ENDLOOP;
};
IF handle.vars.item=rightB
THEN next[handle]
ELSE error[handle, 202, ,
TRUE];
};
IF iArg # na
THEN error[handle, 231];
IF iParm # np
THEN error[handle, 232];
};
-- getFunction
controlFunc:
PROC[handle: Handle, thisBranch: namePtr]= {
nPtr: namePtr;
f: namePtr;
na, np:
NAT;
bDetails: RefBranchRec←
NARROW[thisBranch.details];
next[handle];
IF handle.vars.item=name
THEN {
nPtr← searchName[handle.vars.newString, allLevels, handle.vars.currentCkt];
IF nPtr=
NIL
THEN {
fDetails: RefFunctionRec←
NEW[FunctionRec← [branch: thisBranch] ];
f←
NEW[nameBlk← [details: fDetails]];
-- get values for other fields in f.details, and assign f as the controller for this branch:
[fDetails.functionProc, na, np]←
findFunction[Rope.FromRefText[handle.vars.newString]];
IF fDetails.functionProc=
NIL
THEN error[handle, 502,
FALSE];
next[handle];
bDetails.controller← f;
[fDetails.funcArgs, fDetails.funcParms]← getFunction[handle, na, np];
fDetails.funcArgVec←
NEW[ValueSeq[na]];
}
ELSE
WITH nPtr.details
SELECT
FROM
n: RefModelRec => {
bDetails.controller← nPtr;
next[handle];
IF handle.vars.item=leftB
THEN next[handle]
ELSE error[handle, 201,,
TRUE];
IF handle.vars.item=number
THEN {
bDetails.modelIndex← Real.FixC[handle.vars.value];
IF n.modelResults=
NIL
THEN {
-- unlikely, though
IF handle.vars.value > 0
THEN error[handle, 233]}
ELSE
IF handle.vars.value >= n.modelResults.size
THEN error[handle, 233];
next[handle];
}
ELSE error[handle, 209];
IF handle.vars.item=rightB
THEN next[handle]
ELSE error[handle, 202,,
TRUE];
};
ENDCASE => error[handle, 223];
}
ELSE error[handle, 208];
};
-- controlFunc
enterBranches:
PROC[handle: Handle, bName: namePtr, branchKey: keys]= {
pNode, nNode: namePtr;
bDetails: RefBranchRec;
kind: elements;
IF handle.vars.item=leftB
THEN next[handle]
ELSE error[handle, 201,,
TRUE];
pNode← findNode[handle];
IF handle.vars.item=comma
THEN next[handle]
ELSE error[handle, 200,,
TRUE];
nNode← findNode[handle];
IF handle.vars.item=rightB
THEN next[handle]
ELSE error[handle, 202,,
TRUE];
kind←
SELECT branchKey
FROM
resKey => resistor,
capKey => capacitor,
indKey => inductor,
vsKey => vSource,
isKey => iSource,
ENDCASE => nullElement;
IF kind=nullElement
THEN error[handle, 224,
TRUE];
IF pNode=nNode
THEN error[handle, 241];
IF bName #
NIL
THEN
-- else error! ...
bName.details← bDetails←
NEW[BranchRec← [branchType: kind,
posNode: pNode,
negNode: nNode ] ];
IF handle.vars.item=equal
THEN {
next[handle];
bDetails.valExpr← expression[handle];
}
ELSE
IF handle.vars.item=leftArrow
THEN controlFunc[handle, bName]
ELSE error[handle, 205];
};
-- enterBranches
enterModel:
PROC[handle: Handle, mName: namePtr]= {
na, np, nr:
NAT;
IF handle.vars.item=leftArrow
THEN next[handle]
ELSE error[handle, 210];
IF handle.vars.item=name
THEN {
mDetails: RefModelRec←
NEW[ModelRec← []];
[mDetails.modelProc, na, np, nr]←
findModel[Rope.FromRefText[handle.vars.newString]];
IF mDetails.modelProc=
NIL
THEN error[handle, 501,
FALSE];
next[handle];
[mDetails.modelArgs, mDetails.modelParms]← getFunction[handle, na, np];
mDetails.modelResults←
NEW[spGlobals.ValueSeq[nr]];
mDetails.modelArgVec ←
NEW[spGlobals.ValueSeq[na]];
mDetails.modelOldArgVec ←
NEW[spGlobals.ValueSeq[na]];
mName.details← mDetails;
}
ELSE error[handle, 208];
};
-- enterModel
GetCircuitTree:
PROC[ckt: namePtr]
RETURNS[r: Rope.
ROPE]= {
GetTree:
PROC[c: namePtr]= {
cktDetail: RefCircuitRec←
NARROW[c.details];
IF c #
NIL
AND cktDetail #
NIL
AND cktDetail.father #
NIL
THEN {
GetTree[cktDetail.father];
r← Rope.Cat[r, c.name, "."];
};
};
-- GetTree
GetTree[ckt];
};
-- GetCircuitTree
getNewParameters:
PROC[handle: Handle]
RETURNS[plist: namePtr←
NIL]= {
n: namePtr;
nparms:
NAT← 0;
IF handle.vars.item=vertical
THEN next[handle];
UNTIL handle.vars.item # name
DO
n← enterName[handle];
next[handle];
nparms← nparms + 1;
n.details←
NEW[ParmRec← [nextParm: plist]];
IF handle.vars.item=leftArrow
THEN {
ENABLE ErrorSignal => {
ErrorStrings[handle, error, GetCircuitTree[handle.vars.currentCkt], s];
CONTINUE;
-- GOTO badEnd
};
nDetails: RefParmRec ←
NARROW[n.details];
next[handle];
nDetails.default ←
TRUE;
nDetails.dfltValue ← eval[handle, expression[handle]];
};
plist← n;
IF handle.vars.item=comma
THEN next[handle]
ELSE
EXIT;
IF handle.vars.item # name
THEN error[handle, 208]
ENDLOOP;
};
-- getNewParameters
defineCircuit:
PUBLIC
PROC[handle: Handle, ckt: namePtr, root:
BOOL]= {
OPEN handle.vars;
exp: expressionPtr;
curCktDetails: RefCircuitRec←
NEW[CircuitRec← [father: currentCkt]];
IF Canned[handle]
THEN
SIGNAL Aborted;
ckt.details← curCktDetails;
currentCkt← ckt;
IF root
AND cktRoot=
NIL
THEN {
cktRoot← currentCkt;
undefNode←
NEW[nameBlk← [name: "Undefined",
details:
NEW[NodeRec] ] ];
gndNodeName←
NEW[nameBlk← [name: "Gnd",
details:
NEW[NodeRec] ] ];
curCktDetails.names← gndNodeName;
next[handle];
};
IF item=leftB
THEN {
next[handle];
IF ~root
AND item # vertical
THEN {
-- enter (uniquie) connection names on currentCkt
fakes: namePtr;
[fakes, curCktDetails.conCount]← getNames[handle];
curCktDetails.fakeNodes← fakes;
FOR fn: namePtr← fakes, fn.nextName
UNTIL fn=
NIL
DO
fn.details←
NEW[ConRec];
ENDLOOP;
};
IF root
OR item=vertical
THEN
curCktDetails.parms← getNewParameters[handle];
IF item=rightB
THEN next[handle]
ELSE error[handle, 202,,
TRUE];
};
IF item=name
AND searchKey[handle]=assertsKey
THEN {
next[handle];
IF item=leftB
THEN {
next[handle];
DO
exp← expression[handle];
exp.next← curCktDetails.assertions;
curCktDetails.assertions← exp;
IF item=comma
THEN next[handle]
ELSE
EXIT;
ENDLOOP;
IF item=rightB
THEN next[handle]
ELSE error[handle, 202,,
TRUE];
}
ELSE error[handle, 201];
};
IF item=equal
THEN next[handle]
ELSE error[handle, 205,
TRUE,
TRUE];
IF item=leftC
THEN next[handle]
ELSE error[handle, 203,
TRUE,
FALSE];
DO
IF item=name
THEN enterDefinition[handle];
IF item=rightC
OR item= eof
THEN
EXIT;
IF item=semi
THEN next[handle]
ELSE error[handle, 206,
TRUE,
FALSE];
ENDLOOP;
curCktDetails←
NARROW[currentCkt.details];
currentCkt← curCktDetails.father;
next[handle];
};
-- defineCircuit
getActualParameters:
PROC[handle: Handle, ckt: namePtr]
RETURNS[apList: expressionPtr←
NIL]= {
e: expressionPtr;
IF handle.vars.item=vertical
THEN next[handle];
IF handle.vars.item=rightB
OR handle.vars.item = semi
THEN
RETURN;
DO
IF handle.vars.item # name
THEN
GOTO nameErr;
e← assignExpr[handle, ckt];
e.next← apList;
apList← e;
IF handle.vars.item=comma
THEN next[handle]
ELSE
EXIT;
REPEAT
nameErr => error[handle, 208];
ENDLOOP;
};
-- getActualParameters
getAttributes:
PROC[handle: Handle]
RETURNS[attList: attPtr ←
NIL] = {
IF handle.vars.item = semi THEN next[handle];
IF handle.vars.item = rightB THEN RETURN;
DO
a: attPtr ← NEW[attribute];
IF handle.vars.item # name THEN GOTO nameErr;
a.name ← Rope.FromRefText[handle.vars.newString];
next[handle];
IF handle.vars.item # leftArrow THEN error[handle, 210]
ELSE {
next[handle];
IF handle.vars.item # name THEN error[handle, 208]
ELSE {
a.value ← Rope.FromRefText[handle.vars.newString];
a.next ← attList;
attList ← a;
next[handle];
};
};
IF handle.vars.item = comma THEN next[handle] ELSE EXIT;
REPEAT
nameErr => error[handle,208];
ENDLOOP;
};
defCktInstance: PROC[handle: Handle, cn: REF TEXT, iName: namePtr]= {
cktName: namePtr;
n: namePtr;
cons: conLinkPtr← NIL;
cCnt: NAT← 0;
noConnections: BOOL;
actuals: expressionPtr← NIL;
atts: attPtr ← NIL;
cktName← searchName[cn, allLevels, handle.vars.currentCkt];
IF cktName # NIL THEN
WITH cktName.details SELECT FROM
c: RefCircuitRec => {
IF handle.vars.item=leftB THEN {
next[handle];
noConnections← (c.conCount=0);
IF ~noConnections THEN
WHILE handle.vars.item=name DO
n← findNode[handle];
cons← NEW[conLink← [nextLink: cons, namedNode: n]];
cCnt← cCnt + 1;
IF handle.vars.item=comma THEN next[handle] ELSE EXIT;
ENDLOOP;
IF noConnections OR handle.vars.item=vertical THEN
actuals← getActualParameters[handle, cktName];
IF handle.vars.item = semi THEN
atts ← getAttributes[handle];
IF handle.vars.item=rightB THEN next[handle]
ELSE error[handle, 202,, TRUE];
};
IF cCnt # c.conCount THEN error[handle, 260];
iName.details← NEW[CktInstance← [of: cktName,
connections: cons,
actualParms: actuals,
attributes: atts] ];
};
ENDCASE => error[handle, 225, TRUE]
ELSE error[handle, 251, TRUE];
}; -- defCktInstance
enterDefinition: PROC[handle: Handle]= {
key: keys;
nameCount: NAT;
nPtr: namePtr;
s: REF TEXT← RefText.New[256];
explodeExpr: expressionPtr← NIL;
[nPtr, nameCount]← getNames[handle];
IF nPtr=NIL THEN error[handle, 208];
IF handle.vars.item # colon THEN error[handle, 207,, TRUE] ELSE next[handle];
IF handle.vars.item=leftP THEN {
explodeExpr← expression[handle];
IF nPtr # NIL THEN nPtr.expExpr← explodeExpr;
IF handle.vars.item=implies THEN next[handle] ELSE error[handle, 215,, TRUE];
};
IF handle.vars.item=name THEN {
key← searchKey[handle];
s.length← 0;
s← RefText.Append[s, handle.vars.newString];
next[handle];
IF key # nodeKey AND nameCount # 1 THEN error[handle, 261];
SELECT key FROM
nodeKey => {
IF nPtr.expExpr # NIL THEN error[handle, 253];
UNTIL nPtr=NIL DO
nPtr.details← NEW[NodeRec];
nPtr← nPtr.nextName;
ENDLOOP;
};
resKey, capKey, indKey, vsKey, isKey =>
enterBranches[handle, nPtr, key];
circuitKey => {
IF nPtr.expExpr # NIL THEN error[handle, 253];
defineCircuit[handle: handle, ckt: nPtr, root: FALSE];
};
modelKey => {
IF nPtr.expExpr # NIL THEN error[handle, 253];
enterModel[handle, nPtr];
};
ENDCASE => defCktInstance[handle, s, nPtr];
}
ELSE error[handle, 208, TRUE]
}; -- enterDefinition
levelSpace: PROC[stream: IO.STREAM, level: NAT]= {
UNTIL level=0 DO
IO.PutF[stream, " "];
level← level - 1
ENDLOOP
}; -- levelSpace
output: PUBLIC PROC[handle: Handle, ckt: namePtr, level: NAT]= {
cLink: conLinkPtr;
np: namePtr;
cktDetails: RefCircuitRec← NARROW[ckt.details];
np← cktDetails.names;
UNTIL np=NIL DO
levelSpace[handle.msgStream, level];
IO.PutF[handle.msgStream, "%g", IO.rope[np.name]];
WITH np.details SELECT FROM
n: RefNodeRec => NULL;
n: RefBranchRec => IO.PutF[handle.msgStream, ": branch[%s, %s]",
IO.rope[n.posNode.name], IO.rope[n.negNode.name]];
n: RefCircuitRec => {
IO.PutF[handle.msgStream, ": circuit.\n"];
output[handle, np, level + 1];
};
n: RefConRec => NULL;
n: RefParmRec => {
IO.PutF[handle.msgStream, ": parameter"];
IF n.default THEN IO.PutF[handle.msgStream, "← %13.5f",
IO.real[n.dfltValue]]
};
n: RefCktInstRec => {
IO.PutF[handle.msgStream, ": %g[", IO.rope[n.of.name]];
cLink← n.connections;
UNTIL cLink=NIL DO
IO.PutF[handle.msgStream, "%g", IO.rope[cLink.namedNode.name]];
cLink← cLink.nextLink;
IF cLink # NIL THEN IO.PutF[handle.msgStream, ", "]
ENDLOOP;
IO.PutF[handle.msgStream, "]"]
};
ENDCASE;
np← np.srchLink;
IO.PutF[handle.msgStream, ".\n"];
ENDLOOP;
}; -- output
END.