home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frostbyte's 1980s DOS Shareware Collection
/
floppyshareware.zip
/
floppyshareware
/
USCX
/
TURBO-06.ZIP
/
TXREF.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1985-02-23
|
15KB
|
521 lines
program TXREF;
{$V-}
{$R+}
{ Program TXREF - Produce a Listing and Cross Reference for a Turbo Pascal
source file.
You must have Turbo Toolbox from Borland International, Inc. in order to
compile this program.
As written, this program assumes that you have an Epson FX-80 printer. It
may work on other printers if they are compatible enough.
By Michael Quinlan
Version 1.0.0
12/1/84
Known bugs:
1. This program doesn't correctly handle certain types of constants;
the 'E' in a floating point constant will be considered a name as
will some hex constants. The procedure CopyTillAlpha needs to be
re-written to handle these things better.
2. Numeric labels are not included in the cross reference.
3. Names longer than 79 bytes may mess up the page alignment while
printing the cross reference.
}
const
LinesPerPage = 60;
Type
Str = String[127];
XrefRec = record
Name : Str;
Page : Integer;
Line : Integer;
end;
var
XrefVar : XrefRec;
NumOnLine : Integer;
CurLine : Integer;
CurPage : Integer;
SortResult : Integer;
InFileName : Str;
InFile : Text;
Line : Str;
CurPosn : Integer;
CommentStatus : (NoComment, CurlyBracket, ParenStar);
InsideString : Boolean;
const
NumReservedWords = 44;
BiggestReservedWord = 9;
ReservedWordList : array [1..NumReservedWords] of String[BiggestReservedWord]
= (
'ABSOLUTE', 'AND' , 'ARRAY' , 'BEGIN', 'CASE' , 'CONST' , 'DIV',
'DO' , 'DOWNTO' , 'ELSE' , 'END' , 'EXTERNAL', 'FILE' , 'FOR',
'FORWARD' , 'FUNCTION', 'GOTO' , 'IF' , 'IN' , 'INLINE', 'LABEL',
'MOD' , 'NIL' , 'NOT' , 'OF' , 'OR' , 'PACKED', 'PROCEDURE',
'PROGRAM' , 'RECORD' , 'REPEAT', 'SET' , 'SHL' , 'SHR' , 'STRING',
'THEN' , 'TO' , 'TYPE' , 'UNTIL', 'VAR' , 'WHILE' , 'WITH',
'XOR' , 'OVERLAY');
var
ReservedWordHashTable : array [1..NumReservedWords] of
record
WordPtr : Integer;
NextPtr : Integer
end;
{$IC:SORT.BOX} { Include the sort routines from Turbo ToolBox }
{=======================================================================}
{ Printer Routines }
{=======================================================================}
procedure Printer_Init;
{ Init the printer to 132 column mode }
begin
Write(Lst, #15)
end;
procedure Printer_Reset;
{ reset printer back to 80 column mode }
begin
Write(Lst, #18) { turn compressed mode off }
end;
procedure Printer_Underscore;
{ Turn on underlines }
begin
Write(Lst, #27'-1') { turn on underlines }
end;
procedure Printer_NoUnderscore;
{ Turn off underlines }
begin
Write(Lst, #27'-0') { turn off underlines }
end;
procedure Printer_Eject;
{ Eject to a new page }
begin
Write(Lst, #12)
end;
{======================================================================}
{ Procedures for handling the hash table; this is used to speed up }
{ checking for reserved words. }
{======================================================================}
function ReservedWordHash(var w : Str) : Integer;
var
c : char;
h : integer;
i : integer;
n : integer;
begin
h := 0;
n := 1;
for i := 1 to (length(w) div 2) do
begin
h := h xor ((Ord(w[n]) shl 8) or Ord(w[n+1]));
n := n + 2
end;
if n = length(w) then
h := h xor Ord(w[n]);
ReservedWordHash := ((h and $7FFF) mod NumReservedWords) + 1
end;
procedure SetUpReservedWordHashTable;
var
h : integer;
i : integer;
NewH : integer;
MinProbes, MaxProbes, NumProbes, TotProbes : integer; { for debugging only }
AvgProbes : Real; { for debugging only }
function FindFreeEntry(h : integer) : integer;
begin
repeat
if h >= NumReservedWords then h := 1
else h := h + 1
until ReservedWordHashTable[h].WordPtr = 0;
FindFreeEntry := h
end;
begin
for i := 1 to NumReservedWords do
begin
ReservedWordHashTable[i].WordPtr := 0;
ReservedWordHashTable[i].NextPtr := 0
end;
for i := 1 to NumReservedWords do
begin
h := ReservedWordHash(ReservedWordList[i]);
if ReservedWordHashTable[h].WordPtr = 0 then
ReservedWordHashTable[h].WordPtr := i
else
begin { handle collisions }
{ first find the end of the chain }
while ReservedWordHashTable[h].NextPtr <> 0 do
h := ReservedWordHashTable[h].NextPtr;
{ now attach the new entry onto the end of the chain }
NewH := FindFreeEntry(h);
ReservedWordHashTable[h].NextPtr := Newh;
ReservedWordHashTable[NewH].WordPtr := i
end
end;
{ the following is for debugging only }
(***********************************************************************
D E B U G G I N G C O D E C O M M E N T E D O U T
***********************************************************************
{ calculate the min, max, and average number of probes required into the
hash table }
TotProbes := 0;
MinProbes := MaxInt;
MaxProbes := 0;
for i := 1 to NumReservedWords do
begin
h := ReservedWordHash(ReservedWordList[i]);
NumProbes := 1;
while ReservedWordHashTable[h].WordPtr <> i do
begin
NumProbes := NumProbes + 1;
h := ReservedWordHashTable[h].NextPtr
end;
TotProbes := TotProbes + NumProbes;
if NumProbes > MaxProbes then MaxProbes := NumProbes;
if NumProbes < MinProbes then MinProbes := NumProbes
end;
AvgProbes := TotProbes / NumReservedWords;
writeln('RESERVED WORD HASH TABLE STATISTICS');
writeln(' Max Probes = ', MaxProbes);
writeln(' Min Probes = ', MinProbes);
writeln(' Avg Probes = ', AvgProbes:8:2)
*************************************************************************)
end;
{======================================================================}
{ Procedures to set up the input file. }
{======================================================================}
procedure UpStr(var s : Str);
var
i : integer;
begin
for i := 1 to length(s) do s[i] := UpCase(s[i])
end;
function GetParm : Str;
var
Parm : Str absolute CSeg:$80;
begin
GetParm := Parm
end;
function AskFileName : Str;
var
f : Str;
begin
Write('Name of file to cross reference: ');
Readln(f);
if f = '' then halt; { provide an exit for the user }
AskFileName := f
end;
function OpenInFile : boolean;
begin
UpStr(InFileName); { convert file name to upper case }
if Pos('.', InFileName) = 0 then InFileName := InFileName + '.PAS';
Assign(InFile, InFileName);
{$I-} Reset(InFile); {$I+}
OpenInFile := (IOResult = 0)
end;
procedure GetInFile;
begin
{ on entry, InFileName may already have the file name }
if InFileName = '' then InFileName := AskFileName;
while not OpenInFile do
begin
Writeln('Cannot open ', InFileName);
InFileName := AskFileName
end
end;
procedure NewPage;
begin
if CurPage = 0 then
begin
Writeln('Make sure printer is lined up at the top of the page and powered on.');
Write('Press Enter when ready... ');
readln;
Printer_Init { set printer in 132 column mode }
end
else
Printer_Eject;
CurPage := CurPage + 1;
CurLine := 1;
Writeln(Lst, 'Page ', CurPage:5, 'Listing of ':60, InFileName);
Writeln(Lst)
end;
procedure ReadLine;
begin
Readln(InFile, Line);
if CurLine >= LinesPerPage then NewPage
else CurLine := CurLine + 1;
CurPosn := 1;
InsideString := FALSE;
Write(Lst, CurLine:2, ': ')
end;
{======================================================================}
{ Procedures to process the input file. }
{======================================================================}
procedure CopyTillAlpha;
{ copy chars from Line to the printer until the start of a name is found }
begin
while (CurPosn <= length(Line)) and
(not (Line[CurPosn] in ['A'..'Z','a'..'z','_']) or InsideString or
(CommentStatus <> NoComment)) do
begin
if CommentStatus = NoComment then
begin
if Line[CurPosn] = '''' then InsideString := not InsideString
end;
if not InsideString then
case CommentStatus of
NoComment : begin
if Line[CurPosn] = '{' then CommentStatus := CurlyBracket
else if CurPosn < length(Line) then
begin
if Copy(Line, CurPosn, 2) = '(*' then
CommentStatus := ParenStar
end
end;
CurlyBracket : if Line[CurPosn] = '}' then CommentStatus := NoComment;
ParenStar : if CurPosn < length(Line) then
begin
if Copy(Line, CurPosn, 2) = '*)' then
CommentStatus := NoComment
end
end; { Case }
Write(Lst, Line[CurPosn]);
CurPosn := CurPosn + 1
end
end;
function Reserved(var w : Str) : boolean;
var
h : integer;
r : (DontKnow, IsReserved, NotReserved);
begin
h := ReservedWordHash(w);
r := DontKnow;
repeat
if w = ReservedWordList[ReservedWordHashTable[h].WordPtr] then
r := IsReserved
else if ReservedWordHashTable[h].NextPtr = 0 then
r := NotReserved
else h := ReservedWordHashTable[h].NextPtr
until r <> DontKnow;
Reserved := (r = IsReserved)
end;
procedure WriteReserved(var w : Str);
begin
Printer_Underscore; { turn on underscores }
write(Lst, w);
Printer_NoUnderscore { turn off underscores }
end;
procedure WriteWord(var Word, CapWord : Str);
begin
XrefVar.Name := CapWord;
XrefVar.Page := CurPage;
XrefVar.Line := CurLine;
SortRelease(XrefVar);
write(Lst, Word)
end;
procedure DoWord;
var
wstart : integer;
Word : Str;
CapWord : Str;
begin
wstart := CurPosn;
repeat
CurPosn := CurPosn + 1
until (CurPosn > length(Line)) or not (Line[CurPosn] in ['A'..'Z','a'..'z','_','0'..'9']);
Word := Copy(Line, wstart, CurPosn - wstart);
CapWord := Word;
UpStr(CapWord); { Upper case version of the word }
if Reserved(CapWord) then
WriteReserved(Word)
else
WriteWord(Word, CapWord)
end;
procedure Inp;
begin
GetInFile;
CurLine := 1000; { force page break on first line }
CurPage := 0;
CommentStatus := NoComment;
while not EOF(InFile) do
begin
ReadLine;
while CurPosn <= length(Line) do
begin
CopyTillAlpha;
if CurPosn <= length(Line) then DoWord
end;
Writeln(Lst)
end
end;
{======================================================================}
{ Procedure called by TurboSort to order the cross reference entries }
{======================================================================}
function Less;
var
FirstRec : XrefRec absolute X;
SecondRec : XrefRec absolute Y;
begin
if FirstRec.Name = SecondRec.Name then
begin
if FirstRec.Page = SecondRec.Page then
Less := FirstRec.Line < SecondRec.Line
else
Less := FirstRec.Page < SecondRec.Page
end
else
Less := FirstRec.Name < SecondRec.Name
end;
{======================================================================}
{ Procedures to print the sorted cross reference }
{======================================================================}
procedure Xref_NewPage;
begin
Printer_Eject;
Writeln(Lst, 'C R O S S R E F E R E N C E':54);
Writeln(Lst, 'Entries are PAGE:LINE':50);
Writeln(Lst);
CurLine := 0
end;
procedure Xref_NewLine;
begin
Writeln(Lst);
if CurLine >= LinesPerPage then Xref_NewPage
else CurLine := CurLine + 1;
NumOnLine := 0
end;
procedure Xref_Write_Number(n, count : integer);
{ write "n" to Lst with "count" digits (add leading zeros) }
var
s : Str;
i : integer;
begin
for i := count downto 1 do
begin
s[i] := Chr((n mod 10) + Ord('0'));
n := n div 10
end;
s[0] := Chr(count); { set correct string length }
write(Lst, s)
end;
procedure Xref_Write;
begin
if NumOnLine >= 8 then Xref_NewLine;
if NumOnLine = 0 then Write(Lst, ' ');
Write(Lst, ' ');
Xref_Write_Number(XrefVar.Page, 5);
Write(Lst, ':');
Xref_Write_Number(XrefVar.Line, 2);
NumOnLine := NumOnLine + 1
end;
procedure Xref_NewName;
begin
if (CurLine + 2) >= LinesPerPage then Xref_NewPage;
Write(Lst, XrefVar.Name);
Xref_NewLine
end;
procedure Outp;
var
CurName : Str;
begin
Printer_Reset; { put printer back into 80 column mode }
Xref_NewPage;
SortReturn(XrefVar);
CurName := XrefVar.Name;
Xref_NewName;
Xref_Write;
while not SortEOS do
begin
SortReturn(XrefVar);
if CurName <> XrefVar.Name then
begin
Xref_NewLine;
CurName := XrefVar.Name;
Xref_NewName
end;
Xref_Write
end;
Writeln(Lst);
Printer_Eject
end;
{======================================================================}
{ Main Program }
{======================================================================}
begin
Write('Pascal Source Listing and Cross Reference Program V1.0.0');
Writeln(' By Michael Quinlan');
Writeln;
SetUpReservedWordHashTable;
InFileName := GetParm;
while (length(InFileName)>0) and (InFileName[1] = ' ') do
delete(InFileName, 1, 1);
SortResult := TurboSort(SizeOf(XrefRec));
writeln;
case SortResult of
0 : Writeln('Program Completed OK');
3 : Writeln('Insufficient Memory for Sort');
8 : Writeln('Illegal Item Length for Sort (Program Logic Error)');
9 : Writeln('More Than ', MaxInt, ' Items to be Sorted');
10 : Writeln('Sort Error, Disk Error or Disk Full?');
11 : Writeln('Write Error During Sort, Bad Disk?');
12 : Writeln('File Creation Error During Sort')
else
Writeln('Unknown Error ', SortResult, ' From Sort')
end; { Case }
if SortResult <> 0 then
Writeln('*** Sort Failed; Cross Reference Invalid or Incomplete')
end.