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.
ROPE ←
NIL] = {
name:
REF
TEXT ← RefText.New[
FS.maxFNameLength];
c:
CHAR;
hasFunnyChar:
BOOL ←
FALSE;
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.
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, 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: 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[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.