1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- G N A T . R E G E X P --
11 -- Copyright (C) 1999-2001 Ada Core Technologies, Inc. --
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. --
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. --
31 -- GNAT is maintained by Ada Core Technologies Inc (http://www.gnat.com). --
33 ------------------------------------------------------------------------------
36 with Unchecked_Deallocation;
40 package body GNAT.Regexp is
42 Open_Paren : constant Character := '(';
43 Close_Paren : constant Character := ')';
44 Open_Bracket : constant Character := '[';
45 Close_Bracket : constant Character := ']';
47 type State_Index is new Natural;
48 type Column_Index is new Natural;
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
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.
60 type Mapping is array (Character'Range) of Column_Index;
61 -- Mapping between characters and column in the Regexp_Array
63 type Boolean_Array is array (State_Index range <>) of Boolean;
66 (Alphabet_Size : Column_Index;
67 Num_States : State_Index) is
70 States : Regexp_Array (1 .. Num_States, 0 .. Alphabet_Size);
71 Is_Final : Boolean_Array (1 .. Num_States);
72 Case_Sensitive : Boolean;
74 -- Deterministic finite-state machine
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;
80 -----------------------
81 -- Local Subprograms --
82 -----------------------
85 (Table : in out Regexp_Array_Access;
87 Column : Column_Index;
89 -- Sets a value in the table. If the table is too small, reallocate it
90 -- dynamically so that (State, Column) is a valid index in it.
93 (Table : Regexp_Array_Access;
95 Column : Column_Index)
97 -- Returns the value in the table at (State, Column).
98 -- If this index does not exist in the table, returns 0
100 procedure Free is new Unchecked_Deallocation
101 (Regexp_Array, Regexp_Array_Access);
107 procedure Adjust (R : in out Regexp) is
111 Tmp := new Regexp_Value (Alphabet_Size => R.R.Alphabet_Size,
112 Num_States => R.R.Num_States);
123 Glob : Boolean := False;
124 Case_Sensitive : Boolean := True)
127 S : String := Pattern;
128 -- The pattern which is really compiled (when the pattern is case
129 -- insensitive, we convert this string to lower-cases
131 Map : Mapping := (others => 0);
132 -- Mapping between characters and columns in the tables
134 Alphabet_Size : Column_Index := 0;
135 -- Number of significant characters in the regular expression.
136 -- This total does not include special operators, such as *, (, ...
138 procedure Create_Mapping;
139 -- Creates a mapping between characters in the regexp and columns
140 -- in the tables representing the regexp. Test that the regexp is
141 -- well-formed Modifies Alphabet_Size and Map
143 procedure Create_Primary_Table
144 (Table : out Regexp_Array_Access;
145 Num_States : out State_Index;
146 Start_State : out State_Index;
147 End_State : out State_Index);
148 -- Creates the first version of the regexp (this is a non determinist
149 -- finite state machine, which is unadapted for a fast pattern
150 -- matching algorithm). We use a recursive algorithm to process the
151 -- parenthesis sub-expressions.
153 -- Table : at the end of the procedure : Column 0 is for any character
154 -- ('.') and the last columns are for no character (closure)
155 -- Num_States is set to the number of states in the table
156 -- Start_State is the number of the starting state in the regexp
157 -- End_State is the number of the final state when the regexp matches
159 procedure Create_Primary_Table_Glob
160 (Table : out Regexp_Array_Access;
161 Num_States : out State_Index;
162 Start_State : out State_Index;
163 End_State : out State_Index);
164 -- Same function as above, but it deals with the second possible
165 -- grammar for 'globbing pattern', which is a kind of subset of the
166 -- whole regular expression grammar.
168 function Create_Secondary_Table
169 (First_Table : Regexp_Array_Access;
170 Num_States : State_Index;
171 Start_State : State_Index;
172 End_State : State_Index)
174 -- Creates the definitive table representing the regular expression
175 -- This is actually a transformation of the primary table First_Table,
176 -- where every state is grouped with the states in its 'no-character'
177 -- columns. The transitions between the new states are then recalculated
178 -- and if necessary some new states are created.
180 -- Note that the resulting finite-state machine is not optimized in
181 -- terms of the number of states : it would be more time-consuming to
182 -- add a third pass to reduce the number of states in the machine, with
183 -- no speed improvement...
185 procedure Raise_Exception
188 pragma No_Return (Raise_Exception);
189 -- Raise an exception, indicating an error at character Index in S.
191 procedure Print_Table
192 (Table : Regexp_Array;
193 Num_States : State_Index;
194 Is_Primary : Boolean := True);
195 -- Print a table for debugging purposes
201 procedure Create_Mapping is
203 procedure Add_In_Map (C : Character);
204 -- Add a character in the mapping, if it is not already defined
210 procedure Add_In_Map (C : Character) is
213 Alphabet_Size := Alphabet_Size + 1;
214 Map (C) := Alphabet_Size;
218 J : Integer := S'First;
219 Parenthesis_Level : Integer := 0;
220 Curly_Level : Integer := 0;
222 -- Start of processing for Create_Mapping
225 while J <= S'Last loop
234 if S (J) = ']' or S (J) = '-' then
238 -- The first character never has a special meaning
243 ("Ran out of characters while parsing ", J);
246 exit when S (J) = Close_Bracket;
249 and then S (J + 1) /= Close_Bracket
252 Start : constant Integer := J - 1;
261 for Char in S (Start) .. S (J) loop
276 -- A close bracket must follow a open_bracket,
277 -- and cannot be found alone on the line
279 when Close_Bracket =>
281 ("Incorrect character ']' in regular expression", J);
289 -- \ not allowed at the end of the regexp
292 ("Incorrect character '\' in regular expression", J);
297 Parenthesis_Level := Parenthesis_Level + 1;
299 Add_In_Map (Open_Paren);
304 Parenthesis_Level := Parenthesis_Level - 1;
306 if Parenthesis_Level < 0 then
308 ("')' is not associated with '(' in regular "
312 if S (J - 1) = Open_Paren then
314 ("Empty parenthesis not allowed in regular "
319 Add_In_Map (Close_Paren);
331 Curly_Level := Curly_Level + 1;
338 Curly_Level := Curly_Level - 1;
345 ("'*', '+', '?' and '|' operators can not be in "
346 & "first position in regular expression", J);
354 -- These operators must apply to a sub-expression,
355 -- and cannot be found at the beginning of the line
358 ("'*', '+', '?' and '|' operators can not be in "
359 & "first position in regular expression", J);
373 -- A closing parenthesis must follow an open parenthesis
375 if Parenthesis_Level /= 0 then
377 ("'(' must always be associated with a ')'", J);
380 if Curly_Level /= 0 then
382 ("'{' must always be associated with a '}'", J);
386 --------------------------
387 -- Create_Primary_Table --
388 --------------------------
390 procedure Create_Primary_Table
391 (Table : out Regexp_Array_Access;
392 Num_States : out State_Index;
393 Start_State : out State_Index;
394 End_State : out State_Index)
396 Empty_Char : constant Column_Index := Alphabet_Size + 1;
398 Current_State : State_Index := 0;
399 -- Index of the last created state
401 procedure Add_Empty_Char
402 (State : State_Index;
403 To_State : State_Index);
404 -- Add a empty-character transition from State to To_State.
406 procedure Create_Repetition
407 (Repetition : Character;
408 Start_Prev : State_Index;
409 End_Prev : State_Index;
410 New_Start : out State_Index;
411 New_End : in out State_Index);
412 -- Create the table in case we have a '*', '+' or '?'.
413 -- Start_Prev .. End_Prev should indicate respectively the start and
414 -- end index of the previous expression, to which '*', '+' or '?' is
417 procedure Create_Simple
418 (Start_Index : Integer;
420 Start_State : out State_Index;
421 End_State : out State_Index);
422 -- Fill the table for the regexp Simple.
423 -- This is the recursive procedure called to handle () expressions
424 -- If End_State = 0, then the call to Create_Simple creates an
425 -- independent regexp, not a concatenation
426 -- Start_Index .. End_Index is the starting index in the string S.
428 -- Warning: it may look like we are creating too many empty-string
429 -- transitions, but they are needed to get the correct regexp.
430 -- The table is filled as follow ( s means start-state, e means
433 -- regexp state_num | a b * empty_string
434 -- ------- ---------------------------------------
438 -- ab 1 (s) | 2 - - -
455 -- (a) 1 (s) | 2 - - -
471 function Next_Sub_Expression
472 (Start_Index : Integer;
475 -- Returns the index of the last character of the next sub-expression
476 -- in Simple. Index can not be greater than End_Index
482 procedure Add_Empty_Char
483 (State : State_Index;
484 To_State : State_Index)
486 J : Column_Index := Empty_Char;
489 while Get (Table, State, J) /= 0 loop
493 Set (Table, State, J, To_State);
496 -----------------------
497 -- Create_Repetition --
498 -----------------------
500 procedure Create_Repetition
501 (Repetition : Character;
502 Start_Prev : State_Index;
503 End_Prev : State_Index;
504 New_Start : out State_Index;
505 New_End : in out State_Index)
508 New_Start := Current_State + 1;
511 Add_Empty_Char (New_End, New_Start);
514 Current_State := Current_State + 2;
515 New_End := Current_State;
517 Add_Empty_Char (End_Prev, New_End);
518 Add_Empty_Char (New_Start, Start_Prev);
520 if Repetition /= '+' then
521 Add_Empty_Char (New_Start, New_End);
524 if Repetition /= '?' then
525 Add_Empty_Char (New_End, New_Start);
527 end Create_Repetition;
533 procedure Create_Simple
534 (Start_Index : Integer;
536 Start_State : out State_Index;
537 End_State : out State_Index)
539 J : Integer := Start_Index;
540 Last_Start : State_Index := 0;
545 while J <= End_Index loop
549 J_Start : Integer := J + 1;
550 Next_Start : State_Index;
551 Next_End : State_Index;
554 J := Next_Sub_Expression (J, End_Index);
555 Create_Simple (J_Start, J - 1, Next_Start, Next_End);
558 and then (S (J + 1) = '*' or else
559 S (J + 1) = '+' or else
571 Last_Start := Next_Start;
573 if End_State /= 0 then
574 Add_Empty_Char (End_State, Last_Start);
577 End_State := Next_End;
583 Start_Prev : State_Index := Start_State;
584 End_Prev : State_Index := End_State;
585 Start_Next : State_Index := 0;
586 End_Next : State_Index := 0;
587 Start_J : Integer := J + 1;
590 J := Next_Sub_Expression (J, End_Index);
592 -- Create a new state for the start of the alternative
594 Current_State := Current_State + 1;
595 Last_Start := Current_State;
596 Start_State := Last_Start;
598 -- Create the tree for the second part of alternative
600 Create_Simple (Start_J, J, Start_Next, End_Next);
602 -- Create the end state
604 Add_Empty_Char (Last_Start, Start_Next);
605 Add_Empty_Char (Last_Start, Start_Prev);
606 Current_State := Current_State + 1;
607 End_State := Current_State;
608 Add_Empty_Char (End_Prev, End_State);
609 Add_Empty_Char (End_Next, End_State);
613 Current_State := Current_State + 1;
616 Next_State : State_Index := Current_State + 1;
626 for Column in 0 .. Alphabet_Size loop
627 Set (Table, Current_State, Column,
628 Value => Current_State + 1);
632 -- Automatically add the first character
634 if S (J) = '-' or S (J) = ']' then
635 Set (Table, Current_State, Map (S (J)),
636 Value => Next_State);
640 -- Loop till closing bracket found
643 exit when S (J) = Close_Bracket;
646 and then S (J + 1) /= ']'
649 Start : constant Integer := J - 1;
658 for Char in S (Start) .. S (J) loop
659 Set (Table, Current_State, Map (Char),
660 Value => Next_State);
669 Set (Table, Current_State, Map (S (J)),
670 Value => Next_State);
676 Current_State := Current_State + 1;
678 -- If the next symbol is a special symbol
681 and then (S (J + 1) = '*' or else
682 S (J + 1) = '+' or else
694 Last_Start := Current_State - 1;
696 if End_State /= 0 then
697 Add_Empty_Char (End_State, Last_Start);
700 End_State := Current_State;
703 when '*' | '+' | '?' | Close_Paren | Close_Bracket =>
705 ("Incorrect character in regular expression :", J);
708 Current_State := Current_State + 1;
710 -- Create the state for the symbol S (J)
713 for K in 0 .. Alphabet_Size loop
714 Set (Table, Current_State, K,
715 Value => Current_State + 1);
723 Set (Table, Current_State, Map (S (J)),
724 Value => Current_State + 1);
727 Current_State := Current_State + 1;
729 -- If the next symbol is a special symbol
732 and then (S (J + 1) = '*' or else
733 S (J + 1) = '+' or else
745 Last_Start := Current_State - 1;
747 if End_State /= 0 then
748 Add_Empty_Char (End_State, Last_Start);
751 End_State := Current_State;
756 if Start_State = 0 then
757 Start_State := Last_Start;
764 -------------------------
765 -- Next_Sub_Expression --
766 -------------------------
768 function Next_Sub_Expression
769 (Start_Index : Integer;
773 J : Integer := Start_Index;
774 Start_On_Alter : Boolean := False;
778 Start_On_Alter := True;
782 exit when J = End_Index;
792 exit when S (J) = Close_Bracket;
800 J := Next_Sub_Expression (J, End_Index);
806 if Start_On_Alter then
816 end Next_Sub_Expression;
818 -- Start of Create_Primary_Table
821 Table.all := (others => (others => 0));
822 Create_Simple (S'First, S'Last, Start_State, End_State);
823 Num_States := Current_State;
824 end Create_Primary_Table;
826 -------------------------------
827 -- Create_Primary_Table_Glob --
828 -------------------------------
830 procedure Create_Primary_Table_Glob
831 (Table : out Regexp_Array_Access;
832 Num_States : out State_Index;
833 Start_State : out State_Index;
834 End_State : out State_Index)
836 Empty_Char : constant Column_Index := Alphabet_Size + 1;
838 Current_State : State_Index := 0;
839 -- Index of the last created state
841 procedure Add_Empty_Char
842 (State : State_Index;
843 To_State : State_Index);
844 -- Add a empty-character transition from State to To_State.
846 procedure Create_Simple
847 (Start_Index : Integer;
849 Start_State : out State_Index;
850 End_State : out State_Index);
851 -- Fill the table for the S (Start_Index .. End_Index).
852 -- This is the recursive procedure called to handle () expressions
858 procedure Add_Empty_Char
859 (State : State_Index;
860 To_State : State_Index)
862 J : Column_Index := Empty_Char;
865 while Get (Table, State, J) /= 0 loop
869 Set (Table, State, J,
877 procedure Create_Simple
878 (Start_Index : Integer;
880 Start_State : out State_Index;
881 End_State : out State_Index)
883 J : Integer := Start_Index;
884 Last_Start : State_Index := 0;
890 while J <= End_Index loop
894 Current_State := Current_State + 1;
897 Next_State : State_Index := Current_State + 1;
906 for Column in 0 .. Alphabet_Size loop
907 Set (Table, Current_State, Column,
908 Value => Current_State + 1);
912 -- Automatically add the first character
914 if S (J) = '-' or S (J) = ']' then
915 Set (Table, Current_State, Map (S (J)),
916 Value => Current_State);
920 -- Loop till closing bracket found
923 exit when S (J) = Close_Bracket;
926 and then S (J + 1) /= ']'
929 Start : constant Integer := J - 1;
937 for Char in S (Start) .. S (J) loop
938 Set (Table, Current_State, Map (Char),
939 Value => Next_State);
948 Set (Table, Current_State, Map (S (J)),
949 Value => Next_State);
955 Last_Start := Current_State;
956 Current_State := Current_State + 1;
958 if End_State /= 0 then
959 Add_Empty_Char (End_State, Last_Start);
962 End_State := Current_State;
967 Start_Regexp_Sub : State_Index;
968 End_Regexp_Sub : State_Index;
969 Create_Start : State_Index := 0;
971 Create_End : State_Index := 0;
972 -- Initialized to avoid junk warning
975 while S (J) /= '}' loop
977 -- First step : find sub pattern
980 while S (End_Sub) /= ','
981 and then S (End_Sub) /= '}'
983 End_Sub := End_Sub + 1;
986 -- Second step : create a sub pattern
996 -- Third step : create an alternative
998 if Create_Start = 0 then
999 Current_State := Current_State + 1;
1000 Create_Start := Current_State;
1001 Add_Empty_Char (Create_Start, Start_Regexp_Sub);
1002 Current_State := Current_State + 1;
1003 Create_End := Current_State;
1004 Add_Empty_Char (End_Regexp_Sub, Create_End);
1007 Current_State := Current_State + 1;
1008 Add_Empty_Char (Current_State, Create_Start);
1009 Create_Start := Current_State;
1010 Add_Empty_Char (Create_Start, Start_Regexp_Sub);
1011 Add_Empty_Char (End_Regexp_Sub, Create_End);
1015 if End_State /= 0 then
1016 Add_Empty_Char (End_State, Create_Start);
1019 End_State := Create_End;
1020 Last_Start := Create_Start;
1024 Current_State := Current_State + 1;
1026 if End_State /= 0 then
1027 Add_Empty_Char (End_State, Current_State);
1030 Add_Empty_Char (Current_State, Current_State + 1);
1031 Add_Empty_Char (Current_State, Current_State + 3);
1032 Last_Start := Current_State;
1034 Current_State := Current_State + 1;
1036 for K in 0 .. Alphabet_Size loop
1037 Set (Table, Current_State, K,
1038 Value => Current_State + 1);
1041 Current_State := Current_State + 1;
1042 Add_Empty_Char (Current_State, Current_State + 1);
1044 Current_State := Current_State + 1;
1045 Add_Empty_Char (Current_State, Last_Start);
1046 End_State := Current_State;
1049 Current_State := Current_State + 1;
1052 for K in 0 .. Alphabet_Size loop
1053 Set (Table, Current_State, K,
1054 Value => Current_State + 1);
1062 -- Create the state for the symbol S (J)
1064 Set (Table, Current_State, Map (S (J)),
1065 Value => Current_State + 1);
1068 Last_Start := Current_State;
1069 Current_State := Current_State + 1;
1071 if End_State /= 0 then
1072 Add_Empty_Char (End_State, Last_Start);
1075 End_State := Current_State;
1079 if Start_State = 0 then
1080 Start_State := Last_Start;
1087 -- Start of processing for Create_Primary_Table_Glob
1090 Table.all := (others => (others => 0));
1091 Create_Simple (S'First, S'Last, Start_State, End_State);
1092 Num_States := Current_State;
1093 end Create_Primary_Table_Glob;
1095 ----------------------------
1096 -- Create_Secondary_Table --
1097 ----------------------------
1099 function Create_Secondary_Table
1100 (First_Table : Regexp_Array_Access;
1101 Num_States : State_Index;
1102 Start_State : State_Index;
1103 End_State : State_Index)
1106 Last_Index : constant State_Index := First_Table'Last (1);
1107 type Meta_State is array (1 .. Last_Index) of Boolean;
1109 Table : Regexp_Array (1 .. Last_Index, 0 .. Alphabet_Size) :=
1110 (others => (others => 0));
1112 Meta_States : array (1 .. Last_Index + 1) of Meta_State :=
1113 (others => (others => False));
1115 Temp_State_Not_Null : Boolean;
1117 Is_Final : Boolean_Array (1 .. Last_Index) := (others => False);
1119 Current_State : State_Index := 1;
1120 Nb_State : State_Index := 1;
1123 (State : in out Meta_State;
1124 Item : State_Index);
1125 -- Compute the closure of the state (that is every other state which
1126 -- has a empty-character transition) and add it to the state
1133 (State : in out Meta_State;
1137 if State (Item) then
1141 State (Item) := True;
1143 for Column in Alphabet_Size + 1 .. First_Table'Last (2) loop
1144 if First_Table (Item, Column) = 0 then
1148 Closure (State, First_Table (Item, Column));
1152 -- Start of procesing for Create_Secondary_Table
1155 -- Create a new state
1157 Closure (Meta_States (Current_State), Start_State);
1159 while Current_State <= Nb_State loop
1161 -- If this new meta-state includes the primary table end state,
1162 -- then this meta-state will be a final state in the regexp
1164 if Meta_States (Current_State)(End_State) then
1165 Is_Final (Current_State) := True;
1168 -- For every character in the regexp, calculate the possible
1169 -- transitions from Current_State
1171 for Column in 0 .. Alphabet_Size loop
1172 Meta_States (Nb_State + 1) := (others => False);
1173 Temp_State_Not_Null := False;
1175 for K in Meta_States (Current_State)'Range loop
1176 if Meta_States (Current_State)(K)
1177 and then First_Table (K, Column) /= 0
1180 (Meta_States (Nb_State + 1), First_Table (K, Column));
1181 Temp_State_Not_Null := True;
1185 -- If at least one transition existed
1187 if Temp_State_Not_Null then
1189 -- Check if this new state corresponds to an old one
1191 for K in 1 .. Nb_State loop
1192 if Meta_States (K) = Meta_States (Nb_State + 1) then
1193 Table (Current_State, Column) := K;
1198 -- If not, create a new state
1200 if Table (Current_State, Column) = 0 then
1201 Nb_State := Nb_State + 1;
1202 Table (Current_State, Column) := Nb_State;
1207 Current_State := Current_State + 1;
1210 -- Returns the regexp
1216 R := new Regexp_Value (Alphabet_Size => Alphabet_Size,
1217 Num_States => Nb_State);
1219 R.Is_Final := Is_Final (1 .. Nb_State);
1220 R.Case_Sensitive := Case_Sensitive;
1222 for State in 1 .. Nb_State loop
1223 for K in 0 .. Alphabet_Size loop
1224 R.States (State, K) := Table (State, K);
1229 Ada.Text_IO.New_Line;
1230 Ada.Text_IO.Put_Line ("Secondary table : ");
1231 Print_Table (R.States, Nb_State, False);
1234 return (Ada.Finalization.Controlled with R => R);
1236 end Create_Secondary_Table;
1242 procedure Print_Table
1243 (Table : Regexp_Array;
1244 Num_States : State_Index;
1245 Is_Primary : Boolean := True)
1247 function Reverse_Mapping (N : Column_Index) return Character;
1248 -- Return the character corresponding to a column in the mapping
1250 ---------------------
1251 -- Reverse_Mapping --
1252 ---------------------
1254 function Reverse_Mapping (N : Column_Index) return Character is
1256 for Column in Map'Range loop
1257 if Map (Column) = N then
1263 end Reverse_Mapping;
1265 -- Start of processing for Print_Table
1268 -- Print the header line
1270 Ada.Text_IO.Put (" [*] ");
1272 for Column in 1 .. Alphabet_Size loop
1273 Ada.Text_IO.Put (String'(1 .. 1 => Reverse_Mapping (Column))
1278 Ada.Text_IO.Put ("closure....");
1281 Ada.Text_IO.New_Line;
1285 for State in 1 .. Num_States loop
1286 Ada.Text_IO.Put (State'Img);
1288 for K in 1 .. 3 - State'Img'Length loop
1289 Ada.Text_IO.Put (" ");
1292 for K in 0 .. Alphabet_Size loop
1293 Ada.Text_IO.Put (Table (State, K)'Img & " ");
1296 for K in Alphabet_Size + 1 .. Table'Last (2) loop
1297 if Table (State, K) /= 0 then
1298 Ada.Text_IO.Put (Table (State, K)'Img & ",");
1302 Ada.Text_IO.New_Line;
1307 ---------------------
1308 -- Raise_Exception --
1309 ---------------------
1311 procedure Raise_Exception
1316 Ada.Exceptions.Raise_Exception
1317 (Error_In_Regexp'Identity, M & " at offset " & Index'Img);
1318 end Raise_Exception;
1320 -- Start of processing for Compile
1323 if not Case_Sensitive then
1324 GNAT.Case_Util.To_Lower (S);
1329 -- Creates the primary table
1332 Table : Regexp_Array_Access;
1333 Num_States : State_Index;
1334 Start_State : State_Index;
1335 End_State : State_Index;
1339 Table := new Regexp_Array (1 .. 100,
1340 0 .. Alphabet_Size + 10);
1342 Create_Primary_Table (Table, Num_States, Start_State, End_State);
1344 Create_Primary_Table_Glob
1345 (Table, Num_States, Start_State, End_State);
1349 Print_Table (Table.all, Num_States);
1350 Ada.Text_IO.Put_Line ("Start_State : " & Start_State'Img);
1351 Ada.Text_IO.Put_Line ("End_State : " & End_State'Img);
1354 -- Creates the secondary table
1356 R := Create_Secondary_Table
1357 (Table, Num_States, Start_State, End_State);
1367 procedure Finalize (R : in out Regexp) is
1368 procedure Free is new
1369 Unchecked_Deallocation (Regexp_Value, Regexp_Access);
1380 (Table : Regexp_Array_Access;
1381 State : State_Index;
1382 Column : Column_Index)
1386 if State <= Table'Last (1)
1387 and then Column <= Table'Last (2)
1389 return Table (State, Column);
1399 function Match (S : String; R : Regexp) return Boolean is
1400 Current_State : State_Index := 1;
1404 raise Constraint_Error;
1407 for Char in S'Range loop
1409 if R.R.Case_Sensitive then
1410 Current_State := R.R.States (Current_State, R.R.Map (S (Char)));
1413 R.R.States (Current_State,
1414 R.R.Map (GNAT.Case_Util.To_Lower (S (Char))));
1417 if Current_State = 0 then
1423 return R.R.Is_Final (Current_State);
1431 (Table : in out Regexp_Array_Access;
1432 State : State_Index;
1433 Column : Column_Index;
1434 Value : State_Index)
1436 New_Lines : State_Index;
1437 New_Columns : Column_Index;
1438 New_Table : Regexp_Array_Access;
1441 if State <= Table'Last (1)
1442 and then Column <= Table'Last (2)
1444 Table (State, Column) := Value;
1446 -- Doubles the size of the table until it is big enough that
1447 -- (State, Column) is a valid index
1449 New_Lines := Table'Last (1) * (State / Table'Last (1) + 1);
1450 New_Columns := Table'Last (2) * (Column / Table'Last (2) + 1);
1451 New_Table := new Regexp_Array (Table'First (1) .. New_Lines,
1452 Table'First (2) .. New_Columns);
1453 New_Table.all := (others => (others => 0));
1456 Ada.Text_IO.Put_Line ("Reallocating table: Lines from "
1457 & State_Index'Image (Table'Last (1)) & " to "
1458 & State_Index'Image (New_Lines));
1459 Ada.Text_IO.Put_Line (" and columns from "
1460 & Column_Index'Image (Table'Last (2))
1462 & Column_Index'Image (New_Columns));
1465 for J in Table'Range (1) loop
1466 for K in Table'Range (2) loop
1467 New_Table (J, K) := Table (J, K);
1473 Table (State, Column) := Value;