home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frostbyte's 1980s DOS Shareware Collection
/
floppyshareware.zip
/
floppyshareware
/
USCX
/
TURBO-06.ZIP
/
XLIST.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1985-02-23
|
17KB
|
638 lines
Program XLIST(input,output);
{This program produces a cross-reference listing for a
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.
Note: This program, originally written by N. Wirth,
uses the 'quadratic quotient' hash method. It was
adapted for UCSD Pascal (1.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. It was adapted for Turbo Pascal
by Ron Finger in July 1984. This is a public domain program.}
{$I-}
{$V-}
Const
P = 749; {SIZE of HASHTABLE}
NK = 45; {NO. of KEYWORDS}
PAGESIZE = 57; {LINES PER PAGE}
ALFALEN = 8; {SIZE of IDENTIFIERS}
REFSPERLINE = 17;
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,LST: Text;
LSTFILENAME : String[14];
INPUT_LINE : String[120];
LAST_KEY,PAGE_NUM,NESTLVL:Integer;
ABORT,LITERAL,ACOMMENT,BCOMMENT,EOL,NESTUP,NESTDN,NODOT:Boolean;
BAR : Char ;
FILENAME,FILETITLE:String[14];
DATE:String[20];
LDATE,LTITLE:Byte;
FUNCTION TAB (NUM : Integer) : Char ;
Var
I : Integer ;
Begin
For I := 1 to NUM do
Write (LST, ' ') ;
TAB := CHR(0)
End ; { TAB }
Procedure TITLELINE;
Begin
If PAGE_NUM > 1 then
Writeln(LST,^L);
Writeln(LST);
Writeln(LST);
Write(LST,'File: ',FILETITLE);
Write(LST,TAB(15),'Cross-Reference & Block Listing',TAB(15));
If LDATE>5 then
Write(LST,'Date: ',DATE);
Write(LST,TAB(50-(LDATE+LTITLE)));
Writeln (LST,'Page ', PAGE_NUM:1);
Writeln (LST) ;
PAGE_NUM := PAGE_NUM + 1
End ; {TITLELINE}
Procedure LPWRITELN;
Var
I : Integer;
Begin
BUF[BUFCURSOR]:=CHR(13);
BUFCURSOR:=BUFCURSOR+1;
For I := 0 to BUFCURSOR-1 do
Write(LST,BUF[I]);
Writeln(LST);
BUFCURSOR:=0;
LINECOUNT:=LINECOUNT+1;
If (LINECOUNT MOD PAGESIZE) = 0 then
TITLELINE;
End;
Procedure INITIALIZE;
Var
I : Integer;
Begin { INITIALIZE }
FF:=CHR(12);
ERROR := FALSE;
For I := 0 to P do
T[I].KEY := ' ';
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';
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 ';
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,NUMBLOCKS,OPENERRNUM: Integer;
OPENOK: Boolean;
LISTOPTION: Char;
Begin { OPEN }
Writeln;
ABORT := FALSE ;
Repeat
NODOT := TRUE;
Write('Filename: ( CR to quit): ');
READLN( FILENAME );
ABORT := Length(FILENAME) <= 0;
If NOT ABORT then
Begin
For I := 1 to LENGTH(FILENAME) do
Begin
FILENAME[I] := UPcase(FILENAME[I]) ;
If FILENAME[I] = '.' then
NODOT := False
End;
If NODOT then
FILENAME := FILENAME + '.PAS';
ASSIGN(INFILE,FILENAME);
RESET(INFILE);
OPENERRNUM := IORESULT;
OPENOK := ( OPENERRNUM = 0);
If NOT OPENOK then
Writeln(FILENAME,' not found')
Else
FILETITLE := FILENAME;
If POS(':',FILETITLE) = 2 then
DELETE(FILETITLE,1,2);
LTITLE := LENGTH(FILETITLE);
End;
Until OPENOK OR ABORT;
If NOT ABORT then
Begin
Write('Destination file or device (CR for LST:): ');
READLN(LSTFILENAME);
If LENGTH (LSTFILENAME) <= 0 then
LSTFILENAME := 'LST:' ;
For I := 1 to LENGTH(LSTFILENAME) do
LSTFILENAME[I] := UPcase(LSTFILENAME[I]) ;
ASSIGN(LST,LSTFILENAME);
Rewrite(LST);
End;
If NOT ABORT then
Begin
Repeat
Write('Do you want a listing (Y/N)? ');
READLN( LISTOPTION );
LISTOPTION := UPcase(LISTOPTION);
Until LISTOPTION IN ['Y','N'];
LISTING := LISTOPTION = 'Y';
If LDATE=5 then
Begin
Write('Date: ');
READLN(DATE);
LDATE:=LENGTH(DATE)+5
End;
End
End; {open}
Procedure PUTALFA(S:ALFA);
Begin
MOVE(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]:=' ';
MOVE(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,NEXTREF: Integer;
X: ITEMPTR;
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
TITLELINE;
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 := UPcase(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 }
LDATE:=5;
Repeat
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 := UPcase (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 ;
If LISTING then
OUTPUT_LINE (BUF) ;
LINECOUNT := LINECOUNT + 1
End ;
If NOT ABORT then
Begin
TITLELINE;
LINECOUNT := 0;
BUFCURSOR := 0;
PRINTTABLE;
Writeln(LST,^L);
CLOSE(LST);
If IOresult <> 0 then
Writeln('Error closing output file')
End;
Until LENGTH(FILENAME) <= 0
End.