-- GetTreeImpl.Mesa
-- written by Paxton. May 1981
-- last written by Paxton. August 24, 1982 10:39 am
-- each line of input file becomes a node
-- parent for line is the closest previous line with smaller indent
DIRECTORY
GetTree,
TextNode,
Rope,
RopeEdit,
RopeIO,
RopeReader,
File;
GetTreeImpl: CEDAR PROGRAM
IMPORTS TextNode, RopeEdit, RopeIO, RopeReader
EXPORTS GetTree =
BEGIN OPEN GetTree;
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: BOOLEANFALSE;
ReadLine: PROC RETURNS [ROPE] = { -- read line and set indent
tab: CHAR='I-100B;
space: CHAR=' ;
cr: CHAR='M-100B;
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] };
Start: PUBLIC PROC = {
};
END.