DIRECTORY Ascii USING [CR, FF, LF, NUL, SP, TAB], Atom USING [GetPropFromList], Convert USING [Error, RealFromRope], Graph USING [CaretIndex, CaretSpec, ColorIndex, Entity, FontIndex, GraphHandle, NtNan, ROPE, TargetSpec, ValueList, XY], GraphOps USING [AddCurve, NewGraph, SetXValues], GraphPrivate USING [DataError, RopeList, SyntaxError], GraphUtil USING [BlinkMsg, LengthOfVL], IO USING [EndOfStream, Error, GetCedarToken, GetChar, GetID, GetIndex, int, PeekChar, PutFR, rope, SetIndex, STREAM, TokenError, TokenKind], List USING [Kill], Real USING [Fix], RefText USING [Equal, ObtainScratch, ReleaseScratch, TrustTextAsRope], Rope USING [Equal, FromRefText, Substr]; GraphReadAscii: CEDAR PROGRAM IMPORTS Atom, Convert, GraphOps, GraphPrivate, IO, GraphUtil, List, Real, RefText, Rope EXPORTS GraphPrivate = { OPEN Graph, GraphOps, GraphPrivate, GraphUtil; TextDataKeys: TYPE = {varsKey, nVarsKey, valuesKey, noneKey}; LVL: TYPE = LIST OF ValueList; ReadAsciiFile: PUBLIC PROC [handle: GraphHandle, s: IO.STREAM] RETURNS [msg: ROPE _ NIL] = { ok: BOOL _ TRUE; key: ROPE _ s.GetID[ ! IO.EndOfStream, IO.Error => ok _ FALSE]; IF ok THEN ok _ key.Equal["graph", FALSE]; IF ok THEN msg _ ReadAsciiComplex[handle, s] ELSE { s.SetIndex[0]; msg _ ReadAsciiSimple[handle, s]; }; }; -- ReadAsciiFile ReadAsciiComplex: PROC [handle: GraphHandle, s: IO.STREAM] RETURNS [msg: ROPE _ NIL] = { msg _ "Not implemented yet." }; -- ReadAsciiComplex ReadAsciiSimple: PROC [handle: GraphHandle, s: IO.STREAM] RETURNS [msg: ROPE _ NIL] = { ENABLE { SyntaxError => {msg _ IO.PutFR["Syntax error at [%g], %g.", IO.int[s.GetIndex[]], IO.rope[message]]; CONTINUE}; DataError => {msg _ IO.PutFR["Error at [%g], %g.", IO.int[s.GetIndex[]], IO.rope[message]]; CONTINUE}; }; buffer: REF TEXT _ RefText.ObtainScratch[512]; tokenKind: IO.TokenKind _ tokenCOMMENT; token: REF TEXT; charsSkipped: INT; error: IO.TokenError; get: BOOL _ TRUE; endOfFile: BOOL _ FALSE; key: TextDataKeys _ noneKey; nVars, specifiedN, guessedN, finalN, iRow, iCol: INT; -- iRow, iCol: last row/col processed so far. varsSpecified, nVarsSpecified, valuesSpecified, nVarsGuessed, nToBeGuessed, endOfGroup: BOOL; vars, lastVar: RopeList; xvalues: ValueList; yvalues, tlvl: LVL; status: ROPE; AppendIDtoNames: PROC [] = { nl: RopeList _ CONS[Rope.FromRefText[token], NIL]; IF lastVar = NIL THEN {vars _ lastVar _ nl} ELSE {lastVar.rest _ nl; lastVar _ nl}; nVars _ nVars + 1; varsSpecified _ TRUE; }; -- AppendIDtoNames AppendROPEtoNames: PROC [] = { -- othere input/output: vars and lastVar name: ROPE _ IF token.length <= 2 THEN "" ELSE Rope.FromRefText[token].Substr[1, token.length - 2]; nl: RopeList _ CONS[name, NIL]; IF lastVar = NIL THEN {vars _ lastVar _ nl} ELSE {lastVar.rest _ nl; lastVar _ nl}; nVars _ nVars + 1; varsSpecified _ TRUE; }; -- AppendROPEtoNames ProcessTokenID: PROC [] = { currKey: TextDataKeys _ key; nextChar: CHAR; [nextChar, endOfFile] _ PeekNextNonBlankChar[s]; IF endOfFile THEN SELECT currKey FROM varsKey, nVarsKey, noneKey => SIGNAL DataError["can't find values"]; valuesKey => endOfGroup _ TRUE; ENDCASE ELSE IF nextChar = ': THEN { [] _ s.GetChar[]; key _ GetKeyWord[token, s]; SELECT key FROM varsKey => { IF currKey = varsKey THEN SIGNAL SyntaxError["duplicate vars key"]; IF valuesSpecified THEN endOfGroup _ TRUE ELSE IF varsSpecified THEN SIGNAL SyntaxError["duplicate vars key"]; }; nVarsKey => { IF currKey = nVarsKey THEN SIGNAL SyntaxError["duplicate nVars key"]; IF valuesSpecified THEN endOfGroup _ TRUE ELSE IF nVarsSpecified THEN SIGNAL SyntaxError["duplicate nVars key"]; }; valuesKey => { IF currKey = valuesKey THEN endOfGroup _ TRUE; -- values must have been specified. [finalN, vars, yvalues] _ InitData[nVarsSpecified, specifiedN, nVars, vars]; }; ENDCASE; -- nothing else after GetKeyWord. } ELSE SELECT key FROM varsKey => AppendIDtoNames[]; valuesKey => { -- values must have been specified. endOfGroup _ TRUE; key _ varsKey; get _ FALSE; }; nVarsKey => { -- nVarsSpecified must have been specified. IF varsSpecified THEN { IF valuesSpecified THEN { endOfGroup _ TRUE; key _ varsKey; get _ FALSE; } ELSE SIGNAL SyntaxError["possibly missing `:' after keyword"]; } ELSE { -- vars not specified. key _ varsKey; get _ FALSE; }; }; ENDCASE => { -- noneKey, so values, vars, and nName are not specified. key _ varsKey; get _ FALSE; }; }; -- ProcessTokenID UNTIL endOfFile DO nVars _ specifiedN _ guessedN _ iRow _ iCol _ 0; finalN _ -1; varsSpecified _ nVarsSpecified _ nVarsGuessed _ nToBeGuessed _ valuesSpecified _ endOfGroup _ FALSE; vars _ lastVar _ NIL; xvalues _ NIL; yvalues _ tlvl _ NIL; status _ NIL; UNTIL endOfGroup OR endOfFile DO IF get THEN [tokenKind, token, charsSkipped, error] _ s.GetCedarToken[buffer] ELSE get _ TRUE; SELECT tokenKind FROM tokenCOMMENT => LOOP; tokenERROR => SIGNAL SyntaxError[]; tokenEOF => { IF NOT valuesSpecified THEN SIGNAL DataError["can't find values"]; endOfFile _ TRUE; EXIT; }; ENDCASE => SELECT key FROM noneKey => { -- can happen only at first time in the loop. SELECT tokenKind FROM tokenROPE => {key _ varsKey; get _ FALSE}; tokenID => ProcessTokenID[]; tokenREAL, tokenDECIMAL => { key _ valuesKey; get _ FALSE; [finalN, vars, yvalues] _ InitData[nVarsSpecified, specifiedN, nVars, vars]; }; ENDCASE => SIGNAL SyntaxError["key word, rope, or values expected"]; }; nVarsKey => { status _ "after nVars key"; SELECT tokenKind FROM tokenDECIMAL, tokenREAL => { IF nVarsSpecified THEN { key _ valuesKey; get _ FALSE; [finalN, vars, yvalues] _ InitData[nVarsSpecified, specifiedN, nVars, vars]; } ELSE { ok: BOOL _ TRUE; rope: ROPE _ RefText.TrustTextAsRope[token]; r: REAL; r _ Convert.RealFromRope[rope ! Convert.Error => {ok _ FALSE; CONTINUE}]; IF ok THEN { IF r > LAST[INT] THEN SIGNAL DataError["nVars too big"]; IF r < 1 THEN SIGNAL DataError["nVars < 1"]; specifiedN _ Real.Fix[r]; nVarsSpecified _ TRUE; } ELSE SIGNAL DataError[status]; }; }; ENDCASE => { IF NOT nVarsSpecified THEN SIGNAL DataError["can't find the number of variables"]; SELECT tokenKind FROM tokenSINGLE => LOOP; tokenID => ProcessTokenID[]; tokenROPE => { IF varsSpecified THEN SIGNAL DataError["names have been listed"]; key _ varsKey; get _ FALSE; }; ENDCASE => SIGNAL SyntaxError[status]; }; }; varsKey => { status _ "getting vars"; SELECT tokenKind FROM tokenROPE => AppendROPEtoNames[]; tokenID => ProcessTokenID[]; tokenSINGLE => LOOP; tokenDECIMAL, tokenREAL => { key _ valuesKey; get _ FALSE; [finalN, vars, yvalues] _ InitData[nVarsSpecified, specifiedN, nVars, vars]; }; ENDCASE => SIGNAL SyntaxError[status]; }; -- varsKey valuesKey => { status _ "parsing values"; SELECT tokenKind FROM tokenDECIMAL, tokenREAL => { ok: BOOL _ TRUE; r: REAL; IF iCol = finalN OR iCol = 0 THEN {iCol _ 1; iRow _ iRow + 1} ELSE iCol _ iCol + 1; r _ IF RefText.Equal[token, "*"] THEN NtNan ELSE Convert.RealFromRope[RefText.TrustTextAsRope[token] ! Convert.Error => {ok _ FALSE; CONTINUE}]; IF NOT ok THEN SIGNAL DataError[status]; IF iCol = 1 THEN { xvalues _ CONS[r, xvalues]; tlvl _ yvalues; } ELSE { IF tlvl = NIL THEN SIGNAL DataError["gee!"]; -- incredible? tlvl.first _ CONS[r, tlvl.first]; tlvl _ tlvl.rest; }; valuesSpecified _ TRUE; }; tokenSINGLE => LOOP; tokenID => IF valuesSpecified THEN ProcessTokenID[] ELSE SIGNAL DataError["can't find values"]; tokenROPE => { IF NOT valuesSpecified THEN SIGNAL DataError["can't find values"]; endOfGroup _ TRUE; key _ varsKey; get _ FALSE; }; ENDCASE => SIGNAL SyntaxError[status]; }; -- valuesKey ENDCASE; ENDLOOP; IF valuesSpecified THEN handle _ AddNewGraph[oldGraph: handle, fileName: NARROW[Atom.GetPropFromList[s.propList, $Name]], vars: vars, xvalues: xvalues, yvalues: yvalues]; ENDLOOP; RefText.ReleaseScratch[token]; }; -- ReadAsciiSimple KeyFromToken: PROC [token: REF TEXT] RETURNS [key: TextDataKeys _ noneKey] = { IF token # NIL THEN RETURN [SELECT TRUE FROM RefText.Equal[token, "nVars", FALSE], RefText.Equal[token, "nVariables", FALSE] => nVarsKey, RefText.Equal[token, "values", FALSE] => valuesKey, RefText.Equal[token, "vars", FALSE], RefText.Equal[token, "variables", FALSE] => varsKey, ENDCASE => noneKey]; }; -- KeyFromToken GetKeyWord: PROC [token: REF TEXT, s: IO.STREAM] RETURNS [key: TextDataKeys] = { [] _ s.GetChar[]; -- skip the colon. key _ KeyFromToken[token]; IF key = noneKey THEN SIGNAL SyntaxError["unknown key word"]; }; -- GetKeyWord InitData: PROC [nVarsSpecified: BOOL, specifiedN, nVars: INT, names: RopeList] RETURNS [finalN: INT, vars: RopeList, lvl: LVL _ NIL] = { -- , toGuess: BOOL _ FALSE] = { finalN _ nVars; vars _ names; IF vars = NIL AND NOT nVarsSpecified THEN SIGNAL DataError["number of variables unknown."]; IF vars = NIL AND nVarsSpecified THEN finalN _ specifiedN ELSE IF nVarsSpecified AND vars # NIL THEN { IF specifiedN # nVars THEN BlinkMsg["number of vars listed # specified nVars. The latter is discarded."]; }; IF finalN <= 1 THEN SIGNAL DataError["number of variables <= 1"]; IF vars = NIL THEN FOR i: INT IN [1..finalN] DO vars _ CONS[NIL, vars]; ENDLOOP; FOR j: INT IN [2..finalN] DO lvl _ CONS[NIL, lvl]; ENDLOOP; }; -- InitData BlankChar: PROC [char: CHAR] RETURNS [BOOL] = { OPEN Ascii; RETURN [SELECT char FROM SP, TAB, LF, CR, FF, NUL => TRUE, ENDCASE => FALSE] }; -- BlankChar PeekNextNonBlankChar: PROC [s: IO.STREAM] RETURNS [char: CHAR, eof: BOOL _ FALSE] = { ENABLE IO.EndOfStream => {eof _ TRUE; CONTINUE}; WHILE BlankChar[char _ s.PeekChar[]] DO [] _ s.GetChar[] ENDLOOP; }; -- PeekNextNonBlankChar AddNewGraph: PROC [oldGraph: GraphHandle, fileName: ROPE, vars: RopeList, xvalues: ValueList, yvalues: LVL] RETURNS [newGraph: GraphHandle] = { tlvl: LVL; lengthX, lengthY, iCurve, groupId: INT _ 0; IF oldGraph = NIL OR vars = NIL OR xvalues = NIL OR yvalues = NIL THEN RETURN; lengthX _ LengthOfVL[xvalues]; FOR tlvl _ yvalues, tlvl.rest UNTIL tlvl = NIL DO iCurve _ iCurve + 1; IF (lengthY _ LengthOfVL[tlvl.first]) # lengthX THEN SIGNAL DataError[ IO.PutFR["%g-th variable has %g values but x has %g values", IO.int[iCurve], IO.int[lengthY], IO.int[lengthX]]]; ENDLOOP; [newGraph, groupId] _ NewGraph[ fileName: fileName, comment: fileName, xName: vars.first, oldGraph: oldGraph ]; [] _ SetXValues[handle: newGraph, values: xvalues, groupId: groupId]; -- xvalues is reversed, and it will be cleaned up. tlvl _ yvalues; FOR tn: RopeList _ vars.rest, tn.rest UNTIL tn = NIL DO [] _ AddCurve[handle: newGraph, values: tlvl.first, groupId: groupId, name: tn.first]; tlvl _ tlvl.rest; ENDLOOP; TRUSTED { List.Kill[LOOPHOLE[yvalues]]; List.Kill[LOOPHOLE[vars]]; }; }; -- AddNewGraph }. LOG. SChen, November 16, 1985 9:40:08 pm PST, created. θGraphReadAscii.mesa, Copyright c 1985 by Xerox Corporation. All rights reserved. Last Edited by: Sweetsun Chen, November 17, 1985 2:24:51 am PST read more complicated graph file in text format. If values have been read, then vars key or nVars key will end previous group, and start a new group of data. other input: s, token, varsSpecified; other output: key, get, eog. s is possibly affected too. For nVarsKey and valuesKey, one must make sure the thing they indicate has been specified before calling this. else ok. else ok. begin and end keys are not to be specified. here we must find a legal key. ELSE IF vars # NIL AND NOT nVarsSpecified THEN finalN _ nVars ELSE { finalN _ -1; -- toGuess _ TRUE}; IF NOT toGuess THEN { ReadValueWithGuessedN: PROC [] = { nextChar: CHAR; IF NOT nVarsGuessed THEN { vl: ValuesList _ CONS[r, NIL]; ttlvl: LVL _ CONS[vl, NIL]; IF finalN = -1 THEN finalN _ 1 ELSE finalN _ finalN + 1; iCol _ finalN; vars _ CONS[NIL, vars]; IF iCol = 1 THEN xvalues _ vl ELSE IF tlvl = NIL THEN {yvalues _ tlvl _ ttlvl} ELSE {tlvl.rest _ ttlvl; tlvl _ ttlvl}; nextChar _ s.PeekChar[]; WHILE BlankChar[(nextChar _ s.PeekChar[])] DO ENABLE IO.EndOfStream => {endOfFile _ TRUE; GOTO found}; SELECT nextChar FROM Ascii.CR, Ascii.LF => GOTO guessed; ENDCASE => s.GetChar[]; nextChar _ s.PeekChar[]; ENDLOOP; EXITS found => { nVarsGuessed _ TRUE; ttlvl.first _ NIL; tlvl _ NIL; }; } ELSE { -- nVarsGuessed IF iCol = finalN THEN iCol _ 1 ELSE iCol _ iCol + 1; }; }; -- ReadValuesWithGuessedN ΚP˜JšœΟmœ1™Qšœ™Icode™/—J˜šΟk ˜ Jšœžœžœžœžœžœžœžœ˜'Jšœžœ˜Jšœžœ˜$JšœžœLžœžœ˜xJšœ žœ"˜0Jšœ žœ$˜6Jšœ žœ˜'Jšžœžœežœ˜ŒJšœžœ˜Jšœžœ˜Jšœžœ9˜FJšœžœ˜(J˜—šœžœž˜Jšžœ(žœ&˜WJšžœ˜—J˜Jšžœ*˜.J˜Jšœžœ+˜=Jšžœžœžœžœ ˜J˜šΟn œžœžœžœžœžœžœžœ˜\Jšœžœžœ˜Jš œžœžœžœžœ˜?Jšžœžœžœ˜*Jšžœžœ"˜,šžœ˜J˜Jšœ!˜!J˜—JšœΟc˜J˜šŸœžœžœžœžœžœžœ˜XJ™0J˜Jšœ ˜J˜—J™lšŸœžœžœžœžœžœžœ˜Wšžœ˜šœžœ#˜;Jšžœžœžœ˜3—šœžœ˜2Jšžœžœžœ˜3—J˜J˜—Jšœžœžœ˜.Jšœ žœ˜'Jšœžœžœ˜Jšœžœ˜Jšœžœ ˜J˜Jšœžœžœ˜Jšœ žœžœ˜Jšœ˜J˜šœ1žœ˜5Jš -˜-—JšœXžœ˜]Jšœ˜Jšœ˜Jšœžœ˜Jšœžœ˜ J˜šŸœžœ˜Jšœžœžœ˜2Jšžœ žœžœ˜+Jšžœ#˜'J˜Jšœžœ˜Jšœ ˜J˜—šŸœžœ (˜GJš œžœžœžœžœ5˜cJšœžœžœ˜Jšžœ žœžœ˜+Jšžœ#˜'J˜Jšœžœ˜Jšœ ˜J˜J™—šŸœžœ˜Jšœ^™^Jšœn™nJšœ˜Jšœ žœ˜Jšœ0˜0šžœ žœžœ ž˜%Jšœžœ ˜DJšœžœ˜Jšž˜—šžœžœžœ˜J˜Jšœ˜šžœž˜šœ ˜ Jšžœžœžœ#˜CJšžœžœž˜)Jšžœžœžœžœ#˜DJ™J˜—šœ ˜ Jšžœžœžœ$˜EJšžœžœž˜)Jšžœžœžœžœ$˜FJ™J˜—šœ˜Jšžœžœžœ #˜RJšœL˜LJ˜—Jšžœ !˜*—J˜—šž˜šžœž˜Jšœ˜šœ #˜2Jšœ žœ˜Jšœžœ˜J˜—šœ +˜9šžœžœ˜šžœžœ˜Jšœ žœ˜Jšœžœ˜J˜—Jšžœžœ3˜>J˜—šžœ ˜Jšœžœ˜J˜—J˜—šžœ 9˜FJšœžœ˜J˜———Jšœ ˜J˜—šžœ ž˜Jšœ0˜0J˜ Jšœ^žœ˜dJšœžœ˜Jšœ žœ˜Jšœžœ˜Jšœ žœ˜ šžœ žœ ž˜ JšžœžœB˜MJšžœžœ˜šžœ ž˜Jšœžœ˜Jšœžœ˜#šœ ˜ Jšžœžœžœžœ ˜BJšœ žœ˜Jšžœ˜J˜—šžœžœžœ˜šœ  -˜:šžœ ž˜Jšœ#žœ˜*Jšœ˜šœ˜Jšœžœ˜JšœL˜LJšœ˜—Jšžœžœ3˜D—J˜—šœ ˜ Jšœ˜šžœ ž˜šœ˜šžœžœ˜Jšœžœ˜JšœL˜LJšœ˜—šžœ˜Jšœžœžœ˜Jšœžœ"˜,Jšœžœ˜šœ˜Jšœžœžœ˜+—šžœžœ˜ Jš žœžœžœžœžœ˜8Jšžœžœžœ˜,Jšœ˜Jšœžœ˜J˜—Jšžœžœ˜J˜—J˜—šžœ˜ Jšžœžœžœžœ1˜Ršžœ ž˜Jšœžœ˜Jšœ˜šœ˜Jšžœžœžœ%˜AJšœžœ˜J˜—Jšžœžœ˜&—J˜——J˜—šœ ˜ Jšœ˜šžœ ž˜Jšœ!˜!Jšœ˜Jšœžœ˜šœ˜Jšœžœ˜JšœL˜LJšœ˜—Jšžœžœ˜&—Jšœ  ˜ —šœ˜Jšœ˜šžœ ž˜šœ˜Jšœžœžœ˜Jšœžœ˜Jšžœžœ žœ˜=Jšžœ˜šœžœžœ˜+Jšžœ4˜8Jšœžœžœ˜+—Jšžœžœžœžœ˜(šžœ žœ˜Jšœ žœ ˜J˜J˜—šžœ˜Jš žœžœžœžœ ˜Jšœ žœ*˜:Jšœ0˜0——Jšžœ˜—J˜Jšœ ˜—˜š Ÿ œžœ žœžœžœ"˜NJšœ+™+š žœ žœžœžœžœžœž˜,šœžœ˜%Jšœ#žœ˜6—Jšœžœ˜3šœžœ˜$Jšœ"žœ ˜4—Jšžœ ˜—Jšœ ˜J˜—šŸ œžœ žœžœžœžœžœ˜PJšœ ˜$Jšœ˜J™Jšžœžœžœ!˜=Jšœ  ˜J˜—šŸœžœžœžœžœ žœžœžœ ˜¨Jšœ˜Jšœ ˜ Jš žœžœžœžœžœžœ+˜[šžœžœžœžœ˜9Jš žœžœžœžœžœ™=—š žœžœžœžœžœ˜,JšžœžœO˜iJ˜—šžœ™Jšœ  ™ Jšžœžœ žœ™—Jšžœ žœžœ'˜Aš žœžœžœžœžœžœ ž˜/Jšœžœžœ˜Jšžœ˜—Jšžœžœžœ žœžœžœžœ˜;Jšœ  ˜J˜—š Ÿ œžœžœžœžœžœ˜;šžœžœž˜Jšžœžœžœžœžœžœžœžœžœ˜3—Jšœ  ˜J˜—šŸœžœžœžœžœžœžœžœ˜UJšžœžœžœžœ˜0Jšžœ žœžœ˜AJšœ ˜J˜—šŸ œžœ#žœ˜9Jšœ-žœžœ˜UJšœžœ˜ Jšœ#žœ˜+Jšžœ žœžœžœžœ žœžœ žœžœžœ˜NJšœ˜šžœžœžœž˜1J˜šžœ.žœžœ ˜Fšžœ:˜