File: spGlobalsimpl.mesa
Copyright (C) 1985 by Xerox Corporation. All rights reserved.
Last Edited by:
Sweetsun Chen, September 18, 1985 9:30:10 pm PDT
DIRECTORY
Ascii USING [ControlZ, CR, SP, TAB, Upper],
IO USING [Close, EndOf, Flush, GetChar, GetIndex, 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, FromRefText, IsEmpty, Length, ROPE, Substr],
spGlobals USING [EchoInput, error, Handle, itemType, keys, maxInclude, PutMsgLine],
TypeScript USING [ChangeLooks],
ViewerTools USING [GetContents, SetContents];
spGlobalsImpl: CEDAR PROGRAM
IMPORTS Ascii, IO, FS, RefText, Rope, 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 ← Rope.FromRefText[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]];
fileNameStack[0] ← fullInputName;
fileStack[0] ← 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];
RETURN[
IF extStart >= 0 AND extStart + realExt.Length[] = old.Length[] THEN old
ELSE 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[Rope.FromRefText[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;
} ];
fileStackTop← fileStackTop + 1;
fileNameStack[fileStackTop] ← fullName;
fileStack[fileStackTop] ← 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
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 {
IF inStream # NIL THEN inStream.Close[ ];
fileStack[fileStackTop] ← NIL;
fileNameStack[fileStackTop] ← NIL;
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"];
IF spGlobals.EchoInput[handle] THEN spGlobals.PutMsgLine[handle, Rope.FromRefText[line]]
ELSE {
pos: INT ← inStream.GetIndex[];
IF pos/500 - (pos - line.length)/500 = 1 THEN handle.msgStream.PutF["."];
};
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, '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[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.
Chen, July 22, 1985 8:09:13 pm PDT => Cedar6.0.