home *** CD-ROM | disk | FTP | other *** search
/ Media Share 13 / mediashare_13.zip / mediashare_13 / ZIPPED / PROGRAM / APR94_1.ZIP / ALLEY.ASC next >
Text File  |  1994-02-27  |  14KB  |  532 lines

  1. _ALGORITHM ALLEY_
  2. by Tom Swan
  3.  
  4.  
  5. Listing One
  6.  
  7. (* ----------------------------------------------------------- *(
  8. ** search.pas -- Search engine for IDENT program               **
  9. ** Trie search algorithm                                       **
  10. ** Copyright (c) 1994 by Tom Swan. All rights reserved.        **
  11. )* ----------------------------------------------------------- *)
  12.  
  13. unit Search;
  14. INTERFACE
  15. uses Common;
  16.  
  17. { Return true if Ident is a Turbo Pascal reserved word }
  18. function IsReserved(Ident: IdentStr): Boolean;
  19. IMPLEMENTATION
  20. type
  21.   ResWord = String[14];
  22.   PResWordRec = ^ResWordRec;
  23.   ResWordRec = record
  24.     Word: ResWord;      { Reserved word string }
  25.     Next: PResWordRec;  { List link field }
  26.   end;
  27. var
  28.   Index: array['a' .. 'z'] of PResWordRec;
  29. { Add word W to list at P }
  30. procedure AddList(var P: PResWordRec; var W: ResWord);
  31. begin
  32.   if (P <> nil) then
  33.     AddList(P^.Next, W)
  34.   else begin
  35.     P := new(PResWordRec);
  36.     if (P = nil) then
  37.     begin
  38.       Writeln('Out of memory');
  39.       Halt;
  40.     end;
  41.     P^.Word := W;
  42.     P^.Next := nil
  43.   end
  44. end;
  45. { Add word W to global Index }
  46. procedure AddWord(W: ResWord);
  47. begin
  48.   if Length(W) = 0 then exit;
  49.   AddList(Index[W[1]], W)
  50. end;
  51. { Initialize search engine variables }
  52. procedure Initialize;
  53. var
  54.   C: Char;  { Index[] array index }
  55. begin
  56.   for C := 'a' to 'z' do
  57.     Index[C] := nil;
  58.   AddWord('and');
  59.   AddWord('array');
  60.   AddWord('asm');
  61.   AddWord('begin');
  62.   AddWord('case');
  63.   AddWord('const');
  64.   AddWord('constructor');
  65.   AddWord('destructor');
  66.   AddWord('div');
  67.   AddWord('do');
  68.   AddWord('downto');
  69.   AddWord('else');
  70.   AddWord('end');
  71.   AddWord('export');
  72.   AddWord('exports');
  73.   AddWord('far');
  74.   AddWord('file');
  75.   AddWord('for');
  76.   AddWord('function');
  77.   AddWord('goto');
  78.   AddWord('if');
  79.   AddWord('implementation');
  80.   AddWord('in');
  81.   AddWord('inherited');
  82.   AddWord('inline');
  83.   AddWord('interface');
  84.   AddWord('label');
  85.   AddWord('library');
  86.   AddWord('mod');
  87.   AddWord('near');
  88.   AddWord('nil');
  89.   AddWord('not');
  90.   AddWord('object');
  91.   AddWord('of');
  92.   AddWord('or');
  93.   AddWord('packed');
  94.   AddWord('private');
  95.   AddWord('procedure');
  96.   AddWord('program');
  97.   AddWord('public');
  98.   AddWord('record');
  99.   AddWord('repeat');
  100.   AddWord('set');
  101.   AddWord('shl');
  102.   AddWord('shr');
  103.   AddWord('string');
  104.   AddWord('then');
  105.   AddWord('to');
  106.   AddWord('type');
  107.   AddWord('unit');
  108.   AddWord('until');
  109.   AddWord('uses');
  110.   AddWord('var');
  111.   AddWord('virtual');
  112.   AddWord('while');
  113.   AddWord('with');
  114.   AddWord('xor');
  115. end;
  116. { Trie search algorithm }
  117. function IsReserved(Ident: IdentStr): Boolean;
  118. var
  119.   P: PResWordRec;
  120. begin
  121.   IsReserved := false;
  122.   if Length(Ident) = 0 then exit;
  123.   DownCase(Ident);
  124.   P := Index[Ident[1]];
  125.   while(P <> nil) do
  126.   begin
  127.     if P^.Word = Ident then
  128.     begin
  129.       IsReserved := true;
  130.       exit
  131.     end;
  132.     P := P^.Next
  133.   end
  134. end;
  135. begin
  136.   Initialize;
  137. end.
  138.  
  139.  
  140.  
  141. Listing Two
  142.  
  143. (* ----------------------------------------------------------- *(
  144. ** common.pas -- Various constants, types, and subroutines     **
  145. ** Copyright (c) 1994 by Tom Swan. All rights reserved.        **
  146. )* ----------------------------------------------------------- *)
  147. unit Common;
  148. INTERFACE
  149. const
  150.   identStrLen = 64;
  151.   digitSet = ['0' .. '9'];
  152.   upperSet = ['A' .. 'Z'];
  153.   lowerSet = ['a' .. 'z'];
  154.   alphaSet = upperSet + lowerSet;
  155.   identSet = alphaSet + digitSet + ['_'];
  156. type
  157.   IdentStr = String[identStrLen];
  158. { Return lowercase equivalent of Ch }
  159. function DnCase(Ch: Char): Char;
  160. { Convert all letters in identifier to lowercase }
  161. procedure DownCase(var Ident: IdentStr);
  162. IMPLEMENTATION
  163. { Return lowercase equivalent of Ch }
  164. function DnCase(Ch: Char): Char;
  165. begin
  166.   if Ch in upperSet
  167.     then Ch := Chr(Ord(Ch) + 32);
  168.   DnCase := Ch
  169. end;
  170. { Convert all letters in identifier to lowercase }
  171. procedure DownCase(var Ident: IdentStr);
  172. var
  173.   I: Integer;
  174. begin
  175.   if Length(Ident) > 0 then
  176.     for I := 1 to Length(Ident) do
  177.       Ident[I] := DnCase(Ident[I])
  178. end;
  179. begin
  180. end.
  181.  
  182.  
  183. Listing Three
  184.  
  185. (* ------------------------------------------------------------*(
  186. ** ident.pas -- Convert key word identifiers in .PAS files.    **
  187. ** Converts key words in Pascal listings to lowercase, and     **
  188. ** marks them for bold facing. Words are marked using the      **
  189. ** symbols <* and *>. For example, <*begin*> is interpreted as **
  190. ** a bold faced "begin" key word. A word-processor macro could **
  191. ** search for all <* and *> symbols in the resulting file and  **
  192. ** replace these with bold face on and off commands.           **
  193. ** Copyright (c) 1994 by Tom Swan. All rights reserved.        **
  194. )* ------------------------------------------------------------*)
  195.  
  196. {$X+}  { Enable "extended" syntax }
  197. program Ident;
  198. uses Dos, Common, Search;
  199. const
  200.   bakExt  = '.BAK';   { Backup file extension }
  201.   tempExt = '.$$$';   { Temporary file extension }
  202. type
  203.   PString = ^String;
  204.   PListRec = ^TListRec;
  205.   TListRec = record
  206.     Path: PString;
  207.     Next: PListRec
  208.   end;
  209.   TState = (
  210.     Reading, Chkcomment, Comment1, Comment2, Stopcomment,
  211.     Stringing, Converting
  212.   );
  213. var
  214.   FileSpec: ComStr;         { Files entered on command line }
  215.   Root: PListRec;           { File name list root pointer }
  216.   DelimitWords: Boolean;    { True to add <* and *> to reserved words }
  217.   CapIdentifiers: Boolean;  { True to capitalize non-keywords }
  218. { Return copy of a string }
  219. function NewStr(S: String): PString;
  220. var
  221.   P: PString;
  222. begin
  223.   GetMem(P, Length(S) + 1);
  224.   if (P <> nil) then
  225.     PString(P)^ := S;
  226.   NewStr := P
  227. end;
  228. { Return true if InF is successfully converted to OutF }
  229. function ConvertIdents(var InF, OutF: Text): Boolean;
  230. var
  231.   Ch, PushedCh: Char;
  232.   State: TState;
  233.   Identifier : IdentStr;
  234.   function GetCh(var C: Char): Char;
  235.   begin
  236.     if PushedCh <> #0 then
  237.     begin
  238.       C := PushedCh;
  239.       PushedCh := #0
  240.     end else
  241.       Read(InF, C);
  242.     if (C = #13) or (C = #10) then
  243.     begin
  244.       if (C = #13) then
  245.         Writeln(OutF);  { Start new line }
  246.       C := #0           { Ignore new line characters }
  247.     end;
  248.     GetCh := C
  249.   end;
  250.   procedure UngetCh(Ch: Char);
  251.   begin
  252.     PushedCh := Ch
  253.   end;
  254.   procedure PutCh(Ch: Char);
  255.   begin
  256.     if Ch <> #0 then
  257.       Write(OutF, Ch)
  258.   end;
  259. begin
  260.   PushedCh := #0;     { No pushed character }
  261.   State := Reading;
  262.   while not eof(InF) do
  263.   begin
  264.     GetCh(Ch);
  265.     case State of
  266.       Reading:
  267.       begin
  268.         case Ch of
  269.           '('  : State := Chkcomment;
  270.           '{'  : State := Comment1;
  271.           '''' : State := Stringing;
  272.         end;
  273.         if Ch in alphaSet then
  274.         begin
  275.           UngetCh(Ch);
  276.           State := Converting
  277.         end else
  278.           PutCh(Ch)
  279.       end;
  280.       Chkcomment:
  281.         if Ch = '*' then
  282.         begin
  283.           PutCh(Ch);
  284.           State := Comment2
  285.         end else begin
  286.           UngetCh(Ch);
  287.           State := Reading
  288.         end;
  289.       Comment1:
  290.       begin
  291.         PutCh(Ch);
  292.         if Ch = '}' then
  293.           State := Reading
  294.       end;
  295.       Comment2:
  296.       begin
  297.         PutCh(Ch);
  298.         if Ch = '*' then
  299.           State := Stopcomment
  300.       end;
  301.       Stopcomment:
  302.       begin
  303.         PutCh(Ch);
  304.         if Ch = ')' then
  305.           State := Reading
  306.         else
  307.           State := Comment2;
  308.       end;
  309.       Stringing:
  310.       begin
  311.         PutCh(Ch);
  312.         if Ch = '''' then
  313.           State := Reading;
  314.       end;
  315.       Converting:
  316.       begin
  317.         Identifier := '';
  318.         while Ch in identSet do
  319.         begin
  320.           Identifier := Identifier + Ch;
  321.           Read(InF, Ch)  { Note: Don't call GetCh here! }
  322.         end;
  323.         if IsReserved(Identifier) then
  324.         begin
  325.           DownCase(Identifier);
  326.           if DelimitWords then
  327.             Identifier := '<*' + Identifier + '*>'
  328.         end else
  329.         if CapIdentifiers and (Length(Identifier) > 0) then
  330.           Identifier[1] := UpCase(Identifier[1]);
  331.         Write(OutF, Identifier);
  332.         UngetCh(Ch);
  333.         State := Reading
  334.       end
  335.     end
  336.   end;
  337.   if PushedCh <> #0 then  { Write possible pushed last char that }
  338.     PutCh(Ch);            {  sets eof() to true. }
  339.   ConvertIdents := true
  340. end;
  341. { Convert one file specified in Path string }
  342. procedure ConvertOneFile(Path: PathStr);
  343. var
  344.   Result: Integer;
  345.   BakF, InF, OutF: Text;
  346.   TempName, BakName: PathStr;
  347.   Name: NameStr;
  348.   Dir: DirStr;
  349.   Ext: ExtStr;
  350. begin
  351.   Write(Path);
  352.   Assign(InF, Path);
  353.   {$i-} Reset(InF); {$i+}
  354.   if IoResult <> 0 then
  355.     Writeln(' **Error opening file')
  356.   else begin
  357.     FSplit(Path, Dir, Name, Ext);
  358.     TempName := Dir + Name + tempExt;
  359.     BakName := Dir + Name + bakExt;
  360.     Assign(OutF, TempName);
  361.     {$i-} Rewrite(OutF); {$i+}
  362.     if IoResult <> 0 then
  363.       Writeln(' **Error creating output file')
  364.     else begin
  365.       if ConvertIdents(InF, OutF) then
  366.       begin
  367.         Close(InF);
  368.         Close(OutF);
  369.         Assign(BakF, BakName);
  370.         {$i-}
  371.         Erase(BakF);
  372.         Result := IoResult;      { Throw out IoResult }
  373.         Rename(InF, BakName);
  374.         Rename(OutF, Path);
  375.         {$i+}
  376.         if IoResult <> 0 then
  377.           Writeln(' **Error renaming files')
  378.         else
  379.           Writeln(' done')
  380.       end else
  381.         Writeln(' **Error processing files')
  382.     end
  383.   end
  384. end;
  385. { Convert files on global list at Root pointer }
  386. procedure ConvertFiles(List: PListRec);
  387. begin
  388.   if List = nil then
  389.     Writeln('No files specified')
  390.   else
  391.     while List <> nil do
  392.     begin
  393.       ConvertOneFile(List^.Path^);
  394.       List := List^.Next
  395.     end
  396. end;
  397.  
  398. { Add file path to list }
  399. procedure ListFile(var List: PListRec; Path: PathStr);
  400. var
  401.   P: PListRec;
  402. begin
  403.   New(P);
  404.   P^.Next := List;
  405.   P^.Path := NewStr(Path);
  406.   if P^.Path = nil then
  407.     Dispose(P)
  408.   else
  409.     List := P
  410. end;
  411. { Create list of file names from FileSpec string }
  412. procedure ListFiles(var List: PListRec);
  413. var
  414.   Sr: SearchRec;        { Directory search record }
  415.   L: Integer;           { Length of Dir string }
  416.   OldDir: DirStr;       { Old directory upon entry to procedure }
  417.   Path: PathStr;        { Expanded file specification with path info }
  418.   Dir: DirStr;          { Directory component of Path }
  419.   Name: NameStr;        { File name component of Path }
  420.   Ext: ExtStr;          { File extension component of Path }
  421. begin
  422.   GetDir(0, OldDir);             { Save current path }
  423.   Path := FExpand(FileSpec);     { Add path info to file spec }
  424.   FSplit(Path, Dir, Name, Ext);  { Separate Path components }
  425.   L := Length(Dir);              { Prepare to change directories }
  426.   if L > 0 then
  427.   begin
  428.     if (Dir[L] = '\') and (L > 1) and (Dir[L - 1] <> ':') then
  429.       Delete(Dir, L, 1); { Ensure that ChDir will work }
  430.     ChDir(Dir)           { Change to location of file(s) }
  431.   end;
  432.   FindFirst(Path, 0, Sr);        { Start file name search }
  433.   while DosError = 0 do          { Continue while files found }
  434.   begin
  435.     Path := FExpand(Sr.Name);    { Expand to full path name }
  436.     ListFile(List, Path);        { Add path to list }
  437.     FindNext(Sr)                 { Search for the next file }
  438.   end;
  439.   ChDir(OldDir)
  440. end;
  441. { Display instructions }
  442. procedure Instruct;
  443. begin
  444.   Writeln('Use -b option to surround reserved words with');
  445.   Writeln('<* and *> for bold-facing in a word processor.');
  446.   Writeln('Use -c option to capitalize non-keyword identifers.');
  447.   Writeln;
  448.   Writeln('WARNING: After conversion with -b, the listing will');
  449.   Writeln('not compile. Use -b ONLY on a copy of original files.');
  450.   Writeln;
  451.   Writeln('ex. IDENT single.pas');
  452.   Writeln('    IDENT -b one.pas two.pas');
  453.   Writeln('    IDENT wild??.pas -b *.pas')
  454. end;
  455. { Main program initializations }
  456. procedure Initialize;
  457. begin
  458.   Writeln;
  459.   Writeln('IDENT -- (C) 1994 by Tom Swan');
  460.   Writeln('Converts Pascal reserved words to lowercase.');
  461.   Writeln;
  462.   Root := nil;              { File name list is empty }
  463.   DelimitWords := false;    { Normally do not add <* and *> to words }
  464.   CapIdentifiers := false   { Normally do not capitalize other idents }
  465. end;
  466. { Main program block }
  467. var
  468.   I: Integer;
  469. begin
  470.   Initialize;
  471.   if ParamCount = 0 then
  472.     Instruct
  473.   else for I := 1 to ParamCount do
  474.   begin
  475.     FileSpec := ParamStr(I);
  476.     if (FileSpec = '-b') or (FileSpec = '-B') then
  477.       DelimitWords := true
  478.     else if (FileSpec = '-c') or (FileSpec = '-C') then
  479.       CapIdentifiers := true
  480.     else begin
  481.       ListFiles(Root);
  482.       ConvertFiles(Root)
  483.     end
  484.   end
  485. end.
  486.  
  487.  
  488.  
  489. Listing Four
  490.  
  491. Sub MAIN
  492. StartOfDocument
  493. EditFind .Find = "<*", .WholeWord = 0, .MatchCase = 0, .Direction = 1, \
  494. .Format = 0
  495. While EditFindFound()
  496.  EditClear
  497.  EditFind .Find = "*>", .WholeWord = 0, .MatchCase = 0, .Direction = 1, \
  498. .Format = 0
  499.  If Not EditFindFound() Then
  500.   Stop
  501.  End If
  502.  EditClear
  503.  WordLeft 1, 1
  504.  Bold 1
  505.  EditFind .Find = "<*", .WholeWord = 0, .MatchCase = 0, .Direction = 1, \
  506. .Format = 0
  507. Wend
  508. End Sub
  509.  
  510.  
  511. Example 1: 
  512.  
  513.             input
  514.               Arg: String;
  515.             var
  516.               P: Pointer;
  517.             begin
  518.               P <- Index[Arg[1]];
  519.               while(P <> nil) do
  520.               begin
  521.                 if P^.Word = Arg then
  522.                   return True;
  523.                 P <- P^.Next;
  524.               end;
  525.               return False;
  526.             end;
  527.             
  528.  
  529.  
  530.  
  531.  
  532.