home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / sa104os2.zip / SATHR104.ZIP / SATHER / CONTRIB / HUU / STRMATCH.SA < prev    next >
Text File  |  1994-10-25  |  7KB  |  224 lines

  1. -- Copyright (C) International Computer Science Institute, 1994.  COPYRIGHT  --
  2. -- NOTICE: This code is provided "AS IS" WITHOUT ANY WARRANTY and is subject --
  3. -- to the terms of the SATHER LIBRARY GENERAL PUBLIC LICENSE contained in    --
  4. -- the file "Doc/License" of the Sather distribution.  The license is also   --
  5. -- available from ICSI, 1947 Center St., Suite 600, Berkeley CA 94704, USA.  --
  6. --------> Please email comments to "sather-bugs@icsi.berkeley.edu". <----------
  7.  
  8. -- File: strmatch.sa
  9. -- Author: Le van Huu (huu@ICSI.Berkeley.EDU, levan@imiucca.csi.unimi.it))
  10. --*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  11. --* FUNCTION: Main class for two well known string matching algorithms.
  12. --* The algorithms come from 
  13. --* Thomas H. Cormen, Charles E., Introduction to Algorithms, MIT Press,1990,
  14. --* pp. 853-885.
  15. --*
  16. --*    PROBLEM DEFINITION: 
  17. --*        Assume the text string is an array T[0..n-1] and the
  18. --*     pattern string an array P[0..m-1]. We say that P occurs
  19. --*     with valid shifts s (or occurs beginning at positions s) in T if:
  20. --*                T[s+j] = P[j] for 0 =< j =< m -1
  21. --*        The algorithms implemented are the naive string matcher algorithm
  22. --*        and the Knuth-Morris-Pratt algorithm. 
  23. --*    
  24. --* NAIVE ALGORITHM: 
  25. --*        The algorithm uses P as a template to slide next to the text T
  26. --*     (from left to right, character by character). For each shift,
  27. --*     it compares all P[i] of T[s+i]. If no mismatched character
  28. --*        occurs, we obtain a valid shift position, otherwise we have
  29. --*        to slide P next.
  30. --*        The algorithm takes time O((n-m+1)m).
  31. --*
  32. --* KNUTH-MORRIS-PRATT:
  33. --*        When a mismatched character occurs at position q of P, 
  34. --*        instead of moving the template P to right only of a character,
  35. --*        the algorithm shifts to right of k characters, where k is the 
  36. --*        longhest prefix of P that is also a suffix of Pq.
  37. --*        The suffixes of all possible prefixes of the P string is 
  38. --*        precomputed by an appropriate routine. It takes time O(m).
  39. --*        The algorithm runs in time O(m+n). 
  40. --*
  41. --* CLASSES:  STRMATCH,  PREFIX
  42. --*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  43. class STRMATCH is
  44.     -- Main class for all string matching algorithms.
  45.     -- Each routine corresponds to an algorithm and can be called by 
  46.     -- any application. It contains two parameters corresponding to the
  47.     -- text string (T) and the pattern string (P) respectively. 
  48.     -- The strings must be terminated by the '\0' character.
  49.     -- Each routine also returns
  50.     -- an integer array representing the valid shift values.
  51.  
  52.     const init_size:INT:=10;        -- initial size of shift array
  53.     const ENDARR:INT:=-2;            -- special value indicating the array end
  54.     shared arr_obj : TASK_ARRAY {INT};    -- object for checking array sizes
  55.  
  56.     attr     n:INT;                    -- text length
  57.     attr    m:INT;                    -- pattern length
  58.     attr    s:INT;                    -- shift position 
  59.     attr     arr_shift:ARRAY{INT};     -- array of shift positions
  60.     attr    index_s:INT;            -- index of arr_shift 
  61.     attr    lim:INT;    
  62.  
  63.  
  64.     initialize(T: STR, P: STR) is
  65.         arr_obj := #TASK_ARRAY {INT};
  66.         arr_shift:=#ARRAY{INT}(init_size);
  67.         n:= T.length;    -- to discard the character '\0'
  68.         m:= P.length ;
  69.         lim:= n-m+1;
  70.         s:=0;
  71.         index_s:= 0;
  72.     end;
  73.  
  74.     create:STRMATCH is
  75.         res::=new;
  76.         return res;
  77.     end;
  78.     
  79.     naive (T: STR, P: STR): ARRAY{INT} is 
  80.         -- returns array of all shift numbers
  81.         itext:INT;                -- text index
  82.         ipattern:INT;            -- pattern index
  83.         found:BOOL;
  84.  
  85.         initialize(T, P);
  86.         loop until!  (s=lim);
  87.             found:=true;
  88.             itext:= s;
  89.             ipattern:=0;
  90.             loop until! (ipattern >= m);
  91.                 if P[ipattern] /= T[itext] then
  92.                     found := false;
  93.                     ipattern := m;
  94.                     itext := itext + 1;
  95.                 else
  96.                     itext := itext + 1;
  97.                 end; -- if
  98.                 ipattern := ipattern +1;
  99.             end; -- inner loop
  100.             if found then
  101.                 -- pattern matched a substring of text at position s.
  102.                 -- Before storing s into arr_shift, we must check if there
  103.                 -- are enougth rooms 
  104.                 arr_shift := arr_obj.check_size (arr_shift, index_s);
  105.                 arr_shift[index_s] := s;
  106.                 index_s:= index_s + 1;
  107.             end;    
  108.             s:= s+1;
  109.         end; -- outer loop
  110.         arr_shift[index_s]:= ENDARR;    
  111.         return  arr_shift;
  112.     end;
  113.  
  114.     kmp (T: STR, P: STR): ARRAY{INT} is 
  115.          -- Knuth-Morris-Pratt algorithm
  116.         q, i  : INT;
  117.  
  118.         initialize(T, P);
  119.  
  120.         prefix_id:PREFIX:= #PREFIX;
  121.         prefix_id.compute_prefix (P, m);
  122.  
  123.         q := -1;
  124.         i := 0;
  125.         lim := m-1;
  126.  
  127.         loop until! ( i>= n);
  128.             loop
  129.                 if q >= 0 and P[q+1] /= T[i] then
  130.                     q := prefix_id.arr_prefix [q];
  131.                 else
  132.                     break!;
  133.                 end;
  134.             end; -- inner loop
  135.             if P[q+1] = T[i] then
  136.                 q:= q+1;
  137.             end;
  138.             if q = lim then
  139.                 -- pattern matched a substring of text at position i-m+1.
  140.                 q:=prefix_id.arr_prefix[q];
  141.                 arr_shift := arr_obj.check_size (arr_shift, index_s);
  142.                 arr_shift[index_s] := i-m+1;
  143.                 index_s:= index_s + 1;
  144.             end;    
  145.             i:= i+1;
  146.         end; -- outer loop
  147.         arr_shift[index_s]:= ENDARR; -- special value to indicate the array end.
  148.         return  arr_shift;
  149.     end; -- kmp routine    
  150. end; -- class STRMATCH
  151.  
  152. --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~``
  153.  
  154. class PREFIX is
  155.     -- Useful for the KMP algorithm. 
  156.     -- Prepares the arr_prefix containing the suffixes 
  157.     -- of all possible prefixes of the P string
  158.     const prefix_size:INT:=10;
  159.      attr arr_prefix:ARRAY{INT};     -- array of prefix positions
  160.  
  161.     create:PREFIX is
  162.         res ::= new;
  163.         return res;
  164.     end;
  165.  
  166.     compute_prefix(P:STR, m:INT) is    
  167.         -- Prepares the arr_prefix containing the suffixes 
  168.         -- of all possible prefixes of the P string
  169.         k, q :INT;
  170.         arr_obj:TASK_ARRAY {INT} := #TASK_ARRAY {INT};
  171.         arr_prefix:=#ARRAY{INT}(prefix_size);
  172.  
  173.         arr_prefix[0] := -1;
  174.         k := -1;
  175.         q := 1;
  176.         loop until! (q >= m); 
  177.             loop
  178.                 if k >= 0 and P[k+1] /= P[q] then
  179.                     k := arr_prefix [k];
  180.                 else
  181.                     break!;
  182.                 end;
  183.             end; -- inner loop
  184.             if P[k+1] = P[q] then
  185.                 k:= k+1;
  186.             end;
  187.             arr_prefix := arr_obj.check_size (arr_prefix, q);
  188.             arr_prefix[q] := k;
  189.             q:= q+1;
  190.         end; -- outer loop
  191.     end; -- compute_prefix
  192.  
  193.     print (arr_prefix: ARRAY {INT}, m :INT) is
  194.         i:INT :=0;
  195.         #OUT + "prefix=" + "\n";
  196.         loop until!  (i=m);
  197.             #OUT + arr_prefix[i] + "    ";
  198.             i := i +1;
  199.         end;
  200.         #OUT + "\n";
  201.     end; -- print
  202. end; -- class PREFIX
  203.  
  204. --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~``
  205. class TASK_ARRAY {T} is
  206.     -- class shared by objects that need to check if there are sufficient rooms
  207.     -- in their arrays for storing data. 
  208.     -- Enventually, the built-in toutine "resize" will extend
  209.     -- the array dimensione doubling its preceding size.
  210.  
  211.     create:TASK_ARRAY {T} is
  212.         res ::= new;
  213.         return res;
  214.     end;
  215.  
  216.     check_size (arr: ARRAY{T}, index:INT) : ARRAY{T} is
  217.         
  218.        if index >= (arr.asize - 1) then
  219.             arr:= arr.resize(2*arr.asize);
  220.         end;
  221.         return arr;
  222.     end;
  223. end; -- class TASK_ARRAY
  224.