File: [Cherry]<Thyme>Cedar5.2>System>spInput.mesa
Last Edited by: SChen, September 24, 1984 11:04:11 am PDT
Last Edited by: Gasbarro October 17, 1985 11:23:20 am PDT

DIRECTORY
IO USING [PutF, real, rope, STREAM],
Real USING [FixC],
RefText USING [Append, New],
Rope USING [Cat, Equal, FromRefText, ROPE],
spGlobals USING [Aborted, argList, argNames, assignExpr, attPtr, attribute, BranchRec, Canned, CircuitRec, CktInstance, conLink, conLinkPtr, ConRec, elements, error, ErrorSignal, ErrorStrings, eval, expression, expressionPtr, findFunction, findModel, function, FunctionRec, Handle, keys, ModelRec, nameBlk, namePtr, namePtrSeq, next, NodeRec, ParmRec, RefBranchRec, RefCircuitRec, RefCktInstRec, RefConRec, RefFunctionRec, RefModelRec, RefNodeRec, RefParmRec, searchKey, ValueSeq];

spInput: CEDAR PROGRAM
IMPORTS IO, Real, RefText, Rope, spGlobals
EXPORTS spGlobals=

BEGIN OPEN spGlobals;

enterName: PROC[handle: Handle] RETURNS[newCktNames: namePtr← NIL]= {
-- enter a (one level unique) name string to the search link of currentCkt
OPEN handle.vars;
IF searchName[newString, oneLevel, currentCkt]=NIL THEN {
curCktDetails: RefCircuitRec← NARROW[currentCkt.details];
newCktNames← NEW[nameBlk← [srchLink: curCktDetails.names,
name: Rope.FromRefText[newString]]];
curCktDetails.names← newCktNames;
}
ELSE error[handle, 250];
}; -- enterName

searchName: PROC[nameString: REF TEXT, -- usually newString
level: {oneLevel, allLevels}← oneLevel,
oldCktNames: namePtr] -- usually currentCkt
RETURNS[newCktNames: namePtr← NIL]= {
See if a particular name is on the namelist of oldCktNames. If it is then reorganize the namelist of oldCktNames so that the matched name is now at the front of the list (this is done to speed up repeated references to the same name, I suppose). If level is oneLevel, then only search oldcktNames' circuit. If it is alLevels, then search up through parents in the hierarchy until the top of the hierarchy is found or a match is found.

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.
CHANGE LOG
Wilhelm April 6, 1982 9:59 AM
Barth, 7-May-82 12:20:02 PDT
Chen, February 12, 1984 7:57 PM, to support oldArgVector.
Chen, June 10, 1984 8:54:05 pm PDT, cedarized.