<>=
MODULE Tree;
  <Convenient constants>
  <Utility procedures>
  <Annotating the tree structure>
  <Producing the HTML output>
This code is written to a file (or else not used).

*
<Convenient constants>=
CONST
  StdFont = '<FONT FACE="ARIAL, GENEVA" SIZE=-1>',
  EndFont = '</FONT>';
Used above.

<Utility procedures>=
PROCEDURE EnclosingBlock(x);
  BEGIN
  IF x <> VOID THEN
    RESULT := x.Father;
    WHILE (RESULT <> VOID) AND NOT (RESULT IS StatementBlock) DO
      RESULT := RESULT.Father;
      END;
    END;
  END EnclosingBlock;  
Used above; next definition.

<Utility procedures>+=
PROCEDURE SubTreeImage (Bl, OnRoot);
  VAR
    a, l, Last, Child;
  BEGIN
  IF (#Bl.Ancest = 1) AND NOT OnRoot THEN
    a := "<A NAME=T" & Bl.Nr & ">" & Bl.Label & "</A>";
    a := a & " <A HREF=" & Bl.HRef & ">Go to source...</A>";
   ELSE
    a := Bl.Label;
    END;
  RESULT := { a };
  Last := FALSE;
  FOR i := 1 TO #Bl.Children DO
    Child := Bl.Children [i];
    IF #Child.Ancest = 1 THEN
      l := SubTreeImage(Child, FALSE);
     ELSE
      l := { LocalRef(Child) };
      END;
    IF i = #Bl.Children THEN
      Last := TRUE;
      END;
    RESULT := RESULT & {"  +- " & l[1]};  
    FOR j := 2 TO #l DO
      IF Last THEN
        RESULT := RESULT & { "   " & l[j] };
       ELSE
        RESULT := RESULT & { "  |" & l[j] };
        END;
      END;    
    END;
  END SubTreeImage;
Used above; previous definition.

<Producing the HTML output>=
PROCEDURE DumpSubTree (Bl);
  VAR
    a;
  BEGIN
  a := SubTreeImage (Bl, TRUE);
  FOR IN a DO
    FILE1.WriteLn (X);
    END;
  END DumpSubTree;
Used above; next definition.

<Producing the HTML output>+=
PROCEDURE LocalRef (Bl);
  BEGIN
  RESULT := "<A HREF=#T" &  Bl.Nr & ">" & Bl.Label & "</A>";
  END LocalRef;
Used above; previous and next definitions.

<Producing the HTML output>+=
PROCEDURE DumpRoot (Bl);
  BEGIN
  FILE1.WriteLn ("<HR><A NAME=T", Bl.Nr, 
                   ">", StdFont, "Paragraph ", 
                       Bl.Label, EndFont, "</A>");
  FILE1.WriteLn (StdFont, "<A HREF=", Bl.HRef, "> (Goto source)</A>", EndFont);                     
  IF #Bl.Ancest > 0 THEN
    FILE1.WriteLn (StdFont, " used in:", EndFont, "<UL>");
    FOR x IN Bl.Ancest DO
      FILE1.WriteLn ("<LI>", StdFont, LocalRef (x), EndFont, "</LI>");
      END;
    FILE1.WriteLn ("</UL>");  
    END;
  IF #Bl.Children > 0 THEN
    FILE1.WriteLn ("<PRE>");  
    DumpSubTree (Bl);  
    FILE1.WriteLn ("</PRE>");  
    END;
  END DumpRoot;
Used above; previous and next definitions.

<Producing the HTML output>+=
PROCEDURE ProduceTreeOutput(FName);
  BEGIN
  AnnotateParagraphDependencies (ROOT);
  FILE1.Redirect (FName);
  FILE1.WriteLn ("<!RainCode Generated document>",
                 "<HTML><HEAD><TITLE>" & 
                     ROOT.SourceName & 
                 " - Tree representation</TITLE>",
                 "</HEAD><BODY>");
  FILE1.WriteLn ("<H2>", ROOT.SourceName, "</H2>");               
  FOR Bl IN ROOT.ProcedureDivision.Blocks | #X.Ancest= 0 DO
    DumpRoot (Bl);
    FILE1.WriteLn;
    END;
  FOR Bl IN ROOT.ProcedureDivision.Blocks | #X.Ancest > 1 DO
    DumpRoot (Bl);
    FILE1.WriteLn;
    END;
  FILE1.WriteLn ("</BODY></HTML>");  
  FILE1.Redirect;  
  END ProduceTreeOutput;
Used above; previous definition.

<Annotating the tree structure>=
PROCEDURE AnnotateParagraphDependencies (Root);
  VAR
    l, e;
  BEGIN
  IF NOT (Root CAN AnnotatedTree) THEN
    Root.AnnotatedTree := TRUE;
    FOR IN Root.ProcedureDivision.Blocks DO
      X.Ancest := {};
      X.Children := {};
      END;
    FOR p IN Root.SubNodes | (X IS PerformStatement) AND 
                             (X.Label <> VOID) DO
      l := Root.ProcedureDivision.FindBlock (p.Label.Image);
      e := EnclosingBlock(p);
      IF (l <> VOID) AND (e <> VOID) THEN
        ASSERT e IS StatementBlock;
        ASSERT l IS StatementBlock;
        l.Ancest := l.Ancest & {e};
        e.Children := e.Children & {l};
        END;
      END;
    FOR IN Root.ProcedureDivision.Blocks DO
      X.Ancest := LIST.Unique (X.Ancest | X <> VOID );
      X.Children := LIST.Unique(X.Children | X <> VOID);
      END;
    END;  
  END AnnotateParagraphDependencies;
Used above.