home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / TURBOPAS / XREFTP.ZIP / XREFTP.PAS
Encoding:
Pascal/Delphi Source File  |  1985-12-28  |  28.5 KB  |  812 lines

  1. {$C-,I-,V-,R-,K-}
  2. {++++++++++++++++++++++++++++++++++++++++++++++++++++++++}
  3. {+                                                      +}
  4. {+  PROGRAM TITLE:      Cross Reference Generator       +}
  5. {+                                                      +}
  6. {+  WRITTEN BY:         Peter Grogono                   +}
  7. {+  DATE WRITTEN:       ?                               +}
  8. {+                                                      +}
  9. {+  MODIFIED BY:        Bill Hogan                      +}
  10. {+  LAST MODIFICATION:  7/7/85                          +}
  11. {+                                                      +}
  12. {+  SUMMARY:                                            +}
  13. {+      1. Output Files:                                +}
  14. {+         a. first output file is a numbered listing   +}
  15. {+            of the input source                       +}
  16. {+         b. second output file is cross reference     +}
  17. {+            with each identifier followed by the      +}
  18. {+            line numbers on which it appears.         +}
  19. {+      2. Listing Device:                              +}
  20. {+         The numbered source listing may optionally   +}
  21. {+         be routed to the screen or printer (but not  +}
  22. {+         both).                                       +}
  23. {+                                                      +}
  24. {+  MODIFICATION RECORD:                                +}
  25. {+      17-APR-84       -Modified for Turbo Pascal so   +}
  26. {+                       $ includes are supported       +}
  27. {+                                                      +}
  28. {+      7-July-85       -Modified to record line        +}
  29. {+                       numbers for procedure          +}
  30. {+                       and function blocks.           +}
  31. {+                                                      +}
  32. {+                                                      +}
  33. {+                                                      +}
  34. {+                                                      +}
  35. {++++++++++++++++++++++++++++++++++++++++++++++++++++++++}
  36. PROGRAM XREFG2;
  37. { Cross Reference Generator }
  38. CONST
  39.         alfa_length     =  15;
  40.         dflt_str_len    = 255;
  41.         entrygap        =    0;   { # of blank lines between line numbers}
  42.         heading         : string[23] = 'Cross-Reference Listing';
  43.         headingsize     =    3;   {number of lines for heading}
  44.         LLmax           = dflt_str_len;
  45.         MaxOnLine       =   8;
  46.         Maxlines        = MAXINT; {longest document permitted}
  47.         MaxWordlen      = alfa_length;{longest word read without truncation}
  48.         Maxlinelen      =   79;   {length of output line}
  49.         MaxOnPage       =   60;   {size of output page}
  50.         NumKeys         =   70;   {number of Pascal reseve words}
  51.                                   {Read your Pascal manuals on this one!}
  52.         NumberWidth     =    6;
  53.         space           : char = ' ';
  54.                                       { Added by Bill Hogan 7-7-85}
  55.         MaxProLine      = 100;   {Clips lines for procedure summary to save dynamic record space}
  56.                                        {End of Block Added 7-7-85}
  57. TYPE
  58.         ALFA    = string[alfa_length];
  59.         CHARNAME = (lletter, uletter, digit, blank, quote, atab,
  60.                       EndOfLine, FileMark, otherchar );
  61.         CHARINFO = RECORD
  62.                      name : charname;
  63.                      valu : CHAR
  64.                    END;
  65.         COUNTER = 1..Maxlines;
  66.         pageindex = BYTE;
  67.         Wordindex = 1..MaxWordlen;
  68.         Queuepointer = ^Queueitem;
  69.         Queueitem = RECORD
  70.                         linenumber : counter;
  71.                         NextInQueue: Queuepointer
  72.                     END;
  73.         EntryType = RECORD
  74.                         Wordvalue : alfa;
  75.                         FirstInQueue,
  76.                         lastinQueue: Queuepointer
  77.                      END;
  78.         treepointer = ^node;
  79.         node = RECORD
  80.                  entry : EntryType;
  81.                  left,
  82.                  right : treepointer
  83.                END;
  84.         GenStr  = string[255];
  85.                                       { Added by Bill Hogan 7-7-85}
  86.         ProcedurePointer = ^BlockRead;
  87.         BlockRead = Record
  88.                       Line       : String[MaxProLine];
  89.                       BeginLine  : Counter;
  90.                       EndLine    : Counter;
  91.                       BeginCount,
  92.                       RecordCount,
  93.                       CaseCount  : Integer;
  94.                       EndCount   : Integer;
  95.                       Last       : ProcedurePointer;
  96.                     End;
  97.         ProcedureQueuePointer = ^ProcedureQueueItem;
  98.         ProcedureQueueItem = Record
  99.                                QueueItem : ProcedurePointer;
  100.                                Next      : ProcedureQueuePointer;
  101.                              End;
  102.  
  103.                                     {End of Block Added 7-7-85}
  104. VAR
  105.   bell          : CHAR;
  106.   fatal_error   : BOOLEAN;
  107.   FILE_ID,                      { Input file name }
  108.   PRN_ID,                       { basic file name + '.PRN' }
  109.   New_ID        : string[20];   { basic file name + '.XRF' }
  110.   form_feed     : CHAR;
  111.   Key           : ARRAY[1..NumKeys] OF alfa;
  112.   LISTING       : BOOLEAN;
  113.   tab           : CHAR;
  114.   WordTree      : treepointer;
  115.   GAP           : char      ;
  116.   Currentline: INTEGER;
  117.   FOUT: TEXT; { print output file }
  118.   XOUT: TEXT; { xref  output file }
  119.                                       { Added by Bill Hogan 7-7-85}
  120.   FOUTLineCount : integer;
  121.   CurrentProcedure : ProcedurePointer;
  122.   FirstProcedureQueue,CurrentProcedureQueue : ProcedureQueuePointer;
  123.                                       {End of Block Added 7-7-85}
  124.  
  125. PROCEDURE PAGE(VAR fx: TEXT);
  126. BEGIN
  127.   WRITELN(fx);
  128.   WRITE(fx, form_feed);
  129. END;
  130.  
  131. { FUNCTYPE:                                                        }
  132. { Do binary search for keyword in 'key' list.  If found, return    }
  133. { TRUE, else FALSE.                                                }
  134. Function Find_in_Reserve(var kword: alfa) : boolean;
  135. Label Return;
  136. Var
  137.     low, high, mid : integer;
  138. Begin
  139.     low  := 1;
  140.     high := NUMKEYS;
  141.     while (low <= high) do begin
  142.         mid := (low+high) div 2;
  143.         if kword < key[mid] then
  144.             high := mid - 1
  145.         else if kword > key[mid] then
  146.             low  := mid + 1
  147.         else begin
  148.             Find_in_Reserve := TRUE;
  149.             goto Return;
  150.             end;
  151.         end;
  152.     Find_in_Reserve := FALSE;
  153. Return:
  154. End;
  155.  
  156. PROCEDURE BuildTree(VAR tree: treepointer; VAR INFILE: GenStr);
  157. VAR
  158.   CurrentWord : alfa;
  159.   FIN : TEXT; { local input file }
  160.   currchar,                     { Current operative character }
  161.   nextchar      : charinfo;     { Look-ahead character }
  162.   flushing      : (KNOT, DBL, STD, LIT, SCANFN, SCANFN2);
  163.   fname         : string[30];
  164.   DoInclude     : boolean; { TRUE if we discovered include file }
  165.   fbuffer       : string[255];  { Format buffer - before final Print }
  166.   LineIn        : string[255];
  167.   LineInLast    : string[255];
  168.   cp            : 0..255;
  169.   xeof,                 { EOF status AFTER a read }
  170.   xeoln         : BOOLEAN;      { EOLN status after a read }
  171.   FirstChar     : integer;      { Cleans up Printout in BuildTree, Bill Hogan 7-7-85}
  172.  
  173.    PROCEDURE Entertree(VAR subtree: treepointer;
  174.                            Word   : alfa;
  175.                            line   :counter);
  176.    VAR
  177.      nextitem : Queuepointer;
  178.    BEGIN
  179.      IF subtree=nil THEN
  180.        BEGIN {create a new entry}
  181.          NEW(subtree);
  182.          WITH subtree^ DO BEGIN
  183.            left := nil;
  184.            right := nil;
  185.            WITH entry DO BEGIN
  186.              Wordvalue := Word;
  187.              NEW(FirstInQueue);
  188.              LastinQueue := FirstInQueue;
  189.              WITH FirstInQueue^ DO BEGIN
  190.                 linenumber := line;
  191.                 NextInQueue := nil;
  192.              END;{WITH FirstInQueue}
  193.            END;{WITH entry}
  194.          END;{WITH subtree}
  195.        END {create a new entry}
  196.      ELSE {append a list item}
  197.        WITH subtree^, entry DO
  198.          IF Word=Wordvalue THEN
  199.            BEGIN
  200.              IF lastinQueue^.linenumber <> line THEN
  201.                 BEGIN
  202.                   NEW(nextitem);
  203.                   WITH Nextitem^ DO BEGIN
  204.                     linenumber := line;
  205.                     NextInQueue := nil;
  206.                   END;{WITH}
  207.                   lastinQueue^.NextInQueue := Nextitem;
  208.                   lastinQueue := nextitem;
  209.                 END;
  210.            END
  211.          ELSE
  212.            IF Word < Wordvalue THEN
  213.              Entertree(left,Word,line)
  214.            ELSE
  215.              Entertree(right,Word,line);
  216.    END;{Entertree}
  217.  
  218. Procedure ReadC({updating} VAR nextchar : charinfo;
  219.                 {returning}VAR currchar : charinfo );
  220. Var
  221.   Look          : char; { Character read in from File }
  222. BEGIN   {+++ File status module. +++
  223.    Stores file status "AFTER" a read.
  224.    NOTE this play on words - after one char is
  225.    actually "PRIOR TO" the next character               }
  226.   if xeoln then begin
  227.      LineInLast := LineIn;
  228.      if (not EOF(FIN)) then begin
  229.         readln(FIN, LineIn);
  230.         cp := 0;
  231.         xeoln := FALSE;
  232.         end
  233.       else
  234.         xeof := TRUE;
  235.       end;
  236.   if cp >= length(LineIn) then begin
  237.      xeoln := TRUE;
  238.      xeof  := EOF(FIN);
  239.      Look  := ' ';
  240.      end
  241.   else begin
  242.      cp := cp + 1;
  243.      Look := LineIn[cp];
  244.      End;
  245.         {+++ current operative character module +++}
  246.   currchar := nextchar;
  247.         {+++ Classify the character just read +++}
  248.   WITH nextchar DO BEGIN{ Look-ahead character name module }
  249.     IF xeof THEN
  250.         name := FileMark
  251.     ELSE IF xeoln THEN
  252.         name := EndOfLine
  253.     ELSE IF Look IN ['a'..'z'] THEN {lower case plus}
  254.         name := lletter
  255.     ELSE IF Look IN ['^','$','_','A'..'Z'] THEN {upper case}
  256.         name := uletter
  257.     ELSE IF Look IN ['0'..'9'] THEN {digit}
  258.         name := digit
  259.     ELSE IF Look = '''' THEN
  260.         name := quote
  261.     ELSE IF Look = TAB THEN
  262.         name := atab
  263.     ELSE IF Look = space THEN
  264.         name := blank
  265.     ELSE
  266.         name := otherchar;
  267.     CASE name of{ store character value module }
  268.         EndOfLine,
  269.         FileMark:       Valu := space;
  270.         lletter:        Valu := upcase(look);       { Cnvrt to uppcase }
  271.         ELSE            valu := look;
  272.     END{ case name of };
  273.   End{ Look-ahead character name module };
  274. END; {of ReadC}
  275.  
  276. PROCEDURE GetL( VAR fbuffer :  GenStr      );
  277. {++++++++++++++++++++++++++++++++++++++++++++++++++++++++}
  278. {+      Get a line of text into users buffer.           +}
  279. {+      Flushes comment lines:                          +}
  280. {+      Flushes lines of Literals:  'this is it'        +}
  281. {+      Ignores special characters & tabs:              +}
  282. {+      Recognizes End of File and End of Line.         +}
  283. {+                                                      +}
  284. {+GLOBAL                                                +}
  285. {+      flushing : (KNOT, DBL, STD, LIT, SCANFN);       +}
  286. {+      LLmax   = 0..Max Line length;                   +}
  287. {++++++++++++++++++++++++++++++++++++++++++++++++++++++++}
  288. VAR
  289.   state : (scanning, terminal, overflow);
  290.   sawdot : boolean;
  291. BEGIN { GetL }
  292.    fbuffer := '';
  293.    fname := '';
  294.    fatal_error := FALSE;
  295.    state := scanning;
  296.   REPEAT
  297.     ReadC(nextchar, currchar);
  298.     IF (length(fbuffer) >= LLmax) THEN{ exceeded length of buffer }
  299.       BEGIN{ reset EOLN }
  300.         fatal_error := TRUE;
  301.         state := overflow;
  302.         fbuffer := '';
  303.         WRITE(bell);
  304.         WRITELN('EXCEEDED LENGTH OF INPUT BUFFER');
  305.       END
  306.     ELSE
  307.       BEGIN
  308.         IF (currchar.name IN [FileMark,EndOfLine]) THEN
  309.           state:=terminal{ END of line or END of file };
  310.         CASE flushing of
  311.             KNOT:
  312.                 CASE currchar.name of
  313.                 lletter, uletter, digit, blank:
  314.                         BEGIN{ store }
  315.                         fbuffer := concat(FBUFFER,CURRCHAR.VALU) ;
  316.                         END;
  317.                 atab, quote, otherchar:
  318.                         BEGIN{   Flush comments -convert
  319.                                  tabs & other chars to spaces }
  320.                         IF (currchar.valu='(') and (nextchar.valu='*')
  321.                           THEN flushing := DBL
  322.                         ELSE IF (currchar.valu='{') THEN
  323.                            flushing := STD
  324.                         ELSE IF currchar.name=quote THEN
  325.                            flushing := LIT;
  326.                         { convert to a space }
  327.                            fbuffer := concat(fbuffer,GAP);
  328.                         END;
  329.                 ELSE         { END of line -or- file mark }
  330.                         fbuffer := concat(fbuffer,currchar.valu)
  331.                 END{ case currchar name of };
  332.             DBL:  { scanning for a closing  - double comment }
  333.                 IF (currchar.valu ='*') and (nextchar.valu =')')
  334.                   THEN flushing := KNOT;
  335.             STD:  begin { scanning for a closing curley  }
  336.                   IF currchar.valu = '}' THEN
  337.                       flushing := KNOT;
  338. { Check if incl } if (currchar.valu = '$') and (nextchar.valu = 'I') then
  339.                       flushing := SCANFN;
  340.                   end;
  341.             LIT:  { scanning for a closing quote }
  342.                   IF currchar.name = quote THEN
  343.                     flushing := KNOT;
  344.             SCANFN: if (nextchar.valu<>' ') and (nextchar.valu<>TAB) then
  345.                     begin
  346.                     flushing := SCANFN2;
  347.                     SAWDOT := FALSE;
  348.                     end;
  349.             SCANFN2: if (currchar.valu in ['A'..'Z','0'..'9','.'])
  350.                      then begin
  351.                         fname := concat(fname, currchar.valu);
  352.                         if currchar.valu = '.' then SAWDOT := TRUE;
  353.                         end
  354.                      else begin
  355.                         if length(fname) = 0 then  { Make sure we ignore $I-}
  356.                            DoInclude := FALSE      { compiler directive }
  357.                         else begin
  358.                            if not SAWDOT then fname := Concat(fname, '.PAS');
  359.                            DoInclude := TRUE;
  360.                            end;
  361.                         flushing := STD;
  362.                         end;
  363.         END{ flushing case }
  364.       END{ ELSE }
  365.   UNTIL (state<>scanning);
  366. END; {of GetL}
  367.  
  368.  
  369.                                       { Added by Bill Hogan 7-7-85}
  370.  
  371. PROCEDURE EnterNewProcedure; {Build Block to save line addresses of procedures,functions}
  372. VAR
  373.      LastProcedure : ProcedurePointer;
  374.      LastProcedureQueue : ProcedureQueuePointer;
  375. BEGIN
  376.      LastProcedure:=CurrentProcedure;
  377.      NEW(CurrentProcedure);
  378.      With CurrentProcedure^ do
  379.      Begin
  380.           Str(CurrentLine,Line);
  381.           Line := Line+': '+LineInLast;
  382.           BeginLine:= 1;
  383.           EndLine:=1;
  384.           BeginCount:=0;RecordCount:=0;CaseCount:=0;
  385.           EndCount:=0;
  386.           Last:=LastProcedure;
  387.      end;
  388.      LastProcedureQueue:=CurrentProcedureQueue;
  389.      NEW(CurrentProcedureQueue);
  390.      LastProcedureQueue^.Next := CurrentProcedureQueue;
  391.      CurrentProcedureQueue^.QueueItem := CurrentProcedure;
  392.      CurrentProcedureQueue^.Next:=NIL;
  393. END; {EnterNewProcedure}
  394.  
  395. PROCEDURE UpdateProcedureEndBlock;
  396. VAR
  397.      TotalBlocks : Integer;
  398.      ReturningProcedure : ProcedurePointer;
  399. BEGIN
  400.      ReturningProcedure:=CurrentProcedure;
  401.      With CurrentProcedure^ do
  402.      Begin
  403.           TotalBlocks:=BeginCount+RecordCount+CaseCount;
  404.           EndCount:=EndCount+1;
  405.           If (EndCount=TotalBlocks) then
  406.           If (BeginCount+CaseCount>0) then {Allows Functions without Begins but only cases}
  407.           begin
  408.                EndLine:=CurrentLine;
  409.                ReturningProcedure := Last;
  410.           end;
  411.      End;
  412.      CurrentProcedure:=ReturningProcedure;
  413. END; {UpdateProcedureEndBlock}
  414.                                       {End of Block Added 7-7-85}
  415.  
  416. PROCEDURE ReadWord;
  417. {++++++++++++++++++++++++++++++++++++++++++++++++}
  418. {+                                              +}
  419. {+       Analyze the Line into "words"          +}
  420. {+                                              +}
  421. {++++++++++++++++++++++++++++++++++++++++++++++++}
  422. LABEL   1;
  423. VAR
  424.   ix,           {temp indexer}
  425.   idlen,        {length of the word}
  426.   Cpos : BYTE; { Current Position pointer }
  427. BEGIN{ ReadWord }
  428.   Cpos := 1; { start at the beginning of a line }
  429.   WHILE Cpos < length(fbuffer) DO
  430.     BEGIN {Cpos<length(fbuffer)}
  431.       WHILE (Cpos < length(fbuffer)) AND (fbuffer[Cpos]=space) DO
  432.         Cpos:=Cpos + 1;    {--- skip spaces ---}
  433.       idlen := 0;
  434.       WHILE (Cpos < length(fbuffer)) AND (fbuffer[Cpos ] <> space) DO
  435.         BEGIN{ accept only non-spaces }
  436.           IF idlen < MaxWordlen THEN
  437.             BEGIN
  438.               idlen := idlen + 1;
  439.               CurrentWord[idlen] := fbuffer[Cpos];
  440.             END;
  441.           Cpos := Cpos +1;
  442.         END{ WHILE };
  443.       CurrentWord[0] := chr(idlen);
  444.       IF length(CurrentWord)=0 THEN {no word was found} GOTO 1;
  445.  
  446.       IF (not Find_in_Reserve(CurrentWord)) and    {check if reserved word}
  447.          (not (CurrentWord[1] in ['0'..'9'])) then {or numeric constant}
  448.          EnterTree(tree,CurrentWord,Currentline);
  449.  
  450.                                       { Added by Bill Hogan 7-7-85}
  451.  
  452.       IF (CurrentWord='PROCEDURE') or (CurrentWord='FUNCTION')
  453.                            then EnterNewProcedure;
  454.  
  455.       With CurrentProcedure^ do
  456.       Begin
  457.            IF (CurrentWord='FORWARD') then
  458.              begin
  459.                 IF (BeginCount=0) then BeginLine:=CurrentLine;
  460.                 BeginCount:=BeginCount+1; {Recognize and skip forward references}
  461.                 UpdateProcedureEndBlock;
  462.              end;
  463.  
  464.            IF (CurrentWord='BEGIN') then
  465.              begin
  466.                 IF (BeginCount=0) then BeginLine:=CurrentLine;
  467.                 BeginCount:=BeginCount+1;
  468.              end;
  469.            IF (CurrentWord='CASE') then CaseCount:=CaseCount+1;
  470.  
  471.            IF (CurrentWord='RECORD') then RecordCount:=RecordCount+1;
  472.  
  473.            IF (CurrentWord='END') then UpdateProcedureEndBlock;
  474.       end;
  475.                                       {End of Block Added 7-7-85}
  476.  
  477.      1:{Here is no word <length of word=0>};
  478.     END; {WHILE Cpos<length(fbuffer)}
  479. END; {of Readword}
  480.  
  481. BEGIN{BuildTree}
  482.    flushing := KNOT{ flushing };
  483.    DoInclude := FALSE;
  484.    xeoln := TRUE;
  485.    xeof  := FALSE;
  486.    LineIn := '';
  487.    ASSIGN(FIN,INFILE);
  488.    RESET(FIN);
  489.    IF IOresult <> 0 THEN
  490.       BEGIN
  491.         WRITE(BELL);
  492.         WRITELN('File ',INFILE,' not found !!!!!!');
  493.         fatal_error := TRUE;
  494.       END;
  495.      nextchar.name := blank;       { Initialize next char to a space }
  496.      nextchar.valu := space;
  497.      ReadC({update}    nextchar,   { Initialize current char to space }
  498.            {returning} currchar);  { First char from file in nextchar }
  499.      WHILE ((currchar.name<>filemark) AND (NOT fatal_error)) DO
  500.        BEGIN
  501.          Currentline := Currentline + 1;
  502.          GetL(fbuffer) { attempt to read the first line };
  503.          FirstChar:=1;
  504.          Writeln(Fout, Currentline:6,': ',Copy(LineInLast,FirstChar,MaxLineLen-8));
  505.          FOUTLineCount:=FOUTLineCount+1;
  506.          If FOUTLineCount>MaxOnPage then
  507.          begin
  508.               WRITE(FOUT,form_feed);
  509.               FOUTLineCount:=1;
  510.          end;
  511.          FirstChar:=FirstChar+MaxLineLen-8;
  512.                While (length(LineInLast)>=FirstChar) do
  513.                Begin
  514.                     WRITELN(FOUT,space:8,Copy(LineInLast,FirstChar,MaxLinelen-8));
  515.                     FirstChar:=FirstChar+MaxLinelen-8;
  516.                     FOUTLineCount:=FOUTLineCount+1;
  517.                     If FOUTLineCount>MaxOnPage then
  518.                     begin
  519.                          WRITE(Fout,form_feed);
  520.                          FOUTLineCount:=1;
  521.                     end;
  522.                end;
  523.          IF listing THEN  Writeln(Currentline:6,': ',LineInLast)
  524.          else if (Currentline mod 100) = 0 then
  525.            writeln('ON LINE : ',Currentline:0);
  526.          ReadWord; {Analyze the Text into single 'words' }
  527.          if DoInclude then Begin
  528.             Writeln(FOUT,' ***....Entering Include...*** ',fname);    {Line added by Bill Hogan 7/1/185}
  529.             FOUTLineCount:=FOUTLineCount+1;
  530.             BuildTree(tree, fname);  { recursively do include }
  531.             Writeln(FOUT,' ***....Finished Include...*** ',fname);    {Line added by Bill Hogan 7/1/185}
  532.             FOUTLineCount:=FOUTLineCount+1;
  533.             DoInclude := FALSE;
  534.             end;
  535.        END; {While}
  536.        close(FIN);
  537.  
  538. END; {of BuildTree}{CLOSE(PRN_ID);}
  539.  
  540. PROCEDURE PrintTree(tree: treepointer);
  541. {
  542. GLOBAL
  543.         MaxOnLine   = max line references per line
  544.         NumberWidth = field for each number
  545. }
  546. VAR
  547.   pageposition: pageindex;
  548.    PROCEDURE PrintEntry(subtree: treepointer;
  549.                         VAR position: pageindex);
  550.    VAR  ix: Wordindex;
  551.         itemcount : 0..Maxlinelen;
  552.         itemptr : Queuepointer;
  553.         PROCEDURE PrintLine(VAR Currentposition: pageindex;
  554.                                 newlines: pageindex);
  555.         VAR
  556.           linecounter: pageindex;
  557.         BEGIN
  558.           IF (Currentposition + newlines) < MaxOnPage THEN
  559.             BEGIN
  560.                 FOR linecounter:=1 TO newlines DO WRITELN(XOUT);
  561.                 Currentposition := Currentposition + newlines;
  562.             END
  563.           ELSE
  564.             BEGIN
  565.               PAGE(XOUT);
  566.               WRITELN(XOUT,heading);
  567.               FOR linecounter := 1 TO headingsize - 1 DO
  568.                  WRITELN(XOUT);
  569.               Currentposition := headingsize + 1;
  570.             END
  571.         END;{PrintLine}
  572.  
  573.    BEGIN{PrintEntry}
  574.      IF subtree<>nil THEN
  575.         WITH subtree^ DO BEGIN
  576.           PrintEntry(left,position);
  577.           PrintLine(position,entrygap + 1);
  578.           WITH entry DO BEGIN
  579.             FOR ix := 1 to length(WordValue) do WRITE(XOUT, WordValue[ix]);
  580.             WRITE(XOUT, space:(MaxWordLen-length(WordValue)));
  581.             itemcount := 0;
  582.             itemptr := FirstInQueue;
  583.             WHILE itemptr <> nil DO
  584.               BEGIN
  585.                 itemcount := itemcount + 1;
  586.                 IF itemcount > MaxOnLine THEN
  587.                   BEGIN
  588.                     PrintLine(position,1);
  589.                     WRITE(XOUT, space:MaxWordlen);
  590.                     itemcount := 1;
  591.                   END;
  592.                 WRITE(XOUT, itemptr^.linenumber: numberwidth);
  593.                 itemptr := itemptr^.NextInQueue;
  594.               END;{WHILE}
  595.           END; {WITH entry}
  596.           PrintEntry(right,position);
  597.         END; {WITH subtree^}
  598.    END; {PrintEntry}
  599.  
  600. BEGIN{PrintTree}
  601.   PagePosition := MaxOnPage;
  602.   PrintEntry(tree,PagePosition);
  603. END; {of PrintTree}{CLOSE(New_ID);}
  604.  
  605.  
  606.                                       { Added by Bill Hogan 7-7-85}
  607.  
  608. PROCEDURE PrintProcedureQueue;
  609. VAR
  610.    IterProcedureQueue : ProcedureQueuePointer;
  611.    LineCount,First : integer;
  612.  
  613.   Procedure Header;
  614.   Var
  615.      I : integer;
  616.   Begin
  617.      For I:=1 to 3 do Writeln(Xout);
  618.      WRITELN(XOUT,'Procedure Listing For ',FILE_ID,
  619.           ' (First ',MaxProline:4,' Chars. of Declaration)');
  620.      WRITELN(XOUT);
  621.      LineCount:=5;
  622.   end;
  623. BEGIN
  624.      Header;
  625.      IterProcedureQueue:=FirstProcedureQueue;
  626.      While not (IterProcedureQueue=NIL) do
  627.      With IterProcedureQueue^ do
  628.      begin
  629.           CurrentProcedure:=QueueItem;
  630.           With CurrentProcedure^ do
  631.           begin
  632.                First:=1;
  633.                While (length(Line)>=First) do
  634.                Begin
  635.                     IF (First=1) then WRITELN(XOUT,Copy(Line,First,MaxLinelen)) else
  636.                        WRITELN(XOUT,space:8,Copy(Line,First,MaxLinelen-8));
  637.                     If (First=1) then First:=First+MaxLinelen
  638.                     else First:=First+MaxLineLen-8;
  639.                     LineCount:=LineCount+1;
  640.                end;
  641.                WRITELN(XOUT,space:15,'[',BeginLine:6,' ] ...  to  ... [',EndLine:6,' ]');
  642.                LineCount:=LineCount+1;
  643.                If (LineCount>MaxOnPage) then
  644.                begin
  645.                     WRITE(XOUT,form_feed);
  646.                     Header;
  647.                end;
  648.                IterProcedureQueue:=Next;
  649.           end;
  650.      end;
  651.      Write(XOUT,form_feed);
  652. END; {PrintProcedureQueue}
  653.                                       {End of Block Added 7-7-85}
  654.  
  655. FUNCTION ConnectFiles: boolean;
  656. TYPE
  657.   Linebuffer = string[80];
  658. VAR
  659.   ix  : BYTE;
  660. BEGIN{ ConnectFiles }
  661.   fatal_error := FALSE;
  662.   ConnectFiles := TRUE;
  663.    WRITELN('Enter Complete Filenames') ;
  664.    WRITELN ;
  665.    WRITE('Input File: ');
  666.    READLN(FILE_ID);
  667.    WRITELN;
  668.    WRITE('Printed output: ');
  669.    READLN(PRN_ID);
  670.    WRITELN;
  671.    WRITE('Cross-Reference output: ');
  672.    READLN(NEW_ID);
  673.    WRITELN;
  674.    Assign(fout,PRN_ID);
  675.    Rewrite(FOUT);
  676.    if IOresult <> 0 then begin
  677.       writeln('Could not open ',PRN_ID,' (print output file).');
  678.       ConnectFiles := FALSE;
  679.       fatal_error  := TRUE;
  680.       end;
  681.   assign(xout,NEW_ID);
  682.   Rewrite(Xout) ;
  683.   if IOresult <> 0 then begin
  684.      writeln('Could not open ',NEW_ID,' (xref output file).');
  685.      ConnectFiles := FALSE;
  686.      fatal_error := TRUE;
  687.      end;
  688. END{ of ConnectFiles };
  689.  
  690. PROCEDURE Initialize;
  691. VAR
  692.   Ch: CHAR;
  693. BEGIN
  694.   bell := ^G; GAP := ' ' ;
  695.   Currentline := 0;
  696.  
  697.  
  698.                                       { Added by Bill Hogan 7-7-85}
  699.   FOUTLineCount:=1;
  700.   NEW(CurrentProcedure);
  701.      With CurrentProcedure^ do
  702.      Begin
  703.           Line :=' Main Program';
  704.           BeginLine:= 1;
  705.           EndLine:=MaxLines;
  706.           BeginCount:=0;RecordCount:=0;CaseCount:=0;
  707.           EndCount:=0;
  708.           Last:=NIL;
  709.      end;
  710.   NEW(CurrentProcedureQueue);
  711.   CurrentProcedureQueue^.QueueItem:=CurrentProcedure;
  712.   CurrentProcedureQueue^.Next:=NIL;
  713.   FirstProcedureQueue := CurrentProcedureQueue;
  714.                                       {End of Block Added 7-7-85}
  715.   IF ConnectFiles THEN
  716.     BEGIN
  717.         Key[ 1] := 'ABSOLUTE';
  718.         Key[ 2] := 'AND';
  719.         Key[ 3] := 'ARRAY';
  720.         Key[ 4] := 'ASSIGN';
  721.         Key[ 5] := 'BEGIN';
  722.         Key[ 6] := 'BOOLEAN';
  723.         Key[ 7] := 'BYTE';
  724.         Key[ 8] := 'CASE';
  725.         Key[ 9] := 'CHAIN';
  726.         Key[10] := 'CHAR';
  727.         Key[11] := 'CHR';
  728.         Key[12] := 'CLOSE';
  729.         Key[13] := 'CONCAT';
  730.         Key[14] := 'CONST';
  731.         Key[15] := 'COPY';
  732.         Key[16] := 'DELETE';
  733.         Key[17] := 'DIV';
  734.         Key[18] := 'DO';
  735.         Key[19] := 'DOWNTO';
  736.         Key[20] := 'ELSE';
  737.         Key[21] := 'END';
  738.         Key[22] := 'EOF';
  739.         Key[23] := 'EOLN';
  740.         Key[24] := 'EXECUTE';
  741.         Key[25] := 'EXIT';
  742.         Key[26] := 'EXTERNAL';
  743.         Key[27] := 'FALSE';
  744.         Key[28] := 'FILE';
  745.         Key[29] := 'FILLCHAR';
  746.         Key[30] := 'FOR';
  747.         Key[31] := 'FORWARD';
  748.         Key[32] := 'FUNCTION';
  749.         Key[33] := 'GOTO';
  750.         Key[34] := 'IF';
  751.         Key[35] := 'IN';
  752.         Key[36] := 'INLINE';
  753.         Key[37] := 'INPUT';
  754.         Key[38] := 'INTEGER';
  755.         Key[39] := 'LABEL';
  756.         Key[40] := 'LENGTH';
  757.         Key[41] := 'MOD';
  758.         Key[42] := 'NIL';
  759.         Key[43] := 'NOT';
  760.         Key[44] := 'OF';
  761.         Key[45] := 'OR';
  762.         Key[46] := 'ORD';
  763.         Key[47] := 'OUTPUT';
  764.         Key[48] := 'PACKED';
  765.         Key[49] := 'PROCEDURE';
  766.         Key[50] := 'PROGRAM';
  767.         Key[51] := 'REAL';
  768.         Key[52] := 'RECORD';
  769.         Key[53] := 'REPEAT';
  770.         Key[54] := 'SET';
  771.         Key[55] := 'SHL';
  772.         Key[56] := 'SHR';
  773.         Key[57] := 'STRING';
  774.         Key[58] := 'SUCC';
  775.         Key[59] := 'TEXT';
  776.         Key[60] := 'THEN';
  777.         Key[61] := 'TO';
  778.         Key[62] := 'TRUE';
  779.         Key[63] := 'TYPE';
  780.         Key[64] := 'UNTIL';
  781.         Key[65] := 'VAR';
  782.         Key[66] := 'WHILE';
  783.         Key[67] := 'WITH';
  784.         Key[68] := 'WRITE';
  785.         Key[69] := 'WRITELN';
  786.         Key[70] := 'XOR';
  787.         tab     := CHR(9);  { ASCII Tab character }
  788.         form_feed := CHR(12);  gap  := CHR(32);
  789.         WRITE('List file to console (Y/N)?: ');
  790.         READ(kbd,Ch);
  791.         LISTING := ( (Ch='Y') OR (Ch='y') );
  792.         WRITELN; WRITELN;
  793.     END; {IF ConnectFiles}
  794. END; {of Initialize}
  795.  
  796. BEGIN { Cross Reference }
  797.   CLRSCR;
  798.   WRITELN(' ':22, 'CROSS REFERENCE GENERATOR');
  799.   WRITELN;WRITELN;WRITELN;WRITELN;
  800.   Initialize;
  801.   IF NOT fatal_error THEN
  802.     BEGIN
  803.       WordTree := NIL;          {Make the Tree empty}
  804.       writeln('Pass 1 [Listing] Begins ...');BuildTree(WordTree, FILE_ID);
  805.       close(FOUT) ;
  806.       writeln('Pass 2 [Cross-Ref] Begins ...');PrintProcedureQueue;
  807.       PrintTree(WordTree);
  808.       close(XOUT);
  809.     END;
  810.   WRITELN;
  811. END. { Cross Reference }
  812.