home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / TURBOPAS / TXREF1A.ZIP / TXREF1A.PAS
Encoding:
Pascal/Delphi Source File  |  1986-11-07  |  14.1 KB  |  497 lines

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