home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / 1988 / 04 / decl.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-01-18  |  12.8 KB  |  377 lines

  1. (* ----------------------------------------------------- *)
  2. (*                        DECL.PAS                       *)
  3. (* Auflisten der Prozedur- und Funktionsdeklarationen    *)
  4. (* von Pascal-Programmen unter Berücksichtigung der In-  *)
  5. (* einanderschachtelung dieser Strukturen.               *)
  6. (*      (C) 1988  Markus Satte, MC & PASCAL INT.         *)
  7. (* ----------------------------------------------------- *)
  8. {$P1024}                 (* für Turbo Pascal, ermöglicht *)
  9.                          (* die Ausgabe-Umleitung        *)
  10.  
  11. PROGRAM Decl (Source, Output);
  12.  
  13. CONST LineWidth = 70;
  14.  
  15. TYPE  MyString    = STRING[255];
  16.       CharSet     = SET OF CHAR;
  17.  
  18. VAR   Source                       : TEXT;
  19.       allChars, Delimiters,
  20.       Numbers, Letters             : CharSet;
  21.       FileName,
  22.       word, Line, OutLine, Blanks  : MyString;
  23.       LinePos, LineCount, inProc,
  24.       FuncCount, ProcCount,
  25.       BeginEnd, RecordEnd, TabPos  : INTEGER;
  26.       DeclEnd, ready               : BOOLEAN;
  27. (* ----------------------------------------------------- *)
  28. (* Umwandeln eines Strings in Großbuchstaben unter Ver-  *)
  29. (* wendung der Turbo-Standard-Funktion upcase(), die nur *)
  30. (* für einzelne Zeichen definiert ist. Für nicht Turbo-  *)
  31. (* isten und dem ASCII-Zeichensatz:                      *)
  32. (* FUNCTION UpCase (ch: CHAR): CHAR;                     *)
  33. (* BEGIN                                                 *)
  34. (*   UpCase := ch;                                       *)
  35. (*   IF ch IN ['a'..'z'] THEN UpCase := Chr(Ord(ch)-32); *)
  36. (* END;                                                  *)
  37. PROCEDURE UpString (VAR source, dest : MyString);
  38.  
  39. VAR i : INTEGER;
  40.  
  41. BEGIN
  42.   dest := source;
  43.   FOR i := 1 TO Length(dest) DO dest[i] := UpCase(dest[i]);
  44. END;
  45. (* ----------------------------------------------------- *)
  46. (* ermittelt Position des ersten Nicht-Leerzeichens in   *)
  47. (* einer Zeichenkette ab der Start-Position. Wird keines *)
  48. (* mehr gefunden, wird eine größere Pos. als die Länge   *)
  49. (* der Zeichenkette zurückgegeben.                       *)
  50. FUNCTION PosNonBlank (VAR Line: MyString;
  51.                            Pos: INTEGER): INTEGER;
  52. BEGIN
  53.   WHILE (Line[Pos] = ' ') AND (Pos < Length(Line)) DO
  54.     Pos := Succ(Pos);
  55.   IF Line[Pos] = ' ' THEN Pos := Succ(Pos);
  56.   PosNonBlank := Pos;
  57. END;
  58. (* ----------------------------------------------------- *)
  59. (*  Wandelt eine Integer-Zahl in eine Zeichenkette um:   *)
  60. PROCEDURE NumToStr (number: INTEGER; VAR txt: MyString);
  61.  
  62. VAR  ch : CHAR;
  63.  
  64. BEGIN
  65.   txt := '';
  66.   REPEAT
  67.     ch := Chr(number MOD 10 + Ord('0'));
  68.     txt := Concat(ch,txt);
  69.     number := number DIV 10;
  70.   UNTIL number = 0;
  71. END;
  72. (* ----------------------------------------------------- *)
  73. (* sucht in der Zeile den Anfang eines Wortes ab der an- *)
  74. (* gegebenen Position. "BeginChar" ist die Menge der     *)
  75. (* Zeichen, mit denen ein Wort anfangen darf:            *)
  76. FUNCTION BeginOfWord (VAR Line: MyString;
  77.                            Pos: INTEGER;
  78.                      BeginChar: CharSet): INTEGER;
  79. BEGIN
  80.   WHILE (Pos <= Length(Line))
  81.   AND (NOT(Line[Pos] IN BeginChar)) DO Pos := Succ(Pos);
  82.   BeginOfWord := Pos;
  83. END;
  84. (* ----------------------------------------------------- *)
  85. (* sucht in der Zeile das Ende eines Wortes ab der ange- *)
  86. (* gebenen Position. "EndChar" ist die Menge der Zei-    *)
  87. (* chen, die ein Wort abschließen dürfen. Bei Compilern, *)
  88. (* die beide UNTIL-Bedingungen testen, muß hier die Be-  *)
  89. (* reichsprüfung kurz ausgeschaltet werden !             *)
  90. FUNCTION EndOfWord (VAR Line: MyString;
  91.                          Pos: INTEGER;
  92.                      EndChar: CharSet): INTEGER;
  93. BEGIN
  94.   REPEAT
  95.     Pos := Succ(Pos);
  96.   UNTIL (Pos > Length(Line)) OR (Line[Pos] IN EndChar);
  97.   EndOfWord := Pos;
  98. END;
  99. (* ----------------------------------------------------- *)
  100. (* eine nicht leere Zeile aus der Quelldatei lesen und   *)
  101. (* Zeilenzähler erhöhen:                                 *)
  102. PROCEDURE NextLine;
  103.  
  104. BEGIN
  105.   REPEAT
  106.     ReadLn(Source,Line);  LineCount := Succ(LineCount);
  107.   UNTIL Eof(Source) OR (Line <> '');
  108. END;
  109. (* ----------------------------------------------------- *)
  110. (*  überließt Zeichenketten-Konstanten und Kommentare.   *)
  111. (* Ist "Line[LinePos]" ein Leerzeichen, wird der Anfang  *)
  112. (* des nächsten Textes gesucht. Beginnt ein Kommentar    *)
  113. (* oder String, wird dieser überlesen und "Line[LinePos]"*)
  114. (* auf des den Kommentar folgende nicht-Leerzeichen ge-  *)
  115. (* stellt:                                               *)
  116. PROCEDURE StringComment;
  117.  
  118.   PROCEDURE FindEnd (EndChar: CHAR);          (* klar ?! *)
  119.   BEGIN
  120.     REPEAT
  121.       LinePos := Succ(LinePos);
  122.       IF LinePos <= Length(Line) THEN BEGIN
  123.         IF Line[LinePos] = EndChar THEN BEGIN
  124.           IF EndChar = '*' THEN BEGIN
  125.             IF (LinePos < Length(Line))
  126.             AND (Line[Succ(LinePos)] = ')') THEN BEGIN
  127.               EndChar := ' ';  LinePos := Succ(LinePos);
  128.             END;
  129.           END
  130.           ELSE
  131.             EndChar := ' ';
  132.         END;
  133.       END
  134.       ELSE IF Eof(Source) THEN  EndChar := ' '
  135.       ELSE BEGIN
  136.         NextLine;  LinePos := 0;
  137.       END;
  138.     UNTIL EndChar = ' ';
  139.     LinePos := PosNonBlank(Line,Succ(LinePos));
  140.     StringComment;  (* falls gleich wieder einer folgt ! *)
  141.   END;
  142.  
  143. BEGIN
  144.   LinePos := PosNonBlank(Line,LinePos);
  145.   WHILE (LinePos > Length(Line)) AND NOT Eof(Source) DO
  146.   BEGIN
  147.     NextLine;  LinePos := PosNonBlank(Line,1);
  148.   END;
  149.   IF LinePos <= Length(Line) THEN
  150.     CASE Line[LinePos] OF
  151.       '''' : FindEnd('''');
  152.        '{' : FindEnd('}');
  153.        '(' : IF LinePos < Length(Line) THEN
  154.                IF Line[Succ(LinePos)] = '*' THEN BEGIN
  155.                  LinePos := Succ(LinePos);  FindEnd('*');
  156.                END;
  157.     END;
  158. END;
  159. (* ----------------------------------------------------- *)
  160. (*                Das nächste Wort liefern.              *)
  161. (* "BegChars" ist die Menge der Zeichen, mit denen das   *)
  162. (* Wort anfangen darf, "EndChars" enthält die Menge, die *)
  163. (* nicht zu einem Wort gehören:                          *)
  164. PROCEDURE GetNextWord (VAR word: MyString;
  165.                            BegChars, EndChars: CharSet);
  166.  
  167. VAR  Pos : INTEGER;
  168.  
  169. BEGIN
  170.   word := '';
  171.   WHILE (word = '') AND NOT Eof(Source) DO BEGIN
  172.     StringComment;
  173.     IF LinePos <= Length(Line) THEN
  174.       IF Line[LinePos] IN BegChars THEN BEGIN
  175.         Pos := BeginOfWord(Line,LinePos,BegChars);
  176.         LinePos := EndOfWord(Line,Pos,EndChars);
  177.         word := Copy(Line,Pos,LinePos-Pos);
  178.       END
  179.       ELSE LinePos := Succ(LinePos);
  180.   END;
  181. END;
  182. (* ----------------------------------------------------- *)
  183. (*                     Text-Ausgabe.                     *)
  184. (* Die Ausgabe wird solange zwischengespeichert, bis     *)
  185. (* durch eine neue Ausgabe "LineWidth" überschritten     *)
  186. (* wird oder eine leere Zeichenkette übergeben wird.     *)
  187. (* Nach der Ausgabe wird die nächste Ausgabe ab der      *)
  188. (* Position "TabPos" getätigt. Bei der Überschreitung    *)
  189. (* von "LineWidth" wird der auszugebende Text in die     *)
  190. (* nächste Zeile übernommen:                             *)
  191. PROCEDURE Out (txt: MyString);
  192.  
  193. BEGIN
  194.   IF txt = '' THEN BEGIN
  195.     WriteLn(OutLine);  OutLine := '';  TabPos := 0;
  196.   END
  197.   ELSE IF Length(txt) + Length(OutLine) > LineWidth THEN
  198.   BEGIN
  199.     WriteLn(OutLine);  OutLine := Copy(Blanks,1,TabPos);
  200.   END;
  201.   OutLine := Concat(OutLine,txt);
  202. END;
  203. (* ----------------------------------------------------- *)
  204. (* Zeilennummer der Prozedur/Funktion ausgeben und ent-  *)
  205. (* sprechend der Schachtelung eine Einrückung erzeugen:  *)
  206. PROCEDURE LineNum (num: INTEGER);
  207.  
  208. VAR  i : INTEGER;  temp: MyString;
  209.  
  210. BEGIN
  211.   Out('');
  212.   IF num > 0 THEN BEGIN
  213.     NumToStr(num,temp);
  214.     WHILE Length(temp) < 5 DO temp := Concat('0',temp);
  215.     Out(Concat(temp,': '));
  216.   END
  217.   ELSE Out('       ');
  218.   IF inProc > 1 THEN BEGIN
  219.     FOR i := 2 TO inProc DO Out('.');
  220.     Out(' ');
  221.   END;
  222. END;
  223. (* ----------------------------------------------------- *)
  224. (*         Prozedur/Funktions-Deklaration ausgeben:      *)
  225. PROCEDURE FuncProcOut;
  226.  
  227. VAR temp : MyString;
  228.  
  229.   (* --------------------------------------------------- *)
  230.   (* Parameterliste der Deklaration ausgeben. Dabei wer- *)
  231.   (* den zu lange Zeilen umgebrochen und neu formatiert: *)
  232.   PROCEDURE ParamsOut;
  233.  
  234.   VAR  tempword : MyString;
  235.  
  236.   BEGIN
  237.     Out(temp);  TabPos := Length(OutLine)+2;  temp := ' (';
  238.     REPEAT
  239.       GetNextWord(word,Letters,Delimiters);
  240.       UpString(word,tempword);
  241.       IF tempword = 'VAR' THEN
  242.         temp := Concat(temp,tempword,' ')
  243.       ELSE BEGIN
  244.         temp := Concat(temp,word);
  245.         GetNextWord(word,[',',';',':','(',')'],allChars);
  246.         temp := Concat(temp,word);
  247.         IF word <> ')' THEN temp := Concat(temp,' ');
  248.         IF word = ';' THEN BEGIN
  249.           Out(temp);  temp := ''
  250.         END;
  251.       END;
  252.     UNTIL word = ')';
  253.     GetNextWord(word,[':',';'],allChars);
  254.   END;
  255.  
  256. BEGIN
  257.   LineNum(LineCount);  TabPos := 0;
  258.     (* Deklarations-Anfang "PROC/FUNC Name ..." aufbauen *)
  259.   temp := Concat(word,' ');
  260.   GetNextWord(word,Letters,Delimiters);          (* Name *)
  261.   temp := Concat(temp,word);
  262.   GetNextWord(word,['(',':',';'],allChars);
  263.   IF word = '(' THEN ParamsOut;      (* Parameterliste ? *)
  264.   IF word = ':' THEN BEGIN             (* Funktionstyp ? *)
  265.     GetNextWord(word,Letters,Delimiters);
  266.     temp := Concat(temp,': ',word);
  267.     GetNextWord(word,[';'],allChars);
  268.   END;
  269.   IF word = ';' THEN temp := Concat(temp,';');
  270.   Out(temp);
  271. END;
  272. (* ----------------------------------------------------- *)
  273. (*       Test, ob angegebene Datei vorhanden ist:        *)
  274. FUNCTION FileExist (name : MyString) : BOOLEAN;
  275.  
  276. VAR f : TEXT;
  277.  
  278. BEGIN
  279.   Assign(f,name);
  280.   {$I-}   (* I/O-Überwachung durch Laufzeitsystem aus... *)
  281.   ReSet(f);
  282.   {$I+}                           (* ... und wieder an ! *)
  283.   FileExist := IOResult = 0;
  284.   Close(f);
  285. END;
  286. (* ----------------------------------------------------- *)
  287. (*         prüfen, ob Parameterzeile ok ist:             *)
  288. FUNCTION ParamOk: BOOLEAN;
  289.  
  290. BEGIN
  291.   ParamOk := FALSE;
  292.   IF ParamCount = 0 THEN
  293.     WriteLn('*** Fehler: ungültige Parameter angegeben !')
  294.   ELSE BEGIN
  295.     FileName := ParamStr(1);
  296.     IF Pos('.',FileName) = 0 THEN
  297.       FileName := Concat(FileName,'.PAS');
  298.     UpString(FileName,FileName);
  299.     IF NOT FileExist(FileName) THEN
  300.       WriteLn('*** Fehler: Datei "',FileName,
  301.               '" nicht gefunden !')
  302.     ELSE
  303.       ParamOk := TRUE;
  304.   END;
  305. END;
  306. (* ----------------------------------------------------- *)
  307. BEGIN (* Decl *)
  308.   WriteLn;
  309.   WriteLn('DECL v1.0     ',
  310.           '(C) 1988   Markus Satte, M.Ceol & PASCAL INT.');
  311.   WriteLn;
  312.   WriteLn('Auflisten der Prozedur- und Funktionsdeklara',
  313.           'tionen in Pascal-Programmen');
  314.   IF ParamOk THEN BEGIN
  315.     WriteLn('Datei: ',FileName);  WriteLn;
  316.     allchars := [' '..'}'];
  317.     Numbers  := ['0'..'9'];
  318.     Letters  := ['A'..'Z','a'..'z'];
  319.     Delimiters := allchars - Numbers - Letters - ['_'];
  320.     Line := '';  OutLine := '';  Blanks := '';
  321.     FOR LinePos := 1 TO 100 DO Blanks := Concat(Blanks,' ');
  322.     LineCount := 0;      inProc    := 0;
  323.     BeginEnd  := 0;      RecordEnd := 0;
  324.     FuncCount := 0;      ProcCount := 0;
  325.     LinePos   := 1;      ready := FALSE;
  326.     Assign(Source,FileName);
  327.     ReSet(Source);
  328.     WHILE NOT Eof(Source) AND NOT ready DO BEGIN
  329.       GetNextWord(word,Letters,Delimiters);
  330.       UpString(word,word);
  331.       IF word = 'BEGIN' THEN BEGIN
  332.         IF inProc = 0 THEN BEGIN
  333.           ready := TRUE; LineNum(LineCount); Out('MAIN');
  334.         END
  335.         ELSE BeginEnd := Succ(BeginEnd);
  336.       END
  337.       ELSE IF word = 'CASE' THEN BEGIN
  338.         IF RecordEnd = 0 THEN BeginEnd := Succ(BeginEnd);
  339.       END
  340.       ELSE IF word = 'RECORD' THEN
  341.         RecordEnd := Succ(RecordEnd)
  342.       ELSE IF (word = 'EXTERNAL') OR (word = 'FORWARD')
  343.       THEN BEGIN
  344.         LineNum(0);  Out(word);  inProc := Pred(inProc);
  345.       END
  346.       ELSE IF word = 'END' THEN
  347.         IF RecordEnd > 0 THEN
  348.           RecordEnd := Pred(RecordEnd)
  349.         ELSE BEGIN
  350.           BeginEnd := Pred(BeginEnd);
  351.           IF (inProc > 0) AND (BeginEnd = 0) THEN
  352.             inProc := Pred(inProc)
  353.         END
  354.       ELSE IF (word = 'PROCEDURE') OR (word = 'FUNCTION')
  355.       THEN BEGIN
  356.         inProc := Succ(inProc);
  357.         IF word = 'PROCEDURE' THEN
  358.           ProcCount := Succ(ProcCount)
  359.         ELSE
  360.           FuncCount := Succ(FuncCount);
  361.         FuncProcOut;
  362.       END;
  363.     END; (* WHILE *)
  364.     Out('');
  365.     Close(Source);
  366.     WriteLn;
  367.     WriteLn('Gefunden wurden insgesamt: ',
  368.              FuncCount+ProcCount:3,' Unterprogramme,');
  369.     WriteLn('                    davon: ',
  370.              FuncCount:3,' Funktionen');
  371.     WriteLn('                      und: ',
  372.              ProcCount:3,' Prozeduren.');
  373.     WriteLn;
  374.   END;
  375.   WriteLn;
  376. END.
  377.