<> <> <> <> <> <<>> DIRECTORY Convert, GGBasicTypes, GGBoundBox, GGParseIn, Imager, ImagerColor, ImagerTransformation, IO, RefText, Rope; GGParseInImpl: CEDAR PROGRAM IMPORTS Convert, GGBoundBox, Imager, ImagerColor, ImagerTransformation, IO, RefText, Rope EXPORTS GGParseIn = BEGIN SyntaxError: PUBLIC SIGNAL [position: NAT, wasThere: Rope.ROPE, notThere: Rope.ROPE] = CODE; BoundBox: TYPE = GGBasicTypes.BoundBox; Color: TYPE = Imager.Color; Point: TYPE = GGBasicTypes.Point; SequenceOfReal: TYPE = REF SequenceOfRealObj; SequenceOfRealObj: TYPE = GGBasicTypes.SequenceOfRealObj; ReadBlank: PUBLIC PROC [f: IO.STREAM] = { <'s, 's, and 's until something else is encountered. Doesn't mind if no white space characters are found. Treats comments as white space.>> [] _ IO.SkipWhitespace[f, TRUE]; }; ReadWhiteSpace: PUBLIC PROC [f: IO.STREAM] = { <'s, 's, and 's until something else is encountered. Signals SyntaxError if no white space characters are found.>> WhiteSpaceProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = TRUSTED { SELECT char FROM IO.TAB => RETURN [other]; IO.CR =>RETURN [other]; IO.SP => RETURN [other]; ENDCASE => RETURN [break]; }; whiteSpace: Rope.ROPE; end: BOOL _ FALSE; [whiteSpace, ----] _ IO.GetTokenRope[f, WhiteSpaceProc !IO.EndOfStream => {end _ TRUE; CONTINUE}]; IF end OR Rope.Size[whiteSpace] = 0 THEN SIGNAL SyntaxError[IO.GetIndex[f], "null", ""]; }; ReadHorizontalBlank: PUBLIC PROC [f: IO.STREAM] RETURNS [good: BOOL] = { <'s, and 's until something else is encountered. Returns good = FALSE if a CR is encountered before anything else>> HorizontalBlankProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = TRUSTED { SELECT char FROM IO.TAB, IO.SP => RETURN [other]; ENDCASE => RETURN [break]; }; whiteSpace: Rope.ROPE; c: CHAR; end: BOOL _ FALSE; good _ TRUE; [whiteSpace, ----] _ IO.GetTokenRope[f, HorizontalBlankProc !IO.EndOfStream => {end _ TRUE; CONTINUE}]; IF end THEN {good _ FALSE; RETURN}; c _ Rope.Fetch[whiteSpace, 0]; SELECT c FROM IO.CR => {good _ FALSE; RETURN}; IO.TAB, IO.SP => {good _ TRUE; RETURN}; ENDCASE => {good _ TRUE; IO.Backup[f, c]; RETURN}; }; ReadWord: PROC [f: IO.STREAM] RETURNS [word: Rope.ROPE] = { <> WordBreakProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = CHECKED { SELECT char FROM IO.TAB => RETURN [break]; IO.CR =>RETURN [break]; IO.SP => RETURN [break]; ', => RETURN [break]; '] => RETURN [break]; ') => RETURN [break]; ENDCASE => RETURN [other]; }; [word, ----] _ IO.GetTokenRope[f, WordBreakProc !IO.EndOfStream => {word _ NIL; CONTINUE}]; }; ReadBlankAndWord: PUBLIC PROC [f: IO.STREAM] RETURNS [word: Rope.ROPE] = { ReadBlank[f]; word _ ReadWord[f]; }; ReadRope: PROC [f: IO.STREAM, rope: Rope.ROPE] = { <> <> c: CHAR; endofstream: BOOL _ FALSE; FOR i: INT IN[1..Rope.Length[rope]] DO c _ IO.GetChar[f ! IO.EndOfStream => {endofstream _ TRUE; CONTINUE}]; IF endofstream THEN SIGNAL SyntaxError [IO.GetIndex[f], NIL, rope]; IF NOT c = Rope.Fetch[rope,i-1] THEN SIGNAL SyntaxError [IO.GetIndex[f], Rope.FromChar[c], rope]; ENDLOOP; }; ReadBlankAndRope: PUBLIC PROC [f: IO.STREAM, rope: Rope.ROPE] = { ReadBlank[f]; ReadRope[f, rope]; }; ReadLine: PUBLIC PROC [f: IO.STREAM] RETURNS [line: Rope.ROPE] = { < is encountered.>> LineBreakProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = CHECKED { SELECT char FROM IO.CR =>RETURN [break]; ENDCASE => RETURN [other]; }; end: BOOL _ FALSE; ReadBlank[f]; [line, ----] _ IO.GetTokenRope[f, LineBreakProc !IO.EndOfStream => {end _ TRUE; CONTINUE}]; IF end THEN {line _ NIL; RETURN}; [----, ----] _ IO.GetTokenRope[f, LineBreakProc]; -- remove }; ReadChar: PUBLIC PROC [f: IO.STREAM, c: CHAR] = { streamC: CHAR; ReadBlank[f]; streamC _ IO.GetChar[f]; IF NOT c = streamC THEN SIGNAL SyntaxError[IO.GetIndex[f], Rope.FromChar[streamC], Rope.FromChar[c]]; }; ReadKeyWord: PUBLIC PROC [f: IO.STREAM] RETURNS [keyWord: Rope.ROPE, good: BOOL] = { < are encountered. If CR is encountered first, then good is FALSE since ":" is expected after a keyword.>> KeyWordBreakProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = CHECKED { SELECT char FROM IO.CR =>RETURN [break]; ': => RETURN [break]; ENDCASE => RETURN [other]; }; end: BOOL _ FALSE; nextChar: Rope.ROPE; <> [keyWord, ----] _ IO.GetTokenRope[f, KeyWordBreakProc !IO.EndOfStream => {end _ TRUE; CONTINUE}]; IF end THEN {good _ FALSE; keyWord _ NIL; RETURN}; [nextChar, ----] _ IO.GetTokenRope[f, KeyWordBreakProc !IO.EndOfStream => {end _ TRUE; CONTINUE}]; IF end THEN {good _ FALSE; RETURN}; good _ Rope.Equal[nextChar, ":", TRUE]; }; ReadNAT: PROC [f: IO.STREAM] RETURNS [n: NAT] = { <, . Leaves these terminators on the stream.>> NATBreakProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = TRUSTED { SELECT char FROM '], IO.CR, IO.SP, '., ',, ': => RETURN [break]; ENDCASE => RETURN [other]; }; end: BOOL _ FALSE; intRope: Rope.ROPE; [intRope, ----] _ IO.GetTokenRope[f, NATBreakProc !IO.EndOfStream => {end _ TRUE; CONTINUE}]; IF end THEN {n _ 1; RETURN}; n _ Convert.IntFromRope[intRope]; }; ReadBlankAndNAT: PUBLIC PROC [f: IO.STREAM] RETURNS [n: NAT] = { <> ReadBlank[f]; n _ ReadNAT[f]; }; ReadReal: PUBLIC PROC [f: IO.STREAM] RETURNS [r: REAL] = { <, or . Leaves these terminators on the stream.>> RealBreakProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = TRUSTED { SELECT char FROM '), '], ', => RETURN [break]; IO.CR =>RETURN [break]; IO.SP => RETURN [break]; ENDCASE => RETURN [other]; }; realText, buffer: REF TEXT; end: BOOL _ FALSE; buffer _ RefText.ObtainScratch[50]; [realText, ----] _ IO.GetToken[f, RealBreakProc, buffer !IO.EndOfStream => {end _ TRUE; CONTINUE}]; IF end THEN {r _ 0.0; RETURN}; IF RefText.Find[realText, ".", 0, FALSE] = -1 THEN realText _ RefText.Append[realText, ".0"]; r _ Convert.RealFromRope[RefText.TrustTextAsRope[realText]]; RefText.ReleaseScratch[buffer]; }; ReadBlankAndReal: PUBLIC PROC [f: IO.STREAM] RETURNS [r: REAL] = { <> ReadBlank[f]; r _ ReadReal[f]; }; ReadColor: PUBLIC PROC [f: IO.STREAM, version: REAL] RETURNS [color: Color] = { s: IO.STREAM; word: Rope.ROPE; isBlackToner, good: BOOL; IF version < 8701.26 THEN { word _ ReadColorToken[f]; IF Rope.Equal[word, "none"] THEN RETURN[NIL]; s _ IO.RIS[word, colorStream]; ReadChar[s, '[]; } ELSE { word _ ReadBracketedExpression[f]; IF word = NIL THEN RETURN[NIL]; s _ IO.RIS[word, colorStream]; }; IF version >= 8701.26 THEN { [isBlackToner, good] _ ReadBOOL[s, version]; IF NOT good THEN ERROR; } ELSE isBlackToner _ FALSE; IF isBlackToner THEN { black: REAL; black _ ReadBlankAndReal[s]; color _ ImagerColor.ColorFromGray[black]; } ELSE { r, g, b: REAL; r _ ReadBlankAndReal[s]; IF version < 8701.26 THEN ReadChar[s, ',]; g _ ReadBlankAndReal[s]; IF version < 8701.26 THEN ReadChar[s, ',]; b _ ReadBlankAndReal[s]; color _ ImagerColor.ColorFromRGB[[r, g, b]]; }; IF version < 8701.26 AND ImagerColor.GrayFromColor[NARROW[color]] = 1.0 THEN color _ Imager.black; -- the default used to be "black toner" }; -- end of ReadColor ReadColorToken: PUBLIC PROC [f: IO.STREAM] RETURNS [word: Rope.ROPE] = { <, or are encountered.>> ColorBreakProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = CHECKED { SELECT char FROM IO.TAB => RETURN [break]; IO.CR =>RETURN [break]; IO.SP => RETURN [break]; ENDCASE => RETURN [other]; }; ReadBlank[f]; [word, ----] _ IO.GetTokenRope[f, ColorBreakProc !IO.EndOfStream => {word _ NIL; CONTINUE}]; }; ReadStrokeEnd: PUBLIC PROC [f: IO.STREAM] RETURNS [strokeEnd: Imager.StrokeEnd] = { endName: Rope.ROPE; ReadBlank[f]; endName _ ReadBlankAndWord[f]; SELECT TRUE FROM Rope.Equal[endName, "square", TRUE] => strokeEnd _ square; Rope.Equal[endName, "butt", TRUE] => strokeEnd _ butt; Rope.Equal[endName, "round", TRUE] => strokeEnd _ round; ENDCASE => ERROR; }; ReadPoint: PUBLIC PROC [f: IO.STREAM] RETURNS [point: Point] = { <,]".>> ReadBlank[f]; ReadRope[f, "["]; point.x _ ReadBlankAndReal[f]; ReadRope[f, ","]; point.y _ ReadBlankAndReal[f]; ReadRope[f, "]"]; }; ReadTransformation: PUBLIC PROC [f: IO.STREAM] RETURNS [transform: ImagerTransformation.Transformation] = { a, b, c, d, e, g: REAL; ReadBlankAndRope[f, "["]; a _ ReadBlankAndReal[f]; b _ ReadBlankAndReal[f]; c _ ReadBlankAndReal[f]; d _ ReadBlankAndReal[f]; e _ ReadBlankAndReal[f]; g _ ReadBlankAndReal[f]; ReadBlankAndRope[f, "]"]; transform _ ImagerTransformation.Create[a, b, c, d, e, g]; }; ReadFactoredTransformation: PUBLIC PROC [f: IO.STREAM] RETURNS [transform: ImagerTransformation.Transformation] = { <> <> <> r1, sx, sy, r2, tx, ty: REAL; ReadBlankAndRope[f, "[r1:"]; r1 _ ReadBlankAndReal[f]; ReadBlankAndRope[f, "s:"]; ReadBlankAndRope[f, "["]; sx _ ReadBlankAndReal[f]; sy _ ReadBlankAndReal[f]; ReadBlankAndRope[f, "]"]; ReadBlankAndRope[f, "r2:"]; r2 _ ReadBlankAndReal[f]; ReadBlankAndRope[f, "t:"]; ReadBlankAndRope[f, "["]; tx _ ReadBlankAndReal[f]; ty _ ReadBlankAndReal[f]; ReadBlankAndRope[f, "]"]; ReadBlankAndRope[f, "]"]; { OPEN ImagerTransformation; transform _ Cat[Rotate[r1], Scale2[[sx, sy]], Rotate[r2], Translate[[tx, ty]] ]; }; }; ReadBox: PUBLIC PROC [f: IO.STREAM] RETURNS [box: BoundBox] = { loX, loY, hiX, hiY: REAL; ReadBlankAndRope[f, "["]; loX _ ReadBlankAndReal[f]; loY _ ReadBlankAndReal[f]; hiX _ ReadBlankAndReal[f]; hiY _ ReadBlankAndReal[f]; ReadBlankAndRope[f, "]"]; IF loX = 0.0 AND hiX = -1.0 THEN RETURN[GGBoundBox.NullBoundBox[]]; IF loY = 0.0 AND hiY = -1.0 THEN RETURN[GGBoundBox.CreateBoundBox[0,0,0,0,FALSE,TRUE]]; box _ GGBoundBox.CreateBoundBox[loX, loY, hiX, hiY]; }; ReadBOOL: PUBLIC PROC [f: IO.STREAM, version: REAL] RETURNS [truth: BOOL, good: BOOL] = { <> BoolBreakProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = TRUSTED { SELECT char FROM '], IO.CR, IO.SP, '., ', => RETURN [break]; ENDCASE => RETURN [other]; }; end: BOOL _ FALSE; boolRope: Rope.ROPE; ReadBlank[f]; [boolRope, ----] _ IO.GetTokenRope[f, BoolBreakProc !IO.EndOfStream => {end _ TRUE; CONTINUE}]; IF end THEN {good _ FALSE; truth _ FALSE; RETURN}; good _ TRUE; IF version >= 8701.26 THEN { IF Rope.Equal[boolRope, "T", TRUE] THEN truth _ TRUE ELSE IF Rope.Equal[boolRope, "F", TRUE] THEN truth _ FALSE ELSE {truth _ FALSE; good _ FALSE}; } ELSE { IF Rope.Equal[boolRope, "TRUE", TRUE] THEN truth _ TRUE ELSE IF Rope.Equal[boolRope, "FALSE", TRUE] THEN truth _ FALSE ELSE {truth _ FALSE; good _ FALSE}; }; }; ReadListOfRope: PUBLIC PROC [f: IO.STREAM] RETURNS [ropeList: LIST OF Rope.ROPE] = { RopesOnOneLineOrParenProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = CHECKED { SELECT char FROM IO.CR, '), '] =>RETURN [break]; IO.SP, IO.TAB, ', , '; => RETURN [sepr]; ENDCASE => RETURN [other]; }; rope: Rope.ROPE; end: BOOL _ FALSE; ReadBlank[f]; ropeList _ NIL; WHILE TRUE DO [rope, ----] _ IO.GetTokenRope[f, RopesOnOneLineOrParenProc !IO.EndOfStream => {end _ TRUE; CONTINUE}]; IF end OR rope = NIL THEN RETURN; IF Rope.Equal[rope, Rope.FromChar[IO.CR]] THEN RETURN; IF Rope.Equal[rope, Rope.FromChar[')]] THEN { f.Backup[')]; RETURN; }; IF Rope.Equal[rope, Rope.FromChar[']]] THEN { f.Backup[']]; RETURN; }; ropeList _ AppendRopeToRopeList[rope, ropeList]; ENDLOOP; }; ReadBracketedExpression: PROC [f: IO.STREAM] RETURNS [expr: Rope.ROPE] = { CloseBracketProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = CHECKED { SELECT char FROM '] =>RETURN [break]; ENDCASE => RETURN [other]; }; end: BOOL _ FALSE; ReadChar[f, '[]; [expr, ----] _ IO.GetTokenRope[f, CloseBracketProc]; IF Rope.Equal[expr, "]"] THEN RETURN[NIL] ELSE ReadChar[f, ']]; }; RealLength: PROC [list: LIST OF Rope.ROPE] RETURNS [n: INT _ 0] = { UNTIL list = NIL DO n _ n+1; list _ list.rest; ENDLOOP; }; ReadArrayOfReal: PUBLIC PROC [f: IO.STREAM] RETURNS [reals: SequenceOfReal] = { <> ropeList: LIST OF Rope.ROPE; real: REAL; len, index: NAT; ReadBlankAndRope[f, "["]; ropeList _ ReadListOfRope[f]; ReadBlankAndRope[f, "]"]; len _ RealLength[ropeList]; reals _ NEW[SequenceOfRealObj[len]]; index _ 0; FOR list: LIST OF Rope.ROPE _ ropeList, list.rest UNTIL list = NIL DO real _ Convert.RealFromRope[list.first ! Convert.Error => {ERROR SyntaxError[position: IO.GetIndex[f], wasThere: IO.PutFR["Couldn't convert %g to a REAL", [rope[list.first]]], notThere: NIL]}]; reals[index] _ real; index _ index + 1; ENDLOOP; }; AppendRopeToRopeList: PROC [rope: Rope.ROPE, list: LIST OF Rope.ROPE] RETURNS [LIST OF Rope.ROPE] = { <> z: LIST OF Rope.ROPE _ list; IF z = NIL THEN RETURN[CONS[rope,NIL]]; UNTIL z.rest = NIL DO z _ z.rest; ENDLOOP; z.rest _ CONS[rope,NIL]; RETURN[list]; }; colorStream: IO.STREAM; Init: PROC [] = { colorStream _ IO.RIS["This string is longer than any color is likely to be."]; }; Init[]; END.