File: [Cherry]<Thyme>Cedar5.2>System>spGlobalsimpl.mesa
Last Edited by: SChen, September 18, 1984 12:38:04 pm PDT

DIRECTORY
Ascii USING [ControlZ, CR, SP, TAB, Upper],
IO USING [Close, EndOf, Flush, GetChar, int, PutF, PutFR, rope, STREAM],
FS USING [ComponentPositions, Error, ExpandName, maxFNameLength, StreamOpen],
RefText USING [AppendChar, AppendRope, New, ObtainScratch, ReleaseScratch, TrustTextAsRope],
Rope USING [Concat, Equal, Fetch, Find, IsEmpty, Length, ROPE, Substr],
RopeFrom USING [String],
spGlobals USING [error, Handle, itemType, keys, maxInclude, PutMsgLine],
TypeScript USING [ChangeLooks],
ViewerTools USING [GetContents, SetContents];

spGlobalsImpl: CEDAR PROGRAM
IMPORTS Ascii, IO, FS, RefText, Rope, RopeFrom, spGlobals, TypeScript, ViewerTools
EXPORTS spGlobals=

BEGIN

Handle: TYPE= spGlobals.Handle;

Aborted: PUBLIC SIGNAL = CODE;

keyList: ARRAY spGlobals.keys OF Rope.ROPE← [
"node", "resistor", "capacitor", "inductor", "voltage",
"current", "run", "print", "circuit", "model", "plot",
"ic", "dump", "asserts", "checkpoint", "library", ""];

openInputFile: PUBLIC PROC[handle: Handle] = {
OPEN handle.vars;
RemoveFunnyChars: PROC[old: Rope.ROPE] RETURNS [new: Rope.ROPENIL] = {
name: REF TEXT ← RefText.New[FS.maxFNameLength];
c: CHAR;
hasFunnyChar: BOOLFALSE;
name.length ← 0;
FOR i: INT IN [0..old.Length[]) DO
c ← old.Fetch[i];
SELECT c FROM
IN['0..'9], IN['a..'z], IN['A..'Z], '$, '-, '+, '' , '[, '], '<, '>, '., '!, '#, '/ =>
name ← RefText.AppendChar[name, c];
ENDCASE => hasFunnyChar ← TRUE;
IF name.length >= FS.maxFNameLength THEN EXIT;
ENDLOOP;
IF hasFunnyChar THEN {
new ← RopeFrom.String[name];
ViewerTools.SetContents[handle.input, new];
}
ELSE new ← old;
}; -- RemoveCtrlChars
inputName, fullInputName: Rope.ROPE;
inputName ← RemoveFunnyChars[ViewerTools.GetContents[handle.input]];
inputName ← EnsureExtension[inputName, "thy"];
[fullInputName, ]← FS.ExpandName[inputName, WorkingDirectory[handle]];
inStream← FS.StreamOpen[fullInputName];
}; -- openInputFile

EnsureExtension: PROC[old, ext: Rope.ROPE] RETURNS[Rope.ROPE]= {
-- does nothing if old name has '! in it.
IF Rope.Find[old, "!"] >= 0 THEN RETURN[old]
ELSE {
realExt: Rope.ROPE ← Rope.Concat[".", ext];
dotPos, extStart: INT ← old.Find["."];
UNTIL dotPos <= 0 OR dotPos+1 >= old.Length[] DO
dotPos ← old.Find[".", dotPos+1];
IF dotPos >= 0 THEN extStart ← dotPos;
ENDLOOP;
IF extStart >= 0 THEN extStart← old.Find[realExt, extStart, FALSE];
IF extStart >= 0 AND extStart + realExt.Length[] = old.Length[] THEN RETURN[old]
ELSE RETURN[IO.PutFR["%g.%g", IO.rope[old], IO.rope[ext]]];
};
}; -- EnsureExtension

OutputFileRoot: PUBLIC PROC[handle: Handle] RETURNS[Rope.ROPE]= {
fullName: Rope.ROPE;
inputName: Rope.ROPE ← EnsureExtension[ViewerTools.GetContents[handle.input], "thy"];
c: FS.ComponentPositions;
workDir: Rope.ROPE ← WorkingDirectory[handle];
[fullName, c]← FS.ExpandName[inputName, workDir];
RETURN[Rope.Concat[workDir, Rope.Substr[fullName, c.base.start, c.base.length]]];
}; -- OutputFileRoot

WorkingDirectory: PUBLIC PROC[handle: Handle] RETURNS [dir: Rope.ROPE] = {
dir ← ViewerTools.GetContents[handle.wDir];
IF dir.IsEmpty[] THEN {
dir ← "///Thyme/";
ViewerTools.SetContents[handle.wDir, dir];
};
}; -- WorkingDirectory

includeFile: PROC[handle: Handle]= {OPEN handle.vars;
fname: REF TEXT← RefText.ObtainScratch[128];
fname.length← 0;
nextChar[handle, TRUE];
UNTIL fname.length=128 OR char=Ascii.TAB OR char=Ascii.CR OR char=Ascii.SP DO
fname← RefText.AppendChar[fname, char];
nextChar[handle, FALSE];
ENDLOOP;
IF fileStackTop < spGlobals.maxInclude THEN {
fileName: Rope.ROPE← EnsureExtension[RopeFrom.String[fname], "thy"];
fullName: Rope.ROPE;
[fullName, ]← FS.ExpandName[fileName, WorkingDirectory[handle]
! FS.Error => {
spGlobals.error[handle, 103, FALSE];
handle.msgStream.PutF[" %g\n", IO.rope[error.explanation]];
GOTO fileError;
} ];
fileStack[fileStackTop]← inStream;
fileStackTop← fileStackTop + 1;
inStream← FS.StreamOpen[fullName
! FS.Error => {
spGlobals.error[handle, 103, FALSE];
fileStackTop ← fileStackTop - 1;
inStream← fileStack[fileStackTop];
GOTO fileError;
} ];
EXITS fileError => NULL;
}
ELSE spGlobals.error[handle, 104, FALSE];
RefText.ReleaseScratch[fname];
next[handle];
}; -- includeFile

FlushCloseNil: PUBLIC PROC[stream: IO.STREAM] RETURNS [IO.STREAMNIL] = {
IF stream # NIL THEN {
stream.Flush[ ];
stream.Close[ ];
};
}; -- FlushCloseNil

CloseNil: PUBLIC PROC[stream: IO.STREAM] RETURNS [IO.STREAMNIL] = {
IF stream # NIL THEN stream.Close[ ];
}; -- CloseNil

MsgTextsWithLook
: PUBLIC PROC[handle: Handle, text: Rope.ROPE, look: CHAR['a..'z]]= {
Current Cedar doesn't seem to support PutF with looks
TypeScript.ChangeLooks[handle.message, look];
handle.msgStream.PutF[text];
TypeScript.ChangeLooks[handle.message, Ascii.Upper[look]];
}; -- MsgTextsWithLook

popIncludeFile: PROC[handle: Handle]= {OPEN handle.vars;
IF fileStackTop > 0 THEN {
fileStack[fileStackTop] ← CloseNil[inStream];
fileStackTop← fileStackTop - 1;
inStream← fileStack[fileStackTop];
nextChar[handle, FALSE];
next[handle];
}
ELSE item← eof;
}; -- popIncludeFile

newLine: PROC[handle: Handle]= {OPEN handle.vars;
cptr← 0;
line.length← 0;
DO
char← IF inStream.EndOf[ ] THEN Ascii.ControlZ
ELSE inStream.GetChar[ ];
IF char=Ascii.ControlZ OR char=Ascii.CR THEN EXIT;
line← RefText.AppendChar[line, char];
ENDLOOP;
-- MsgTextsWithLook[handle, RopeFrom.String[line], 'p];
-- handle.msgStream.PutF["\n"];
spGlobals.PutMsgLine[handle, RopeFrom.String[line]];
line← RefText.AppendChar[line, char];
IF char=Ascii.ControlZ THEN line← RefText.AppendChar[line, Ascii.CR];
}; -- newLine

nextChar: PROC[handle: Handle, skip: BOOLEAN]= {
DO OPEN handle.vars;
IF cptr >= line.length THEN newLine[handle];
char← line[cptr];
cptr← cptr + 1;
IF char # Ascii.SP THEN EXIT;
IF ~skip THEN EXIT;
ENDLOOP
}; -- nextChar

scaleFactor: PROC[handle: Handle] RETURNS[s: INT]= {
s← SELECT handle.vars.char FROM
'M => 6,
'k => 3,
'K => 3,
'c => -2,
'm => -3,
'u => -6,
'n => -9,
'p => -12,
ENDCASE => 0;
IF s # 0 THEN nextChar[handle, FALSE];
SELECT handle.vars.char FROM
'F, 'H, 'V, 'A, 's => nextChar[handle, TRUE];
ENDCASE
}; -- scaleFactor

next: PUBLIC PROC[handle: Handle]= {OPEN handle.vars;
minusExp, validReal: BOOLEANFALSE;
exp: INTEGER← 0;
f1, f10: REAL;

MoveOnWithNewItem: PROC[c: CHAR]= {
-- "MoveOn" means: get next char in input file, skipping blanks.
item← SELECT c FROM
'{ => leftC, '} => rightC,
'[ => leftB, '] => rightB,
'( => leftP, ') => rightP,
': => colon, '; => semi,
', => comma, '' => quote,
'← => leftArrow, '^ => upArrow,
'/ => slash, '| => vertical, '\\ => backSlash,
'+ => plus, '~ => squiggle,
'@ => atSign, '* => star,
'& => amperesand, '# => pound,
ENDCASE => nullItem;
IF item=nullItem THEN spGlobals.error[handle, 100, FALSE];
nextChar[handle, TRUE];
}; -- MoveOnWithNewItem

SELECT char FROM
Ascii.ControlZ => popIncludeFile[handle];

'! => includeFile[handle];

Ascii.TAB, Ascii.SP, Ascii.CR => {nextChar[handle, TRUE]; next[handle]};

'{, '}, '[, '], '(, '), ':, ';,
',, '', '←, '^, '/, '|, '\\,
'+, '~, '@, '*, '&, '# => MoveOnWithNewItem[char];

'= => {nextChar[handle, FALSE];
IF char='> THEN {item← implies; nextChar[handle, TRUE]}
ELSE item← equal;
};

'- => {item← minus;
nextChar[handle, FALSE];
IF char='- THEN {
UNTIL char=Ascii.CR OR char=Ascii.ControlZ DO
nextChar[handle, TRUE];
IF char='- THEN {
nextChar[handle, FALSE];
IF char='- THEN {nextChar[handle, TRUE]; EXIT};
};
ENDLOOP;
next[handle];
};
};

'> => {nextChar[handle, FALSE];
IF char='= THEN {item← greatEqual; nextChar[handle, TRUE]}
ELSE item← greater;
};

'< => {nextChar[handle, FALSE];
IF char='= THEN {item← lessEqual; nextChar[handle, TRUE]}
ELSE item← less;
};

'" => {item← string;
newString.length← 0;
DO
nextChar[handle, FALSE];
IF char=Ascii.ControlZ THEN
{spGlobals.error[handle, 213, FALSE]; EXIT};
IF char='" THEN {
nextChar[handle, FALSE];
IF char # '" THEN EXIT
};
newString← RefText.AppendChar[newString, char];
ENDLOOP;
};

'? => {newString.length← 0;
newString← RefText.AppendRope[newString,
IO.PutFR["?%g", IO.int[genSymCtr]] ];
genSymCtr← genSymCtr + 1;
item← name;
nextChar[handle, TRUE];
};

'$ => {nextChar[handle, FALSE];
newString.length← 0;
UNTIL char='$ DO
IF char=Ascii.ControlZ THEN {spGlobals.error[handle, 214, FALSE]; EXIT};
newString← RefText.AppendChar[newString, char];
nextChar[handle, FALSE]
ENDLOOP;
nextChar[handle, TRUE];
item← name;
};

IN ['A..'Z], IN ['a..'z] => {
newString.length← 0;
UNTIL ~(char IN ['A..'Z] OR char IN ['a..'z] OR char IN ['0..'9]) DO
newString← RefText.AppendChar[newString, char];
nextChar[handle, FALSE];
ENDLOOP;
IF Rope.Equal[RefText.TrustTextAsRope[newString], "MAX", FALSE]
THEN {item← maximum; GOTO done}
ELSE IF Rope.Equal[RefText.TrustTextAsRope[newString], "MIN", FALSE]
THEN {item← minimum; GOTO done}
ELSE item← name;
EXITS
done => IF char=Ascii.SP OR char=Ascii.CR OR
char=Ascii.TAB THEN nextChar[handle, TRUE];
};

'., IN ['0..'9] => {
item← number;
value← 0.0;
WHILE char IN ['0..'9] DO
validReal← TRUE;
value← value*10.0 + (char - '0);
nextChar[handle, FALSE]
ENDLOOP;
IF char='. THEN {
nextChar[handle, FALSE];
f10← 0.1;
WHILE char IN ['0..'9] DO
validReal← TRUE;
value← value + f10*(char - '0);
f10← 0.1*f10;
nextChar[handle, FALSE]
ENDLOOP
};
IF char='e OR char='E THEN {
nextChar[handle, FALSE];
minusExp← (char='-);
IF minusExp OR (char='+) THEN nextChar[handle, FALSE];
IF char IN ['0..'9] THEN {
WHILE char IN ['0..'9] DO
exp← exp*10 + (char - '0);
nextChar[handle, FALSE];
ENDLOOP;
}
ELSE validReal← FALSE;
IF minusExp THEN exp← -exp;
};
exp← exp + scaleFactor[handle];
validReal← validReal AND (exp < 37) AND (exp > -37);
IF validReal THEN {
f1← 1.0E+1; f10← 1.0E+10;
IF exp < 0 THEN {f1← 1.0/f1; f10← 1.0/f10; exp← -exp };
UNTIL exp < 10 DO value← value*f10; exp← exp - 10 ENDLOOP;
UNTIL exp=0 DO value← value*f1; exp← exp - 1 ENDLOOP
}
ELSE spGlobals.error[handle, 102, FALSE];
};
ENDCASE => {
nextChar[handle, TRUE];
spGlobals.error[handle, 101, FALSE];
};
}; -- next

getSignedNumber: PUBLIC PROC[handle: Handle] RETURNS[n: REAL← 1.0]= {
negative: BOOLEAN← (handle.vars.item=minus);

IF negative THEN next[handle];
IF handle.vars.item=number THEN {
n← IF negative THEN -handle.vars.value ELSE handle.vars.value;
next[handle]
}
ELSE spGlobals.error[handle, 105, FALSE];
}; -- getSignedNumber

searchKey: PUBLIC PROC[handle: Handle] RETURNS[index: spGlobals.keys]= {
FOR i: spGlobals.keys IN spGlobals.keys DO
index← i;
IF Rope.Equal[
RefText.TrustTextAsRope[handle.vars.newString],
keyList[i], FALSE] THEN EXIT;
ENDLOOP;
}; -- searchKey

GetLineAndCptr: PUBLIC PROC[handle: Handle] RETURNS[Rope.ROPE, NAT]= {
RETURN[RopeFrom.String[handle.vars.line], handle.vars.cptr]};

END.
CHANGE LOG
Wilhelm, April 27, 1982 4:05 PM
Barth, 7-May-82 11:00:25 PDT
Chen, April 19, 1983 1:45 PM, modified "next" to support min and max operations.
Chen, February 12, 1984 7:56 PM, to support oldArgVector.
Chen, June 11, 1984 7:34:25 pm PDT, cedarized.