OSDN Git Service

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