home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 19 / CD_ASCQ_19_010295.iso / dos / prg / pas / swag / findrepl.swg / 0010_NICECODE.PAS.pas < prev    next >
Pascal/Delphi Source File  |  1993-05-28  |  15KB  |  428 lines

  1. (*
  2. >Does anyone know of a utility Program that will apply some sort of
  3. >reasonable structuring to a pascal source File?
  4.  
  5. I'm not sure if it's what you want, but the source For a Pascal
  6. reFormatter, etc, was entered in the Fidonet PASCAL Programming
  7. Competition, and came third (I came second!!).
  8.  
  9. As you can see by the File dates, this is a very recent thing and
  10. since it is Nearly too late I toyed With the idea of just keeping it
  11. to myself.  It certainly is not an example of inspired Programming.
  12. But then, I thought, if everyone felt that way you'd have nothing to
  13. chose from and even if this is not a prize winner, mayby someone
  14. else will find it useful.
  15.  
  16. So here it is...  not extensively tested, but I couldn't find any
  17. bugs.  Used Pretty to reFormat itself and it still Compiled and
  18. worked.  Anyway, the only possible use is to another Turbo Pascal
  19. Programmer who shouldn't have any difficult modifying to suit
  20. himself.  They'd probably do that anyway since the output represents
  21. my own peculiar notion as to what a readable Format should be.
  22.  
  23. 'Pretty Printers' date back to the earliest Computer days and
  24. Variations existed For just about any language.  However, I've been
  25. unable to find a current one For Turbo Pascal.
  26.  
  27. Here's what this one does:
  28.  
  29. Pretty With no parameters generates a syntax message.
  30.  
  31. Input is scanned line-by-line, Word-by-Word and Byte-by-Byte.  Any
  32. identifiers recognized as part of TP's language are replaced by
  33. mixed Case (in a style which _I_ like).  Someone else can edit
  34. Constants Borland1 through Borland5 and TP3.  (Why TP3 later.)  The
  35. first one on a line is capitalized anyway.
  36.  
  37. A fallout of this is to use selected ones to determine indentation
  38. in increments of 'IndentSpcs' which I arbitrarily set to 3.  Change
  39. if you like. Indentation is incremented whenever one of the
  40. 'IndentIDs' appears and decremented With 'UnindentIDs' (surprise!).
  41.  
  42. Single indents are also provided For 'SectionIDs' (Const, Type,
  43. Uses, Var) and For 'NestIDs' (Procedure Function) to make these more
  44. visible.  White space is what does it, right?
  45.  
  46. On the other hand, no attempt is made to affect white space in the
  47. vertical direction.  Since that generally stays the way you
  48. originate it.
  49.  
  50. Any '{', '(' or '''' (Single quote) detected during the line scan
  51. trigger a 'skipit' mode which moves the enclosed stuff directly to
  52. output, unmodified. With one exception.  {Comments} which begin a
  53. line are aligned to the left margin (where I like to see Compiler
  54. directives and one line Procedure/Function explanations).  Other
  55. {Comments} which begin/end on the same line are shifted so the '}'
  56. aligns at the (80th column) right margin.  I think this makes them
  57. more visible than when snuggled up to a semi-colon and getting them
  58. away from the code makes it more legible, too.
  59.  
  60. and it did look better originally when it used some of my personal
  61. Units. Hastily modified to stand alone.  There are, no doubt, some
  62. obvious ways the Programming can be improved (you would probably
  63. have used some nice hash tables to look up key Words) but, as I say,
  64. I thought I would be the only one using this and speed in this Case
  65. is not all that important.
  66.  
  67. With one exception.  Something I worked up For an earlier
  68. application and may be worth looking at -- 'LowCase'.
  69.  
  70. It will Compile With TP4-TP5.5 and probably TP6 (if it still
  71. supports Inline). I included TP3 stuff because some of the old
  72. software I was looking at was written in it.  and it recognizes
  73. Units in a clumsy sort of way.
  74.  
  75. Switching to chat mode here.  if you're Really busy, you can skip the
  76. following.
  77.  
  78. This thing actually began as a 'Case-converter'.  I was trying to
  79. avoid re-inventing some wheels by re-working some old Pascal source
  80. dating back to the late 70's and 80's.  Upper Case Programs became a
  81. 'standard' back in the days when you talked to main frames through a
  82. teleType machine, which has no lower Case.  Sadly, this persisted
  83. long after it was no longer necessary and I find those
  84. all-upper-Case Programs almost unreadable.  That is I can't find
  85. what I'm looking For.  They were making me crazy.  (BTW I suspect
  86. some of this has to do With why Pascal has UpCase but no LoCase.)
  87.  
  88. I stole the orginal LowCase included here from someone who had done
  89. the intuitive thing -- first test For 'A', then For 'Z'.  Changing
  90. to an initial test For 'Z' does two things.  A whopping 164 of the
  91. 255 possible Characters can be eliminated With just one test and,
  92. since ordinary Text consists of mostly lower Case, these will be
  93. passed over rapidly.
  94.  
  95. When you received this you thought, "Who the heck is Art Weller?  I
  96. don't remember him on the Pascal Echo."  Right.  I'm a 'lurker'!
  97. Been reading the echo since beFore it had a moderator.  (Now we have
  98. an excellent one.  Thank you.) I have a machine on a timer which
  99. calls the BBS each morning to read and store several echos which I
  100. read later.  Rarely get inspired enough to call back and enter a
  101. discussion.  Things usually get resolved nicely without me.  I
  102. especially don't want to get involved in such as the 'Goto' wars.
  103. But I monitor the better discussions to enhance my TP skills.
  104.  
  105. I'm not Really a Programmer (no Formal training, that is --
  106. Computers hadn't been invented when I was in school!), but an
  107. engineer.  I'm retired from White Sands Missile Range where I was
  108. Chief of Plans and Programs For (mumble, mumble) years.  I
  109. self-taught myself Computers when folks from our Analysis and
  110. Computation Directorate started using jargon on me.  I did that well
  111. enough to later help Write a book For people who wanted to convert
  112. from BASIC to Pascal then after "retiring" was an editor For a small
  113. Computer magazine (68 Micro-Journal).
  114.  
  115. In summary, if you think this worth sharing With others I'll be
  116. pleased enough even without a prize.  not even sure it will get
  117. there in time.  Snail-Mail, you know.
  118. *)
  119.  
  120. Program Pretty;
  121. {A 'Pretty Printer' For Turbo Pascal Programs}
  122. {  This Program converts Turbo Pascal identifiers in a source code File to
  123.    mixed Case and indents the code.
  124.    Released into Public Domain June, 1992 on an 'AS IS' basis.  Enjoy at your
  125.    own risk.
  126.                                                     Art Weller
  127.                                                     3217 Pagosa Court
  128.                                                     El Paso, Texas  79904
  129.                                                     U. S. A.
  130.                                                     Ph. (915) 755-2516}
  131.  
  132. {Uses
  133.    Strings;}
  134.  
  135. Const
  136.    IndentSpcs = 3;
  137.  
  138.    Borland1 =
  139.    ' Absolute Addr and ArcTan Array Assign AuxInptr AuxOutptr BDos begin Bios '+
  140.    ' BlockRead BlockWrite Boolean Buflen Byte Case Chain Char Chr Close ClrEol '+
  141.    ' ClrScr Color Concat Const Copy Cos Delay Delete DelLine Dispose div do ';
  142.    Borland2 =
  143.    ' Downto Draw else end Eof Eoln Erase Execute Exp External False File '+
  144.    ' FilePos FileSize FillChar Flush For Forward Frac Freemem Function Getmem '+
  145.    ' Goto GotoXY Halt HeapPtr Hi HighVideo HiRes if Implementation in Inline ';
  146.    Borland3 =
  147.    ' Input Insert InsLine Int Integer Interface Intr IOResult KeyPressed '+
  148.    ' Label Length Ln Lo LowVideo Lst Mark MaxAvail Maxint Mem MemAvail Memw Mod '+
  149.    ' Move New Nil NormVideo not Odd of Ofs or Ord Output Overlay Packed ';
  150.    Borland4 =
  151.    ' Pallette Pi Plot Port Pos Pred Procedure Program Ptr Random Randomize Read '+
  152.    ' ReadLn Real Record Release Rename Repeat Reset ReWrite Round Seek Seg Set '+
  153.    ' Shl Shr Sin SizeOf Sound Sqr Sqrt Str String Succ Swap Text then to ';
  154.    Borland5 =
  155.    ' True Trunc Type Unit Until UpCase Uses UsrOutPtr Val Var While Window With '+
  156.    ' Write WriteLn xor ';
  157.    TP3 =
  158.    ' AUX CONinPTR CON CONOUTPTR ConstPTR CrtEXIT CrtinIT ERRorPTR Kbd '+
  159.    ' LStoUTPTR TRM USR USRinPTR ';
  160.  
  161.    IndentIDs   = ' begin Case Const Record Repeat Type Uses Var ';
  162.    UnIndentIDs = ' end Until ';
  163.    SectionIDs  = ' Const Type Uses Var ';
  164.    endSection  = ' begin Const Uses Var Function Implementation Interface '+
  165.                  ' Procedure Type Unit ';
  166.    NestIDs     = ' Function Procedure Unit ';
  167.  
  168.    IDAlphas    = ['a'..'z', '1'..'0', '_'];
  169.  
  170. Var
  171.    Indent,
  172.    endPend,
  173.    Pending,
  174.    UnitFlag       : Boolean;
  175.    NestLevel,
  176.    NestIndent,
  177.    IndentNext,
  178.    IndentNow,
  179.    Pntr, LineNum  : Integer;
  180.    IDs,
  181.    InFile,
  182.    OutFile,
  183.    ProgWrd,
  184.    ProgLine       : String;
  185.    Idents,
  186.    OutID          : Array [1..5] of String;
  187.    f1, f2         : Text;
  188.  
  189. Function  LowCase(Ch: Char): Char;
  190. begin
  191.   Inline(
  192.    $8A/$86/>Ch/                          {      mov al,>Ch[bp]   ;Char to check}
  193.    $3C/$5A/                              {      cmp al,'Z'                     }
  194.    $7F/$06/                              {      jg  Done                       }
  195.    $3C/$41/                              {      cmp al,'A'                     }
  196.    $7C/$02/                              {      jl  Done                       }
  197.    $0C/$20/                              {      or al,$20                      }
  198.    $88/$86/>LowCase);                    {Done :mov >LowCase[bp],al            }
  199. end;
  200.  
  201. Function LowCaseStr(InStr : String): String;
  202. Var
  203.   i  : Integer;
  204.   len: Byte Absolute InStr;
  205. begin
  206.   LowCaseStr[0] := Chr(len);
  207.   For i := 1 to len do
  208.   LowCaseStr[i] := LowCase(InStr[i]);
  209. end;
  210.  
  211. Function  Blanks(Count: Byte): String; {return String of 'Count' spaces}
  212. Var
  213.   Result: String;
  214. begin
  215.   FillChar(Result[1], Count+1, ' ');
  216.   Result[0] := Chr(Count);
  217.   Blanks := Result;
  218. end;
  219.  
  220. Procedure StripLeading(Var Str: String);  {remove all leading spaces}
  221. begin
  222.   While (Str[1] = #32) and (length(Str) > 0) do
  223.     Delete(Str,1,1);
  224. end;
  225.  
  226. Procedure Initialize;
  227. begin
  228.   IDs := IndentIDs + UnIndentIDs + endSection;
  229.   OutID[1] := Borland1;
  230.   Idents[1] := LowCaseStr(OutID[1]);
  231.   OutID[2] := Borland2;
  232.   Idents[2] := LowCaseStr(OutID[2]);
  233.   OutID[3] := Borland3;
  234.   Idents[3] := LowCaseStr(OutID[3]);
  235.   OutID[4] := Borland4;
  236.   Idents[4] := LowCaseStr(OutID[4]);
  237.   OutID[5] := Borland5 + TP3;
  238.   Idents[5] := LowCaseStr(OutID[5]);
  239.   Pending := False;
  240.   UnitFlag := False;
  241.   IndentNext := 0;
  242.   IndentNow := 0;
  243.   LineNum := 0;
  244.   NestIndent := 0;
  245.   NestLevel := 0;
  246. end;
  247.  
  248. Procedure Greeting;
  249. begin
  250.   Writeln;
  251.   Writeln('Pascal Program Indenter');
  252.   Writeln; Writeln;
  253.   Writeln('SYNTAX:  INDENT InputFile OutPutFile');
  254.   Writeln('         INDENT InputFile > OutPut');
  255.   Writeln; Writeln;
  256.   Halt(0);
  257. end;
  258.  
  259. Procedure OpenFiles;
  260. begin
  261.   if paramcount <> 0 then
  262.   begin
  263.     InFile := ParamStr(1);
  264.     if (pos('.', InFile) = 0) then
  265.       InFile := InFile + '.pas';
  266.     OutFile := Paramstr(2);
  267.   end
  268.   else
  269.     Greeting;
  270.   Assign(f1, InFile);
  271.   Reset(f1);
  272.   Assign(f2, OutFile);
  273.   ReWrite(f2);
  274. end;
  275.  
  276. Procedure GetWord;
  277. Var
  278.   i,
  279.   index,
  280.   TmpPtr,
  281.   WrdPos   : Integer;
  282.  
  283.   Procedure DecIndent;
  284.   begin
  285.     if (IndentNext > IndentNow) then   {begin/end on same line}
  286.       Dec(IndentNext)
  287.     else
  288.     if IndentNow > 0 then
  289.       dec(IndentNow);
  290.     IndentNext := IndentNow;    {next line, too}
  291.   end;
  292.  
  293. begin
  294.   ProgWrd := ' ';
  295.   TmpPtr := Pntr;
  296.  
  297.   While (LowCase(ProgLine[Pntr]) in IDAlphas) {Convert checked For LCase alpha}
  298.         and (Pntr <= length(ProgLine)) do
  299.   begin
  300.     ProgWrd := ProgWrd + LowCase(ProgLine[Pntr]);
  301.     Inc(Pntr);
  302.   end;
  303.  
  304.   ProgWrd := ProgWrd+' ';   {surrounded With blanks to make it unique!}
  305.   index := 0;
  306.  
  307.   Repeat;     {is it a Turbo Pascal Word?}
  308.     inc(index);
  309.     WrdPos := Pos(ProgWrd, Idents[index]);
  310.   Until (WrdPos <> 0) or (index = 5);
  311.  
  312.   if WrdPos <> 0 then   {found a Pascal Word}
  313.   begin
  314.     Move(OutID[index][WrdPos+1], ProgLine[TmpPtr], Length(ProgWrd)-2);
  315.     if TmpPtr = 1 then
  316.       ProgLine[1] := UpCase(ProgLine[1]);
  317.  
  318.     if Pos(ProgWrd, IDs) <> 0 then  {only checked if a Pascal Word ^}
  319.     begin
  320.       if Pos(ProgWrd, endSection) <> 0 then  {this includes "SectionIDs"}
  321.       begin                                      {and "NestIDs"}
  322.         if (pos(ProgWrd, NestIDs) <> 0) then
  323.         begin
  324.           if ProgWrd = ' Unit ' then
  325.             UnitFlag := True;
  326.           if not UnitFlag then
  327.             inc(NestLevel);
  328.         end;
  329.         if Pending then
  330.           DecIndent;
  331.         Pending := Pos(ProgWrd, SectionIDs) <> 0;
  332.         if ProgWrd = ' Implementation ' then
  333.           UnitFlag := False;
  334.       end;
  335.       if Pos(ProgWrd, IndentIDs) <> 0 then
  336.         inc(IndentNext); {Indent 1 level}
  337.       if Pos(ProgWrd, UnIndentIDs) <> 0 then
  338.       begin
  339.          DecIndent;   {Unindent 1 level}
  340.          if (IndentNow = 0) and (NestLevel > 0) then
  341.            dec(NestLevel);
  342.       end;
  343.       if NestLevel > 1 then
  344.         NestIndent := 1;
  345.     end;
  346.   end;
  347. end;
  348.  
  349. Procedure Convert;
  350.  
  351.   Procedure OutLine;
  352.   Var
  353.     Tabs : String[40];
  354.   begin
  355.     Tabs := Blanks((IndentNow+NestIndent) * IndentSpcs);
  356.     if ProgLine[1] = '{' then
  357.       Writeln(f2, ProgLine)
  358.     else
  359.       Writeln(f2, Tabs, ProgLine);
  360.     IndentNow := IndentNext;   { get ready For next line }
  361.     if NestLevel < 2 then
  362.       NestIndent := 0;
  363.   end;
  364.  
  365.   Procedure Skipto(SearchChar: Char);
  366.   begin
  367.     Repeat
  368.       if pntr > Length(ProgLine) then
  369.       begin
  370.         OutLine;
  371.         Readln(f1, ProgLine);   {get another line}
  372.         Pntr := 0;
  373.       end;
  374.       Inc(pntr);
  375.     Until (ProgLine[pntr] = SearchChar) or Eof(f1);
  376.   end;
  377.  
  378.   Procedure MoveComments;
  379.   Var
  380.     TmpIndent : Integer;
  381.   begin
  382.     if (ProgLine[1] = '{') or (ProgLine[Pntr+1] = '$') then
  383.     begin
  384.       Skipto('}');
  385.       Exit;
  386.     end;
  387.     TmpIndent := (IndentNow+NestIndent) * IndentSpcs;
  388.     While Length(ProgLine) < 80-TmpIndent do
  389.       Insert(' ', ProgLine, Pntr);
  390.     While (pos('}', ProgLine) > 80-TmpIndent) and (pos(' {', ProgLine) > 1) do
  391.     begin
  392.       Delete(ProgLine, Pos(' {', ProgLine), 1);
  393.       Dec(Pntr);
  394.     end;
  395.     Skipto('}');
  396.   end;
  397.  
  398. begin
  399.   While not Eof(f1) do
  400.   begin
  401.     Readln(f1, ProgLine);
  402.     StripLeading(ProgLine);
  403.     if Length(ProgLine) = 0 then
  404.       Writeln(f2)
  405.     else
  406.     begin
  407.       Pntr := 1;
  408.       Repeat
  409.         Case LowCase(ProgLine[pntr]) of
  410.           'a'..'z','_'  :  GetWord;
  411.           '{'           :  MoveComments;
  412.           '('           :  Skipto(')');
  413.           #39           :  Skipto(#39)        {Single quote}
  414.         end;
  415.         Inc(pntr)
  416.       Until (pntr >= length(ProgLine));
  417.       OutLine;
  418.     end;
  419.   end;  { While }
  420.   Close(f1); Close(f2);
  421. end;
  422.  
  423. begin
  424.   Initialize;
  425.   OpenFiles;
  426.   Convert;
  427. end.
  428.