home *** CD-ROM | disk | FTP | other *** search
- (*====================================================================*)
- (* PROGRAM TITLE: PASCAL CROSS-REFERENCING PROGRAM *)
- (* *)
- (* PROGRAM NAME: XREF *)
- (* *)
- (* LAST UPDATE: 14-JUL-81 by Warren A. Smith *)
- (* *)
- (* NOTE: THIS PROGRAM WAS ORIGINALLY WRITTEN BY N. WIRTH AND *)
- (* ADAPTED FOR UCSD PASCAL (I.4 - THE PUBLIC DOMAIN VERSION) *)
- (* BY SHAWN FANNING (IN 1978) AND SUBSEQUENTLY ADAPTED FOR *)
- (* PASCAL/MT+ BY MIKE LEHMAN (IN 1981). THIS VERSION WAS THEN *)
- (* MODIFIED BE WARREN A. SMITH TO TRY TO GET BACK TO ISO STAN- *)
- (* DARD PASCAL AND TO ADD THE ADDITIONAL FEATURE OF MAPPING *)
- (* OUT THE COMPOUND STATEMENTS. THIS IS A PUBLIC DOMAIN PROGRAM. *)
- (* IF YOU MAKE REVISIONS, ETC. PLEASE LEAVE THE AUTHOR *)
- (* AND ALL MODIFIERS NAMES IN THE SOURCE FILE. THANK YOU. *)
- (* *)
- (* PROGRAM SUMMARY: *)
- (* *)
- (* THIS PROGRAM PRODUCES A CROSS-REFERENCE LISTING FOR ANY *)
- (* PASCAL PROGRAM. OCCURENCES ONLY ARE LISTED. NO DISTINCTION IS *)
- (* MADE BETWEEN DEFINITIONS AND REFERENCES. IT WILL ALSO GIVE A *)
- (* GRAPHICAL REPRESENTATION OF THE BLOCK STRUCTURE OF THE PROGRAM. *)
- (* THIS FEATURE WAS ADDED BY WARREN A. SMITH (IN JULY 1981) *)
- (*====================================================================*)
-
-
- PROGRAM XREF;
-
- (*CROSS REFERENCE GENERATOR FOR PASCAL PROGRAMS. N.WIRTH, 7.5.74*)
- (*'QUADRATIC QUOTIENT' HASH METHOD*)
-
- CONST
- P = 749; (*SIZE OF HASHTABLE*)
- NK = 45; (*NO. OF KEYWORDS*)
- PAGESIZE = 60; (*LINES PER PAGE*)
- ALFALEN = 8; (*SIZE OF IDENTIFIERS*)
- REFSPERLINE = 15;
- REFSPERITEM = 5;
- NESTMAX = 10 ;
-
- TYPE
- ALFA = PACKED ARRAY[1..ALFALEN] OF CHAR;
- INDEX = 0..P;
- ITEMPTR = ^ITEM;
- WORD = RECORD
- KEY: ALFA;
- FIRST, LAST: ITEMPTR;
- FOL: INDEX
- END ;
- NUMREFS = 1..REFSPERITEM;
- REFTYPE = (COUNT, PTR);
- ITEM = RECORD
- REF : ARRAY[NUMREFS] OF INTEGER;
- CASE REFTYPE OF
- COUNT: (REFNUM: NUMREFS);
- PTR: (NEXT: ITEMPTR)
- END ;
- BUFFER = PACKED ARRAY[0..131] OF CHAR;
-
- VAR
- TOP: INDEX; (*TOP OF CHAIN LINKING ALL ENTRIES IN T*)
- I,LINECOUNT,BUFCURSOR: INTEGER; (*CURRENT LINE NUMBER*)
- FF,CH: CHAR; (*CURRENT CHAR SCANNED *)
- BUF : BUFFER;
- T: ARRAY [INDEX] OF WORD; (*HASH TABLE*)
- KEY: ARRAY [1..NK] OF ALFA; (* RESERVED KEYWORD TABLE *)
- ERROR, (* ERROR FLAG *)
- LISTING: BOOLEAN; (* LISTING OPTION *)
- INFILE: TEXT;
- LST : TEXT;
- LSTFILENAME : STRING;
- INPUT_LINE : STRING;
- PAGE_NUM,
- NESTLVL,
- LAST_KEY : INTEGER ;
- ABORT,
- LITERAL,
- ACOMMENT,
- BCOMMENT,
- EOL,
- NESTUP,
- NESTDN : BOOLEAN ;
- BAR : CHAR ;
-
- FUNCTION UPPER (CH : CHAR) : CHAR ;
-
- BEGIN (* UPPER *)
- IF (CH >= 'a') AND (CH <= 'z') THEN
- UPPER := CHR(ORD(CH) + (ORD('A') - ORD('a')))
- ELSE
- UPPER := CH
- END ; (* UPPER *)
-
- PROCEDURE INITIALIZE;
- VAR
- I : INTEGER;
-
- PROCEDURE FIRSTHALF;
- BEGIN
- KEY[ 1] := 'AND ';
- KEY[ 2] := 'ARRAY ';
- KEY[ 3] := 'BEGIN ';
- KEY[ 4] := 'BOOLEAN ';
- KEY[ 5] := 'CASE ';
- KEY[ 6] := 'CHAR ';
- KEY[ 7] := 'CONST ';
- KEY[ 8] := 'DIV ';
- KEY[ 9] := 'DOWNTO ';
- KEY[10] := 'DO ';
- KEY[11] := 'ELSE ';
- KEY[12] := 'END ';
- KEY[13] := 'EXIT ';
- KEY[14] := 'FILE ';
- KEY[15] := 'FOR ';
- KEY[16] := 'FUNCTION';
- END;
-
- PROCEDURE SECONDHALF;
- BEGIN
- KEY[17] := 'GOTO ';
- KEY[18] := 'IF ';
- KEY[19] := 'IN ';
- KEY[20] := 'INPUT ';
- KEY[21] := 'INTEGER ';
- KEY[22] := 'MOD ';
- KEY[23] := 'NIL ';
- KEY[24] := 'NOT ';
- KEY[25] := 'OF ';
- KEY[26] := 'OR ';
- KEY[27] := 'OUTPUT ';
- KEY[28] := 'PACKED ';
- KEY[29] := 'PROCEDUR';
- KEY[30] := 'PROGRAM ';
- KEY[31] := 'REAL ';
- KEY[32] := 'RECORD ';
- KEY[33] := 'REPEAT ';
- KEY[34] := 'SET ';
- KEY[35] := 'STRING ';
- KEY[36] := 'TEXT ';
- KEY[37] := 'THEN ';
- KEY[38] := 'TO ';
- KEY[39] := 'TYPE ';
- KEY[40] := 'UNTIL ';
- KEY[41] := 'VAR ';
- KEY[42] := 'WHILE ';
- KEY[43] := 'WITH ';
- KEY[44] := 'WRITE ';
- KEY[45] := 'WRITELN ';
- END;
-
- BEGIN (* INITIALIZE *)
- FOR I := 1 TO 25 DO { clear the screen }
- WRITELN ;
- WRITELN('Pascal Program Xref Utility');
- WRITELN('This program is public domain');
- WRITELN('Contributed by Warren A. Smith -- July 14, 1981');
- FOR I := 1 TO 13 DO
- WRITELN ;
- FF:=CHR(12);
- ERROR := FALSE;
- FOR I := 0 TO P DO
- T[I].KEY := ' ';
- FIRSTHALF;
- SECONDHALF;
- LINECOUNT:= 1;
- TOP := P;
- PAGE_NUM := 1 ;
- LITERAL := FALSE ;
- ACOMMENT := FALSE ;
- BCOMMENT := FALSE ;
- NESTLVL := 0 ;
- LAST_KEY := 0 ;
- BAR := '|' ;
- CH := ' '
- END; (* INITIALIZE *)
-
- PROCEDURE OPENFILES;
- VAR
- I : INTEGER ;
- NUMBLOCKS: INTEGER;
- OPENOK: BOOLEAN;
- OPENERRNUM : INTEGER;
- LISTOPTION: CHAR;
- FILENAME: STRING;
-
- BEGIN (* OPEN *)
- WRITELN ;
- WRITELN ('An answer of a $ character to any question') ;
- WRITELN (' will cause the program to abort.') ;
- ABORT := FALSE ;
- REPEAT
- WRITELN;
- WRITELN('Type in the name of the file you want cross-referenced.' );
- WRITELN(' The file will also have the compound statements displayed');
- WRITELN(' if you select the list option. ');
- READLN( FILENAME );
- IF LENGTH(FILENAME) > 0 THEN
- BEGIN
- FOR I := 1 TO LENGTH(FILENAME) DO
- FILENAME[I] := UPPER(FILENAME[I]) ;
- ABORT := FILENAME[1] = '$' ;
- IF NOT ABORT THEN
- BEGIN
-
- {---------------------------------------------------------------}
- { This section is implementation dependent. It will work }
- { for UCSD Pascal or Pascal/MT+ but not for Pascal/Z. }
- { For Pascal/Z, use }
- { RESET (FILENAME,INFILE); }
- {---------------------------------------------------------------}
- {} ASSIGN(INFILE,FILENAME); {}
- {} RESET(INFILE); {}
- {---------------------------------------------------------------}
-
- OPENERRNUM := IORESULT;
- OPENOK := ( OPENERRNUM <> 255 );
- ABORT := EOF (INFILE) ;
- IF NOT OPENOK THEN
- WRITELN( '*** INPUT OPEN ERROR #', OPENERRNUM )
- ELSE
- IF ABORT THEN
- WRITELN ('*** FILE ', FILENAME,' IS EMPTY, PROGRAM ABORTING')
- END
- END;
- UNTIL OPENOK OR ABORT;
-
- IF NOT ABORT THEN
- BEGIN
- WRITELN;
- WRITELN('Destination file or device name?');
- WRITE (' The default is LST: - ');
- READLN(LSTFILENAME);
- WRITELN;
- IF LENGTH (LSTFILENAME) <= 0 THEN
- LSTFILENAME := 'LST:' ;
- ABORT := LSTFILENAME [1] = '$' ;
- IF NOT ABORT THEN
- BEGIN
- FOR I := 1 TO LENGTH(LSTFILENAME) DO
- LSTFILENAME[I] := UPPER(LSTFILENAME[I]) ;
-
- {---------------------------------------------------------------}
- { This section is implementation dependent. It will work }
- { for UCSD Pascal or Pascal/MT+ but not for Pascal/Z. }
- { For Pascal/Z, use }
- { REWRITE (LSTFILENAME, LST); }
- {---------------------------------------------------------------}
- {} ASSIGN(LST,LSTFILENAME); {}
- {} REWRITE(LST) {}
- {---------------------------------------------------------------}
- END
- END ;
-
- IF NOT ABORT THEN
- BEGIN
- REPEAT
- WRITE( 'Do you want a listing (y or n)? ' );
- READ( LISTOPTION );
- WRITELN ;
- ABORT := LISTOPTION = '$'
- UNTIL ABORT OR (LISTOPTION IN ['Y','y','N','n']);
- IF NOT ABORT THEN
- BEGIN
- LISTING := NOT(LISTOPTION in ['N','n']) ;
- WRITELN ;
- IF LISTING THEN
- WRITELN ('LIST OPTION ON')
- ELSE
- WRITELN
- END
- END
- END; (* OPEN *)
-
- FUNCTION TAB (NUM : INTEGER) : CHAR ;
-
- VAR
- I : INTEGER ;
-
- BEGIN
- FOR I := 1 TO NUM DO
- WRITE (LST, ' ') ;
- TAB := CHR(0)
- END ; (* TAB *)
-
- PROCEDURE LPWRITELN;
- VAR
- I : INTEGER;
- BEGIN
- BUF[BUFCURSOR]:=CHR(13);
- BUFCURSOR:=BUFCURSOR+1;
- FOR I := 0 TO BUFCURSOR-1 DO
- WRITE(LST,BUF[I]);
- BUFCURSOR:=0;
- LINECOUNT:=LINECOUNT+1;
- IF (LINECOUNT MOD PAGESIZE) = 0 THEN
- PAGE(LST);
- END;
-
- PROCEDURE PUTALFA(S:ALFA);
- BEGIN
- MOVELEFT(S[1],BUF[BUFCURSOR],8);
- BUFCURSOR:=BUFCURSOR+8;
- END;
-
- PROCEDURE PUTNUMBER(NUM: INTEGER);
- VAR I,IPOT:INTEGER;
- A: ALFA;
- CH: CHAR;
- ZAP:BOOLEAN;
-
- BEGIN
- ZAP:=TRUE;
- IPOT:=10000;
- A[1]:=' ';
- FOR I:= 2 TO 6 DO
- BEGIN
- CH:=CHR(NUM DIV IPOT + ORD('0'));
- IF I <> 6 THEN
- IF ZAP THEN
- IF CH = '0' THEN
- CH:=' '
- ELSE ZAP:=FALSE;
- A[I]:=CH;
- NUM:=NUM MOD IPOT;
- IPOT:=IPOT DIV 10;
- END;
- A[7]:=' ';
- MOVELEFT(A,BUF[BUFCURSOR],7);
- BUFCURSOR:=BUFCURSOR+7;
- END;
-
- PROCEDURE SEARCH( ID: ALFA ); (*MODULO P HASH SEARCH*)
- (*GLOBAL: T, TOP*)
- VAR
- I,J,H,D : INTEGER;
- X : ITEMPTR;
- F : BOOLEAN;
-
- BEGIN
- J:=0;
- FOR I:= 1 TO ALFALEN DO
- J:= J*10+ORD(ID[I]);
- H := ABS(J) MOD P;
- F := FALSE;
- D := 1;
- REPEAT
- IF T[H].KEY = ID
- THEN
- BEGIN (*FOUND*)
- F := TRUE;
- IF T[H].LAST^.REFNUM = REFSPERITEM
- THEN
- BEGIN
- NEW(X);
- X^.REFNUM := 1;
- X^.REF[1] := LINECOUNT;
- T[H].LAST^.NEXT:= X;
- T[H].LAST := X;
- END
- ELSE
- WITH T[H].LAST^ DO
- BEGIN
- REFNUM := REFNUM + 1;
- REF[REFNUM] := LINECOUNT
- END
- END
- ELSE
- IF T[H].KEY = ' '
- THEN
- BEGIN (*NEW ENTRY*)
- F := TRUE;
- NEW(X);
- X^.REFNUM := 1;
- X^.REF[1] := LINECOUNT;
- T[H].KEY := ID;
- T[H].FIRST := X;
- T[H].LAST := X;
- T[H].FOL := TOP;
- TOP := H
- END
- ELSE
- BEGIN (*COLLISION*)
- H := H+D;
- D := D+2;
- IF H >= P
- THEN
- H := H - P;
- IF D = P
- THEN
- BEGIN
- WRITELN(OUTPUT,'TBLE OVFLW');
- ERROR := TRUE
- END ;
- END
- UNTIL F OR ERROR
- END (*SEARCH*) ;
-
-
-
- PROCEDURE PRINTWORD(W: WORD);
- VAR
- L: INTEGER;
- X: ITEMPTR;
- NEXTREF : INTEGER;
- THISREF: NUMREFS;
- BEGIN
- PUTALFA(W.KEY);
- X := W.FIRST;
- L := 0;
- REPEAT
- IF L = REFSPERLINE
- THEN
- BEGIN
- L := 0;
- LPWRITELN;
- PUTALFA(' ');
- END ;
- L := L+1;
- THISREF := (L-1) MOD REFSPERITEM + 1;
- NEXTREF := X^.REF[ THISREF ];
- IF THISREF = X^.REFNUM
- THEN
- X := NIL
- ELSE
- IF THISREF = REFSPERITEM
- THEN
- X := X^.NEXT;
- PUTNUMBER(NEXTREF);
- UNTIL X = NIL;
- LPWRITELN;
- END (*PRINTWORD*) ;
-
- PROCEDURE PRINTTABLE;
-
- VAR
- I,J,M: INDEX;
-
- BEGIN
- I := TOP;
- WHILE I <> P DO
- BEGIN (*FIND MINIMAL WORD*)
- M := I;
- J := T[I].FOL;
- WHILE J <> P DO
- BEGIN
- IF T[J].KEY < T[M].KEY
- THEN
- M := J;
- J := T[J].FOL
- END ;
- PRINTWORD(T[M]);
- IF M <> I THEN
- BEGIN
- T[M].KEY:=T[I].KEY;
- T[M].FIRST:=T[I].FIRST;
- T[M].LAST:=T[I].LAST;
- END;
- I := T[I].FOL
- END
- END (*PRINTTABLE*) ;
-
- PROCEDURE OUTPUT_LINE (BUF : BUFFER) ;
-
- VAR
- I : INTEGER ;
-
- PROCEDURE FILL_LINE (VAR LINE : BUFFER) ;
-
- VAR I : INTEGER ;
-
- BEGIN (* FILL_LINE *)
- I := 1 ;
- WHILE (LINE[I] = ' ') DO
- BEGIN
- LINE[I] := '-' ;
- I := I + 1
- END
- END ; (* FILL_LINE *)
-
-
-
- PROCEDURE PRTNEST (VAR LINE : BUFFER) ;
-
- VAR COL : INTEGER ;
-
-
- BEGIN (* PRTNEST *)
- FOR COL := 1 TO NESTLVL - 1 DO
- WRITE (LST, BAR, ' ') ;
- IF NESTLVL > 0 THEN
- IF NESTUP OR NESTDN THEN
- BEGIN
- IF NESTDN THEN
- BEGIN
- WRITE (LST, BAR, ' ') ;
- WRITE (LST, 'E--') ;
- FOR COL := NESTLVL+2 TO NESTMAX DO
- WRITE (LST, '---')
- END
- ELSE
- BEGIN
- WRITE (LST, 'B--') ;
- FOR COL := NESTLVL+1 TO NESTMAX DO
- WRITE (LST, '---')
- END ;
- FILL_LINE (LINE)
- END
- ELSE
- BEGIN
- WRITE (LST, BAR, ' ') ;
- FOR COL := NESTLVL+1 TO NESTMAX DO
- WRITE (LST, ' ')
- END
- ELSE
- IF NESTDN THEN
- BEGIN
- WRITE (LST, 'E--') ;
- FOR COL := 2 TO NESTMAX DO
- WRITE (LST, '---') ;
- FILL_LINE (LINE)
- END
- ELSE
- FOR COL := 1 TO NESTMAX DO
- WRITE (LST, ' ')
- END ; (* PRTNEST *)
-
- BEGIN (* OUTPUT_LINE *)
- IF ((LINECOUNT MOD PAGESIZE) = 0) OR (PAGE_NUM = 1) THEN
- BEGIN
- IF LISTING THEN
- BEGIN
- PAGE (LST) ;
- WRITELN (LST, TAB(70), 'PAGE ', PAGE_NUM:1) ;
- WRITELN (LST) ;
- PAGE_NUM := PAGE_NUM + 1
- END ;
- IF (LSTFILENAME <> 'CON:') AND ((LINECOUNT MOD PAGESIZE) = 0) THEN
- WRITELN (OUTPUT, '< ', LINECOUNT:4, ',', MEMAVAIL:5, ' >')
- END ;
- WRITE (LST, LINECOUNT:4, ' ') ;
- PRTNEST (BUF) ;
- FOR I := 1 TO BUFCURSOR DO
- WRITE (LST, BUF[I]) ;
- WRITELN (LST) ;
- IF LSTFILENAME <> 'CON:' THEN
- WRITE (OUTPUT, '.')
- END ; (* OUTPUT_LINE *)
-
-
- PROCEDURE GETNEXTCHAR;
- VAR I : INTEGER;
-
- BEGIN (* GETNEXTCHAR *)
- IF BUFCURSOR >= LENGTH (INPUT_LINE) THEN
- BEGIN
- EOL := TRUE ;
- CH := ' ' ;
- ERROR := EOF(INFILE)
- END
- ELSE
- BEGIN
- BUFCURSOR := BUFCURSOR + 1 ;
- CH := INPUT_LINE [BUFCURSOR] ;
- BUF [BUFCURSOR] := CH ;
- CH := UPPER(CH)
- END
- END; (* GETNEXTCHAR *)
-
-
- PROCEDURE GETIDENTIFIER;
- VAR
- J,K,I: INTEGER;
- ID: ALFA;
-
- BEGIN (* GETIDENTIFIER *)
- I := 0;
- ID := ' ';
- REPEAT
- IF I < ALFALEN
- THEN
- BEGIN
- I := I+1;
- ID[I] := CH
- END;
- GETNEXTCHAR
- UNTIL ( NOT(((CH>='A') AND (CH<='Z')) OR (CH='_')
- OR ((CH>='0') AND (CH<='9')))) OR (ERROR);
- I := 1;
- J := NK;
- REPEAT
- K := (I+J) DIV 2; (*BINARY SEARCH*)
- IF KEY[K] <= ID
- THEN
- I := K+1;
-
- IF KEY[K] >= ID
- THEN
- J := K-1;
-
- UNTIL I > J;
- IF KEY[K] <> ID THEN
- SEARCH(ID)
- ELSE
- BEGIN
- IF (K=3) OR ((K=5) AND (LAST_KEY<>32)) OR { BEGIN or CASE }
- (K=32) OR (K=33) THEN { RECORD or REPEAT }
- BEGIN
- LAST_KEY := K ;
- IF NESTLVL = NESTMAX THEN
- WRITE (LST, '----Too many levels')
- ELSE
- BEGIN
- NESTLVL := NESTLVL + 1 ;
- NESTUP := TRUE
- END
- END ;
- IF (K=12) OR (K=40) THEN { END or UNTIL }
- IF NESTLVL = 0 THEN
- WRITE (LST, '----Nesting error ')
- ELSE
- BEGIN
- NESTLVL := NESTLVL - 1 ;
- NESTDN := TRUE
- END
- END
-
- END; (* GETIDENTIFIER *)
-
- BEGIN (* CROSSREF *)
-
- INITIALIZE;
-
- OPENFILES;
-
- WHILE NOT EOF(INFILE) AND (NOT ABORT) DO
- BEGIN
- BUFCURSOR:= 0;
- NESTUP := FALSE ;
- NESTDN := FALSE ;
- READLN (INFILE, INPUT_LINE) ;
- IF LENGTH (INPUT_LINE) > 0 THEN
- BEGIN
- EOL := FALSE ;
- BUFCURSOR := BUFCURSOR + 1 ;
- CH := INPUT_LINE [BUFCURSOR] ;
- BUF [BUFCURSOR] := CH ;
- CH := UPPER (CH)
- END
- ELSE
- BEGIN
- EOL := TRUE ;
- CH := ' '
- END ;
- WHILE NOT EOL DO
- BEGIN
- IF ((CH >= 'A') AND (CH <= 'Z')) AND (NOT LITERAL) AND
- (NOT ACOMMENT) AND (NOT BCOMMENT) THEN
- GETIDENTIFIER
- ELSE
- IF (CH = '''') OR LITERAL THEN
- BEGIN
- REPEAT
- GETNEXTCHAR;
- UNTIL (CH = '''') OR (ERROR) OR EOL;
- LITERAL := EOL ;
- GETNEXTCHAR
- END
- ELSE
- IF (CH = '{') OR ACOMMENT THEN
- BEGIN
- WHILE (CH <> '}') AND (NOT ERROR) AND (NOT EOL) DO
- GETNEXTCHAR ;
- ACOMMENT := EOL ;
- GETNEXTCHAR
- END
- ELSE
- IF (CH = '(') OR BCOMMENT THEN
- BEGIN
- IF NOT BCOMMENT THEN
- GETNEXTCHAR;
- IF (CH = '*') OR BCOMMENT THEN
- BEGIN
- IF NOT BCOMMENT THEN
- GETNEXTCHAR;
- REPEAT
- WHILE (CH <> '*') AND (NOT ERROR) AND (NOT EOL) DO
- GETNEXTCHAR ;
- BCOMMENT := EOL ;
- IF NOT EOL THEN
- GETNEXTCHAR
- UNTIL (CH = ')') OR ERROR OR EOL ;
- IF NOT EOL THEN
- GETNEXTCHAR
- END
- END
- ELSE
- GETNEXTCHAR;
-
- END; (* WHILE *)
- EOL := FALSE ;
- OUTPUT_LINE (BUF) ;
- LINECOUNT := LINECOUNT + 1
- END ;
- IF NOT ABORT THEN
- BEGIN
- PAGE(LST);
- LINECOUNT := 0;
- BUFCURSOR := 0;
- PRINTTABLE;
- PAGE(LST);
- CLOSE(LST,I);
- IF I = 255 THEN
- WRITELN('Error closing output file')
- END
- END.
-