File: [Cherry]<Thyme>Cedar5.2>System>spGlobalsimpl.mesa
Last Edited by: SChen, September 18, 1984 12:38:04 pm PDT
Last Edited by: Gasbarro October 17, 1985 11:22:07 am PDT
DIRECTORY
Ascii
USING [ControlZ,
CR,
SP,
TAB],
IO
USING [Close, EndOf, Flush, GetChar, int, PutF, PutFR, rope,
STREAM],
FS
USING [Error, StreamOpen],
RefText
USING [AppendChar, AppendRope, ObtainScratch, ReleaseScratch, TrustTextAsRope],
Rope
USING [Concat, Equal, Find, FromRefText, Length,
ROPE],
spGlobals
USING [error, Handle, itemType, keys, maxInclude];
spGlobalsImpl:
CEDAR
PROGRAM
IMPORTS
IO,
FS, RefText, Rope, spGlobals
EXPORTS spGlobals=
BEGIN
Handle:
TYPE= spGlobals.Handle;
Aborted:
PUBLIC
SIGNAL =
CODE;
Retreat:
PUBLIC
SIGNAL[cause: Rope.
ROPE] =
CODE;
Failure:
PUBLIC
SIGNAL[errorNum:
NAT] =
CODE;
keyList:
ARRAY spGlobals.keys
OF Rope.
ROPE← [
"node", "resistor", "capacitor", "inductor", "voltage",
"current", "run", "print", "circuit", "model", "plot",
"ic", "dump", "asserts", "checkpoint", "library", ""];
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
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[Rope.FromRefText[fname], "thy"];
fileStack[fileStackTop]← inStream;
fileStackTop← fileStackTop + 1;
inStream←
FS.StreamOpen[fileName
!
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.
STREAM ←
NIL] = {
IF stream #
NIL
THEN {
stream.Flush[ ];
stream.Close[ ];
};
};
-- FlushCloseNil
CloseNil:
PUBLIC
PROC[stream:
IO.
STREAM]
RETURNS [
IO.
STREAM ←
NIL] = {
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, Rope.FromRefText[line], 'p];
-- handle.msgStream.PutF["\n"];
-- deleted for Crystal use. spGlobals.PutMsgLine[handle, Rope.FromRefText[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: BOOLEAN← FALSE;
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[Rope.FromRefText[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.