DIRECTORY Ascii USING [CR, SP, TAB], GetTree USING [], Rope USING [ROPE], RopeEdit USING [Substr], RopeIO USING [FromFile], RopeReader USING [FreeRopeReader, Get, GetIndex, GetRopeReader, ReadOffEnd, Ref, SetPosition], TextNode USING [NewTextNode, Node]; GetTreeImpl: CEDAR PROGRAM IMPORTS TextNode, RopeEdit, RopeIO, RopeReader EXPORTS GetTree = BEGIN OPEN GetTree; ROPE: TYPE = Rope.ROPE; Node: TYPE ~ TextNode.Node; ReadIndent: PUBLIC PROC [fileName: ROPE, tabIndent: NAT _ 4] RETURNS [root: Node] = { input: ROPE _ RopeIO.FromFile[fileName]; rdr: RopeReader.Ref _ RopeReader.GetRopeReader[]; maxOpen: NAT = 40; openNodes: ARRAY [0..maxOpen] OF Node; openIndents: ARRAY [0..maxOpen] OF INTEGER; level, lvl: NAT; indent: INTEGER; node: Node; noMoreInput: BOOL _ FALSE; ReadLine: PROC RETURNS [ROPE] = { -- read line and set indent tab: CHAR=Ascii.TAB; space: CHAR=Ascii.SP; cr: CHAR=Ascii.CR; start, end: INT _ 0; indent _ 0; DO SELECT RopeReader.Get[rdr ! RopeReader.ReadOffEnd => { noMoreInput _ TRUE; EXIT }] FROM cr => EXIT; -- blank line tab => indent _ indent+tabIndent; space => indent _ indent+1; 0C => { noMoreInput _ TRUE; EXIT }; -- stop at first NULL char ENDCASE => { -- just saw the first nonblank char on the line start _ RopeReader.GetIndex[rdr]-1; DO SELECT RopeReader.Get[rdr ! RopeReader.ReadOffEnd => { end _ RopeReader.GetIndex[rdr]; noMoreInput _ TRUE; EXIT }] FROM cr => { end _ RopeReader.GetIndex[rdr]-1; EXIT }; 0C => { end _ RopeReader.GetIndex[rdr]-1; noMoreInput _ TRUE; EXIT }; ENDCASE; ENDLOOP; EXIT }; ENDLOOP; RETURN [RopeEdit.Substr[input,start,end-start]] }; PlaceNode: PROC = { dest: Node; SELECT lvl FROM < level => { -- insert as sibling of node at lvl+1 dest _ openNodes[level _ lvl+1]; dest.last _ FALSE; node.next _ dest.next; dest.next _ node }; = maxOpen => { -- insert as sibling of node at max level dest _ openNodes[level]; dest.last _ FALSE; node.next _ dest.next; dest.next _ node }; ENDCASE => { -- increase level dest _ openNodes[level]; node.next _ dest; dest.child _ node; level _ level+1 }; node.last _ TRUE; openIndents[level] _ indent; openNodes[level] _ node }; RopeReader.SetPosition[rdr,input,0]; openNodes[0] _ root _ TextNode.NewTextNode[]; root.last _ TRUE; openIndents[0] _ -1; level _ 0; UNTIL noMoreInput DO node _ TextNode.NewTextNode[]; IF (node.rope _ ReadLine[])=NIL THEN indent _ MAX[0,openIndents[level]]; FOR lvl _ level, lvl-1 DO IF openIndents[lvl] < indent THEN { PlaceNode[]; EXIT }; ENDLOOP; ENDLOOP; RopeReader.FreeRopeReader[rdr]; }; END. RGetTreeImpl.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. written by Paxton. May 1981 Paxton. August 24, 1982 10:39 am Russ Atkinson, July 26, 1983 5:43 pm Doug Wyatt, August 28, 1986 5:41:07 pm PDT Each line of input file becomes a node (parent for line is the closest previous line with smaller indent). ΚŒ˜codešœ™Kšœ Οmœ7™BKšœ™Kšœ ™ K™$K™*—K˜Kšœj™jK˜šΟk ˜ Kš œžœžœžœžœ˜Kšœžœ˜Kšœžœžœ˜Kšœ žœ ˜Kšœžœ ˜Kšœ žœN˜^Kšœ žœ˜#—K˜KšΠbl œžœž˜Kšžœ'˜.Kšžœ˜Kšœžœžœ ˜K˜Kšžœžœžœ˜Kšœžœ˜K˜š Οn œžœžœ žœ žœžœ˜UKšœžœ˜(K˜1Kšœ žœ˜Kšœ žœžœ˜&Kšœ žœžœžœ˜+Kšœ žœ˜Kšœžœ˜K˜ Kšœ žœžœ˜K˜š  œžœžœžœΟc˜=Kšœžœžœ˜Kšœžœžœ˜Kšœžœžœ˜Kšœ žœ˜K˜ šžœžœ0˜9Kšœžœžœž˜ —Kšœžœ‘ ˜K˜!K˜Kšœžœžœ‘˜>šžœ‘/˜