OSDN Git Service

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