ThymeGlobalsImpl.mesa
Copyright (C) 1985 by Xerox Corporation. All rights reserved.
Last Edited by:
Christian LeCocq January 28, 1987 11:21:33 am PST
Sweetsun Chen, April 26, 1986 4:39:14 pm PST
DIRECTORY
Ascii USING [ControlZ, CR, SP, TAB],
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],
ThymeGlobals USING [EchoInput, Error, Handle, itemType, keys, maxInclude, PutMsgLine],
ViewerTools USING [GetContents, SetContents];
ThymeGlobalsImpl: CEDAR PROGRAM
IMPORTS
IO,
FS,
RefText,
Rope,
ThymeGlobals,
ViewerTools
EXPORTS
ThymeGlobals
= BEGIN
Handle: TYPE = ThymeGlobals.Handle;
Aborted: PUBLIC SIGNAL = CODE;
keyList: ARRAY ThymeGlobals.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: PUBLIC 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 < ThymeGlobals.maxInclude THEN {
fileName: Rope.ROPE← EnsureExtension[Rope.FromRefText[fname], "thy"];
fullName: Rope.ROPE;
[fullName, ] ← FS.ExpandName[fileName, WorkingDirectory[handle]
! FS.Error => {
ThymeGlobals.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 => {
ThymeGlobals.Error[handle, 103, FALSE];
fileStackTop ← fileStackTop - 1;
inStream← fileStack[fileStackTop];
GOTO fileError;
} ];
EXITS fileError => NULL;
}
ELSE ThymeGlobals.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 ThymeGlobals.EchoInput[handle] THEN ThymeGlobals.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 ThymeGlobals.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 { -- skip comments
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 {ThymeGlobals.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 {ThymeGlobals.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 ThymeGlobals.Error[handle, 102, FALSE];
};
ENDCASE => {
NextChar[handle, TRUE];
ThymeGlobals.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 ThymeGlobals.Error[handle, 105, FALSE];
}; -- GetSignedNumber
SearchKey: PUBLIC PROC[handle: Handle] RETURNS[index: ThymeGlobals.keys]= {
FOR i: ThymeGlobals.keys IN ThymeGlobals.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.