<> <> <> <> <> 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.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 _ 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]= { <> 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.STREAM _ NIL] = { IF stream # NIL THEN { stream.Flush[ ]; stream.Close[ ]; }; }; -- FlushCloseNil MsgTextsWithLook: PUBLIC PROC[handle: Handle, text: Rope.ROPE, look: CHAR['a..'z]]= { <> <> handle.msgStream.PutF[text]; <> }; -- 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; <> <> 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: 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 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.