OSDN Git Service

Add Fariborz to my last change.
[pf3gnuchains/gcc-fork.git] / gcc / ada / g-spipat.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT LIBRARY COMPONENTS                          --
4 --                                                                          --
5 --                G N A T . S P I T B O L . P A T T E R N S                 --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --           Copyright (C) 1998-2003, Ada Core Technologies, Inc.           --
10 --                                                                          --
11 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
12 -- terms of the  GNU General Public License as published  by the Free Soft- --
13 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
17 -- for  more details.  You should have  received  a copy of the GNU General --
18 -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
19 -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
20 -- MA 02111-1307, USA.                                                      --
21 --                                                                          --
22 -- As a special exception,  if other files  instantiate  generics from this --
23 -- unit, or you link  this unit with other files  to produce an executable, --
24 -- this  unit  does not  by itself cause  the resulting  executable  to  be --
25 -- covered  by the  GNU  General  Public  License.  This exception does not --
26 -- however invalidate  any other reasons why  the executable file  might be --
27 -- covered by the  GNU Public License.                                      --
28 --                                                                          --
29 -- GNAT was originally developed  by the GNAT team at  New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
31 --                                                                          --
32 ------------------------------------------------------------------------------
33
34 --  Note: the data structures and general approach used in this implementation
35 --  are derived from the original MINIMAL sources for SPITBOL. The code is not
36 --  a direct translation, but the approach is followed closely. In particular,
37 --  we use the one stack approach developed in the SPITBOL implementation.
38
39 with Ada.Exceptions;            use Ada.Exceptions;
40 with Ada.Strings.Maps;          use Ada.Strings.Maps;
41 with Ada.Strings.Unbounded.Aux; use Ada.Strings.Unbounded.Aux;
42
43 with GNAT.Debug_Utilities;      use GNAT.Debug_Utilities;
44
45 with System;                    use System;
46
47 with Unchecked_Conversion;
48 with Unchecked_Deallocation;
49
50 package body GNAT.Spitbol.Patterns is
51
52    ------------------------
53    -- Internal Debugging --
54    ------------------------
55
56    Internal_Debug : constant Boolean := False;
57    --  Set this flag to True to activate some built-in debugging traceback
58    --  These are all lines output with PutD and Put_LineD.
59
60    procedure New_LineD;
61    pragma Inline (New_LineD);
62    --  Output new blank line with New_Line if Internal_Debug is True
63
64    procedure PutD (Str : String);
65    pragma Inline (PutD);
66    --  Output string with Put if Internal_Debug is True
67
68    procedure Put_LineD (Str : String);
69    pragma Inline (Put_LineD);
70    --  Output string with Put_Line if Internal_Debug is True
71
72    -----------------------------
73    -- Local Type Declarations --
74    -----------------------------
75
76    subtype String_Ptr is Ada.Strings.Unbounded.String_Access;
77    subtype File_Ptr   is Ada.Text_IO.File_Access;
78
79    function To_Address is new Unchecked_Conversion (PE_Ptr, Address);
80    --  Used only for debugging output purposes
81
82    subtype AFC is Ada.Finalization.Controlled;
83
84    N : constant PE_Ptr := null;
85    --  Shorthand used to initialize Copy fields to null
86
87    type Natural_Ptr   is access all Natural;
88    type Pattern_Ptr   is access all Pattern;
89
90    --------------------------------------------------
91    -- Description of Algorithm and Data Structures --
92    --------------------------------------------------
93
94    --  A pattern structure is represented as a linked graph of nodes
95    --  with the following structure:
96
97    --      +------------------------------------+
98    --      I                Pcode               I
99    --      +------------------------------------+
100    --      I                Index               I
101    --      +------------------------------------+
102    --      I                Pthen               I
103    --      +------------------------------------+
104    --      I             parameter(s)           I
105    --      +------------------------------------+
106
107    --     Pcode is a code value indicating the type of the patterm node. This
108    --     code is used both as the discriminant value for the record, and as
109    --     the case index in the main match routine that branches to the proper
110    --     match code for the given element.
111
112    --     Index is a serial index number. The use of these serial index
113    --     numbers is described in a separate section.
114
115    --     Pthen is a pointer to the successor node, i.e the node to be matched
116    --     if the attempt to match the node succeeds. If this is the last node
117    --     of the pattern to be matched, then Pthen points to a dummy node
118    --     of kind PC_EOP (end of pattern), which initiales pattern exit.
119
120    --     The parameter or parameters are present for certain node types,
121    --     and the type varies with the pattern code.
122
123    type Pattern_Code is (
124       PC_Arb_Y,
125       PC_Assign,
126       PC_Bal,
127       PC_BreakX_X,
128       PC_Cancel,
129       PC_EOP,
130       PC_Fail,
131       PC_Fence,
132       PC_Fence_X,
133       PC_Fence_Y,
134       PC_R_Enter,
135       PC_R_Remove,
136       PC_R_Restore,
137       PC_Rest,
138       PC_Succeed,
139       PC_Unanchored,
140
141       PC_Alt,
142       PC_Arb_X,
143       PC_Arbno_S,
144       PC_Arbno_X,
145
146       PC_Rpat,
147
148       PC_Pred_Func,
149
150       PC_Assign_Imm,
151       PC_Assign_OnM,
152       PC_Any_VP,
153       PC_Break_VP,
154       PC_BreakX_VP,
155       PC_NotAny_VP,
156       PC_NSpan_VP,
157       PC_Span_VP,
158       PC_String_VP,
159
160       PC_Write_Imm,
161       PC_Write_OnM,
162
163       PC_Null,
164       PC_String,
165
166       PC_String_2,
167       PC_String_3,
168       PC_String_4,
169       PC_String_5,
170       PC_String_6,
171
172       PC_Setcur,
173
174       PC_Any_CH,
175       PC_Break_CH,
176       PC_BreakX_CH,
177       PC_Char,
178       PC_NotAny_CH,
179       PC_NSpan_CH,
180       PC_Span_CH,
181
182       PC_Any_CS,
183       PC_Break_CS,
184       PC_BreakX_CS,
185       PC_NotAny_CS,
186       PC_NSpan_CS,
187       PC_Span_CS,
188
189       PC_Arbno_Y,
190       PC_Len_Nat,
191       PC_Pos_Nat,
192       PC_RPos_Nat,
193       PC_RTab_Nat,
194       PC_Tab_Nat,
195
196       PC_Pos_NF,
197       PC_Len_NF,
198       PC_RPos_NF,
199       PC_RTab_NF,
200       PC_Tab_NF,
201
202       PC_Pos_NP,
203       PC_Len_NP,
204       PC_RPos_NP,
205       PC_RTab_NP,
206       PC_Tab_NP,
207
208       PC_Any_VF,
209       PC_Break_VF,
210       PC_BreakX_VF,
211       PC_NotAny_VF,
212       PC_NSpan_VF,
213       PC_Span_VF,
214       PC_String_VF);
215
216    type IndexT is range 0 .. +(2 **15 - 1);
217
218    type PE (Pcode : Pattern_Code) is record
219
220       Index : IndexT;
221       --  Serial index number of pattern element within pattern.
222
223       Pthen : PE_Ptr;
224       --  Successor element, to be matched after this one
225
226       case Pcode is
227
228          when PC_Arb_Y      |
229               PC_Assign     |
230               PC_Bal        |
231               PC_BreakX_X   |
232               PC_Cancel     |
233               PC_EOP        |
234               PC_Fail       |
235               PC_Fence      |
236               PC_Fence_X    |
237               PC_Fence_Y    |
238               PC_Null       |
239               PC_R_Enter    |
240               PC_R_Remove   |
241               PC_R_Restore  |
242               PC_Rest       |
243               PC_Succeed    |
244               PC_Unanchored => null;
245
246          when PC_Alt        |
247               PC_Arb_X      |
248               PC_Arbno_S    |
249               PC_Arbno_X    => Alt  : PE_Ptr;
250
251          when PC_Rpat       => PP   : Pattern_Ptr;
252
253          when PC_Pred_Func  => BF   : Boolean_Func;
254
255          when PC_Assign_Imm |
256               PC_Assign_OnM |
257               PC_Any_VP     |
258               PC_Break_VP   |
259               PC_BreakX_VP  |
260               PC_NotAny_VP  |
261               PC_NSpan_VP   |
262               PC_Span_VP    |
263               PC_String_VP  => VP   : VString_Ptr;
264
265          when PC_Write_Imm  |
266               PC_Write_OnM  => FP   : File_Ptr;
267
268          when PC_String     => Str  : String_Ptr;
269
270          when PC_String_2   => Str2 : String (1 .. 2);
271
272          when PC_String_3   => Str3 : String (1 .. 3);
273
274          when PC_String_4   => Str4 : String (1 .. 4);
275
276          when PC_String_5   => Str5 : String (1 .. 5);
277
278          when PC_String_6   => Str6 : String (1 .. 6);
279
280          when PC_Setcur     => Var  : Natural_Ptr;
281
282          when PC_Any_CH     |
283               PC_Break_CH   |
284               PC_BreakX_CH  |
285               PC_Char       |
286               PC_NotAny_CH  |
287               PC_NSpan_CH   |
288               PC_Span_CH    => Char : Character;
289
290          when PC_Any_CS     |
291               PC_Break_CS   |
292               PC_BreakX_CS  |
293               PC_NotAny_CS  |
294               PC_NSpan_CS   |
295               PC_Span_CS    => CS   : Character_Set;
296
297          when PC_Arbno_Y    |
298               PC_Len_Nat    |
299               PC_Pos_Nat    |
300               PC_RPos_Nat   |
301               PC_RTab_Nat   |
302               PC_Tab_Nat    => Nat  : Natural;
303
304          when PC_Pos_NF     |
305               PC_Len_NF     |
306               PC_RPos_NF    |
307               PC_RTab_NF    |
308               PC_Tab_NF     => NF   : Natural_Func;
309
310          when PC_Pos_NP     |
311               PC_Len_NP     |
312               PC_RPos_NP    |
313               PC_RTab_NP    |
314               PC_Tab_NP     => NP   : Natural_Ptr;
315
316          when PC_Any_VF     |
317               PC_Break_VF   |
318               PC_BreakX_VF  |
319               PC_NotAny_VF  |
320               PC_NSpan_VF   |
321               PC_Span_VF    |
322               PC_String_VF  => VF   : VString_Func;
323
324       end case;
325    end record;
326
327    subtype PC_Has_Alt is Pattern_Code range PC_Alt .. PC_Arbno_X;
328    --  Range of pattern codes that has an Alt field. This is used in the
329    --  recursive traversals, since these links must be followed.
330
331    EOP_Element : aliased constant PE := (PC_EOP, 0, N);
332    --  This is the end of pattern element, and is thus the representation of
333    --  a null pattern. It has a zero index element since it is never placed
334    --  inside a pattern. Furthermore it does not need a successor, since it
335    --  marks the end of the pattern, so that no more successors are needed.
336
337    EOP : constant PE_Ptr := EOP_Element'Unrestricted_Access;
338    --  This is the end of pattern pointer, that is used in the Pthen pointer
339    --  of other nodes to signal end of pattern.
340
341    --  The following array is used to determine if a pattern used as an
342    --  argument for Arbno is eligible for treatment using the simple Arbno
343    --  structure (i.e. it is a pattern that is guaranteed to match at least
344    --  one character on success, and not to make any entries on the stack.
345
346    OK_For_Simple_Arbno : constant array (Pattern_Code) of Boolean :=
347      (PC_Any_CS    |
348       PC_Any_CH    |
349       PC_Any_VF    |
350       PC_Any_VP    |
351       PC_Char      |
352       PC_Len_Nat   |
353       PC_NotAny_CS |
354       PC_NotAny_CH |
355       PC_NotAny_VF |
356       PC_NotAny_VP |
357       PC_Span_CS   |
358       PC_Span_CH   |
359       PC_Span_VF   |
360       PC_Span_VP   |
361       PC_String    |
362       PC_String_2  |
363       PC_String_3  |
364       PC_String_4  |
365       PC_String_5  |
366       PC_String_6   => True,
367       others        => False);
368
369    -------------------------------
370    -- The Pattern History Stack --
371    -------------------------------
372
373    --  The pattern history stack is used for controlling backtracking when
374    --  a match fails. The idea is to stack entries that give a cursor value
375    --  to be restored, and a node to be reestablished as the current node to
376    --  attempt an appropriate rematch operation. The processing for a pattern
377    --  element that has rematch alternatives pushes an appropriate entry or
378    --  entry on to the stack, and the proceeds. If a match fails at any point,
379    --  the top element of the stack is popped off, resetting the cursor and
380    --  the match continues by accessing the node stored with this entry.
381
382    type Stack_Entry is record
383
384       Cursor : Integer;
385       --  Saved cursor value that is restored when this entry is popped
386       --  from the stack if a match attempt fails. Occasionally, this
387       --  field is used to store a history stack pointer instead of a
388       --  cursor. Such cases are noted in the documentation and the value
389       --  stored is negative since stack pointer values are always negative.
390
391       Node : PE_Ptr;
392       --  This pattern element reference is reestablished as the current
393       --  Node to be matched (which will attempt an appropriate rematch).
394
395    end record;
396
397    subtype Stack_Range is Integer range -Stack_Size .. -1;
398
399    type Stack_Type is array (Stack_Range) of Stack_Entry;
400    --  The type used for a history stack. The actual instance of the stack
401    --  is declared as a local variable in the Match routine, to properly
402    --  handle recursive calls to Match. All stack pointer values are negative
403    --  to distinguish them from normal cursor values.
404
405    --  Note: the pattern matching stack is used only to handle backtracking.
406    --  If no backtracking occurs, its entries are never accessed, and never
407    --  popped off, and in particular it is normal for a successful match
408    --  to terminate with entries on the stack that are simply discarded.
409
410    --  Note: in subsequent diagrams of the stack, we always place element
411    --  zero (the deepest element) at the top of the page, then build the
412    --  stack down on the page with the most recent (top of stack) element
413    --  being the bottom-most entry on the page.
414
415    --  Stack checking is handled by labeling every pattern with the maximum
416    --  number of stack entries that are required, so a single check at the
417    --  start of matching the pattern suffices. There are two exceptions.
418
419    --  First, the count does not include entries for recursive pattern
420    --  references. Such recursions must therefore perform a specific
421    --  stack check with respect to the number of stack entries required
422    --  by the recursive pattern that is accessed and the amount of stack
423    --  that remains unused.
424
425    --  Second, the count includes only one iteration of an Arbno pattern,
426    --  so a specific check must be made on subsequent iterations that there
427    --  is still enough stack space left. The Arbno node has a field that
428    --  records the number of stack entries required by its argument for
429    --  this purpose.
430
431    ---------------------------------------------------
432    -- Use of Serial Index Field in Pattern Elements --
433    ---------------------------------------------------
434
435    --  The serial index numbers for the pattern elements are assigned as
436    --  a pattern is consructed from its constituent elements. Note that there
437    --  is never any sharing of pattern elements between patterns (copies are
438    --  always made), so the serial index numbers are unique to a particular
439    --  pattern as referenced from the P field of a value of type Pattern.
440
441    --  The index numbers meet three separate invariants, which are used for
442    --  various purposes as described in this section.
443
444    --  First, the numbers uniquely identify the pattern elements within a
445    --  pattern. If Num is the number of elements in a given pattern, then
446    --  the serial index numbers for the elements of this pattern will range
447    --  from 1 .. Num, so that each element has a separate value.
448
449    --  The purpose of this assignment is to provide a convenient auxiliary
450    --  data structure mechanism during operations which must traverse a
451    --  pattern (e.g. copy and finalization processing). Once constructed
452    --  patterns are strictly read only. This is necessary to allow sharing
453    --  of patterns between tasks. This means that we cannot go marking the
454    --  pattern (e.g. with a visited bit). Instead we cosntuct a separate
455    --  vector that contains the necessary information indexed by the Index
456    --  values in the pattern elements. For this purpose the only requirement
457    --  is that they be uniquely assigned.
458
459    --  Second, the pattern element referenced directly, i.e. the leading
460    --  pattern element, is always the maximum numbered element and therefore
461    --  indicates the total number of elements in the pattern. More precisely,
462    --  the element referenced by the P field of a pattern value, or the
463    --  element returned by any of the internal pattern construction routines
464    --  in the body (that return a value of type PE_Ptr) always is this
465    --  maximum element,
466
467    --  The purpose of this requirement is to allow an immediate determination
468    --  of the number of pattern elements within a pattern. This is used to
469    --  properly size the vectors used to contain auxiliary information for
470    --  traversal as described above.
471
472    --  Third, as compound pattern structures are constructed, the way in which
473    --  constituent parts of the pattern are constructed is stylized. This is
474    --  an automatic consequence of the way that these compounjd structures
475    --  are constructed, and basically what we are doing is simply documenting
476    --  and specifying the natural result of the pattern construction. The
477    --  section describing compound pattern structures gives details of the
478    --  numbering of each compound pattern structure.
479
480    --  The purpose of specifying the stylized numbering structures for the
481    --  compound patterns is to help simplify the processing in the Image
482    --  function, since it eases the task of retrieving the original recursive
483    --  structure of the pattern from the flat graph structure of elements.
484    --  This use in the Image function is the only point at which the code
485    --  makes use of the stylized structures.
486
487    type Ref_Array is array (IndexT range <>) of PE_Ptr;
488    --  This type is used to build an array whose N'th entry references the
489    --  element in a pattern whose Index value is N. See Build_Ref_Array.
490
491    procedure Build_Ref_Array (E : PE_Ptr; RA : out Ref_Array);
492    --  Given a pattern element which is the leading element of a pattern
493    --  structure, and a Ref_Array with bounds 1 .. E.Index, fills in the
494    --  Ref_Array so that its N'th entry references the element of the
495    --  referenced pattern whose Index value is N.
496
497    -------------------------------
498    -- Recursive Pattern Matches --
499    -------------------------------
500
501    --  The pattern primitive (+P) where P is a Pattern_Ptr or Pattern_Func
502    --  causes a recursive pattern match. This cannot be handled by an actual
503    --  recursive call to the outer level Match routine, since this would not
504    --  allow for possible backtracking into the region matched by the inner
505    --  pattern. Indeed this is the classical clash between recursion and
506    --  backtracking, and a simple recursive stack structure does not suffice.
507
508    --  This section describes how this recursion and the possible associated
509    --  backtracking is handled. We still use a single stack, but we establish
510    --  the concept of nested regions on this stack, each of which has a stack
511    --  base value pointing to the deepest stack entry of the region. The base
512    --  value for the outer level is zero.
513
514    --  When a recursive match is established, two special stack entries are
515    --  made. The first entry is used to save the original node that starts
516    --  the recursive match. This is saved so that the successor field of
517    --  this node is accessible at the end of the match, but it is never
518    --  popped and executed.
519
520    --  The second entry corresponds to a standard new region action. A
521    --  PC_R_Remove node is stacked, whose cursor field is used to store
522    --  the outer stack base, and the stack base is reset to point to
523    --  this PC_R_Remove node. Then the recursive pattern is matched and
524    --  it can make history stack entries in the normal matter, so now
525    --  the stack looks like:
526
527    --     (stack entries made by outer level)
528
529    --     (Special entry, node is (+P) successor
530    --      cursor entry is not used)
531
532    --     (PC_R_Remove entry, "cursor" value is (negative)     <-- Stack base
533    --      saved base value for the enclosing region)
534
535    --     (stack entries made by inner level)
536
537    --  If a subsequent failure occurs and pops the PC_R_Remove node, it
538    --  removes itself and the special entry immediately underneath it,
539    --  restores the stack base value for the enclosing region, and then
540    --  again signals failure to look for alternatives that were stacked
541    --  before the recursion was initiated.
542
543    --  Now we need to consider what happens if the inner pattern succeeds, as
544    --  signalled by accessing the special PC_EOP pattern primitive. First we
545    --  recognize the nested case by looking at the Base value. If this Base
546    --  value is Stack'First, then the entire match has succeeded, but if the
547    --  base value is greater than Stack'First, then we have successfully
548    --  matched an inner pattern, and processing continues at the outer level.
549
550    --  There are two cases. The simple case is when the inner pattern has made
551    --  no stack entries, as recognized by the fact that the current stack
552    --  pointer is equal to the current base value. In this case it is fine to
553    --  remove all trace of the recursion by restoring the outer base value and
554    --  using the special entry to find the appropriate successor node.
555
556    --  The more complex case arises when the inner match does make stack
557    --  entries. In this case, the PC_EOP processing stacks a special entry
558    --  whose cursor value saves the saved inner base value (the one that
559    --  references the corresponding PC_R_Remove value), and whose node
560    --  pointer references a PC_R_Restore node, so the stack looks like:
561
562    --     (stack entries made by outer level)
563
564    --     (Special entry, node is (+P) successor,
565    --      cursor entry is not used)
566
567    --     (PC_R_Remove entry, "cursor" value is (negative)
568    --      saved base value for the enclosing region)
569
570    --     (stack entries made by inner level)
571
572    --     (PC_Region_Replace entry, "cursor" value is (negative)
573    --      stack pointer value referencing the PC_R_Remove entry).
574
575    --  If the entire match succeeds, then these stack entries are, as usual,
576    --  ignored and abandoned. If on the other hand a subsequent failure
577    --  causes the PC_Region_Replace entry to be popped, it restores the
578    --  inner base value from its saved "cursor" value and then fails again.
579    --  Note that it is OK that the cursor is temporarily clobbered by this
580    --  pop, since the second failure will reestablish a proper cursor value.
581
582    ---------------------------------
583    -- Compound Pattern Structures --
584    ---------------------------------
585
586    --  This section discusses the compound structures used to represent
587    --  constructed patterns. It shows the graph structures of pattern
588    --  elements that are constructed, and in the case of patterns that
589    --  provide backtracking possibilities, describes how the history
590    --  stack is used to control the backtracking. Finally, it notes the
591    --  way in which the Index numbers are assigned to the structure.
592
593    --  In all diagrams, solid lines (built witth minus signs or vertical
594    --  bars, represent successor pointers (Pthen fields) with > or V used
595    --  to indicate the direction of the pointer. The initial node of the
596    --  structure is in the upper left of the diagram. A dotted line is an
597    --  alternative pointer from the element above it to the element below
598    --  it. See individual sections for details on how alternatives are used.
599
600       -------------------
601       -- Concatenation --
602       -------------------
603
604       --  In the pattern structures listed in this section, a line that looks
605       --  lile ----> with nothing to the right indicates an end of pattern
606       --  (EOP) pointer that represents the end of the match.
607
608       --  When a pattern concatenation (L & R) occurs, the resulting structure
609       --  is obtained by finding all such EOP pointers in L, and replacing
610       --  them to point to R. This is the most important flattening that
611       --  occurs in constructing a pattern, and it means that the pattern
612       --  matching circuitry does not have to keep track of the structure
613       --  of a pattern with respect to concatenation, since the appropriate
614       --  succesor is always at hand.
615
616       --  Concatenation itself generates no additional possibilities for
617       --  backtracking, but the constituent patterns of the concatenated
618       --  structure will make stack entries as usual. The maximum amount
619       --  of stack required by the structure is thus simply the sum of the
620       --  maximums required by L and R.
621
622       --  The index numbering of a concatenation structure works by leaving
623       --  the numbering of the right hand pattern, R, unchanged and adjusting
624       --  the numbers in the left hand pattern, L up by the count of elements
625       --  in R. This ensures that the maximum numbered element is the leading
626       --  element as required (given that it was the leading element in L).
627
628       -----------------
629       -- Alternation --
630       -----------------
631
632       --  A pattern (L or R) constructs the structure:
633
634       --    +---+     +---+
635       --    | A |---->| L |---->
636       --    +---+     +---+
637       --      .
638       --      .
639       --    +---+
640       --    | R |---->
641       --    +---+
642
643       --  The A element here is a PC_Alt node, and the dotted line represents
644       --  the contents of the Alt field. When the PC_Alt element is matched,
645       --  it stacks a pointer to the leading element of R on the history stack
646       --  so that on subsequent failure, a match of R is attempted.
647
648       --  The A node is the higest numbered element in the pattern. The
649       --  original index numbers of R are unchanged, but the index numbers
650       --  of the L pattern are adjusted up by the count of elements in R.
651
652       --  Note that the difference between the index of the L leading element
653       --  the index of the R leading element (after building the alt structure)
654       --  indicates the number of nodes in L, and this is true even after the
655       --  structure is incorporated into some larger structure. For example,
656       --  if the A node has index 16, and L has index 15 and R has index
657       --  5, then we know that L has 10 (15-5) elements in it.
658
659       --  Suppose that we now concatenate this structure to another pattern
660       --  with 9 elements in it. We will now have the A node with an index
661       --  of 25, L with an index of 24 and R with an index of 14. We still
662       --  know that L has 10 (24-14) elements in it, numbered 15-24, and
663       --  consequently the successor of the alternation structure has an
664       --  index with a value less than 15. This is used in Image to figure
665       --  out the original recursive structure of a pattern.
666
667       --  To clarify the interaction of the alternation and concatenation
668       --  structures, here is a more complex example of the structure built
669       --  for the pattern:
670
671       --      (V or W or X) (Y or Z)
672
673       --  where A,B,C,D,E are all single element patterns:
674
675       --    +---+     +---+       +---+     +---+
676       --    I A I---->I V I---+-->I A I---->I Y I---->
677       --    +---+     +---+   I   +---+     +---+
678       --      .               I     .
679       --      .               I     .
680       --    +---+     +---+   I   +---+
681       --    I A I---->I W I-->I   I Z I---->
682       --    +---+     +---+   I   +---+
683       --      .               I
684       --      .               I
685       --    +---+             I
686       --    I X I------------>+
687       --    +---+
688
689       --  The numbering of the nodes would be as follows:
690
691       --    +---+     +---+       +---+     +---+
692       --    I 8 I---->I 7 I---+-->I 3 I---->I 2 I---->
693       --    +---+     +---+   I   +---+     +---+
694       --      .               I     .
695       --      .               I     .
696       --    +---+     +---+   I   +---+
697       --    I 6 I---->I 5 I-->I   I 1 I---->
698       --    +---+     +---+   I   +---+
699       --      .               I
700       --      .               I
701       --    +---+             I
702       --    I 4 I------------>+
703       --    +---+
704
705       --  Note: The above structure actually corresponds to
706
707       --    (A or (B or C)) (D or E)
708
709       --  rather than
710
711       --    ((A or B) or C) (D or E)
712
713       --  which is the more natural interpretation, but in fact alternation
714       --  is associative, and the construction of an alternative changes the
715       --  left grouped pattern to the right grouped pattern in any case, so
716       --  that the Image function produces a more natural looking output.
717
718       ---------
719       -- Arb --
720       ---------
721
722       --  An Arb pattern builds the structure
723
724       --    +---+
725       --    | X |---->
726       --    +---+
727       --      .
728       --      .
729       --    +---+
730       --    | Y |---->
731       --    +---+
732
733       --  The X node is a PC_Arb_X node, which matches null, and stacks a
734       --  pointer to Y node, which is the PC_Arb_Y node that matches one
735       --  extra character and restacks itself.
736
737       --  The PC_Arb_X node is numbered 2, and the PC_Arb_Y node is 1.
738
739       -------------------------
740       -- Arbno (simple case) --
741       -------------------------
742
743       --  The simple form of Arbno can be used where the pattern always
744       --  matches at least one character if it succeeds, and it is known
745       --  not to make any history stack entries. In this case, Arbno (P)
746       --  can construct the following structure:
747
748       --      +-------------+
749       --      |             ^
750       --      V             |
751       --    +---+           |
752       --    | S |---->      |
753       --    +---+           |
754       --      .             |
755       --      .             |
756       --    +---+           |
757       --    | P |---------->+
758       --    +---+
759
760       --  The S (PC_Arbno_S) node matches null stacking a pointer to the
761       --  pattern P. If a subsequent failure causes P to be matched and
762       --  this match succeeds, then node A gets restacked to try another
763       --  instance if needed by a subsequent failure.
764
765       --  The node numbering of the constituent pattern P is not affected.
766       --  The S node has a node number of P.Index + 1.
767
768       --------------------------
769       -- Arbno (complex case) --
770       --------------------------
771
772       --  A call to Arbno (P), where P can match null (or at least is not
773       --  known to require a non-null string) and/or P requires pattern stack
774       --  entries, constructs the following structure:
775
776       --      +--------------------------+
777       --      |                          ^
778       --      V                          |
779       --    +---+                        |
780       --    | X |---->                   |
781       --    +---+                        |
782       --      .                          |
783       --      .                          |
784       --    +---+     +---+     +---+    |
785       --    | E |---->| P |---->| Y |--->+
786       --    +---+     +---+     +---+
787
788       --  The node X (PC_Arbno_X) matches null, stacking a pointer to the
789       --  E-P-X structure used to match one Arbno instance.
790
791       --  Here E is the PC_R_Enter node which matches null and creates two
792       --  stack entries. The first is a special entry whose node field is
793       --  not used at all, and whose cursor field has the initial cursor.
794
795       --  The second entry corresponds to a standard new region action. A
796       --  PC_R_Remove node is stacked, whose cursor field is used to store
797       --  the outer stack base, and the stack base is reset to point to
798       --  this PC_R_Remove node. Then the pattern P is matched, and it can
799       --  make history stack entries in the normal manner, so now the stack
800       --  looks like:
801
802       --     (stack entries made before assign pattern)
803
804       --     (Special entry, node field not used,
805       --      used only to save initial cursor)
806
807       --     (PC_R_Remove entry, "cursor" value is (negative)  <-- Stack Base
808       --      saved base value for the enclosing region)
809
810       --     (stack entries made by matching P)
811
812       --  If the match of P fails, then the PC_R_Remove entry is popped and
813       --  it removes both itself and the special entry underneath it,
814       --  restores the outer stack base, and signals failure.
815
816       --  If the match of P succeeds, then node Y, the PC_Arbno_Y node, pops
817       --  the inner region. There are two possibilities. If matching P left
818       --  no stack entries, then all traces of the inner region can be removed.
819       --  If there are stack entries, then we push an PC_Region_Replace stack
820       --  entry whose "cursor" value is the inner stack base value, and then
821       --  restore the outer stack base value, so the stack looks like:
822
823       --     (stack entries made before assign pattern)
824
825       --     (Special entry, node field not used,
826       --      used only to save initial cursor)
827
828       --     (PC_R_Remove entry, "cursor" value is (negative)
829       --      saved base value for the enclosing region)
830
831       --     (stack entries made by matching P)
832
833       --     (PC_Region_Replace entry, "cursor" value is (negative)
834       --      stack pointer value referencing the PC_R_Remove entry).
835
836       --  Now that we have matched another instance of the Arbno pattern,
837       --  we need to move to the successor. There are two cases. If the
838       --  Arbno pattern matched null, then there is no point in seeking
839       --  alternatives, since we would just match a whole bunch of nulls.
840       --  In this case we look through the alternative node, and move
841       --  directly to its successor (i.e. the successor of the Arbno
842       --  pattern). If on the other hand a non-null string was matched,
843       --  we simply follow the successor to the alternative node, which
844       --  sets up for another possible match of the Arbno pattern.
845
846       --  As noted in the section on stack checking, the stack count (and
847       --  hence the stack check) for a pattern includes only one iteration
848       --  of the Arbno pattern. To make sure that multiple iterations do not
849       --  overflow the stack, the Arbno node saves the stack count required
850       --  by a single iteration, and the Concat function increments this to
851       --  include stack entries required by any successor. The PC_Arbno_Y
852       --  node uses this count to ensure that sufficient stack remains
853       --  before proceeding after matching each new instance.
854
855       --  The node numbering of the constituent pattern P is not affected.
856       --  Where N is the number of nodes in P, the Y node is numbered N + 1,
857       --  the E node is N + 2, and the X node is N + 3.
858
859       ----------------------
860       -- Assign Immediate --
861       ----------------------
862
863       --  Immediate assignment (P * V) constructs the following structure
864
865       --    +---+     +---+     +---+
866       --    | E |---->| P |---->| A |---->
867       --    +---+     +---+     +---+
868
869       --  Here E is the PC_R_Enter node which matches null and creates two
870       --  stack entries. The first is a special entry whose node field is
871       --  not used at all, and whose cursor field has the initial cursor.
872
873       --  The second entry corresponds to a standard new region action. A
874       --  PC_R_Remove node is stacked, whose cursor field is used to store
875       --  the outer stack base, and the stack base is reset to point to
876       --  this PC_R_Remove node. Then the pattern P is matched, and it can
877       --  make history stack entries in the normal manner, so now the stack
878       --  looks like:
879
880       --     (stack entries made before assign pattern)
881
882       --     (Special entry, node field not used,
883       --      used only to save initial cursor)
884
885       --     (PC_R_Remove entry, "cursor" value is (negative)  <-- Stack Base
886       --      saved base value for the enclosing region)
887
888       --     (stack entries made by matching P)
889
890       --  If the match of P fails, then the PC_R_Remove entry is popped
891       --  and it removes both itself and the special entry underneath it,
892       --  restores the outer stack base, and signals failure.
893
894       --  If the match of P succeeds, then node A, which is the actual
895       --  PC_Assign_Imm node, executes the assignment (using the stack
896       --  base to locate the entry with the saved starting cursor value),
897       --  and the pops the inner region. There are two possibilities, if
898       --  matching P left no stack entries, then all traces of the inner
899       --  region can be removed. If there are stack entries, then we push
900       --  an PC_Region_Replace stack entry whose "cursor" value is the
901       --  inner stack base value, and then restore the outer stack base
902       --  value, so the stack looks like:
903
904       --     (stack entries made before assign pattern)
905
906       --     (Special entry, node field not used,
907       --      used only to save initial cursor)
908
909       --     (PC_R_Remove entry, "cursor" value is (negative)
910       --      saved base value for the enclosing region)
911
912       --     (stack entries made by matching P)
913
914       --     (PC_Region_Replace entry, "cursor" value is the (negative)
915       --      stack pointer value referencing the PC_R_Remove entry).
916
917       --  If a subsequent failure occurs, the PC_Region_Replace node restores
918       --  the inner stack base value and signals failure to explore rematches
919       --  of the pattern P.
920
921       --  The node numbering of the constituent pattern P is not affected.
922       --  Where N is the number of nodes in P, the A node is numbered N + 1,
923       --  and the E node is N + 2.
924
925       ---------------------
926       -- Assign On Match --
927       ---------------------
928
929       --  The assign on match (**) pattern is quite similar to the assign
930       --  immediate pattern, except that the actual assignment has to be
931       --  delayed. The following structure is constructed:
932
933       --    +---+     +---+     +---+
934       --    | E |---->| P |---->| A |---->
935       --    +---+     +---+     +---+
936
937       --  The operation of this pattern is identical to that described above
938       --  for deferred assignment, up to the point where P has been matched.
939
940       --  The A node, which is the PC_Assign_OnM node first pushes a
941       --  PC_Assign node onto the history stack. This node saves the ending
942       --  cursor and acts as a flag for the final assignment, as further
943       --  described below.
944
945       --  It then stores a pointer to itself in the special entry node field.
946       --  This was otherwise unused, and is now used to retrive the address
947       --  of the variable to be assigned at the end of the pattern.
948
949       --  After that the inner region is terminated in the usual manner,
950       --  by stacking a PC_R_Restore entry as described for the assign
951       --  immediate case. Note that the optimization of completely
952       --  removing the inner region does not happen in this case, since
953       --  we have at least one stack entry (the PC_Assign one we just made).
954       --  The stack now looks like:
955
956       --     (stack entries made before assign pattern)
957
958       --     (Special entry, node points to copy of
959       --      the PC_Assign_OnM node, and the
960       --      cursor field saves the initial cursor).
961
962       --     (PC_R_Remove entry, "cursor" value is (negative)
963       --      saved base value for the enclosing region)
964
965       --     (stack entries made by matching P)
966
967       --     (PC_Assign entry, saves final cursor)
968
969       --     (PC_Region_Replace entry, "cursor" value is (negative)
970       --      stack pointer value referencing the PC_R_Remove entry).
971
972       --  If a subsequent failure causes the PC_Assign node to execute it
973       --  simply removes itself and propagates the failure.
974
975       --  If the match succeeds, then the history stack is scanned for
976       --  PC_Assign nodes, and the assignments are executed (examination
977       --  of the above diagram will show that all the necessary data is
978       --  at hand for the assignment).
979
980       --  To optimize the common case where no assign-on-match operations
981       --  are present, a global flag Assign_OnM is maintained which is
982       --  initialize to False, and gets set True as part of the execution
983       --  of the PC_Assign_OnM node. The scan of the history stack for
984       --  PC_Assign entries is done only if this flag is set.
985
986       --  The node numbering of the constituent pattern P is not affected.
987       --  Where N is the number of nodes in P, the A node is numbered N + 1,
988       --  and the E node is N + 2.
989
990       ---------
991       -- Bal --
992       ---------
993
994       --  Bal builds a single node:
995
996       --    +---+
997       --    | B |---->
998       --    +---+
999
1000       --  The node B is the PC_Bal node which matches a parentheses balanced
1001       --  string, starting at the current cursor position. It then updates
1002       --  the cursor past this matched string, and stacks a pointer to itself
1003       --  with this updated cursor value on the history stack, to extend the
1004       --  matched string on a subequent failure.
1005
1006       --  Since this is a single node it is numbered 1 (the reason we include
1007       --  it in the compound patterns section is that it backtracks).
1008
1009       ------------
1010       -- BreakX --
1011       ------------
1012
1013       --  BreakX builds the structure
1014
1015       --    +---+     +---+
1016       --    | B |---->| A |---->
1017       --    +---+     +---+
1018       --      ^         .
1019       --      |         .
1020       --      |       +---+
1021       --      +<------| X |
1022       --              +---+
1023
1024       --  Here the B node is the BreakX_xx node that performs a normal Break
1025       --  function. The A node is an alternative (PC_Alt) node that matches
1026       --  null, but stacks a pointer to node X (the PC_BreakX_X node) which
1027       --  extends the match one character (to eat up the previously detected
1028       --  break character), and then rematches the break.
1029
1030       --  The B node is numbered 3, the alternative node is 1, and the X
1031       --  node is 2.
1032
1033       -----------
1034       -- Fence --
1035       -----------
1036
1037       --  Fence builds a single node:
1038
1039       --    +---+
1040       --    | F |---->
1041       --    +---+
1042
1043       --  The element F, PC_Fence,  matches null, and stacks a pointer to a
1044       --  PC_Cancel element which will abort the match on a subsequent failure.
1045
1046       --  Since this is a single element it is numbered 1 (the reason we
1047       --  include it in the compound patterns section is that it backtracks).
1048
1049       --------------------
1050       -- Fence Function --
1051       --------------------
1052
1053       --  A call to the Fence function builds the structure:
1054
1055       --    +---+     +---+     +---+
1056       --    | E |---->| P |---->| X |---->
1057       --    +---+     +---+     +---+
1058
1059       --  Here E is the PC_R_Enter node which matches null and creates two
1060       --  stack entries. The first is a special entry which is not used at
1061       --  all in the fence case (it is present merely for uniformity with
1062       --  other cases of region enter operations).
1063
1064       --  The second entry corresponds to a standard new region action. A
1065       --  PC_R_Remove node is stacked, whose cursor field is used to store
1066       --  the outer stack base, and the stack base is reset to point to
1067       --  this PC_R_Remove node. Then the pattern P is matched, and it can
1068       --  make history stack entries in the normal manner, so now the stack
1069       --  looks like:
1070
1071       --     (stack entries made before fence pattern)
1072
1073       --     (Special entry, not used at all)
1074
1075       --     (PC_R_Remove entry, "cursor" value is (negative)  <-- Stack Base
1076       --      saved base value for the enclosing region)
1077
1078       --     (stack entries made by matching P)
1079
1080       --  If the match of P fails, then the PC_R_Remove entry is popped
1081       --  and it removes both itself and the special entry underneath it,
1082       --  restores the outer stack base, and signals failure.
1083
1084       --  If the match of P succeeds, then node X, the PC_Fence_X node, gets
1085       --  control. One might be tempted to think that at this point, the
1086       --  history stack entries made by matching P can just be removed since
1087       --  they certainly are not going to be used for rematching (that is
1088       --  whole point of Fence after all!) However, this is wrong, because
1089       --  it would result in the loss of possible assign-on-match entries
1090       --  for deferred pattern assignments.
1091
1092       --  Instead what we do is to make a special entry whose node references
1093       --  PC_Fence_Y, and whose cursor saves the inner stack base value, i.e.
1094       --  the pointer to the PC_R_Remove entry. Then the outer stack base
1095       --  pointer is restored, so the stack looks like:
1096
1097       --     (stack entries made before assign pattern)
1098
1099       --     (Special entry, not used at all)
1100
1101       --     (PC_R_Remove entry, "cursor" value is (negative)
1102       --      saved base value for the enclosing region)
1103
1104       --     (stack entries made by matching P)
1105
1106       --     (PC_Fence_Y entry, "cursor" value is (negative) stack
1107       --      pointer value referencing the PC_R_Remove entry).
1108
1109       --  If a subsequent failure occurs, then the PC_Fence_Y entry removes
1110       --  the entire inner region, including all entries made by matching P,
1111       --  and alternatives prior to the Fence pattern are sought.
1112
1113       --  The node numbering of the constituent pattern P is not affected.
1114       --  Where N is the number of nodes in P, the X node is numbered N + 1,
1115       --  and the E node is N + 2.
1116
1117       -------------
1118       -- Succeed --
1119       -------------
1120
1121       --  Succeed builds a single node:
1122
1123       --    +---+
1124       --    | S |---->
1125       --    +---+
1126
1127       --  The node S is the PC_Succeed node which matches null, and stacks
1128       --  a pointer to itself on the history stack, so that a subsequent
1129       --  failure repeats the same match.
1130
1131       --  Since this is a single node it is numbered 1 (the reason we include
1132       --  it in the compound patterns section is that it backtracks).
1133
1134       ---------------------
1135       -- Write Immediate --
1136       ---------------------
1137
1138       --  The structure built for a write immediate operation (P * F, where
1139       --  F is a file access value) is:
1140
1141       --    +---+     +---+     +---+
1142       --    | E |---->| P |---->| W |---->
1143       --    +---+     +---+     +---+
1144
1145       --  Here E is the PC_R_Enter node and W is the PC_Write_Imm node. The
1146       --  handling is identical to that described above for Assign Immediate,
1147       --  except that at the point where a successful match occurs, the matched
1148       --  substring is written to the referenced file.
1149
1150       --  The node numbering of the constituent pattern P is not affected.
1151       --  Where N is the number of nodes in P, the W node is numbered N + 1,
1152       --  and the E node is N + 2.
1153
1154       --------------------
1155       -- Write On Match --
1156       --------------------
1157
1158       --  The structure built for a write on match operation (P ** F, where
1159       --  F is a file access value) is:
1160
1161       --    +---+     +---+     +---+
1162       --    | E |---->| P |---->| W |---->
1163       --    +---+     +---+     +---+
1164
1165       --  Here E is the PC_R_Enter node and W is the PC_Write_OnM node. The
1166       --  handling is identical to that described above for Assign On Match,
1167       --  except that at the point where a successful match has completed,
1168       --  the matched substring is written to the referenced file.
1169
1170       --  The node numbering of the constituent pattern P is not affected.
1171       --  Where N is the number of nodes in P, the W node is numbered N + 1,
1172       --  and the E node is N + 2.
1173    -----------------------
1174    -- Constant Patterns --
1175    -----------------------
1176
1177    --  The following pattern elements are referenced only from the pattern
1178    --  history stack. In each case the processing for the pattern element
1179    --  results in pattern match abort, or futher failure, so there is no
1180    --  need for a successor and no need for a node number
1181
1182    CP_Assign    : aliased PE := (PC_Assign,    0, N);
1183    CP_Cancel    : aliased PE := (PC_Cancel,    0, N);
1184    CP_Fence_Y   : aliased PE := (PC_Fence_Y,   0, N);
1185    CP_R_Remove  : aliased PE := (PC_R_Remove,  0, N);
1186    CP_R_Restore : aliased PE := (PC_R_Restore, 0, N);
1187
1188    -----------------------
1189    -- Local Subprograms --
1190    -----------------------
1191
1192    function Alternate (L, R : PE_Ptr) return PE_Ptr;
1193    function "or"      (L, R : PE_Ptr) return PE_Ptr renames Alternate;
1194    --  Build pattern structure corresponding to the alternation of L, R.
1195    --  (i.e. try to match L, and if that fails, try to match R).
1196
1197    function Arbno_Simple (P : PE_Ptr) return PE_Ptr;
1198    --  Build simple Arbno pattern, P is a pattern that is guaranteed to
1199    --  match at least one character if it succeeds and to require no
1200    --  stack entries under all circumstances. The result returned is
1201    --  a simple Arbno structure as previously described.
1202
1203    function Bracket (E, P, A : PE_Ptr) return PE_Ptr;
1204    --  Given two single node pattern elements E and A, and a (possible
1205    --  complex) pattern P, construct the concatenation E-->P-->A and
1206    --  return a pointer to E. The concatenation does not affect the
1207    --  node numbering in P. A has a number one higher than the maximum
1208    --  number in P, and E has a number two higher than the maximum
1209    --  number in P (see for example the Assign_Immediate structure to
1210    --  understand a typical use of this function).
1211
1212    function BreakX_Make (B : PE_Ptr) return Pattern;
1213    --  Given a pattern element for a Break patternx, returns the
1214    --  corresponding BreakX compound pattern structure.
1215
1216    function Concat (L, R : PE_Ptr; Incr : Natural) return PE_Ptr;
1217    --  Creates a pattern eelement that represents a concatenation of the
1218    --  two given pattern elements (i.e. the pattern L followed by R).
1219    --  The result returned is always the same as L, but the pattern
1220    --  referenced by L is modified to have R as a successor. This
1221    --  procedure does not copy L or R, so if a copy is required, it
1222    --  is the responsibility of the caller. The Incr parameter is an
1223    --  amount to be added to the Nat field of any P_Arbno_Y node that is
1224    --  in the left operand, it represents the additional stack space
1225    --  required by the right operand.
1226
1227    function C_To_PE (C : PChar) return PE_Ptr;
1228    --  Given a character, constructs a pattern element that matches
1229    --  the single character.
1230
1231    function Copy (P : PE_Ptr) return PE_Ptr;
1232    --  Creates a copy of the pattern element referenced by the given
1233    --  pattern element reference. This is a deep copy, which means that
1234    --  it follows the Next and Alt pointers.
1235
1236    function Image (P : PE_Ptr) return String;
1237    --  Returns the image of the address of the referenced pattern element.
1238    --  This is equivalent to Image (To_Address (P));
1239
1240    function Is_In (C : Character; Str : String) return Boolean;
1241    pragma Inline (Is_In);
1242    --  Determines if the character C is in string Str.
1243
1244    procedure Logic_Error;
1245    --  Called to raise Program_Error with an appropriate message if an
1246    --  internal logic error is detected.
1247
1248    function Str_BF (A : Boolean_Func)   return String;
1249    function Str_FP (A : File_Ptr)       return String;
1250    function Str_NF (A : Natural_Func)   return String;
1251    function Str_NP (A : Natural_Ptr)    return String;
1252    function Str_PP (A : Pattern_Ptr)    return String;
1253    function Str_VF (A : VString_Func)   return String;
1254    function Str_VP (A : VString_Ptr)    return String;
1255    --  These are debugging routines, which return a representation of the
1256    --  given access value (they are called only by Image and Dump)
1257
1258    procedure Set_Successor (Pat : PE_Ptr; Succ : PE_Ptr);
1259    --  Adjusts all EOP pointers in Pat to point to Succ. No other changes
1260    --  are made. In particular, Succ is unchanged, and no index numbers
1261    --  are modified. Note that Pat may not be equal to EOP on entry.
1262
1263    function S_To_PE (Str : PString) return PE_Ptr;
1264    --  Given a string, constructs a pattern element that matches the string
1265
1266    procedure Uninitialized_Pattern;
1267    pragma No_Return (Uninitialized_Pattern);
1268    --  Called to raise Program_Error with an appropriate error message if
1269    --  an uninitialized pattern is used in any pattern construction or
1270    --  pattern matching operation.
1271
1272    procedure XMatch
1273      (Subject : String;
1274       Pat_P   : PE_Ptr;
1275       Pat_S   : Natural;
1276       Start   : out Natural;
1277       Stop    : out Natural);
1278    --  This is the common pattern match routine. It is passed a string and
1279    --  a pattern, and it indicates success or failure, and on success the
1280    --  section of the string matched. It does not perform any assignments
1281    --  to the subject string, so pattern replacement is for the caller.
1282    --
1283    --  Subject The subject string. The lower bound is always one. In the
1284    --          Match procedures, it is fine to use strings whose lower bound
1285    --          is not one, but we perform a one time conversion before the
1286    --          call to XMatch, so that XMatch does not have to be bothered
1287    --          with strange lower bounds.
1288    --
1289    --  Pat_P   Points to initial pattern element of pattern to be matched
1290    --
1291    --  Pat_S   Maximum required stack entries for pattern to be matched
1292    --
1293    --  Start   If match is successful, starting index of matched section.
1294    --          This value is always non-zero. A value of zero is used to
1295    --          indicate a failed match.
1296    --
1297    --  Stop    If match is successful, ending index of matched section.
1298    --          This can be zero if we match the null string at the start,
1299    --          in which case Start is set to zero, and Stop to one. If the
1300    --          Match fails, then the contents of Stop is undefined.
1301
1302    procedure XMatchD
1303      (Subject : String;
1304       Pat_P   : PE_Ptr;
1305       Pat_S   : Natural;
1306       Start   : out Natural;
1307       Stop    : out Natural);
1308    --  Identical in all respects to XMatch, except that trace information is
1309    --  output on Standard_Ouput during execution of the match. This is the
1310    --  version that is called if the original Match call has Debug => True.
1311
1312    ---------
1313    -- "&" --
1314    ---------
1315
1316    function "&" (L : PString; R : Pattern) return Pattern is
1317    begin
1318       return (AFC with R.Stk, Concat (S_To_PE (L), Copy (R.P), R.Stk));
1319    end "&";
1320
1321    function "&" (L : Pattern; R : PString) return Pattern is
1322    begin
1323       return (AFC with L.Stk, Concat (Copy (L.P), S_To_PE (R), 0));
1324    end "&";
1325
1326    function "&" (L : PChar; R : Pattern) return Pattern is
1327    begin
1328       return (AFC with R.Stk, Concat (C_To_PE (L), Copy (R.P), R.Stk));
1329    end "&";
1330
1331    function "&" (L : Pattern; R : PChar) return Pattern is
1332    begin
1333       return (AFC with L.Stk, Concat (Copy (L.P), C_To_PE (R), 0));
1334    end "&";
1335
1336    function "&" (L : Pattern; R : Pattern) return Pattern is
1337    begin
1338       return (AFC with L.Stk + R.Stk, Concat (Copy (L.P), Copy (R.P), R.Stk));
1339    end "&";
1340
1341    ---------
1342    -- "*" --
1343    ---------
1344
1345    --  Assign immediate
1346
1347    --    +---+     +---+     +---+
1348    --    | E |---->| P |---->| A |---->
1349    --    +---+     +---+     +---+
1350
1351    --  The node numbering of the constituent pattern P is not affected.
1352    --  Where N is the number of nodes in P, the A node is numbered N + 1,
1353    --  and the E node is N + 2.
1354
1355    function "*" (P : Pattern; Var : VString_Var) return Pattern is
1356       Pat : constant PE_Ptr := Copy (P.P);
1357       E   : constant PE_Ptr := new PE'(PC_R_Enter,    0, EOP);
1358       A   : constant PE_Ptr :=
1359               new PE'(PC_Assign_Imm, 0, EOP, Var'Unrestricted_Access);
1360
1361    begin
1362       return (AFC with P.Stk + 3, Bracket (E, Pat, A));
1363    end "*";
1364
1365    function "*" (P : PString; Var : VString_Var) return Pattern is
1366       Pat : constant PE_Ptr := S_To_PE (P);
1367       E   : constant PE_Ptr := new PE'(PC_R_Enter,    0, EOP);
1368       A   : constant PE_Ptr :=
1369               new PE'(PC_Assign_Imm, 0, EOP, Var'Unrestricted_Access);
1370
1371    begin
1372       return (AFC with 3, Bracket (E, Pat, A));
1373    end "*";
1374
1375    function "*" (P : PChar; Var : VString_Var) return Pattern is
1376       Pat : constant PE_Ptr := C_To_PE (P);
1377       E   : constant PE_Ptr := new PE'(PC_R_Enter,    0, EOP);
1378       A   : constant PE_Ptr :=
1379               new PE'(PC_Assign_Imm, 0, EOP, Var'Unrestricted_Access);
1380
1381    begin
1382       return (AFC with 3, Bracket (E, Pat, A));
1383    end "*";
1384
1385    --  Write immediate
1386
1387    --    +---+     +---+     +---+
1388    --    | E |---->| P |---->| W |---->
1389    --    +---+     +---+     +---+
1390
1391    --  The node numbering of the constituent pattern P is not affected.
1392    --  Where N is the number of nodes in P, the W node is numbered N + 1,
1393    --  and the E node is N + 2.
1394
1395    function "*" (P : Pattern; Fil : File_Access) return Pattern is
1396       Pat : constant PE_Ptr := Copy (P.P);
1397       E   : constant PE_Ptr := new PE'(PC_R_Enter,   0, EOP);
1398       W   : constant PE_Ptr := new PE'(PC_Write_Imm, 0, EOP, Fil);
1399
1400    begin
1401       return (AFC with 3, Bracket (E, Pat, W));
1402    end "*";
1403
1404    function "*" (P : PString; Fil : File_Access) return Pattern is
1405       Pat : constant PE_Ptr := S_To_PE (P);
1406       E   : constant PE_Ptr := new PE'(PC_R_Enter,   0, EOP);
1407       W   : constant PE_Ptr := new PE'(PC_Write_Imm, 0, EOP, Fil);
1408
1409    begin
1410       return (AFC with 3, Bracket (E, Pat, W));
1411    end "*";
1412
1413    function "*" (P : PChar; Fil : File_Access) return Pattern is
1414       Pat : constant PE_Ptr := C_To_PE (P);
1415       E   : constant PE_Ptr := new PE'(PC_R_Enter,   0, EOP);
1416       W   : constant PE_Ptr := new PE'(PC_Write_Imm, 0, EOP, Fil);
1417
1418    begin
1419       return (AFC with 3, Bracket (E, Pat, W));
1420    end "*";
1421
1422    ----------
1423    -- "**" --
1424    ----------
1425
1426    --  Assign on match
1427
1428    --    +---+     +---+     +---+
1429    --    | E |---->| P |---->| A |---->
1430    --    +---+     +---+     +---+
1431
1432    --  The node numbering of the constituent pattern P is not affected.
1433    --  Where N is the number of nodes in P, the A node is numbered N + 1,
1434    --  and the E node is N + 2.
1435
1436    function "**" (P : Pattern; Var : VString_Var) return Pattern is
1437       Pat : constant PE_Ptr := Copy (P.P);
1438       E   : constant PE_Ptr := new PE'(PC_R_Enter,    0, EOP);
1439       A   : constant PE_Ptr :=
1440               new PE'(PC_Assign_OnM, 0, EOP, Var'Unrestricted_Access);
1441
1442    begin
1443       return (AFC with P.Stk + 3, Bracket (E, Pat, A));
1444    end "**";
1445
1446    function "**" (P : PString; Var : VString_Var) return Pattern is
1447       Pat : constant PE_Ptr := S_To_PE (P);
1448       E   : constant PE_Ptr := new PE'(PC_R_Enter,    0, EOP);
1449       A   : constant PE_Ptr :=
1450               new PE'(PC_Assign_OnM, 0, EOP, Var'Unrestricted_Access);
1451
1452    begin
1453       return (AFC with 3, Bracket (E, Pat, A));
1454    end "**";
1455
1456    function "**" (P : PChar; Var : VString_Var) return Pattern is
1457       Pat : constant PE_Ptr := C_To_PE (P);
1458       E   : constant PE_Ptr := new PE'(PC_R_Enter,    0, EOP);
1459       A   : constant PE_Ptr :=
1460               new PE'(PC_Assign_OnM, 0, EOP, Var'Unrestricted_Access);
1461
1462    begin
1463       return (AFC with 3, Bracket (E, Pat, A));
1464    end "**";
1465
1466    --  Write on match
1467
1468    --    +---+     +---+     +---+
1469    --    | E |---->| P |---->| W |---->
1470    --    +---+     +---+     +---+
1471
1472    --  The node numbering of the constituent pattern P is not affected.
1473    --  Where N is the number of nodes in P, the W node is numbered N + 1,
1474    --  and the E node is N + 2.
1475
1476    function "**" (P : Pattern; Fil : File_Access) return Pattern is
1477       Pat : constant PE_Ptr := Copy (P.P);
1478       E   : constant PE_Ptr := new PE'(PC_R_Enter,   0, EOP);
1479       W   : constant PE_Ptr := new PE'(PC_Write_OnM, 0, EOP, Fil);
1480
1481    begin
1482       return (AFC with P.Stk + 3, Bracket (E, Pat, W));
1483    end "**";
1484
1485    function "**" (P : PString; Fil : File_Access) return Pattern is
1486       Pat : constant PE_Ptr := S_To_PE (P);
1487       E   : constant PE_Ptr := new PE'(PC_R_Enter,   0, EOP);
1488       W   : constant PE_Ptr := new PE'(PC_Write_OnM, 0, EOP, Fil);
1489
1490    begin
1491       return (AFC with 3, Bracket (E, Pat, W));
1492    end "**";
1493
1494    function "**" (P : PChar; Fil : File_Access) return Pattern is
1495       Pat : constant PE_Ptr := C_To_PE (P);
1496       E   : constant PE_Ptr := new PE'(PC_R_Enter,   0, EOP);
1497       W   : constant PE_Ptr := new PE'(PC_Write_OnM, 0, EOP, Fil);
1498
1499    begin
1500       return (AFC with 3, Bracket (E, Pat, W));
1501    end "**";
1502
1503    ---------
1504    -- "+" --
1505    ---------
1506
1507    function "+" (Str : VString_Var) return Pattern is
1508    begin
1509       return
1510         (AFC with 0,
1511          new PE'(PC_String_VP, 1, EOP, Str'Unrestricted_Access));
1512    end "+";
1513
1514    function "+" (Str : VString_Func) return Pattern is
1515    begin
1516       return (AFC with 0, new PE'(PC_String_VF, 1, EOP, Str));
1517    end "+";
1518
1519    function "+" (P : Pattern_Var) return Pattern is
1520    begin
1521       return
1522         (AFC with 3,
1523          new PE'(PC_Rpat, 1, EOP, P'Unrestricted_Access));
1524    end "+";
1525
1526    function "+" (P : Boolean_Func) return Pattern is
1527    begin
1528       return (AFC with 3, new PE'(PC_Pred_Func, 1, EOP, P));
1529    end "+";
1530
1531    ----------
1532    -- "or" --
1533    ----------
1534
1535    function "or" (L : PString; R : Pattern) return Pattern is
1536    begin
1537       return (AFC with R.Stk + 1, S_To_PE (L) or Copy (R.P));
1538    end "or";
1539
1540    function "or" (L : Pattern; R : PString) return Pattern is
1541    begin
1542       return (AFC with L.Stk + 1, Copy (L.P) or S_To_PE (R));
1543    end "or";
1544
1545    function "or" (L : PString; R : PString) return Pattern is
1546    begin
1547       return (AFC with 1, S_To_PE (L) or S_To_PE (R));
1548    end "or";
1549
1550    function "or" (L : Pattern; R : Pattern) return Pattern is
1551    begin
1552       return (AFC with
1553                 Natural'Max (L.Stk, R.Stk) + 1, Copy (L.P) or Copy (R.P));
1554    end "or";
1555
1556    function "or" (L : PChar;   R : Pattern) return Pattern is
1557    begin
1558       return (AFC with 1, C_To_PE (L) or Copy (R.P));
1559    end "or";
1560
1561    function "or" (L : Pattern; R : PChar) return Pattern is
1562    begin
1563       return (AFC with 1, Copy (L.P) or C_To_PE (R));
1564    end "or";
1565
1566    function "or" (L : PChar;   R : PChar) return Pattern is
1567    begin
1568       return (AFC with 1, C_To_PE (L) or C_To_PE (R));
1569    end "or";
1570
1571    function "or" (L : PString; R : PChar) return Pattern is
1572    begin
1573       return (AFC with 1, S_To_PE (L) or C_To_PE (R));
1574    end "or";
1575
1576    function "or" (L : PChar;   R : PString) return Pattern is
1577    begin
1578       return (AFC with 1, C_To_PE (L) or S_To_PE (R));
1579    end "or";
1580
1581    ------------
1582    -- Adjust --
1583    ------------
1584
1585    --  No two patterns share the same pattern elements, so the adjust
1586    --  procedure for a Pattern assignment must do a deep copy of the
1587    --  pattern element structure.
1588
1589    procedure Adjust (Object : in out Pattern) is
1590    begin
1591       Object.P := Copy (Object.P);
1592    end Adjust;
1593
1594    ---------------
1595    -- Alternate --
1596    ---------------
1597
1598    function Alternate (L, R : PE_Ptr) return PE_Ptr is
1599    begin
1600       --  If the left pattern is null, then we just add the alternation
1601       --  node with an index one greater than the right hand pattern.
1602
1603       if L = EOP then
1604          return new PE'(PC_Alt, R.Index + 1, EOP, R);
1605
1606       --  If the left pattern is non-null, then build a reference vector
1607       --  for its elements, and adjust their index values to acccomodate
1608       --  the right hand elements. Then add the alternation node.
1609
1610       else
1611          declare
1612             Refs : Ref_Array (1 .. L.Index);
1613
1614          begin
1615             Build_Ref_Array (L, Refs);
1616
1617             for J in Refs'Range loop
1618                Refs (J).Index := Refs (J).Index + R.Index;
1619             end loop;
1620          end;
1621
1622          return new PE'(PC_Alt, L.Index + 1, L, R);
1623       end if;
1624    end Alternate;
1625
1626    ---------
1627    -- Any --
1628    ---------
1629
1630    function Any (Str : String) return Pattern is
1631    begin
1632       return (AFC with 0, new PE'(PC_Any_CS, 1, EOP, To_Set (Str)));
1633    end Any;
1634
1635    function Any (Str : VString) return Pattern is
1636    begin
1637       return Any (S (Str));
1638    end Any;
1639
1640    function Any (Str : Character) return Pattern is
1641    begin
1642       return (AFC with 0, new PE'(PC_Any_CH, 1, EOP, Str));
1643    end Any;
1644
1645    function Any (Str : Character_Set) return Pattern is
1646    begin
1647       return (AFC with 0, new PE'(PC_Any_CS, 1, EOP, Str));
1648    end Any;
1649
1650    function Any (Str : access VString) return Pattern is
1651    begin
1652       return (AFC with 0, new PE'(PC_Any_VP, 1, EOP, VString_Ptr (Str)));
1653    end Any;
1654
1655    function Any (Str : VString_Func) return Pattern is
1656    begin
1657       return (AFC with 0, new PE'(PC_Any_VF, 1, EOP, Str));
1658    end Any;
1659
1660    ---------
1661    -- Arb --
1662    ---------
1663
1664    --    +---+
1665    --    | X |---->
1666    --    +---+
1667    --      .
1668    --      .
1669    --    +---+
1670    --    | Y |---->
1671    --    +---+
1672
1673    --  The PC_Arb_X element is numbered 2, and the PC_Arb_Y element is 1.
1674
1675    function Arb return Pattern is
1676       Y : constant PE_Ptr := new PE'(PC_Arb_Y, 1, EOP);
1677       X : constant PE_Ptr := new PE'(PC_Arb_X, 2, EOP, Y);
1678
1679    begin
1680       return (AFC with 1, X);
1681    end Arb;
1682
1683    -----------
1684    -- Arbno --
1685    -----------
1686
1687    function Arbno (P : PString) return Pattern is
1688    begin
1689       if P'Length = 0 then
1690          return (AFC with 0, EOP);
1691
1692       else
1693          return (AFC with 0, Arbno_Simple (S_To_PE (P)));
1694       end if;
1695    end Arbno;
1696
1697    function Arbno (P : PChar) return Pattern is
1698    begin
1699       return (AFC with 0, Arbno_Simple (C_To_PE (P)));
1700    end Arbno;
1701
1702    function Arbno (P : Pattern) return Pattern is
1703       Pat : constant PE_Ptr := Copy (P.P);
1704
1705    begin
1706       if P.Stk = 0
1707         and then OK_For_Simple_Arbno (Pat.Pcode)
1708       then
1709          return (AFC with 0, Arbno_Simple (Pat));
1710       end if;
1711
1712       --  This is the complex case, either the pattern makes stack entries
1713       --  or it is possible for the pattern to match the null string (more
1714       --  accurately, we don't know that this is not the case).
1715
1716       --      +--------------------------+
1717       --      |                          ^
1718       --      V                          |
1719       --    +---+                        |
1720       --    | X |---->                   |
1721       --    +---+                        |
1722       --      .                          |
1723       --      .                          |
1724       --    +---+     +---+     +---+    |
1725       --    | E |---->| P |---->| Y |--->+
1726       --    +---+     +---+     +---+
1727
1728       --  The node numbering of the constituent pattern P is not affected.
1729       --  Where N is the number of nodes in P, the Y node is numbered N + 1,
1730       --  the E node is N + 2, and the X node is N + 3.
1731
1732       declare
1733          E   : constant PE_Ptr := new PE'(PC_R_Enter, 0, EOP);
1734          X   : constant PE_Ptr := new PE'(PC_Arbno_X, 0, EOP, E);
1735          Y   : constant PE_Ptr := new PE'(PC_Arbno_Y, 0, X,   P.Stk + 3);
1736          EPY : constant PE_Ptr := Bracket (E, Pat, Y);
1737
1738       begin
1739          X.Alt := EPY;
1740          X.Index := EPY.Index + 1;
1741          return (AFC with P.Stk + 3, X);
1742       end;
1743    end Arbno;
1744
1745    ------------------
1746    -- Arbno_Simple --
1747    ------------------
1748
1749       --      +-------------+
1750       --      |             ^
1751       --      V             |
1752       --    +---+           |
1753       --    | S |---->      |
1754       --    +---+           |
1755       --      .             |
1756       --      .             |
1757       --    +---+           |
1758       --    | P |---------->+
1759       --    +---+
1760
1761    --  The node numbering of the constituent pattern P is not affected.
1762    --  The S node has a node number of P.Index + 1.
1763
1764    --  Note that we know that P cannot be EOP, because a null pattern
1765    --  does not meet the requirements for simple Arbno.
1766
1767    function Arbno_Simple (P : PE_Ptr) return PE_Ptr is
1768       S : constant PE_Ptr := new PE'(PC_Arbno_S, P.Index + 1, EOP, P);
1769
1770    begin
1771       Set_Successor (P, S);
1772       return S;
1773    end Arbno_Simple;
1774
1775    ---------
1776    -- Bal --
1777    ---------
1778
1779    function Bal return Pattern is
1780    begin
1781       return (AFC with 1, new PE'(PC_Bal, 1, EOP));
1782    end Bal;
1783
1784    -------------
1785    -- Bracket --
1786    -------------
1787
1788    function Bracket (E, P, A : PE_Ptr) return PE_Ptr is
1789    begin
1790       if P = EOP then
1791          E.Pthen := A;
1792          E.Index := 2;
1793          A.Index := 1;
1794
1795       else
1796          E.Pthen := P;
1797          Set_Successor (P, A);
1798          E.Index := P.Index + 2;
1799          A.Index := P.Index + 1;
1800       end if;
1801
1802       return E;
1803    end Bracket;
1804
1805    -----------
1806    -- Break --
1807    -----------
1808
1809    function Break (Str : String) return Pattern is
1810    begin
1811       return (AFC with 0, new PE'(PC_Break_CS, 1, EOP, To_Set (Str)));
1812    end Break;
1813
1814    function Break (Str : VString) return Pattern is
1815    begin
1816       return Break (S (Str));
1817    end Break;
1818
1819    function Break (Str : Character) return Pattern is
1820    begin
1821       return (AFC with 0, new PE'(PC_Break_CH, 1, EOP, Str));
1822    end Break;
1823
1824    function Break (Str : Character_Set) return Pattern is
1825    begin
1826       return (AFC with 0, new PE'(PC_Break_CS, 1, EOP, Str));
1827    end Break;
1828
1829    function Break (Str : access VString) return Pattern is
1830    begin
1831       return (AFC with 0, new PE'(PC_Break_VP, 1, EOP, VString_Ptr (Str)));
1832    end Break;
1833
1834    function Break (Str : VString_Func) return Pattern is
1835    begin
1836       return (AFC with 0, new PE'(PC_Break_VF, 1, EOP, Str));
1837    end Break;
1838
1839    ------------
1840    -- BreakX --
1841    ------------
1842
1843    function BreakX (Str : String) return Pattern is
1844    begin
1845       return BreakX_Make (new PE'(PC_BreakX_CS, 3, N, To_Set (Str)));
1846    end BreakX;
1847
1848    function BreakX (Str : VString) return Pattern is
1849    begin
1850       return BreakX (S (Str));
1851    end BreakX;
1852
1853    function BreakX (Str : Character) return Pattern is
1854    begin
1855       return BreakX_Make (new PE'(PC_BreakX_CH, 3, N, Str));
1856    end BreakX;
1857
1858    function BreakX (Str : Character_Set) return Pattern is
1859    begin
1860       return BreakX_Make (new PE'(PC_BreakX_CS, 3, N, Str));
1861    end BreakX;
1862
1863    function BreakX (Str : access VString) return Pattern is
1864    begin
1865       return BreakX_Make (new PE'(PC_BreakX_VP, 3, N, VString_Ptr (Str)));
1866    end BreakX;
1867
1868    function BreakX (Str : VString_Func) return Pattern is
1869    begin
1870       return BreakX_Make (new PE'(PC_BreakX_VF, 3, N, Str));
1871    end BreakX;
1872
1873    -----------------
1874    -- BreakX_Make --
1875    -----------------
1876
1877    --    +---+     +---+
1878    --    | B |---->| A |---->
1879    --    +---+     +---+
1880    --      ^         .
1881    --      |         .
1882    --      |       +---+
1883    --      +<------| X |
1884    --              +---+
1885
1886    --  The B node is numbered 3, the alternative node is 1, and the X
1887    --  node is 2.
1888
1889    function BreakX_Make (B : PE_Ptr) return Pattern is
1890       X : constant PE_Ptr := new PE'(PC_BreakX_X, 2, B);
1891       A : constant PE_Ptr := new PE'(PC_Alt,      1, EOP, X);
1892
1893    begin
1894       B.Pthen := A;
1895       return (AFC with 2, B);
1896    end BreakX_Make;
1897
1898    ---------------------
1899    -- Build_Ref_Array --
1900    ---------------------
1901
1902    procedure Build_Ref_Array (E : PE_Ptr; RA : out Ref_Array) is
1903
1904       procedure Record_PE (E : PE_Ptr);
1905       --  Record given pattern element if not already recorded in RA,
1906       --  and also record any referenced pattern elements recursively.
1907
1908       procedure Record_PE (E : PE_Ptr) is
1909       begin
1910          PutD ("  Record_PE called with PE_Ptr = " & Image (E));
1911
1912          if E = EOP or else RA (E.Index) /= null then
1913             Put_LineD (", nothing to do");
1914             return;
1915
1916          else
1917             Put_LineD (", recording" & IndexT'Image (E.Index));
1918             RA (E.Index) := E;
1919             Record_PE (E.Pthen);
1920
1921             if E.Pcode in PC_Has_Alt then
1922                Record_PE (E.Alt);
1923             end if;
1924          end if;
1925       end Record_PE;
1926
1927    --  Start of processing for Build_Ref_Array
1928
1929    begin
1930       New_LineD;
1931       Put_LineD ("Entering Build_Ref_Array");
1932       Record_PE (E);
1933       New_LineD;
1934    end Build_Ref_Array;
1935
1936    -------------
1937    -- C_To_PE --
1938    -------------
1939
1940    function C_To_PE (C : PChar) return PE_Ptr is
1941    begin
1942       return new PE'(PC_Char, 1, EOP, C);
1943    end C_To_PE;
1944
1945    ------------
1946    -- Cancel --
1947    ------------
1948
1949    function Cancel return Pattern is
1950    begin
1951       return (AFC with 0, new PE'(PC_Cancel, 1, EOP));
1952    end Cancel;
1953
1954    ------------
1955    -- Concat --
1956    ------------
1957
1958    --  Concat needs to traverse the left operand performing the following
1959    --  set of fixups:
1960
1961    --    a) Any successor pointers (Pthen fields) that are set to EOP are
1962    --       reset to point to the second operand.
1963
1964    --    b) Any PC_Arbno_Y node has its stack count field incremented
1965    --       by the parameter Incr provided for this purpose.
1966
1967    --    d) Num fields of all pattern elements in the left operand are
1968    --       adjusted to include the elements of the right operand.
1969
1970    --  Note: we do not use Set_Successor in the processing for Concat, since
1971    --  there is no point in doing two traversals, we may as well do everything
1972    --  at the same time.
1973
1974    function Concat (L, R : PE_Ptr; Incr : Natural) return PE_Ptr is
1975    begin
1976       if L = EOP then
1977          return R;
1978
1979       elsif R = EOP then
1980          return L;
1981
1982       else
1983          declare
1984             Refs : Ref_Array (1 .. L.Index);
1985             --  We build a reference array for L whose N'th element points to
1986             --  the pattern element of L whose original Index value is N.
1987
1988             P : PE_Ptr;
1989
1990          begin
1991             Build_Ref_Array (L, Refs);
1992
1993             for J in Refs'Range loop
1994                P := Refs (J);
1995
1996                P.Index := P.Index + R.Index;
1997
1998                if P.Pcode = PC_Arbno_Y then
1999                   P.Nat := P.Nat + Incr;
2000                end if;
2001
2002                if P.Pthen = EOP then
2003                   P.Pthen := R;
2004                end if;
2005
2006                if P.Pcode in PC_Has_Alt and then P.Alt = EOP then
2007                   P.Alt := R;
2008                end if;
2009             end loop;
2010          end;
2011
2012          return L;
2013       end if;
2014    end Concat;
2015
2016    ----------
2017    -- Copy --
2018    ----------
2019
2020    function Copy (P : PE_Ptr) return PE_Ptr is
2021    begin
2022       if P = null then
2023          Uninitialized_Pattern;
2024
2025       else
2026          declare
2027             Refs : Ref_Array (1 .. P.Index);
2028             --  References to elements in P, indexed by Index field
2029
2030             Copy : Ref_Array (1 .. P.Index);
2031             --  Holds copies of elements of P, indexed by Index field.
2032
2033             E : PE_Ptr;
2034
2035          begin
2036             Build_Ref_Array (P, Refs);
2037
2038             --  Now copy all nodes
2039
2040             for J in Refs'Range loop
2041                Copy (J) := new PE'(Refs (J).all);
2042             end loop;
2043
2044             --  Adjust all internal references
2045
2046             for J in Copy'Range loop
2047                E := Copy (J);
2048
2049                --  Adjust successor pointer to point to copy
2050
2051                if E.Pthen /= EOP then
2052                   E.Pthen := Copy (E.Pthen.Index);
2053                end if;
2054
2055                --  Adjust Alt pointer if there is one to point to copy
2056
2057                if E.Pcode in PC_Has_Alt and then E.Alt /= EOP then
2058                   E.Alt := Copy (E.Alt.Index);
2059                end if;
2060
2061                --  Copy referenced string
2062
2063                if E.Pcode = PC_String then
2064                   E.Str := new String'(E.Str.all);
2065                end if;
2066             end loop;
2067
2068             return Copy (P.Index);
2069          end;
2070       end if;
2071    end Copy;
2072
2073    ----------
2074    -- Dump --
2075    ----------
2076
2077    procedure Dump (P : Pattern) is
2078
2079       subtype Count is Ada.Text_IO.Count;
2080       Scol : Count;
2081       --  Used to keep track of column in dump output
2082
2083       Refs : Ref_Array (1 .. P.P.Index);
2084       --  We build a reference array whose N'th element points to the
2085       --  pattern element whose Index value is N.
2086
2087       Cols : Natural := 2;
2088       --  Number of columns used for pattern numbers, minimum is 2
2089
2090       E : PE_Ptr;
2091
2092       procedure Write_Node_Id (E : PE_Ptr);
2093       --  Writes out a string identifying the given pattern element.
2094
2095       procedure Write_Node_Id (E : PE_Ptr) is
2096       begin
2097          if E = EOP then
2098             Put ("EOP");
2099
2100             for J in 4 .. Cols loop
2101                Put (' ');
2102             end loop;
2103
2104          else
2105             declare
2106                Str : String (1 .. Cols);
2107                N   : Natural := Natural (E.Index);
2108
2109             begin
2110                Put ("#");
2111
2112                for J in reverse Str'Range loop
2113                   Str (J) := Character'Val (48 + N mod 10);
2114                   N := N / 10;
2115                end loop;
2116
2117                Put (Str);
2118             end;
2119          end if;
2120       end Write_Node_Id;
2121
2122    begin
2123       New_Line;
2124       Put ("Pattern Dump Output (pattern at " &
2125            Image (P'Address) &
2126            ", S = " & Natural'Image (P.Stk) & ')');
2127
2128       Scol := Col;
2129       New_Line;
2130
2131       while Col < Scol loop
2132          Put ('-');
2133       end loop;
2134
2135       New_Line;
2136
2137       --  If uninitialized pattern, dump line and we are done
2138
2139       if P.P = null then
2140          Put_Line ("Uninitialized pattern value");
2141          return;
2142       end if;
2143
2144       --  If null pattern, just dump it and we are all done
2145
2146       if P.P = EOP then
2147          Put_Line ("EOP (null pattern)");
2148          return;
2149       end if;
2150
2151       Build_Ref_Array (P.P, Refs);
2152
2153       --  Set number of columns required for node numbers
2154
2155       while 10 ** Cols - 1 < Integer (P.P.Index) loop
2156          Cols := Cols + 1;
2157       end loop;
2158
2159       --  Now dump the nodes in reverse sequence. We output them in reverse
2160       --  sequence since this corresponds to the natural order used to
2161       --  construct the patterns.
2162
2163       for J in reverse Refs'Range loop
2164          E := Refs (J);
2165          Write_Node_Id (E);
2166          Set_Col (Count (Cols) + 4);
2167          Put (Image (E));
2168          Put ("  ");
2169          Put (Pattern_Code'Image (E.Pcode));
2170          Put ("  ");
2171          Set_Col (21 + Count (Cols) + Address_Image_Length);
2172          Write_Node_Id (E.Pthen);
2173          Set_Col (24 + 2 * Count (Cols) + Address_Image_Length);
2174
2175          case E.Pcode is
2176
2177             when PC_Alt     |
2178                  PC_Arb_X   |
2179                  PC_Arbno_S |
2180                  PC_Arbno_X =>
2181                Write_Node_Id (E.Alt);
2182
2183             when PC_Rpat =>
2184                Put (Str_PP (E.PP));
2185
2186             when PC_Pred_Func =>
2187                Put (Str_BF (E.BF));
2188
2189             when PC_Assign_Imm |
2190                  PC_Assign_OnM |
2191                  PC_Any_VP     |
2192                  PC_Break_VP   |
2193                  PC_BreakX_VP  |
2194                  PC_NotAny_VP  |
2195                  PC_NSpan_VP   |
2196                  PC_Span_VP    |
2197                  PC_String_VP  =>
2198                Put (Str_VP (E.VP));
2199
2200             when PC_Write_Imm  |
2201                  PC_Write_OnM =>
2202                Put (Str_FP (E.FP));
2203
2204             when PC_String =>
2205                Put (Image (E.Str.all));
2206
2207             when PC_String_2 =>
2208                Put (Image (E.Str2));
2209
2210             when PC_String_3 =>
2211                Put (Image (E.Str3));
2212
2213             when PC_String_4 =>
2214                Put (Image (E.Str4));
2215
2216             when PC_String_5 =>
2217                Put (Image (E.Str5));
2218
2219             when PC_String_6 =>
2220                Put (Image (E.Str6));
2221
2222             when PC_Setcur =>
2223                Put (Str_NP (E.Var));
2224
2225             when PC_Any_CH      |
2226                  PC_Break_CH    |
2227                  PC_BreakX_CH   |
2228                  PC_Char        |
2229                  PC_NotAny_CH   |
2230                  PC_NSpan_CH    |
2231                  PC_Span_CH     =>
2232                Put (''' & E.Char & ''');
2233
2234             when PC_Any_CS      |
2235                  PC_Break_CS    |
2236                  PC_BreakX_CS   |
2237                  PC_NotAny_CS   |
2238                  PC_NSpan_CS    |
2239                  PC_Span_CS     =>
2240                Put ('"' & To_Sequence (E.CS) & '"');
2241
2242             when PC_Arbno_Y     |
2243                  PC_Len_Nat     |
2244                  PC_Pos_Nat     |
2245                  PC_RPos_Nat    |
2246                  PC_RTab_Nat    |
2247                  PC_Tab_Nat     =>
2248                Put (S (E.Nat));
2249
2250             when PC_Pos_NF      |
2251                  PC_Len_NF      |
2252                  PC_RPos_NF     |
2253                  PC_RTab_NF     |
2254                  PC_Tab_NF      =>
2255                Put (Str_NF (E.NF));
2256
2257             when PC_Pos_NP      |
2258                  PC_Len_NP      |
2259                  PC_RPos_NP     |
2260                  PC_RTab_NP     |
2261                  PC_Tab_NP      =>
2262                Put (Str_NP (E.NP));
2263
2264             when PC_Any_VF      |
2265                  PC_Break_VF    |
2266                  PC_BreakX_VF   |
2267                  PC_NotAny_VF   |
2268                  PC_NSpan_VF    |
2269                  PC_Span_VF     |
2270                  PC_String_VF   =>
2271                Put (Str_VF (E.VF));
2272
2273             when others => null;
2274
2275          end case;
2276
2277          New_Line;
2278       end loop;
2279
2280       New_Line;
2281    end Dump;
2282
2283    ----------
2284    -- Fail --
2285    ----------
2286
2287    function Fail return Pattern is
2288    begin
2289       return (AFC with 0, new PE'(PC_Fail, 1, EOP));
2290    end Fail;
2291
2292    -----------
2293    -- Fence --
2294    -----------
2295
2296    --  Simple case
2297
2298    function Fence return Pattern is
2299    begin
2300       return (AFC with 1, new PE'(PC_Fence, 1, EOP));
2301    end Fence;
2302
2303    --  Function case
2304
2305    --    +---+     +---+     +---+
2306    --    | E |---->| P |---->| X |---->
2307    --    +---+     +---+     +---+
2308
2309    --  The node numbering of the constituent pattern P is not affected.
2310    --  Where N is the number of nodes in P, the X node is numbered N + 1,
2311    --  and the E node is N + 2.
2312
2313    function Fence (P : Pattern) return Pattern is
2314       Pat : constant PE_Ptr := Copy (P.P);
2315       E   : constant PE_Ptr := new PE'(PC_R_Enter, 0, EOP);
2316       X   : constant PE_Ptr := new PE'(PC_Fence_X, 0, EOP);
2317
2318    begin
2319       return (AFC with P.Stk + 1, Bracket (E, Pat, X));
2320    end Fence;
2321
2322    --------------
2323    -- Finalize --
2324    --------------
2325
2326    procedure Finalize (Object : in out Pattern) is
2327
2328       procedure Free is new Unchecked_Deallocation (PE, PE_Ptr);
2329       procedure Free is new Unchecked_Deallocation (String, String_Ptr);
2330
2331    begin
2332       --  Nothing to do if already freed
2333
2334       if Object.P = null then
2335          return;
2336
2337       --  Otherwise we must free all elements
2338
2339       else
2340          declare
2341             Refs : Ref_Array (1 .. Object.P.Index);
2342             --  References to elements in pattern to be finalized
2343
2344          begin
2345             Build_Ref_Array (Object.P, Refs);
2346
2347             for J in Refs'Range loop
2348                if Refs (J).Pcode = PC_String then
2349                   Free (Refs (J).Str);
2350                end if;
2351
2352                Free (Refs (J));
2353             end loop;
2354
2355             Object.P := null;
2356          end;
2357       end if;
2358    end Finalize;
2359
2360    -----------
2361    -- Image --
2362    -----------
2363
2364    function Image (P : PE_Ptr) return String is
2365    begin
2366       return Image (To_Address (P));
2367    end Image;
2368
2369    function Image (P : Pattern) return String is
2370    begin
2371       return S (Image (P));
2372    end Image;
2373
2374    function Image (P : Pattern) return VString is
2375
2376       Kill_Ampersand : Boolean := False;
2377       --  Set True to delete next & to be output to Result
2378
2379       Result : VString := Nul;
2380       --  The result is accumulated here, using Append
2381
2382       Refs : Ref_Array (1 .. P.P.Index);
2383       --  We build a reference array whose N'th element points to the
2384       --  pattern element whose Index value is N.
2385
2386       procedure Delete_Ampersand;
2387       --  Deletes the ampersand at the end of Result
2388
2389       procedure Image_Seq (E : PE_Ptr; Succ : PE_Ptr; Paren : Boolean);
2390       --  E refers to a pattern structure whose successor is given by Succ.
2391       --  This procedure appends to Result a representation of this pattern.
2392       --  The Paren parameter indicates whether parentheses are required if
2393       --  the output is more than one element.
2394
2395       procedure Image_One (E : in out PE_Ptr);
2396       --  E refers to a pattern structure. This procedure appends to Result
2397       --  a representation of the single simple or compound pattern structure
2398       --  at the start of E and updates E to point to its successor.
2399
2400       ----------------------
2401       -- Delete_Ampersand --
2402       ----------------------
2403
2404       procedure Delete_Ampersand is
2405          L : constant Natural := Length (Result);
2406
2407       begin
2408          if L > 2 then
2409             Delete (Result, L - 1, L);
2410          end if;
2411       end Delete_Ampersand;
2412
2413       ---------------
2414       -- Image_One --
2415       ---------------
2416
2417       procedure Image_One (E : in out PE_Ptr) is
2418
2419          ER : PE_Ptr := E.Pthen;
2420          --  Successor set as result in E unless reset
2421
2422       begin
2423          case E.Pcode is
2424
2425             when PC_Cancel =>
2426                Append (Result, "Cancel");
2427
2428             when PC_Alt => Alt : declare
2429
2430                Elmts_In_L : constant IndexT := E.Pthen.Index - E.Alt.Index;
2431                --  Number of elements in left pattern of alternation.
2432
2433                Lowest_In_L : constant IndexT := E.Index - Elmts_In_L;
2434                --  Number of lowest index in elements of left pattern
2435
2436                E1 : PE_Ptr;
2437
2438             begin
2439                --  The successor of the alternation node must have a lower
2440                --  index than any node that is in the left pattern or a
2441                --  higher index than the alternation node itself.
2442
2443                while ER /= EOP
2444                  and then ER.Index >= Lowest_In_L
2445                  and then ER.Index < E.Index
2446                loop
2447                   ER := ER.Pthen;
2448                end loop;
2449
2450                Append (Result, '(');
2451
2452                E1 := E;
2453                loop
2454                   Image_Seq (E1.Pthen, ER, False);
2455                   Append (Result, " or ");
2456                   E1 := E1.Alt;
2457                   exit when E1.Pcode /= PC_Alt;
2458                end loop;
2459
2460                Image_Seq (E1, ER, False);
2461                Append (Result, ')');
2462             end Alt;
2463
2464             when PC_Any_CS =>
2465                Append (Result, "Any (" & Image (To_Sequence (E.CS)) & ')');
2466
2467             when PC_Any_VF =>
2468                Append (Result, "Any (" & Str_VF (E.VF) & ')');
2469
2470             when PC_Any_VP =>
2471                Append (Result, "Any (" & Str_VP (E.VP) & ')');
2472
2473             when PC_Arb_X =>
2474                Append (Result, "Arb");
2475
2476             when PC_Arbno_S =>
2477                Append (Result, "Arbno (");
2478                Image_Seq (E.Alt, E, False);
2479                Append (Result, ')');
2480
2481             when PC_Arbno_X =>
2482                Append (Result, "Arbno (");
2483                Image_Seq (E.Alt.Pthen, Refs (E.Index - 2), False);
2484                Append (Result, ')');
2485
2486             when PC_Assign_Imm =>
2487                Delete_Ampersand;
2488                Append (Result, "* " & Str_VP (Refs (E.Index - 1).VP));
2489
2490             when PC_Assign_OnM =>
2491                Delete_Ampersand;
2492                Append (Result, "** " & Str_VP (Refs (E.Index - 1).VP));
2493
2494             when PC_Any_CH =>
2495                Append (Result, "Any ('" & E.Char & "')");
2496
2497             when PC_Bal =>
2498                Append (Result, "Bal");
2499
2500             when PC_Break_CH =>
2501                Append (Result, "Break ('" & E.Char & "')");
2502
2503             when PC_Break_CS =>
2504                Append (Result, "Break (" & Image (To_Sequence (E.CS)) & ')');
2505
2506             when PC_Break_VF =>
2507                Append (Result, "Break (" & Str_VF (E.VF) & ')');
2508
2509             when PC_Break_VP =>
2510                Append (Result, "Break (" & Str_VP (E.VP) & ')');
2511
2512             when PC_BreakX_CH =>
2513                Append (Result, "BreakX ('" & E.Char & "')");
2514                ER := ER.Pthen;
2515
2516             when PC_BreakX_CS =>
2517                Append (Result, "BreakX (" & Image (To_Sequence (E.CS)) & ')');
2518                ER := ER.Pthen;
2519
2520             when PC_BreakX_VF =>
2521                Append (Result, "BreakX (" & Str_VF (E.VF) & ')');
2522                ER := ER.Pthen;
2523
2524             when PC_BreakX_VP =>
2525                Append (Result, "BreakX (" & Str_VP (E.VP) & ')');
2526                ER := ER.Pthen;
2527
2528             when PC_Char =>
2529                Append (Result, ''' & E.Char & ''');
2530
2531             when PC_Fail =>
2532                Append (Result, "Fail");
2533
2534             when PC_Fence =>
2535                Append (Result, "Fence");
2536
2537             when PC_Fence_X =>
2538                Append (Result, "Fence (");
2539                Image_Seq (E.Pthen, Refs (E.Index - 1), False);
2540                Append (Result, ")");
2541                ER := Refs (E.Index - 1).Pthen;
2542
2543             when PC_Len_Nat =>
2544                Append (Result, "Len (" & E.Nat & ')');
2545
2546             when PC_Len_NF =>
2547                Append (Result, "Len (" & Str_NF (E.NF) & ')');
2548
2549             when PC_Len_NP =>
2550                Append (Result, "Len (" & Str_NP (E.NP) & ')');
2551
2552             when PC_NotAny_CH =>
2553                Append (Result, "NotAny ('" & E.Char & "')");
2554
2555             when PC_NotAny_CS =>
2556                Append (Result, "NotAny (" & Image (To_Sequence (E.CS)) & ')');
2557
2558             when PC_NotAny_VF =>
2559                Append (Result, "NotAny (" & Str_VF (E.VF) & ')');
2560
2561             when PC_NotAny_VP =>
2562                Append (Result, "NotAny (" & Str_VP (E.VP) & ')');
2563
2564             when PC_NSpan_CH =>
2565                Append (Result, "NSpan ('" & E.Char & "')");
2566
2567             when PC_NSpan_CS =>
2568                Append (Result, "NSpan (" & Image (To_Sequence (E.CS)) & ')');
2569
2570             when PC_NSpan_VF =>
2571                Append (Result, "NSpan (" & Str_VF (E.VF) & ')');
2572
2573             when PC_NSpan_VP =>
2574                Append (Result, "NSpan (" & Str_VP (E.VP) & ')');
2575
2576             when PC_Null =>
2577                Append (Result, """""");
2578
2579             when PC_Pos_Nat =>
2580                Append (Result, "Pos (" & E.Nat & ')');
2581
2582             when PC_Pos_NF =>
2583                Append (Result, "Pos (" & Str_NF (E.NF) & ')');
2584
2585             when PC_Pos_NP =>
2586                Append (Result, "Pos (" & Str_NP (E.NP) & ')');
2587
2588             when PC_R_Enter =>
2589                Kill_Ampersand := True;
2590
2591             when PC_Rest =>
2592                Append (Result, "Rest");
2593
2594             when PC_Rpat =>
2595                Append (Result, "(+ " & Str_PP (E.PP) & ')');
2596
2597             when PC_Pred_Func =>
2598                Append (Result, "(+ " & Str_BF (E.BF) & ')');
2599
2600             when PC_RPos_Nat =>
2601                Append (Result, "RPos (" & E.Nat & ')');
2602
2603             when PC_RPos_NF =>
2604                Append (Result, "RPos (" & Str_NF (E.NF) & ')');
2605
2606             when PC_RPos_NP =>
2607                Append (Result, "RPos (" & Str_NP (E.NP) & ')');
2608
2609             when PC_RTab_Nat =>
2610                Append (Result, "RTab (" & E.Nat & ')');
2611
2612             when PC_RTab_NF =>
2613                Append (Result, "RTab (" & Str_NF (E.NF) & ')');
2614
2615             when PC_RTab_NP =>
2616                Append (Result, "RTab (" & Str_NP (E.NP) & ')');
2617
2618             when PC_Setcur =>
2619                Append (Result, "Setcur (" & Str_NP (E.Var) & ')');
2620
2621             when PC_Span_CH =>
2622                Append (Result, "Span ('" & E.Char & "')");
2623
2624             when PC_Span_CS =>
2625                Append (Result, "Span (" & Image (To_Sequence (E.CS)) & ')');
2626
2627             when PC_Span_VF =>
2628                Append (Result, "Span (" & Str_VF (E.VF) & ')');
2629
2630             when PC_Span_VP =>
2631                Append (Result, "Span (" & Str_VP (E.VP) & ')');
2632
2633             when PC_String =>
2634                Append (Result, Image (E.Str.all));
2635
2636             when PC_String_2 =>
2637                Append (Result, Image (E.Str2));
2638
2639             when PC_String_3 =>
2640                Append (Result, Image (E.Str3));
2641
2642             when PC_String_4 =>
2643                Append (Result, Image (E.Str4));
2644
2645             when PC_String_5 =>
2646                Append (Result, Image (E.Str5));
2647
2648             when PC_String_6 =>
2649                Append (Result, Image (E.Str6));
2650
2651             when PC_String_VF =>
2652                Append (Result, "(+" &  Str_VF (E.VF) & ')');
2653
2654             when PC_String_VP =>
2655                Append (Result, "(+" & Str_VP (E.VP) & ')');
2656
2657             when PC_Succeed =>
2658                Append (Result, "Succeed");
2659
2660             when PC_Tab_Nat =>
2661                Append (Result, "Tab (" & E.Nat & ')');
2662
2663             when PC_Tab_NF =>
2664                Append (Result, "Tab (" & Str_NF (E.NF) & ')');
2665
2666             when PC_Tab_NP =>
2667                Append (Result, "Tab (" & Str_NP (E.NP) & ')');
2668
2669             when PC_Write_Imm =>
2670                Append (Result, '(');
2671                Image_Seq (E, Refs (E.Index - 1), True);
2672                Append (Result, " * " & Str_FP (Refs (E.Index - 1).FP));
2673                ER := Refs (E.Index - 1).Pthen;
2674
2675             when PC_Write_OnM =>
2676                Append (Result, '(');
2677                Image_Seq (E.Pthen, Refs (E.Index - 1), True);
2678                Append (Result, " ** " & Str_FP (Refs (E.Index - 1).FP));
2679                ER := Refs (E.Index - 1).Pthen;
2680
2681             --  Other pattern codes should not appear as leading elements
2682
2683             when PC_Arb_Y      |
2684                  PC_Arbno_Y    |
2685                  PC_Assign     |
2686                  PC_BreakX_X   |
2687                  PC_EOP        |
2688                  PC_Fence_Y    |
2689                  PC_R_Remove   |
2690                  PC_R_Restore  |
2691                  PC_Unanchored =>
2692                Append (Result, "???");
2693
2694          end case;
2695
2696          E := ER;
2697       end Image_One;
2698
2699       ---------------
2700       -- Image_Seq --
2701       ---------------
2702
2703       procedure Image_Seq (E : PE_Ptr; Succ : PE_Ptr; Paren : Boolean) is
2704          Indx : constant Natural := Length (Result);
2705          E1   : PE_Ptr  := E;
2706          Mult : Boolean := False;
2707
2708       begin
2709          --  The image of EOP is "" (the null string)
2710
2711          if E = EOP then
2712             Append (Result, """""");
2713
2714          --  Else generate appropriate concatenation sequence
2715
2716          else
2717             loop
2718                Image_One (E1);
2719                exit when E1 = Succ;
2720                exit when E1 = EOP;
2721                Mult := True;
2722
2723                if Kill_Ampersand then
2724                   Kill_Ampersand := False;
2725                else
2726                   Append (Result, " & ");
2727                end if;
2728             end loop;
2729          end if;
2730
2731          if Mult and Paren then
2732             Insert (Result, Indx + 1, "(");
2733             Append (Result, ")");
2734          end if;
2735       end Image_Seq;
2736
2737    --  Start of processing for Image
2738
2739    begin
2740       Build_Ref_Array (P.P, Refs);
2741       Image_Seq (P.P, EOP, False);
2742       return Result;
2743    end Image;
2744
2745    -----------
2746    -- Is_In --
2747    -----------
2748
2749    function Is_In (C : Character; Str : String) return Boolean is
2750    begin
2751       for J in Str'Range loop
2752          if Str (J) = C then
2753             return True;
2754          end if;
2755       end loop;
2756
2757       return False;
2758    end Is_In;
2759
2760    ---------
2761    -- Len --
2762    ---------
2763
2764    function Len (Count : Natural) return Pattern is
2765    begin
2766       --  Note, the following is not just an optimization, it is needed
2767       --  to ensure that Arbno (Len (0)) does not generate an infinite
2768       --  matching loop (since PC_Len_Nat is OK_For_Simple_Arbno).
2769
2770       if Count = 0 then
2771          return (AFC with 0, new PE'(PC_Null, 1, EOP));
2772
2773       else
2774          return (AFC with 0, new PE'(PC_Len_Nat, 1, EOP, Count));
2775       end if;
2776    end Len;
2777
2778    function Len (Count : Natural_Func) return Pattern is
2779    begin
2780       return (AFC with 0, new PE'(PC_Len_NF, 1, EOP, Count));
2781    end Len;
2782
2783    function Len (Count : access Natural) return Pattern is
2784    begin
2785       return (AFC with 0, new PE'(PC_Len_NP, 1, EOP, Natural_Ptr (Count)));
2786    end Len;
2787
2788    -----------------
2789    -- Logic_Error --
2790    -----------------
2791
2792    procedure Logic_Error is
2793    begin
2794       Raise_Exception
2795         (Program_Error'Identity,
2796          "Internal logic error in GNAT.Spitbol.Patterns");
2797    end Logic_Error;
2798
2799    -----------
2800    -- Match --
2801    -----------
2802
2803    function Match
2804      (Subject : VString;
2805       Pat     : Pattern)
2806       return    Boolean
2807    is
2808       Start, Stop : Natural;
2809
2810    begin
2811       if Debug_Mode then
2812          XMatchD (Get_String (Subject).all, Pat.P, Pat.Stk, Start, Stop);
2813       else
2814          XMatch  (Get_String (Subject).all, Pat.P, Pat.Stk, Start, Stop);
2815       end if;
2816
2817       return Start /= 0;
2818    end Match;
2819
2820    function Match
2821      (Subject : String;
2822       Pat     : Pattern)
2823       return    Boolean
2824    is
2825       Start, Stop : Natural;
2826       subtype String1 is String (1 .. Subject'Length);
2827
2828    begin
2829       if Debug_Mode then
2830          XMatchD (String1 (Subject), Pat.P, Pat.Stk, Start, Stop);
2831       else
2832          XMatch  (String1 (Subject), Pat.P, Pat.Stk, Start, Stop);
2833       end if;
2834
2835       return Start /= 0;
2836    end Match;
2837
2838    function Match
2839      (Subject : VString_Var;
2840       Pat     : Pattern;
2841       Replace : VString)
2842       return    Boolean
2843    is
2844       Start, Stop : Natural;
2845
2846    begin
2847       if Debug_Mode then
2848          XMatchD (Get_String (Subject).all, Pat.P, Pat.Stk, Start, Stop);
2849       else
2850          XMatch  (Get_String (Subject).all, Pat.P, Pat.Stk, Start, Stop);
2851       end if;
2852
2853       if Start = 0 then
2854          return False;
2855       else
2856          Replace_Slice
2857            (Subject'Unrestricted_Access.all,
2858             Start, Stop, Get_String (Replace).all);
2859          return True;
2860       end if;
2861    end Match;
2862
2863    function Match
2864      (Subject : VString_Var;
2865       Pat     : Pattern;
2866       Replace : String)
2867       return    Boolean
2868    is
2869       Start, Stop : Natural;
2870
2871    begin
2872       if Debug_Mode then
2873          XMatchD (Get_String (Subject).all, Pat.P, Pat.Stk, Start, Stop);
2874       else
2875          XMatch  (Get_String (Subject).all, Pat.P, Pat.Stk, Start, Stop);
2876       end if;
2877
2878       if Start = 0 then
2879          return False;
2880       else
2881          Replace_Slice
2882            (Subject'Unrestricted_Access.all, Start, Stop, Replace);
2883          return True;
2884       end if;
2885    end Match;
2886
2887    procedure Match
2888      (Subject : VString;
2889       Pat     : Pattern)
2890    is
2891       Start, Stop : Natural;
2892
2893    begin
2894       if Debug_Mode then
2895          XMatchD (Get_String (Subject).all, Pat.P, Pat.Stk, Start, Stop);
2896       else
2897          XMatch  (Get_String (Subject).all, Pat.P, Pat.Stk, Start, Stop);
2898       end if;
2899
2900    end Match;
2901
2902    procedure Match
2903      (Subject : String;
2904       Pat     : Pattern)
2905    is
2906       Start, Stop : Natural;
2907       subtype String1 is String (1 .. Subject'Length);
2908    begin
2909       if Debug_Mode then
2910          XMatchD (String1 (Subject), Pat.P, Pat.Stk, Start, Stop);
2911       else
2912          XMatch  (String1 (Subject), Pat.P, Pat.Stk, Start, Stop);
2913       end if;
2914    end Match;
2915
2916    procedure Match
2917      (Subject : in out VString;
2918       Pat     : Pattern;
2919       Replace : VString)
2920    is
2921       Start, Stop : Natural;
2922
2923    begin
2924       if Debug_Mode then
2925          XMatchD (Get_String (Subject).all, Pat.P, Pat.Stk, Start, Stop);
2926       else
2927          XMatch  (Get_String (Subject).all, Pat.P, Pat.Stk, Start, Stop);
2928       end if;
2929
2930       if Start /= 0 then
2931          Replace_Slice (Subject, Start, Stop, Get_String (Replace).all);
2932       end if;
2933    end Match;
2934
2935    procedure Match
2936      (Subject : in out VString;
2937       Pat     : Pattern;
2938       Replace : String)
2939    is
2940       Start, Stop : Natural;
2941
2942    begin
2943       if Debug_Mode then
2944          XMatchD (Get_String (Subject).all, Pat.P, Pat.Stk, Start, Stop);
2945       else
2946          XMatch  (Get_String (Subject).all, Pat.P, Pat.Stk, Start, Stop);
2947       end if;
2948
2949       if Start /= 0 then
2950          Replace_Slice (Subject, Start, Stop, Replace);
2951       end if;
2952    end Match;
2953
2954    function Match
2955      (Subject : VString;
2956       Pat     : PString)
2957       return    Boolean
2958    is
2959       Pat_Len : constant Natural       := Pat'Length;
2960       Sub_Len : constant Natural       := Length (Subject);
2961       Sub_Str : constant String_Access := Get_String (Subject);
2962
2963    begin
2964       if Anchored_Mode then
2965          if Pat_Len > Sub_Len then
2966             return False;
2967          else
2968             return Pat = Sub_Str.all (1 .. Pat_Len);
2969          end if;
2970
2971       else
2972          for J in 1 .. Sub_Len - Pat_Len + 1 loop
2973             if Pat = Sub_Str.all (J .. J + (Pat_Len - 1)) then
2974                return True;
2975             end if;
2976          end loop;
2977
2978          return False;
2979       end if;
2980    end Match;
2981
2982    function Match
2983      (Subject : String;
2984       Pat     : PString)
2985       return    Boolean
2986    is
2987       Pat_Len : constant Natural := Pat'Length;
2988       Sub_Len : constant Natural := Subject'Length;
2989       SFirst  : constant Natural := Subject'First;
2990
2991    begin
2992       if Anchored_Mode then
2993          if Pat_Len > Sub_Len then
2994             return False;
2995          else
2996             return Pat = Subject (SFirst .. SFirst + Pat_Len - 1);
2997          end if;
2998
2999       else
3000          for J in SFirst .. SFirst + Sub_Len - Pat_Len loop
3001             if Pat = Subject (J .. J + (Pat_Len - 1)) then
3002                return True;
3003             end if;
3004          end loop;
3005
3006          return False;
3007       end if;
3008    end Match;
3009
3010    function Match
3011      (Subject : VString_Var;
3012       Pat     : PString;
3013       Replace : VString)
3014       return    Boolean
3015    is
3016       Start, Stop : Natural;
3017
3018    begin
3019       if Debug_Mode then
3020          XMatchD (Get_String (Subject).all, S_To_PE (Pat), 0, Start, Stop);
3021       else
3022          XMatch  (Get_String (Subject).all, S_To_PE (Pat), 0, Start, Stop);
3023       end if;
3024
3025       if Start = 0 then
3026          return False;
3027       else
3028          Replace_Slice
3029            (Subject'Unrestricted_Access.all,
3030             Start, Stop, Get_String (Replace).all);
3031          return True;
3032       end if;
3033    end Match;
3034
3035    function Match
3036      (Subject : VString_Var;
3037       Pat     : PString;
3038       Replace : String)
3039       return    Boolean
3040    is
3041       Start, Stop : Natural;
3042
3043    begin
3044       if Debug_Mode then
3045          XMatchD (Get_String (Subject).all, S_To_PE (Pat), 0, Start, Stop);
3046       else
3047          XMatch  (Get_String (Subject).all, S_To_PE (Pat), 0, Start, Stop);
3048       end if;
3049
3050       if Start = 0 then
3051          return False;
3052       else
3053          Replace_Slice
3054            (Subject'Unrestricted_Access.all, Start, Stop, Replace);
3055          return True;
3056       end if;
3057    end Match;
3058
3059    procedure Match
3060      (Subject : VString;
3061       Pat     : PString)
3062    is
3063       Start, Stop : Natural;
3064
3065    begin
3066       if Debug_Mode then
3067          XMatchD (Get_String (Subject).all, S_To_PE (Pat), 0, Start, Stop);
3068       else
3069          XMatch  (Get_String (Subject).all, S_To_PE (Pat), 0, Start, Stop);
3070       end if;
3071    end Match;
3072
3073    procedure Match
3074      (Subject : String;
3075       Pat     : PString)
3076    is
3077       Start, Stop : Natural;
3078       subtype String1 is String (1 .. Subject'Length);
3079
3080    begin
3081       if Debug_Mode then
3082          XMatchD (String1 (Subject), S_To_PE (Pat), 0, Start, Stop);
3083       else
3084          XMatch  (String1 (Subject), S_To_PE (Pat), 0, Start, Stop);
3085       end if;
3086    end Match;
3087
3088    procedure Match
3089      (Subject : in out VString;
3090       Pat     : PString;
3091       Replace : VString)
3092    is
3093       Start, Stop : Natural;
3094
3095    begin
3096       if Debug_Mode then
3097          XMatchD (Get_String (Subject).all, S_To_PE (Pat), 0, Start, Stop);
3098       else
3099          XMatch  (Get_String (Subject).all, S_To_PE (Pat), 0, Start, Stop);
3100       end if;
3101
3102       if Start /= 0 then
3103          Replace_Slice (Subject, Start, Stop, Get_String (Replace).all);
3104       end if;
3105    end Match;
3106
3107    procedure Match
3108      (Subject : in out VString;
3109       Pat     : PString;
3110       Replace : String)
3111    is
3112       Start, Stop : Natural;
3113
3114    begin
3115       if Debug_Mode then
3116          XMatchD (Get_String (Subject).all, S_To_PE (Pat), 0, Start, Stop);
3117       else
3118          XMatch  (Get_String (Subject).all, S_To_PE (Pat), 0, Start, Stop);
3119       end if;
3120
3121       if Start /= 0 then
3122          Replace_Slice (Subject, Start, Stop, Replace);
3123       end if;
3124    end Match;
3125
3126    function Match
3127      (Subject : VString_Var;
3128       Pat     : Pattern;
3129       Result  : Match_Result_Var)
3130       return    Boolean
3131    is
3132       Start, Stop : Natural;
3133
3134    begin
3135       if Debug_Mode then
3136          XMatchD (Get_String (Subject).all, Pat.P, Pat.Stk, Start, Stop);
3137       else
3138          XMatch  (Get_String (Subject).all, Pat.P, Pat.Stk, Start, Stop);
3139       end if;
3140
3141       if Start = 0 then
3142          Result'Unrestricted_Access.all.Var := null;
3143          return False;
3144
3145       else
3146          Result'Unrestricted_Access.all.Var   := Subject'Unrestricted_Access;
3147          Result'Unrestricted_Access.all.Start := Start;
3148          Result'Unrestricted_Access.all.Stop  := Stop;
3149          return True;
3150       end if;
3151    end Match;
3152
3153    procedure Match
3154      (Subject : in out VString;
3155       Pat     : Pattern;
3156       Result  : out Match_Result)
3157    is
3158       Start, Stop : Natural;
3159
3160    begin
3161       if Debug_Mode then
3162          XMatchD (Get_String (Subject).all, Pat.P, Pat.Stk, Start, Stop);
3163       else
3164          XMatch  (Get_String (Subject).all, Pat.P, Pat.Stk, Start, Stop);
3165       end if;
3166
3167       if Start = 0 then
3168          Result.Var := null;
3169
3170       else
3171          Result.Var   := Subject'Unrestricted_Access;
3172          Result.Start := Start;
3173          Result.Stop  := Stop;
3174       end if;
3175    end Match;
3176
3177    ---------------
3178    -- New_LineD --
3179    ---------------
3180
3181    procedure New_LineD is
3182    begin
3183       if Internal_Debug then
3184          New_Line;
3185       end if;
3186    end New_LineD;
3187
3188    ------------
3189    -- NotAny --
3190    ------------
3191
3192    function NotAny (Str : String) return Pattern is
3193    begin
3194       return (AFC with 0, new PE'(PC_NotAny_CS, 1, EOP, To_Set (Str)));
3195    end NotAny;
3196
3197    function NotAny (Str : VString) return Pattern is
3198    begin
3199       return NotAny (S (Str));
3200    end NotAny;
3201
3202    function NotAny (Str : Character) return Pattern is
3203    begin
3204       return (AFC with 0, new PE'(PC_NotAny_CH, 1, EOP, Str));
3205    end NotAny;
3206
3207    function NotAny (Str : Character_Set) return Pattern is
3208    begin
3209       return (AFC with 0, new PE'(PC_NotAny_CS, 1, EOP, Str));
3210    end NotAny;
3211
3212    function NotAny (Str : access VString) return Pattern is
3213    begin
3214       return (AFC with 0, new PE'(PC_NotAny_VP, 1, EOP, VString_Ptr (Str)));
3215    end NotAny;
3216
3217    function NotAny (Str : VString_Func) return Pattern is
3218    begin
3219       return (AFC with 0, new PE'(PC_NotAny_VF, 1, EOP, Str));
3220    end NotAny;
3221
3222    -----------
3223    -- NSpan --
3224    -----------
3225
3226    function NSpan (Str : String) return Pattern is
3227    begin
3228       return (AFC with 0, new PE'(PC_NSpan_CS, 1, EOP, To_Set (Str)));
3229    end NSpan;
3230
3231    function NSpan (Str : VString) return Pattern is
3232    begin
3233       return NSpan (S (Str));
3234    end NSpan;
3235
3236    function NSpan (Str : Character) return Pattern is
3237    begin
3238       return (AFC with 0, new PE'(PC_NSpan_CH, 1, EOP, Str));
3239    end NSpan;
3240
3241    function NSpan (Str : Character_Set) return Pattern is
3242    begin
3243       return (AFC with 0, new PE'(PC_NSpan_CS, 1, EOP, Str));
3244    end NSpan;
3245
3246    function NSpan (Str : access VString) return Pattern is
3247    begin
3248       return (AFC with 0, new PE'(PC_NSpan_VP, 1, EOP, VString_Ptr (Str)));
3249    end NSpan;
3250
3251    function NSpan (Str : VString_Func) return Pattern is
3252    begin
3253       return (AFC with 0, new PE'(PC_NSpan_VF, 1, EOP, Str));
3254    end NSpan;
3255
3256    ---------
3257    -- Pos --
3258    ---------
3259
3260    function Pos (Count : Natural) return Pattern is
3261    begin
3262       return (AFC with 0, new PE'(PC_Pos_Nat, 1, EOP, Count));
3263    end Pos;
3264
3265    function Pos (Count : Natural_Func) return Pattern is
3266    begin
3267       return (AFC with 0, new PE'(PC_Pos_NF, 1, EOP, Count));
3268    end Pos;
3269
3270    function Pos (Count : access Natural) return Pattern is
3271    begin
3272       return (AFC with 0, new PE'(PC_Pos_NP, 1, EOP, Natural_Ptr (Count)));
3273    end Pos;
3274
3275    ----------
3276    -- PutD --
3277    ----------
3278
3279    procedure PutD (Str : String) is
3280    begin
3281       if Internal_Debug then
3282          Put (Str);
3283       end if;
3284    end PutD;
3285
3286    ---------------
3287    -- Put_LineD --
3288    ---------------
3289
3290    procedure Put_LineD (Str : String) is
3291    begin
3292       if Internal_Debug then
3293          Put_Line (Str);
3294       end if;
3295    end Put_LineD;
3296
3297    -------------
3298    -- Replace --
3299    -------------
3300
3301    procedure Replace
3302      (Result  : in out Match_Result;
3303       Replace : VString)
3304    is
3305    begin
3306       if Result.Var /= null then
3307          Replace_Slice
3308            (Result.Var.all,
3309             Result.Start,
3310             Result.Stop,
3311             Get_String (Replace).all);
3312          Result.Var := null;
3313       end if;
3314    end Replace;
3315
3316    ----------
3317    -- Rest --
3318    ----------
3319
3320    function Rest return Pattern is
3321    begin
3322       return (AFC with 0, new PE'(PC_Rest, 1, EOP));
3323    end Rest;
3324
3325    ----------
3326    -- Rpos --
3327    ----------
3328
3329    function Rpos (Count : Natural) return Pattern is
3330    begin
3331       return (AFC with 0, new PE'(PC_RPos_Nat, 1, EOP, Count));
3332    end Rpos;
3333
3334    function Rpos (Count : Natural_Func) return Pattern is
3335    begin
3336       return (AFC with 0, new PE'(PC_RPos_NF, 1, EOP, Count));
3337    end Rpos;
3338
3339    function Rpos (Count : access Natural) return Pattern is
3340    begin
3341       return (AFC with 0, new PE'(PC_RPos_NP, 1, EOP, Natural_Ptr (Count)));
3342    end Rpos;
3343
3344    ----------
3345    -- Rtab --
3346    ----------
3347
3348    function Rtab (Count : Natural) return Pattern is
3349    begin
3350       return (AFC with 0, new PE'(PC_RTab_Nat, 1, EOP, Count));
3351    end Rtab;
3352
3353    function Rtab (Count : Natural_Func) return Pattern is
3354    begin
3355       return (AFC with 0, new PE'(PC_RTab_NF, 1, EOP, Count));
3356    end Rtab;
3357
3358    function Rtab (Count : access Natural) return Pattern is
3359    begin
3360       return (AFC with 0, new PE'(PC_RTab_NP, 1, EOP, Natural_Ptr (Count)));
3361    end Rtab;
3362
3363    -------------
3364    -- S_To_PE --
3365    -------------
3366
3367    function S_To_PE (Str : PString) return PE_Ptr is
3368       Len : constant Natural := Str'Length;
3369
3370    begin
3371       case Len is
3372          when 0 =>
3373             return new PE'(PC_Null,     1, EOP);
3374
3375          when 1 =>
3376             return new PE'(PC_Char,     1, EOP, Str (1));
3377
3378          when 2 =>
3379             return new PE'(PC_String_2, 1, EOP, Str);
3380
3381          when 3 =>
3382             return new PE'(PC_String_3, 1, EOP, Str);
3383
3384          when 4 =>
3385             return new PE'(PC_String_4, 1, EOP, Str);
3386
3387          when 5 =>
3388             return new PE'(PC_String_5, 1, EOP, Str);
3389
3390          when 6 =>
3391             return new PE'(PC_String_6, 1, EOP, Str);
3392
3393          when others =>
3394             return new PE'(PC_String, 1, EOP, new String'(Str));
3395
3396       end case;
3397    end S_To_PE;
3398
3399    -------------------
3400    -- Set_Successor --
3401    -------------------
3402
3403    --  Note: this procedure is not used by the normal concatenation circuit,
3404    --  since other fixups are required on the left operand in this case, and
3405    --  they might as well be done all together.
3406
3407    procedure Set_Successor (Pat : PE_Ptr; Succ : PE_Ptr) is
3408    begin
3409       if Pat = null then
3410          Uninitialized_Pattern;
3411
3412       elsif Pat = EOP then
3413          Logic_Error;
3414
3415       else
3416          declare
3417             Refs : Ref_Array (1 .. Pat.Index);
3418             --  We build a reference array for L whose N'th element points to
3419             --  the pattern element of L whose original Index value is N.
3420
3421             P : PE_Ptr;
3422
3423          begin
3424             Build_Ref_Array (Pat, Refs);
3425
3426             for J in Refs'Range loop
3427                P := Refs (J);
3428
3429                if P.Pthen = EOP then
3430                   P.Pthen := Succ;
3431                end if;
3432
3433                if P.Pcode in PC_Has_Alt and then P.Alt = EOP then
3434                   P.Alt := Succ;
3435                end if;
3436             end loop;
3437          end;
3438       end if;
3439    end Set_Successor;
3440
3441    ------------
3442    -- Setcur --
3443    ------------
3444
3445    function Setcur (Var : access Natural) return Pattern is
3446    begin
3447       return (AFC with 0, new PE'(PC_Setcur, 1, EOP, Natural_Ptr (Var)));
3448    end Setcur;
3449
3450    ----------
3451    -- Span --
3452    ----------
3453
3454    function Span (Str : String) return Pattern is
3455    begin
3456       return (AFC with 0, new PE'(PC_Span_CS, 1, EOP, To_Set (Str)));
3457    end Span;
3458
3459    function Span (Str : VString) return Pattern is
3460    begin
3461       return Span (S (Str));
3462    end Span;
3463
3464    function Span (Str : Character) return Pattern is
3465    begin
3466       return (AFC with 0, new PE'(PC_Span_CH, 1, EOP, Str));
3467    end Span;
3468
3469    function Span (Str : Character_Set) return Pattern is
3470    begin
3471       return (AFC with 0, new PE'(PC_Span_CS, 1, EOP, Str));
3472    end Span;
3473
3474    function Span (Str : access VString) return Pattern is
3475    begin
3476       return (AFC with 0, new PE'(PC_Span_VP, 1, EOP, VString_Ptr (Str)));
3477    end Span;
3478
3479    function Span (Str : VString_Func) return Pattern is
3480    begin
3481       return (AFC with 0, new PE'(PC_Span_VF, 1, EOP, Str));
3482    end Span;
3483
3484    ------------
3485    -- Str_BF --
3486    ------------
3487
3488    function Str_BF (A : Boolean_Func) return String is
3489       function To_A is new Unchecked_Conversion (Boolean_Func, Address);
3490
3491    begin
3492       return "BF(" & Image (To_A (A)) & ')';
3493    end Str_BF;
3494
3495    ------------
3496    -- Str_FP --
3497    ------------
3498
3499    function Str_FP (A : File_Ptr) return String is
3500    begin
3501       return "FP(" & Image (A.all'Address) & ')';
3502    end Str_FP;
3503
3504    ------------
3505    -- Str_NF --
3506    ------------
3507
3508    function Str_NF (A : Natural_Func) return String is
3509       function To_A is new Unchecked_Conversion (Natural_Func, Address);
3510
3511    begin
3512       return "NF(" & Image (To_A (A)) & ')';
3513    end Str_NF;
3514
3515    ------------
3516    -- Str_NP --
3517    ------------
3518
3519    function Str_NP (A : Natural_Ptr) return String is
3520    begin
3521       return "NP(" & Image (A.all'Address) & ')';
3522    end Str_NP;
3523
3524    ------------
3525    -- Str_PP --
3526    ------------
3527
3528    function Str_PP (A : Pattern_Ptr) return String is
3529    begin
3530       return "PP(" & Image (A.all'Address) & ')';
3531    end Str_PP;
3532
3533    ------------
3534    -- Str_VF --
3535    ------------
3536
3537    function Str_VF (A : VString_Func) return String is
3538       function To_A is new Unchecked_Conversion (VString_Func, Address);
3539
3540    begin
3541       return "VF(" & Image (To_A (A)) & ')';
3542    end Str_VF;
3543
3544    ------------
3545    -- Str_VP --
3546    ------------
3547
3548    function Str_VP (A : VString_Ptr) return String is
3549    begin
3550       return "VP(" & Image (A.all'Address) & ')';
3551    end Str_VP;
3552
3553    -------------
3554    -- Succeed --
3555    -------------
3556
3557    function Succeed return Pattern is
3558    begin
3559       return (AFC with 1, new PE'(PC_Succeed, 1, EOP));
3560    end Succeed;
3561
3562    ---------
3563    -- Tab --
3564    ---------
3565
3566    function Tab (Count : Natural) return Pattern is
3567    begin
3568       return (AFC with 0, new PE'(PC_Tab_Nat, 1, EOP, Count));
3569    end Tab;
3570
3571    function Tab (Count : Natural_Func) return Pattern is
3572    begin
3573       return (AFC with 0, new PE'(PC_Tab_NF, 1, EOP, Count));
3574    end Tab;
3575
3576    function Tab (Count : access Natural) return Pattern is
3577    begin
3578       return (AFC with 0, new PE'(PC_Tab_NP, 1, EOP, Natural_Ptr (Count)));
3579    end Tab;
3580
3581    ---------------------------
3582    -- Uninitialized_Pattern --
3583    ---------------------------
3584
3585    procedure Uninitialized_Pattern is
3586    begin
3587       Raise_Exception
3588         (Program_Error'Identity,
3589          "uninitialized value of type GNAT.Spitbol.Patterns.Pattern");
3590    end Uninitialized_Pattern;
3591
3592    ------------
3593    -- XMatch --
3594    ------------
3595
3596    procedure XMatch
3597      (Subject : String;
3598       Pat_P   : PE_Ptr;
3599       Pat_S   : Natural;
3600       Start   : out Natural;
3601       Stop    : out Natural)
3602    is
3603       Node : PE_Ptr;
3604       --  Pointer to current pattern node. Initialized from Pat_P, and then
3605       --  updated as the match proceeds through its constituent elements.
3606
3607       Length : constant Natural := Subject'Length;
3608       --  Length of string (= Subject'Last, since Subject'First is always 1)
3609
3610       Cursor : Integer := 0;
3611       --  If the value is non-negative, then this value is the index showing
3612       --  the current position of the match in the subject string. The next
3613       --  character to be matched is at Subject (Cursor + 1). Note that since
3614       --  our view of the subject string in XMatch always has a lower bound
3615       --  of one, regardless of original bounds, that this definition exactly
3616       --  corresponds to the cursor value as referenced by functions like Pos.
3617       --
3618       --  If the value is negative, then this is a saved stack pointer,
3619       --  typically a base pointer of an inner or outer region. Cursor
3620       --  temporarily holds such a value when it is popped from the stack
3621       --  by Fail. In all cases, Cursor is reset to a proper non-negative
3622       --  cursor value before the match proceeds (e.g. by propagating the
3623       --  failure and popping a "real" cursor value from the stack.
3624
3625       PE_Unanchored : aliased PE := (PC_Unanchored, 0, Pat_P);
3626       --  Dummy pattern element used in the unanchored case.
3627
3628       Stack : Stack_Type;
3629       --  The pattern matching failure stack for this call to Match
3630
3631       Stack_Ptr : Stack_Range;
3632       --  Current stack pointer. This points to the top element of the stack
3633       --  that is currently in use. At the outer level this is the special
3634       --  entry placed on the stack according to the anchor mode.
3635
3636       Stack_Init : constant Stack_Range := Stack'First + 1;
3637       --  This is the initial value of the Stack_Ptr and Stack_Base. The
3638       --  initial (Stack'First) element of the stack is not used so that
3639       --  when we pop the last element off, Stack_Ptr is still in range.
3640
3641       Stack_Base : Stack_Range;
3642       --  This value is the stack base value, i.e. the stack pointer for the
3643       --  first history stack entry in the current stack region. See separate
3644       --  section on handling of recursive pattern matches.
3645
3646       Assign_OnM : Boolean := False;
3647       --  Set True if assign-on-match or write-on-match operations may be
3648       --  present in the history stack, which must then be scanned on a
3649       --  successful match.
3650
3651       procedure Pop_Region;
3652       pragma Inline (Pop_Region);
3653       --  Used at the end of processing of an inner region. if the inner
3654       --  region left no stack entries, then all trace of it is removed.
3655       --  Otherwise a PC_Restore_Region entry is pushed to ensure proper
3656       --  handling of alternatives in the inner region.
3657
3658       procedure Push (Node : PE_Ptr);
3659       pragma Inline (Push);
3660       --  Make entry in pattern matching stack with current cursor valeu
3661
3662       procedure Push_Region;
3663       pragma Inline (Push_Region);
3664       --  This procedure makes a new region on the history stack. The
3665       --  caller first establishes the special entry on the stack, but
3666       --  does not push the stack pointer. Then this call stacks a
3667       --  PC_Remove_Region node, on top of this entry, using the cursor
3668       --  field of the PC_Remove_Region entry to save the outer level
3669       --  stack base value, and resets the stack base to point to this
3670       --  PC_Remove_Region node.
3671
3672       ----------------
3673       -- Pop_Region --
3674       ----------------
3675
3676       procedure Pop_Region is
3677       begin
3678          --  If nothing was pushed in the inner region, we can just get
3679          --  rid of it entirely, leaving no traces that it was ever there
3680
3681          if Stack_Ptr = Stack_Base then
3682             Stack_Ptr := Stack_Base - 2;
3683             Stack_Base := Stack (Stack_Ptr + 2).Cursor;
3684
3685          --  If stuff was pushed in the inner region, then we have to
3686          --  push a PC_R_Restore node so that we properly handle possible
3687          --  rematches within the region.
3688
3689          else
3690             Stack_Ptr := Stack_Ptr + 1;
3691             Stack (Stack_Ptr).Cursor := Stack_Base;
3692             Stack (Stack_Ptr).Node   := CP_R_Restore'Access;
3693             Stack_Base := Stack (Stack_Base).Cursor;
3694          end if;
3695       end Pop_Region;
3696
3697       ----------
3698       -- Push --
3699       ----------
3700
3701       procedure Push (Node : PE_Ptr) is
3702       begin
3703          Stack_Ptr := Stack_Ptr + 1;
3704          Stack (Stack_Ptr).Cursor := Cursor;
3705          Stack (Stack_Ptr).Node   := Node;
3706       end Push;
3707
3708       -----------------
3709       -- Push_Region --
3710       -----------------
3711
3712       procedure Push_Region is
3713       begin
3714          Stack_Ptr := Stack_Ptr + 2;
3715          Stack (Stack_Ptr).Cursor := Stack_Base;
3716          Stack (Stack_Ptr).Node   := CP_R_Remove'Access;
3717          Stack_Base := Stack_Ptr;
3718       end Push_Region;
3719
3720    --  Start of processing for XMatch
3721
3722    begin
3723       if Pat_P = null then
3724          Uninitialized_Pattern;
3725       end if;
3726
3727       --  Check we have enough stack for this pattern. This check deals with
3728       --  every possibility except a match of a recursive pattern, where we
3729       --  make a check at each recursion level.
3730
3731       if Pat_S >= Stack_Size - 1 then
3732          raise Pattern_Stack_Overflow;
3733       end if;
3734
3735       --  In anchored mode, the bottom entry on the stack is an abort entry
3736
3737       if Anchored_Mode then
3738          Stack (Stack_Init).Node   := CP_Cancel'Access;
3739          Stack (Stack_Init).Cursor := 0;
3740
3741       --  In unanchored more, the bottom entry on the stack references
3742       --  the special pattern element PE_Unanchored, whose Pthen field
3743       --  points to the initial pattern element. The cursor value in this
3744       --  entry is the number of anchor moves so far.
3745
3746       else
3747          Stack (Stack_Init).Node   := PE_Unanchored'Unchecked_Access;
3748          Stack (Stack_Init).Cursor := 0;
3749       end if;
3750
3751       Stack_Ptr    := Stack_Init;
3752       Stack_Base   := Stack_Ptr;
3753       Cursor       := 0;
3754       Node         := Pat_P;
3755       goto Match;
3756
3757       -----------------------------------------
3758       -- Main Pattern Matching State Control --
3759       -----------------------------------------
3760
3761       --  This is a state machine which uses gotos to change state. The
3762       --  initial state is Match, to initiate the matching of the first
3763       --  element, so the goto Match above starts the match. In the
3764       --  following descriptions, we indicate the global values that
3765       --  are relevant for the state transition.
3766
3767       --  Come here if entire match fails
3768
3769       <<Match_Fail>>
3770          Start := 0;
3771          Stop  := 0;
3772          return;
3773
3774       --  Come here if entire match succeeds
3775
3776       --    Cursor        current position in subject string
3777
3778       <<Match_Succeed>>
3779          Start := Stack (Stack_Init).Cursor + 1;
3780          Stop  := Cursor;
3781
3782          --  Scan history stack for deferred assignments or writes
3783
3784          if Assign_OnM then
3785             for S in Stack_Init .. Stack_Ptr loop
3786                if Stack (S).Node = CP_Assign'Access then
3787                   declare
3788                      Inner_Base    : constant Stack_Range :=
3789                                        Stack (S + 1).Cursor;
3790                      Special_Entry : constant Stack_Range :=
3791                                        Inner_Base - 1;
3792                      Node_OnM      : constant PE_Ptr  :=
3793                                        Stack (Special_Entry).Node;
3794                      Start         : constant Natural :=
3795                                        Stack (Special_Entry).Cursor + 1;
3796                      Stop          : constant Natural := Stack (S).Cursor;
3797
3798                   begin
3799                      if Node_OnM.Pcode = PC_Assign_OnM then
3800                         Set_String (Node_OnM.VP.all, Subject (Start .. Stop));
3801
3802                      elsif Node_OnM.Pcode = PC_Write_OnM then
3803                         Put_Line (Node_OnM.FP.all, Subject (Start .. Stop));
3804
3805                      else
3806                         Logic_Error;
3807                      end if;
3808                   end;
3809                end if;
3810             end loop;
3811          end if;
3812
3813          return;
3814
3815       --  Come here if attempt to match current element fails
3816
3817       --    Stack_Base    current stack base
3818       --    Stack_Ptr     current stack pointer
3819
3820       <<Fail>>
3821          Cursor := Stack (Stack_Ptr).Cursor;
3822          Node   := Stack (Stack_Ptr).Node;
3823          Stack_Ptr := Stack_Ptr - 1;
3824          goto Match;
3825
3826       --  Come here if attempt to match current element succeeds
3827
3828       --    Cursor        current position in subject string
3829       --    Node          pointer to node successfully matched
3830       --    Stack_Base    current stack base
3831       --    Stack_Ptr     current stack pointer
3832
3833       <<Succeed>>
3834          Node := Node.Pthen;
3835
3836       --  Come here to match the next pattern element
3837
3838       --    Cursor        current position in subject string
3839       --    Node          pointer to node to be matched
3840       --    Stack_Base    current stack base
3841       --    Stack_Ptr     current stack pointer
3842
3843       <<Match>>
3844
3845       --------------------------------------------------
3846       -- Main Pattern Match Element Matching Routines --
3847       --------------------------------------------------
3848
3849       --  Here is the case statement that processes the current node. The
3850       --  processing for each element does one of five things:
3851
3852       --    goto Succeed        to move to the successor
3853       --    goto Match_Succeed  if the entire match succeeds
3854       --    goto Match_Fail     if the entire match fails
3855       --    goto Fail           to signal failure of current match
3856
3857       --  Processing is NOT allowed to fall through
3858
3859       case Node.Pcode is
3860
3861          --  Cancel
3862
3863          when PC_Cancel =>
3864             goto Match_Fail;
3865
3866          --  Alternation
3867
3868          when PC_Alt =>
3869             Push (Node.Alt);
3870             Node := Node.Pthen;
3871             goto Match;
3872
3873          --  Any (one character case)
3874
3875          when PC_Any_CH =>
3876             if Cursor < Length
3877               and then Subject (Cursor + 1) = Node.Char
3878             then
3879                Cursor := Cursor + 1;
3880                goto Succeed;
3881             else
3882                goto Fail;
3883             end if;
3884
3885          --  Any (character set case)
3886
3887          when PC_Any_CS =>
3888             if Cursor < Length
3889               and then Is_In (Subject (Cursor + 1), Node.CS)
3890             then
3891                Cursor := Cursor + 1;
3892                goto Succeed;
3893             else
3894                goto Fail;
3895             end if;
3896
3897          --  Any (string function case)
3898
3899          when PC_Any_VF => declare
3900             U   : constant VString       := Node.VF.all;
3901             Str : constant String_Access := Get_String (U);
3902
3903          begin
3904             if Cursor < Length
3905               and then Is_In (Subject (Cursor + 1), Str.all)
3906             then
3907                Cursor := Cursor + 1;
3908                goto Succeed;
3909             else
3910                goto Fail;
3911             end if;
3912          end;
3913
3914          --  Any (string pointer case)
3915
3916          when PC_Any_VP => declare
3917             Str : constant String_Access := Get_String (Node.VP.all);
3918
3919          begin
3920             if Cursor < Length
3921               and then Is_In (Subject (Cursor + 1), Str.all)
3922             then
3923                Cursor := Cursor + 1;
3924                goto Succeed;
3925             else
3926                goto Fail;
3927             end if;
3928          end;
3929
3930          --  Arb (initial match)
3931
3932          when PC_Arb_X =>
3933             Push (Node.Alt);
3934             Node := Node.Pthen;
3935             goto Match;
3936
3937          --  Arb (extension)
3938
3939          when PC_Arb_Y  =>
3940             if Cursor < Length then
3941                Cursor := Cursor + 1;
3942                Push (Node);
3943                goto Succeed;
3944             else
3945                goto Fail;
3946             end if;
3947
3948          --  Arbno_S (simple Arbno initialize). This is the node that
3949          --  initiates the match of a simple Arbno structure.
3950
3951          when PC_Arbno_S =>
3952             Push (Node.Alt);
3953             Node := Node.Pthen;
3954             goto Match;
3955
3956          --  Arbno_X (Arbno initialize). This is the node that initiates
3957          --  the match of a complex Arbno structure.
3958
3959          when PC_Arbno_X =>
3960             Push (Node.Alt);
3961             Node := Node.Pthen;
3962             goto Match;
3963
3964          --  Arbno_Y (Arbno rematch). This is the node that is executed
3965          --  following successful matching of one instance of a complex
3966          --  Arbno pattern.
3967
3968          when PC_Arbno_Y => declare
3969             Null_Match : constant Boolean :=
3970                            Cursor = Stack (Stack_Base - 1).Cursor;
3971
3972          begin
3973             Pop_Region;
3974
3975             --  If arbno extension matched null, then immediately fail
3976
3977             if Null_Match then
3978                goto Fail;
3979             end if;
3980
3981             --  Here we must do a stack check to make sure enough stack
3982             --  is left. This check will happen once for each instance of
3983             --  the Arbno pattern that is matched. The Nat field of a
3984             --  PC_Arbno pattern contains the maximum stack entries needed
3985             --  for the Arbno with one instance and the successor pattern
3986
3987             if Stack_Ptr + Node.Nat >= Stack'Last then
3988                raise Pattern_Stack_Overflow;
3989             end if;
3990
3991             goto Succeed;
3992          end;
3993
3994          --  Assign. If this node is executed, it means the assign-on-match
3995          --  or write-on-match operation will not happen after all, so we
3996          --  is propagate the failure, removing the PC_Assign node.
3997
3998          when PC_Assign =>
3999             goto Fail;
4000
4001          --  Assign immediate. This node performs the actual assignment.
4002
4003          when PC_Assign_Imm =>
4004             Set_String
4005               (Node.VP.all,
4006                Subject (Stack (Stack_Base - 1).Cursor + 1 .. Cursor));
4007             Pop_Region;
4008             goto Succeed;
4009
4010          --  Assign on match. This node sets up for the eventual assignment
4011
4012          when PC_Assign_OnM =>
4013             Stack (Stack_Base - 1).Node := Node;
4014             Push (CP_Assign'Access);
4015             Pop_Region;
4016             Assign_OnM := True;
4017             goto Succeed;
4018
4019          --  Bal
4020
4021          when PC_Bal =>
4022             if Cursor >= Length or else Subject (Cursor + 1) = ')' then
4023                goto Fail;
4024
4025             elsif Subject (Cursor + 1) = '(' then
4026                declare
4027                   Paren_Count : Natural := 1;
4028
4029                begin
4030                   loop
4031                      Cursor := Cursor + 1;
4032
4033                      if Cursor >= Length then
4034                         goto Fail;
4035
4036                      elsif Subject (Cursor + 1) = '(' then
4037                         Paren_Count := Paren_Count + 1;
4038
4039                      elsif Subject (Cursor + 1) = ')' then
4040                         Paren_Count := Paren_Count - 1;
4041                         exit when Paren_Count = 0;
4042                      end if;
4043                   end loop;
4044                end;
4045             end if;
4046
4047             Cursor := Cursor + 1;
4048             Push (Node);
4049             goto Succeed;
4050
4051          --  Break (one character case)
4052
4053          when PC_Break_CH =>
4054             while Cursor < Length loop
4055                if Subject (Cursor + 1) = Node.Char then
4056                   goto Succeed;
4057                else
4058                   Cursor := Cursor + 1;
4059                end if;
4060             end loop;
4061
4062             goto Fail;
4063
4064          --  Break (character set case)
4065
4066          when PC_Break_CS =>
4067             while Cursor < Length loop
4068                if Is_In (Subject (Cursor + 1), Node.CS) then
4069                   goto Succeed;
4070                else
4071                   Cursor := Cursor + 1;
4072                end if;
4073             end loop;
4074
4075             goto Fail;
4076
4077          --  Break (string function case)
4078
4079          when PC_Break_VF => declare
4080             U   : constant VString       := Node.VF.all;
4081             Str : constant String_Access := Get_String (U);
4082
4083          begin
4084             while Cursor < Length loop
4085                if Is_In (Subject (Cursor + 1), Str.all) then
4086                   goto Succeed;
4087                else
4088                   Cursor := Cursor + 1;
4089                end if;
4090             end loop;
4091
4092             goto Fail;
4093          end;
4094
4095          --  Break (string pointer case)
4096
4097          when PC_Break_VP => declare
4098             Str : constant String_Access := Get_String (Node.VP.all);
4099
4100          begin
4101             while Cursor < Length loop
4102                if Is_In (Subject (Cursor + 1), Str.all) then
4103                   goto Succeed;
4104                else
4105                   Cursor := Cursor + 1;
4106                end if;
4107             end loop;
4108
4109             goto Fail;
4110          end;
4111
4112          --  BreakX (one character case)
4113
4114          when PC_BreakX_CH =>
4115             while Cursor < Length loop
4116                if Subject (Cursor + 1) = Node.Char then
4117                   goto Succeed;
4118                else
4119                   Cursor := Cursor + 1;
4120                end if;
4121             end loop;
4122
4123             goto Fail;
4124
4125          --  BreakX (character set case)
4126
4127          when PC_BreakX_CS =>
4128             while Cursor < Length loop
4129                if Is_In (Subject (Cursor + 1), Node.CS) then
4130                   goto Succeed;
4131                else
4132                   Cursor := Cursor + 1;
4133                end if;
4134             end loop;
4135
4136             goto Fail;
4137
4138          --  BreakX (string function case)
4139
4140          when PC_BreakX_VF => declare
4141             U   : constant VString       := Node.VF.all;
4142             Str : constant String_Access := Get_String (U);
4143
4144          begin
4145             while Cursor < Length loop
4146                if Is_In (Subject (Cursor + 1), Str.all) then
4147                   goto Succeed;
4148                else
4149                   Cursor := Cursor + 1;
4150                end if;
4151             end loop;
4152
4153             goto Fail;
4154          end;
4155
4156          --  BreakX (string pointer case)
4157
4158          when PC_BreakX_VP => declare
4159             Str : constant String_Access := Get_String (Node.VP.all);
4160
4161          begin
4162             while Cursor < Length loop
4163                if Is_In (Subject (Cursor + 1), Str.all) then
4164                   goto Succeed;
4165                else
4166                   Cursor := Cursor + 1;
4167                end if;
4168             end loop;
4169
4170             goto Fail;
4171          end;
4172
4173          --  BreakX_X (BreakX extension). See section on "Compound Pattern
4174          --  Structures". This node is the alternative that is stacked to
4175          --  skip past the break character and extend the break.
4176
4177          when PC_BreakX_X =>
4178             Cursor := Cursor + 1;
4179             goto Succeed;
4180
4181          --  Character (one character string)
4182
4183          when PC_Char =>
4184             if Cursor < Length
4185               and then Subject (Cursor + 1) = Node.Char
4186             then
4187                Cursor := Cursor + 1;
4188                goto Succeed;
4189             else
4190                goto Fail;
4191             end if;
4192
4193          --  End of Pattern
4194
4195          when PC_EOP =>
4196             if Stack_Base = Stack_Init then
4197                goto Match_Succeed;
4198
4199             --  End of recursive inner match. See separate section on
4200             --  handing of recursive pattern matches for details.
4201
4202             else
4203                Node := Stack (Stack_Base - 1).Node;
4204                Pop_Region;
4205                goto Match;
4206             end if;
4207
4208          --  Fail
4209
4210          when PC_Fail =>
4211             goto Fail;
4212
4213          --  Fence (built in pattern)
4214
4215          when PC_Fence =>
4216             Push (CP_Cancel'Access);
4217             goto Succeed;
4218
4219          --  Fence function node X. This is the node that gets control
4220          --  after a successful match of the fenced pattern.
4221
4222          when PC_Fence_X =>
4223             Stack_Ptr := Stack_Ptr + 1;
4224             Stack (Stack_Ptr).Cursor := Stack_Base;
4225             Stack (Stack_Ptr).Node   := CP_Fence_Y'Access;
4226             Stack_Base := Stack (Stack_Base).Cursor;
4227             goto Succeed;
4228
4229          --  Fence function node Y. This is the node that gets control on
4230          --  a failure that occurs after the fenced pattern has matched.
4231
4232          --  Note: the Cursor at this stage is actually the inner stack
4233          --  base value. We don't reset this, but we do use it to strip
4234          --  off all the entries made by the fenced pattern.
4235
4236          when PC_Fence_Y =>
4237             Stack_Ptr := Cursor - 2;
4238             goto Fail;
4239
4240          --  Len (integer case)
4241
4242          when PC_Len_Nat =>
4243             if Cursor + Node.Nat > Length then
4244                goto Fail;
4245             else
4246                Cursor := Cursor + Node.Nat;
4247                goto Succeed;
4248             end if;
4249
4250          --  Len (Integer function case)
4251
4252          when PC_Len_NF => declare
4253             N : constant Natural := Node.NF.all;
4254
4255          begin
4256             if Cursor + N > Length then
4257                goto Fail;
4258             else
4259                Cursor := Cursor + N;
4260                goto Succeed;
4261             end if;
4262          end;
4263
4264          --  Len (integer pointer case)
4265
4266          when PC_Len_NP =>
4267             if Cursor + Node.NP.all > Length then
4268                goto Fail;
4269             else
4270                Cursor := Cursor + Node.NP.all;
4271                goto Succeed;
4272             end if;
4273
4274          --  NotAny (one character case)
4275
4276          when PC_NotAny_CH =>
4277             if Cursor < Length
4278               and then Subject (Cursor + 1) /= Node.Char
4279             then
4280                Cursor := Cursor + 1;
4281                goto Succeed;
4282             else
4283                goto Fail;
4284             end if;
4285
4286          --  NotAny (character set case)
4287
4288          when PC_NotAny_CS =>
4289             if Cursor < Length
4290               and then not Is_In (Subject (Cursor + 1), Node.CS)
4291             then
4292                Cursor := Cursor + 1;
4293                goto Succeed;
4294             else
4295                goto Fail;
4296             end if;
4297
4298          --  NotAny (string function case)
4299
4300          when PC_NotAny_VF => declare
4301             U   : constant VString       := Node.VF.all;
4302             Str : constant String_Access := Get_String (U);
4303
4304          begin
4305             if Cursor < Length
4306               and then
4307                 not Is_In (Subject (Cursor + 1), Str.all)
4308             then
4309                Cursor := Cursor + 1;
4310                goto Succeed;
4311             else
4312                goto Fail;
4313             end if;
4314          end;
4315
4316          --  NotAny (string pointer case)
4317
4318          when PC_NotAny_VP => declare
4319             Str : constant String_Access := Get_String (Node.VP.all);
4320
4321          begin
4322             if Cursor < Length
4323               and then
4324                 not Is_In (Subject (Cursor + 1), Str.all)
4325             then
4326                Cursor := Cursor + 1;
4327                goto Succeed;
4328             else
4329                goto Fail;
4330             end if;
4331          end;
4332
4333          --  NSpan (one character case)
4334
4335          when PC_NSpan_CH =>
4336             while Cursor < Length
4337               and then Subject (Cursor + 1) = Node.Char
4338             loop
4339                Cursor := Cursor + 1;
4340             end loop;
4341
4342             goto Succeed;
4343
4344          --  NSpan (character set case)
4345
4346          when PC_NSpan_CS =>
4347             while Cursor < Length
4348               and then Is_In (Subject (Cursor + 1), Node.CS)
4349             loop
4350                Cursor := Cursor + 1;
4351             end loop;
4352
4353             goto Succeed;
4354
4355          --  NSpan (string function case)
4356
4357          when PC_NSpan_VF => declare
4358             U   : constant VString       := Node.VF.all;
4359             Str : constant String_Access := Get_String (U);
4360
4361          begin
4362             while Cursor < Length
4363               and then Is_In (Subject (Cursor + 1), Str.all)
4364             loop
4365                Cursor := Cursor + 1;
4366             end loop;
4367
4368             goto Succeed;
4369          end;
4370
4371          --  NSpan (string pointer case)
4372
4373          when PC_NSpan_VP => declare
4374             Str : constant String_Access := Get_String (Node.VP.all);
4375
4376          begin
4377             while Cursor < Length
4378               and then Is_In (Subject (Cursor + 1), Str.all)
4379             loop
4380                Cursor := Cursor + 1;
4381             end loop;
4382
4383             goto Succeed;
4384          end;
4385
4386          --  Null string
4387
4388          when PC_Null =>
4389             goto Succeed;
4390
4391          --  Pos (integer case)
4392
4393          when PC_Pos_Nat =>
4394             if Cursor = Node.Nat then
4395                goto Succeed;
4396             else
4397                goto Fail;
4398             end if;
4399
4400          --  Pos (Integer function case)
4401
4402          when PC_Pos_NF => declare
4403             N : constant Natural := Node.NF.all;
4404
4405          begin
4406             if Cursor = N then
4407                goto Succeed;
4408             else
4409                goto Fail;
4410             end if;
4411          end;
4412
4413          --  Pos (integer pointer case)
4414
4415          when PC_Pos_NP =>
4416             if Cursor = Node.NP.all then
4417                goto Succeed;
4418             else
4419                goto Fail;
4420             end if;
4421
4422          --  Predicate function
4423
4424          when PC_Pred_Func =>
4425             if Node.BF.all then
4426                goto Succeed;
4427             else
4428                goto Fail;
4429             end if;
4430
4431          --  Region Enter. Initiate new pattern history stack region
4432
4433          when PC_R_Enter =>
4434             Stack (Stack_Ptr + 1).Cursor := Cursor;
4435             Push_Region;
4436             goto Succeed;
4437
4438          --  Region Remove node. This is the node stacked by an R_Enter.
4439          --  It removes the special format stack entry right underneath, and
4440          --  then restores the outer level stack base and signals failure.
4441
4442          --  Note: the cursor value at this stage is actually the (negative)
4443          --  stack base value for the outer level.
4444
4445          when PC_R_Remove =>
4446             Stack_Base := Cursor;
4447             Stack_Ptr := Stack_Ptr - 1;
4448             goto Fail;
4449
4450          --  Region restore node. This is the node stacked at the end of an
4451          --  inner level match. Its function is to restore the inner level
4452          --  region, so that alternatives in this region can be sought.
4453
4454          --  Note: the Cursor at this stage is actually the negative of the
4455          --  inner stack base value, which we use to restore the inner region.
4456
4457          when PC_R_Restore =>
4458             Stack_Base := Cursor;
4459             goto Fail;
4460
4461          --  Rest
4462
4463          when PC_Rest =>
4464             Cursor := Length;
4465             goto Succeed;
4466
4467          --  Initiate recursive match (pattern pointer case)
4468
4469          when PC_Rpat =>
4470             Stack (Stack_Ptr + 1).Node := Node.Pthen;
4471             Push_Region;
4472
4473             if Stack_Ptr + Node.PP.all.Stk >= Stack_Size then
4474                raise Pattern_Stack_Overflow;
4475             else
4476                Node := Node.PP.all.P;
4477                goto Match;
4478             end if;
4479
4480          --  RPos (integer case)
4481
4482          when PC_RPos_Nat =>
4483             if Cursor = (Length - Node.Nat) then
4484                goto Succeed;
4485             else
4486                goto Fail;
4487             end if;
4488
4489          --  RPos (integer function case)
4490
4491          when PC_RPos_NF => declare
4492             N : constant Natural := Node.NF.all;
4493
4494          begin
4495             if Length - Cursor = N then
4496                goto Succeed;
4497             else
4498                goto Fail;
4499             end if;
4500          end;
4501
4502          --  RPos (integer pointer case)
4503
4504          when PC_RPos_NP =>
4505             if Cursor = (Length - Node.NP.all) then
4506                goto Succeed;
4507             else
4508                goto Fail;
4509             end if;
4510
4511          --  RTab (integer case)
4512
4513          when PC_RTab_Nat =>
4514             if Cursor <= (Length - Node.Nat) then
4515                Cursor := Length - Node.Nat;
4516                goto Succeed;
4517             else
4518                goto Fail;
4519             end if;
4520
4521          --  RTab (integer function case)
4522
4523          when PC_RTab_NF => declare
4524             N : constant Natural := Node.NF.all;
4525
4526          begin
4527             if Length - Cursor >= N then
4528                Cursor := Length - N;
4529                goto Succeed;
4530             else
4531                goto Fail;
4532             end if;
4533          end;
4534
4535          --  RTab (integer pointer case)
4536
4537          when PC_RTab_NP =>
4538             if Cursor <= (Length - Node.NP.all) then
4539                Cursor := Length - Node.NP.all;
4540                goto Succeed;
4541             else
4542                goto Fail;
4543             end if;
4544
4545          --  Cursor assignment
4546
4547          when PC_Setcur =>
4548             Node.Var.all := Cursor;
4549             goto Succeed;
4550
4551          --  Span (one character case)
4552
4553          when PC_Span_CH => declare
4554             P : Natural := Cursor;
4555
4556          begin
4557             while P < Length
4558               and then Subject (P + 1) = Node.Char
4559             loop
4560                P := P + 1;
4561             end loop;
4562
4563             if P /= Cursor then
4564                Cursor := P;
4565                goto Succeed;
4566             else
4567                goto Fail;
4568             end if;
4569          end;
4570
4571          --  Span (character set case)
4572
4573          when PC_Span_CS => declare
4574             P : Natural := Cursor;
4575
4576          begin
4577             while P < Length
4578               and then Is_In (Subject (P + 1), Node.CS)
4579             loop
4580                P := P + 1;
4581             end loop;
4582
4583             if P /= Cursor then
4584                Cursor := P;
4585                goto Succeed;
4586             else
4587                goto Fail;
4588             end if;
4589          end;
4590
4591          --  Span (string function case)
4592
4593          when PC_Span_VF => declare
4594             U   : constant VString       := Node.VF.all;
4595             Str : constant String_Access := Get_String (U);
4596             P   : Natural := Cursor;
4597
4598          begin
4599             while P < Length
4600               and then Is_In (Subject (P + 1), Str.all)
4601             loop
4602                P := P + 1;
4603             end loop;
4604
4605             if P /= Cursor then
4606                Cursor := P;
4607                goto Succeed;
4608             else
4609                goto Fail;
4610             end if;
4611          end;
4612
4613          --  Span (string pointer case)
4614
4615          when PC_Span_VP => declare
4616             Str : constant String_Access := Get_String (Node.VP.all);
4617             P   : Natural := Cursor;
4618
4619          begin
4620             while P < Length
4621               and then Is_In (Subject (P + 1), Str.all)
4622             loop
4623                P := P + 1;
4624             end loop;
4625
4626             if P /= Cursor then
4627                Cursor := P;
4628                goto Succeed;
4629             else
4630                goto Fail;
4631             end if;
4632          end;
4633
4634          --  String (two character case)
4635
4636          when PC_String_2 =>
4637             if (Length - Cursor) >= 2
4638               and then Subject (Cursor + 1 .. Cursor + 2) = Node.Str2
4639             then
4640                Cursor := Cursor + 2;
4641                goto Succeed;
4642             else
4643                goto Fail;
4644             end if;
4645
4646          --  String (three character case)
4647
4648          when PC_String_3 =>
4649             if (Length - Cursor) >= 3
4650               and then Subject (Cursor + 1 .. Cursor + 3) = Node.Str3
4651             then
4652                Cursor := Cursor + 3;
4653                goto Succeed;
4654             else
4655                goto Fail;
4656             end if;
4657
4658          --  String (four character case)
4659
4660          when PC_String_4 =>
4661             if (Length - Cursor) >= 4
4662               and then Subject (Cursor + 1 .. Cursor + 4) = Node.Str4
4663             then
4664                Cursor := Cursor + 4;
4665                goto Succeed;
4666             else
4667                goto Fail;
4668             end if;
4669
4670          --  String (five character case)
4671
4672          when PC_String_5 =>
4673             if (Length - Cursor) >= 5
4674               and then Subject (Cursor + 1 .. Cursor + 5) = Node.Str5
4675             then
4676                Cursor := Cursor + 5;
4677                goto Succeed;
4678             else
4679                goto Fail;
4680             end if;
4681
4682          --  String (six character case)
4683
4684          when PC_String_6 =>
4685             if (Length - Cursor) >= 6
4686               and then Subject (Cursor + 1 .. Cursor + 6) = Node.Str6
4687             then
4688                Cursor := Cursor + 6;
4689                goto Succeed;
4690             else
4691                goto Fail;
4692             end if;
4693
4694          --  String (case of more than six characters)
4695
4696          when PC_String => declare
4697             Len : constant Natural := Node.Str'Length;
4698
4699          begin
4700             if (Length - Cursor) >= Len
4701               and then Node.Str.all = Subject (Cursor + 1 .. Cursor + Len)
4702             then
4703                Cursor := Cursor + Len;
4704                goto Succeed;
4705             else
4706                goto Fail;
4707             end if;
4708          end;
4709
4710          --  String (function case)
4711
4712          when PC_String_VF => declare
4713             U   : constant VString       := Node.VF.all;
4714             Str : constant String_Access := Get_String (U);
4715             Len : constant Natural       := Str'Length;
4716
4717          begin
4718             if (Length - Cursor) >= Len
4719               and then Str.all = Subject (Cursor + 1 .. Cursor + Len)
4720             then
4721                Cursor := Cursor + Len;
4722                goto Succeed;
4723             else
4724                goto Fail;
4725             end if;
4726          end;
4727
4728          --  String (pointer case)
4729
4730          when PC_String_VP => declare
4731             S   : constant String_Access := Get_String (Node.VP.all);
4732             Len : constant Natural       := S'Length;
4733
4734          begin
4735             if (Length - Cursor) >= Len
4736               and then S.all = Subject (Cursor + 1 .. Cursor + Len)
4737             then
4738                Cursor := Cursor + Len;
4739                goto Succeed;
4740             else
4741                goto Fail;
4742             end if;
4743          end;
4744
4745          --  Succeed
4746
4747          when PC_Succeed =>
4748             Push (Node);
4749             goto Succeed;
4750
4751          --  Tab (integer case)
4752
4753          when PC_Tab_Nat =>
4754             if Cursor <= Node.Nat then
4755                Cursor := Node.Nat;
4756                goto Succeed;
4757             else
4758                goto Fail;
4759             end if;
4760
4761          --  Tab (integer function case)
4762
4763          when PC_Tab_NF => declare
4764             N : constant Natural := Node.NF.all;
4765
4766          begin
4767             if Cursor <= N then
4768                Cursor := N;
4769                goto Succeed;
4770             else
4771                goto Fail;
4772             end if;
4773          end;
4774
4775          --  Tab (integer pointer case)
4776
4777          when PC_Tab_NP =>
4778             if Cursor <= Node.NP.all then
4779                Cursor := Node.NP.all;
4780                goto Succeed;
4781             else
4782                goto Fail;
4783             end if;
4784
4785          --  Unanchored movement
4786
4787          when PC_Unanchored =>
4788
4789             --  All done if we tried every position
4790
4791             if Cursor > Length then
4792                goto Match_Fail;
4793
4794             --  Otherwise extend the anchor point, and restack ourself
4795
4796             else
4797                Cursor := Cursor + 1;
4798                Push (Node);
4799                goto Succeed;
4800             end if;
4801
4802          --  Write immediate. This node performs the actual write
4803
4804          when PC_Write_Imm =>
4805             Put_Line
4806               (Node.FP.all,
4807                Subject (Stack (Stack_Base - 1).Cursor + 1 .. Cursor));
4808             Pop_Region;
4809             goto Succeed;
4810
4811          --  Write on match. This node sets up for the eventual write
4812
4813          when PC_Write_OnM =>
4814             Stack (Stack_Base - 1).Node := Node;
4815             Push (CP_Assign'Access);
4816             Pop_Region;
4817             Assign_OnM := True;
4818             goto Succeed;
4819
4820       end case;
4821
4822       --  We are NOT allowed to fall though this case statement, since every
4823       --  match routine must end by executing a goto to the appropriate point
4824       --  in the finite state machine model.
4825
4826       Logic_Error;
4827
4828    end XMatch;
4829
4830    -------------
4831    -- XMatchD --
4832    -------------
4833
4834    --  Maintenance note: There is a LOT of code duplication between XMatch
4835    --  and XMatchD. This is quite intentional, the point is to avoid any
4836    --  unnecessary debugging overhead in the XMatch case, but this does mean
4837    --  that any changes to XMatchD must be mirrored in XMatch. In case of
4838    --  any major changes, the proper approach is to delete XMatch, make the
4839    --  changes to XMatchD, and then make a copy of XMatchD, removing all
4840    --  calls to Dout, and all Put and Put_Line operations. This copy becomes
4841    --  the new XMatch.
4842
4843    procedure XMatchD
4844      (Subject : String;
4845       Pat_P   : PE_Ptr;
4846       Pat_S   : Natural;
4847       Start   : out Natural;
4848       Stop    : out Natural)
4849    is
4850       Node : PE_Ptr;
4851       --  Pointer to current pattern node. Initialized from Pat_P, and then
4852       --  updated as the match proceeds through its constituent elements.
4853
4854       Length : constant Natural := Subject'Length;
4855       --  Length of string (= Subject'Last, since Subject'First is always 1)
4856
4857       Cursor : Integer := 0;
4858       --  If the value is non-negative, then this value is the index showing
4859       --  the current position of the match in the subject string. The next
4860       --  character to be matched is at Subject (Cursor + 1). Note that since
4861       --  our view of the subject string in XMatch always has a lower bound
4862       --  of one, regardless of original bounds, that this definition exactly
4863       --  corresponds to the cursor value as referenced by functions like Pos.
4864       --
4865       --  If the value is negative, then this is a saved stack pointer,
4866       --  typically a base pointer of an inner or outer region. Cursor
4867       --  temporarily holds such a value when it is popped from the stack
4868       --  by Fail. In all cases, Cursor is reset to a proper non-negative
4869       --  cursor value before the match proceeds (e.g. by propagating the
4870       --  failure and popping a "real" cursor value from the stack.
4871
4872       PE_Unanchored : aliased PE := (PC_Unanchored, 0, Pat_P);
4873       --  Dummy pattern element used in the unanchored case.
4874
4875       Region_Level : Natural := 0;
4876       --  Keeps track of recursive region level. This is used only for
4877       --  debugging, it is the number of saved history stack base values.
4878
4879       Stack : Stack_Type;
4880       --  The pattern matching failure stack for this call to Match
4881
4882       Stack_Ptr : Stack_Range;
4883       --  Current stack pointer. This points to the top element of the stack
4884       --  that is currently in use. At the outer level this is the special
4885       --  entry placed on the stack according to the anchor mode.
4886
4887       Stack_Init : constant Stack_Range := Stack'First + 1;
4888       --  This is the initial value of the Stack_Ptr and Stack_Base. The
4889       --  initial (Stack'First) element of the stack is not used so that
4890       --  when we pop the last element off, Stack_Ptr is still in range.
4891
4892       Stack_Base : Stack_Range;
4893       --  This value is the stack base value, i.e. the stack pointer for the
4894       --  first history stack entry in the current stack region. See separate
4895       --  section on handling of recursive pattern matches.
4896
4897       Assign_OnM : Boolean := False;
4898       --  Set True if assign-on-match or write-on-match operations may be
4899       --  present in the history stack, which must then be scanned on a
4900       --  successful match.
4901
4902       procedure Dout (Str : String);
4903       --  Output string to standard error with bars indicating region level.
4904
4905       procedure Dout (Str : String; A : Character);
4906       --  Calls Dout with the string S ('A')
4907
4908       procedure Dout (Str : String; A : Character_Set);
4909       --  Calls Dout with the string S ("A")
4910
4911       procedure Dout (Str : String; A : Natural);
4912       --  Calls Dout with the string S (A)
4913
4914       procedure Dout (Str : String; A : String);
4915       --  Calls Dout with the string S ("A")
4916
4917       function Img (P : PE_Ptr) return String;
4918       --  Returns a string of the form #nnn where nnn is P.Index
4919
4920       procedure Pop_Region;
4921       pragma Inline (Pop_Region);
4922       --  Used at the end of processing of an inner region. if the inner
4923       --  region left no stack entries, then all trace of it is removed.
4924       --  Otherwise a PC_Restore_Region entry is pushed to ensure proper
4925       --  handling of alternatives in the inner region.
4926
4927       procedure Push (Node : PE_Ptr);
4928       pragma Inline (Push);
4929       --  Make entry in pattern matching stack with current cursor valeu
4930
4931       procedure Push_Region;
4932       pragma Inline (Push_Region);
4933       --  This procedure makes a new region on the history stack. The
4934       --  caller first establishes the special entry on the stack, but
4935       --  does not push the stack pointer. Then this call stacks a
4936       --  PC_Remove_Region node, on top of this entry, using the cursor
4937       --  field of the PC_Remove_Region entry to save the outer level
4938       --  stack base value, and resets the stack base to point to this
4939       --  PC_Remove_Region node.
4940
4941       ----------
4942       -- Dout --
4943       ----------
4944
4945       procedure Dout (Str : String) is
4946       begin
4947          for J in 1 .. Region_Level loop
4948             Put ("| ");
4949          end loop;
4950
4951          Put_Line (Str);
4952       end Dout;
4953
4954       procedure Dout (Str : String; A : Character) is
4955       begin
4956          Dout (Str & " ('" & A & "')");
4957       end Dout;
4958
4959       procedure Dout (Str : String; A : Character_Set) is
4960       begin
4961          Dout (Str & " (" & Image (To_Sequence (A)) & ')');
4962       end Dout;
4963
4964       procedure Dout (Str : String; A : Natural) is
4965       begin
4966          Dout (Str & " (" & A & ')');
4967       end Dout;
4968
4969       procedure Dout (Str : String; A : String) is
4970       begin
4971          Dout (Str & " (" & Image (A) & ')');
4972       end Dout;
4973
4974       ---------
4975       -- Img --
4976       ---------
4977
4978       function Img (P : PE_Ptr) return String is
4979       begin
4980          return "#" & Integer (P.Index) & " ";
4981       end Img;
4982
4983       ----------------
4984       -- Pop_Region --
4985       ----------------
4986
4987       procedure Pop_Region is
4988       begin
4989          Region_Level := Region_Level - 1;
4990
4991          --  If nothing was pushed in the inner region, we can just get
4992          --  rid of it entirely, leaving no traces that it was ever there
4993
4994          if Stack_Ptr = Stack_Base then
4995             Stack_Ptr := Stack_Base - 2;
4996             Stack_Base := Stack (Stack_Ptr + 2).Cursor;
4997
4998          --  If stuff was pushed in the inner region, then we have to
4999          --  push a PC_R_Restore node so that we properly handle possible
5000          --  rematches within the region.
5001
5002          else
5003             Stack_Ptr := Stack_Ptr + 1;
5004             Stack (Stack_Ptr).Cursor := Stack_Base;
5005             Stack (Stack_Ptr).Node   := CP_R_Restore'Access;
5006             Stack_Base := Stack (Stack_Base).Cursor;
5007          end if;
5008       end Pop_Region;
5009
5010       ----------
5011       -- Push --
5012       ----------
5013
5014       procedure Push (Node : PE_Ptr) is
5015       begin
5016          Stack_Ptr := Stack_Ptr + 1;
5017          Stack (Stack_Ptr).Cursor := Cursor;
5018          Stack (Stack_Ptr).Node   := Node;
5019       end Push;
5020
5021       -----------------
5022       -- Push_Region --
5023       -----------------
5024
5025       procedure Push_Region is
5026       begin
5027          Region_Level := Region_Level + 1;
5028          Stack_Ptr := Stack_Ptr + 2;
5029          Stack (Stack_Ptr).Cursor := Stack_Base;
5030          Stack (Stack_Ptr).Node   := CP_R_Remove'Access;
5031          Stack_Base := Stack_Ptr;
5032       end Push_Region;
5033
5034    --  Start of processing for XMatchD
5035
5036    begin
5037       New_Line;
5038       Put_Line ("Initiating pattern match, subject = " & Image (Subject));
5039       Put      ("--------------------------------------");
5040
5041       for J in 1 .. Length loop
5042          Put ('-');
5043       end loop;
5044
5045       New_Line;
5046       Put_Line ("subject length = " & Length);
5047
5048       if Pat_P = null then
5049          Uninitialized_Pattern;
5050       end if;
5051
5052       --  Check we have enough stack for this pattern. This check deals with
5053       --  every possibility except a match of a recursive pattern, where we
5054       --  make a check at each recursion level.
5055
5056       if Pat_S >= Stack_Size - 1 then
5057          raise Pattern_Stack_Overflow;
5058       end if;
5059
5060       --  In anchored mode, the bottom entry on the stack is an abort entry
5061
5062       if Anchored_Mode then
5063          Stack (Stack_Init).Node   := CP_Cancel'Access;
5064          Stack (Stack_Init).Cursor := 0;
5065
5066       --  In unanchored more, the bottom entry on the stack references
5067       --  the special pattern element PE_Unanchored, whose Pthen field
5068       --  points to the initial pattern element. The cursor value in this
5069       --  entry is the number of anchor moves so far.
5070
5071       else
5072          Stack (Stack_Init).Node   := PE_Unanchored'Unchecked_Access;
5073          Stack (Stack_Init).Cursor := 0;
5074       end if;
5075
5076       Stack_Ptr    := Stack_Init;
5077       Stack_Base   := Stack_Ptr;
5078       Cursor       := 0;
5079       Node         := Pat_P;
5080       goto Match;
5081
5082       -----------------------------------------
5083       -- Main Pattern Matching State Control --
5084       -----------------------------------------
5085
5086       --  This is a state machine which uses gotos to change state. The
5087       --  initial state is Match, to initiate the matching of the first
5088       --  element, so the goto Match above starts the match. In the
5089       --  following descriptions, we indicate the global values that
5090       --  are relevant for the state transition.
5091
5092       --  Come here if entire match fails
5093
5094       <<Match_Fail>>
5095          Dout ("match fails");
5096          New_Line;
5097          Start := 0;
5098          Stop  := 0;
5099          return;
5100
5101       --  Come here if entire match succeeds
5102
5103       --    Cursor        current position in subject string
5104
5105       <<Match_Succeed>>
5106          Dout ("match succeeds");
5107          Start := Stack (Stack_Init).Cursor + 1;
5108          Stop  := Cursor;
5109          Dout ("first matched character index = " & Start);
5110          Dout ("last matched character index = " & Stop);
5111          Dout ("matched substring = " & Image (Subject (Start .. Stop)));
5112
5113          --  Scan history stack for deferred assignments or writes
5114
5115          if Assign_OnM then
5116             for S in Stack'First .. Stack_Ptr loop
5117                if Stack (S).Node = CP_Assign'Access then
5118                   declare
5119                      Inner_Base    : constant Stack_Range :=
5120                                        Stack (S + 1).Cursor;
5121                      Special_Entry : constant Stack_Range :=
5122                                        Inner_Base - 1;
5123                      Node_OnM      : constant PE_Ptr  :=
5124                                        Stack (Special_Entry).Node;
5125                      Start         : constant Natural :=
5126                                        Stack (Special_Entry).Cursor + 1;
5127                      Stop          : constant Natural := Stack (S).Cursor;
5128
5129                   begin
5130                      if Node_OnM.Pcode = PC_Assign_OnM then
5131                         Set_String (Node_OnM.VP.all, Subject (Start .. Stop));
5132                         Dout
5133                           (Img (Stack (S).Node) &
5134                            "deferred assignment of " &
5135                            Image (Subject (Start .. Stop)));
5136
5137                      elsif Node_OnM.Pcode = PC_Write_OnM then
5138                         Put_Line (Node_OnM.FP.all, Subject (Start .. Stop));
5139                         Dout
5140                           (Img (Stack (S).Node) &
5141                            "deferred write of " &
5142                            Image (Subject (Start .. Stop)));
5143
5144                      else
5145                         Logic_Error;
5146                      end if;
5147                   end;
5148                end if;
5149             end loop;
5150          end if;
5151
5152          New_Line;
5153          return;
5154
5155       --  Come here if attempt to match current element fails
5156
5157       --    Stack_Base    current stack base
5158       --    Stack_Ptr     current stack pointer
5159
5160       <<Fail>>
5161          Cursor := Stack (Stack_Ptr).Cursor;
5162          Node   := Stack (Stack_Ptr).Node;
5163          Stack_Ptr := Stack_Ptr - 1;
5164
5165          if Cursor >= 0 then
5166             Dout ("failure, cursor reset to " & Cursor);
5167          end if;
5168
5169          goto Match;
5170
5171       --  Come here if attempt to match current element succeeds
5172
5173       --    Cursor        current position in subject string
5174       --    Node          pointer to node successfully matched
5175       --    Stack_Base    current stack base
5176       --    Stack_Ptr     current stack pointer
5177
5178       <<Succeed>>
5179          Dout ("success, cursor = " & Cursor);
5180          Node := Node.Pthen;
5181
5182       --  Come here to match the next pattern element
5183
5184       --    Cursor        current position in subject string
5185       --    Node          pointer to node to be matched
5186       --    Stack_Base    current stack base
5187       --    Stack_Ptr     current stack pointer
5188
5189       <<Match>>
5190
5191       --------------------------------------------------
5192       -- Main Pattern Match Element Matching Routines --
5193       --------------------------------------------------
5194
5195       --  Here is the case statement that processes the current node. The
5196       --  processing for each element does one of five things:
5197
5198       --    goto Succeed        to move to the successor
5199       --    goto Match_Succeed  if the entire match succeeds
5200       --    goto Match_Fail     if the entire match fails
5201       --    goto Fail           to signal failure of current match
5202
5203       --  Processing is NOT allowed to fall through
5204
5205       case Node.Pcode is
5206
5207          --  Cancel
5208
5209          when PC_Cancel =>
5210             Dout (Img (Node) & "matching Cancel");
5211             goto Match_Fail;
5212
5213          --  Alternation
5214
5215          when PC_Alt =>
5216             Dout
5217               (Img (Node) & "setting up alternative " & Img (Node.Alt));
5218             Push (Node.Alt);
5219             Node := Node.Pthen;
5220             goto Match;
5221
5222          --  Any (one character case)
5223
5224          when PC_Any_CH =>
5225             Dout (Img (Node) & "matching Any", Node.Char);
5226
5227             if Cursor < Length
5228               and then Subject (Cursor + 1) = Node.Char
5229             then
5230                Cursor := Cursor + 1;
5231                goto Succeed;
5232             else
5233                goto Fail;
5234             end if;
5235
5236          --  Any (character set case)
5237
5238          when PC_Any_CS =>
5239             Dout (Img (Node) & "matching Any", Node.CS);
5240
5241             if Cursor < Length
5242               and then Is_In (Subject (Cursor + 1), Node.CS)
5243             then
5244                Cursor := Cursor + 1;
5245                goto Succeed;
5246             else
5247                goto Fail;
5248             end if;
5249
5250          --  Any (string function case)
5251
5252          when PC_Any_VF => declare
5253             U   : constant VString       := Node.VF.all;
5254             Str : constant String_Access := Get_String (U);
5255
5256          begin
5257             Dout (Img (Node) & "matching Any", Str.all);
5258
5259             if Cursor < Length
5260               and then Is_In (Subject (Cursor + 1), Str.all)
5261             then
5262                Cursor := Cursor + 1;
5263                goto Succeed;
5264             else
5265                goto Fail;
5266             end if;
5267          end;
5268
5269          --  Any (string pointer case)
5270
5271          when PC_Any_VP => declare
5272             Str : constant String_Access := Get_String (Node.VP.all);
5273
5274          begin
5275             Dout (Img (Node) & "matching Any", Str.all);
5276
5277             if Cursor < Length
5278               and then Is_In (Subject (Cursor + 1), Str.all)
5279             then
5280                Cursor := Cursor + 1;
5281                goto Succeed;
5282             else
5283                goto Fail;
5284             end if;
5285          end;
5286
5287          --  Arb (initial match)
5288
5289          when PC_Arb_X =>
5290             Dout (Img (Node) & "matching Arb");
5291             Push (Node.Alt);
5292             Node := Node.Pthen;
5293             goto Match;
5294
5295          --  Arb (extension)
5296
5297          when PC_Arb_Y  =>
5298             Dout (Img (Node) & "extending Arb");
5299
5300             if Cursor < Length then
5301                Cursor := Cursor + 1;
5302                Push (Node);
5303                goto Succeed;
5304             else
5305                goto Fail;
5306             end if;
5307
5308          --  Arbno_S (simple Arbno initialize). This is the node that
5309          --  initiates the match of a simple Arbno structure.
5310
5311          when PC_Arbno_S =>
5312             Dout (Img (Node) &
5313                   "setting up Arbno alternative " & Img (Node.Alt));
5314             Push (Node.Alt);
5315             Node := Node.Pthen;
5316             goto Match;
5317
5318          --  Arbno_X (Arbno initialize). This is the node that initiates
5319          --  the match of a complex Arbno structure.
5320
5321          when PC_Arbno_X =>
5322             Dout (Img (Node) &
5323                   "setting up Arbno alternative " & Img (Node.Alt));
5324             Push (Node.Alt);
5325             Node := Node.Pthen;
5326             goto Match;
5327
5328          --  Arbno_Y (Arbno rematch). This is the node that is executed
5329          --  following successful matching of one instance of a complex
5330          --  Arbno pattern.
5331
5332          when PC_Arbno_Y => declare
5333             Null_Match : constant Boolean :=
5334                            Cursor = Stack (Stack_Base - 1).Cursor;
5335
5336          begin
5337             Dout (Img (Node) & "extending Arbno");
5338             Pop_Region;
5339
5340             --  If arbno extension matched null, then immediately fail
5341
5342             if Null_Match then
5343                Dout ("Arbno extension matched null, so fails");
5344                goto Fail;
5345             end if;
5346
5347             --  Here we must do a stack check to make sure enough stack
5348             --  is left. This check will happen once for each instance of
5349             --  the Arbno pattern that is matched. The Nat field of a
5350             --  PC_Arbno pattern contains the maximum stack entries needed
5351             --  for the Arbno with one instance and the successor pattern
5352
5353             if Stack_Ptr + Node.Nat >= Stack'Last then
5354                raise Pattern_Stack_Overflow;
5355             end if;
5356
5357             goto Succeed;
5358          end;
5359
5360          --  Assign. If this node is executed, it means the assign-on-match
5361          --  or write-on-match operation will not happen after all, so we
5362          --  is propagate the failure, removing the PC_Assign node.
5363
5364          when PC_Assign =>
5365             Dout (Img (Node) & "deferred assign/write cancelled");
5366             goto Fail;
5367
5368          --  Assign immediate. This node performs the actual assignment.
5369
5370          when PC_Assign_Imm =>
5371             Dout
5372               (Img (Node) & "executing immediate assignment of " &
5373                Image (Subject (Stack (Stack_Base - 1).Cursor + 1 .. Cursor)));
5374             Set_String
5375               (Node.VP.all,
5376                Subject (Stack (Stack_Base - 1).Cursor + 1 .. Cursor));
5377             Pop_Region;
5378             goto Succeed;
5379
5380          --  Assign on match. This node sets up for the eventual assignment
5381
5382          when PC_Assign_OnM =>
5383             Dout (Img (Node) & "registering deferred assignment");
5384             Stack (Stack_Base - 1).Node := Node;
5385             Push (CP_Assign'Access);
5386             Pop_Region;
5387             Assign_OnM := True;
5388             goto Succeed;
5389
5390          --  Bal
5391
5392          when PC_Bal =>
5393             Dout (Img (Node) & "matching or extending Bal");
5394             if Cursor >= Length or else Subject (Cursor + 1) = ')' then
5395                goto Fail;
5396
5397             elsif Subject (Cursor + 1) = '(' then
5398                declare
5399                   Paren_Count : Natural := 1;
5400
5401                begin
5402                   loop
5403                      Cursor := Cursor + 1;
5404
5405                      if Cursor >= Length then
5406                         goto Fail;
5407
5408                      elsif Subject (Cursor + 1) = '(' then
5409                         Paren_Count := Paren_Count + 1;
5410
5411                      elsif Subject (Cursor + 1) = ')' then
5412                         Paren_Count := Paren_Count - 1;
5413                         exit when Paren_Count = 0;
5414                      end if;
5415                   end loop;
5416                end;
5417             end if;
5418
5419             Cursor := Cursor + 1;
5420             Push (Node);
5421             goto Succeed;
5422
5423          --  Break (one character case)
5424
5425          when PC_Break_CH =>
5426             Dout (Img (Node) & "matching Break", Node.Char);
5427
5428             while Cursor < Length loop
5429                if Subject (Cursor + 1) = Node.Char then
5430                   goto Succeed;
5431                else
5432                   Cursor := Cursor + 1;
5433                end if;
5434             end loop;
5435
5436             goto Fail;
5437
5438          --  Break (character set case)
5439
5440          when PC_Break_CS =>
5441             Dout (Img (Node) & "matching Break", Node.CS);
5442
5443             while Cursor < Length loop
5444                if Is_In (Subject (Cursor + 1), Node.CS) then
5445                   goto Succeed;
5446                else
5447                   Cursor := Cursor + 1;
5448                end if;
5449             end loop;
5450
5451             goto Fail;
5452
5453          --  Break (string function case)
5454
5455          when PC_Break_VF => declare
5456             U   : constant VString       := Node.VF.all;
5457             Str : constant String_Access := Get_String (U);
5458
5459          begin
5460             Dout (Img (Node) & "matching Break", Str.all);
5461
5462             while Cursor < Length loop
5463                if Is_In (Subject (Cursor + 1), Str.all) then
5464                   goto Succeed;
5465                else
5466                   Cursor := Cursor + 1;
5467                end if;
5468             end loop;
5469
5470             goto Fail;
5471          end;
5472
5473          --  Break (string pointer case)
5474
5475          when PC_Break_VP => declare
5476             Str : constant String_Access := Get_String (Node.VP.all);
5477
5478          begin
5479             Dout (Img (Node) & "matching Break", Str.all);
5480
5481             while Cursor < Length loop
5482                if Is_In (Subject (Cursor + 1), Str.all) then
5483                   goto Succeed;
5484                else
5485                   Cursor := Cursor + 1;
5486                end if;
5487             end loop;
5488
5489             goto Fail;
5490          end;
5491
5492          --  BreakX (one character case)
5493
5494          when PC_BreakX_CH =>
5495             Dout (Img (Node) & "matching BreakX", Node.Char);
5496
5497             while Cursor < Length loop
5498                if Subject (Cursor + 1) = Node.Char then
5499                   goto Succeed;
5500                else
5501                   Cursor := Cursor + 1;
5502                end if;
5503             end loop;
5504
5505             goto Fail;
5506
5507          --  BreakX (character set case)
5508
5509          when PC_BreakX_CS =>
5510             Dout (Img (Node) & "matching BreakX", Node.CS);
5511
5512             while Cursor < Length loop
5513                if Is_In (Subject (Cursor + 1), Node.CS) then
5514                   goto Succeed;
5515                else
5516                   Cursor := Cursor + 1;
5517                end if;
5518             end loop;
5519
5520             goto Fail;
5521
5522          --  BreakX (string function case)
5523
5524          when PC_BreakX_VF => declare
5525             U   : constant VString       := Node.VF.all;
5526             Str : constant String_Access := Get_String (U);
5527
5528          begin
5529             Dout (Img (Node) & "matching BreakX", Str.all);
5530
5531             while Cursor < Length loop
5532                if Is_In (Subject (Cursor + 1), Str.all) then
5533                   goto Succeed;
5534                else
5535                   Cursor := Cursor + 1;
5536                end if;
5537             end loop;
5538
5539             goto Fail;
5540          end;
5541
5542          --  BreakX (string pointer case)
5543
5544          when PC_BreakX_VP => declare
5545             Str : constant String_Access := Get_String (Node.VP.all);
5546
5547          begin
5548             Dout (Img (Node) & "matching BreakX", Str.all);
5549
5550             while Cursor < Length loop
5551                if Is_In (Subject (Cursor + 1), Str.all) then
5552                   goto Succeed;
5553                else
5554                   Cursor := Cursor + 1;
5555                end if;
5556             end loop;
5557
5558             goto Fail;
5559          end;
5560
5561          --  BreakX_X (BreakX extension). See section on "Compound Pattern
5562          --  Structures". This node is the alternative that is stacked
5563          --  to skip past the break character and extend the break.
5564
5565          when PC_BreakX_X =>
5566             Dout (Img (Node) & "extending BreakX");
5567
5568             Cursor := Cursor + 1;
5569             goto Succeed;
5570
5571          --  Character (one character string)
5572
5573          when PC_Char =>
5574             Dout (Img (Node) & "matching '" & Node.Char & ''');
5575
5576             if Cursor < Length
5577               and then Subject (Cursor + 1) = Node.Char
5578             then
5579                Cursor := Cursor + 1;
5580                goto Succeed;
5581             else
5582                goto Fail;
5583             end if;
5584
5585          --  End of Pattern
5586
5587          when PC_EOP =>
5588             if Stack_Base = Stack_Init then
5589                Dout ("end of pattern");
5590                goto Match_Succeed;
5591
5592             --  End of recursive inner match. See separate section on
5593             --  handing of recursive pattern matches for details.
5594
5595             else
5596                Dout ("terminating recursive match");
5597                Node := Stack (Stack_Base - 1).Node;
5598                Pop_Region;
5599                goto Match;
5600             end if;
5601
5602          --  Fail
5603
5604          when PC_Fail =>
5605             Dout (Img (Node) & "matching Fail");
5606             goto Fail;
5607
5608          --  Fence (built in pattern)
5609
5610          when PC_Fence =>
5611             Dout (Img (Node) & "matching Fence");
5612             Push (CP_Cancel'Access);
5613             goto Succeed;
5614
5615          --  Fence function node X. This is the node that gets control
5616          --  after a successful match of the fenced pattern.
5617
5618          when PC_Fence_X =>
5619             Dout (Img (Node) & "matching Fence function");
5620             Stack_Ptr := Stack_Ptr + 1;
5621             Stack (Stack_Ptr).Cursor := Stack_Base;
5622             Stack (Stack_Ptr).Node   := CP_Fence_Y'Access;
5623             Stack_Base := Stack (Stack_Base).Cursor;
5624             Region_Level := Region_Level - 1;
5625             goto Succeed;
5626
5627          --  Fence function node Y. This is the node that gets control on
5628          --  a failure that occurs after the fenced pattern has matched.
5629
5630          --  Note: the Cursor at this stage is actually the inner stack
5631          --  base value. We don't reset this, but we do use it to strip
5632          --  off all the entries made by the fenced pattern.
5633
5634          when PC_Fence_Y =>
5635             Dout (Img (Node) & "pattern matched by Fence caused failure");
5636             Stack_Ptr := Cursor - 2;
5637             goto Fail;
5638
5639          --  Len (integer case)
5640
5641          when PC_Len_Nat =>
5642             Dout (Img (Node) & "matching Len", Node.Nat);
5643
5644             if Cursor + Node.Nat > Length then
5645                goto Fail;
5646             else
5647                Cursor := Cursor + Node.Nat;
5648                goto Succeed;
5649             end if;
5650
5651          --  Len (Integer function case)
5652
5653          when PC_Len_NF => declare
5654             N : constant Natural := Node.NF.all;
5655
5656          begin
5657             Dout (Img (Node) & "matching Len", N);
5658
5659             if Cursor + N > Length then
5660                goto Fail;
5661             else
5662                Cursor := Cursor + N;
5663                goto Succeed;
5664             end if;
5665          end;
5666
5667          --  Len (integer pointer case)
5668
5669          when PC_Len_NP =>
5670             Dout (Img (Node) & "matching Len", Node.NP.all);
5671
5672             if Cursor + Node.NP.all > Length then
5673                goto Fail;
5674             else
5675                Cursor := Cursor + Node.NP.all;
5676                goto Succeed;
5677             end if;
5678
5679          --  NotAny (one character case)
5680
5681          when PC_NotAny_CH =>
5682             Dout (Img (Node) & "matching NotAny", Node.Char);
5683
5684             if Cursor < Length
5685               and then Subject (Cursor + 1) /= Node.Char
5686             then
5687                Cursor := Cursor + 1;
5688                goto Succeed;
5689             else
5690                goto Fail;
5691             end if;
5692
5693          --  NotAny (character set case)
5694
5695          when PC_NotAny_CS =>
5696             Dout (Img (Node) & "matching NotAny", Node.CS);
5697
5698             if Cursor < Length
5699               and then not Is_In (Subject (Cursor + 1), Node.CS)
5700             then
5701                Cursor := Cursor + 1;
5702                goto Succeed;
5703             else
5704                goto Fail;
5705             end if;
5706
5707          --  NotAny (string function case)
5708
5709          when PC_NotAny_VF => declare
5710             U   : constant VString       := Node.VF.all;
5711             Str : constant String_Access := Get_String (U);
5712
5713          begin
5714             Dout (Img (Node) & "matching NotAny", Str.all);
5715
5716             if Cursor < Length
5717               and then
5718                 not Is_In (Subject (Cursor + 1), Str.all)
5719             then
5720                Cursor := Cursor + 1;
5721                goto Succeed;
5722             else
5723                goto Fail;
5724             end if;
5725          end;
5726
5727          --  NotAny (string pointer case)
5728
5729          when PC_NotAny_VP => declare
5730             Str : constant String_Access := Get_String (Node.VP.all);
5731
5732          begin
5733             Dout (Img (Node) & "matching NotAny", Str.all);
5734
5735             if Cursor < Length
5736               and then
5737                 not Is_In (Subject (Cursor + 1), Str.all)
5738             then
5739                Cursor := Cursor + 1;
5740                goto Succeed;
5741             else
5742                goto Fail;
5743             end if;
5744          end;
5745
5746          --  NSpan (one character case)
5747
5748          when PC_NSpan_CH =>
5749             Dout (Img (Node) & "matching NSpan", Node.Char);
5750
5751             while Cursor < Length
5752               and then Subject (Cursor + 1) = Node.Char
5753             loop
5754                Cursor := Cursor + 1;
5755             end loop;
5756
5757             goto Succeed;
5758
5759          --  NSpan (character set case)
5760
5761          when PC_NSpan_CS =>
5762             Dout (Img (Node) & "matching NSpan", Node.CS);
5763
5764             while Cursor < Length
5765               and then Is_In (Subject (Cursor + 1), Node.CS)
5766             loop
5767                Cursor := Cursor + 1;
5768             end loop;
5769
5770             goto Succeed;
5771
5772          --  NSpan (string function case)
5773
5774          when PC_NSpan_VF => declare
5775             U   : constant VString       := Node.VF.all;
5776             Str : constant String_Access := Get_String (U);
5777
5778          begin
5779             Dout (Img (Node) & "matching NSpan", Str.all);
5780
5781             while Cursor < Length
5782               and then Is_In (Subject (Cursor + 1), Str.all)
5783             loop
5784                Cursor := Cursor + 1;
5785             end loop;
5786
5787             goto Succeed;
5788          end;
5789
5790          --  NSpan (string pointer case)
5791
5792          when PC_NSpan_VP => declare
5793             Str : constant String_Access := Get_String (Node.VP.all);
5794
5795          begin
5796             Dout (Img (Node) & "matching NSpan", Str.all);
5797
5798             while Cursor < Length
5799               and then Is_In (Subject (Cursor + 1), Str.all)
5800             loop
5801                Cursor := Cursor + 1;
5802             end loop;
5803
5804             goto Succeed;
5805          end;
5806
5807          when PC_Null =>
5808             Dout (Img (Node) & "matching null");
5809             goto Succeed;
5810
5811          --  Pos (integer case)
5812
5813          when PC_Pos_Nat =>
5814             Dout (Img (Node) & "matching Pos", Node.Nat);
5815
5816             if Cursor = Node.Nat then
5817                goto Succeed;
5818             else
5819                goto Fail;
5820             end if;
5821
5822          --  Pos (Integer function case)
5823
5824          when PC_Pos_NF => declare
5825             N : constant Natural := Node.NF.all;
5826
5827          begin
5828             Dout (Img (Node) & "matching Pos", N);
5829
5830             if Cursor = N then
5831                goto Succeed;
5832             else
5833                goto Fail;
5834             end if;
5835          end;
5836
5837          --  Pos (integer pointer case)
5838
5839          when PC_Pos_NP =>
5840             Dout (Img (Node) & "matching Pos", Node.NP.all);
5841
5842             if Cursor = Node.NP.all then
5843                goto Succeed;
5844             else
5845                goto Fail;
5846             end if;
5847
5848          --  Predicate function
5849
5850          when PC_Pred_Func =>
5851             Dout (Img (Node) & "matching predicate function");
5852
5853             if Node.BF.all then
5854                goto Succeed;
5855             else
5856                goto Fail;
5857             end if;
5858
5859          --  Region Enter. Initiate new pattern history stack region
5860
5861          when PC_R_Enter =>
5862             Dout (Img (Node) & "starting match of nested pattern");
5863             Stack (Stack_Ptr + 1).Cursor := Cursor;
5864             Push_Region;
5865             goto Succeed;
5866
5867          --  Region Remove node. This is the node stacked by an R_Enter.
5868          --  It removes the special format stack entry right underneath, and
5869          --  then restores the outer level stack base and signals failure.
5870
5871          --  Note: the cursor value at this stage is actually the (negative)
5872          --  stack base value for the outer level.
5873
5874          when PC_R_Remove =>
5875             Dout ("failure, match of nested pattern terminated");
5876             Stack_Base := Cursor;
5877             Region_Level := Region_Level - 1;
5878             Stack_Ptr := Stack_Ptr - 1;
5879             goto Fail;
5880
5881          --  Region restore node. This is the node stacked at the end of an
5882          --  inner level match. Its function is to restore the inner level
5883          --  region, so that alternatives in this region can be sought.
5884
5885          --  Note: the Cursor at this stage is actually the negative of the
5886          --  inner stack base value, which we use to restore the inner region.
5887
5888          when PC_R_Restore =>
5889             Dout ("failure, search for alternatives in nested pattern");
5890             Region_Level := Region_Level + 1;
5891             Stack_Base := Cursor;
5892             goto Fail;
5893
5894          --  Rest
5895
5896          when PC_Rest =>
5897             Dout (Img (Node) & "matching Rest");
5898             Cursor := Length;
5899             goto Succeed;
5900
5901          --  Initiate recursive match (pattern pointer case)
5902
5903          when PC_Rpat =>
5904             Stack (Stack_Ptr + 1).Node := Node.Pthen;
5905             Push_Region;
5906             Dout (Img (Node) & "initiating recursive match");
5907
5908             if Stack_Ptr + Node.PP.all.Stk >= Stack_Size then
5909                raise Pattern_Stack_Overflow;
5910             else
5911                Node := Node.PP.all.P;
5912                goto Match;
5913             end if;
5914
5915          --  RPos (integer case)
5916
5917          when PC_RPos_Nat =>
5918             Dout (Img (Node) & "matching RPos", Node.Nat);
5919
5920             if Cursor = (Length - Node.Nat) then
5921                goto Succeed;
5922             else
5923                goto Fail;
5924             end if;
5925
5926          --  RPos (integer function case)
5927
5928          when PC_RPos_NF => declare
5929             N : constant Natural := Node.NF.all;
5930
5931          begin
5932             Dout (Img (Node) & "matching RPos", N);
5933
5934             if Length - Cursor = N then
5935                goto Succeed;
5936             else
5937                goto Fail;
5938             end if;
5939          end;
5940
5941          --  RPos (integer pointer case)
5942
5943          when PC_RPos_NP =>
5944             Dout (Img (Node) & "matching RPos", Node.NP.all);
5945
5946             if Cursor = (Length - Node.NP.all) then
5947                goto Succeed;
5948             else
5949                goto Fail;
5950             end if;
5951
5952          --  RTab (integer case)
5953
5954          when PC_RTab_Nat =>
5955             Dout (Img (Node) & "matching RTab", Node.Nat);
5956
5957             if Cursor <= (Length - Node.Nat) then
5958                Cursor := Length - Node.Nat;
5959                goto Succeed;
5960             else
5961                goto Fail;
5962             end if;
5963
5964          --  RTab (integer function case)
5965
5966          when PC_RTab_NF => declare
5967             N : constant Natural := Node.NF.all;
5968
5969          begin
5970             Dout (Img (Node) & "matching RPos", N);
5971
5972             if Length - Cursor >= N then
5973                Cursor := Length - N;
5974                goto Succeed;
5975             else
5976                goto Fail;
5977             end if;
5978          end;
5979
5980          --  RTab (integer pointer case)
5981
5982          when PC_RTab_NP =>
5983             Dout (Img (Node) & "matching RPos", Node.NP.all);
5984
5985             if Cursor <= (Length - Node.NP.all) then
5986                Cursor := Length - Node.NP.all;
5987                goto Succeed;
5988             else
5989                goto Fail;
5990             end if;
5991
5992          --  Cursor assignment
5993
5994          when PC_Setcur =>
5995             Dout (Img (Node) & "matching Setcur");
5996             Node.Var.all := Cursor;
5997             goto Succeed;
5998
5999          --  Span (one character case)
6000
6001          when PC_Span_CH => declare
6002             P : Natural := Cursor;
6003
6004          begin
6005             Dout (Img (Node) & "matching Span", Node.Char);
6006
6007             while P < Length
6008               and then Subject (P + 1) = Node.Char
6009             loop
6010                P := P + 1;
6011             end loop;
6012
6013             if P /= Cursor then
6014                Cursor := P;
6015                goto Succeed;
6016             else
6017                goto Fail;
6018             end if;
6019          end;
6020
6021          --  Span (character set case)
6022
6023          when PC_Span_CS => declare
6024             P : Natural := Cursor;
6025
6026          begin
6027             Dout (Img (Node) & "matching Span", Node.CS);
6028
6029             while P < Length
6030               and then Is_In (Subject (P + 1), Node.CS)
6031             loop
6032                P := P + 1;
6033             end loop;
6034
6035             if P /= Cursor then
6036                Cursor := P;
6037                goto Succeed;
6038             else
6039                goto Fail;
6040             end if;
6041          end;
6042
6043          --  Span (string function case)
6044
6045          when PC_Span_VF => declare
6046             U   : constant VString       := Node.VF.all;
6047             Str : constant String_Access := Get_String (U);
6048             P   : Natural := Cursor;
6049
6050          begin
6051             Dout (Img (Node) & "matching Span", Str.all);
6052
6053             while P < Length
6054               and then Is_In (Subject (P + 1), Str.all)
6055             loop
6056                P := P + 1;
6057             end loop;
6058
6059             if P /= Cursor then
6060                Cursor := P;
6061                goto Succeed;
6062             else
6063                goto Fail;
6064             end if;
6065          end;
6066
6067          --  Span (string pointer case)
6068
6069          when PC_Span_VP => declare
6070             Str : constant String_Access := Get_String (Node.VP.all);
6071             P   : Natural := Cursor;
6072
6073          begin
6074             Dout (Img (Node) & "matching Span", Str.all);
6075
6076             while P < Length
6077               and then Is_In (Subject (P + 1), Str.all)
6078             loop
6079                P := P + 1;
6080             end loop;
6081
6082             if P /= Cursor then
6083                Cursor := P;
6084                goto Succeed;
6085             else
6086                goto Fail;
6087             end if;
6088          end;
6089
6090          --  String (two character case)
6091
6092          when PC_String_2 =>
6093             Dout (Img (Node) & "matching " & Image (Node.Str2));
6094
6095             if (Length - Cursor) >= 2
6096               and then Subject (Cursor + 1 .. Cursor + 2) = Node.Str2
6097             then
6098                Cursor := Cursor + 2;
6099                goto Succeed;
6100             else
6101                goto Fail;
6102             end if;
6103
6104          --  String (three character case)
6105
6106          when PC_String_3 =>
6107             Dout (Img (Node) & "matching " & Image (Node.Str3));
6108
6109             if (Length - Cursor) >= 3
6110               and then Subject (Cursor + 1 .. Cursor + 3) = Node.Str3
6111             then
6112                Cursor := Cursor + 3;
6113                goto Succeed;
6114             else
6115                goto Fail;
6116             end if;
6117
6118          --  String (four character case)
6119
6120          when PC_String_4 =>
6121             Dout (Img (Node) & "matching " & Image (Node.Str4));
6122
6123             if (Length - Cursor) >= 4
6124               and then Subject (Cursor + 1 .. Cursor + 4) = Node.Str4
6125             then
6126                Cursor := Cursor + 4;
6127                goto Succeed;
6128             else
6129                goto Fail;
6130             end if;
6131
6132          --  String (five character case)
6133
6134          when PC_String_5 =>
6135             Dout (Img (Node) & "matching " & Image (Node.Str5));
6136
6137             if (Length - Cursor) >= 5
6138               and then Subject (Cursor + 1 .. Cursor + 5) = Node.Str5
6139             then
6140                Cursor := Cursor + 5;
6141                goto Succeed;
6142             else
6143                goto Fail;
6144             end if;
6145
6146          --  String (six character case)
6147
6148          when PC_String_6 =>
6149             Dout (Img (Node) & "matching " & Image (Node.Str6));
6150
6151             if (Length - Cursor) >= 6
6152               and then Subject (Cursor + 1 .. Cursor + 6) = Node.Str6
6153             then
6154                Cursor := Cursor + 6;
6155                goto Succeed;
6156             else
6157                goto Fail;
6158             end if;
6159
6160          --  String (case of more than six characters)
6161
6162          when PC_String => declare
6163             Len : constant Natural := Node.Str'Length;
6164
6165          begin
6166             Dout (Img (Node) & "matching " & Image (Node.Str.all));
6167
6168             if (Length - Cursor) >= Len
6169               and then Node.Str.all = Subject (Cursor + 1 .. Cursor + Len)
6170             then
6171                Cursor := Cursor + Len;
6172                goto Succeed;
6173             else
6174                goto Fail;
6175             end if;
6176          end;
6177
6178          --  String (function case)
6179
6180          when PC_String_VF => declare
6181             U   : constant VString       := Node.VF.all;
6182             Str : constant String_Access := Get_String (U);
6183             Len : constant Natural       := Str'Length;
6184
6185          begin
6186             Dout (Img (Node) & "matching " & Image (Str.all));
6187
6188             if (Length - Cursor) >= Len
6189               and then Str.all = Subject (Cursor + 1 .. Cursor + Len)
6190             then
6191                Cursor := Cursor + Len;
6192                goto Succeed;
6193             else
6194                goto Fail;
6195             end if;
6196          end;
6197
6198          --  String (vstring pointer case)
6199
6200          when PC_String_VP => declare
6201             S   : constant String_Access := Get_String (Node.VP.all);
6202             Len : constant Natural :=
6203                     Ada.Strings.Unbounded.Length (Node.VP.all);
6204
6205          begin
6206             Dout
6207               (Img (Node) & "matching " & Image (S.all));
6208
6209             if (Length - Cursor) >= Len
6210               and then S.all = Subject (Cursor + 1 .. Cursor + Len)
6211             then
6212                Cursor := Cursor + Len;
6213                goto Succeed;
6214             else
6215                goto Fail;
6216             end if;
6217          end;
6218
6219          --  Succeed
6220
6221          when PC_Succeed =>
6222             Dout (Img (Node) & "matching Succeed");
6223             Push (Node);
6224             goto Succeed;
6225
6226          --  Tab (integer case)
6227
6228          when PC_Tab_Nat =>
6229             Dout (Img (Node) & "matching Tab", Node.Nat);
6230
6231             if Cursor <= Node.Nat then
6232                Cursor := Node.Nat;
6233                goto Succeed;
6234             else
6235                goto Fail;
6236             end if;
6237
6238          --  Tab (integer function case)
6239
6240          when PC_Tab_NF => declare
6241             N : constant Natural := Node.NF.all;
6242
6243          begin
6244             Dout (Img (Node) & "matching Tab ", N);
6245
6246             if Cursor <= N then
6247                Cursor := N;
6248                goto Succeed;
6249             else
6250                goto Fail;
6251             end if;
6252          end;
6253
6254          --  Tab (integer pointer case)
6255
6256          when PC_Tab_NP =>
6257             Dout (Img (Node) & "matching Tab ", Node.NP.all);
6258
6259             if Cursor <= Node.NP.all then
6260                Cursor := Node.NP.all;
6261                goto Succeed;
6262             else
6263                goto Fail;
6264             end if;
6265
6266          --  Unanchored movement
6267
6268          when PC_Unanchored =>
6269             Dout ("attempting to move anchor point");
6270
6271             --  All done if we tried every position
6272
6273             if Cursor > Length then
6274                goto Match_Fail;
6275
6276             --  Otherwise extend the anchor point, and restack ourself
6277
6278             else
6279                Cursor := Cursor + 1;
6280                Push (Node);
6281                goto Succeed;
6282             end if;
6283
6284          --  Write immediate. This node performs the actual write
6285
6286          when PC_Write_Imm =>
6287             Dout (Img (Node) & "executing immediate write of " &
6288                    Subject (Stack (Stack_Base - 1).Cursor + 1 .. Cursor));
6289
6290             Put_Line
6291               (Node.FP.all,
6292                Subject (Stack (Stack_Base - 1).Cursor + 1 .. Cursor));
6293             Pop_Region;
6294             goto Succeed;
6295
6296          --  Write on match. This node sets up for the eventual write
6297
6298          when PC_Write_OnM =>
6299             Dout (Img (Node) & "registering deferred write");
6300             Stack (Stack_Base - 1).Node := Node;
6301             Push (CP_Assign'Access);
6302             Pop_Region;
6303             Assign_OnM := True;
6304             goto Succeed;
6305
6306       end case;
6307
6308       --  We are NOT allowed to fall though this case statement, since every
6309       --  match routine must end by executing a goto to the appropriate point
6310       --  in the finite state machine model.
6311
6312       Logic_Error;
6313
6314    end XMatchD;
6315
6316 end GNAT.Spitbol.Patterns;