GGParseInImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last edited by Bier on January 29, 1986 11:33:00 pm PST
Last edited by Pier on February 16, 1987 6:40:57 pm PST
Contents: Routines for reading gargoyle data structures from a stream. Stolen from Solidviews Solidmodeler TFI3d.mesa.
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] = {
Reads, <SPACE>'s, <CR>'s, and <TAB>'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] = {
Reads, <SPACE>'s, <CR>'s, and <TAB>'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", "<whitespace>"];
};
ReadHorizontalBlank:
PUBLIC
PROC [f:
IO.
STREAM]
RETURNS [good:
BOOL] = {
Reads <SPACE>'s, and <TABS>'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] = {
Used to read in a rope which is data.
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] = {
Removes the given rope from the top of the stream. Used to remove formatting words and phrases from 3d files. We are not interested in these strings but only in the data in between them.
Signals SyntaxError if some other rope is on top.
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] = {
Reads a rope UNTIL <CR> 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 <CR>
};
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] = {
Reads a rope until a ':' or <CR> 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;
ReadBlank[f];
[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] = {
Reads digits up to the next ], <CR>, <SPACE>. 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] = {
A convenience function. Equivalent to ReadBlank[f]; n ← ReadNAT[f];
ReadBlank[f];
n ← ReadNAT[f];
};
ReadReal:
PUBLIC
PROC [f:
IO.
STREAM]
RETURNS [r:
REAL] = {
Reads digits up to the next ), ], <CR>, <SPACE> or <COMMA>. 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] = {
A convenience function. Equivalent to ReadBlank[f]; r ← ReadReal[f];
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] = {
Reads a rope until <SPACE>, <CR> or <TAB> 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] = {
Assumes the next rope on the stream will be of the form "[<real1>,<real2>]".
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];
};
ReadFactoredTransformationVEC:
PUBLIC
PROC [f:
IO.
STREAM]
RETURNS [transform: ImagerTransformation.Transformation] = {
FactoredTransformation: TYPE ~ RECORD[r1: REAL, s: VEC, r2: REAL, t: VEC];
Represents Cat[Rotate[r1], Scale2[s], Rotate[r2], Translate[t]].
Expects "[r1: REAL s: [REAL REAL] r2: REAL ]. No translation"
r1, sx, sy, r2 : 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, "]"];
{
OPEN ImagerTransformation;
transform ← Cat[Rotate[r1], Scale2[[sx, sy]], Rotate[r2]];
};
};
ReadFactoredTransformation:
PUBLIC
PROC [f:
IO.
STREAM]
RETURNS [transform: ImagerTransformation.Transformation] = {
FactoredTransformation: TYPE ~ RECORD[r1: REAL, s: VEC, r2: REAL, t: VEC];
Represents Cat[Rotate[r1], Scale2[s], Rotate[r2], Translate[t]].
Gargoyle file format "[r1: REAL s: [REAL REAL] r2: REAL t: [REAL REAL] ]"
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] = {
Tries to read T or F from the stream. If it encounters another word, good = FALSE;
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] = {
Reads a list of REALs enclosed in square brackets, separated by spaces, tabs, commas, or semi-colons. For instance [3.5, 2.6, 1, 4. 3.0 ] returns a list of 5 real numbers.
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] = {
A copy of List.Nconc1 for LIST OF Rope.ROPE instead of LIST OF REF ANY
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.