GetTreeImpl.mesa
Copyright © 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).
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: BOOLFALSE;
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.