home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / TURBOPAS / ID_REF.ZIP / ID-REF.PAS next >
Encoding:
Pascal/Delphi Source File  |  1985-12-28  |  31.1 KB  |  1,075 lines

  1. { Identifier Cross-referencer - Copyright 1985 Lodestar Computing, Inc. }
  2. {$R-,V-}
  3. PROGRAM ident_cross_ref;
  4.  
  5.   { MODIFICATIONS:
  6.  
  7.     28 Jun 85 - Dap - Corrected for Pointers verses Control Chars
  8.     05 Jun 85 - Dap - Corrected for hexidecimal numers
  9.     22 Apr 85 - Dap - Find Match corrected for length
  10.     21 Apr 85 - Dap - Corrected for Turbos use of '#' & '$' for numbers
  11.     20 Oct 84 - Dap - Modified to run under Turbo Pascal
  12.     12 Oct 84 - Dap - Rewrite of original Xiu_Ref
  13.       Which was a Cross-referencer that handled UCSD Include files & Units
  14.     1976      - Nw  - Pascal Cross-reference program
  15.       "Algorithms + Data Structures = Programs" by Niklaus Wirth
  16.         Copyright 1976 by Prentice-Hall, Inc.
  17.       See pages 206 - 8 program crossref
  18.   }
  19.  
  20.   CONST
  21.                               { Version Control }
  22.     icr_name    = 'Identifier Cross Referencer';
  23.     icr_version = '[2.2e] 28 Jun 85';
  24.  
  25.     forever     = False; { How long this thing would go }
  26.  
  27.     sys_slop    = 200; { Leave a little space for the system     }
  28.  
  29.     bs  = #08; { Back space                           }
  30.     cr  = #13; { Carriage return                      }
  31.     ff  = #12; { Form feed                            }
  32.     nul = #00; { Null char - used to zero in fillchar }
  33.     tab = #09; { Tab horizontal                       }
  34.  
  35.     big_len     =  255; { Maximum string length                 }
  36.     name_len    =   12; { Maximum file name with volume info    }
  37.     digit_width =    5; { DIGITS PER NUMBER                     }
  38.     max_ln_num  = 9999; { MAX LINE NUMBER                       }
  39.     max_nst_lev =    1; { Maximum nesting level                 }
  40.     scrn_width  =   80; { Screen line width                     }
  41.     out_width   =  132; { Out device line width                 }
  42.     out_height  =   66; { Out device page height                }
  43.     out_border  =    4; { White space on top and bottom of page }
  44.     dot_max     =   70; { dot max per line                      }
  45.  
  46.   TYPE
  47.     char_set      = SET OF Char;
  48.     big_string    = String[big_len];
  49.     file_name     = String[name_len];
  50.     alpha         = String[1];
  51.  
  52.     nest_info     = ARRAY [0 .. max_nst_lev] OF { 0 is main file }
  53.       RECORD
  54.         cur_file  : file_name;
  55.         cur_block : Integer;
  56.         cur_byte  : Integer;
  57.         cur_line  : big_string;
  58.         in_file   : Text[2024]     { Specify 2K buffer size }
  59.       END;
  60.  
  61.                          { Pointers to Reference Data }
  62.  
  63.     item_ref      = ^item;
  64.     rsrv_ref      = ^rsrv;
  65.     word_ref      = ^word;
  66.  
  67.                          { Reference Data Structures }
  68.  
  69.     item          =
  70.       RECORD
  71.         ln_num : 0 .. max_ln_num;
  72.         next   : item_ref;
  73.       END;
  74.     rsrv          =
  75.       RECORD
  76.         bal   : -1 .. 1;
  77.         left  : rsrv_ref;
  78.         right : rsrv_ref;
  79.         key   : alpha;
  80.       END;
  81.     word          =
  82.       RECORD
  83.         first : item_ref;
  84.         last  : item_ref;
  85.         left  : word_ref;
  86.         right : word_ref;
  87.         key   : alpha;
  88.       END;
  89.  
  90.   VAR
  91.     done       : Boolean;
  92.     first_time : Boolean; { First time through program }
  93.  
  94.     comment_chars : char_set; { All the valid comment options   }
  95.     com_delimit   : char_set; { Delimiting chars for comments   }
  96.     com_opt_chars : char_set; { What options used for cross ref }
  97.     delimiters    : char_set;
  98.     ident_chars   : char_set;
  99.     lower_letters : char_set;
  100.     numbers       : char_set;
  101.     hexdigits     : char_set;
  102.     parse_chars   : char_set;
  103.     start_ident   : char_set;
  104.     upper_letters : char_set;
  105.  
  106.     ord_lwr_a : Integer;
  107.     
  108.     dit_cnt   : Integer;
  109.     dot_cnt   : Integer;
  110.     line_cnt  : Integer;
  111.     page_cnt  : Integer;
  112.     
  113.     heap      : ^Integer; { Pointer for memory management }
  114.  
  115.     item_bytes : Integer; { Number of 16 bit words for an item    }
  116.     rsrv_bytes : Integer; { Number of 16 bit words for a reserved }
  117.     word_bytes : Integer; { Number of 16 bit words for a word     }
  118.  
  119.     word_max  : Integer; { Longest word length   }
  120.  
  121.     nest_lev  : Integer;   { Current nesting level }
  122.     nesting   : nest_info; { Where at in what file }
  123.  
  124.     title    : big_string; { Heading of each page of listing }
  125.     out_name : big_string; { Output file name                }
  126.  
  127.     out_file : Text[2024]; { Specify 2K buffer size }
  128.  
  129.     rsrv_root : rsrv_ref; { Reserved rsrv identifier root }
  130.     rwrd_root : word_ref; { Reserved word identifier root }
  131.     word_root : word_ref; { Word     word identifier root }
  132.  
  133.   FUNCTION lower_ch ( ch : Char ) : Char;
  134.  
  135.     BEGIN { lower_ch }
  136.       IF ch IN upper_letters THEN
  137.         ch := Chr (Ord (ch) + ord_lwr_a);
  138.       lower_ch := ch
  139.     END;  { lower_ch }
  140.  
  141.   PROCEDURE lower_str (     in_str  : big_string;
  142.                         VAR out_str : big_string );
  143.  
  144.     VAR
  145.       i : Integer;
  146.  
  147.     BEGIN { lower_str }
  148.       out_str := in_str;
  149.       FOR i := 1 TO Length (in_str) DO
  150.         out_str[i] := lower_ch (in_str[i] );
  151.     END;  { lower_str }
  152.  
  153.   PROCEDURE upper_str (     in_str  : big_string;
  154.                         VAR out_str : big_string );
  155.  
  156.     VAR
  157.       i : Integer;
  158.  
  159.     BEGIN { upper_str }
  160.       out_str := in_str;
  161.       FOR i := 1 TO Length (in_str) DO
  162.         out_str[i] := upcase (in_str[i] );
  163.     END;  { upper_str }
  164.  
  165.   FUNCTION min ( a, b : Integer ) : Integer;
  166.  
  167.     BEGIN { min }
  168.       IF a < b THEN
  169.         min := a
  170.       ELSE
  171.         min := b
  172.     END;  { min }
  173.  
  174.   FUNCTION max ( a, b : Integer ) : Integer;
  175.  
  176.     BEGIN { max }
  177.       IF a > b THEN
  178.         max := a
  179.       ELSE
  180.         max := b
  181.     END;  { max }
  182.  
  183.   PROCEDURE init_dot ( message : big_string );
  184.  
  185.     BEGIN { init_dot }
  186.       WriteLn;
  187.       Write (message:(scrn_width + Length (message) ) DIV 2);
  188.       dit_cnt  := out_height;
  189.       dot_cnt  := dot_max;
  190.       line_cnt := 0;
  191.       page_cnt := 0;
  192.     END;  { init_dot }
  193.  
  194.   PROCEDURE term_dot;
  195.  
  196.     BEGIN { term_dot }
  197.       WriteLn;
  198.       WriteLn ('<', line_cnt:digit_width, '>');
  199.     END;  { term_dot }
  200.  
  201.   PROCEDURE dot;
  202.  
  203.     BEGIN { dot }
  204.       IF dot_cnt < dot_max THEN
  205.         dot_cnt := dot_cnt + 1
  206.       ELSE
  207.         BEGIN
  208.           dot_cnt := 1;
  209.           WriteLn;
  210.           Write ('<', line_cnt:digit_width, '>')
  211.         END;
  212.       line_cnt := line_cnt + 1;
  213.       Write ('.')
  214.     END;  { dot }
  215.  
  216.   PROCEDURE dit;
  217.  
  218.     BEGIN { dit }
  219.       IF dit_cnt < out_height - out_border THEN
  220.         dit_cnt := dit_cnt + 1
  221.       ELSE
  222.         BEGIN
  223.           page_cnt := page_cnt + 1;
  224.           Write (out_file, ff);
  225.           WriteLn (out_file);
  226.           WriteLn (out_file);
  227.           WriteLn (out_file, title, 'Page':15, page_cnt:3);
  228.           WriteLn (out_file);
  229.           dit_cnt := out_border
  230.         END
  231.     END;  { dit }
  232.  
  233.   PROCEDURE show_avail;
  234.  
  235.     BEGIN { show_avail }
  236.       WriteLn;
  237.       WriteLn ('Memory Available   :', MemAvail:7);
  238.     END;  { show_avail }
  239.  
  240.   PROCEDURE init_sys;
  241.  
  242.     PROCEDURE process_reserved_file;
  243.  
  244.       VAR
  245.         s       : big_string;
  246.         rebal   : Boolean;
  247.         in_file : Text;
  248.  
  249.       PROCEDURE add_reserved (     id    : big_string;
  250.                                VAR r     : rsrv_ref;
  251.                                VAR rebal : Boolean );
  252.  
  253.         VAR
  254.           r1 : rsrv_ref;
  255.           r2 : rsrv_ref;
  256.  
  257.         PROCEDURE new_reserved ( VAR r : rsrv_ref );
  258.  
  259.                      { Allocate memory for reserved word }
  260.  
  261.           VAR
  262.             valid : Integer;
  263.  
  264.           BEGIN { new_reserved }
  265.             valid := rsrv_bytes + Length (id) + 1;
  266.             GetMem (r, valid);
  267.             IF (valid = 0) OR (MemAvail <= sys_slop) THEN
  268.               BEGIN
  269.                 WriteLn;
  270.                 Write ('I''ve run out of internal memory. Program terminated.');
  271.                 done := True
  272.               END;
  273.           END;  { new_reserved }
  274.           
  275.         BEGIN { add_reserved }
  276.           IF r = Nil THEN
  277.             BEGIN
  278.               new_reserved (r);
  279.               IF NOT done THEN
  280.                 BEGIN
  281.                   rebal := True; { Check for rebalancing }
  282.                   WITH r^ DO
  283.                     BEGIN
  284.                       Move (id, key, Length (id) + 1);
  285.                       left  := Nil;
  286.                       right := Nil;
  287.                       bal   := 0
  288.                     END
  289.                 END
  290.             END
  291.           ELSE IF id = r^.key THEN
  292.             rebal := False
  293.           ELSE IF id < r^.key THEN
  294.             BEGIN
  295.               add_reserved (id, r^.left, rebal);
  296.               IF rebal THEN
  297.                 CASE r^.bal OF
  298.                   + 0 : r^.bal := - 1;
  299.                   + 1 :
  300.                     BEGIN
  301.                       r^.bal := 0;
  302.                       rebal  := False
  303.                     END;
  304.                   - 1 :
  305.                     BEGIN
  306.                       r1 := r^.left;
  307.                       IF r1^.bal = - 1 THEN
  308.                         BEGIN
  309.                           r^.left   := r1^.right;
  310.                           r1^.right := r;
  311.                           r^.bal    := 0;
  312.                           r         := r1
  313.                         END
  314.                       ELSE
  315.                         BEGIN
  316.                           r2        := r1^.right;
  317.                           r1^.right := r2^.left;
  318.                           r2^.left  := r1;
  319.                           r^.left   := r2^.right;
  320.                           r2^.right := r;
  321.                           IF r2^.bal = - 1 THEN
  322.                             r^.bal := + 1
  323.                           ELSE
  324.                             r^.bal := + 0;
  325.                           IF r2^.bal = + 1 THEN
  326.                             r1^.bal := - 1
  327.                           ELSE
  328.                             r1^.bal := + 0;
  329.                           r := r2
  330.                         END;
  331.                       r^.bal := 0;
  332.                       rebal  := False
  333.                     END
  334.                 END
  335.             END
  336.           ELSE { id > r^.key }
  337.             BEGIN
  338.               add_reserved (id, r^.right, rebal);
  339.               IF rebal THEN
  340.                 CASE r^.bal OF
  341.                   + 0 : r^.bal := + 1;
  342.                   - 1 :
  343.                     BEGIN
  344.                       r^.bal := 0;
  345.                       rebal  := False
  346.                     END;
  347.                   + 1 :
  348.                     BEGIN
  349.                       r1 := r^.right;
  350.                       IF r1^.bal = + 1 THEN
  351.                         BEGIN
  352.                           r^.right := r1^.left;
  353.                           r1^.left := r;
  354.                           r^.bal   := 0;
  355.                           r        := r1
  356.                         END
  357.                       ELSE
  358.                         BEGIN
  359.                           r2        := r1^.left;
  360.                           r1^.left  := r2^.right;
  361.                           r2^.right := r1;
  362.                           r^.right  := r2^.left;
  363.                           r2^.left  := r;
  364.                           IF r2^.bal = + 1 THEN
  365.                             r^.bal := - 1
  366.                           ELSE
  367.                             r^.bal := + 0;
  368.                           IF r2^.bal = - 1 THEN
  369.                             r1^.bal := + 1
  370.                           ELSE
  371.                             r2^.bal := + 0;
  372.                           r := r2
  373.                         END;
  374.                       r^.bal := 0;
  375.                       rebal  := False
  376.                     END
  377.                 END
  378.             END
  379.         END;  { add_reserved }
  380.  
  381.       BEGIN { process_reserved_file }
  382.         init_dot ('Processing Reserved Word File');
  383.         Assign (in_file, 'C:Resrv.Txt');
  384.         {$I-}
  385.         Reset (in_file);
  386.         {$I+}
  387.         IF IoResult <> 0 THEN
  388.           BEGIN
  389.             WriteLn;
  390.             WriteLn ('Reserved Word File not found.');
  391.             Halt
  392.           END
  393.         ELSE
  394.           BEGIN
  395.             WHILE NOT (Eof (in_file) OR done) DO
  396.               BEGIN
  397.                 ReadLn (in_file, s);
  398.                 upper_str (s, s);
  399.                 dot;
  400.                 add_reserved (s, rsrv_root, rebal)
  401.               END;
  402.             term_dot
  403.           END;
  404.         Close (in_file)
  405.       END;  { process_reserved_file }
  406.  
  407.     BEGIN { init_sys }
  408.       done       := False;
  409.       first_time := True;
  410.  
  411.       comment_chars :=
  412.         ['A', 'B', 'C', 'I', 'K', 'P', 'R', 'T', 'U', 'V', 'W', 'X',
  413.          'a', 'b', 'c', 'i', 'k', 'p', 'r', 't', 'u', 'v', 'w', 'x'];
  414.       com_delimit   := ['+', '-', ',', ' '];
  415.       com_opt_chars := ['I', 'P', 'T', 'i', 'p', 't'];
  416.       delimiters    :=
  417.         ['{', '}', '(', ')', '[', ']',
  418.          '+', '-', '*', '/', '<', '>', '=',
  419.          '.', ',', ':', ';', '^', ' ', '''', '#', '$'];  { 21 Apr 85 }
  420.       lower_letters := ['a' .. 'z'];
  421.       upper_letters := ['A' .. 'Z'];
  422.       numbers       := ['0' .. '9'];
  423.       hexdigits     := numbers + ['A' .. 'F', 'a' .. 'f'];
  424.       start_ident   := lower_letters + upper_letters ;
  425.       ident_chars   := start_ident + numbers + ['_'];
  426.       parse_chars   := ident_chars + delimiters;
  427.  
  428.       ord_lwr_a := Ord ('a') - Ord ('A');
  429.  
  430.       item_bytes := SizeOf (item);
  431.       rsrv_bytes := SizeOf (rsrv);
  432.       word_bytes := SizeOf (word);
  433.  
  434.       rsrv_root := Nil;
  435.       
  436.       ClrScr;
  437.       WriteLn (icr_name:(scrn_width + Length (icr_name) ) DIV 2,
  438.         icr_version:scrn_width - (scrn_width + Length (icr_name) ) DIV 2);
  439.       show_avail;
  440.       process_reserved_file;
  441.     END;  { init_sys }
  442.  
  443.   PROCEDURE init;
  444.  
  445.     PROCEDURE open_files;
  446.  
  447.       LABEL
  448.         exit;
  449.  
  450.       VAR
  451.         io_error : Integer;
  452.         f_name   : big_string;
  453.  
  454.       BEGIN { open_files }
  455.         WriteLn;
  456.         Write ('Process what file ? ');
  457.         ReadLn (f_name);
  458.         IF Length (f_name) = 0 THEN
  459.           BEGIN
  460.             done := True;
  461.             Goto exit
  462.           END;
  463.         upper_str (f_name, f_name);
  464.         IF (Pos ('.PAS', f_name) = 0) AND (Pos ('.', f_name) = 0) THEN
  465.           f_name := Concat (f_name, '.PAS');
  466.         WITH nesting[nest_lev] DO
  467.           BEGIN
  468.             Close (in_file);
  469.             {$I-}
  470.             Assign (in_file, f_name);
  471.             Reset (in_file);
  472.             {$I+}
  473.           END;
  474.         io_error := IoResult;
  475.         IF io_error = 0 THEN
  476.           nesting[nest_lev].cur_file := f_name
  477.         ELSE
  478.           BEGIN
  479.             WriteLn;
  480.             Write ('Unable to open ', f_name, ' due to I/O error #', io_error);
  481.             done := True;
  482.             Goto exit
  483.           END;
  484.         WriteLn;
  485.         Write ('To      what file ? ');
  486.         ReadLn (f_name);
  487.         IF Length (f_name) = 0 THEN
  488.           BEGIN
  489.             done := True;
  490.             Goto exit
  491.           END;
  492.         upper_str (f_name, f_name);
  493.         IF (Pos ('.LST', f_name) = 0) AND (Pos ('.', f_name) = 0) THEN
  494.           f_name := Concat (f_name, '.LST');
  495.         out_name := Concat (Copy (f_name, 1, Pos ('.', f_name) ), 'REF');
  496.         {$I-}
  497.         Assign (out_file, f_name);
  498.         Rewrite (out_file);
  499.         {$I+}
  500.         io_error := IoResult;
  501.         IF io_error <> 0 THEN
  502.           BEGIN
  503.             WriteLn;
  504.             Write ('Unable to open ', f_name, ' due to I/O error #', io_error);
  505.             done := True
  506.           END;
  507.         exit:
  508.       END;  { open_files }
  509.  
  510.     BEGIN { init }
  511.       word_max  := 0;
  512.  
  513.       rwrd_root := Nil;
  514.       word_root := Nil;
  515.  
  516.       nest_lev := 0;
  517.       FillChar (nesting, SizeOf (nesting), nul);
  518.       
  519.       IF first_time THEN
  520.         first_time := NOT first_time
  521.       ELSE
  522.         BEGIN
  523.           WriteLn;
  524.           WriteLn;
  525.           WriteLn (icr_name:(scrn_width + Length (icr_name) ) DIV 2,
  526.             icr_version:scrn_width - (scrn_width + Length (icr_name) ) DIV 2)
  527.         END;
  528.       open_files;
  529.       IF NOT done THEN
  530.         BEGIN
  531.           WriteLn;
  532.           Write ('Title : ');
  533.           ReadLn (title);
  534.           show_avail
  535.         END;
  536.     END;  { init }
  537.  
  538.   PROCEDURE cross_reference;
  539.  
  540.     VAR
  541.       end_file : Boolean;
  542.       end_line : Boolean;
  543.       
  544.       was_proc   : Boolean;
  545.       
  546.       i : Integer;
  547.       
  548.       in_line  : big_string;
  549.  
  550.     FUNCTION is_reserved ( id : big_string;
  551.                            r  : rsrv_ref ) : Boolean;
  552.  
  553.       VAR
  554.         found : Boolean;
  555.  
  556.       BEGIN { is_reserved }
  557.         upper_str (id, id);
  558.         found := False;
  559.         WHILE NOT found AND (r <> Nil) DO
  560.           IF      id < r^.key THEN
  561.             r := r^.left
  562.           ELSE IF id > r^.key THEN
  563.             r := r^.right
  564.           ELSE
  565.             found := True;
  566.         IF found THEN
  567.           IF (id = 'FUNCTION') OR (id = 'PROCEDURE') OR (id = 'PROGRAM') THEN
  568.             was_proc := True;
  569.         is_reserved := found
  570.       END;  { is_reserved }
  571.  
  572.     PROCEDURE fix_nest;
  573.  
  574.       BEGIN { fix_nest }
  575.         i := 1;
  576.         WITH nesting[nest_lev] DO
  577.           BEGIN
  578.             in_line  := in_line + ' ' + cur_line;
  579.             end_line := i >= Length (in_line)
  580.           END
  581.       END;  { fix_nest }
  582.  
  583.     PROCEDURE set_nest;
  584.  
  585.       BEGIN { set_nest }
  586.         WITH nesting[nest_lev] DO
  587.           cur_line := Copy (in_line, i, Length (in_line) - i + 1)
  588.       END;  { set_nest }
  589.  
  590.     PROCEDURE get_line;
  591.  
  592.       PROCEDURE put_line;
  593.  
  594.         PROCEDURE fix_tabs;
  595.  
  596.           CONST
  597.             tab_spaces : String[8] = '        ';
  598.  
  599.           VAR
  600.             x : Integer;
  601.             l : big_string;
  602.  
  603.           BEGIN { fix_tabs }
  604.             l       := in_line;
  605.             in_line := '';
  606.             FOR x := 1 TO Length (l) DO
  607.               IF l[x] = tab THEN
  608.                 in_line := in_line + Copy (tab_spaces, 1, 8 - (x - 1) MOD 8)
  609.               ELSE
  610.                 in_line := in_line + l[x]
  611.           END;  { fix_tabs }
  612.  
  613.         BEGIN { put_line }
  614.           IF Pos (tab, in_line) > 0 THEN
  615.             fix_tabs;
  616.           dit;
  617.           Write (out_file, line_cnt:digit_width, ':');
  618.           IF Length (in_line) > 0 THEN
  619.             Write (out_file, ' ', in_line);
  620.           WriteLn (out_file)
  621.         END;  { put_line }
  622.  
  623.       BEGIN { get_line }
  624.         i := 1;
  625.         WITH nesting[nest_lev] DO
  626.           BEGIN
  627.             REPEAT
  628.               ReadLn (in_file, in_line);
  629.               dot;
  630.               put_line;
  631.               end_line := Length (in_line) = 0;
  632.             UNTIL NOT end_line OR Eof (in_file);
  633.             IF Eof (in_file) THEN
  634.               IF nest_lev = 0 THEN
  635.                 end_file := True
  636.               ELSE
  637.                 BEGIN
  638.                   IF Length (in_line) > 0 THEN
  639.                     BEGIN
  640.                       WriteLn (out_file);
  641.                       dit
  642.                     END;
  643.                   WriteLn (out_file, '*** End of include file ', cur_file:name_len);
  644.                   dit;
  645.                   WriteLn;
  646.                   Write ('*** End of include file ', cur_file:name_len);
  647.                   dot_cnt := dot_max;
  648.                   Close (in_file);
  649.                   nest_lev := nest_lev - 1;
  650.                   fix_nest
  651.                 END
  652.           END
  653.       END;  { get_line }
  654.  
  655.     FUNCTION cur_ch : Char;
  656.  
  657.       BEGIN { cur_ch }
  658.         cur_ch := in_line[i]
  659.       END;  { cur_ch }
  660.       
  661.     FUNCTION next_ch : Char;
  662.       
  663.       BEGIN { next_ch }
  664.         IF i + 1 > Length (in_line) THEN
  665.           next_ch := cr
  666.         ELSE
  667.           next_ch := in_line[i + 1]
  668.       END;  { next_ch }
  669.  
  670.     FUNCTION next2_ch : Char; { 22 Apr 85 }
  671.  
  672.       BEGIN { next2_ch }
  673.         IF i + 2 > Length (in_line) THEN
  674.           next2_ch := cr
  675.         ELSE
  676.           next2_ch := in_line[i + 2]
  677.       END;  { next2_ch }
  678.  
  679.     PROCEDURE get_ch;
  680.  
  681.       BEGIN { get_ch }
  682.         IF i < Length (in_line) THEN
  683.           i := i + 1
  684.         ELSE
  685.           end_line := True
  686.       END;  { get_ch }
  687.  
  688.     PROCEDURE get_identifier;
  689.  
  690.       VAR
  691.         loc : Integer;
  692.         id  : big_string;
  693.  
  694.       PROCEDURE bomb;
  695.  
  696.         BEGIN { bomb }
  697.           term_dot;
  698.           WriteLn;
  699.           WriteLn ('I''ve run out of internal memory.',
  700.             ' Identifier Cross Referencing prematurely terminated.');
  701.           show_avail;
  702.           done := True
  703.         END;  { bomb }
  704.  
  705.       PROCEDURE add_identifier (     id : big_string;
  706.                                  VAR wd : word_ref );
  707.  
  708.         VAR
  709.           ir : item_ref;
  710.           wr : word_ref;
  711.  
  712.         PROCEDURE new_identifier ( VAR w : word_ref );
  713.  
  714.                           { Allocate memory for word }
  715.  
  716.           VAR
  717.             valid : Integer;
  718.  
  719.           BEGIN { new_identifier }
  720.             valid := word_bytes + Length (id) + 1;
  721.             GetMem (w, valid);
  722.             IF (valid = 0) OR (MemAvail <= sys_slop) THEN
  723.               bomb;
  724.           END;  { new_identifier }
  725.  
  726.         BEGIN { add_identifier }
  727.           wr := wd;
  728.           IF wd <> Nil THEN
  729.             IF      id < wd^.key THEN
  730.               add_identifier (id, wd^.left)
  731.             ELSE IF id > wd^.key THEN
  732.               add_identifier (id, wd^.right)
  733.             ELSE { id = wd^.key }
  734.               BEGIN
  735.                 New (ir);
  736.                 ir^.ln_num       := line_cnt;
  737.                 ir^.next         := Nil;
  738.                 wr^.last^.next   := ir;
  739.                 wr^.last         := ir
  740.               END
  741.           ELSE { wd = Nil }
  742.             BEGIN
  743.               new_identifier (wr);
  744.               New (ir);
  745.               WITH wr^ DO
  746.                 BEGIN
  747.                   word_max := max (Length (id), word_max);
  748.                   Move (id, key, Length (id) + 1);
  749.                   left  := Nil;
  750.                   right := Nil;
  751.                   first := ir;
  752.                   last  := ir
  753.                 END;
  754.               ir^.ln_num := line_cnt;
  755.               ir^.next   := Nil;
  756.               wd         := wr
  757.             END
  758.         END;  { add_identifier }
  759.  
  760.       BEGIN { get_identifier }
  761.         loc := i;
  762.         WHILE next_ch IN ident_chars DO
  763.           get_ch;
  764.         id := Copy (in_line, loc, i - loc + 1);
  765.         IF NOT is_reserved (id, rsrv_root) THEN
  766.           BEGIN
  767.             add_identifier (id, word_root);
  768.             IF was_proc THEN
  769.               BEGIN
  770.                 was_proc := False;
  771.                 WriteLn;
  772.                 Write (id);
  773.                 dot_cnt := dot_max
  774.               END
  775.           END
  776.       END;  { get_identifier }
  777.  
  778.     PROCEDURE find_match ( pattern : big_string );
  779.  
  780.       BEGIN { find_match }
  781.         get_ch;
  782.         IF end_line THEN
  783.           get_line
  784.         ELSE
  785.           BEGIN
  786.             Delete (in_line, 1, i - 1);
  787.             i := 1
  788.           END;
  789.         WHILE NOT end_file AND (Pos (pattern, in_line) < i) DO
  790.           get_line;
  791.         i := Pos (pattern, in_line) + Length (pattern) - 1
  792.       END;  { find_match }
  793.  
  794.     PROCEDURE parse_comment ( pattern : big_string );
  795.  
  796.       VAR
  797.         done : Boolean;
  798.         j    : Integer;
  799.  
  800.       PROCEDURE get_com_str ( VAR s       : big_string;
  801.                                   max_len : Integer );
  802.  
  803.         VAR
  804.           k : Integer;
  805.  
  806.         BEGIN { get_com_str }
  807.           k := 0;
  808.           WHILE (cur_ch <> ' ') AND (next_ch <> pattern[1] ) DO
  809.             get_ch;
  810.           WHILE cur_ch = ' ' DO
  811.             get_ch;
  812.           WHILE NOT end_line AND (cur_ch <> pattern[1] ) AND (k < max_len) DO
  813.             BEGIN
  814.               k    := k + 1;
  815.               s[k] := cur_ch;
  816.               get_ch
  817.             END;
  818.           s[0] := Chr (k);
  819.         END;  { get_com_str }
  820.  
  821.       PROCEDURE do_page;
  822.  
  823.         BEGIN { do_page }
  824.           Write (out_file, ff);
  825.           dit_cnt := out_height
  826.         END;  { do_page }
  827.  
  828.       PROCEDURE do_find;
  829.  
  830.         BEGIN { do_find }
  831.           i := i - 1;
  832.           find_match (pattern);
  833.           done := True
  834.         END;  { do_find }
  835.  
  836.       PROCEDURE get_include_file;
  837.  
  838.         LABEL
  839.           leave_include;
  840.  
  841.         VAR
  842.           io_error : Integer;
  843.           f_name   : big_string;
  844.           t_file   : Text;
  845.  
  846.         BEGIN { get_include_file }
  847.           get_com_str (f_name, name_len);
  848.           IF Length (f_name) > 0 THEN
  849.             BEGIN
  850.               set_nest;
  851.               dit;
  852.               WriteLn (out_file);
  853.               dit;
  854.               WriteLn (out_file, '*** Including text from ', f_name);
  855.               WriteLn;
  856.               Write ('*** Including text from ', f_name);
  857.               dot_cnt := dot_max;
  858.               IF nest_lev >= max_nst_lev THEN
  859.                 BEGIN
  860.                   WriteLn (out_file, '*** Unable to include files beyond ',
  861.                     max_nst_lev, ' levels.');
  862.                   dit;
  863.                   WriteLn;
  864.                   Write ('*** Unable to nest include files beyond ',
  865.                     max_nst_lev, ' levels.');
  866.                   Goto leave_include
  867.                 END
  868.               ELSE
  869.                 BEGIN
  870.                   {$I-}
  871.                   Assign (t_file, f_name);
  872.                   Reset (t_file);
  873.                   {$I+}
  874.                   io_error := IoResult;
  875.                   Close (t_file);
  876.                   IF io_error <> 0 THEN
  877.                     BEGIN
  878.                       WriteLn (out_file, '*** Unable to open include file due to I/O error #', io_error);
  879.                       dit;
  880.                       WriteLn;
  881.                       Write ('*** Unable to open include file ', f_name:name_len,
  882.                         ' due to I/O error #', io_error)
  883.                     END
  884.                   ELSE
  885.                     BEGIN
  886.                       nest_lev := nest_lev + 1;
  887.                       WITH nesting[nest_lev] DO
  888.                         BEGIN
  889.                           cur_file := f_name;
  890.                           {$I-}
  891.                           Assign (in_file, cur_file);
  892.                           Reset (in_file);
  893.                           {$I+}
  894.                         END
  895.                     END
  896.                 END
  897.             END;
  898.           leave_include:
  899.         END;  { get_include_file }
  900.  
  901.       BEGIN { parse_comment }
  902.         done := False;
  903.         FOR j := 1 TO Length (pattern) + 1 DO
  904.           get_ch;
  905.         REPEAT
  906.           IF end_line THEN
  907.             get_line;
  908.           IF NOT (cur_ch IN comment_chars + com_delimit) THEN
  909.             do_find
  910.           ELSE IF NOT (cur_ch IN com_opt_chars) THEN { cur_ch IN comment_chars + com_delimit }
  911.             IF next_ch IN com_delimit THEN
  912.               WHILE next_ch IN com_delimit DO
  913.                 get_ch
  914.             ELSE
  915.               do_find
  916.           ELSE IF NOT (next_ch IN ['-', '+'] ) THEN { cur_ch IN com_opt_chars }
  917.             BEGIN
  918.               CASE upcase (cur_ch) OF
  919.                 'I' : get_include_file;
  920.                 'P' : do_page;
  921.                 'T' : get_com_str (title, scrn_width);
  922.               END;
  923.               IF UpCase (cur_ch) <> 'P' THEN
  924.                 do_find
  925.             END
  926.           ELSE { Switch option: next_ch IN ['-', '+'] }
  927.             get_ch
  928.         UNTIL done
  929.       END;  { parse_comment }
  930.  
  931.     BEGIN { cross_reference }
  932.       end_file := False;
  933.       end_line := False;
  934.  
  935.       was_proc   := False;
  936.       
  937.       init_dot ('Cross Referencing File');
  938.       WHILE NOT (end_file OR done) DO
  939.         BEGIN
  940.           get_line;
  941.           WHILE NOT (end_line OR done) DO
  942.             BEGIN
  943.               IF      NOT (cur_ch IN parse_chars) THEN
  944.                 BEGIN
  945.                   term_dot;
  946.                   WriteLn;
  947.                   Write ('Invalid character in text ');
  948.                   IF cur_ch IN [' ' .. '~'] + [#128 .. #254] THEN
  949.                     WriteLn ('"', cur_ch, '"')
  950.                   ELSE
  951.                     WriteLn ('(', Ord (cur_ch), ')');
  952.                   done := True
  953.                 END
  954.               ELSE IF cur_ch IN start_ident THEN
  955.                 get_identifier
  956.               ELSE IF cur_ch = '{' THEN
  957.                 IF next_ch IN ['#', '$'] THEN
  958.                   parse_comment ('}')
  959.                 ELSE
  960.                   find_match ('}')
  961.               ELSE IF (cur_ch = '(') AND (next_ch = '*') THEN
  962.                 IF next2_ch IN ['#', '$'] THEN
  963.                   parse_comment ('*)')
  964.                 ELSE
  965.                   find_match ('*)')
  966.               ELSE IF cur_ch = '''' THEN
  967.                 find_match ('''')
  968.               ELSE IF cur_ch IN numbers + ['$', '#'] THEN { Numbers, Hexidecimal, Chars ASCII value }
  969.                 WHILE next_ch IN hexdigits + ['$'] DO
  970.                   get_ch
  971.               ELSE IF (cur_ch = '^') AND (next_ch IN start_ident) AND
  972.                       NOT (next2_ch IN ident_chars) { 28 Jun 85 } THEN { Control Chars }
  973.                 get_ch;
  974.               get_ch
  975.             END
  976.         END;
  977.       term_dot
  978.     END;  { cross_reference }
  979.  
  980.   PROCEDURE term;
  981.  
  982.     VAR
  983.       cnt      : Integer;
  984.       digit_ln : Integer;
  985.       num_ir   : Integer;
  986.       num_wd   : Integer;
  987.       io_error : Integer;
  988.  
  989.     PROCEDURE print_tree ( w : word_ref );
  990.  
  991.       PROCEDURE print_word ( VAR w : word ); { MUST be a variable parameter! }
  992.  
  993.         VAR
  994.           ir : item_ref;
  995.  
  996.         BEGIN { print_word }
  997.           num_wd := num_wd + 1;
  998.           Write (out_file, w.key, '':word_max - Length (w.key) );
  999.           dot;
  1000.           cnt := 0;
  1001.           ir  := w.first;
  1002.           REPEAT
  1003.             IF cnt < digit_ln THEN
  1004.               cnt := cnt + 1
  1005.             ELSE
  1006.               BEGIN
  1007.                 cnt := 1;
  1008.                 dit;
  1009.                 IF (dit_cnt = out_border) AND (page_cnt > 1) THEN { New page }
  1010.                   BEGIN
  1011.                     Write (out_file, w.key, '':word_max - Length (w.key),
  1012.                       ' (Continued from previous page)');
  1013.                     dit
  1014.                   END;
  1015.                 WriteLn (out_file);
  1016.                 Write (out_file, '':word_max)
  1017.               END;
  1018.             num_ir := num_ir + 1;
  1019.             Write (out_file, ir^.ln_num:digit_width);
  1020.             ir := ir^.next
  1021.           UNTIL ir = Nil;
  1022.           WriteLn (out_file);
  1023.           dit
  1024.         END;  { print_word }
  1025.         
  1026.       BEGIN { print_tree }
  1027.         IF w <> Nil THEN
  1028.           BEGIN
  1029.             print_tree (w^.left);
  1030.             print_word (w^);
  1031.             print_tree (w^.right)
  1032.           END
  1033.       END;  { print_tree }
  1034.  
  1035.     BEGIN { term }
  1036.       Close (out_file);
  1037.       {$I-}
  1038.       Assign (out_file, out_name);
  1039.       Rewrite (out_file);
  1040.       {$I+}
  1041.       io_error := IoResult;
  1042.       IF io_error <> 0 THEN
  1043.         BEGIN
  1044.           WriteLn;
  1045.           Write ('Unable to open ', out_name, ' due to I/O error #', io_error);
  1046.           Halt
  1047.         END;
  1048.       digit_ln := (out_width - word_max) DIV digit_width;
  1049.       init_dot ('Printing Cross Reference List');
  1050.       dit;
  1051.       WriteLn;
  1052.       num_ir := 0;
  1053.       num_wd := 0;
  1054.       print_tree (word_root);
  1055.       WriteLn (out_file);
  1056.       WriteLn (out_file, 'There were ', num_wd, ' identifiers',
  1057.         ' with ', num_ir, ' occurences.');
  1058.       Close (out_file);
  1059.       term_dot;
  1060.     END;  { term }
  1061.  
  1062.   BEGIN { ident_cross_ref }
  1063.     init_sys;
  1064.     WHILE NOT done DO
  1065.       BEGIN
  1066.         init;
  1067.         IF NOT done THEN
  1068.           BEGIN
  1069.             Mark (heap);
  1070.             cross_reference;
  1071.             term;
  1072.             Release (heap)
  1073.           END
  1074.       END
  1075.   END   { ident_cross_ref }.