GetTreeImpl.mesa
Copyright © 1985 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, March 3, 1985 6:32:00 pm PST
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,
TextNode,
Rope,
RopeEdit,
RopeIO,
RopeReader;
GetTreeImpl: CEDAR PROGRAM
IMPORTS TextNode, RopeEdit, RopeIO, RopeReader
EXPORTS GetTree
= BEGIN OPEN GetTree;
ROPE: TYPE = Rope.ROPE;
Offset: TYPE = TextNode.Offset;
ReadIndent: PUBLIC PROC [fileName: ROPE, tabIndent: NAT ← 4] RETURNS [root: RefTextNode] = {
input: ROPE ← RopeIO.FromFile[fileName];
rdr: RopeReader.Ref ← RopeReader.GetRopeReader[];
maxOpen: NAT = 40;
openNodes: ARRAY [0..maxOpen] OF RefTextNode;
openIndents: ARRAY [0..maxOpen] OF INTEGER;
level, lvl: NAT;
indent: INTEGER;
node: RefTextNode;
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: Offset ← 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: RefTextNode;
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.