home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / simtel / sigm / vols000 / vol064 / xref.pas < prev   
Pascal/Delphi Source File  |  1984-04-29  |  19KB  |  717 lines

  1. (*====================================================================*)
  2. (*  PROGRAM TITLE: PASCAL CROSS-REFERENCING PROGRAM                   *)
  3. (*                                                                    *)
  4. (*  PROGRAM NAME: XREF                                                *)
  5. (*                                                                    *)
  6. (*  LAST UPDATE:  14-JUL-81 by Warren A. Smith                        *)
  7. (*                                                                    *)
  8. (*      NOTE: THIS PROGRAM WAS ORIGINALLY WRITTEN BY N. WIRTH AND     *)
  9. (*      ADAPTED FOR UCSD PASCAL (I.4 - THE PUBLIC DOMAIN VERSION)     *)
  10. (*      BY SHAWN FANNING (IN 1978) AND SUBSEQUENTLY ADAPTED FOR       *)
  11. (*      PASCAL/MT+ BY MIKE LEHMAN (IN 1981). THIS VERSION WAS THEN    *)
  12. (*      MODIFIED BE WARREN A. SMITH TO TRY TO GET BACK TO ISO STAN-   *)
  13. (*      DARD PASCAL AND TO ADD THE ADDITIONAL FEATURE OF MAPPING      *)
  14. (*      OUT THE COMPOUND STATEMENTS. THIS IS A PUBLIC DOMAIN PROGRAM. *)
  15. (*      IF YOU MAKE REVISIONS, ETC. PLEASE LEAVE THE AUTHOR           *)
  16. (*      AND ALL MODIFIERS NAMES IN THE SOURCE FILE.  THANK YOU.       *)
  17. (*                                                                    *)
  18. (*  PROGRAM SUMMARY:                                                  *)
  19. (*                                                                    *)
  20. (*     THIS PROGRAM PRODUCES A CROSS-REFERENCE LISTING FOR ANY        *)
  21. (*   PASCAL PROGRAM.  OCCURENCES ONLY ARE LISTED.  NO DISTINCTION IS  *)
  22. (*   MADE BETWEEN DEFINITIONS AND REFERENCES.  IT WILL ALSO GIVE A    *)
  23. (*   GRAPHICAL REPRESENTATION OF THE BLOCK STRUCTURE OF THE PROGRAM.  *)
  24. (*   THIS FEATURE WAS ADDED BY WARREN A. SMITH (IN JULY 1981)         *)
  25. (*====================================================================*)
  26.  
  27.  
  28. PROGRAM XREF;
  29.  
  30. (*CROSS REFERENCE GENERATOR FOR PASCAL PROGRAMS.  N.WIRTH, 7.5.74*)
  31. (*'QUADRATIC QUOTIENT' HASH METHOD*)
  32.  
  33. CONST
  34.       P  = 749;           (*SIZE OF HASHTABLE*)
  35.       NK =  45;           (*NO. OF KEYWORDS*)
  36.       PAGESIZE = 60;      (*LINES PER PAGE*)
  37.       ALFALEN  =  8;      (*SIZE OF IDENTIFIERS*)
  38.       REFSPERLINE = 15;
  39.       REFSPERITEM =  5;
  40.       NESTMAX = 10 ;
  41.  
  42. TYPE
  43.      ALFA = PACKED ARRAY[1..ALFALEN] OF CHAR;
  44.      INDEX = 0..P;
  45.      ITEMPTR = ^ITEM;
  46.      WORD = RECORD
  47.                KEY: ALFA;
  48.                FIRST, LAST: ITEMPTR;
  49.                FOL: INDEX
  50.             END ;
  51.      NUMREFS = 1..REFSPERITEM;
  52.      REFTYPE = (COUNT, PTR);
  53.      ITEM = RECORD
  54.                REF   : ARRAY[NUMREFS] OF INTEGER;
  55.                CASE REFTYPE OF
  56.                   COUNT: (REFNUM: NUMREFS);
  57.                   PTR: (NEXT: ITEMPTR)
  58.             END ;
  59.      BUFFER = PACKED ARRAY[0..131] OF CHAR;
  60.  
  61. VAR
  62.     TOP: INDEX;        (*TOP OF CHAIN LINKING ALL ENTRIES IN T*)
  63.     I,LINECOUNT,BUFCURSOR: INTEGER;        (*CURRENT LINE NUMBER*)
  64.     FF,CH: CHAR;          (*CURRENT CHAR SCANNED *)
  65.     BUF : BUFFER;
  66.     T: ARRAY [INDEX] OF WORD;        (*HASH TABLE*)
  67.     KEY: ARRAY [1..NK] OF ALFA;      (* RESERVED KEYWORD TABLE *)
  68.     ERROR,                           (* ERROR FLAG *)
  69.     LISTING: BOOLEAN;                (* LISTING OPTION *)
  70.     INFILE: TEXT;
  71.     LST : TEXT;                 
  72.     LSTFILENAME : STRING;
  73.     INPUT_LINE : STRING;
  74.     PAGE_NUM,
  75.     NESTLVL,
  76.     LAST_KEY : INTEGER ;
  77.     ABORT,
  78.     LITERAL,
  79.     ACOMMENT,
  80.     BCOMMENT,
  81.     EOL,
  82.     NESTUP,
  83.     NESTDN : BOOLEAN ;
  84.     BAR : CHAR ;
  85.  
  86. FUNCTION UPPER (CH : CHAR) : CHAR ;
  87.  
  88.   BEGIN (* UPPER *)
  89.   IF (CH >= 'a') AND (CH <= 'z') THEN
  90.     UPPER := CHR(ORD(CH) + (ORD('A') - ORD('a')))
  91.   ELSE
  92.     UPPER := CH
  93.   END ; (* UPPER *)
  94.  
  95. PROCEDURE INITIALIZE;
  96. VAR
  97.   I : INTEGER;
  98.  
  99. PROCEDURE FIRSTHALF;
  100. BEGIN
  101.    KEY[ 1] := 'AND     ';
  102.    KEY[ 2] := 'ARRAY   ';
  103.    KEY[ 3] := 'BEGIN   ';
  104.    KEY[ 4] := 'BOOLEAN ';
  105.    KEY[ 5] := 'CASE    ';
  106.    KEY[ 6] := 'CHAR    ';
  107.    KEY[ 7] := 'CONST   ';
  108.    KEY[ 8] := 'DIV     ';
  109.    KEY[ 9] := 'DOWNTO  ';
  110.    KEY[10] := 'DO      ';
  111.    KEY[11] := 'ELSE    ';
  112.    KEY[12] := 'END     ';
  113.    KEY[13] := 'EXIT    ';
  114.    KEY[14] := 'FILE    ';
  115.    KEY[15] := 'FOR     ';
  116.    KEY[16] := 'FUNCTION';
  117. END;
  118.  
  119. PROCEDURE SECONDHALF;
  120. BEGIN
  121.    KEY[17] := 'GOTO    ';
  122.    KEY[18] := 'IF      ';
  123.    KEY[19] := 'IN      ';
  124.    KEY[20] := 'INPUT   ';
  125.    KEY[21] := 'INTEGER ';
  126.    KEY[22] := 'MOD     ';
  127.    KEY[23] := 'NIL     ';
  128.    KEY[24] := 'NOT     ';
  129.    KEY[25] := 'OF      ';
  130.    KEY[26] := 'OR      ';
  131.    KEY[27] := 'OUTPUT  ';
  132.    KEY[28] := 'PACKED  ';
  133.    KEY[29] := 'PROCEDUR';
  134.    KEY[30] := 'PROGRAM ';
  135.    KEY[31] := 'REAL    ';
  136.    KEY[32] := 'RECORD  ';
  137.    KEY[33] := 'REPEAT  ';
  138.    KEY[34] := 'SET     ';
  139.    KEY[35] := 'STRING  ';
  140.    KEY[36] := 'TEXT    ';
  141.    KEY[37] := 'THEN    ';
  142.    KEY[38] := 'TO      ';
  143.    KEY[39] := 'TYPE    ';
  144.    KEY[40] := 'UNTIL   ';
  145.    KEY[41] := 'VAR     ';
  146.    KEY[42] := 'WHILE   ';
  147.    KEY[43] := 'WITH    ';
  148.    KEY[44] := 'WRITE   ';
  149.    KEY[45] := 'WRITELN ';
  150. END;
  151.  
  152. BEGIN (* INITIALIZE *)
  153.    FOR I := 1 TO 25 DO      { clear the screen }
  154.      WRITELN ;
  155.    WRITELN('Pascal Program Xref Utility');
  156.    WRITELN('This program is public domain');
  157.    WRITELN('Contributed by Warren A. Smith  --  July 14, 1981');
  158.    FOR I := 1 TO 13 DO
  159.      WRITELN ;
  160.    FF:=CHR(12);
  161.    ERROR := FALSE;
  162.    FOR I := 0 TO P DO
  163.       T[I].KEY := '        ';
  164.    FIRSTHALF;
  165.    SECONDHALF;
  166.    LINECOUNT:= 1;
  167.    TOP := P;
  168.    PAGE_NUM := 1 ;
  169.    LITERAL := FALSE ;
  170.    ACOMMENT := FALSE ;
  171.    BCOMMENT := FALSE ;
  172.    NESTLVL := 0 ;
  173.    LAST_KEY := 0 ;
  174.    BAR := '|' ;
  175.    CH  := ' '
  176. END; (* INITIALIZE *)
  177.  
  178. PROCEDURE OPENFILES;
  179. VAR                                       
  180.     I : INTEGER ;
  181.     NUMBLOCKS: INTEGER;
  182.     OPENOK: BOOLEAN;
  183.     OPENERRNUM : INTEGER;
  184.     LISTOPTION: CHAR;
  185.     FILENAME: STRING;
  186.  
  187. BEGIN (* OPEN *)
  188.    WRITELN ;
  189.    WRITELN ('An answer of a $ character to any question') ;
  190.    WRITELN ('   will cause the program to abort.') ;
  191.    ABORT := FALSE ;
  192.    REPEAT
  193.       WRITELN;
  194.       WRITELN('Type in the name of the file you want cross-referenced.' );
  195.       WRITELN('   The file will also have the compound statements displayed');
  196.       WRITELN('   if you select the list option.  ');
  197.       READLN( FILENAME );
  198.       IF LENGTH(FILENAME) > 0 THEN
  199.         BEGIN
  200.         FOR I := 1 TO LENGTH(FILENAME) DO
  201.           FILENAME[I] := UPPER(FILENAME[I]) ;
  202.         ABORT := FILENAME[1] = '$' ;
  203.         IF NOT ABORT THEN
  204.           BEGIN
  205.  
  206. {---------------------------------------------------------------}
  207. {    This section is implementation dependent.  It will work    }
  208. {    for UCSD Pascal or Pascal/MT+ but not for Pascal/Z.    }
  209. {    For Pascal/Z, use                         }
  210. {      RESET (FILENAME,INFILE);                    }
  211. {---------------------------------------------------------------}
  212. {}        ASSIGN(INFILE,FILENAME);                   {}
  213. {}        RESET(INFILE);                       {}
  214. {---------------------------------------------------------------}
  215.  
  216.           OPENERRNUM := IORESULT;
  217.           OPENOK     := ( OPENERRNUM <> 255 );
  218.           ABORT      := EOF (INFILE) ;
  219.           IF NOT OPENOK THEN
  220.             WRITELN( '*** INPUT OPEN ERROR #', OPENERRNUM )
  221.           ELSE
  222.             IF ABORT THEN
  223.               WRITELN ('*** FILE ', FILENAME,' IS EMPTY, PROGRAM ABORTING')
  224.           END
  225.         END;
  226.    UNTIL OPENOK OR ABORT;
  227.  
  228.    IF NOT ABORT THEN
  229.      BEGIN
  230.      WRITELN;
  231.      WRITELN('Destination file or device name?');
  232.      WRITE  ('  The default is LST: - ');
  233.      READLN(LSTFILENAME);
  234.      WRITELN;
  235.      IF LENGTH (LSTFILENAME) <= 0 THEN
  236.        LSTFILENAME := 'LST:' ;
  237.      ABORT := LSTFILENAME [1] = '$' ;
  238.      IF NOT ABORT THEN
  239.        BEGIN
  240.        FOR I := 1 TO LENGTH(LSTFILENAME) DO
  241.          LSTFILENAME[I] := UPPER(LSTFILENAME[I]) ;
  242.  
  243. {---------------------------------------------------------------}
  244. {    This section is implementation dependent.  It will work    }
  245. {    for UCSD Pascal or Pascal/MT+ but not for Pascal/Z.    }
  246. {    For Pascal/Z, use                         }
  247. {      REWRITE (LSTFILENAME, LST);                }
  248. {---------------------------------------------------------------}
  249. {}     ASSIGN(LST,LSTFILENAME);                       {}
  250. {}     REWRITE(LST)                           {}
  251. {---------------------------------------------------------------}
  252.        END
  253.      END ;
  254.  
  255.    IF NOT ABORT THEN
  256.      BEGIN
  257.      REPEAT
  258.        WRITE( 'Do you want a listing (y or n)? ' );
  259.        READ( LISTOPTION );
  260.        WRITELN ;
  261.        ABORT := LISTOPTION = '$'
  262.      UNTIL ABORT OR (LISTOPTION IN ['Y','y','N','n']);
  263.      IF NOT ABORT THEN
  264.        BEGIN
  265.        LISTING := NOT(LISTOPTION in ['N','n']) ;
  266.        WRITELN ;
  267.        IF LISTING THEN
  268.          WRITELN ('LIST OPTION ON')
  269.        ELSE
  270.          WRITELN
  271.        END
  272.      END
  273. END; (* OPEN *)
  274.  
  275. FUNCTION TAB (NUM : INTEGER) : CHAR ;
  276.  
  277.   VAR
  278.       I : INTEGER ;
  279.  
  280.   BEGIN
  281.   FOR I := 1 TO NUM DO
  282.     WRITE (LST, ' ') ;
  283.   TAB := CHR(0)
  284.   END ; (* TAB *)
  285.  
  286. PROCEDURE LPWRITELN;
  287. VAR
  288.   I : INTEGER;
  289. BEGIN
  290.   BUF[BUFCURSOR]:=CHR(13);
  291.   BUFCURSOR:=BUFCURSOR+1;
  292.   FOR I := 0 TO BUFCURSOR-1 DO
  293.     WRITE(LST,BUF[I]);
  294.   BUFCURSOR:=0;
  295.   LINECOUNT:=LINECOUNT+1;
  296.   IF (LINECOUNT MOD PAGESIZE) = 0 THEN
  297.     PAGE(LST);
  298. END;
  299.  
  300. PROCEDURE PUTALFA(S:ALFA);
  301. BEGIN
  302.   MOVELEFT(S[1],BUF[BUFCURSOR],8);
  303.   BUFCURSOR:=BUFCURSOR+8;
  304. END;
  305.  
  306. PROCEDURE PUTNUMBER(NUM: INTEGER);
  307. VAR I,IPOT:INTEGER;
  308.     A: ALFA;
  309.     CH: CHAR;
  310.     ZAP:BOOLEAN;
  311.     
  312. BEGIN
  313.   ZAP:=TRUE;
  314.   IPOT:=10000;
  315.   A[1]:=' ';
  316.   FOR I:= 2 TO 6 DO
  317.     BEGIN
  318.       CH:=CHR(NUM DIV IPOT + ORD('0'));
  319.       IF I <> 6 THEN
  320.         IF ZAP THEN
  321.            IF CH = '0' THEN
  322.              CH:=' '
  323.            ELSE ZAP:=FALSE;
  324.       A[I]:=CH;
  325.       NUM:=NUM MOD IPOT;
  326.       IPOT:=IPOT DIV 10;
  327.     END;
  328.   A[7]:=' ';
  329.   MOVELEFT(A,BUF[BUFCURSOR],7);
  330.   BUFCURSOR:=BUFCURSOR+7;
  331. END;
  332.  
  333. PROCEDURE SEARCH( ID: ALFA );          (*MODULO P HASH SEARCH*)
  334. (*GLOBAL: T, TOP*)
  335. VAR
  336.     I,J,H,D  : INTEGER;
  337.     X    : ITEMPTR;
  338.     F    : BOOLEAN;
  339.  
  340. BEGIN
  341.    J:=0;
  342.    FOR I:= 1 TO ALFALEN DO
  343.      J:= J*10+ORD(ID[I]);
  344.    H  := ABS(J) MOD P;
  345.    F  := FALSE;
  346.    D  := 1;
  347.    REPEAT
  348.       IF T[H].KEY = ID
  349.          THEN
  350.             BEGIN (*FOUND*)
  351.                F := TRUE;
  352.                IF T[H].LAST^.REFNUM = REFSPERITEM
  353.                   THEN
  354.                      BEGIN
  355.                          NEW(X);
  356.                          X^.REFNUM := 1;
  357.                          X^.REF[1] := LINECOUNT;
  358.                          T[H].LAST^.NEXT:= X;
  359.                          T[H].LAST      := X;
  360.                      END
  361.                  ELSE
  362.                     WITH T[H].LAST^ DO
  363.                        BEGIN
  364.                           REFNUM      := REFNUM + 1;
  365.                           REF[REFNUM] := LINECOUNT
  366.                        END
  367.             END
  368.          ELSE
  369.             IF T[H].KEY = '        '
  370.                THEN
  371.                   BEGIN (*NEW ENTRY*)
  372.                      F  := TRUE;
  373.                      NEW(X);
  374.                      X^.REFNUM := 1;
  375.                      X^.REF[1] := LINECOUNT;
  376.                      T[H].KEY   := ID;
  377.                      T[H].FIRST := X;
  378.                      T[H].LAST  := X;
  379.                      T[H].FOL   := TOP;
  380.                      TOP := H
  381.                   END
  382.                ELSE
  383.                   BEGIN (*COLLISION*)
  384.                      H := H+D;
  385.                      D := D+2;
  386.                      IF H >= P
  387.                         THEN
  388.                            H := H - P;
  389.                      IF D = P
  390.                         THEN
  391.                            BEGIN
  392.                               WRITELN(OUTPUT,'TBLE OVFLW');
  393.                               ERROR := TRUE
  394.                            END ;
  395.                   END
  396.    UNTIL F OR ERROR
  397. END (*SEARCH*) ;
  398.  
  399.  
  400.  
  401. PROCEDURE PRINTWORD(W: WORD);
  402. VAR
  403.     L: INTEGER;
  404.     X: ITEMPTR;
  405.     NEXTREF : INTEGER;
  406.     THISREF: NUMREFS;
  407. BEGIN
  408.    PUTALFA(W.KEY);
  409.    X := W.FIRST;
  410.    L := 0;
  411.    REPEAT
  412.       IF L = REFSPERLINE
  413.          THEN
  414.             BEGIN
  415.                L := 0;
  416.                LPWRITELN;
  417.                PUTALFA('        ');
  418.             END ;
  419.       L := L+1;
  420.       THISREF := (L-1) MOD REFSPERITEM + 1;
  421.       NEXTREF := X^.REF[ THISREF ];
  422.       IF THISREF = X^.REFNUM
  423.          THEN
  424.             X := NIL
  425.          ELSE
  426.             IF THISREF = REFSPERITEM
  427.                THEN
  428.                   X := X^.NEXT;
  429.       PUTNUMBER(NEXTREF);
  430.    UNTIL X = NIL;
  431.   LPWRITELN;
  432. END (*PRINTWORD*) ;
  433.  
  434. PROCEDURE PRINTTABLE;
  435.  
  436. VAR
  437.     I,J,M: INDEX;
  438.  
  439. BEGIN
  440.    I := TOP;
  441.    WHILE I <> P DO
  442.       BEGIN (*FIND MINIMAL WORD*)
  443.          M := I;
  444.          J := T[I].FOL;
  445.          WHILE J <> P DO
  446.             BEGIN
  447.                IF T[J].KEY < T[M].KEY
  448.                   THEN
  449.                      M := J;
  450.                J := T[J].FOL
  451.             END ;
  452.          PRINTWORD(T[M]);
  453.          IF M <> I THEN 
  454.            BEGIN
  455.              T[M].KEY:=T[I].KEY;
  456.              T[M].FIRST:=T[I].FIRST;
  457.              T[M].LAST:=T[I].LAST;
  458.            END;
  459.          I := T[I].FOL
  460.       END
  461. END (*PRINTTABLE*) ;
  462.  
  463. PROCEDURE OUTPUT_LINE (BUF : BUFFER) ;
  464.   
  465.   VAR
  466.       I : INTEGER ;
  467.  
  468.   PROCEDURE FILL_LINE (VAR LINE : BUFFER) ;
  469.     
  470.     VAR I : INTEGER ;
  471.           
  472.     BEGIN (* FILL_LINE *)
  473.     I := 1 ;
  474.     WHILE (LINE[I] = ' ') DO
  475.       BEGIN
  476.       LINE[I] := '-' ;
  477.       I := I + 1
  478.       END
  479.     END ; (* FILL_LINE *)
  480.  
  481.  
  482.  
  483.   PROCEDURE PRTNEST (VAR LINE : BUFFER) ;
  484.   
  485.     VAR COL : INTEGER ;
  486.  
  487.  
  488.     BEGIN (* PRTNEST *)
  489.     FOR COL := 1 TO NESTLVL - 1 DO
  490.       WRITE (LST, BAR, '  ') ;
  491.     IF NESTLVL > 0 THEN
  492.       IF NESTUP OR NESTDN THEN
  493.         BEGIN
  494.         IF NESTDN THEN
  495.           BEGIN
  496.           WRITE (LST, BAR, '  ') ;
  497.           WRITE (LST, 'E--') ;
  498.           FOR COL := NESTLVL+2 TO NESTMAX DO
  499.             WRITE (LST, '---')
  500.           END
  501.         ELSE
  502.           BEGIN
  503.           WRITE (LST, 'B--') ;
  504.           FOR COL := NESTLVL+1 TO NESTMAX DO
  505.             WRITE (LST, '---')
  506.           END ;
  507.         FILL_LINE (LINE)
  508.         END
  509.       ELSE
  510.         BEGIN
  511.         WRITE (LST, BAR, '  ') ;
  512.         FOR COL := NESTLVL+1 TO NESTMAX DO
  513.           WRITE (LST, '   ')
  514.         END
  515.     ELSE
  516.       IF NESTDN THEN
  517.         BEGIN
  518.         WRITE (LST, 'E--') ;
  519.         FOR COL := 2 TO NESTMAX DO
  520.           WRITE (LST, '---') ;
  521.         FILL_LINE (LINE)
  522.         END
  523.       ELSE
  524.         FOR COL := 1 TO NESTMAX DO
  525.           WRITE (LST, '   ')
  526.     END ; (* PRTNEST *)
  527.         
  528.   BEGIN (* OUTPUT_LINE *)
  529.   IF ((LINECOUNT MOD PAGESIZE) = 0) OR (PAGE_NUM = 1) THEN
  530.     BEGIN
  531.     IF LISTING THEN
  532.       BEGIN
  533.       PAGE (LST) ;
  534.       WRITELN (LST, TAB(70), 'PAGE ', PAGE_NUM:1) ;
  535.       WRITELN (LST) ;
  536.       PAGE_NUM := PAGE_NUM + 1
  537.       END ;
  538.     IF (LSTFILENAME <> 'CON:') AND ((LINECOUNT MOD PAGESIZE) = 0) THEN
  539.       WRITELN (OUTPUT, '< ', LINECOUNT:4, ',', MEMAVAIL:5, ' >')
  540.     END ;
  541.   WRITE (LST, LINECOUNT:4, '  ') ;
  542.   PRTNEST (BUF) ;
  543.   FOR I := 1 TO BUFCURSOR DO
  544.     WRITE (LST, BUF[I]) ;
  545.   WRITELN (LST) ;
  546.   IF LSTFILENAME <> 'CON:' THEN
  547.     WRITE (OUTPUT, '.')
  548.   END ; (* OUTPUT_LINE *)
  549.  
  550.  
  551. PROCEDURE GETNEXTCHAR;
  552. VAR I : INTEGER;
  553.  
  554. BEGIN (* GETNEXTCHAR *)
  555. IF BUFCURSOR >= LENGTH (INPUT_LINE) THEN
  556.   BEGIN
  557.   EOL := TRUE ;
  558.   CH := ' ' ;
  559.   ERROR := EOF(INFILE)
  560.   END
  561. ELSE
  562.   BEGIN
  563.   BUFCURSOR := BUFCURSOR + 1 ;
  564.   CH := INPUT_LINE [BUFCURSOR] ;
  565.   BUF [BUFCURSOR] := CH ;
  566.   CH := UPPER(CH)
  567.   END
  568. END; (* GETNEXTCHAR *)
  569.  
  570.  
  571. PROCEDURE GETIDENTIFIER;
  572. VAR
  573.     J,K,I: INTEGER;
  574.     ID: ALFA;
  575.  
  576. BEGIN (* GETIDENTIFIER *)
  577.    I := 0;
  578.    ID := '        ';
  579.    REPEAT
  580.       IF I < ALFALEN
  581.          THEN
  582.             BEGIN
  583.                I := I+1;
  584.                ID[I] := CH
  585.             END;
  586.       GETNEXTCHAR
  587.    UNTIL ( NOT(((CH>='A') AND (CH<='Z')) OR (CH='_')
  588.                 OR ((CH>='0') AND (CH<='9')))) OR (ERROR);
  589.    I := 1;
  590.    J := NK;
  591.    REPEAT
  592.       K := (I+J) DIV 2;      (*BINARY SEARCH*)
  593.       IF KEY[K] <= ID
  594.          THEN
  595.             I := K+1;
  596.  
  597.       IF KEY[K] >= ID
  598.          THEN
  599.             J := K-1;
  600.  
  601.    UNTIL I > J;
  602.    IF KEY[K] <> ID THEN
  603.      SEARCH(ID)
  604.    ELSE
  605.      BEGIN
  606.        IF (K=3) OR ((K=5) AND (LAST_KEY<>32)) OR     { BEGIN or CASE }
  607.           (K=32) OR (K=33) THEN                      { RECORD or REPEAT }
  608.          BEGIN
  609.            LAST_KEY := K ;
  610.            IF NESTLVL = NESTMAX THEN
  611.              WRITE (LST, '----Too many levels')
  612.            ELSE
  613.              BEGIN
  614.                NESTLVL := NESTLVL + 1 ;
  615.                NESTUP := TRUE
  616.              END
  617.          END ;
  618.        IF (K=12) OR (K=40) THEN          { END or UNTIL }
  619.          IF NESTLVL = 0 THEN
  620.            WRITE (LST, '----Nesting error  ')
  621.          ELSE
  622.            BEGIN
  623.              NESTLVL := NESTLVL - 1 ;
  624.              NESTDN := TRUE
  625.            END
  626.      END
  627.  
  628. END; (* GETIDENTIFIER *)
  629.  
  630. BEGIN (* CROSSREF *)
  631.  
  632.    INITIALIZE;
  633.  
  634.    OPENFILES;
  635.    
  636.    WHILE NOT EOF(INFILE) AND (NOT ABORT) DO
  637.       BEGIN
  638.       BUFCURSOR:= 0;
  639.       NESTUP := FALSE ;
  640.       NESTDN := FALSE ;
  641.       READLN (INFILE, INPUT_LINE) ;
  642.       IF LENGTH (INPUT_LINE) > 0 THEN
  643.         BEGIN
  644.         EOL := FALSE ;
  645.         BUFCURSOR := BUFCURSOR + 1 ;
  646.         CH := INPUT_LINE [BUFCURSOR] ;
  647.         BUF [BUFCURSOR] := CH ;
  648.         CH := UPPER (CH)
  649.         END
  650.       ELSE
  651.         BEGIN
  652.         EOL := TRUE ;
  653.         CH := ' '
  654.         END ;
  655.       WHILE NOT EOL DO
  656.         BEGIN
  657.         IF ((CH >= 'A') AND (CH <= 'Z')) AND (NOT LITERAL) AND
  658.            (NOT ACOMMENT) AND (NOT BCOMMENT) THEN
  659.           GETIDENTIFIER
  660.         ELSE
  661.           IF (CH = '''') OR LITERAL THEN
  662.             BEGIN
  663.               REPEAT
  664.                 GETNEXTCHAR;
  665.               UNTIL (CH = '''') OR (ERROR) OR EOL;
  666.               LITERAL := EOL ;
  667.               GETNEXTCHAR
  668.             END
  669.           ELSE
  670.             IF (CH = '{') OR ACOMMENT THEN
  671.               BEGIN
  672.                 WHILE (CH <> '}') AND (NOT ERROR) AND (NOT EOL) DO
  673.                   GETNEXTCHAR ;
  674.                 ACOMMENT := EOL ;
  675.                 GETNEXTCHAR
  676.               END
  677.             ELSE
  678.               IF (CH = '(') OR BCOMMENT THEN
  679.                 BEGIN
  680.                   IF NOT BCOMMENT THEN
  681.                     GETNEXTCHAR;
  682.                   IF (CH = '*') OR BCOMMENT THEN
  683.                     BEGIN
  684.                       IF NOT BCOMMENT THEN
  685.                         GETNEXTCHAR;
  686.                       REPEAT
  687.                         WHILE (CH <> '*') AND (NOT ERROR) AND (NOT EOL) DO
  688.                           GETNEXTCHAR ;
  689.                         BCOMMENT := EOL ;
  690.                         IF NOT EOL THEN
  691.                           GETNEXTCHAR
  692.                       UNTIL (CH = ')') OR ERROR OR EOL ;
  693.                       IF NOT EOL THEN
  694.                         GETNEXTCHAR
  695.                     END
  696.                 END
  697.               ELSE
  698.                 GETNEXTCHAR;
  699.  
  700.         END; (* WHILE *)
  701.       EOL := FALSE ;
  702.       OUTPUT_LINE (BUF) ;
  703.       LINECOUNT := LINECOUNT + 1
  704.       END ;
  705.    IF NOT ABORT THEN
  706.      BEGIN
  707.      PAGE(LST);
  708.      LINECOUNT := 0;
  709.      BUFCURSOR := 0;
  710.      PRINTTABLE;
  711.      PAGE(LST);
  712.      CLOSE(LST,I);
  713.      IF I = 255 THEN
  714.        WRITELN('Error closing output file')
  715.      END
  716. END.
  717.