DIRECTORY Parquet, TerminalIO USING [RequestRope, WriteRope], CDOrient USING [rotate90, rotate180, mirrorX, rotate270, ComposeOrient], FS USING [StreamOpen, Error], IO USING [STREAM, BreakProc, GetTokenRope, CharClass, EndOfStream, NUL, SP], Rope USING [ROPE, Fetch, Equal, Length]; PQuilt: CEDAR PROGRAM IMPORTS Parquet, TerminalIO, CDOrient, IO, FS, Rope = BEGIN PQuiltProc: Parquet.ModuleGeneratorProc = BEGIN BreakProc: IO.BreakProc = BEGIN IF char IN [IO.NUL .. IO.SP] THEN RETURN[sepr] ELSE RETURN[other]; END; fileName, token, tileSetName: Rope.ROPE; tile: Parquet.Tile; tiles: Parquet.Design; module: Parquet.Module; technology: Parquet.Technology; prevTile: Parquet.PlacedTile; -- the previous tile placed prevRow: Parquet.PlacedTile; -- the first tile in the previous row newRow: BOOL _ TRUE; orient: Parquet.Orientation _ Parquet.IdentityOrient; mirrorY: Parquet.Orientation _ CDOrient.ComposeOrient[CDOrient.ComposeOrient[CDOrient.rotate90, CDOrient.mirrorX], CDOrient.rotate270]; stream: IO.STREAM; endOfFile: BOOL _ FALSE; tileSetName _ TerminalIO.RequestRope["(PQuilt version 1) What file contains the tiles? "]; [tiles, technology, ] _ Parquet.ReadDesign[tileSetName]; IF tiles = NIL THEN BEGIN TerminalIO.WriteRope["Could not load tiles.\n"]; GOTO Punt; END; fileName _ TerminalIO.RequestRope["What file contains the array description? "]; stream _ FS.StreamOpen[fileName ! FS.Error => IF error.group = user THEN { TerminalIO.WriteRope["Could not open input file: '"]; TerminalIO.WriteRope[error.explanation]; TerminalIO.WriteRope["'.\n"]; GOTO Punt; }]; [module, prevTile] _ Parquet.NewModule[technology]; prevRow _ prevTile; DO [token, ] _ IO.GetTokenRope[stream, BreakProc !IO.EndOfStream => {endOfFile _ TRUE; CONTINUE} ]; IF endOfFile THEN BEGIN TerminalIO.WriteRope["PQuilt done.\n"]; RETURN[module]; END; SELECT TRUE FROM (Rope.Equal[token, "$NEWROW", FALSE]) => newRow _ TRUE; (Rope.Fetch[token, 0] = '#) => BEGIN newOrient: Parquet.Orientation _ Parquet.IdentityOrient; FOR i: INT IN [1..Rope.Length[token]) DO badMessage: BOOL _ FALSE; SELECT Rope.Fetch[token, i] FROM '= => newOrient _ CDOrient.ComposeOrient[newOrient, orient]; '1 => newOrient _ CDOrient.ComposeOrient[newOrient, CDOrient.rotate180]; '2 => newOrient _ CDOrient.ComposeOrient[newOrient, CDOrient.rotate90]; '9 => newOrient _ CDOrient.ComposeOrient[newOrient, CDOrient.rotate270]; 'x, 'X => newOrient _ CDOrient.ComposeOrient[newOrient, CDOrient.mirrorX]; 'y, 'Y => newOrient _ CDOrient.ComposeOrient[newOrient, mirrorY]; ENDCASE => BEGIN IF ~badMessage THEN BEGIN TerminalIO.WriteRope["Bad rotation specification: '"]; TerminalIO.WriteRope[token]; TerminalIO.WriteRope["' -- illegal characters ignored.\n"]; badMessage _ TRUE; END; END; ENDLOOP; orient _ newOrient; END; (TRUE) => BEGIN tile _ Parquet.GetTile[tiles, token]; IF tile = NIL THEN BEGIN TerminalIO.WriteRope["Could not find tile '"]; TerminalIO.WriteRope[token]; TerminalIO.WriteRope["'.\n"]; GOTO Punt; END; IF newRow THEN BEGIN prevRow _ prevTile _ Parquet.AdjacentTile[prevRow, tile, below, orient]; newRow _ FALSE; END ELSE prevTile _ Parquet.AdjacentTile[prevTile, tile, rightOf, orient]; END; ENDCASE; ENDLOOP; EXITS Punt => RETURN[NIL]; END; [] _ Parquet.RegisterCommand["PQuilt", PQuiltProc]; END. φFile: PQuilt.mesa Copyright c 1984 by Xerox Corporation. All rights reserved. Created by: Bob Mayo, July 20, 1984 4:20:05 pm PDT Last Edited by: Mayo, July 27, 1984 12:55:41 pm PDT -- This program forms a stream oriented interface to a subset of the Parquet operations. -- It can generate rectangular arrays. PQuilt reads tokens (things separated by white space) from the input file and assigns this interpretation to them: token = "$NEWROW" => Skip to a new row. token = #abcd => Set the current rotation according to the string abcd. All subsequent tiles will be placed using this orientation. The string may contain any number of characters, and a transform is constructed starting from an identity transform by scanning the characters left to right. An 'X' causes a mirror in x (x coordinates are flipped), a 'Y' does the same in y. A '9' rotates clockwise by 90 degrees, a '1' by 180 degrees, and a '2' by 270 degrees. An '=' stands for the current orientation before this token was read. Examples: #=x mirrors the current transform in X, #x sets the transform to be a mirror in x, and #9x sets the transform to a 90 degree rotation followed by a mirror in x. Also, # alone just sets the transform back to the identity transform, while #= is a no-op. token = anything else => Interpret the token as a tile name, and place that tile to the right of the last tile placed. If we just encounted a $NEWROW token instead place the tile below the first tile in the row above. -- user parameters -- state information -- constants -- misc -- query user for parameters -- initialize data structures -- main body of module generator -- pass result back to Parquet -- remember that Parquet's rotations are counter-clockwise -- register this generator with Parquet Κž˜– "Cedar" stylešœ™Jšœ Οmœ1™