File: [Cherry]<Thyme>Cedar5.2>System>spInput.mesa
Last Edited by: SChen, September 6, 1984 3:11:03 pm PDT

DIRECTORY
IO USING [PutF, real, rope, STREAM],
Real USING [FixC],
RefText USING [Append, New],
Rope USING [Cat, Equal, ROPE],
RopeFrom USING [String],
spGlobals USING [Aborted, argList, argNames, assignExpr, 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, RopeFrom, 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: RopeFrom.String[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]= {
lastNamePtr: namePtr;
oldDetails: RefCircuitRec;
nameRope: Rope.ROPE← RopeFrom.String[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 =>
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[RopeFrom.String[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[RopeFrom.String[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;
IF handle.vars.item=leftArrow THEN {
ENABLE
ErrorSignal => {
ErrorStrings[handle, error, GetCircuitTree[handle.vars.currentCkt], s];
n.details← NEW[ParmRec← [nextParm: plist]];
GOTO badEnd;
};

next[handle];
n.details← NEW[ParmRec← [default: TRUE,
dfltValue: eval[handle, expression[handle]],
nextParm: plist ] ];
EXITS
badEnd => NULL;
}
ELSE n.details← NEW[ParmRec← [nextParm: plist]];
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) names on currentCkt
[ckt, curCktDetails.conCount]← getNames[handle];
curCktDetails.fakeNodes← ckt;
UNTIL ckt=NIL DO
ckt.details← NEW[ConRec];
ckt← ckt.nextName;
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 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

defCktInstance: PROC[handle: Handle, cn: REF TEXT, iName: namePtr]= {
cktName: namePtr;
n: namePtr;
cons: conLinkPtr← NIL;
cCnt: NAT← 0;
noConnections: BOOL;
actuals: expressionPtr← 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=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] ];
};
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.