home *** CD-ROM | disk | FTP | other *** search
/ Frostbyte's 1980s DOS Shareware Collection / floppyshareware.zip / floppyshareware / USCX / TURBO-06.ZIP / TXREF.PAS < prev    next >
Pascal/Delphi Source File  |  1985-02-23  |  15KB  |  521 lines

  1. program TXREF;
  2.  
  3. {$V-}
  4. {$R+}
  5.  
  6. {  Program TXREF - Produce a Listing and Cross Reference for a Turbo Pascal
  7.    source file.
  8.  
  9.    You must have Turbo Toolbox from Borland International, Inc. in order to
  10.    compile this program.
  11.  
  12.    As written, this program assumes that you have an Epson FX-80 printer. It
  13.    may work on other printers if they are compatible enough.
  14.  
  15.    By Michael Quinlan
  16.       Version 1.0.0
  17.       12/1/84
  18.  
  19.   Known bugs:
  20.  
  21.     1. This program doesn't correctly handle certain types of constants;
  22.        the 'E' in a floating point constant will be considered a name as
  23.        will some hex constants. The procedure CopyTillAlpha needs to be
  24.        re-written to handle these things better.
  25.  
  26.     2. Numeric labels are not included in the cross reference.
  27.  
  28.     3. Names longer than 79 bytes may mess up the page alignment while
  29.        printing the cross reference.
  30.  
  31. }
  32.  
  33. const
  34.   LinesPerPage = 60;
  35.  
  36. Type
  37.   Str = String[127];
  38.   XrefRec = record
  39.               Name : Str;
  40.               Page : Integer;
  41.               Line : Integer;
  42.             end;
  43.  
  44. var
  45.   XrefVar       : XrefRec;
  46.   NumOnLine     : Integer;
  47.   CurLine       : Integer;
  48.   CurPage       : Integer;
  49.   SortResult    : Integer;
  50.   InFileName    : Str;
  51.   InFile        : Text;
  52.   Line          : Str;
  53.   CurPosn       : Integer;
  54.   CommentStatus : (NoComment, CurlyBracket, ParenStar);
  55.   InsideString  : Boolean;
  56.  
  57. const
  58.  NumReservedWords = 44;
  59.  BiggestReservedWord = 9;
  60.  ReservedWordList : array [1..NumReservedWords] of String[BiggestReservedWord]
  61.    = (
  62.   'ABSOLUTE', 'AND'     , 'ARRAY' , 'BEGIN', 'CASE'    , 'CONST' , 'DIV',
  63.   'DO'      , 'DOWNTO'  , 'ELSE'  , 'END'  , 'EXTERNAL', 'FILE'  , 'FOR',
  64.   'FORWARD' , 'FUNCTION', 'GOTO'  , 'IF'   , 'IN'      , 'INLINE', 'LABEL',
  65.   'MOD'     , 'NIL'     , 'NOT'   , 'OF'   , 'OR'      , 'PACKED', 'PROCEDURE',
  66.   'PROGRAM' , 'RECORD'  , 'REPEAT', 'SET'  , 'SHL'     , 'SHR'   , 'STRING',
  67.   'THEN'    , 'TO'      , 'TYPE'  , 'UNTIL', 'VAR'     , 'WHILE' , 'WITH',
  68.   'XOR'     , 'OVERLAY');
  69.  
  70. var
  71.   ReservedWordHashTable : array [1..NumReservedWords] of
  72.                             record
  73.                               WordPtr : Integer;
  74.                               NextPtr : Integer
  75.                             end;
  76.  
  77.  {$IC:SORT.BOX}  { Include the sort routines from Turbo ToolBox }
  78.  
  79. {=======================================================================}
  80. {  Printer Routines                                                     }
  81. {=======================================================================}
  82.  
  83. procedure Printer_Init;
  84. { Init the printer to 132 column mode }
  85. begin
  86.   Write(Lst, #15)
  87. end;
  88.  
  89. procedure Printer_Reset;
  90. { reset printer back to 80 column mode }
  91. begin
  92.   Write(Lst, #18)  { turn compressed mode off }
  93. end;
  94.  
  95. procedure Printer_Underscore;
  96. { Turn on underlines }
  97. begin
  98.   Write(Lst, #27'-1')  { turn on underlines }
  99. end;
  100.  
  101. procedure Printer_NoUnderscore;
  102. { Turn off underlines }
  103. begin
  104.   Write(Lst, #27'-0')  { turn off underlines }
  105. end;
  106.  
  107. procedure Printer_Eject;
  108. { Eject to a new page }
  109. begin
  110.   Write(Lst, #12)
  111. end;
  112.  
  113. {======================================================================}
  114. { Procedures for handling the hash table; this is used to speed up     }
  115. { checking for reserved words.                                         }
  116. {======================================================================}
  117.  
  118. function ReservedWordHash(var w : Str) : Integer;
  119. var
  120.   c : char;
  121.   h : integer;
  122.   i : integer;
  123.   n : integer;
  124. begin
  125.   h := 0;
  126.   n := 1;
  127.   for i := 1 to (length(w) div 2) do
  128.     begin
  129.       h := h xor ((Ord(w[n]) shl 8) or Ord(w[n+1]));
  130.       n := n + 2
  131.     end;
  132.   if n = length(w) then
  133.     h := h xor Ord(w[n]);
  134.   ReservedWordHash := ((h and $7FFF) mod NumReservedWords) + 1
  135. end;
  136.  
  137. procedure SetUpReservedWordHashTable;
  138. var
  139.   h : integer;
  140.   i : integer;
  141.   NewH : integer;
  142.   MinProbes, MaxProbes, NumProbes, TotProbes : integer;  { for debugging only }
  143.   AvgProbes : Real;  { for debugging only }
  144.  
  145.   function FindFreeEntry(h : integer) : integer;
  146.   begin
  147.     repeat
  148.       if h >= NumReservedWords then h := 1
  149.       else h := h + 1
  150.     until ReservedWordHashTable[h].WordPtr = 0;
  151.     FindFreeEntry := h
  152.   end;
  153.  
  154. begin
  155.   for i := 1 to NumReservedWords do
  156.     begin
  157.       ReservedWordHashTable[i].WordPtr := 0;
  158.       ReservedWordHashTable[i].NextPtr := 0
  159.     end;
  160.   for i := 1 to NumReservedWords do
  161.     begin
  162.       h := ReservedWordHash(ReservedWordList[i]);
  163.       if ReservedWordHashTable[h].WordPtr = 0 then
  164.         ReservedWordHashTable[h].WordPtr := i
  165.       else
  166.         begin { handle collisions }
  167.           { first find the end of the chain }
  168.           while ReservedWordHashTable[h].NextPtr <> 0 do
  169.             h := ReservedWordHashTable[h].NextPtr;
  170.           { now attach the new entry onto the end of the chain }
  171.           NewH := FindFreeEntry(h);
  172.           ReservedWordHashTable[h].NextPtr := Newh;
  173.           ReservedWordHashTable[NewH].WordPtr := i
  174.         end
  175.     end;
  176.  
  177. { the following is for debugging only }
  178.   (***********************************************************************
  179.  
  180.      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
  181.  
  182.    ***********************************************************************
  183.  
  184.   { calculate the min, max, and average number of probes required into the
  185.     hash table }
  186.   TotProbes := 0;
  187.   MinProbes := MaxInt;
  188.   MaxProbes := 0;
  189.   for i := 1 to NumReservedWords do
  190.     begin
  191.       h := ReservedWordHash(ReservedWordList[i]);
  192.       NumProbes := 1;
  193.       while ReservedWordHashTable[h].WordPtr <> i do
  194.         begin
  195.           NumProbes := NumProbes + 1;
  196.           h := ReservedWordHashTable[h].NextPtr
  197.         end;
  198.       TotProbes := TotProbes + NumProbes;
  199.       if NumProbes > MaxProbes then MaxProbes := NumProbes;
  200.       if NumProbes < MinProbes then MinProbes := NumProbes
  201.     end;
  202.   AvgProbes := TotProbes / NumReservedWords;
  203.   writeln('RESERVED WORD HASH TABLE STATISTICS');
  204.   writeln(' Max Probes = ', MaxProbes);
  205.   writeln(' Min Probes = ', MinProbes);
  206.   writeln(' Avg Probes = ', AvgProbes:8:2)
  207.  
  208. *************************************************************************)
  209.  
  210. end;
  211.  
  212. {======================================================================}
  213. {  Procedures to set up the input file.                                }
  214. {======================================================================}
  215.  
  216. procedure UpStr(var s : Str);
  217. var
  218.   i : integer;
  219. begin
  220.   for i := 1 to length(s) do s[i] := UpCase(s[i])
  221. end;
  222.  
  223. function GetParm : Str;
  224. var
  225.   Parm : Str absolute CSeg:$80;
  226. begin
  227.   GetParm := Parm
  228. end;
  229.  
  230. function AskFileName : Str;
  231. var
  232.   f : Str;
  233. begin
  234.   Write('Name of file to cross reference: ');
  235.   Readln(f);
  236.   if f = '' then halt;  { provide an exit for the user }
  237.   AskFileName := f
  238. end;
  239.  
  240. function OpenInFile : boolean;
  241. begin
  242.   UpStr(InFileName);  { convert file name to upper case }
  243.   if Pos('.', InFileName) = 0 then InFileName := InFileName + '.PAS';
  244.   Assign(InFile, InFileName);
  245.   {$I-} Reset(InFile); {$I+}
  246.   OpenInFile := (IOResult = 0)
  247. end;
  248.  
  249. procedure GetInFile;
  250. begin
  251. { on entry, InFileName may already have the file name }
  252.   if InFileName = '' then InFileName := AskFileName;
  253.   while not OpenInFile do
  254.     begin
  255.       Writeln('Cannot open ', InFileName);
  256.       InFileName := AskFileName
  257.     end
  258. end;
  259.  
  260. procedure NewPage;
  261. begin
  262.   if CurPage = 0 then
  263.     begin
  264.       Writeln('Make sure printer is lined up at the top of the page and powered on.');
  265.       Write('Press Enter when ready... ');
  266.       readln;
  267.       Printer_Init  { set printer in 132 column mode }
  268.     end
  269.   else
  270.     Printer_Eject;
  271.   CurPage := CurPage + 1;
  272.   CurLine := 1;
  273.   Writeln(Lst, 'Page ', CurPage:5, 'Listing of ':60, InFileName);
  274.   Writeln(Lst)
  275. end;
  276.  
  277. procedure ReadLine;
  278. begin
  279.   Readln(InFile, Line);
  280.   if CurLine >= LinesPerPage then NewPage
  281.   else CurLine := CurLine + 1;
  282.   CurPosn := 1;
  283.   InsideString := FALSE;
  284.   Write(Lst, CurLine:2, ': ')
  285. end;
  286.  
  287. {======================================================================}
  288. {  Procedures to process the input file.                               }
  289. {======================================================================}
  290.  
  291. procedure CopyTillAlpha;
  292. { copy chars from Line to the printer until the start of a name is found }
  293. begin
  294.   while (CurPosn <= length(Line)) and
  295.          (not (Line[CurPosn] in ['A'..'Z','a'..'z','_']) or InsideString or
  296.           (CommentStatus <> NoComment)) do
  297.     begin
  298.       if CommentStatus = NoComment then
  299.         begin
  300.           if Line[CurPosn] = '''' then InsideString := not InsideString
  301.         end;
  302.       if not InsideString then
  303.         case CommentStatus of
  304.           NoComment : begin
  305.                         if Line[CurPosn] = '{' then CommentStatus := CurlyBracket
  306.                         else if CurPosn < length(Line) then
  307.                                begin
  308.                                  if Copy(Line, CurPosn, 2) = '(*' then
  309.                                    CommentStatus := ParenStar
  310.                                end
  311.                       end;
  312.           CurlyBracket : if Line[CurPosn] = '}' then CommentStatus := NoComment;
  313.           ParenStar    : if CurPosn < length(Line) then
  314.                            begin
  315.                              if Copy(Line, CurPosn, 2) = '*)' then
  316.                                CommentStatus := NoComment
  317.                            end
  318.         end; { Case }
  319.       Write(Lst, Line[CurPosn]);
  320.       CurPosn := CurPosn + 1
  321.     end
  322. end;
  323.  
  324. function Reserved(var w : Str) : boolean;
  325. var
  326.   h : integer;
  327.   r : (DontKnow, IsReserved, NotReserved);
  328. begin
  329.   h := ReservedWordHash(w);
  330.   r := DontKnow;
  331.   repeat
  332.     if w = ReservedWordList[ReservedWordHashTable[h].WordPtr] then
  333.       r := IsReserved
  334.     else if ReservedWordHashTable[h].NextPtr = 0 then
  335.       r := NotReserved
  336.     else h := ReservedWordHashTable[h].NextPtr
  337.   until r <> DontKnow;
  338.   Reserved := (r = IsReserved)
  339. end;
  340.  
  341. procedure WriteReserved(var w : Str);
  342. begin
  343.   Printer_Underscore;  { turn on underscores }
  344.   write(Lst, w);
  345.   Printer_NoUnderscore { turn off underscores }
  346. end;
  347.  
  348. procedure WriteWord(var Word, CapWord : Str);
  349. begin
  350.   XrefVar.Name := CapWord;
  351.   XrefVar.Page := CurPage;
  352.   XrefVar.Line := CurLine;
  353.   SortRelease(XrefVar);
  354.   write(Lst, Word)
  355. end;
  356.  
  357. procedure DoWord;
  358. var
  359.   wstart  : integer;
  360.   Word    : Str;
  361.   CapWord : Str;
  362. begin
  363.   wstart := CurPosn;
  364.   repeat
  365.     CurPosn := CurPosn + 1
  366.   until (CurPosn > length(Line)) or not (Line[CurPosn] in ['A'..'Z','a'..'z','_','0'..'9']);
  367.   Word := Copy(Line, wstart, CurPosn - wstart);
  368.   CapWord := Word;
  369.   UpStr(CapWord);  { Upper case version of the word }
  370.   if Reserved(CapWord) then
  371.     WriteReserved(Word)
  372.   else
  373.     WriteWord(Word, CapWord)
  374. end;
  375.  
  376. procedure Inp;
  377. begin
  378.   GetInFile;
  379.   CurLine := 1000;  { force page break on first line }
  380.   CurPage := 0;
  381.   CommentStatus := NoComment;
  382.   while not EOF(InFile) do
  383.     begin
  384.       ReadLine;
  385.       while CurPosn <= length(Line) do
  386.         begin
  387.           CopyTillAlpha;
  388.           if CurPosn <= length(Line) then DoWord
  389.         end;
  390.       Writeln(Lst)
  391.     end
  392. end;
  393.  
  394. {======================================================================}
  395. {  Procedure called by TurboSort to order the cross reference entries  }
  396. {======================================================================}
  397.  
  398. function Less;
  399. var
  400.   FirstRec  : XrefRec absolute X;
  401.   SecondRec : XrefRec absolute Y;
  402. begin
  403.   if FirstRec.Name = SecondRec.Name then
  404.     begin
  405.       if FirstRec.Page = SecondRec.Page then
  406.         Less := FirstRec.Line < SecondRec.Line
  407.       else
  408.         Less := FirstRec.Page < SecondRec.Page
  409.     end
  410.   else
  411.     Less := FirstRec.Name < SecondRec.Name
  412. end;
  413.  
  414. {======================================================================}
  415. {  Procedures to print the sorted cross reference                      }
  416. {======================================================================}
  417.  
  418. procedure Xref_NewPage;
  419. begin
  420.   Printer_Eject;
  421.   Writeln(Lst, 'C R O S S   R E F E R E N C E':54);
  422.   Writeln(Lst, 'Entries are PAGE:LINE':50);
  423.   Writeln(Lst);
  424.   CurLine := 0
  425. end;
  426.  
  427. procedure Xref_NewLine;
  428. begin
  429.   Writeln(Lst);
  430.   if CurLine >= LinesPerPage then Xref_NewPage
  431.   else CurLine := CurLine + 1;
  432.   NumOnLine := 0
  433. end;
  434.  
  435. procedure Xref_Write_Number(n, count : integer);
  436. { write "n" to Lst with "count" digits (add leading zeros) }
  437. var
  438.   s : Str;
  439.   i : integer;
  440. begin
  441.   for i := count downto 1 do
  442.     begin
  443.       s[i] := Chr((n mod 10) + Ord('0'));
  444.       n := n div 10
  445.     end;
  446.   s[0] := Chr(count);  { set correct string length }
  447.   write(Lst, s)
  448. end;
  449.  
  450. procedure Xref_Write;
  451. begin
  452.   if NumOnLine >= 8 then Xref_NewLine;
  453.   if NumOnLine = 0 then Write(Lst, '   ');
  454.   Write(Lst, ' ');
  455.   Xref_Write_Number(XrefVar.Page, 5);
  456.   Write(Lst, ':');
  457.   Xref_Write_Number(XrefVar.Line, 2);
  458.   NumOnLine := NumOnLine + 1
  459. end;
  460.  
  461. procedure Xref_NewName;
  462. begin
  463.   if (CurLine + 2) >= LinesPerPage then Xref_NewPage;
  464.   Write(Lst, XrefVar.Name);
  465.   Xref_NewLine
  466. end;
  467.  
  468. procedure Outp;
  469. var
  470.   CurName : Str;
  471. begin
  472.   Printer_Reset;  { put printer back into 80 column mode }
  473.   Xref_NewPage;
  474.   SortReturn(XrefVar);
  475.   CurName := XrefVar.Name;
  476.   Xref_NewName;
  477.   Xref_Write;
  478.   while not SortEOS do
  479.     begin
  480.       SortReturn(XrefVar);
  481.       if CurName <> XrefVar.Name then
  482.         begin
  483.           Xref_NewLine;
  484.           CurName := XrefVar.Name;
  485.           Xref_NewName
  486.         end;
  487.       Xref_Write
  488.     end;
  489.   Writeln(Lst);
  490.   Printer_Eject
  491. end;
  492.  
  493. {======================================================================}
  494. {  Main Program                                                        }
  495. {======================================================================}
  496.  
  497. begin
  498.   Write('Pascal Source Listing and Cross Reference Program V1.0.0');
  499.   Writeln('  By Michael Quinlan');
  500.   Writeln;
  501.   SetUpReservedWordHashTable;
  502.   InFileName := GetParm;
  503.   while (length(InFileName)>0) and (InFileName[1] = ' ') do
  504.     delete(InFileName, 1, 1);
  505.   SortResult := TurboSort(SizeOf(XrefRec));
  506.   writeln;
  507.   case SortResult of
  508.      0 : Writeln('Program Completed OK');
  509.      3 : Writeln('Insufficient Memory for Sort');
  510.      8 : Writeln('Illegal Item Length for Sort (Program Logic Error)');
  511.      9 : Writeln('More Than ', MaxInt, ' Items to be Sorted');
  512.     10 : Writeln('Sort Error, Disk Error or Disk Full?');
  513.     11 : Writeln('Write Error During Sort, Bad Disk?');
  514.     12 : Writeln('File Creation Error During Sort')
  515.   else
  516.     Writeln('Unknown Error ', SortResult, ' From Sort')
  517.   end; { Case }
  518.   if SortResult <> 0 then
  519.     Writeln('*** Sort Failed; Cross Reference Invalid or Incomplete')
  520. end.
  521.