OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gcc-4.5.1/] [gcc/] [ada/] [g-spipat.adb] - Blame information for rev 826

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 281 jeremybenn
------------------------------------------------------------------------------
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-2008, 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     : String_Access;
2797
      L     : Natural;
2798
 
2799
      Start : Natural;
2800
      Stop  : Natural;
2801
      pragma Unreferenced (Stop);
2802
 
2803
   begin
2804
      Get_String (Subject, S, L);
2805
 
2806
      if Debug_Mode then
2807
         XMatchD (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2808
      else
2809
         XMatch  (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2810
      end if;
2811
 
2812
      return Start /= 0;
2813
   end Match;
2814
 
2815
   function Match
2816
     (Subject : String;
2817
      Pat     : Pattern) return Boolean
2818
   is
2819
      Start, Stop : Natural;
2820
      pragma Unreferenced (Stop);
2821
 
2822
      subtype String1 is String (1 .. Subject'Length);
2823
 
2824
   begin
2825
      if Debug_Mode then
2826
         XMatchD (String1 (Subject), Pat.P, Pat.Stk, Start, Stop);
2827
      else
2828
         XMatch  (String1 (Subject), Pat.P, Pat.Stk, Start, Stop);
2829
      end if;
2830
 
2831
      return Start /= 0;
2832
   end Match;
2833
 
2834
   function Match
2835
     (Subject : VString_Var;
2836
      Pat     : Pattern;
2837
      Replace : VString) return Boolean
2838
   is
2839
      Start : Natural;
2840
      Stop  : Natural;
2841
      S     : String_Access;
2842
      L     : Natural;
2843
 
2844
   begin
2845
      Get_String (Subject, S, L);
2846
 
2847
      if Debug_Mode then
2848
         XMatchD (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2849
      else
2850
         XMatch  (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2851
      end if;
2852
 
2853
      if Start = 0 then
2854
         return False;
2855
      else
2856
         Get_String (Replace, S, L);
2857
         Replace_Slice
2858
           (Subject'Unrestricted_Access.all, Start, Stop, S (1 .. L));
2859
         return True;
2860
      end if;
2861
   end Match;
2862
 
2863
   function Match
2864
     (Subject : VString_Var;
2865
      Pat     : Pattern;
2866
      Replace : String) return Boolean
2867
   is
2868
      Start : Natural;
2869
      Stop  : Natural;
2870
      S     : String_Access;
2871
      L     : Natural;
2872
 
2873
   begin
2874
      Get_String (Subject, S, L);
2875
 
2876
      if Debug_Mode then
2877
         XMatchD (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2878
      else
2879
         XMatch  (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2880
      end if;
2881
 
2882
      if Start = 0 then
2883
         return False;
2884
      else
2885
         Replace_Slice
2886
           (Subject'Unrestricted_Access.all, Start, Stop, Replace);
2887
         return True;
2888
      end if;
2889
   end Match;
2890
 
2891
   procedure Match
2892
     (Subject : VString;
2893
      Pat     : Pattern)
2894
   is
2895
      S : String_Access;
2896
      L : Natural;
2897
 
2898
      Start : Natural;
2899
      Stop  : Natural;
2900
      pragma Unreferenced (Start, Stop);
2901
 
2902
   begin
2903
      Get_String (Subject, S, L);
2904
 
2905
      if Debug_Mode then
2906
         XMatchD (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2907
      else
2908
         XMatch  (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2909
      end if;
2910
   end Match;
2911
 
2912
   procedure Match
2913
     (Subject : String;
2914
      Pat     : Pattern)
2915
   is
2916
      Start, Stop : Natural;
2917
      pragma Unreferenced (Start, Stop);
2918
 
2919
      subtype String1 is String (1 .. Subject'Length);
2920
 
2921
   begin
2922
      if Debug_Mode then
2923
         XMatchD (String1 (Subject), Pat.P, Pat.Stk, Start, Stop);
2924
      else
2925
         XMatch  (String1 (Subject), Pat.P, Pat.Stk, Start, Stop);
2926
      end if;
2927
   end Match;
2928
 
2929
   procedure Match
2930
     (Subject : in out VString;
2931
      Pat     : Pattern;
2932
      Replace : VString)
2933
   is
2934
      Start : Natural;
2935
      Stop  : Natural;
2936
      S     : String_Access;
2937
      L     : Natural;
2938
 
2939
   begin
2940
      Get_String (Subject, S, L);
2941
 
2942
      if Debug_Mode then
2943
         XMatchD (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2944
      else
2945
         XMatch  (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2946
      end if;
2947
 
2948
      if Start /= 0 then
2949
         Get_String (Replace, S, L);
2950
         Replace_Slice (Subject, Start, Stop, S (1 .. L));
2951
      end if;
2952
   end Match;
2953
 
2954
   procedure Match
2955
     (Subject : in out VString;
2956
      Pat     : Pattern;
2957
      Replace : String)
2958
   is
2959
      Start : Natural;
2960
      Stop  : Natural;
2961
      S     : String_Access;
2962
      L     : Natural;
2963
 
2964
   begin
2965
      Get_String (Subject, S, L);
2966
 
2967
      if Debug_Mode then
2968
         XMatchD (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2969
      else
2970
         XMatch  (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2971
      end if;
2972
 
2973
      if Start /= 0 then
2974
         Replace_Slice (Subject, Start, Stop, Replace);
2975
      end if;
2976
   end Match;
2977
 
2978
   function Match
2979
     (Subject : VString;
2980
      Pat     : PString) return Boolean
2981
   is
2982
      Pat_Len : constant Natural := Pat'Length;
2983
      S       : String_Access;
2984
      L       : Natural;
2985
 
2986
   begin
2987
      Get_String (Subject, S, L);
2988
 
2989
      if Anchored_Mode then
2990
         if Pat_Len > L then
2991
            return False;
2992
         else
2993
            return Pat = S (1 .. Pat_Len);
2994
         end if;
2995
 
2996
      else
2997
         for J in 1 .. L - Pat_Len + 1 loop
2998
            if Pat = S (J .. J + (Pat_Len - 1)) then
2999
               return True;
3000
            end if;
3001
         end loop;
3002
 
3003
         return False;
3004
      end if;
3005
   end Match;
3006
 
3007
   function Match
3008
     (Subject : String;
3009
      Pat     : PString) return Boolean
3010
   is
3011
      Pat_Len : constant Natural := Pat'Length;
3012
      Sub_Len : constant Natural := Subject'Length;
3013
      SFirst  : constant Natural := Subject'First;
3014
 
3015
   begin
3016
      if Anchored_Mode then
3017
         if Pat_Len > Sub_Len then
3018
            return False;
3019
         else
3020
            return Pat = Subject (SFirst .. SFirst + Pat_Len - 1);
3021
         end if;
3022
 
3023
      else
3024
         for J in SFirst .. SFirst + Sub_Len - Pat_Len loop
3025
            if Pat = Subject (J .. J + (Pat_Len - 1)) then
3026
               return True;
3027
            end if;
3028
         end loop;
3029
 
3030
         return False;
3031
      end if;
3032
   end Match;
3033
 
3034
   function Match
3035
     (Subject : VString_Var;
3036
      Pat     : PString;
3037
      Replace : VString) return Boolean
3038
   is
3039
      Start : Natural;
3040
      Stop  : Natural;
3041
      S     : String_Access;
3042
      L     : Natural;
3043
 
3044
   begin
3045
      Get_String (Subject, S, L);
3046
 
3047
      if Debug_Mode then
3048
         XMatchD (S (1 .. L), S_To_PE (Pat), 0, Start, Stop);
3049
      else
3050
         XMatch  (S (1 .. L), S_To_PE (Pat), 0, Start, Stop);
3051
      end if;
3052
 
3053
      if Start = 0 then
3054
         return False;
3055
      else
3056
         Get_String (Replace, S, L);
3057
         Replace_Slice
3058
           (Subject'Unrestricted_Access.all, Start, Stop, S (1 .. L));
3059
         return True;
3060
      end if;
3061
   end Match;
3062
 
3063
   function Match
3064
     (Subject : VString_Var;
3065
      Pat     : PString;
3066
      Replace : String) return Boolean
3067
   is
3068
      Start : Natural;
3069
      Stop  : Natural;
3070
      S     : String_Access;
3071
      L     : Natural;
3072
 
3073
   begin
3074
      Get_String (Subject, S, L);
3075
 
3076
      if Debug_Mode then
3077
         XMatchD (S (1 .. L), S_To_PE (Pat), 0, Start, Stop);
3078
      else
3079
         XMatch  (S (1 .. L), S_To_PE (Pat), 0, Start, Stop);
3080
      end if;
3081
 
3082
      if Start = 0 then
3083
         return False;
3084
      else
3085
         Replace_Slice
3086
           (Subject'Unrestricted_Access.all, Start, Stop, Replace);
3087
         return True;
3088
      end if;
3089
   end Match;
3090
 
3091
   procedure Match
3092
     (Subject : VString;
3093
      Pat     : PString)
3094
   is
3095
      S : String_Access;
3096
      L : Natural;
3097
 
3098
      Start : Natural;
3099
      Stop  : Natural;
3100
      pragma Unreferenced (Start, Stop);
3101
 
3102
   begin
3103
      Get_String (Subject, S, L);
3104
 
3105
      if Debug_Mode then
3106
         XMatchD (S (1 .. L), S_To_PE (Pat), 0, Start, Stop);
3107
      else
3108
         XMatch  (S (1 .. L), S_To_PE (Pat), 0, Start, Stop);
3109
      end if;
3110
   end Match;
3111
 
3112
   procedure Match
3113
     (Subject : String;
3114
      Pat     : PString)
3115
   is
3116
      Start, Stop : Natural;
3117
      pragma Unreferenced (Start, Stop);
3118
 
3119
      subtype String1 is String (1 .. Subject'Length);
3120
 
3121
   begin
3122
      if Debug_Mode then
3123
         XMatchD (String1 (Subject), S_To_PE (Pat), 0, Start, Stop);
3124
      else
3125
         XMatch  (String1 (Subject), S_To_PE (Pat), 0, Start, Stop);
3126
      end if;
3127
   end Match;
3128
 
3129
   procedure Match
3130
     (Subject : in out VString;
3131
      Pat     : PString;
3132
      Replace : VString)
3133
   is
3134
      Start : Natural;
3135
      Stop  : Natural;
3136
      S     : String_Access;
3137
      L     : Natural;
3138
 
3139
   begin
3140
      Get_String (Subject, S, L);
3141
 
3142
      if Debug_Mode then
3143
         XMatchD (S (1 .. L), S_To_PE (Pat), 0, Start, Stop);
3144
      else
3145
         XMatch  (S (1 .. L), S_To_PE (Pat), 0, Start, Stop);
3146
      end if;
3147
 
3148
      if Start /= 0 then
3149
         Get_String (Replace, S, L);
3150
         Replace_Slice (Subject, Start, Stop, S (1 .. L));
3151
      end if;
3152
   end Match;
3153
 
3154
   procedure Match
3155
     (Subject : in out VString;
3156
      Pat     : PString;
3157
      Replace : String)
3158
   is
3159
      Start : Natural;
3160
      Stop  : Natural;
3161
      S     : String_Access;
3162
      L     : Natural;
3163
 
3164
   begin
3165
      Get_String (Subject, S, L);
3166
 
3167
      if Debug_Mode then
3168
         XMatchD (S (1 .. L), S_To_PE (Pat), 0, Start, Stop);
3169
      else
3170
         XMatch  (S (1 .. L), S_To_PE (Pat), 0, Start, Stop);
3171
      end if;
3172
 
3173
      if Start /= 0 then
3174
         Replace_Slice (Subject, Start, Stop, Replace);
3175
      end if;
3176
   end Match;
3177
 
3178
   function Match
3179
     (Subject : VString_Var;
3180
      Pat     : Pattern;
3181
      Result  : Match_Result_Var) return Boolean
3182
   is
3183
      Start : Natural;
3184
      Stop  : Natural;
3185
      S     : String_Access;
3186
      L     : Natural;
3187
 
3188
   begin
3189
      Get_String (Subject, S, L);
3190
 
3191
      if Debug_Mode then
3192
         XMatchD (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
3193
      else
3194
         XMatch  (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
3195
      end if;
3196
 
3197
      if Start = 0 then
3198
         Result'Unrestricted_Access.all.Var := null;
3199
         return False;
3200
 
3201
      else
3202
         Result'Unrestricted_Access.all.Var   := Subject'Unrestricted_Access;
3203
         Result'Unrestricted_Access.all.Start := Start;
3204
         Result'Unrestricted_Access.all.Stop  := Stop;
3205
         return True;
3206
      end if;
3207
   end Match;
3208
 
3209
   procedure Match
3210
     (Subject : in out VString;
3211
      Pat     : Pattern;
3212
      Result  : out Match_Result)
3213
   is
3214
      Start : Natural;
3215
      Stop  : Natural;
3216
      S     : String_Access;
3217
      L     : Natural;
3218
 
3219
   begin
3220
      Get_String (Subject, S, L);
3221
 
3222
      if Debug_Mode then
3223
         XMatchD (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
3224
      else
3225
         XMatch  (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
3226
      end if;
3227
 
3228
      if Start = 0 then
3229
         Result.Var := null;
3230
      else
3231
         Result.Var   := Subject'Unrestricted_Access;
3232
         Result.Start := Start;
3233
         Result.Stop  := Stop;
3234
      end if;
3235
   end Match;
3236
 
3237
   ---------------
3238
   -- New_LineD --
3239
   ---------------
3240
 
3241
   procedure New_LineD is
3242
   begin
3243
      if Internal_Debug then
3244
         New_Line;
3245
      end if;
3246
   end New_LineD;
3247
 
3248
   ------------
3249
   -- NotAny --
3250
   ------------
3251
 
3252
   function NotAny (Str : String) return Pattern is
3253
   begin
3254
      return (AFC with 0, new PE'(PC_NotAny_CS, 1, EOP, To_Set (Str)));
3255
   end NotAny;
3256
 
3257
   function NotAny (Str : VString) return Pattern is
3258
   begin
3259
      return NotAny (S (Str));
3260
   end NotAny;
3261
 
3262
   function NotAny (Str : Character) return Pattern is
3263
   begin
3264
      return (AFC with 0, new PE'(PC_NotAny_CH, 1, EOP, Str));
3265
   end NotAny;
3266
 
3267
   function NotAny (Str : Character_Set) return Pattern is
3268
   begin
3269
      return (AFC with 0, new PE'(PC_NotAny_CS, 1, EOP, Str));
3270
   end NotAny;
3271
 
3272
   function NotAny (Str : not null access VString) return Pattern is
3273
   begin
3274
      return (AFC with 0, new PE'(PC_NotAny_VP, 1, EOP, VString_Ptr (Str)));
3275
   end NotAny;
3276
 
3277
   function NotAny (Str : VString_Func) return Pattern is
3278
   begin
3279
      return (AFC with 0, new PE'(PC_NotAny_VF, 1, EOP, Str));
3280
   end NotAny;
3281
 
3282
   -----------
3283
   -- NSpan --
3284
   -----------
3285
 
3286
   function NSpan (Str : String) return Pattern is
3287
   begin
3288
      return (AFC with 0, new PE'(PC_NSpan_CS, 1, EOP, To_Set (Str)));
3289
   end NSpan;
3290
 
3291
   function NSpan (Str : VString) return Pattern is
3292
   begin
3293
      return NSpan (S (Str));
3294
   end NSpan;
3295
 
3296
   function NSpan (Str : Character) return Pattern is
3297
   begin
3298
      return (AFC with 0, new PE'(PC_NSpan_CH, 1, EOP, Str));
3299
   end NSpan;
3300
 
3301
   function NSpan (Str : Character_Set) return Pattern is
3302
   begin
3303
      return (AFC with 0, new PE'(PC_NSpan_CS, 1, EOP, Str));
3304
   end NSpan;
3305
 
3306
   function NSpan (Str : not null access VString) return Pattern is
3307
   begin
3308
      return (AFC with 0, new PE'(PC_NSpan_VP, 1, EOP, VString_Ptr (Str)));
3309
   end NSpan;
3310
 
3311
   function NSpan (Str : VString_Func) return Pattern is
3312
   begin
3313
      return (AFC with 0, new PE'(PC_NSpan_VF, 1, EOP, Str));
3314
   end NSpan;
3315
 
3316
   ---------
3317
   -- Pos --
3318
   ---------
3319
 
3320
   function Pos (Count : Natural) return Pattern is
3321
   begin
3322
      return (AFC with 0, new PE'(PC_Pos_Nat, 1, EOP, Count));
3323
   end Pos;
3324
 
3325
   function Pos (Count : Natural_Func) return Pattern is
3326
   begin
3327
      return (AFC with 0, new PE'(PC_Pos_NF, 1, EOP, Count));
3328
   end Pos;
3329
 
3330
   function Pos (Count : not null access Natural) return Pattern is
3331
   begin
3332
      return (AFC with 0, new PE'(PC_Pos_NP, 1, EOP, Natural_Ptr (Count)));
3333
   end Pos;
3334
 
3335
   ----------
3336
   -- PutD --
3337
   ----------
3338
 
3339
   procedure PutD (Str : String) is
3340
   begin
3341
      if Internal_Debug then
3342
         Put (Str);
3343
      end if;
3344
   end PutD;
3345
 
3346
   ---------------
3347
   -- Put_LineD --
3348
   ---------------
3349
 
3350
   procedure Put_LineD (Str : String) is
3351
   begin
3352
      if Internal_Debug then
3353
         Put_Line (Str);
3354
      end if;
3355
   end Put_LineD;
3356
 
3357
   -------------
3358
   -- Replace --
3359
   -------------
3360
 
3361
   procedure Replace
3362
     (Result  : in out Match_Result;
3363
      Replace : VString)
3364
   is
3365
      S : String_Access;
3366
      L : Natural;
3367
 
3368
   begin
3369
      Get_String (Replace, S, L);
3370
 
3371
      if Result.Var /= null then
3372
         Replace_Slice (Result.Var.all, Result.Start, Result.Stop, S (1 .. L));
3373
         Result.Var := null;
3374
      end if;
3375
   end Replace;
3376
 
3377
   ----------
3378
   -- Rest --
3379
   ----------
3380
 
3381
   function Rest return Pattern is
3382
   begin
3383
      return (AFC with 0, new PE'(PC_Rest, 1, EOP));
3384
   end Rest;
3385
 
3386
   ----------
3387
   -- Rpos --
3388
   ----------
3389
 
3390
   function Rpos (Count : Natural) return Pattern is
3391
   begin
3392
      return (AFC with 0, new PE'(PC_RPos_Nat, 1, EOP, Count));
3393
   end Rpos;
3394
 
3395
   function Rpos (Count : Natural_Func) return Pattern is
3396
   begin
3397
      return (AFC with 0, new PE'(PC_RPos_NF, 1, EOP, Count));
3398
   end Rpos;
3399
 
3400
   function Rpos (Count : not null access Natural) return Pattern is
3401
   begin
3402
      return (AFC with 0, new PE'(PC_RPos_NP, 1, EOP, Natural_Ptr (Count)));
3403
   end Rpos;
3404
 
3405
   ----------
3406
   -- Rtab --
3407
   ----------
3408
 
3409
   function Rtab (Count : Natural) return Pattern is
3410
   begin
3411
      return (AFC with 0, new PE'(PC_RTab_Nat, 1, EOP, Count));
3412
   end Rtab;
3413
 
3414
   function Rtab (Count : Natural_Func) return Pattern is
3415
   begin
3416
      return (AFC with 0, new PE'(PC_RTab_NF, 1, EOP, Count));
3417
   end Rtab;
3418
 
3419
   function Rtab (Count : not null access Natural) return Pattern is
3420
   begin
3421
      return (AFC with 0, new PE'(PC_RTab_NP, 1, EOP, Natural_Ptr (Count)));
3422
   end Rtab;
3423
 
3424
   -------------
3425
   -- S_To_PE --
3426
   -------------
3427
 
3428
   function S_To_PE (Str : PString) return PE_Ptr is
3429
      Len : constant Natural := Str'Length;
3430
 
3431
   begin
3432
      case Len is
3433
         when 0 =>
3434
            return new PE'(PC_Null,     1, EOP);
3435
 
3436
         when 1 =>
3437
            return new PE'(PC_Char,     1, EOP, Str (Str'First));
3438
 
3439
         when 2 =>
3440
            return new PE'(PC_String_2, 1, EOP, Str);
3441
 
3442
         when 3 =>
3443
            return new PE'(PC_String_3, 1, EOP, Str);
3444
 
3445
         when 4 =>
3446
            return new PE'(PC_String_4, 1, EOP, Str);
3447
 
3448
         when 5 =>
3449
            return new PE'(PC_String_5, 1, EOP, Str);
3450
 
3451
         when 6 =>
3452
            return new PE'(PC_String_6, 1, EOP, Str);
3453
 
3454
         when others =>
3455
            return new PE'(PC_String, 1, EOP, new String'(Str));
3456
 
3457
      end case;
3458
   end S_To_PE;
3459
 
3460
   -------------------
3461
   -- Set_Successor --
3462
   -------------------
3463
 
3464
   --  Note: this procedure is not used by the normal concatenation circuit,
3465
   --  since other fixups are required on the left operand in this case, and
3466
   --  they might as well be done all together.
3467
 
3468
   procedure Set_Successor (Pat : PE_Ptr; Succ : PE_Ptr) is
3469
   begin
3470
      if Pat = null then
3471
         Uninitialized_Pattern;
3472
 
3473
      elsif Pat = EOP then
3474
         Logic_Error;
3475
 
3476
      else
3477
         declare
3478
            Refs : Ref_Array (1 .. Pat.Index);
3479
            --  We build a reference array for L whose N'th element points to
3480
            --  the pattern element of L whose original Index value is N.
3481
 
3482
            P : PE_Ptr;
3483
 
3484
         begin
3485
            Build_Ref_Array (Pat, Refs);
3486
 
3487
            for J in Refs'Range loop
3488
               P := Refs (J);
3489
 
3490
               if P.Pthen = EOP then
3491
                  P.Pthen := Succ;
3492
               end if;
3493
 
3494
               if P.Pcode in PC_Has_Alt and then P.Alt = EOP then
3495
                  P.Alt := Succ;
3496
               end if;
3497
            end loop;
3498
         end;
3499
      end if;
3500
   end Set_Successor;
3501
 
3502
   ------------
3503
   -- Setcur --
3504
   ------------
3505
 
3506
   function Setcur (Var : not null access Natural) return Pattern is
3507
   begin
3508
      return (AFC with 0, new PE'(PC_Setcur, 1, EOP, Natural_Ptr (Var)));
3509
   end Setcur;
3510
 
3511
   ----------
3512
   -- Span --
3513
   ----------
3514
 
3515
   function Span (Str : String) return Pattern is
3516
   begin
3517
      return (AFC with 0, new PE'(PC_Span_CS, 1, EOP, To_Set (Str)));
3518
   end Span;
3519
 
3520
   function Span (Str : VString) return Pattern is
3521
   begin
3522
      return Span (S (Str));
3523
   end Span;
3524
 
3525
   function Span (Str : Character) return Pattern is
3526
   begin
3527
      return (AFC with 0, new PE'(PC_Span_CH, 1, EOP, Str));
3528
   end Span;
3529
 
3530
   function Span (Str : Character_Set) return Pattern is
3531
   begin
3532
      return (AFC with 0, new PE'(PC_Span_CS, 1, EOP, Str));
3533
   end Span;
3534
 
3535
   function Span (Str : not null access VString) return Pattern is
3536
   begin
3537
      return (AFC with 0, new PE'(PC_Span_VP, 1, EOP, VString_Ptr (Str)));
3538
   end Span;
3539
 
3540
   function Span (Str : VString_Func) return Pattern is
3541
   begin
3542
      return (AFC with 0, new PE'(PC_Span_VF, 1, EOP, Str));
3543
   end Span;
3544
 
3545
   ------------
3546
   -- Str_BF --
3547
   ------------
3548
 
3549
   function Str_BF (A : Boolean_Func) return String is
3550
      function To_A is new Ada.Unchecked_Conversion (Boolean_Func, Address);
3551
   begin
3552
      return "BF(" & Image (To_A (A)) & ')';
3553
   end Str_BF;
3554
 
3555
   ------------
3556
   -- Str_FP --
3557
   ------------
3558
 
3559
   function Str_FP (A : File_Ptr) return String is
3560
   begin
3561
      return "FP(" & Image (A.all'Address) & ')';
3562
   end Str_FP;
3563
 
3564
   ------------
3565
   -- Str_NF --
3566
   ------------
3567
 
3568
   function Str_NF (A : Natural_Func) return String is
3569
      function To_A is new Ada.Unchecked_Conversion (Natural_Func, Address);
3570
   begin
3571
      return "NF(" & Image (To_A (A)) & ')';
3572
   end Str_NF;
3573
 
3574
   ------------
3575
   -- Str_NP --
3576
   ------------
3577
 
3578
   function Str_NP (A : Natural_Ptr) return String is
3579
   begin
3580
      return "NP(" & Image (A.all'Address) & ')';
3581
   end Str_NP;
3582
 
3583
   ------------
3584
   -- Str_PP --
3585
   ------------
3586
 
3587
   function Str_PP (A : Pattern_Ptr) return String is
3588
   begin
3589
      return "PP(" & Image (A.all'Address) & ')';
3590
   end Str_PP;
3591
 
3592
   ------------
3593
   -- Str_VF --
3594
   ------------
3595
 
3596
   function Str_VF (A : VString_Func) return String is
3597
      function To_A is new Ada.Unchecked_Conversion (VString_Func, Address);
3598
   begin
3599
      return "VF(" & Image (To_A (A)) & ')';
3600
   end Str_VF;
3601
 
3602
   ------------
3603
   -- Str_VP --
3604
   ------------
3605
 
3606
   function Str_VP (A : VString_Ptr) return String is
3607
   begin
3608
      return "VP(" & Image (A.all'Address) & ')';
3609
   end Str_VP;
3610
 
3611
   -------------
3612
   -- Succeed --
3613
   -------------
3614
 
3615
   function Succeed return Pattern is
3616
   begin
3617
      return (AFC with 1, new PE'(PC_Succeed, 1, EOP));
3618
   end Succeed;
3619
 
3620
   ---------
3621
   -- Tab --
3622
   ---------
3623
 
3624
   function Tab (Count : Natural) return Pattern is
3625
   begin
3626
      return (AFC with 0, new PE'(PC_Tab_Nat, 1, EOP, Count));
3627
   end Tab;
3628
 
3629
   function Tab (Count : Natural_Func) return Pattern is
3630
   begin
3631
      return (AFC with 0, new PE'(PC_Tab_NF, 1, EOP, Count));
3632
   end Tab;
3633
 
3634
   function Tab (Count : not null access Natural) return Pattern is
3635
   begin
3636
      return (AFC with 0, new PE'(PC_Tab_NP, 1, EOP, Natural_Ptr (Count)));
3637
   end Tab;
3638
 
3639
   ---------------------------
3640
   -- Uninitialized_Pattern --
3641
   ---------------------------
3642
 
3643
   procedure Uninitialized_Pattern is
3644
   begin
3645
      raise Program_Error with
3646
         "uninitialized value of type GNAT.Spitbol.Patterns.Pattern";
3647
   end Uninitialized_Pattern;
3648
 
3649
   ------------
3650
   -- XMatch --
3651
   ------------
3652
 
3653
   procedure XMatch
3654
     (Subject : String;
3655
      Pat_P   : PE_Ptr;
3656
      Pat_S   : Natural;
3657
      Start   : out Natural;
3658
      Stop    : out Natural)
3659
   is
3660
      Node : PE_Ptr;
3661
      --  Pointer to current pattern node. Initialized from Pat_P, and then
3662
      --  updated as the match proceeds through its constituent elements.
3663
 
3664
      Length : constant Natural := Subject'Length;
3665
      --  Length of string (= Subject'Last, since Subject'First is always 1)
3666
 
3667
      Cursor : Integer := 0;
3668
      --  If the value is non-negative, then this value is the index showing
3669
      --  the current position of the match in the subject string. The next
3670
      --  character to be matched is at Subject (Cursor + 1). Note that since
3671
      --  our view of the subject string in XMatch always has a lower bound
3672
      --  of one, regardless of original bounds, that this definition exactly
3673
      --  corresponds to the cursor value as referenced by functions like Pos.
3674
      --
3675
      --  If the value is negative, then this is a saved stack pointer,
3676
      --  typically a base pointer of an inner or outer region. Cursor
3677
      --  temporarily holds such a value when it is popped from the stack
3678
      --  by Fail. In all cases, Cursor is reset to a proper non-negative
3679
      --  cursor value before the match proceeds (e.g. by propagating the
3680
      --  failure and popping a "real" cursor value from the stack.
3681
 
3682
      PE_Unanchored : aliased PE := (PC_Unanchored, 0, Pat_P);
3683
      --  Dummy pattern element used in the unanchored case
3684
 
3685
      Stack : Stack_Type;
3686
      --  The pattern matching failure stack for this call to Match
3687
 
3688
      Stack_Ptr : Stack_Range;
3689
      --  Current stack pointer. This points to the top element of the stack
3690
      --  that is currently in use. At the outer level this is the special
3691
      --  entry placed on the stack according to the anchor mode.
3692
 
3693
      Stack_Init : constant Stack_Range := Stack'First + 1;
3694
      --  This is the initial value of the Stack_Ptr and Stack_Base. The
3695
      --  initial (Stack'First) element of the stack is not used so that
3696
      --  when we pop the last element off, Stack_Ptr is still in range.
3697
 
3698
      Stack_Base : Stack_Range;
3699
      --  This value is the stack base value, i.e. the stack pointer for the
3700
      --  first history stack entry in the current stack region. See separate
3701
      --  section on handling of recursive pattern matches.
3702
 
3703
      Assign_OnM : Boolean := False;
3704
      --  Set True if assign-on-match or write-on-match operations may be
3705
      --  present in the history stack, which must then be scanned on a
3706
      --  successful match.
3707
 
3708
      procedure Pop_Region;
3709
      pragma Inline (Pop_Region);
3710
      --  Used at the end of processing of an inner region. If the inner
3711
      --  region left no stack entries, then all trace of it is removed.
3712
      --  Otherwise a PC_Restore_Region entry is pushed to ensure proper
3713
      --  handling of alternatives in the inner region.
3714
 
3715
      procedure Push (Node : PE_Ptr);
3716
      pragma Inline (Push);
3717
      --  Make entry in pattern matching stack with current cursor value
3718
 
3719
      procedure Push_Region;
3720
      pragma Inline (Push_Region);
3721
      --  This procedure makes a new region on the history stack. The
3722
      --  caller first establishes the special entry on the stack, but
3723
      --  does not push the stack pointer. Then this call stacks a
3724
      --  PC_Remove_Region node, on top of this entry, using the cursor
3725
      --  field of the PC_Remove_Region entry to save the outer level
3726
      --  stack base value, and resets the stack base to point to this
3727
      --  PC_Remove_Region node.
3728
 
3729
      ----------------
3730
      -- Pop_Region --
3731
      ----------------
3732
 
3733
      procedure Pop_Region is
3734
      begin
3735
         --  If nothing was pushed in the inner region, we can just get
3736
         --  rid of it entirely, leaving no traces that it was ever there
3737
 
3738
         if Stack_Ptr = Stack_Base then
3739
            Stack_Ptr := Stack_Base - 2;
3740
            Stack_Base := Stack (Stack_Ptr + 2).Cursor;
3741
 
3742
         --  If stuff was pushed in the inner region, then we have to
3743
         --  push a PC_R_Restore node so that we properly handle possible
3744
         --  rematches within the region.
3745
 
3746
         else
3747
            Stack_Ptr := Stack_Ptr + 1;
3748
            Stack (Stack_Ptr).Cursor := Stack_Base;
3749
            Stack (Stack_Ptr).Node   := CP_R_Restore'Access;
3750
            Stack_Base := Stack (Stack_Base).Cursor;
3751
         end if;
3752
      end Pop_Region;
3753
 
3754
      ----------
3755
      -- Push --
3756
      ----------
3757
 
3758
      procedure Push (Node : PE_Ptr) is
3759
      begin
3760
         Stack_Ptr := Stack_Ptr + 1;
3761
         Stack (Stack_Ptr).Cursor := Cursor;
3762
         Stack (Stack_Ptr).Node   := Node;
3763
      end Push;
3764
 
3765
      -----------------
3766
      -- Push_Region --
3767
      -----------------
3768
 
3769
      procedure Push_Region is
3770
      begin
3771
         Stack_Ptr := Stack_Ptr + 2;
3772
         Stack (Stack_Ptr).Cursor := Stack_Base;
3773
         Stack (Stack_Ptr).Node   := CP_R_Remove'Access;
3774
         Stack_Base := Stack_Ptr;
3775
      end Push_Region;
3776
 
3777
   --  Start of processing for XMatch
3778
 
3779
   begin
3780
      if Pat_P = null then
3781
         Uninitialized_Pattern;
3782
      end if;
3783
 
3784
      --  Check we have enough stack for this pattern. This check deals with
3785
      --  every possibility except a match of a recursive pattern, where we
3786
      --  make a check at each recursion level.
3787
 
3788
      if Pat_S >= Stack_Size - 1 then
3789
         raise Pattern_Stack_Overflow;
3790
      end if;
3791
 
3792
      --  In anchored mode, the bottom entry on the stack is an abort entry
3793
 
3794
      if Anchored_Mode then
3795
         Stack (Stack_Init).Node   := CP_Cancel'Access;
3796
         Stack (Stack_Init).Cursor := 0;
3797
 
3798
      --  In unanchored more, the bottom entry on the stack references
3799
      --  the special pattern element PE_Unanchored, whose Pthen field
3800
      --  points to the initial pattern element. The cursor value in this
3801
      --  entry is the number of anchor moves so far.
3802
 
3803
      else
3804
         Stack (Stack_Init).Node   := PE_Unanchored'Unchecked_Access;
3805
         Stack (Stack_Init).Cursor := 0;
3806
      end if;
3807
 
3808
      Stack_Ptr    := Stack_Init;
3809
      Stack_Base   := Stack_Ptr;
3810
      Cursor       := 0;
3811
      Node         := Pat_P;
3812
      goto Match;
3813
 
3814
      -----------------------------------------
3815
      -- Main Pattern Matching State Control --
3816
      -----------------------------------------
3817
 
3818
      --  This is a state machine which uses gotos to change state. The
3819
      --  initial state is Match, to initiate the matching of the first
3820
      --  element, so the goto Match above starts the match. In the
3821
      --  following descriptions, we indicate the global values that
3822
      --  are relevant for the state transition.
3823
 
3824
      --  Come here if entire match fails
3825
 
3826
      <<Match_Fail>>
3827
         Start := 0;
3828
         Stop  := 0;
3829
         return;
3830
 
3831
      --  Come here if entire match succeeds
3832
 
3833
      --    Cursor        current position in subject string
3834
 
3835
      <<Match_Succeed>>
3836
         Start := Stack (Stack_Init).Cursor + 1;
3837
         Stop  := Cursor;
3838
 
3839
         --  Scan history stack for deferred assignments or writes
3840
 
3841
         if Assign_OnM then
3842
            for S in Stack_Init .. Stack_Ptr loop
3843
               if Stack (S).Node = CP_Assign'Access then
3844
                  declare
3845
                     Inner_Base    : constant Stack_Range :=
3846
                                       Stack (S + 1).Cursor;
3847
                     Special_Entry : constant Stack_Range :=
3848
                                       Inner_Base - 1;
3849
                     Node_OnM      : constant PE_Ptr  :=
3850
                                       Stack (Special_Entry).Node;
3851
                     Start         : constant Natural :=
3852
                                       Stack (Special_Entry).Cursor + 1;
3853
                     Stop          : constant Natural := Stack (S).Cursor;
3854
 
3855
                  begin
3856
                     if Node_OnM.Pcode = PC_Assign_OnM then
3857
                        Set_String (Node_OnM.VP.all, Subject (Start .. Stop));
3858
 
3859
                     elsif Node_OnM.Pcode = PC_Write_OnM then
3860
                        Put_Line (Node_OnM.FP.all, Subject (Start .. Stop));
3861
 
3862
                     else
3863
                        Logic_Error;
3864
                     end if;
3865
                  end;
3866
               end if;
3867
            end loop;
3868
         end if;
3869
 
3870
         return;
3871
 
3872
      --  Come here if attempt to match current element fails
3873
 
3874
      --    Stack_Base    current stack base
3875
      --    Stack_Ptr     current stack pointer
3876
 
3877
      <<Fail>>
3878
         Cursor := Stack (Stack_Ptr).Cursor;
3879
         Node   := Stack (Stack_Ptr).Node;
3880
         Stack_Ptr := Stack_Ptr - 1;
3881
         goto Match;
3882
 
3883
      --  Come here if attempt to match current element succeeds
3884
 
3885
      --    Cursor        current position in subject string
3886
      --    Node          pointer to node successfully matched
3887
      --    Stack_Base    current stack base
3888
      --    Stack_Ptr     current stack pointer
3889
 
3890
      <<Succeed>>
3891
         Node := Node.Pthen;
3892
 
3893
      --  Come here to match the next pattern element
3894
 
3895
      --    Cursor        current position in subject string
3896
      --    Node          pointer to node to be matched
3897
      --    Stack_Base    current stack base
3898
      --    Stack_Ptr     current stack pointer
3899
 
3900
      <<Match>>
3901
 
3902
      --------------------------------------------------
3903
      -- Main Pattern Match Element Matching Routines --
3904
      --------------------------------------------------
3905
 
3906
      --  Here is the case statement that processes the current node. The
3907
      --  processing for each element does one of five things:
3908
 
3909
      --    goto Succeed        to move to the successor
3910
      --    goto Match_Succeed  if the entire match succeeds
3911
      --    goto Match_Fail     if the entire match fails
3912
      --    goto Fail           to signal failure of current match
3913
 
3914
      --  Processing is NOT allowed to fall through
3915
 
3916
      case Node.Pcode is
3917
 
3918
         --  Cancel
3919
 
3920
         when PC_Cancel =>
3921
            goto Match_Fail;
3922
 
3923
         --  Alternation
3924
 
3925
         when PC_Alt =>
3926
            Push (Node.Alt);
3927
            Node := Node.Pthen;
3928
            goto Match;
3929
 
3930
         --  Any (one character case)
3931
 
3932
         when PC_Any_CH =>
3933
            if Cursor < Length
3934
              and then Subject (Cursor + 1) = Node.Char
3935
            then
3936
               Cursor := Cursor + 1;
3937
               goto Succeed;
3938
            else
3939
               goto Fail;
3940
            end if;
3941
 
3942
         --  Any (character set case)
3943
 
3944
         when PC_Any_CS =>
3945
            if Cursor < Length
3946
              and then Is_In (Subject (Cursor + 1), Node.CS)
3947
            then
3948
               Cursor := Cursor + 1;
3949
               goto Succeed;
3950
            else
3951
               goto Fail;
3952
            end if;
3953
 
3954
         --  Any (string function case)
3955
 
3956
         when PC_Any_VF => declare
3957
            U : constant VString := Node.VF.all;
3958
            S : String_Access;
3959
            L : Natural;
3960
 
3961
         begin
3962
            Get_String (U, S, L);
3963
 
3964
            if Cursor < Length
3965
              and then Is_In (Subject (Cursor + 1), S (1 .. L))
3966
            then
3967
               Cursor := Cursor + 1;
3968
               goto Succeed;
3969
            else
3970
               goto Fail;
3971
            end if;
3972
         end;
3973
 
3974
         --  Any (string pointer case)
3975
 
3976
         when PC_Any_VP => declare
3977
            U : constant VString := Node.VP.all;
3978
            S : String_Access;
3979
            L : Natural;
3980
 
3981
         begin
3982
            Get_String (U, S, L);
3983
 
3984
            if Cursor < Length
3985
              and then Is_In (Subject (Cursor + 1), S (1 .. L))
3986
            then
3987
               Cursor := Cursor + 1;
3988
               goto Succeed;
3989
            else
3990
               goto Fail;
3991
            end if;
3992
         end;
3993
 
3994
         --  Arb (initial match)
3995
 
3996
         when PC_Arb_X =>
3997
            Push (Node.Alt);
3998
            Node := Node.Pthen;
3999
            goto Match;
4000
 
4001
         --  Arb (extension)
4002
 
4003
         when PC_Arb_Y  =>
4004
            if Cursor < Length then
4005
               Cursor := Cursor + 1;
4006
               Push (Node);
4007
               goto Succeed;
4008
            else
4009
               goto Fail;
4010
            end if;
4011
 
4012
         --  Arbno_S (simple Arbno initialize). This is the node that
4013
         --  initiates the match of a simple Arbno structure.
4014
 
4015
         when PC_Arbno_S =>
4016
            Push (Node.Alt);
4017
            Node := Node.Pthen;
4018
            goto Match;
4019
 
4020
         --  Arbno_X (Arbno initialize). This is the node that initiates
4021
         --  the match of a complex Arbno structure.
4022
 
4023
         when PC_Arbno_X =>
4024
            Push (Node.Alt);
4025
            Node := Node.Pthen;
4026
            goto Match;
4027
 
4028
         --  Arbno_Y (Arbno rematch). This is the node that is executed
4029
         --  following successful matching of one instance of a complex
4030
         --  Arbno pattern.
4031
 
4032
         when PC_Arbno_Y => declare
4033
            Null_Match : constant Boolean :=
4034
                           Cursor = Stack (Stack_Base - 1).Cursor;
4035
 
4036
         begin
4037
            Pop_Region;
4038
 
4039
            --  If arbno extension matched null, then immediately fail
4040
 
4041
            if Null_Match then
4042
               goto Fail;
4043
            end if;
4044
 
4045
            --  Here we must do a stack check to make sure enough stack
4046
            --  is left. This check will happen once for each instance of
4047
            --  the Arbno pattern that is matched. The Nat field of a
4048
            --  PC_Arbno pattern contains the maximum stack entries needed
4049
            --  for the Arbno with one instance and the successor pattern
4050
 
4051
            if Stack_Ptr + Node.Nat >= Stack'Last then
4052
               raise Pattern_Stack_Overflow;
4053
            end if;
4054
 
4055
            goto Succeed;
4056
         end;
4057
 
4058
         --  Assign. If this node is executed, it means the assign-on-match
4059
         --  or write-on-match operation will not happen after all, so we
4060
         --  is propagate the failure, removing the PC_Assign node.
4061
 
4062
         when PC_Assign =>
4063
            goto Fail;
4064
 
4065
         --  Assign immediate. This node performs the actual assignment
4066
 
4067
         when PC_Assign_Imm =>
4068
            Set_String
4069
              (Node.VP.all,
4070
               Subject (Stack (Stack_Base - 1).Cursor + 1 .. Cursor));
4071
            Pop_Region;
4072
            goto Succeed;
4073
 
4074
         --  Assign on match. This node sets up for the eventual assignment
4075
 
4076
         when PC_Assign_OnM =>
4077
            Stack (Stack_Base - 1).Node := Node;
4078
            Push (CP_Assign'Access);
4079
            Pop_Region;
4080
            Assign_OnM := True;
4081
            goto Succeed;
4082
 
4083
         --  Bal
4084
 
4085
         when PC_Bal =>
4086
            if Cursor >= Length or else Subject (Cursor + 1) = ')' then
4087
               goto Fail;
4088
 
4089
            elsif Subject (Cursor + 1) = '(' then
4090
               declare
4091
                  Paren_Count : Natural := 1;
4092
 
4093
               begin
4094
                  loop
4095
                     Cursor := Cursor + 1;
4096
 
4097
                     if Cursor >= Length then
4098
                        goto Fail;
4099
 
4100
                     elsif Subject (Cursor + 1) = '(' then
4101
                        Paren_Count := Paren_Count + 1;
4102
 
4103
                     elsif Subject (Cursor + 1) = ')' then
4104
                        Paren_Count := Paren_Count - 1;
4105
                        exit when Paren_Count = 0;
4106
                     end if;
4107
                  end loop;
4108
               end;
4109
            end if;
4110
 
4111
            Cursor := Cursor + 1;
4112
            Push (Node);
4113
            goto Succeed;
4114
 
4115
         --  Break (one character case)
4116
 
4117
         when PC_Break_CH =>
4118
            while Cursor < Length loop
4119
               if Subject (Cursor + 1) = Node.Char then
4120
                  goto Succeed;
4121
               else
4122
                  Cursor := Cursor + 1;
4123
               end if;
4124
            end loop;
4125
 
4126
            goto Fail;
4127
 
4128
         --  Break (character set case)
4129
 
4130
         when PC_Break_CS =>
4131
            while Cursor < Length loop
4132
               if Is_In (Subject (Cursor + 1), Node.CS) then
4133
                  goto Succeed;
4134
               else
4135
                  Cursor := Cursor + 1;
4136
               end if;
4137
            end loop;
4138
 
4139
            goto Fail;
4140
 
4141
         --  Break (string function case)
4142
 
4143
         when PC_Break_VF => declare
4144
            U : constant VString := Node.VF.all;
4145
            S : String_Access;
4146
            L : Natural;
4147
 
4148
         begin
4149
            Get_String (U, S, L);
4150
 
4151
            while Cursor < Length loop
4152
               if Is_In (Subject (Cursor + 1), S (1 .. L)) then
4153
                  goto Succeed;
4154
               else
4155
                  Cursor := Cursor + 1;
4156
               end if;
4157
            end loop;
4158
 
4159
            goto Fail;
4160
         end;
4161
 
4162
         --  Break (string pointer case)
4163
 
4164
         when PC_Break_VP => declare
4165
            U : constant VString := Node.VP.all;
4166
            S : String_Access;
4167
            L : Natural;
4168
 
4169
         begin
4170
            Get_String (U, S, L);
4171
 
4172
            while Cursor < Length loop
4173
               if Is_In (Subject (Cursor + 1), S (1 .. L)) then
4174
                  goto Succeed;
4175
               else
4176
                  Cursor := Cursor + 1;
4177
               end if;
4178
            end loop;
4179
 
4180
            goto Fail;
4181
         end;
4182
 
4183
         --  BreakX (one character case)
4184
 
4185
         when PC_BreakX_CH =>
4186
            while Cursor < Length loop
4187
               if Subject (Cursor + 1) = Node.Char then
4188
                  goto Succeed;
4189
               else
4190
                  Cursor := Cursor + 1;
4191
               end if;
4192
            end loop;
4193
 
4194
            goto Fail;
4195
 
4196
         --  BreakX (character set case)
4197
 
4198
         when PC_BreakX_CS =>
4199
            while Cursor < Length loop
4200
               if Is_In (Subject (Cursor + 1), Node.CS) then
4201
                  goto Succeed;
4202
               else
4203
                  Cursor := Cursor + 1;
4204
               end if;
4205
            end loop;
4206
 
4207
            goto Fail;
4208
 
4209
         --  BreakX (string function case)
4210
 
4211
         when PC_BreakX_VF => declare
4212
            U : constant VString := Node.VF.all;
4213
            S : String_Access;
4214
            L : Natural;
4215
 
4216
         begin
4217
            Get_String (U, S, L);
4218
 
4219
            while Cursor < Length loop
4220
               if Is_In (Subject (Cursor + 1), S (1 .. L)) then
4221
                  goto Succeed;
4222
               else
4223
                  Cursor := Cursor + 1;
4224
               end if;
4225
            end loop;
4226
 
4227
            goto Fail;
4228
         end;
4229
 
4230
         --  BreakX (string pointer case)
4231
 
4232
         when PC_BreakX_VP => declare
4233
            U : constant VString := Node.VP.all;
4234
            S : String_Access;
4235
            L : Natural;
4236
 
4237
         begin
4238
            Get_String (U, S, L);
4239
 
4240
            while Cursor < Length loop
4241
               if Is_In (Subject (Cursor + 1), S (1 .. L)) then
4242
                  goto Succeed;
4243
               else
4244
                  Cursor := Cursor + 1;
4245
               end if;
4246
            end loop;
4247
 
4248
            goto Fail;
4249
         end;
4250
 
4251
         --  BreakX_X (BreakX extension). See section on "Compound Pattern
4252
         --  Structures". This node is the alternative that is stacked to
4253
         --  skip past the break character and extend the break.
4254
 
4255
         when PC_BreakX_X =>
4256
            Cursor := Cursor + 1;
4257
            goto Succeed;
4258
 
4259
         --  Character (one character string)
4260
 
4261
         when PC_Char =>
4262
            if Cursor < Length
4263
              and then Subject (Cursor + 1) = Node.Char
4264
            then
4265
               Cursor := Cursor + 1;
4266
               goto Succeed;
4267
            else
4268
               goto Fail;
4269
            end if;
4270
 
4271
         --  End of Pattern
4272
 
4273
         when PC_EOP =>
4274
            if Stack_Base = Stack_Init then
4275
               goto Match_Succeed;
4276
 
4277
            --  End of recursive inner match. See separate section on
4278
            --  handing of recursive pattern matches for details.
4279
 
4280
            else
4281
               Node := Stack (Stack_Base - 1).Node;
4282
               Pop_Region;
4283
               goto Match;
4284
            end if;
4285
 
4286
         --  Fail
4287
 
4288
         when PC_Fail =>
4289
            goto Fail;
4290
 
4291
         --  Fence (built in pattern)
4292
 
4293
         when PC_Fence =>
4294
            Push (CP_Cancel'Access);
4295
            goto Succeed;
4296
 
4297
         --  Fence function node X. This is the node that gets control
4298
         --  after a successful match of the fenced pattern.
4299
 
4300
         when PC_Fence_X =>
4301
            Stack_Ptr := Stack_Ptr + 1;
4302
            Stack (Stack_Ptr).Cursor := Stack_Base;
4303
            Stack (Stack_Ptr).Node   := CP_Fence_Y'Access;
4304
            Stack_Base := Stack (Stack_Base).Cursor;
4305
            goto Succeed;
4306
 
4307
         --  Fence function node Y. This is the node that gets control on
4308
         --  a failure that occurs after the fenced pattern has matched.
4309
 
4310
         --  Note: the Cursor at this stage is actually the inner stack
4311
         --  base value. We don't reset this, but we do use it to strip
4312
         --  off all the entries made by the fenced pattern.
4313
 
4314
         when PC_Fence_Y =>
4315
            Stack_Ptr := Cursor - 2;
4316
            goto Fail;
4317
 
4318
         --  Len (integer case)
4319
 
4320
         when PC_Len_Nat =>
4321
            if Cursor + Node.Nat > Length then
4322
               goto Fail;
4323
            else
4324
               Cursor := Cursor + Node.Nat;
4325
               goto Succeed;
4326
            end if;
4327
 
4328
         --  Len (Integer function case)
4329
 
4330
         when PC_Len_NF => declare
4331
            N : constant Natural := Node.NF.all;
4332
         begin
4333
            if Cursor + N > Length then
4334
               goto Fail;
4335
            else
4336
               Cursor := Cursor + N;
4337
               goto Succeed;
4338
            end if;
4339
         end;
4340
 
4341
         --  Len (integer pointer case)
4342
 
4343
         when PC_Len_NP =>
4344
            if Cursor + Node.NP.all > Length then
4345
               goto Fail;
4346
            else
4347
               Cursor := Cursor + Node.NP.all;
4348
               goto Succeed;
4349
            end if;
4350
 
4351
         --  NotAny (one character case)
4352
 
4353
         when PC_NotAny_CH =>
4354
            if Cursor < Length
4355
              and then Subject (Cursor + 1) /= Node.Char
4356
            then
4357
               Cursor := Cursor + 1;
4358
               goto Succeed;
4359
            else
4360
               goto Fail;
4361
            end if;
4362
 
4363
         --  NotAny (character set case)
4364
 
4365
         when PC_NotAny_CS =>
4366
            if Cursor < Length
4367
              and then not Is_In (Subject (Cursor + 1), Node.CS)
4368
            then
4369
               Cursor := Cursor + 1;
4370
               goto Succeed;
4371
            else
4372
               goto Fail;
4373
            end if;
4374
 
4375
         --  NotAny (string function case)
4376
 
4377
         when PC_NotAny_VF => declare
4378
            U : constant VString := Node.VF.all;
4379
            S : String_Access;
4380
            L : Natural;
4381
 
4382
         begin
4383
            Get_String (U, S, L);
4384
 
4385
            if Cursor < Length
4386
              and then
4387
                not Is_In (Subject (Cursor + 1), S (1 .. L))
4388
            then
4389
               Cursor := Cursor + 1;
4390
               goto Succeed;
4391
            else
4392
               goto Fail;
4393
            end if;
4394
         end;
4395
 
4396
         --  NotAny (string pointer case)
4397
 
4398
         when PC_NotAny_VP => declare
4399
            U : constant VString := Node.VP.all;
4400
            S : String_Access;
4401
            L : Natural;
4402
 
4403
         begin
4404
            Get_String (U, S, L);
4405
 
4406
            if Cursor < Length
4407
              and then
4408
                not Is_In (Subject (Cursor + 1), S (1 .. L))
4409
            then
4410
               Cursor := Cursor + 1;
4411
               goto Succeed;
4412
            else
4413
               goto Fail;
4414
            end if;
4415
         end;
4416
 
4417
         --  NSpan (one character case)
4418
 
4419
         when PC_NSpan_CH =>
4420
            while Cursor < Length
4421
              and then Subject (Cursor + 1) = Node.Char
4422
            loop
4423
               Cursor := Cursor + 1;
4424
            end loop;
4425
 
4426
            goto Succeed;
4427
 
4428
         --  NSpan (character set case)
4429
 
4430
         when PC_NSpan_CS =>
4431
            while Cursor < Length
4432
              and then Is_In (Subject (Cursor + 1), Node.CS)
4433
            loop
4434
               Cursor := Cursor + 1;
4435
            end loop;
4436
 
4437
            goto Succeed;
4438
 
4439
         --  NSpan (string function case)
4440
 
4441
         when PC_NSpan_VF => declare
4442
            U : constant VString := Node.VF.all;
4443
            S : String_Access;
4444
            L : Natural;
4445
 
4446
         begin
4447
            Get_String (U, S, L);
4448
 
4449
            while Cursor < Length
4450
              and then Is_In (Subject (Cursor + 1), S (1 .. L))
4451
            loop
4452
               Cursor := Cursor + 1;
4453
            end loop;
4454
 
4455
            goto Succeed;
4456
         end;
4457
 
4458
         --  NSpan (string pointer case)
4459
 
4460
         when PC_NSpan_VP => declare
4461
            U : constant VString := Node.VP.all;
4462
            S : String_Access;
4463
            L : Natural;
4464
 
4465
         begin
4466
            Get_String (U, S, L);
4467
 
4468
            while Cursor < Length
4469
              and then Is_In (Subject (Cursor + 1), S (1 .. L))
4470
            loop
4471
               Cursor := Cursor + 1;
4472
            end loop;
4473
 
4474
            goto Succeed;
4475
         end;
4476
 
4477
         --  Null string
4478
 
4479
         when PC_Null =>
4480
            goto Succeed;
4481
 
4482
         --  Pos (integer case)
4483
 
4484
         when PC_Pos_Nat =>
4485
            if Cursor = Node.Nat then
4486
               goto Succeed;
4487
            else
4488
               goto Fail;
4489
            end if;
4490
 
4491
         --  Pos (Integer function case)
4492
 
4493
         when PC_Pos_NF => declare
4494
            N : constant Natural := Node.NF.all;
4495
         begin
4496
            if Cursor = N then
4497
               goto Succeed;
4498
            else
4499
               goto Fail;
4500
            end if;
4501
         end;
4502
 
4503
         --  Pos (integer pointer case)
4504
 
4505
         when PC_Pos_NP =>
4506
            if Cursor = Node.NP.all then
4507
               goto Succeed;
4508
            else
4509
               goto Fail;
4510
            end if;
4511
 
4512
         --  Predicate function
4513
 
4514
         when PC_Pred_Func =>
4515
            if Node.BF.all then
4516
               goto Succeed;
4517
            else
4518
               goto Fail;
4519
            end if;
4520
 
4521
         --  Region Enter. Initiate new pattern history stack region
4522
 
4523
         when PC_R_Enter =>
4524
            Stack (Stack_Ptr + 1).Cursor := Cursor;
4525
            Push_Region;
4526
            goto Succeed;
4527
 
4528
         --  Region Remove node. This is the node stacked by an R_Enter.
4529
         --  It removes the special format stack entry right underneath, and
4530
         --  then restores the outer level stack base and signals failure.
4531
 
4532
         --  Note: the cursor value at this stage is actually the (negative)
4533
         --  stack base value for the outer level.
4534
 
4535
         when PC_R_Remove =>
4536
            Stack_Base := Cursor;
4537
            Stack_Ptr := Stack_Ptr - 1;
4538
            goto Fail;
4539
 
4540
         --  Region restore node. This is the node stacked at the end of an
4541
         --  inner level match. Its function is to restore the inner level
4542
         --  region, so that alternatives in this region can be sought.
4543
 
4544
         --  Note: the Cursor at this stage is actually the negative of the
4545
         --  inner stack base value, which we use to restore the inner region.
4546
 
4547
         when PC_R_Restore =>
4548
            Stack_Base := Cursor;
4549
            goto Fail;
4550
 
4551
         --  Rest
4552
 
4553
         when PC_Rest =>
4554
            Cursor := Length;
4555
            goto Succeed;
4556
 
4557
         --  Initiate recursive match (pattern pointer case)
4558
 
4559
         when PC_Rpat =>
4560
            Stack (Stack_Ptr + 1).Node := Node.Pthen;
4561
            Push_Region;
4562
 
4563
            if Stack_Ptr + Node.PP.all.Stk >= Stack_Size then
4564
               raise Pattern_Stack_Overflow;
4565
            else
4566
               Node := Node.PP.all.P;
4567
               goto Match;
4568
            end if;
4569
 
4570
         --  RPos (integer case)
4571
 
4572
         when PC_RPos_Nat =>
4573
            if Cursor = (Length - Node.Nat) then
4574
               goto Succeed;
4575
            else
4576
               goto Fail;
4577
            end if;
4578
 
4579
         --  RPos (integer function case)
4580
 
4581
         when PC_RPos_NF => declare
4582
            N : constant Natural := Node.NF.all;
4583
         begin
4584
            if Length - Cursor = N then
4585
               goto Succeed;
4586
            else
4587
               goto Fail;
4588
            end if;
4589
         end;
4590
 
4591
         --  RPos (integer pointer case)
4592
 
4593
         when PC_RPos_NP =>
4594
            if Cursor = (Length - Node.NP.all) then
4595
               goto Succeed;
4596
            else
4597
               goto Fail;
4598
            end if;
4599
 
4600
         --  RTab (integer case)
4601
 
4602
         when PC_RTab_Nat =>
4603
            if Cursor <= (Length - Node.Nat) then
4604
               Cursor := Length - Node.Nat;
4605
               goto Succeed;
4606
            else
4607
               goto Fail;
4608
            end if;
4609
 
4610
         --  RTab (integer function case)
4611
 
4612
         when PC_RTab_NF => declare
4613
            N : constant Natural := Node.NF.all;
4614
         begin
4615
            if Length - Cursor >= N then
4616
               Cursor := Length - N;
4617
               goto Succeed;
4618
            else
4619
               goto Fail;
4620
            end if;
4621
         end;
4622
 
4623
         --  RTab (integer pointer case)
4624
 
4625
         when PC_RTab_NP =>
4626
            if Cursor <= (Length - Node.NP.all) then
4627
               Cursor := Length - Node.NP.all;
4628
               goto Succeed;
4629
            else
4630
               goto Fail;
4631
            end if;
4632
 
4633
         --  Cursor assignment
4634
 
4635
         when PC_Setcur =>
4636
            Node.Var.all := Cursor;
4637
            goto Succeed;
4638
 
4639
         --  Span (one character case)
4640
 
4641
         when PC_Span_CH => declare
4642
            P : Natural;
4643
 
4644
         begin
4645
            P := Cursor;
4646
            while P < Length
4647
              and then Subject (P + 1) = Node.Char
4648
            loop
4649
               P := P + 1;
4650
            end loop;
4651
 
4652
            if P /= Cursor then
4653
               Cursor := P;
4654
               goto Succeed;
4655
            else
4656
               goto Fail;
4657
            end if;
4658
         end;
4659
 
4660
         --  Span (character set case)
4661
 
4662
         when PC_Span_CS => declare
4663
            P : Natural;
4664
 
4665
         begin
4666
            P := Cursor;
4667
            while P < Length
4668
              and then Is_In (Subject (P + 1), Node.CS)
4669
            loop
4670
               P := P + 1;
4671
            end loop;
4672
 
4673
            if P /= Cursor then
4674
               Cursor := P;
4675
               goto Succeed;
4676
            else
4677
               goto Fail;
4678
            end if;
4679
         end;
4680
 
4681
         --  Span (string function case)
4682
 
4683
         when PC_Span_VF => declare
4684
            U : constant VString := Node.VF.all;
4685
            S : String_Access;
4686
            L : Natural;
4687
            P : Natural;
4688
 
4689
         begin
4690
            Get_String (U, S, L);
4691
 
4692
            P := Cursor;
4693
            while P < Length
4694
              and then Is_In (Subject (P + 1), S (1 .. L))
4695
            loop
4696
               P := P + 1;
4697
            end loop;
4698
 
4699
            if P /= Cursor then
4700
               Cursor := P;
4701
               goto Succeed;
4702
            else
4703
               goto Fail;
4704
            end if;
4705
         end;
4706
 
4707
         --  Span (string pointer case)
4708
 
4709
         when PC_Span_VP => declare
4710
            U : constant VString := Node.VP.all;
4711
            S : String_Access;
4712
            L : Natural;
4713
            P : Natural;
4714
 
4715
         begin
4716
            Get_String (U, S, L);
4717
 
4718
            P := Cursor;
4719
            while P < Length
4720
              and then Is_In (Subject (P + 1), S (1 .. L))
4721
            loop
4722
               P := P + 1;
4723
            end loop;
4724
 
4725
            if P /= Cursor then
4726
               Cursor := P;
4727
               goto Succeed;
4728
            else
4729
               goto Fail;
4730
            end if;
4731
         end;
4732
 
4733
         --  String (two character case)
4734
 
4735
         when PC_String_2 =>
4736
            if (Length - Cursor) >= 2
4737
              and then Subject (Cursor + 1 .. Cursor + 2) = Node.Str2
4738
            then
4739
               Cursor := Cursor + 2;
4740
               goto Succeed;
4741
            else
4742
               goto Fail;
4743
            end if;
4744
 
4745
         --  String (three character case)
4746
 
4747
         when PC_String_3 =>
4748
            if (Length - Cursor) >= 3
4749
              and then Subject (Cursor + 1 .. Cursor + 3) = Node.Str3
4750
            then
4751
               Cursor := Cursor + 3;
4752
               goto Succeed;
4753
            else
4754
               goto Fail;
4755
            end if;
4756
 
4757
         --  String (four character case)
4758
 
4759
         when PC_String_4 =>
4760
            if (Length - Cursor) >= 4
4761
              and then Subject (Cursor + 1 .. Cursor + 4) = Node.Str4
4762
            then
4763
               Cursor := Cursor + 4;
4764
               goto Succeed;
4765
            else
4766
               goto Fail;
4767
            end if;
4768
 
4769
         --  String (five character case)
4770
 
4771
         when PC_String_5 =>
4772
            if (Length - Cursor) >= 5
4773
              and then Subject (Cursor + 1 .. Cursor + 5) = Node.Str5
4774
            then
4775
               Cursor := Cursor + 5;
4776
               goto Succeed;
4777
            else
4778
               goto Fail;
4779
            end if;
4780
 
4781
         --  String (six character case)
4782
 
4783
         when PC_String_6 =>
4784
            if (Length - Cursor) >= 6
4785
              and then Subject (Cursor + 1 .. Cursor + 6) = Node.Str6
4786
            then
4787
               Cursor := Cursor + 6;
4788
               goto Succeed;
4789
            else
4790
               goto Fail;
4791
            end if;
4792
 
4793
         --  String (case of more than six characters)
4794
 
4795
         when PC_String => declare
4796
            Len : constant Natural := Node.Str'Length;
4797
         begin
4798
            if (Length - Cursor) >= Len
4799
              and then Node.Str.all = Subject (Cursor + 1 .. Cursor + Len)
4800
            then
4801
               Cursor := Cursor + Len;
4802
               goto Succeed;
4803
            else
4804
               goto Fail;
4805
            end if;
4806
         end;
4807
 
4808
         --  String (function case)
4809
 
4810
         when PC_String_VF => declare
4811
            U : constant VString := Node.VF.all;
4812
            S : String_Access;
4813
            L : Natural;
4814
 
4815
         begin
4816
            Get_String (U, S, L);
4817
 
4818
            if (Length - Cursor) >= L
4819
              and then S (1 .. L) = Subject (Cursor + 1 .. Cursor + L)
4820
            then
4821
               Cursor := Cursor + L;
4822
               goto Succeed;
4823
            else
4824
               goto Fail;
4825
            end if;
4826
         end;
4827
 
4828
         --  String (pointer case)
4829
 
4830
         when PC_String_VP => declare
4831
            U : constant VString := Node.VP.all;
4832
            S : String_Access;
4833
            L : Natural;
4834
 
4835
         begin
4836
            Get_String (U, S, L);
4837
 
4838
            if (Length - Cursor) >= L
4839
              and then S (1 .. L) = Subject (Cursor + 1 .. Cursor + L)
4840
            then
4841
               Cursor := Cursor + L;
4842
               goto Succeed;
4843
            else
4844
               goto Fail;
4845
            end if;
4846
         end;
4847
 
4848
         --  Succeed
4849
 
4850
         when PC_Succeed =>
4851
            Push (Node);
4852
            goto Succeed;
4853
 
4854
         --  Tab (integer case)
4855
 
4856
         when PC_Tab_Nat =>
4857
            if Cursor <= Node.Nat then
4858
               Cursor := Node.Nat;
4859
               goto Succeed;
4860
            else
4861
               goto Fail;
4862
            end if;
4863
 
4864
         --  Tab (integer function case)
4865
 
4866
         when PC_Tab_NF => declare
4867
            N : constant Natural := Node.NF.all;
4868
         begin
4869
            if Cursor <= N then
4870
               Cursor := N;
4871
               goto Succeed;
4872
            else
4873
               goto Fail;
4874
            end if;
4875
         end;
4876
 
4877
         --  Tab (integer pointer case)
4878
 
4879
         when PC_Tab_NP =>
4880
            if Cursor <= Node.NP.all then
4881
               Cursor := Node.NP.all;
4882
               goto Succeed;
4883
            else
4884
               goto Fail;
4885
            end if;
4886
 
4887
         --  Unanchored movement
4888
 
4889
         when PC_Unanchored =>
4890
 
4891
            --  All done if we tried every position
4892
 
4893
            if Cursor > Length then
4894
               goto Match_Fail;
4895
 
4896
            --  Otherwise extend the anchor point, and restack ourself
4897
 
4898
            else
4899
               Cursor := Cursor + 1;
4900
               Push (Node);
4901
               goto Succeed;
4902
            end if;
4903
 
4904
         --  Write immediate. This node performs the actual write
4905
 
4906
         when PC_Write_Imm =>
4907
            Put_Line
4908
              (Node.FP.all,
4909
               Subject (Stack (Stack_Base - 1).Cursor + 1 .. Cursor));
4910
            Pop_Region;
4911
            goto Succeed;
4912
 
4913
         --  Write on match. This node sets up for the eventual write
4914
 
4915
         when PC_Write_OnM =>
4916
            Stack (Stack_Base - 1).Node := Node;
4917
            Push (CP_Assign'Access);
4918
            Pop_Region;
4919
            Assign_OnM := True;
4920
            goto Succeed;
4921
 
4922
      end case;
4923
 
4924
      --  We are NOT allowed to fall though this case statement, since every
4925
      --  match routine must end by executing a goto to the appropriate point
4926
      --  in the finite state machine model.
4927
 
4928
      pragma Warnings (Off);
4929
      Logic_Error;
4930
      pragma Warnings (On);
4931
   end XMatch;
4932
 
4933
   -------------
4934
   -- XMatchD --
4935
   -------------
4936
 
4937
   --  Maintenance note: There is a LOT of code duplication between XMatch
4938
   --  and XMatchD. This is quite intentional, the point is to avoid any
4939
   --  unnecessary debugging overhead in the XMatch case, but this does mean
4940
   --  that any changes to XMatchD must be mirrored in XMatch. In case of
4941
   --  any major changes, the proper approach is to delete XMatch, make the
4942
   --  changes to XMatchD, and then make a copy of XMatchD, removing all
4943
   --  calls to Dout, and all Put and Put_Line operations. This copy becomes
4944
   --  the new XMatch.
4945
 
4946
   procedure XMatchD
4947
     (Subject : String;
4948
      Pat_P   : PE_Ptr;
4949
      Pat_S   : Natural;
4950
      Start   : out Natural;
4951
      Stop    : out Natural)
4952
   is
4953
      Node : PE_Ptr;
4954
      --  Pointer to current pattern node. Initialized from Pat_P, and then
4955
      --  updated as the match proceeds through its constituent elements.
4956
 
4957
      Length : constant Natural := Subject'Length;
4958
      --  Length of string (= Subject'Last, since Subject'First is always 1)
4959
 
4960
      Cursor : Integer := 0;
4961
      --  If the value is non-negative, then this value is the index showing
4962
      --  the current position of the match in the subject string. The next
4963
      --  character to be matched is at Subject (Cursor + 1). Note that since
4964
      --  our view of the subject string in XMatch always has a lower bound
4965
      --  of one, regardless of original bounds, that this definition exactly
4966
      --  corresponds to the cursor value as referenced by functions like Pos.
4967
      --
4968
      --  If the value is negative, then this is a saved stack pointer,
4969
      --  typically a base pointer of an inner or outer region. Cursor
4970
      --  temporarily holds such a value when it is popped from the stack
4971
      --  by Fail. In all cases, Cursor is reset to a proper non-negative
4972
      --  cursor value before the match proceeds (e.g. by propagating the
4973
      --  failure and popping a "real" cursor value from the stack.
4974
 
4975
      PE_Unanchored : aliased PE := (PC_Unanchored, 0, Pat_P);
4976
      --  Dummy pattern element used in the unanchored case
4977
 
4978
      Region_Level : Natural := 0;
4979
      --  Keeps track of recursive region level. This is used only for
4980
      --  debugging, it is the number of saved history stack base values.
4981
 
4982
      Stack : Stack_Type;
4983
      --  The pattern matching failure stack for this call to Match
4984
 
4985
      Stack_Ptr : Stack_Range;
4986
      --  Current stack pointer. This points to the top element of the stack
4987
      --  that is currently in use. At the outer level this is the special
4988
      --  entry placed on the stack according to the anchor mode.
4989
 
4990
      Stack_Init : constant Stack_Range := Stack'First + 1;
4991
      --  This is the initial value of the Stack_Ptr and Stack_Base. The
4992
      --  initial (Stack'First) element of the stack is not used so that
4993
      --  when we pop the last element off, Stack_Ptr is still in range.
4994
 
4995
      Stack_Base : Stack_Range;
4996
      --  This value is the stack base value, i.e. the stack pointer for the
4997
      --  first history stack entry in the current stack region. See separate
4998
      --  section on handling of recursive pattern matches.
4999
 
5000
      Assign_OnM : Boolean := False;
5001
      --  Set True if assign-on-match or write-on-match operations may be
5002
      --  present in the history stack, which must then be scanned on a
5003
      --  successful match.
5004
 
5005
      procedure Dout (Str : String);
5006
      --  Output string to standard error with bars indicating region level
5007
 
5008
      procedure Dout (Str : String; A : Character);
5009
      --  Calls Dout with the string S ('A')
5010
 
5011
      procedure Dout (Str : String; A : Character_Set);
5012
      --  Calls Dout with the string S ("A")
5013
 
5014
      procedure Dout (Str : String; A : Natural);
5015
      --  Calls Dout with the string S (A)
5016
 
5017
      procedure Dout (Str : String; A : String);
5018
      --  Calls Dout with the string S ("A")
5019
 
5020
      function Img (P : PE_Ptr) return String;
5021
      --  Returns a string of the form #nnn where nnn is P.Index
5022
 
5023
      procedure Pop_Region;
5024
      pragma Inline (Pop_Region);
5025
      --  Used at the end of processing of an inner region. If the inner
5026
      --  region left no stack entries, then all trace of it is removed.
5027
      --  Otherwise a PC_Restore_Region entry is pushed to ensure proper
5028
      --  handling of alternatives in the inner region.
5029
 
5030
      procedure Push (Node : PE_Ptr);
5031
      pragma Inline (Push);
5032
      --  Make entry in pattern matching stack with current cursor value
5033
 
5034
      procedure Push_Region;
5035
      pragma Inline (Push_Region);
5036
      --  This procedure makes a new region on the history stack. The
5037
      --  caller first establishes the special entry on the stack, but
5038
      --  does not push the stack pointer. Then this call stacks a
5039
      --  PC_Remove_Region node, on top of this entry, using the cursor
5040
      --  field of the PC_Remove_Region entry to save the outer level
5041
      --  stack base value, and resets the stack base to point to this
5042
      --  PC_Remove_Region node.
5043
 
5044
      ----------
5045
      -- Dout --
5046
      ----------
5047
 
5048
      procedure Dout (Str : String) is
5049
      begin
5050
         for J in 1 .. Region_Level loop
5051
            Put ("| ");
5052
         end loop;
5053
 
5054
         Put_Line (Str);
5055
      end Dout;
5056
 
5057
      procedure Dout (Str : String; A : Character) is
5058
      begin
5059
         Dout (Str & " ('" & A & "')");
5060
      end Dout;
5061
 
5062
      procedure Dout (Str : String; A : Character_Set) is
5063
      begin
5064
         Dout (Str & " (" & Image (To_Sequence (A)) & ')');
5065
      end Dout;
5066
 
5067
      procedure Dout (Str : String; A : Natural) is
5068
      begin
5069
         Dout (Str & " (" & A & ')');
5070
      end Dout;
5071
 
5072
      procedure Dout (Str : String; A : String) is
5073
      begin
5074
         Dout (Str & " (" & Image (A) & ')');
5075
      end Dout;
5076
 
5077
      ---------
5078
      -- Img --
5079
      ---------
5080
 
5081
      function Img (P : PE_Ptr) return String is
5082
      begin
5083
         return "#" & Integer (P.Index) & " ";
5084
      end Img;
5085
 
5086
      ----------------
5087
      -- Pop_Region --
5088
      ----------------
5089
 
5090
      procedure Pop_Region is
5091
      begin
5092
         Region_Level := Region_Level - 1;
5093
 
5094
         --  If nothing was pushed in the inner region, we can just get
5095
         --  rid of it entirely, leaving no traces that it was ever there
5096
 
5097
         if Stack_Ptr = Stack_Base then
5098
            Stack_Ptr := Stack_Base - 2;
5099
            Stack_Base := Stack (Stack_Ptr + 2).Cursor;
5100
 
5101
         --  If stuff was pushed in the inner region, then we have to
5102
         --  push a PC_R_Restore node so that we properly handle possible
5103
         --  rematches within the region.
5104
 
5105
         else
5106
            Stack_Ptr := Stack_Ptr + 1;
5107
            Stack (Stack_Ptr).Cursor := Stack_Base;
5108
            Stack (Stack_Ptr).Node   := CP_R_Restore'Access;
5109
            Stack_Base := Stack (Stack_Base).Cursor;
5110
         end if;
5111
      end Pop_Region;
5112
 
5113
      ----------
5114
      -- Push --
5115
      ----------
5116
 
5117
      procedure Push (Node : PE_Ptr) is
5118
      begin
5119
         Stack_Ptr := Stack_Ptr + 1;
5120
         Stack (Stack_Ptr).Cursor := Cursor;
5121
         Stack (Stack_Ptr).Node   := Node;
5122
      end Push;
5123
 
5124
      -----------------
5125
      -- Push_Region --
5126
      -----------------
5127
 
5128
      procedure Push_Region is
5129
      begin
5130
         Region_Level := Region_Level + 1;
5131
         Stack_Ptr := Stack_Ptr + 2;
5132
         Stack (Stack_Ptr).Cursor := Stack_Base;
5133
         Stack (Stack_Ptr).Node   := CP_R_Remove'Access;
5134
         Stack_Base := Stack_Ptr;
5135
      end Push_Region;
5136
 
5137
   --  Start of processing for XMatchD
5138
 
5139
   begin
5140
      New_Line;
5141
      Put_Line ("Initiating pattern match, subject = " & Image (Subject));
5142
      Put      ("--------------------------------------");
5143
 
5144
      for J in 1 .. Length loop
5145
         Put ('-');
5146
      end loop;
5147
 
5148
      New_Line;
5149
      Put_Line ("subject length = " & Length);
5150
 
5151
      if Pat_P = null then
5152
         Uninitialized_Pattern;
5153
      end if;
5154
 
5155
      --  Check we have enough stack for this pattern. This check deals with
5156
      --  every possibility except a match of a recursive pattern, where we
5157
      --  make a check at each recursion level.
5158
 
5159
      if Pat_S >= Stack_Size - 1 then
5160
         raise Pattern_Stack_Overflow;
5161
      end if;
5162
 
5163
      --  In anchored mode, the bottom entry on the stack is an abort entry
5164
 
5165
      if Anchored_Mode then
5166
         Stack (Stack_Init).Node   := CP_Cancel'Access;
5167
         Stack (Stack_Init).Cursor := 0;
5168
 
5169
      --  In unanchored more, the bottom entry on the stack references
5170
      --  the special pattern element PE_Unanchored, whose Pthen field
5171
      --  points to the initial pattern element. The cursor value in this
5172
      --  entry is the number of anchor moves so far.
5173
 
5174
      else
5175
         Stack (Stack_Init).Node   := PE_Unanchored'Unchecked_Access;
5176
         Stack (Stack_Init).Cursor := 0;
5177
      end if;
5178
 
5179
      Stack_Ptr    := Stack_Init;
5180
      Stack_Base   := Stack_Ptr;
5181
      Cursor       := 0;
5182
      Node         := Pat_P;
5183
      goto Match;
5184
 
5185
      -----------------------------------------
5186
      -- Main Pattern Matching State Control --
5187
      -----------------------------------------
5188
 
5189
      --  This is a state machine which uses gotos to change state. The
5190
      --  initial state is Match, to initiate the matching of the first
5191
      --  element, so the goto Match above starts the match. In the
5192
      --  following descriptions, we indicate the global values that
5193
      --  are relevant for the state transition.
5194
 
5195
      --  Come here if entire match fails
5196
 
5197
      <<Match_Fail>>
5198
         Dout ("match fails");
5199
         New_Line;
5200
         Start := 0;
5201
         Stop  := 0;
5202
         return;
5203
 
5204
      --  Come here if entire match succeeds
5205
 
5206
      --    Cursor        current position in subject string
5207
 
5208
      <<Match_Succeed>>
5209
         Dout ("match succeeds");
5210
         Start := Stack (Stack_Init).Cursor + 1;
5211
         Stop  := Cursor;
5212
         Dout ("first matched character index = " & Start);
5213
         Dout ("last matched character index = " & Stop);
5214
         Dout ("matched substring = " & Image (Subject (Start .. Stop)));
5215
 
5216
         --  Scan history stack for deferred assignments or writes
5217
 
5218
         if Assign_OnM then
5219
            for S in Stack'First .. Stack_Ptr loop
5220
               if Stack (S).Node = CP_Assign'Access then
5221
                  declare
5222
                     Inner_Base    : constant Stack_Range :=
5223
                                       Stack (S + 1).Cursor;
5224
                     Special_Entry : constant Stack_Range :=
5225
                                       Inner_Base - 1;
5226
                     Node_OnM      : constant PE_Ptr  :=
5227
                                       Stack (Special_Entry).Node;
5228
                     Start         : constant Natural :=
5229
                                       Stack (Special_Entry).Cursor + 1;
5230
                     Stop          : constant Natural := Stack (S).Cursor;
5231
 
5232
                  begin
5233
                     if Node_OnM.Pcode = PC_Assign_OnM then
5234
                        Set_String (Node_OnM.VP.all, Subject (Start .. Stop));
5235
                        Dout
5236
                          (Img (Stack (S).Node) &
5237
                           "deferred assignment of " &
5238
                           Image (Subject (Start .. Stop)));
5239
 
5240
                     elsif Node_OnM.Pcode = PC_Write_OnM then
5241
                        Put_Line (Node_OnM.FP.all, Subject (Start .. Stop));
5242
                        Dout
5243
                          (Img (Stack (S).Node) &
5244
                           "deferred write of " &
5245
                           Image (Subject (Start .. Stop)));
5246
 
5247
                     else
5248
                        Logic_Error;
5249
                     end if;
5250
                  end;
5251
               end if;
5252
            end loop;
5253
         end if;
5254
 
5255
         New_Line;
5256
         return;
5257
 
5258
      --  Come here if attempt to match current element fails
5259
 
5260
      --    Stack_Base    current stack base
5261
      --    Stack_Ptr     current stack pointer
5262
 
5263
      <<Fail>>
5264
         Cursor := Stack (Stack_Ptr).Cursor;
5265
         Node   := Stack (Stack_Ptr).Node;
5266
         Stack_Ptr := Stack_Ptr - 1;
5267
 
5268
         if Cursor >= 0 then
5269
            Dout ("failure, cursor reset to " & Cursor);
5270
         end if;
5271
 
5272
         goto Match;
5273
 
5274
      --  Come here if attempt to match current element succeeds
5275
 
5276
      --    Cursor        current position in subject string
5277
      --    Node          pointer to node successfully matched
5278
      --    Stack_Base    current stack base
5279
      --    Stack_Ptr     current stack pointer
5280
 
5281
      <<Succeed>>
5282
         Dout ("success, cursor = " & Cursor);
5283
         Node := Node.Pthen;
5284
 
5285
      --  Come here to match the next pattern element
5286
 
5287
      --    Cursor        current position in subject string
5288
      --    Node          pointer to node to be matched
5289
      --    Stack_Base    current stack base
5290
      --    Stack_Ptr     current stack pointer
5291
 
5292
      <<Match>>
5293
 
5294
      --------------------------------------------------
5295
      -- Main Pattern Match Element Matching Routines --
5296
      --------------------------------------------------
5297
 
5298
      --  Here is the case statement that processes the current node. The
5299
      --  processing for each element does one of five things:
5300
 
5301
      --    goto Succeed        to move to the successor
5302
      --    goto Match_Succeed  if the entire match succeeds
5303
      --    goto Match_Fail     if the entire match fails
5304
      --    goto Fail           to signal failure of current match
5305
 
5306
      --  Processing is NOT allowed to fall through
5307
 
5308
      case Node.Pcode is
5309
 
5310
         --  Cancel
5311
 
5312
         when PC_Cancel =>
5313
            Dout (Img (Node) & "matching Cancel");
5314
            goto Match_Fail;
5315
 
5316
         --  Alternation
5317
 
5318
         when PC_Alt =>
5319
            Dout
5320
              (Img (Node) & "setting up alternative " & Img (Node.Alt));
5321
            Push (Node.Alt);
5322
            Node := Node.Pthen;
5323
            goto Match;
5324
 
5325
         --  Any (one character case)
5326
 
5327
         when PC_Any_CH =>
5328
            Dout (Img (Node) & "matching Any", Node.Char);
5329
 
5330
            if Cursor < Length
5331
              and then Subject (Cursor + 1) = Node.Char
5332
            then
5333
               Cursor := Cursor + 1;
5334
               goto Succeed;
5335
            else
5336
               goto Fail;
5337
            end if;
5338
 
5339
         --  Any (character set case)
5340
 
5341
         when PC_Any_CS =>
5342
            Dout (Img (Node) & "matching Any", Node.CS);
5343
 
5344
            if Cursor < Length
5345
              and then Is_In (Subject (Cursor + 1), Node.CS)
5346
            then
5347
               Cursor := Cursor + 1;
5348
               goto Succeed;
5349
            else
5350
               goto Fail;
5351
            end if;
5352
 
5353
         --  Any (string function case)
5354
 
5355
         when PC_Any_VF => declare
5356
            U : constant VString := Node.VF.all;
5357
            S : String_Access;
5358
            L : Natural;
5359
 
5360
         begin
5361
            Get_String (U, S, L);
5362
 
5363
            Dout (Img (Node) & "matching Any", S (1 .. L));
5364
 
5365
            if Cursor < Length
5366
              and then Is_In (Subject (Cursor + 1), S (1 .. L))
5367
            then
5368
               Cursor := Cursor + 1;
5369
               goto Succeed;
5370
            else
5371
               goto Fail;
5372
            end if;
5373
         end;
5374
 
5375
         --  Any (string pointer case)
5376
 
5377
         when PC_Any_VP => declare
5378
            U : constant VString := Node.VP.all;
5379
            S : String_Access;
5380
            L : Natural;
5381
 
5382
         begin
5383
            Get_String (U, S, L);
5384
            Dout (Img (Node) & "matching Any", S (1 .. L));
5385
 
5386
            if Cursor < Length
5387
              and then Is_In (Subject (Cursor + 1), S (1 .. L))
5388
            then
5389
               Cursor := Cursor + 1;
5390
               goto Succeed;
5391
            else
5392
               goto Fail;
5393
            end if;
5394
         end;
5395
 
5396
         --  Arb (initial match)
5397
 
5398
         when PC_Arb_X =>
5399
            Dout (Img (Node) & "matching Arb");
5400
            Push (Node.Alt);
5401
            Node := Node.Pthen;
5402
            goto Match;
5403
 
5404
         --  Arb (extension)
5405
 
5406
         when PC_Arb_Y  =>
5407
            Dout (Img (Node) & "extending Arb");
5408
 
5409
            if Cursor < Length then
5410
               Cursor := Cursor + 1;
5411
               Push (Node);
5412
               goto Succeed;
5413
            else
5414
               goto Fail;
5415
            end if;
5416
 
5417
         --  Arbno_S (simple Arbno initialize). This is the node that
5418
         --  initiates the match of a simple Arbno structure.
5419
 
5420
         when PC_Arbno_S =>
5421
            Dout (Img (Node) &
5422
                  "setting up Arbno alternative " & Img (Node.Alt));
5423
            Push (Node.Alt);
5424
            Node := Node.Pthen;
5425
            goto Match;
5426
 
5427
         --  Arbno_X (Arbno initialize). This is the node that initiates
5428
         --  the match of a complex Arbno structure.
5429
 
5430
         when PC_Arbno_X =>
5431
            Dout (Img (Node) &
5432
                  "setting up Arbno alternative " & Img (Node.Alt));
5433
            Push (Node.Alt);
5434
            Node := Node.Pthen;
5435
            goto Match;
5436
 
5437
         --  Arbno_Y (Arbno rematch). This is the node that is executed
5438
         --  following successful matching of one instance of a complex
5439
         --  Arbno pattern.
5440
 
5441
         when PC_Arbno_Y => declare
5442
            Null_Match : constant Boolean :=
5443
                           Cursor = Stack (Stack_Base - 1).Cursor;
5444
 
5445
         begin
5446
            Dout (Img (Node) & "extending Arbno");
5447
            Pop_Region;
5448
 
5449
            --  If arbno extension matched null, then immediately fail
5450
 
5451
            if Null_Match then
5452
               Dout ("Arbno extension matched null, so fails");
5453
               goto Fail;
5454
            end if;
5455
 
5456
            --  Here we must do a stack check to make sure enough stack
5457
            --  is left. This check will happen once for each instance of
5458
            --  the Arbno pattern that is matched. The Nat field of a
5459
            --  PC_Arbno pattern contains the maximum stack entries needed
5460
            --  for the Arbno with one instance and the successor pattern
5461
 
5462
            if Stack_Ptr + Node.Nat >= Stack'Last then
5463
               raise Pattern_Stack_Overflow;
5464
            end if;
5465
 
5466
            goto Succeed;
5467
         end;
5468
 
5469
         --  Assign. If this node is executed, it means the assign-on-match
5470
         --  or write-on-match operation will not happen after all, so we
5471
         --  is propagate the failure, removing the PC_Assign node.
5472
 
5473
         when PC_Assign =>
5474
            Dout (Img (Node) & "deferred assign/write cancelled");
5475
            goto Fail;
5476
 
5477
         --  Assign immediate. This node performs the actual assignment
5478
 
5479
         when PC_Assign_Imm =>
5480
            Dout
5481
              (Img (Node) & "executing immediate assignment of " &
5482
               Image (Subject (Stack (Stack_Base - 1).Cursor + 1 .. Cursor)));
5483
            Set_String
5484
              (Node.VP.all,
5485
               Subject (Stack (Stack_Base - 1).Cursor + 1 .. Cursor));
5486
            Pop_Region;
5487
            goto Succeed;
5488
 
5489
         --  Assign on match. This node sets up for the eventual assignment
5490
 
5491
         when PC_Assign_OnM =>
5492
            Dout (Img (Node) & "registering deferred assignment");
5493
            Stack (Stack_Base - 1).Node := Node;
5494
            Push (CP_Assign'Access);
5495
            Pop_Region;
5496
            Assign_OnM := True;
5497
            goto Succeed;
5498
 
5499
         --  Bal
5500
 
5501
         when PC_Bal =>
5502
            Dout (Img (Node) & "matching or extending Bal");
5503
            if Cursor >= Length or else Subject (Cursor + 1) = ')' then
5504
               goto Fail;
5505
 
5506
            elsif Subject (Cursor + 1) = '(' then
5507
               declare
5508
                  Paren_Count : Natural := 1;
5509
 
5510
               begin
5511
                  loop
5512
                     Cursor := Cursor + 1;
5513
 
5514
                     if Cursor >= Length then
5515
                        goto Fail;
5516
 
5517
                     elsif Subject (Cursor + 1) = '(' then
5518
                        Paren_Count := Paren_Count + 1;
5519
 
5520
                     elsif Subject (Cursor + 1) = ')' then
5521
                        Paren_Count := Paren_Count - 1;
5522
                        exit when Paren_Count = 0;
5523
                     end if;
5524
                  end loop;
5525
               end;
5526
            end if;
5527
 
5528
            Cursor := Cursor + 1;
5529
            Push (Node);
5530
            goto Succeed;
5531
 
5532
         --  Break (one character case)
5533
 
5534
         when PC_Break_CH =>
5535
            Dout (Img (Node) & "matching Break", Node.Char);
5536
 
5537
            while Cursor < Length loop
5538
               if Subject (Cursor + 1) = Node.Char then
5539
                  goto Succeed;
5540
               else
5541
                  Cursor := Cursor + 1;
5542
               end if;
5543
            end loop;
5544
 
5545
            goto Fail;
5546
 
5547
         --  Break (character set case)
5548
 
5549
         when PC_Break_CS =>
5550
            Dout (Img (Node) & "matching Break", Node.CS);
5551
 
5552
            while Cursor < Length loop
5553
               if Is_In (Subject (Cursor + 1), Node.CS) then
5554
                  goto Succeed;
5555
               else
5556
                  Cursor := Cursor + 1;
5557
               end if;
5558
            end loop;
5559
 
5560
            goto Fail;
5561
 
5562
         --  Break (string function case)
5563
 
5564
         when PC_Break_VF => declare
5565
            U : constant VString := Node.VF.all;
5566
            S : String_Access;
5567
            L : Natural;
5568
 
5569
         begin
5570
            Get_String (U, S, L);
5571
            Dout (Img (Node) & "matching Break", S (1 .. L));
5572
 
5573
            while Cursor < Length loop
5574
               if Is_In (Subject (Cursor + 1), S (1 .. L)) then
5575
                  goto Succeed;
5576
               else
5577
                  Cursor := Cursor + 1;
5578
               end if;
5579
            end loop;
5580
 
5581
            goto Fail;
5582
         end;
5583
 
5584
         --  Break (string pointer case)
5585
 
5586
         when PC_Break_VP => declare
5587
            U : constant VString := Node.VP.all;
5588
            S : String_Access;
5589
            L : Natural;
5590
 
5591
         begin
5592
            Get_String (U, S, L);
5593
            Dout (Img (Node) & "matching Break", S (1 .. L));
5594
 
5595
            while Cursor < Length loop
5596
               if Is_In (Subject (Cursor + 1), S (1 .. L)) then
5597
                  goto Succeed;
5598
               else
5599
                  Cursor := Cursor + 1;
5600
               end if;
5601
            end loop;
5602
 
5603
            goto Fail;
5604
         end;
5605
 
5606
         --  BreakX (one character case)
5607
 
5608
         when PC_BreakX_CH =>
5609
            Dout (Img (Node) & "matching BreakX", Node.Char);
5610
 
5611
            while Cursor < Length loop
5612
               if Subject (Cursor + 1) = Node.Char then
5613
                  goto Succeed;
5614
               else
5615
                  Cursor := Cursor + 1;
5616
               end if;
5617
            end loop;
5618
 
5619
            goto Fail;
5620
 
5621
         --  BreakX (character set case)
5622
 
5623
         when PC_BreakX_CS =>
5624
            Dout (Img (Node) & "matching BreakX", Node.CS);
5625
 
5626
            while Cursor < Length loop
5627
               if Is_In (Subject (Cursor + 1), Node.CS) then
5628
                  goto Succeed;
5629
               else
5630
                  Cursor := Cursor + 1;
5631
               end if;
5632
            end loop;
5633
 
5634
            goto Fail;
5635
 
5636
         --  BreakX (string function case)
5637
 
5638
         when PC_BreakX_VF => declare
5639
            U : constant VString := Node.VF.all;
5640
            S : String_Access;
5641
            L : Natural;
5642
 
5643
         begin
5644
            Get_String (U, S, L);
5645
            Dout (Img (Node) & "matching BreakX", S (1 .. L));
5646
 
5647
            while Cursor < Length loop
5648
               if Is_In (Subject (Cursor + 1), S (1 .. L)) then
5649
                  goto Succeed;
5650
               else
5651
                  Cursor := Cursor + 1;
5652
               end if;
5653
            end loop;
5654
 
5655
            goto Fail;
5656
         end;
5657
 
5658
         --  BreakX (string pointer case)
5659
 
5660
         when PC_BreakX_VP => declare
5661
            U : constant VString := Node.VP.all;
5662
            S : String_Access;
5663
            L : Natural;
5664
 
5665
         begin
5666
            Get_String (U, S, L);
5667
            Dout (Img (Node) & "matching BreakX", S (1 .. L));
5668
 
5669
            while Cursor < Length loop
5670
               if Is_In (Subject (Cursor + 1), S (1 .. L)) then
5671
                  goto Succeed;
5672
               else
5673
                  Cursor := Cursor + 1;
5674
               end if;
5675
            end loop;
5676
 
5677
            goto Fail;
5678
         end;
5679
 
5680
         --  BreakX_X (BreakX extension). See section on "Compound Pattern
5681
         --  Structures". This node is the alternative that is stacked
5682
         --  to skip past the break character and extend the break.
5683
 
5684
         when PC_BreakX_X =>
5685
            Dout (Img (Node) & "extending BreakX");
5686
            Cursor := Cursor + 1;
5687
            goto Succeed;
5688
 
5689
         --  Character (one character string)
5690
 
5691
         when PC_Char =>
5692
            Dout (Img (Node) & "matching '" & Node.Char & ''');
5693
 
5694
            if Cursor < Length
5695
              and then Subject (Cursor + 1) = Node.Char
5696
            then
5697
               Cursor := Cursor + 1;
5698
               goto Succeed;
5699
            else
5700
               goto Fail;
5701
            end if;
5702
 
5703
         --  End of Pattern
5704
 
5705
         when PC_EOP =>
5706
            if Stack_Base = Stack_Init then
5707
               Dout ("end of pattern");
5708
               goto Match_Succeed;
5709
 
5710
            --  End of recursive inner match. See separate section on
5711
            --  handing of recursive pattern matches for details.
5712
 
5713
            else
5714
               Dout ("terminating recursive match");
5715
               Node := Stack (Stack_Base - 1).Node;
5716
               Pop_Region;
5717
               goto Match;
5718
            end if;
5719
 
5720
         --  Fail
5721
 
5722
         when PC_Fail =>
5723
            Dout (Img (Node) & "matching Fail");
5724
            goto Fail;
5725
 
5726
         --  Fence (built in pattern)
5727
 
5728
         when PC_Fence =>
5729
            Dout (Img (Node) & "matching Fence");
5730
            Push (CP_Cancel'Access);
5731
            goto Succeed;
5732
 
5733
         --  Fence function node X. This is the node that gets control
5734
         --  after a successful match of the fenced pattern.
5735
 
5736
         when PC_Fence_X =>
5737
            Dout (Img (Node) & "matching Fence function");
5738
            Stack_Ptr := Stack_Ptr + 1;
5739
            Stack (Stack_Ptr).Cursor := Stack_Base;
5740
            Stack (Stack_Ptr).Node   := CP_Fence_Y'Access;
5741
            Stack_Base := Stack (Stack_Base).Cursor;
5742
            Region_Level := Region_Level - 1;
5743
            goto Succeed;
5744
 
5745
         --  Fence function node Y. This is the node that gets control on
5746
         --  a failure that occurs after the fenced pattern has matched.
5747
 
5748
         --  Note: the Cursor at this stage is actually the inner stack
5749
         --  base value. We don't reset this, but we do use it to strip
5750
         --  off all the entries made by the fenced pattern.
5751
 
5752
         when PC_Fence_Y =>
5753
            Dout (Img (Node) & "pattern matched by Fence caused failure");
5754
            Stack_Ptr := Cursor - 2;
5755
            goto Fail;
5756
 
5757
         --  Len (integer case)
5758
 
5759
         when PC_Len_Nat =>
5760
            Dout (Img (Node) & "matching Len", Node.Nat);
5761
 
5762
            if Cursor + Node.Nat > Length then
5763
               goto Fail;
5764
            else
5765
               Cursor := Cursor + Node.Nat;
5766
               goto Succeed;
5767
            end if;
5768
 
5769
         --  Len (Integer function case)
5770
 
5771
         when PC_Len_NF => declare
5772
            N : constant Natural := Node.NF.all;
5773
 
5774
         begin
5775
            Dout (Img (Node) & "matching Len", N);
5776
 
5777
            if Cursor + N > Length then
5778
               goto Fail;
5779
            else
5780
               Cursor := Cursor + N;
5781
               goto Succeed;
5782
            end if;
5783
         end;
5784
 
5785
         --  Len (integer pointer case)
5786
 
5787
         when PC_Len_NP =>
5788
            Dout (Img (Node) & "matching Len", Node.NP.all);
5789
 
5790
            if Cursor + Node.NP.all > Length then
5791
               goto Fail;
5792
            else
5793
               Cursor := Cursor + Node.NP.all;
5794
               goto Succeed;
5795
            end if;
5796
 
5797
         --  NotAny (one character case)
5798
 
5799
         when PC_NotAny_CH =>
5800
            Dout (Img (Node) & "matching NotAny", Node.Char);
5801
 
5802
            if Cursor < Length
5803
              and then Subject (Cursor + 1) /= Node.Char
5804
            then
5805
               Cursor := Cursor + 1;
5806
               goto Succeed;
5807
            else
5808
               goto Fail;
5809
            end if;
5810
 
5811
         --  NotAny (character set case)
5812
 
5813
         when PC_NotAny_CS =>
5814
            Dout (Img (Node) & "matching NotAny", Node.CS);
5815
 
5816
            if Cursor < Length
5817
              and then not Is_In (Subject (Cursor + 1), Node.CS)
5818
            then
5819
               Cursor := Cursor + 1;
5820
               goto Succeed;
5821
            else
5822
               goto Fail;
5823
            end if;
5824
 
5825
         --  NotAny (string function case)
5826
 
5827
         when PC_NotAny_VF => declare
5828
            U : constant VString := Node.VF.all;
5829
            S : String_Access;
5830
            L : Natural;
5831
 
5832
         begin
5833
            Get_String (U, S, L);
5834
            Dout (Img (Node) & "matching NotAny", S (1 .. L));
5835
 
5836
            if Cursor < Length
5837
              and then
5838
                not Is_In (Subject (Cursor + 1), S (1 .. L))
5839
            then
5840
               Cursor := Cursor + 1;
5841
               goto Succeed;
5842
            else
5843
               goto Fail;
5844
            end if;
5845
         end;
5846
 
5847
         --  NotAny (string pointer case)
5848
 
5849
         when PC_NotAny_VP => declare
5850
            U : constant VString := Node.VP.all;
5851
            S : String_Access;
5852
            L : Natural;
5853
 
5854
         begin
5855
            Get_String (U, S, L);
5856
            Dout (Img (Node) & "matching NotAny", S (1 .. L));
5857
 
5858
            if Cursor < Length
5859
              and then
5860
                not Is_In (Subject (Cursor + 1), S (1 .. L))
5861
            then
5862
               Cursor := Cursor + 1;
5863
               goto Succeed;
5864
            else
5865
               goto Fail;
5866
            end if;
5867
         end;
5868
 
5869
         --  NSpan (one character case)
5870
 
5871
         when PC_NSpan_CH =>
5872
            Dout (Img (Node) & "matching NSpan", Node.Char);
5873
 
5874
            while Cursor < Length
5875
              and then Subject (Cursor + 1) = Node.Char
5876
            loop
5877
               Cursor := Cursor + 1;
5878
            end loop;
5879
 
5880
            goto Succeed;
5881
 
5882
         --  NSpan (character set case)
5883
 
5884
         when PC_NSpan_CS =>
5885
            Dout (Img (Node) & "matching NSpan", Node.CS);
5886
 
5887
            while Cursor < Length
5888
              and then Is_In (Subject (Cursor + 1), Node.CS)
5889
            loop
5890
               Cursor := Cursor + 1;
5891
            end loop;
5892
 
5893
            goto Succeed;
5894
 
5895
         --  NSpan (string function case)
5896
 
5897
         when PC_NSpan_VF => declare
5898
            U : constant VString := Node.VF.all;
5899
            S : String_Access;
5900
            L : Natural;
5901
 
5902
         begin
5903
            Get_String (U, S, L);
5904
            Dout (Img (Node) & "matching NSpan", S (1 .. L));
5905
 
5906
            while Cursor < Length
5907
              and then Is_In (Subject (Cursor + 1), S (1 .. L))
5908
            loop
5909
               Cursor := Cursor + 1;
5910
            end loop;
5911
 
5912
            goto Succeed;
5913
         end;
5914
 
5915
         --  NSpan (string pointer case)
5916
 
5917
         when PC_NSpan_VP => declare
5918
            U : constant VString := Node.VP.all;
5919
            S : String_Access;
5920
            L : Natural;
5921
 
5922
         begin
5923
            Get_String (U, S, L);
5924
            Dout (Img (Node) & "matching NSpan", S (1 .. L));
5925
 
5926
            while Cursor < Length
5927
              and then Is_In (Subject (Cursor + 1), S (1 .. L))
5928
            loop
5929
               Cursor := Cursor + 1;
5930
            end loop;
5931
 
5932
            goto Succeed;
5933
         end;
5934
 
5935
         when PC_Null =>
5936
            Dout (Img (Node) & "matching null");
5937
            goto Succeed;
5938
 
5939
         --  Pos (integer case)
5940
 
5941
         when PC_Pos_Nat =>
5942
            Dout (Img (Node) & "matching Pos", Node.Nat);
5943
 
5944
            if Cursor = Node.Nat then
5945
               goto Succeed;
5946
            else
5947
               goto Fail;
5948
            end if;
5949
 
5950
         --  Pos (Integer function case)
5951
 
5952
         when PC_Pos_NF => declare
5953
            N : constant Natural := Node.NF.all;
5954
 
5955
         begin
5956
            Dout (Img (Node) & "matching Pos", N);
5957
 
5958
            if Cursor = N then
5959
               goto Succeed;
5960
            else
5961
               goto Fail;
5962
            end if;
5963
         end;
5964
 
5965
         --  Pos (integer pointer case)
5966
 
5967
         when PC_Pos_NP =>
5968
            Dout (Img (Node) & "matching Pos", Node.NP.all);
5969
 
5970
            if Cursor = Node.NP.all then
5971
               goto Succeed;
5972
            else
5973
               goto Fail;
5974
            end if;
5975
 
5976
         --  Predicate function
5977
 
5978
         when PC_Pred_Func =>
5979
            Dout (Img (Node) & "matching predicate function");
5980
 
5981
            if Node.BF.all then
5982
               goto Succeed;
5983
            else
5984
               goto Fail;
5985
            end if;
5986
 
5987
         --  Region Enter. Initiate new pattern history stack region
5988
 
5989
         when PC_R_Enter =>
5990
            Dout (Img (Node) & "starting match of nested pattern");
5991
            Stack (Stack_Ptr + 1).Cursor := Cursor;
5992
            Push_Region;
5993
            goto Succeed;
5994
 
5995
         --  Region Remove node. This is the node stacked by an R_Enter.
5996
         --  It removes the special format stack entry right underneath, and
5997
         --  then restores the outer level stack base and signals failure.
5998
 
5999
         --  Note: the cursor value at this stage is actually the (negative)
6000
         --  stack base value for the outer level.
6001
 
6002
         when PC_R_Remove =>
6003
            Dout ("failure, match of nested pattern terminated");
6004
            Stack_Base := Cursor;
6005
            Region_Level := Region_Level - 1;
6006
            Stack_Ptr := Stack_Ptr - 1;
6007
            goto Fail;
6008
 
6009
         --  Region restore node. This is the node stacked at the end of an
6010
         --  inner level match. Its function is to restore the inner level
6011
         --  region, so that alternatives in this region can be sought.
6012
 
6013
         --  Note: the Cursor at this stage is actually the negative of the
6014
         --  inner stack base value, which we use to restore the inner region.
6015
 
6016
         when PC_R_Restore =>
6017
            Dout ("failure, search for alternatives in nested pattern");
6018
            Region_Level := Region_Level + 1;
6019
            Stack_Base := Cursor;
6020
            goto Fail;
6021
 
6022
         --  Rest
6023
 
6024
         when PC_Rest =>
6025
            Dout (Img (Node) & "matching Rest");
6026
            Cursor := Length;
6027
            goto Succeed;
6028
 
6029
         --  Initiate recursive match (pattern pointer case)
6030
 
6031
         when PC_Rpat =>
6032
            Stack (Stack_Ptr + 1).Node := Node.Pthen;
6033
            Push_Region;
6034
            Dout (Img (Node) & "initiating recursive match");
6035
 
6036
            if Stack_Ptr + Node.PP.all.Stk >= Stack_Size then
6037
               raise Pattern_Stack_Overflow;
6038
            else
6039
               Node := Node.PP.all.P;
6040
               goto Match;
6041
            end if;
6042
 
6043
         --  RPos (integer case)
6044
 
6045
         when PC_RPos_Nat =>
6046
            Dout (Img (Node) & "matching RPos", Node.Nat);
6047
 
6048
            if Cursor = (Length - Node.Nat) then
6049
               goto Succeed;
6050
            else
6051
               goto Fail;
6052
            end if;
6053
 
6054
         --  RPos (integer function case)
6055
 
6056
         when PC_RPos_NF => declare
6057
            N : constant Natural := Node.NF.all;
6058
 
6059
         begin
6060
            Dout (Img (Node) & "matching RPos", N);
6061
 
6062
            if Length - Cursor = N then
6063
               goto Succeed;
6064
            else
6065
               goto Fail;
6066
            end if;
6067
         end;
6068
 
6069
         --  RPos (integer pointer case)
6070
 
6071
         when PC_RPos_NP =>
6072
            Dout (Img (Node) & "matching RPos", Node.NP.all);
6073
 
6074
            if Cursor = (Length - Node.NP.all) then
6075
               goto Succeed;
6076
            else
6077
               goto Fail;
6078
            end if;
6079
 
6080
         --  RTab (integer case)
6081
 
6082
         when PC_RTab_Nat =>
6083
            Dout (Img (Node) & "matching RTab", Node.Nat);
6084
 
6085
            if Cursor <= (Length - Node.Nat) then
6086
               Cursor := Length - Node.Nat;
6087
               goto Succeed;
6088
            else
6089
               goto Fail;
6090
            end if;
6091
 
6092
         --  RTab (integer function case)
6093
 
6094
         when PC_RTab_NF => declare
6095
            N : constant Natural := Node.NF.all;
6096
 
6097
         begin
6098
            Dout (Img (Node) & "matching RPos", N);
6099
 
6100
            if Length - Cursor >= N then
6101
               Cursor := Length - N;
6102
               goto Succeed;
6103
            else
6104
               goto Fail;
6105
            end if;
6106
         end;
6107
 
6108
         --  RTab (integer pointer case)
6109
 
6110
         when PC_RTab_NP =>
6111
            Dout (Img (Node) & "matching RPos", Node.NP.all);
6112
 
6113
            if Cursor <= (Length - Node.NP.all) then
6114
               Cursor := Length - Node.NP.all;
6115
               goto Succeed;
6116
            else
6117
               goto Fail;
6118
            end if;
6119
 
6120
         --  Cursor assignment
6121
 
6122
         when PC_Setcur =>
6123
            Dout (Img (Node) & "matching Setcur");
6124
            Node.Var.all := Cursor;
6125
            goto Succeed;
6126
 
6127
         --  Span (one character case)
6128
 
6129
         when PC_Span_CH => declare
6130
            P : Natural := Cursor;
6131
 
6132
         begin
6133
            Dout (Img (Node) & "matching Span", Node.Char);
6134
 
6135
            while P < Length
6136
              and then Subject (P + 1) = Node.Char
6137
            loop
6138
               P := P + 1;
6139
            end loop;
6140
 
6141
            if P /= Cursor then
6142
               Cursor := P;
6143
               goto Succeed;
6144
            else
6145
               goto Fail;
6146
            end if;
6147
         end;
6148
 
6149
         --  Span (character set case)
6150
 
6151
         when PC_Span_CS => declare
6152
            P : Natural := Cursor;
6153
 
6154
         begin
6155
            Dout (Img (Node) & "matching Span", Node.CS);
6156
 
6157
            while P < Length
6158
              and then Is_In (Subject (P + 1), Node.CS)
6159
            loop
6160
               P := P + 1;
6161
            end loop;
6162
 
6163
            if P /= Cursor then
6164
               Cursor := P;
6165
               goto Succeed;
6166
            else
6167
               goto Fail;
6168
            end if;
6169
         end;
6170
 
6171
         --  Span (string function case)
6172
 
6173
         when PC_Span_VF => declare
6174
            U : constant VString := Node.VF.all;
6175
            S : String_Access;
6176
            L : Natural;
6177
            P : Natural;
6178
 
6179
         begin
6180
            Get_String (U, S, L);
6181
            Dout (Img (Node) & "matching Span", S (1 .. L));
6182
 
6183
            P := Cursor;
6184
            while P < Length
6185
              and then Is_In (Subject (P + 1), S (1 .. L))
6186
            loop
6187
               P := P + 1;
6188
            end loop;
6189
 
6190
            if P /= Cursor then
6191
               Cursor := P;
6192
               goto Succeed;
6193
            else
6194
               goto Fail;
6195
            end if;
6196
         end;
6197
 
6198
         --  Span (string pointer case)
6199
 
6200
         when PC_Span_VP => declare
6201
            U : constant VString := Node.VP.all;
6202
            S : String_Access;
6203
            L : Natural;
6204
            P : Natural;
6205
 
6206
         begin
6207
            Get_String (U, S, L);
6208
            Dout (Img (Node) & "matching Span", S (1 .. L));
6209
 
6210
            P := Cursor;
6211
            while P < Length
6212
              and then Is_In (Subject (P + 1), S (1 .. L))
6213
            loop
6214
               P := P + 1;
6215
            end loop;
6216
 
6217
            if P /= Cursor then
6218
               Cursor := P;
6219
               goto Succeed;
6220
            else
6221
               goto Fail;
6222
            end if;
6223
         end;
6224
 
6225
         --  String (two character case)
6226
 
6227
         when PC_String_2 =>
6228
            Dout (Img (Node) & "matching " & Image (Node.Str2));
6229
 
6230
            if (Length - Cursor) >= 2
6231
              and then Subject (Cursor + 1 .. Cursor + 2) = Node.Str2
6232
            then
6233
               Cursor := Cursor + 2;
6234
               goto Succeed;
6235
            else
6236
               goto Fail;
6237
            end if;
6238
 
6239
         --  String (three character case)
6240
 
6241
         when PC_String_3 =>
6242
            Dout (Img (Node) & "matching " & Image (Node.Str3));
6243
 
6244
            if (Length - Cursor) >= 3
6245
              and then Subject (Cursor + 1 .. Cursor + 3) = Node.Str3
6246
            then
6247
               Cursor := Cursor + 3;
6248
               goto Succeed;
6249
            else
6250
               goto Fail;
6251
            end if;
6252
 
6253
         --  String (four character case)
6254
 
6255
         when PC_String_4 =>
6256
            Dout (Img (Node) & "matching " & Image (Node.Str4));
6257
 
6258
            if (Length - Cursor) >= 4
6259
              and then Subject (Cursor + 1 .. Cursor + 4) = Node.Str4
6260
            then
6261
               Cursor := Cursor + 4;
6262
               goto Succeed;
6263
            else
6264
               goto Fail;
6265
            end if;
6266
 
6267
         --  String (five character case)
6268
 
6269
         when PC_String_5 =>
6270
            Dout (Img (Node) & "matching " & Image (Node.Str5));
6271
 
6272
            if (Length - Cursor) >= 5
6273
              and then Subject (Cursor + 1 .. Cursor + 5) = Node.Str5
6274
            then
6275
               Cursor := Cursor + 5;
6276
               goto Succeed;
6277
            else
6278
               goto Fail;
6279
            end if;
6280
 
6281
         --  String (six character case)
6282
 
6283
         when PC_String_6 =>
6284
            Dout (Img (Node) & "matching " & Image (Node.Str6));
6285
 
6286
            if (Length - Cursor) >= 6
6287
              and then Subject (Cursor + 1 .. Cursor + 6) = Node.Str6
6288
            then
6289
               Cursor := Cursor + 6;
6290
               goto Succeed;
6291
            else
6292
               goto Fail;
6293
            end if;
6294
 
6295
         --  String (case of more than six characters)
6296
 
6297
         when PC_String => declare
6298
            Len : constant Natural := Node.Str'Length;
6299
 
6300
         begin
6301
            Dout (Img (Node) & "matching " & Image (Node.Str.all));
6302
 
6303
            if (Length - Cursor) >= Len
6304
              and then Node.Str.all = Subject (Cursor + 1 .. Cursor + Len)
6305
            then
6306
               Cursor := Cursor + Len;
6307
               goto Succeed;
6308
            else
6309
               goto Fail;
6310
            end if;
6311
         end;
6312
 
6313
         --  String (function case)
6314
 
6315
         when PC_String_VF => declare
6316
            U : constant VString := Node.VF.all;
6317
            S : String_Access;
6318
            L : Natural;
6319
 
6320
         begin
6321
            Get_String (U, S, L);
6322
            Dout (Img (Node) & "matching " & Image (S (1 .. L)));
6323
 
6324
            if (Length - Cursor) >= L
6325
              and then S (1 .. L) = Subject (Cursor + 1 .. Cursor + L)
6326
            then
6327
               Cursor := Cursor + L;
6328
               goto Succeed;
6329
            else
6330
               goto Fail;
6331
            end if;
6332
         end;
6333
 
6334
         --  String (vstring pointer case)
6335
 
6336
         when PC_String_VP => declare
6337
            U : constant VString := Node.VP.all;
6338
            S : String_Access;
6339
            L : Natural;
6340
 
6341
         begin
6342
            Get_String (U, S, L);
6343
            Dout (Img (Node) & "matching " & Image (S (1 .. L)));
6344
 
6345
            if (Length - Cursor) >= L
6346
              and then S (1 .. L) = Subject (Cursor + 1 .. Cursor + L)
6347
            then
6348
               Cursor := Cursor + L;
6349
               goto Succeed;
6350
            else
6351
               goto Fail;
6352
            end if;
6353
         end;
6354
 
6355
         --  Succeed
6356
 
6357
         when PC_Succeed =>
6358
            Dout (Img (Node) & "matching Succeed");
6359
            Push (Node);
6360
            goto Succeed;
6361
 
6362
         --  Tab (integer case)
6363
 
6364
         when PC_Tab_Nat =>
6365
            Dout (Img (Node) & "matching Tab", Node.Nat);
6366
 
6367
            if Cursor <= Node.Nat then
6368
               Cursor := Node.Nat;
6369
               goto Succeed;
6370
            else
6371
               goto Fail;
6372
            end if;
6373
 
6374
         --  Tab (integer function case)
6375
 
6376
         when PC_Tab_NF => declare
6377
            N : constant Natural := Node.NF.all;
6378
 
6379
         begin
6380
            Dout (Img (Node) & "matching Tab ", N);
6381
 
6382
            if Cursor <= N then
6383
               Cursor := N;
6384
               goto Succeed;
6385
            else
6386
               goto Fail;
6387
            end if;
6388
         end;
6389
 
6390
         --  Tab (integer pointer case)
6391
 
6392
         when PC_Tab_NP =>
6393
            Dout (Img (Node) & "matching Tab ", Node.NP.all);
6394
 
6395
            if Cursor <= Node.NP.all then
6396
               Cursor := Node.NP.all;
6397
               goto Succeed;
6398
            else
6399
               goto Fail;
6400
            end if;
6401
 
6402
         --  Unanchored movement
6403
 
6404
         when PC_Unanchored =>
6405
            Dout ("attempting to move anchor point");
6406
 
6407
            --  All done if we tried every position
6408
 
6409
            if Cursor > Length then
6410
               goto Match_Fail;
6411
 
6412
            --  Otherwise extend the anchor point, and restack ourself
6413
 
6414
            else
6415
               Cursor := Cursor + 1;
6416
               Push (Node);
6417
               goto Succeed;
6418
            end if;
6419
 
6420
         --  Write immediate. This node performs the actual write
6421
 
6422
         when PC_Write_Imm =>
6423
            Dout (Img (Node) & "executing immediate write of " &
6424
                   Subject (Stack (Stack_Base - 1).Cursor + 1 .. Cursor));
6425
 
6426
            Put_Line
6427
              (Node.FP.all,
6428
               Subject (Stack (Stack_Base - 1).Cursor + 1 .. Cursor));
6429
            Pop_Region;
6430
            goto Succeed;
6431
 
6432
         --  Write on match. This node sets up for the eventual write
6433
 
6434
         when PC_Write_OnM =>
6435
            Dout (Img (Node) & "registering deferred write");
6436
            Stack (Stack_Base - 1).Node := Node;
6437
            Push (CP_Assign'Access);
6438
            Pop_Region;
6439
            Assign_OnM := True;
6440
            goto Succeed;
6441
 
6442
      end case;
6443
 
6444
      --  We are NOT allowed to fall though this case statement, since every
6445
      --  match routine must end by executing a goto to the appropriate point
6446
      --  in the finite state machine model.
6447
 
6448
      pragma Warnings (Off);
6449
      Logic_Error;
6450
      pragma Warnings (On);
6451
   end XMatchD;
6452
 
6453
end GNAT.Spitbol.Patterns;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.