OSDN Git Service

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