home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / adav313.zip / gnat-3_13p-os2-bin-20010916.zip / emx / gnatlib / g-regexp.adb < prev    next >
Text File  |  2000-07-19  |  50KB  |  1,460 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT COMPILER COMPONENTS                         --
  4. --                                                                          --
  5. --                          G N A T . R E G E X P                           --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.23 $                             --
  10. --                                                                          --
  11. --              Copyright (C) 1999 Ada Core Technologies, Inc.              --
  12. --                                                                          --
  13. -- GNAT is free software;  you can  redistribute it  and/or modify it under --
  14. -- terms of the  GNU General Public License as published  by the Free Soft- --
  15. -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
  16. -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  17. -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  18. -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
  19. -- for  more details.  You should have  received  a copy of the GNU General --
  20. -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
  21. -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
  22. -- MA 02111-1307, USA.                                                      --
  23. --                                                                          --
  24. -- As a special exception,  if other files  instantiate  generics from this --
  25. -- unit, or you link  this unit with other files  to produce an executable, --
  26. -- this  unit  does not  by itself cause  the resulting  executable  to  be --
  27. -- covered  by the  GNU  General  Public  License.  This exception does not --
  28. -- however invalidate  any other reasons why  the executable file  might be --
  29. -- covered by the  GNU Public License.                                      --
  30. --                                                                          --
  31. -- GNAT is maintained by Ada Core Technologies Inc (http://www.gnat.com).   --
  32. --                                                                          --
  33. ------------------------------------------------------------------------------
  34.  
  35. with Ada.Text_IO;
  36. with Unchecked_Deallocation;
  37. with Ada.Exceptions;
  38. with GNAT.Case_Util;
  39.  
  40. package body GNAT.Regexp is
  41.  
  42.    Open_Paren    : constant Character := '(';
  43.    Close_Paren   : constant Character := ')';
  44.    Open_Bracket  : constant Character := '[';
  45.    Close_Bracket : constant Character := ']';
  46.  
  47.    type State_Index is new Natural;
  48.    type Column_Index is new Natural;
  49.  
  50.    type Regexp_Array is array
  51.      (State_Index range <>, Column_Index range <>) of State_Index;
  52.    --  First index is for the state number
  53.    --  Second index is for the character type
  54.    --  Contents is the new State
  55.  
  56.    type Regexp_Array_Access is access Regexp_Array;
  57.    --  Use this type through the functions Set below, so that it
  58.    --  can grow dynamically depending on the needs.
  59.  
  60.    type Mapping is array (Character'Range) of Column_Index;
  61.    --  Mapping between characters and column in the Regexp_Array
  62.  
  63.    type Boolean_Array is array (State_Index range <>) of Boolean;
  64.  
  65.    type Regexp_Value
  66.      (Alphabet_Size : Column_Index;
  67.       Num_States    : State_Index) is
  68.    record
  69.       Map            : Mapping;
  70.       States         : Regexp_Array (1 .. Num_States, 0 .. Alphabet_Size);
  71.       Is_Final       : Boolean_Array (1 .. Num_States);
  72.       Case_Sensitive : Boolean;
  73.    end record;
  74.    --  Deterministic finite-state machine
  75.  
  76.    Debug : constant Boolean := False;
  77.    --  When True, the primary and secondary tables will be printed.
  78.    --  Gnat does not generate any code if this variable is False;
  79.  
  80.    procedure Set (Table  : in out Regexp_Array_Access;
  81.                   State  : State_Index;
  82.                   Column : Column_Index;
  83.                   Value  : State_Index);
  84.    --  Sets a value in the table. If the table is too small, reallocate it
  85.    --  dynamically so that (State, Column) is a valid index in it.
  86.  
  87.    function Get (Table  : Regexp_Array_Access;
  88.                  State  : State_Index;
  89.                  Column : Column_Index)
  90.                 return State_Index;
  91.    --  Returns the value in the table at (State, Column).
  92.    --  If this index does not exist in the table, returns 0
  93.  
  94.    procedure Free is new Unchecked_Deallocation
  95.      (Regexp_Array, Regexp_Array_Access);
  96.  
  97.    ------------
  98.    -- Adjust --
  99.    ------------
  100.  
  101.    procedure Adjust (R : in out Regexp) is
  102.       Tmp : Regexp_Access;
  103.    begin
  104.       Tmp := new Regexp_Value (Alphabet_Size => R.R.Alphabet_Size,
  105.                                Num_States    => R.R.Num_States);
  106.       Tmp.all := R.R.all;
  107.       R.R := Tmp;
  108.    end Adjust;
  109.  
  110.    -------------
  111.    -- Compile --
  112.    -------------
  113.  
  114.    function Compile
  115.      (Pattern        : String;
  116.       Glob           : Boolean := False;
  117.       Case_Sensitive : Boolean := True)
  118.       return           Regexp
  119.    is
  120.       S : String := Pattern;
  121.       --  The pattern which is really compiled (when the pattern is case
  122.       --  insensitive, we convert this string to lower-cases
  123.  
  124.       Map : Mapping := (others => 0);
  125.       --  Mapping between characters and columns in the tables
  126.  
  127.       Alphabet_Size : Column_Index := 0;
  128.       --  Number of significant characters in the regular expression.
  129.       --  This total does not include special operators, such as *, (, ...
  130.  
  131.       procedure Create_Mapping;
  132.       --  Creates a mapping between characters in the regexp and columns
  133.       --  in the tables representing the regexp. Test that the regexp is
  134.       --  well-formed Modifies Alphabet_Size and Map
  135.  
  136.       procedure Create_Primary_Table
  137.         (Table       : out Regexp_Array_Access;
  138.          Num_States  : out State_Index;
  139.          Start_State : out State_Index;
  140.          End_State   : out State_Index);
  141.       --  Creates the first version of the regexp (this is a non determinist
  142.       --  finite state machine, which is unadapted for a fast pattern
  143.       --  matching algorithm). We use a recursive algorithm to process the
  144.       --  parenthesis sub-expressions.
  145.       --
  146.       --  Table : at the end of the procedure : Column 0 is for any character
  147.       --  ('.') and the last columns are for no character (closure)
  148.       --  Num_States is set to the number of states in the table
  149.       --  Start_State is the number of the starting state in the regexp
  150.       --  End_State is the number of the final state when the regexp matches
  151.  
  152.       procedure Create_Primary_Table_Glob
  153.         (Table       : out Regexp_Array_Access;
  154.          Num_States  : out State_Index;
  155.          Start_State : out State_Index;
  156.          End_State   : out State_Index);
  157.       --  Same function as above, but it deals with the second possible
  158.       --  grammar for 'globbing pattern', which is a kind of subset of the
  159.       --  whole regular expression grammar.
  160.  
  161.       function Create_Secondary_Table
  162.         (First_Table : Regexp_Array_Access;
  163.          Num_States  : State_Index;
  164.          Start_State : State_Index;
  165.          End_State   : State_Index)
  166.          return        Regexp;
  167.       --  Creates the definitive table representing the regular expression
  168.       --  This is actually a transformation of the primary table First_Table,
  169.       --  where every state is grouped with the states in its 'no-character'
  170.       --  columns. The transitions between the new states are then recalculated
  171.       --  and if necessary some new states are created.
  172.       --
  173.       --  Note that the resulting finite-state machine is not optimized in
  174.       --  terms of the number of states : it would be more time-consuming to
  175.       --  add a third pass to reduce the number of states in the machine, with
  176.       --  no speed improvement...
  177.  
  178.       procedure Raise_Exception
  179.         (M     : String;
  180.          Index : Integer);
  181.       pragma No_Return (Raise_Exception);
  182.       --  Raise an exception, indicating an error at character Index in S.
  183.  
  184.       procedure Print_Table
  185.         (Table      : Regexp_Array;
  186.          Num_States : State_Index;
  187.          Is_Primary : Boolean := True);
  188.       --  Print a table for debugging purposes
  189.  
  190.       --------------------
  191.       -- Create_Mapping --
  192.       --------------------
  193.  
  194.       procedure Create_Mapping is
  195.  
  196.          procedure Add_In_Map (C : Character);
  197.          --  Add a character in the mapping, if it is not already defined
  198.  
  199.          -----------------
  200.          --  Add_In_Map --
  201.          -----------------
  202.  
  203.          procedure Add_In_Map (C : Character) is
  204.          begin
  205.             if Map (C) = 0 then
  206.                Alphabet_Size := Alphabet_Size + 1;
  207.                Map (C) := Alphabet_Size;
  208.             end if;
  209.          end Add_In_Map;
  210.  
  211.          J                 : Integer := S'First;
  212.          Parenthesis_Level : Integer := 0;
  213.          Curly_Level       : Integer := 0;
  214.  
  215.       --  Start of processing for Create_Mapping
  216.  
  217.       begin
  218.          while J <= S'Last loop
  219.             case S (J) is
  220.                when Open_Bracket =>
  221.                   J := J + 1;
  222.  
  223.                   if S (J) = '^' then
  224.                      J := J + 1;
  225.                   end if;
  226.  
  227.                   if S (J) = ']' or S (J) = '-' then
  228.                      J := J + 1;
  229.                   end if;
  230.  
  231.                   --  The first character never has a special meaning
  232.  
  233.                   loop
  234.                      if J > S'Last then
  235.                         Raise_Exception
  236.                           ("Ran out of characters while parsing ", J);
  237.                      end if;
  238.  
  239.                      exit when S (J) = Close_Bracket;
  240.  
  241.                      if S (J) = '-'
  242.                        and then S (J + 1) /= Close_Bracket
  243.                      then
  244.                         declare
  245.                            Start : constant Integer := J - 1;
  246.                         begin
  247.                            J := J + 1;
  248.                            if S (J) = '\' then
  249.                               J := J + 1;
  250.                            end if;
  251.  
  252.                            for Char in S (Start) .. S (J) loop
  253.                               Add_In_Map (Char);
  254.                            end loop;
  255.                         end;
  256.                      else
  257.                         if S (J) = '\' then
  258.                            J := J + 1;
  259.                         end if;
  260.  
  261.                         Add_In_Map (S (J));
  262.                      end if;
  263.                      J := J + 1;
  264.                   end loop;
  265.  
  266.                   --  A close bracket must follow a open_bracket,
  267.                   --  and cannot be found alone on the line
  268.  
  269.                when Close_Bracket =>
  270.                   Raise_Exception
  271.                     ("Incorrect character ']' in regular expression", J);
  272.  
  273.                when '\' =>
  274.                   if J < S'Last  then
  275.                      J := J + 1;
  276.                      Add_In_Map (S (J));
  277.                   else
  278.  
  279.                      --  \ not allowed at the end of the regexp
  280.                      Raise_Exception
  281.                        ("Incorrect character '\' in regular expression", J);
  282.                   end if;
  283.  
  284.                when Open_Paren =>
  285.                   if not Glob then
  286.                      Parenthesis_Level := Parenthesis_Level + 1;
  287.                   else
  288.                      Add_In_Map (Open_Paren);
  289.                   end if;
  290.  
  291.                when Close_Paren =>
  292.                   if not Glob then
  293.                      Parenthesis_Level := Parenthesis_Level - 1;
  294.  
  295.                      if Parenthesis_Level < 0 then
  296.                         Raise_Exception
  297.                           ("')' is not associated with '(' in regular "
  298.                            & "expression", J);
  299.                      end if;
  300.  
  301.                      if S (J - 1) = Open_Paren then
  302.                         Raise_Exception
  303.                           ("Empty parenthesis not allowed in regular "
  304.                            & "expression", J);
  305.                      end if;
  306.  
  307.                   else
  308.                      Add_In_Map (Close_Paren);
  309.                   end if;
  310.  
  311.                when '.' =>
  312.                   if Glob then
  313.                      Add_In_Map ('.');
  314.                   end if;
  315.  
  316.                when '{' =>
  317.                   if not Glob then
  318.                      Add_In_Map (S (J));
  319.                   else
  320.                      Curly_Level := Curly_Level + 1;
  321.                   end if;
  322.  
  323.                when '}' =>
  324.                   if not Glob then
  325.                      Add_In_Map (S (J));
  326.                   else
  327.                      Curly_Level := Curly_Level - 1;
  328.                   end if;
  329.  
  330.                when '*' | '?' =>
  331.                   if not Glob then
  332.                      if J = S'First then
  333.                         Raise_Exception
  334.                           ("'*', '+', '?' and '|' operators can not be in "
  335.                            & "first position in regular expression", J);
  336.                      end if;
  337.                   end if;
  338.  
  339.                when '|' | '+' =>
  340.                   if not Glob then
  341.                      if J = S'First then
  342.  
  343.                         --  These operators must apply to a sub-expression,
  344.                         --  and cannot be found at the beginning of the line
  345.  
  346.                         Raise_Exception
  347.                           ("'*', '+', '?' and '|' operators can not be in "
  348.                            & "first position in regular expression", J);
  349.                      end if;
  350.  
  351.                   else
  352.                      Add_In_Map (S (J));
  353.                   end if;
  354.  
  355.                when others =>
  356.                   Add_In_Map (S (J));
  357.             end case;
  358.  
  359.             J := J + 1;
  360.          end loop;
  361.  
  362.          --  A closing parenthesis must follow an open parenthesis
  363.  
  364.          if Parenthesis_Level /= 0 then
  365.             Raise_Exception
  366.               ("'(' must always be associated with a ')'", J);
  367.          end if;
  368.  
  369.          if Curly_Level /= 0 then
  370.             Raise_Exception
  371.               ("'{' must always be associated with a '}'", J);
  372.          end if;
  373.       end Create_Mapping;
  374.  
  375.       --------------------------
  376.       -- Create_Primary_Table --
  377.       --------------------------
  378.  
  379.       procedure Create_Primary_Table
  380.         (Table       : out Regexp_Array_Access;
  381.          Num_States  : out State_Index;
  382.          Start_State : out State_Index;
  383.          End_State   : out State_Index)
  384.       is
  385.          Empty_Char : constant Column_Index := Alphabet_Size + 1;
  386.  
  387.          Current_State : State_Index := 0;
  388.          --  Index of the last created state
  389.  
  390.          procedure Add_Empty_Char
  391.            (State    : State_Index;
  392.             To_State : State_Index);
  393.          --  Add a empty-character transition from State to To_State.
  394.  
  395.          procedure Create_Repetition
  396.            (Repetition : Character;
  397.             Start_Prev : State_Index;
  398.             End_Prev   : State_Index;
  399.             New_Start  : out State_Index;
  400.             New_End    : in out State_Index);
  401.          --  Create the table in case we have a '*', '+' or '?'.
  402.          --  Start_Prev .. End_Prev should indicate respectively the start and
  403.          --  end index of the previous expression, to which '*', '+' or '?' is
  404.          --  applied.
  405.  
  406.          procedure Create_Simple
  407.            (Start_Index : Integer;
  408.             End_Index   : Integer;
  409.             Start_State : out State_Index;
  410.             End_State   : out State_Index);
  411.          --  Fill the table for the regexp Simple.
  412.          --  This is the recursive procedure called to handle () expressions
  413.          --  If End_State = 0, then the call to Create_Simple creates an
  414.          --  independent regexp, not a concatenation
  415.          --  Start_Index .. End_Index is the starting index in the string S.
  416.          --
  417.          --  Warning: it may look like we are creating too many empty-string
  418.          --  transitions, but they are needed to get the correct regexp.
  419.          --  The table is filled as follow ( s means start-state, e means
  420.          --  end-state) :
  421.          --
  422.          --  regexp   state_num | a b * empty_string
  423.          --  -------  ---------------------------------------
  424.          --    a          1 (s) | 2 - - -
  425.          --               2 (e) | - - - -
  426.          --
  427.          --    ab         1 (s) | 2 - - -
  428.          --               2     | - - - 3
  429.          --               3     | - 4 - -
  430.          --               4 (e) | - - - -
  431.          --
  432.          --    a|b        1     | 2 - - -
  433.          --               2     | - - - 6
  434.          --               3     | - 4 - -
  435.          --               4     | - - - 6
  436.          --               5 (s) | - - - 1,3
  437.          --               6 (e) | - - - -
  438.          --
  439.          --    a*         1     | 2 - - -
  440.          --               2     | - - - 4
  441.          --               3 (s) | - - - 1,4
  442.          --               4 (e) | - - - 3
  443.          --
  444.          --    (a)        1 (s) | 2 - - -
  445.          --               2 (e) | - - - -
  446.          --
  447.          --    a+         1     | 2 - - -
  448.          --               2     | - - - 4
  449.          --               3 (s) | - - - 1
  450.          --               4 (e) | - - - 3
  451.          --
  452.          --    a?         1     | 2 - - -
  453.          --               2     | - - - 4
  454.          --               3 (s) | - - - 1,4
  455.          --               4 (e) | - - - -
  456.          --
  457.          --    .          1 (s) | 2 2 2 -
  458.          --               2 (e) | - - - -
  459.  
  460.          function Next_Sub_Expression
  461.            (Start_Index : Integer;
  462.             End_Index   : Integer)
  463.             return        Integer;
  464.          --  Returns the index of the last character of the next sub-expression
  465.          --  in Simple. Index can not be greater than End_Index
  466.  
  467.          --------------------
  468.          -- Add_Empty_Char --
  469.          --------------------
  470.  
  471.          procedure Add_Empty_Char
  472.            (State    : State_Index;
  473.             To_State : State_Index)
  474.          is
  475.             J : Column_Index := Empty_Char;
  476.  
  477.          begin
  478.             while Get (Table, State, J) /= 0 loop
  479.                J := J + 1;
  480.             end loop;
  481.  
  482.             Set (Table, State, J, To_State);
  483.          end Add_Empty_Char;
  484.  
  485.          -----------------------
  486.          -- Create_Repetition --
  487.          -----------------------
  488.  
  489.          procedure Create_Repetition
  490.            (Repetition : Character;
  491.             Start_Prev : State_Index;
  492.             End_Prev   : State_Index;
  493.             New_Start  : out State_Index;
  494.             New_End    : in out State_Index)
  495.          is
  496.          begin
  497.             New_Start := Current_State + 1;
  498.  
  499.             if New_End /= 0 then
  500.                Add_Empty_Char (New_End, New_Start);
  501.             end if;
  502.  
  503.             Current_State := Current_State + 2;
  504.             New_End   := Current_State;
  505.  
  506.             Add_Empty_Char (End_Prev, New_End);
  507.             Add_Empty_Char (New_Start, Start_Prev);
  508.  
  509.             if Repetition /= '+' then
  510.                Add_Empty_Char (New_Start, New_End);
  511.             end if;
  512.  
  513.             if Repetition /= '?' then
  514.                Add_Empty_Char (New_End, New_Start);
  515.             end if;
  516.          end Create_Repetition;
  517.  
  518.          -------------------
  519.          -- Create_Simple --
  520.          -------------------
  521.  
  522.          procedure Create_Simple
  523.            (Start_Index : Integer;
  524.             End_Index   : Integer;
  525.             Start_State : out State_Index;
  526.             End_State   : out State_Index)
  527.          is
  528.             J          : Integer := Start_Index;
  529.             Last_Start : State_Index := 0;
  530.  
  531.          begin
  532.             Start_State := 0;
  533.             End_State   := 0;
  534.             while J <= End_Index loop
  535.                case S (J) is
  536.                   when Open_Paren =>
  537.                      declare
  538.                         J_Start    : Integer := J + 1;
  539.                         Next_Start : State_Index;
  540.                         Next_End   : State_Index;
  541.  
  542.                      begin
  543.                         J := Next_Sub_Expression (J, End_Index);
  544.                         Create_Simple (J_Start, J - 1, Next_Start, Next_End);
  545.  
  546.                         if J < End_Index
  547.                           and then (S (J + 1) = '*' or else
  548.                                     S (J + 1) = '+' or else
  549.                                     S (J + 1) = '?')
  550.                         then
  551.                            J := J + 1;
  552.                            Create_Repetition
  553.                              (S (J),
  554.                               Next_Start,
  555.                               Next_End,
  556.                               Last_Start,
  557.                               End_State);
  558.  
  559.                         else
  560.                            Last_Start := Next_Start;
  561.  
  562.                            if End_State /= 0 then
  563.                               Add_Empty_Char (End_State, Last_Start);
  564.                            end if;
  565.  
  566.                            End_State := Next_End;
  567.                         end if;
  568.                      end;
  569.  
  570.                   when '|' =>
  571.                      declare
  572.                         Start_Prev : State_Index := Start_State;
  573.                         End_Prev   : State_Index := End_State;
  574.                         Start_Next : State_Index := 0;
  575.                         End_Next   : State_Index := 0;
  576.                         Start_J    : Integer := J + 1;
  577.  
  578.                      begin
  579.                         J := Next_Sub_Expression (J, End_Index);
  580.  
  581.                         --  Create a new state for the start of the alternative
  582.  
  583.                         Current_State := Current_State + 1;
  584.                         Last_Start := Current_State;
  585.                         Start_State := Last_Start;
  586.  
  587.                         --  Create the tree for the second part of alternative
  588.  
  589.                         Create_Simple (Start_J, J, Start_Next, End_Next);
  590.  
  591.                         --  Create the end state
  592.  
  593.                         Add_Empty_Char (Last_Start, Start_Next);
  594.                         Add_Empty_Char (Last_Start, Start_Prev);
  595.                         Current_State := Current_State + 1;
  596.                         End_State := Current_State;
  597.                         Add_Empty_Char (End_Prev, End_State);
  598.                         Add_Empty_Char (End_Next, End_State);
  599.                      end;
  600.  
  601.                   when Open_Bracket =>
  602.                      Current_State := Current_State + 1;
  603.  
  604.                      declare
  605.                         Next_State : State_Index := Current_State + 1;
  606.  
  607.                      begin
  608.                         J := J + 1;
  609.  
  610.                         if S (J) = '^' then
  611.                            J := J + 1;
  612.  
  613.                            Next_State := 0;
  614.  
  615.                            for Column in 0 .. Alphabet_Size loop
  616.                               Set (Table, Current_State, Column,
  617.                                    Value => Current_State + 1);
  618.                            end loop;
  619.                         end if;
  620.  
  621.                         --  Automatically add the first character
  622.  
  623.                         if S (J) = '-' or S (J) = ']' then
  624.                            Set (Table, Current_State, Map (S (J)),
  625.                                 Value => Next_State);
  626.                            J := J + 1;
  627.                         end if;
  628.  
  629.                         --  Loop till closing bracket found
  630.  
  631.                         loop
  632.                            exit when S (J) = Close_Bracket;
  633.  
  634.                            if S (J) = '-'
  635.                              and then S (J + 1) /= ']'
  636.                            then
  637.                               declare
  638.                                  Start : constant Integer := J - 1;
  639.                               begin
  640.                                  J := J + 1;
  641.  
  642.                                  if S (J) = '\' then
  643.                                     J := J + 1;
  644.                                  end if;
  645.  
  646.                                  for Char in S (Start) .. S (J) loop
  647.                                     Set (Table, Current_State, Map (Char),
  648.                                          Value => Next_State);
  649.                                  end loop;
  650.                               end;
  651.  
  652.                            else
  653.                               if S (J) = '\' then
  654.                                  J := J + 1;
  655.                               end if;
  656.  
  657.                               Set (Table, Current_State, Map (S (J)),
  658.                                    Value => Next_State);
  659.                            end if;
  660.                            J := J + 1;
  661.                         end loop;
  662.                      end;
  663.  
  664.                      Current_State := Current_State + 1;
  665.  
  666.                      --  If the next symbol is a special symbol
  667.  
  668.                      if J < End_Index
  669.                        and then (S (J + 1) = '*' or else
  670.                                  S (J + 1) = '+' or else
  671.                                  S (J + 1) = '?')
  672.                      then
  673.                         J := J + 1;
  674.                         Create_Repetition
  675.                           (S (J),
  676.                            Current_State - 1,
  677.                            Current_State,
  678.                            Last_Start,
  679.                            End_State);
  680.  
  681.                      else
  682.                         Last_Start := Current_State - 1;
  683.  
  684.                         if End_State /= 0 then
  685.                            Add_Empty_Char (End_State, Last_Start);
  686.                         end if;
  687.  
  688.                         End_State := Current_State;
  689.                      end if;
  690.  
  691.                   when '*' | '+' | '?'
  692.                     | Close_Paren
  693.                     | Close_Bracket =>
  694.                      Raise_Exception
  695.                        ("Incorrect character in regular expression :", J);
  696.  
  697.                   when others =>
  698.                      Current_State := Current_State + 1;
  699.  
  700.                      --  Create the state for the symbol S (J)
  701.  
  702.                      if S (J) = '.' then
  703.                         for K in 0 .. Alphabet_Size loop
  704.                            Set (Table, Current_State, K,
  705.                                 Value => Current_State + 1);
  706.                         end loop;
  707.                      else
  708.                         if S (J) = '\' then
  709.                            J := J + 1;
  710.                         end if;
  711.                         Set (Table, Current_State, Map (S (J)),
  712.                              Value => Current_State + 1);
  713.                      end if;
  714.  
  715.                      Current_State := Current_State + 1;
  716.  
  717.                      --  If the next symbol is a special symbol
  718.  
  719.                      if J < End_Index
  720.                        and then (S (J + 1) = '*' or else
  721.                                  S (J + 1) = '+' or else
  722.                                  S (J + 1) = '?')
  723.                      then
  724.                         J := J + 1;
  725.                         Create_Repetition
  726.                           (S (J),
  727.                            Current_State - 1,
  728.                            Current_State,
  729.                            Last_Start,
  730.                            End_State);
  731.  
  732.                      else
  733.                         Last_Start := Current_State - 1;
  734.  
  735.                         if End_State /= 0 then
  736.                            Add_Empty_Char (End_State, Last_Start);
  737.                         end if;
  738.  
  739.                         End_State := Current_State;
  740.                      end if;
  741.  
  742.                end case;
  743.  
  744.                if Start_State = 0 then
  745.                   Start_State := Last_Start;
  746.                end if;
  747.  
  748.                J := J + 1;
  749.             end loop;
  750.          end Create_Simple;
  751.  
  752.          -------------------------
  753.          -- Next_Sub_Expression --
  754.          -------------------------
  755.  
  756.          function Next_Sub_Expression
  757.            (Start_Index : Integer;
  758.             End_Index   : Integer)
  759.             return        Integer
  760.          is
  761.             J              : Integer := Start_Index;
  762.             Start_On_Alter : Boolean := False;
  763.  
  764.          begin
  765.             if S (J) = '|' then
  766.                Start_On_Alter := True;
  767.             end if;
  768.  
  769.             loop
  770.                exit when J = End_Index;
  771.                J := J + 1;
  772.  
  773.                case S (J) is
  774.                   when '\' =>
  775.                      J := J + 1;
  776.  
  777.                   when Open_Bracket =>
  778.                      loop
  779.                         J := J + 1;
  780.                         exit when S (J) = Close_Bracket;
  781.  
  782.                         if S (J) = '\' then
  783.                            J := J + 1;
  784.                         end if;
  785.                      end loop;
  786.  
  787.                   when Open_Paren =>
  788.                      J := Next_Sub_Expression (J, End_Index);
  789.  
  790.                   when Close_Paren =>
  791.                      return J;
  792.  
  793.                   when '|' =>
  794.                      if Start_On_Alter then
  795.                         return J - 1;
  796.                      end if;
  797.  
  798.                   when others =>
  799.                      null;
  800.                end case;
  801.             end loop;
  802.  
  803.             return J;
  804.          end Next_Sub_Expression;
  805.  
  806.       --  Start of Create_Primary_Table
  807.  
  808.       begin
  809.          Table.all := (others => (others => 0));
  810.          Create_Simple (S'First, S'Last, Start_State, End_State);
  811.          Num_States := Current_State;
  812.       end Create_Primary_Table;
  813.  
  814.       -------------------------------
  815.       -- Create_Primary_Table_Glob --
  816.       -------------------------------
  817.  
  818.       procedure Create_Primary_Table_Glob
  819.         (Table       : out Regexp_Array_Access;
  820.          Num_States  : out State_Index;
  821.          Start_State : out State_Index;
  822.          End_State   : out State_Index)
  823.       is
  824.          Empty_Char : constant Column_Index := Alphabet_Size + 1;
  825.  
  826.          Current_State : State_Index := 0;
  827.          --  Index of the last created state
  828.  
  829.          procedure Add_Empty_Char
  830.            (State    : State_Index;
  831.             To_State : State_Index);
  832.          --  Add a empty-character transition from State to To_State.
  833.  
  834.          procedure Create_Simple
  835.            (Start_Index : Integer;
  836.             End_Index   : Integer;
  837.             Start_State : out State_Index;
  838.             End_State   : out State_Index);
  839.          --  Fill the table for the S (Start_Index .. End_Index).
  840.          --  This is the recursive procedure called to handle () expressions
  841.  
  842.          --------------------
  843.          -- Add_Empty_Char --
  844.          --------------------
  845.  
  846.          procedure Add_Empty_Char
  847.            (State    : State_Index;
  848.             To_State : State_Index)
  849.          is
  850.             J : Column_Index := Empty_Char;
  851.  
  852.          begin
  853.             while Get (Table, State, J) /= 0 loop
  854.                J := J + 1;
  855.             end loop;
  856.  
  857.             Set (Table, State, J,
  858.                  Value => To_State);
  859.          end Add_Empty_Char;
  860.  
  861.          -------------------
  862.          -- Create_Simple --
  863.          -------------------
  864.  
  865.          procedure Create_Simple
  866.            (Start_Index : Integer;
  867.             End_Index   : Integer;
  868.             Start_State : out State_Index;
  869.             End_State   : out State_Index)
  870.          is
  871.             J          : Integer := Start_Index;
  872.             Last_Start : State_Index := 0;
  873.  
  874.          begin
  875.             Start_State := 0;
  876.             End_State   := 0;
  877.  
  878.             while J <= End_Index loop
  879.                case S (J) is
  880.  
  881.                   when Open_Bracket =>
  882.                      Current_State := Current_State + 1;
  883.  
  884.                      declare
  885.                         Next_State : State_Index := Current_State + 1;
  886.  
  887.                      begin
  888.                         J := J + 1;
  889.  
  890.                         if S (J) = '^' then
  891.                            J := J + 1;
  892.                            Next_State := 0;
  893.  
  894.                            for Column in 0 .. Alphabet_Size loop
  895.                               Set (Table, Current_State, Column,
  896.                                    Value => Current_State + 1);
  897.                            end loop;
  898.                         end if;
  899.  
  900.                         --  Automatically add the first character
  901.  
  902.                         if S (J) = '-' or S (J) = ']' then
  903.                            Set (Table, Current_State, Map (S (J)),
  904.                                 Value => Current_State);
  905.                            J := J + 1;
  906.                         end if;
  907.  
  908.                         --  Loop till closing bracket found
  909.  
  910.                         loop
  911.                            exit when S (J) = Close_Bracket;
  912.  
  913.                            if S (J) = '-'
  914.                              and then S (J + 1) /= ']'
  915.                            then
  916.                               declare
  917.                                  Start : constant Integer := J - 1;
  918.                               begin
  919.                                  J := J + 1;
  920.  
  921.                                  if S (J) = '\' then
  922.                                     J := J + 1;
  923.                                  end if;
  924.  
  925.                                  for Char in S (Start) .. S (J) loop
  926.                                     Set (Table, Current_State, Map (Char),
  927.                                          Value => Next_State);
  928.                                  end loop;
  929.                               end;
  930.  
  931.                            else
  932.                               if S (J) = '\' then
  933.                                  J := J + 1;
  934.                               end if;
  935.  
  936.                               Set (Table, Current_State, Map (S (J)),
  937.                                    Value => Next_State);
  938.                            end if;
  939.                            J := J + 1;
  940.                         end loop;
  941.                      end;
  942.  
  943.                      Last_Start := Current_State;
  944.                      Current_State := Current_State + 1;
  945.  
  946.                      if End_State /= 0 then
  947.                         Add_Empty_Char (End_State, Last_Start);
  948.                      end if;
  949.  
  950.                      End_State := Current_State;
  951.  
  952.                   when '{' =>
  953.                      declare
  954.                         End_Sub          : Integer;
  955.                         Start_Regexp_Sub : State_Index;
  956.                         End_Regexp_Sub   : State_Index;
  957.                         Create_Start     : State_Index := 0;
  958.                         Create_End       : State_Index;
  959.  
  960.                      begin
  961.                         while S (J) /= '}' loop
  962.  
  963.                            --  First step : find sub pattern
  964.  
  965.                            End_Sub := J + 1;
  966.                            while S (End_Sub) /= ','
  967.                              and then S (End_Sub) /= '}'
  968.                            loop
  969.                               End_Sub := End_Sub + 1;
  970.                            end loop;
  971.  
  972.                            --  Second step : create a sub pattern
  973.  
  974.                            Create_Simple (J + 1, End_Sub - 1,
  975.                                           Start_Regexp_Sub, End_Regexp_Sub);
  976.                            J := End_Sub;
  977.  
  978.                            --  Third step : create an alternative
  979.  
  980.                            if Create_Start = 0 then
  981.                               Current_State := Current_State + 1;
  982.                               Create_Start := Current_State;
  983.                               Add_Empty_Char (Create_Start, Start_Regexp_Sub);
  984.                               Current_State := Current_State + 1;
  985.                               Create_End := Current_State;
  986.                               Add_Empty_Char (End_Regexp_Sub, Create_End);
  987.  
  988.                            else
  989.                               Current_State := Current_State + 1;
  990.                               Add_Empty_Char (Current_State, Create_Start);
  991.                               Create_Start := Current_State;
  992.                               Add_Empty_Char (Create_Start, Start_Regexp_Sub);
  993.                               Add_Empty_Char (End_Regexp_Sub, Create_End);
  994.                            end if;
  995.                         end loop;
  996.  
  997.                         if End_State /= 0 then
  998.                            Add_Empty_Char (End_State, Create_Start);
  999.                         end if;
  1000.  
  1001.                         End_State := Create_End;
  1002.                         Last_Start := Create_Start;
  1003.                      end;
  1004.  
  1005.                   when '*' =>
  1006.                      Current_State := Current_State + 1;
  1007.  
  1008.                      if End_State /= 0 then
  1009.                         Add_Empty_Char (End_State, Current_State);
  1010.                      end if;
  1011.  
  1012.                      Add_Empty_Char (Current_State, Current_State + 1);
  1013.                      Add_Empty_Char (Current_State, Current_State + 3);
  1014.                      Last_Start := Current_State;
  1015.  
  1016.                      Current_State := Current_State + 1;
  1017.  
  1018.                      for K in 0 .. Alphabet_Size loop
  1019.                         Set (Table, Current_State, K,
  1020.                              Value => Current_State + 1);
  1021.                      end loop;
  1022.  
  1023.                      Current_State := Current_State + 1;
  1024.                      Add_Empty_Char (Current_State, Current_State + 1);
  1025.  
  1026.                      Current_State := Current_State + 1;
  1027.                      Add_Empty_Char (Current_State,  Last_Start);
  1028.                      End_State := Current_State;
  1029.  
  1030.                   when others =>
  1031.                      Current_State := Current_State + 1;
  1032.  
  1033.                      if S (J) = '?' then
  1034.                         for K in 0 .. Alphabet_Size loop
  1035.                            Set (Table, Current_State, K,
  1036.                                 Value => Current_State + 1);
  1037.                         end loop;
  1038.  
  1039.                      else
  1040.                         if S (J) = '\' then
  1041.                            J := J + 1;
  1042.                         end if;
  1043.  
  1044.                         --  Create the state for the symbol S (J)
  1045.  
  1046.                         Set (Table, Current_State, Map (S (J)),
  1047.                              Value => Current_State + 1);
  1048.                      end if;
  1049.  
  1050.                      Last_Start := Current_State;
  1051.                      Current_State := Current_State + 1;
  1052.  
  1053.                      if End_State /= 0 then
  1054.                         Add_Empty_Char (End_State, Last_Start);
  1055.                      end if;
  1056.  
  1057.                      End_State := Current_State;
  1058.  
  1059.                end case;
  1060.  
  1061.                if Start_State = 0 then
  1062.                   Start_State := Last_Start;
  1063.                end if;
  1064.  
  1065.                J := J + 1;
  1066.             end loop;
  1067.          end Create_Simple;
  1068.  
  1069.       --  Start of processing for Create_Primary_Table_Glob
  1070.  
  1071.       begin
  1072.          Table.all := (others => (others => 0));
  1073.          Create_Simple (S'First, S'Last, Start_State, End_State);
  1074.          Num_States := Current_State;
  1075.       end Create_Primary_Table_Glob;
  1076.  
  1077.       ----------------------------
  1078.       -- Create_Secondary_Table --
  1079.       ----------------------------
  1080.  
  1081.       function Create_Secondary_Table
  1082.         (First_Table : Regexp_Array_Access;
  1083.          Num_States  : State_Index;
  1084.          Start_State : State_Index;
  1085.          End_State   : State_Index)
  1086.          return        Regexp
  1087.       is
  1088.          Last_Index : constant State_Index := First_Table'Last (1);
  1089.          type Meta_State is array (1 .. Last_Index) of Boolean;
  1090.  
  1091.          Table : Regexp_Array (1 .. Last_Index, 0 .. Alphabet_Size) :=
  1092.                    (others => (others => 0));
  1093.  
  1094.          Meta_States : array (1 .. Last_Index + 1) of Meta_State :=
  1095.                          (others => (others => False));
  1096.  
  1097.          Temp_State_Not_Null : Boolean;
  1098.  
  1099.          Is_Final : Boolean_Array (1 .. Last_Index) := (others => False);
  1100.  
  1101.          Current_State       : State_Index := 1;
  1102.          Nb_State            : State_Index := 1;
  1103.  
  1104.          procedure Closure
  1105.            (State : in out Meta_State;
  1106.             Item  :        State_Index);
  1107.          --  Compute the closure of the state (that is every other state which
  1108.          --  has a empty-character transition) and add it to the state
  1109.  
  1110.          -------------
  1111.          -- Closure --
  1112.          -------------
  1113.  
  1114.          procedure Closure
  1115.            (State : in out Meta_State;
  1116.             Item  : State_Index)
  1117.          is
  1118.          begin
  1119.             if State (Item) then
  1120.                return;
  1121.             end if;
  1122.  
  1123.             State (Item) := True;
  1124.  
  1125.             for Column in Alphabet_Size + 1 .. First_Table'Last (2) loop
  1126.                if First_Table (Item, Column) = 0 then
  1127.                   return;
  1128.                end if;
  1129.  
  1130.                Closure (State, First_Table (Item, Column));
  1131.             end loop;
  1132.          end Closure;
  1133.  
  1134.       --  Start of procesing for Create_Secondary_Table
  1135.  
  1136.       begin
  1137.          --  Create a new state
  1138.  
  1139.          Closure (Meta_States (Current_State), Start_State);
  1140.  
  1141.          while Current_State <= Nb_State loop
  1142.  
  1143.             --  If this new meta-state includes the primary table end state,
  1144.             --  then this meta-state will be a final state in the regexp
  1145.  
  1146.             if Meta_States (Current_State)(End_State) then
  1147.                Is_Final (Current_State) := True;
  1148.             end if;
  1149.  
  1150.             --  For every character in the regexp, calculate the possible
  1151.             --  transitions from Current_State
  1152.  
  1153.             for Column in 0 .. Alphabet_Size loop
  1154.                Meta_States (Nb_State + 1) := (others => False);
  1155.                Temp_State_Not_Null := False;
  1156.  
  1157.                for K in Meta_States (Current_State)'Range loop
  1158.                   if Meta_States (Current_State)(K)
  1159.                     and then First_Table (K, Column) /= 0
  1160.                   then
  1161.                      Closure
  1162.                        (Meta_States (Nb_State + 1), First_Table (K, Column));
  1163.                      Temp_State_Not_Null := True;
  1164.                   end if;
  1165.                end loop;
  1166.  
  1167.                --  If at least one transition existed
  1168.  
  1169.                if Temp_State_Not_Null then
  1170.  
  1171.                   --  Check if this new state corresponds to an old one
  1172.  
  1173.                   for K in 1 .. Nb_State loop
  1174.                      if Meta_States (K) = Meta_States (Nb_State + 1) then
  1175.                         Table (Current_State, Column) := K;
  1176.                         exit;
  1177.                      end if;
  1178.                   end loop;
  1179.  
  1180.                   --  If not, create a new state
  1181.  
  1182.                   if Table (Current_State, Column) = 0 then
  1183.                      Nb_State := Nb_State + 1;
  1184.                      Table (Current_State, Column) := Nb_State;
  1185.                   end if;
  1186.                end if;
  1187.             end loop;
  1188.  
  1189.             Current_State := Current_State + 1;
  1190.          end loop;
  1191.  
  1192.          --  Returns the regexp
  1193.  
  1194.          declare
  1195.             R : Regexp_Access;
  1196.  
  1197.          begin
  1198.             R := new Regexp_Value (Alphabet_Size => Alphabet_Size,
  1199.                                    Num_States    => Nb_State);
  1200.             R.Map            := Map;
  1201.             R.Is_Final       := Is_Final (1 .. Nb_State);
  1202.             R.Case_Sensitive := Case_Sensitive;
  1203.  
  1204.             for State in 1 .. Nb_State loop
  1205.                for K in 0 .. Alphabet_Size loop
  1206.                   R.States (State, K) := Table (State, K);
  1207.                end loop;
  1208.             end loop;
  1209.  
  1210.             if Debug then
  1211.                Ada.Text_IO.New_Line;
  1212.                Ada.Text_IO.Put_Line ("Secondary table : ");
  1213.                Print_Table (R.States, Nb_State, False);
  1214.             end if;
  1215.  
  1216.             return (Ada.Finalization.Controlled with R => R);
  1217.          end;
  1218.       end Create_Secondary_Table;
  1219.  
  1220.       -----------------
  1221.       -- Print_Table --
  1222.       -----------------
  1223.  
  1224.       procedure Print_Table
  1225.         (Table      : Regexp_Array;
  1226.          Num_States : State_Index;
  1227.          Is_Primary : Boolean := True)
  1228.       is
  1229.          function Reverse_Mapping (N : Column_Index) return Character;
  1230.          --  Return the character corresponding to a column in the mapping
  1231.  
  1232.          ---------------------
  1233.          -- Reverse_Mapping --
  1234.          ---------------------
  1235.  
  1236.          function Reverse_Mapping (N : Column_Index) return Character is
  1237.          begin
  1238.             for Column in Map'Range loop
  1239.                if Map (Column) = N then
  1240.                   return Column;
  1241.                end if;
  1242.             end loop;
  1243.  
  1244.             return ' ';
  1245.          end Reverse_Mapping;
  1246.  
  1247.       --  Start of processing for Print_Table
  1248.  
  1249.       begin
  1250.          --  Print the header line
  1251.  
  1252.          Ada.Text_IO.Put ("   [*]  ");
  1253.  
  1254.          for Column in 1 .. Alphabet_Size  loop
  1255.             Ada.Text_IO.Put (String'(1 .. 1 => Reverse_Mapping (Column))
  1256.                              & "   ");
  1257.          end loop;
  1258.  
  1259.          if Is_Primary then
  1260.             Ada.Text_IO.Put ("closure....");
  1261.          end if;
  1262.  
  1263.          Ada.Text_IO.New_Line;
  1264.  
  1265.          --  Print every line
  1266.  
  1267.          for State in 1 .. Num_States loop
  1268.             Ada.Text_IO.Put (State'Img);
  1269.  
  1270.             for K in 1 .. 3 - State'Img'Length loop
  1271.                Ada.Text_IO.Put (" ");
  1272.             end loop;
  1273.  
  1274.             for K in 0 .. Alphabet_Size loop
  1275.                Ada.Text_IO.Put (Table (State, K)'Img & "  ");
  1276.             end loop;
  1277.  
  1278.             for K in Alphabet_Size + 1 .. Table'Last (2) loop
  1279.                if Table (State, K) /= 0 then
  1280.                   Ada.Text_IO.Put (Table (State, K)'Img & ",");
  1281.                end if;
  1282.             end loop;
  1283.  
  1284.             Ada.Text_IO.New_Line;
  1285.          end loop;
  1286.  
  1287.       end Print_Table;
  1288.  
  1289.       ---------------------
  1290.       -- Raise_Exception --
  1291.       ---------------------
  1292.  
  1293.       procedure Raise_Exception
  1294.         (M     : String;
  1295.          Index : Integer)
  1296.       is
  1297.       begin
  1298.          Ada.Exceptions.Raise_Exception
  1299.            (Error_In_Regexp'Identity, M & " at offset " & Index'Img);
  1300.       end Raise_Exception;
  1301.  
  1302.    --  Start of processing for Compile
  1303.  
  1304.    begin
  1305.       if not Case_Sensitive then
  1306.          GNAT.Case_Util.To_Lower (S);
  1307.       end if;
  1308.  
  1309.       Create_Mapping;
  1310.  
  1311.       --  Creates the primary table
  1312.  
  1313.       declare
  1314.          Table : Regexp_Array_Access;
  1315.          Num_States  : State_Index;
  1316.          Start_State : State_Index;
  1317.          End_State   : State_Index;
  1318.          R           : Regexp;
  1319.  
  1320.       begin
  1321.          Table := new Regexp_Array (1 .. 100,
  1322.                                     0 .. Alphabet_Size + 10);
  1323.          if not Glob then
  1324.             Create_Primary_Table (Table, Num_States, Start_State, End_State);
  1325.          else
  1326.             Create_Primary_Table_Glob
  1327.               (Table, Num_States, Start_State, End_State);
  1328.          end if;
  1329.  
  1330.          if Debug then
  1331.             Print_Table (Table.all, Num_States);
  1332.             Ada.Text_IO.Put_Line ("Start_State : " & Start_State'Img);
  1333.             Ada.Text_IO.Put_Line ("End_State   : " & End_State'Img);
  1334.          end if;
  1335.  
  1336.          --  Creates the secondary table
  1337.  
  1338.          R := Create_Secondary_Table
  1339.            (Table, Num_States, Start_State, End_State);
  1340.          Free (Table);
  1341.          return R;
  1342.       end;
  1343.    end Compile;
  1344.  
  1345.    --------------
  1346.    -- Finalize --
  1347.    --------------
  1348.  
  1349.    procedure Finalize (R : in out Regexp) is
  1350.       procedure Free is new
  1351.         Unchecked_Deallocation (Regexp_Value, Regexp_Access);
  1352.  
  1353.    begin
  1354.       Free (R.R);
  1355.    end Finalize;
  1356.  
  1357.    -----------
  1358.    -- Match --
  1359.    -----------
  1360.  
  1361.    function Match (S : String; R : Regexp) return Boolean is
  1362.       Current_State : State_Index := 1;
  1363.  
  1364.    begin
  1365.       if R.R = null then
  1366.          return True;
  1367.       end if;
  1368.  
  1369.       for Char in S'Range loop
  1370.  
  1371.          if R.R.Case_Sensitive then
  1372.             Current_State := R.R.States (Current_State, R.R.Map (S (Char)));
  1373.          else
  1374.             Current_State :=
  1375.               R.R.States (Current_State,
  1376.                           R.R.Map (GNAT.Case_Util.To_Lower (S (Char))));
  1377.          end if;
  1378.  
  1379.          if Current_State = 0 then
  1380.             return False;
  1381.          end if;
  1382.  
  1383.       end loop;
  1384.  
  1385.       return R.R.Is_Final (Current_State);
  1386.    end Match;
  1387.  
  1388.    ---------
  1389.    -- Get --
  1390.    ---------
  1391.  
  1392.    function Get (Table  : Regexp_Array_Access;
  1393.                  State  : State_Index;
  1394.                  Column : Column_Index)
  1395.                 return State_Index
  1396.    is
  1397.    begin
  1398.       if State <= Table'Last (1)
  1399.         and then Column <= Table'Last (2)
  1400.       then
  1401.          return Table (State, Column);
  1402.       else
  1403.          return 0;
  1404.       end if;
  1405.    end Get;
  1406.  
  1407.    ---------
  1408.    -- Set --
  1409.    ---------
  1410.  
  1411.    procedure Set (Table  : in out Regexp_Array_Access;
  1412.                   State  : State_Index;
  1413.                   Column : Column_Index;
  1414.                   Value  : State_Index)
  1415.    is
  1416.       New_Lines   : State_Index;
  1417.       New_Columns : Column_Index;
  1418.       New_Table   : Regexp_Array_Access;
  1419.    begin
  1420.       if State <= Table'Last (1)
  1421.         and then Column <= Table'Last (2)
  1422.       then
  1423.          Table (State, Column) := Value;
  1424.       else
  1425.  
  1426.          --  Doubles the size of the table until it is big enough that
  1427.          --  (State, Column) is a valid index
  1428.          New_Lines := Table'Last (1) * (State / Table'Last (1) + 1);
  1429.          New_Columns := Table'Last (2) * (Column / Table'Last (2) + 1);
  1430.          New_Table := new Regexp_Array (Table'First (1) .. New_Lines,
  1431.                                         Table'First (2) .. New_Columns);
  1432.          New_Table.all := (others => (others => 0));
  1433.  
  1434.          if Debug then
  1435.             Ada.Text_IO.Put_Line ("Reallocating table: Lines from "
  1436.                                   & State_Index'Image (Table'Last (1)) & " to "
  1437.                                   & State_Index'Image (New_Lines));
  1438.             Ada.Text_IO.Put_Line ("   and columns from "
  1439.                                   & Column_Index'Image (Table'Last (2))
  1440.                                   & " to "
  1441.                                   & Column_Index'Image (New_Columns));
  1442.          end if;
  1443.  
  1444.          for J in Table'Range (1) loop
  1445.             for K in Table'Range (2) loop
  1446.                New_Table (J, K) := Table (J, K);
  1447.             end loop;
  1448.          end loop;
  1449.  
  1450.  
  1451.          Free (Table);
  1452.          Table := New_Table;
  1453.          Table (State, Column) := Value;
  1454.       end if;
  1455.    end Set;
  1456.  
  1457. end GNAT.Regexp;
  1458.  
  1459.  
  1460.