2011-05-31 Gabriel Charette <gchare@google.com>
[official-gcc.git] / gcc / ada / g-spipat.adb
bloba85697507f31173f93ebcea11e4819002c4a5fb3
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT LIBRARY COMPONENTS --
4 -- --
5 -- G N A T . S P I T B O L . P A T T E R N S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1998-2009, AdaCore --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 2, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
20 -- Boston, MA 02110-1301, USA. --
21 -- --
22 -- As a special exception, if other files instantiate generics from this --
23 -- unit, or you link this unit with other files to produce an executable, --
24 -- this unit does not by itself cause the resulting executable to be --
25 -- covered by the GNU General Public License. This exception does not --
26 -- however invalidate any other reasons why the executable file might be --
27 -- covered by the GNU Public License. --
28 -- --
29 -- GNAT was originally developed by the GNAT team at New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc. --
31 -- --
32 ------------------------------------------------------------------------------
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.
39 with Ada.Strings.Unbounded.Aux; use Ada.Strings.Unbounded.Aux;
41 with GNAT.Debug_Utilities; use GNAT.Debug_Utilities;
43 with System; use System;
45 with Ada.Unchecked_Conversion;
46 with Ada.Unchecked_Deallocation;
48 package body GNAT.Spitbol.Patterns is
50 ------------------------
51 -- Internal Debugging --
52 ------------------------
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.
58 procedure New_LineD;
59 pragma Inline (New_LineD);
60 -- Output new blank line with New_Line if Internal_Debug is True
62 procedure PutD (Str : String);
63 pragma Inline (PutD);
64 -- Output string with Put if Internal_Debug is True
66 procedure Put_LineD (Str : String);
67 pragma Inline (Put_LineD);
68 -- Output string with Put_Line if Internal_Debug is True
70 -----------------------------
71 -- Local Type Declarations --
72 -----------------------------
74 subtype String_Ptr is Ada.Strings.Unbounded.String_Access;
75 subtype File_Ptr is Ada.Text_IO.File_Access;
77 function To_Address is new Ada.Unchecked_Conversion (PE_Ptr, Address);
78 -- Used only for debugging output purposes
80 subtype AFC is Ada.Finalization.Controlled;
82 N : constant PE_Ptr := null;
83 -- Shorthand used to initialize Copy fields to null
85 type Natural_Ptr is access all Natural;
86 type Pattern_Ptr is access all Pattern;
88 --------------------------------------------------
89 -- Description of Algorithm and Data Structures --
90 --------------------------------------------------
92 -- A pattern structure is represented as a linked graph of nodes
93 -- with the following structure:
95 -- +------------------------------------+
96 -- I Pcode I
97 -- +------------------------------------+
98 -- I Index I
99 -- +------------------------------------+
100 -- I Pthen I
101 -- +------------------------------------+
102 -- I parameter(s) I
103 -- +------------------------------------+
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.
110 -- Index is a serial index number. The use of these serial index
111 -- numbers is described in a separate section.
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.
118 -- The parameter or parameters are present for certain node types,
119 -- and the type varies with the pattern code.
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,
139 PC_Alt,
140 PC_Arb_X,
141 PC_Arbno_S,
142 PC_Arbno_X,
144 PC_Rpat,
146 PC_Pred_Func,
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,
158 PC_Write_Imm,
159 PC_Write_OnM,
161 PC_Null,
162 PC_String,
164 PC_String_2,
165 PC_String_3,
166 PC_String_4,
167 PC_String_5,
168 PC_String_6,
170 PC_Setcur,
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,
180 PC_Any_CS,
181 PC_Break_CS,
182 PC_BreakX_CS,
183 PC_NotAny_CS,
184 PC_NSpan_CS,
185 PC_Span_CS,
187 PC_Arbno_Y,
188 PC_Len_Nat,
189 PC_Pos_Nat,
190 PC_RPos_Nat,
191 PC_RTab_Nat,
192 PC_Tab_Nat,
194 PC_Pos_NF,
195 PC_Len_NF,
196 PC_RPos_NF,
197 PC_RTab_NF,
198 PC_Tab_NF,
200 PC_Pos_NP,
201 PC_Len_NP,
202 PC_RPos_NP,
203 PC_RTab_NP,
204 PC_Tab_NP,
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);
214 type IndexT is range 0 .. +(2 **15 - 1);
216 type PE (Pcode : Pattern_Code) is record
218 Index : IndexT;
219 -- Serial index number of pattern element within pattern
221 Pthen : PE_Ptr;
222 -- Successor element, to be matched after this one
224 case Pcode is
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;
244 when PC_Alt |
245 PC_Arb_X |
246 PC_Arbno_S |
247 PC_Arbno_X => Alt : PE_Ptr;
249 when PC_Rpat => PP : Pattern_Ptr;
251 when PC_Pred_Func => BF : Boolean_Func;
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;
263 when PC_Write_Imm |
264 PC_Write_OnM => FP : File_Ptr;
266 when PC_String => Str : String_Ptr;
268 when PC_String_2 => Str2 : String (1 .. 2);
270 when PC_String_3 => Str3 : String (1 .. 3);
272 when PC_String_4 => Str4 : String (1 .. 4);
274 when PC_String_5 => Str5 : String (1 .. 5);
276 when PC_String_6 => Str6 : String (1 .. 6);
278 when PC_Setcur => Var : Natural_Ptr;
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;
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;
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;
302 when PC_Pos_NF |
303 PC_Len_NF |
304 PC_RPos_NF |
305 PC_RTab_NF |
306 PC_Tab_NF => NF : Natural_Func;
308 when PC_Pos_NP |
309 PC_Len_NP |
310 PC_RPos_NP |
311 PC_RTab_NP |
312 PC_Tab_NP => NP : Natural_Ptr;
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;
322 end case;
323 end record;
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.
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.
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.
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.
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);
367 -------------------------------
368 -- The Pattern History Stack --
369 -------------------------------
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.
380 type Stack_Entry is record
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.
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).
393 end record;
395 subtype Stack_Range is Integer range -Stack_Size .. -1;
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.
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.
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.
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.
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.
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.
429 ---------------------------------------------------
430 -- Use of Serial Index Field in Pattern Elements --
431 ---------------------------------------------------
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.
439 -- The index numbers meet three separate invariants, which are used for
440 -- various purposes as described in this section.
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.
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.
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,
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.
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.
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.
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.
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.
495 -------------------------------
496 -- Recursive Pattern Matches --
497 -------------------------------
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.
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.
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.
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:
525 -- (stack entries made by outer level)
527 -- (Special entry, node is (+P) successor
528 -- cursor entry is not used)
530 -- (PC_R_Remove entry, "cursor" value is (negative) <-- Stack base
531 -- saved base value for the enclosing region)
533 -- (stack entries made by inner level)
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.
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.
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.
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:
560 -- (stack entries made by outer level)
562 -- (Special entry, node is (+P) successor,
563 -- cursor entry is not used)
565 -- (PC_R_Remove entry, "cursor" value is (negative)
566 -- saved base value for the enclosing region)
568 -- (stack entries made by inner level)
570 -- (PC_Region_Replace entry, "cursor" value is (negative)
571 -- stack pointer value referencing the PC_R_Remove entry).
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.
580 ---------------------------------
581 -- Compound Pattern Structures --
582 ---------------------------------
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.
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.
598 -------------------
599 -- Concatenation --
600 -------------------
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.
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.
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.
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).
626 -----------------
627 -- Alternation --
628 -----------------
630 -- A pattern (L or R) constructs the structure:
632 -- +---+ +---+
633 -- | A |---->| L |---->
634 -- +---+ +---+
635 -- .
636 -- .
637 -- +---+
638 -- | R |---->
639 -- +---+
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.
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.
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.
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.
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:
669 -- (V or W or X) (Y or Z)
671 -- where A,B,C,D,E are all single element patterns:
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 -- +---+
687 -- The numbering of the nodes would be as follows:
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 -- +---+
703 -- Note: The above structure actually corresponds to
705 -- (A or (B or C)) (D or E)
707 -- rather than
709 -- ((A or B) or C) (D or E)
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.
716 ---------
717 -- Arb --
718 ---------
720 -- An Arb pattern builds the structure
722 -- +---+
723 -- | X |---->
724 -- +---+
725 -- .
726 -- .
727 -- +---+
728 -- | Y |---->
729 -- +---+
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.
735 -- The PC_Arb_X node is numbered 2, and the PC_Arb_Y node is 1
737 -------------------------
738 -- Arbno (simple case) --
739 -------------------------
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:
746 -- +-------------+
747 -- | ^
748 -- V |
749 -- +---+ |
750 -- | S |----> |
751 -- +---+ |
752 -- . |
753 -- . |
754 -- +---+ |
755 -- | P |---------->+
756 -- +---+
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.
763 -- The node numbering of the constituent pattern P is not affected.
764 -- The S node has a node number of P.Index + 1.
766 --------------------------
767 -- Arbno (complex case) --
768 --------------------------
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:
774 -- +--------------------------+
775 -- | ^
776 -- V |
777 -- +---+ |
778 -- | X |----> |
779 -- +---+ |
780 -- . |
781 -- . |
782 -- +---+ +---+ +---+ |
783 -- | E |---->| P |---->| Y |--->+
784 -- +---+ +---+ +---+
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.
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.
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:
800 -- (stack entries made before assign pattern)
802 -- (Special entry, node field not used,
803 -- used only to save initial cursor)
805 -- (PC_R_Remove entry, "cursor" value is (negative) <-- Stack Base
806 -- saved base value for the enclosing region)
808 -- (stack entries made by matching P)
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.
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:
821 -- (stack entries made before assign pattern)
823 -- (Special entry, node field not used,
824 -- used only to save initial cursor)
826 -- (PC_R_Remove entry, "cursor" value is (negative)
827 -- saved base value for the enclosing region)
829 -- (stack entries made by matching P)
831 -- (PC_Region_Replace entry, "cursor" value is (negative)
832 -- stack pointer value referencing the PC_R_Remove entry).
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.
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.
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.
857 ----------------------
858 -- Assign Immediate --
859 ----------------------
861 -- Immediate assignment (P * V) constructs the following structure
863 -- +---+ +---+ +---+
864 -- | E |---->| P |---->| A |---->
865 -- +---+ +---+ +---+
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.
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:
878 -- (stack entries made before assign pattern)
880 -- (Special entry, node field not used,
881 -- used only to save initial cursor)
883 -- (PC_R_Remove entry, "cursor" value is (negative) <-- Stack Base
884 -- saved base value for the enclosing region)
886 -- (stack entries made by matching P)
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.
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:
902 -- (stack entries made before assign pattern)
904 -- (Special entry, node field not used,
905 -- used only to save initial cursor)
907 -- (PC_R_Remove entry, "cursor" value is (negative)
908 -- saved base value for the enclosing region)
910 -- (stack entries made by matching P)
912 -- (PC_Region_Replace entry, "cursor" value is the (negative)
913 -- stack pointer value referencing the PC_R_Remove entry).
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.
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.
923 ---------------------
924 -- Assign On Match --
925 ---------------------
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:
931 -- +---+ +---+ +---+
932 -- | E |---->| P |---->| A |---->
933 -- +---+ +---+ +---+
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.
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.
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.
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:
954 -- (stack entries made before assign pattern)
956 -- (Special entry, node points to copy of
957 -- the PC_Assign_OnM node, and the
958 -- cursor field saves the initial cursor).
960 -- (PC_R_Remove entry, "cursor" value is (negative)
961 -- saved base value for the enclosing region)
963 -- (stack entries made by matching P)
965 -- (PC_Assign entry, saves final cursor)
967 -- (PC_Region_Replace entry, "cursor" value is (negative)
968 -- stack pointer value referencing the PC_R_Remove entry).
970 -- If a subsequent failure causes the PC_Assign node to execute it
971 -- simply removes itself and propagates the failure.
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).
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.
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.
988 ---------
989 -- Bal --
990 ---------
992 -- Bal builds a single node:
994 -- +---+
995 -- | B |---->
996 -- +---+
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.
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).
1007 ------------
1008 -- BreakX --
1009 ------------
1011 -- BreakX builds the structure
1013 -- +---+ +---+
1014 -- | B |---->| A |---->
1015 -- +---+ +---+
1016 -- ^ .
1017 -- | .
1018 -- | +---+
1019 -- +<------| X |
1020 -- +---+
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.
1028 -- The B node is numbered 3, the alternative node is 1, and the X
1029 -- node is 2.
1031 -----------
1032 -- Fence --
1033 -----------
1035 -- Fence builds a single node:
1037 -- +---+
1038 -- | F |---->
1039 -- +---+
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.
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).
1047 --------------------
1048 -- Fence Function --
1049 --------------------
1051 -- A call to the Fence function builds the structure:
1053 -- +---+ +---+ +---+
1054 -- | E |---->| P |---->| X |---->
1055 -- +---+ +---+ +---+
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).
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:
1069 -- (stack entries made before fence pattern)
1071 -- (Special entry, not used at all)
1073 -- (PC_R_Remove entry, "cursor" value is (negative) <-- Stack Base
1074 -- saved base value for the enclosing region)
1076 -- (stack entries made by matching P)
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.
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.
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:
1095 -- (stack entries made before assign pattern)
1097 -- (Special entry, not used at all)
1099 -- (PC_R_Remove entry, "cursor" value is (negative)
1100 -- saved base value for the enclosing region)
1102 -- (stack entries made by matching P)
1104 -- (PC_Fence_Y entry, "cursor" value is (negative) stack
1105 -- pointer value referencing the PC_R_Remove entry).
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.
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.
1115 -------------
1116 -- Succeed --
1117 -------------
1119 -- Succeed builds a single node:
1121 -- +---+
1122 -- | S |---->
1123 -- +---+
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.
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).
1132 ---------------------
1133 -- Write Immediate --
1134 ---------------------
1136 -- The structure built for a write immediate operation (P * F, where
1137 -- F is a file access value) is:
1139 -- +---+ +---+ +---+
1140 -- | E |---->| P |---->| W |---->
1141 -- +---+ +---+ +---+
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.
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.
1152 --------------------
1153 -- Write On Match --
1154 --------------------
1156 -- The structure built for a write on match operation (P ** F, where
1157 -- F is a file access value) is:
1159 -- +---+ +---+ +---+
1160 -- | E |---->| P |---->| W |---->
1161 -- +---+ +---+ +---+
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.
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 -----------------------
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
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);
1186 -----------------------
1187 -- Local Subprograms --
1188 -----------------------
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).
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.
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).
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.
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.
1225 function C_To_PE (C : PChar) return PE_Ptr;
1226 -- Given a character, constructs a pattern element that matches
1227 -- the single character.
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.
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));
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
1242 procedure Logic_Error;
1243 -- Called to raise Program_Error with an appropriate message if an
1244 -- internal logic error is detected.
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)
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.
1261 function S_To_PE (Str : PString) return PE_Ptr;
1262 -- Given a string, constructs a pattern element that matches the string
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.
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.
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.
1287 -- Pat_P Points to initial pattern element of pattern to be matched
1289 -- Pat_S Maximum required stack entries for pattern to be matched
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.
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.
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.
1310 ---------
1311 -- "&" --
1312 ---------
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 "&";
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 "&";
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 "&";
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 "&";
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 "&";
1339 ---------
1340 -- "*" --
1341 ---------
1343 -- Assign immediate
1345 -- +---+ +---+ +---+
1346 -- | E |---->| P |---->| A |---->
1347 -- +---+ +---+ +---+
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.
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 "*";
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 "*";
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 "*";
1380 -- Write immediate
1382 -- +---+ +---+ +---+
1383 -- | E |---->| P |---->| W |---->
1384 -- +---+ +---+ +---+
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.
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 "*";
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 "*";
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 "*";
1414 ----------
1415 -- "**" --
1416 ----------
1418 -- Assign on match
1420 -- +---+ +---+ +---+
1421 -- | E |---->| P |---->| A |---->
1422 -- +---+ +---+ +---+
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.
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 "**";
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 "**";
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 "**";
1455 -- Write on match
1457 -- +---+ +---+ +---+
1458 -- | E |---->| P |---->| W |---->
1459 -- +---+ +---+ +---+
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.
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 "**";
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 "**";
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 "**";
1489 ---------
1490 -- "+" --
1491 ---------
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 "+";
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 "+";
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 "+";
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 "+";
1517 ----------
1518 -- "or" --
1519 ----------
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";
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";
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";
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";
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";
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";
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";
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";
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";
1567 ------------
1568 -- Adjust --
1569 ------------
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.
1575 procedure Adjust (Object : in out Pattern) is
1576 begin
1577 Object.P := Copy (Object.P);
1578 end Adjust;
1580 ---------------
1581 -- Alternate --
1582 ---------------
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.
1589 if L = EOP then
1590 return new PE'(PC_Alt, R.Index + 1, EOP, R);
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.
1596 else
1597 declare
1598 Refs : Ref_Array (1 .. L.Index);
1600 begin
1601 Build_Ref_Array (L, Refs);
1603 for J in Refs'Range loop
1604 Refs (J).Index := Refs (J).Index + R.Index;
1605 end loop;
1606 end;
1608 return new PE'(PC_Alt, L.Index + 1, L, R);
1609 end if;
1610 end Alternate;
1612 ---------
1613 -- Any --
1614 ---------
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;
1621 function Any (Str : VString) return Pattern is
1622 begin
1623 return Any (S (Str));
1624 end Any;
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;
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;
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;
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;
1646 ---------
1647 -- Arb --
1648 ---------
1650 -- +---+
1651 -- | X |---->
1652 -- +---+
1653 -- .
1654 -- .
1655 -- +---+
1656 -- | Y |---->
1657 -- +---+
1659 -- The PC_Arb_X element is numbered 2, and the PC_Arb_Y element is 1
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;
1668 -----------
1669 -- Arbno --
1670 -----------
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;
1681 function Arbno (P : PChar) return Pattern is
1682 begin
1683 return (AFC with 0, Arbno_Simple (C_To_PE (P)));
1684 end Arbno;
1686 function Arbno (P : Pattern) return Pattern is
1687 Pat : constant PE_Ptr := Copy (P.P);
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;
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).
1700 -- +--------------------------+
1701 -- | ^
1702 -- V |
1703 -- +---+ |
1704 -- | X |----> |
1705 -- +---+ |
1706 -- . |
1707 -- . |
1708 -- +---+ +---+ +---+ |
1709 -- | E |---->| P |---->| Y |--->+
1710 -- +---+ +---+ +---+
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.
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;
1728 ------------------
1729 -- Arbno_Simple --
1730 ------------------
1732 -- +-------------+
1733 -- | ^
1734 -- V |
1735 -- +---+ |
1736 -- | S |----> |
1737 -- +---+ |
1738 -- . |
1739 -- . |
1740 -- +---+ |
1741 -- | P |---------->+
1742 -- +---+
1744 -- The node numbering of the constituent pattern P is not affected.
1745 -- The S node has a node number of P.Index + 1.
1747 -- Note that we know that P cannot be EOP, because a null pattern
1748 -- does not meet the requirements for simple Arbno.
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;
1757 ---------
1758 -- Bal --
1759 ---------
1761 function Bal return Pattern is
1762 begin
1763 return (AFC with 1, new PE'(PC_Bal, 1, EOP));
1764 end Bal;
1766 -------------
1767 -- Bracket --
1768 -------------
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;
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;
1784 return E;
1785 end Bracket;
1787 -----------
1788 -- Break --
1789 -----------
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;
1796 function Break (Str : VString) return Pattern is
1797 begin
1798 return Break (S (Str));
1799 end Break;
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;
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;
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;
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;
1822 ------------
1823 -- BreakX --
1824 ------------
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;
1831 function BreakX (Str : VString) return Pattern is
1832 begin
1833 return BreakX (S (Str));
1834 end BreakX;
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;
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;
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;
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;
1856 -----------------
1857 -- BreakX_Make --
1858 -----------------
1860 -- +---+ +---+
1861 -- | B |---->| A |---->
1862 -- +---+ +---+
1863 -- ^ .
1864 -- | .
1865 -- | +---+
1866 -- +<------| X |
1867 -- +---+
1869 -- The B node is numbered 3, the alternative node is 1, and the X
1870 -- node is 2.
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;
1880 ---------------------
1881 -- Build_Ref_Array --
1882 ---------------------
1884 procedure Build_Ref_Array (E : PE_Ptr; RA : out Ref_Array) is
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.
1890 ---------------
1891 -- Record_PE --
1892 ---------------
1894 procedure Record_PE (E : PE_Ptr) is
1895 begin
1896 PutD (" Record_PE called with PE_Ptr = " & Image (E));
1898 if E = EOP or else RA (E.Index) /= null then
1899 Put_LineD (", nothing to do");
1900 return;
1902 else
1903 Put_LineD (", recording" & IndexT'Image (E.Index));
1904 RA (E.Index) := E;
1905 Record_PE (E.Pthen);
1907 if E.Pcode in PC_Has_Alt then
1908 Record_PE (E.Alt);
1909 end if;
1910 end if;
1911 end Record_PE;
1913 -- Start of processing for Build_Ref_Array
1915 begin
1916 New_LineD;
1917 Put_LineD ("Entering Build_Ref_Array");
1918 Record_PE (E);
1919 New_LineD;
1920 end Build_Ref_Array;
1922 -------------
1923 -- C_To_PE --
1924 -------------
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;
1931 ------------
1932 -- Cancel --
1933 ------------
1935 function Cancel return Pattern is
1936 begin
1937 return (AFC with 0, new PE'(PC_Cancel, 1, EOP));
1938 end Cancel;
1940 ------------
1941 -- Concat --
1942 ------------
1944 -- Concat needs to traverse the left operand performing the following
1945 -- set of fixups:
1947 -- a) Any successor pointers (Pthen fields) that are set to EOP are
1948 -- reset to point to the second operand.
1950 -- b) Any PC_Arbno_Y node has its stack count field incremented
1951 -- by the parameter Incr provided for this purpose.
1953 -- d) Num fields of all pattern elements in the left operand are
1954 -- adjusted to include the elements of the right operand.
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.
1960 function Concat (L, R : PE_Ptr; Incr : Natural) return PE_Ptr is
1961 begin
1962 if L = EOP then
1963 return R;
1965 elsif R = EOP then
1966 return L;
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.
1974 P : PE_Ptr;
1976 begin
1977 Build_Ref_Array (L, Refs);
1979 for J in Refs'Range loop
1980 P := Refs (J);
1982 P.Index := P.Index + R.Index;
1984 if P.Pcode = PC_Arbno_Y then
1985 P.Nat := P.Nat + Incr;
1986 end if;
1988 if P.Pthen = EOP then
1989 P.Pthen := R;
1990 end if;
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;
1998 return L;
1999 end if;
2000 end Concat;
2002 ----------
2003 -- Copy --
2004 ----------
2006 function Copy (P : PE_Ptr) return PE_Ptr is
2007 begin
2008 if P = null then
2009 Uninitialized_Pattern;
2011 else
2012 declare
2013 Refs : Ref_Array (1 .. P.Index);
2014 -- References to elements in P, indexed by Index field
2016 Copy : Ref_Array (1 .. P.Index);
2017 -- Holds copies of elements of P, indexed by Index field
2019 E : PE_Ptr;
2021 begin
2022 Build_Ref_Array (P, Refs);
2024 -- Now copy all nodes
2026 for J in Refs'Range loop
2027 Copy (J) := new PE'(Refs (J).all);
2028 end loop;
2030 -- Adjust all internal references
2032 for J in Copy'Range loop
2033 E := Copy (J);
2035 -- Adjust successor pointer to point to copy
2037 if E.Pthen /= EOP then
2038 E.Pthen := Copy (E.Pthen.Index);
2039 end if;
2041 -- Adjust Alt pointer if there is one to point to copy
2043 if E.Pcode in PC_Has_Alt and then E.Alt /= EOP then
2044 E.Alt := Copy (E.Alt.Index);
2045 end if;
2047 -- Copy referenced string
2049 if E.Pcode = PC_String then
2050 E.Str := new String'(E.Str.all);
2051 end if;
2052 end loop;
2054 return Copy (P.Index);
2055 end;
2056 end if;
2057 end Copy;
2059 ----------
2060 -- Dump --
2061 ----------
2063 procedure Dump (P : Pattern) is
2065 subtype Count is Ada.Text_IO.Count;
2066 Scol : Count;
2067 -- Used to keep track of column in dump output
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.
2073 Cols : Natural := 2;
2074 -- Number of columns used for pattern numbers, minimum is 2
2076 E : PE_Ptr;
2078 procedure Write_Node_Id (E : PE_Ptr);
2079 -- Writes out a string identifying the given pattern element
2081 -------------------
2082 -- Write_Node_Id --
2083 -------------------
2085 procedure Write_Node_Id (E : PE_Ptr) is
2086 begin
2087 if E = EOP then
2088 Put ("EOP");
2090 for J in 4 .. Cols loop
2091 Put (' ');
2092 end loop;
2094 else
2095 declare
2096 Str : String (1 .. Cols);
2097 N : Natural := Natural (E.Index);
2099 begin
2100 Put ("#");
2102 for J in reverse Str'Range loop
2103 Str (J) := Character'Val (48 + N mod 10);
2104 N := N / 10;
2105 end loop;
2107 Put (Str);
2108 end;
2109 end if;
2110 end Write_Node_Id;
2112 -- Start of processing for Dump
2114 begin
2115 New_Line;
2116 Put ("Pattern Dump Output (pattern at " &
2117 Image (P'Address) &
2118 ", S = " & Natural'Image (P.Stk) & ')');
2120 Scol := Col;
2121 New_Line;
2123 while Col < Scol loop
2124 Put ('-');
2125 end loop;
2127 New_Line;
2129 -- If uninitialized pattern, dump line and we are done
2131 if P.P = null then
2132 Put_Line ("Uninitialized pattern value");
2133 return;
2134 end if;
2136 -- If null pattern, just dump it and we are all done
2138 if P.P = EOP then
2139 Put_Line ("EOP (null pattern)");
2140 return;
2141 end if;
2143 Build_Ref_Array (P.P, Refs);
2145 -- Set number of columns required for node numbers
2147 while 10 ** Cols - 1 < Integer (P.P.Index) loop
2148 Cols := Cols + 1;
2149 end loop;
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.
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);
2167 case E.Pcode is
2169 when PC_Alt |
2170 PC_Arb_X |
2171 PC_Arbno_S |
2172 PC_Arbno_X =>
2173 Write_Node_Id (E.Alt);
2175 when PC_Rpat =>
2176 Put (Str_PP (E.PP));
2178 when PC_Pred_Func =>
2179 Put (Str_BF (E.BF));
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));
2192 when PC_Write_Imm |
2193 PC_Write_OnM =>
2194 Put (Str_FP (E.FP));
2196 when PC_String =>
2197 Put (Image (E.Str.all));
2199 when PC_String_2 =>
2200 Put (Image (E.Str2));
2202 when PC_String_3 =>
2203 Put (Image (E.Str3));
2205 when PC_String_4 =>
2206 Put (Image (E.Str4));
2208 when PC_String_5 =>
2209 Put (Image (E.Str5));
2211 when PC_String_6 =>
2212 Put (Image (E.Str6));
2214 when PC_Setcur =>
2215 Put (Str_NP (E.Var));
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 & ''');
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) & '"');
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));
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));
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));
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));
2265 when others => null;
2267 end case;
2269 New_Line;
2270 end loop;
2272 New_Line;
2273 end Dump;
2275 ----------
2276 -- Fail --
2277 ----------
2279 function Fail return Pattern is
2280 begin
2281 return (AFC with 0, new PE'(PC_Fail, 1, EOP));
2282 end Fail;
2284 -----------
2285 -- Fence --
2286 -----------
2288 -- Simple case
2290 function Fence return Pattern is
2291 begin
2292 return (AFC with 1, new PE'(PC_Fence, 1, EOP));
2293 end Fence;
2295 -- Function case
2297 -- +---+ +---+ +---+
2298 -- | E |---->| P |---->| X |---->
2299 -- +---+ +---+ +---+
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.
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;
2313 --------------
2314 -- Finalize --
2315 --------------
2317 procedure Finalize (Object : in out Pattern) is
2319 procedure Free is new Ada.Unchecked_Deallocation (PE, PE_Ptr);
2320 procedure Free is new Ada.Unchecked_Deallocation (String, String_Ptr);
2322 begin
2323 -- Nothing to do if already freed
2325 if Object.P = null then
2326 return;
2328 -- Otherwise we must free all elements
2330 else
2331 declare
2332 Refs : Ref_Array (1 .. Object.P.Index);
2333 -- References to elements in pattern to be finalized
2335 begin
2336 Build_Ref_Array (Object.P, Refs);
2338 for J in Refs'Range loop
2339 if Refs (J).Pcode = PC_String then
2340 Free (Refs (J).Str);
2341 end if;
2343 Free (Refs (J));
2344 end loop;
2346 Object.P := null;
2347 end;
2348 end if;
2349 end Finalize;
2351 -----------
2352 -- Image --
2353 -----------
2355 function Image (P : PE_Ptr) return String is
2356 begin
2357 return Image (To_Address (P));
2358 end Image;
2360 function Image (P : Pattern) return String is
2361 begin
2362 return S (Image (P));
2363 end Image;
2365 function Image (P : Pattern) return VString is
2367 Kill_Ampersand : Boolean := False;
2368 -- Set True to delete next & to be output to Result
2370 Result : VString := Nul;
2371 -- The result is accumulated here, using Append
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.
2377 procedure Delete_Ampersand;
2378 -- Deletes the ampersand at the end of Result
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.
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.
2391 ----------------------
2392 -- Delete_Ampersand --
2393 ----------------------
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;
2403 ---------------
2404 -- Image_One --
2405 ---------------
2407 procedure Image_One (E : in out PE_Ptr) is
2409 ER : PE_Ptr := E.Pthen;
2410 -- Successor set as result in E unless reset
2412 begin
2413 case E.Pcode is
2415 when PC_Cancel =>
2416 Append (Result, "Cancel");
2418 when PC_Alt => Alt : declare
2420 Elmts_In_L : constant IndexT := E.Pthen.Index - E.Alt.Index;
2421 -- Number of elements in left pattern of alternation
2423 Lowest_In_L : constant IndexT := E.Index - Elmts_In_L;
2424 -- Number of lowest index in elements of left pattern
2426 E1 : PE_Ptr;
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.
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;
2440 Append (Result, '(');
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;
2450 Image_Seq (E1, ER, False);
2451 Append (Result, ')');
2452 end Alt;
2454 when PC_Any_CS =>
2455 Append (Result, "Any (" & Image (To_Sequence (E.CS)) & ')');
2457 when PC_Any_VF =>
2458 Append (Result, "Any (" & Str_VF (E.VF) & ')');
2460 when PC_Any_VP =>
2461 Append (Result, "Any (" & Str_VP (E.VP) & ')');
2463 when PC_Arb_X =>
2464 Append (Result, "Arb");
2466 when PC_Arbno_S =>
2467 Append (Result, "Arbno (");
2468 Image_Seq (E.Alt, E, False);
2469 Append (Result, ')');
2471 when PC_Arbno_X =>
2472 Append (Result, "Arbno (");
2473 Image_Seq (E.Alt.Pthen, Refs (E.Index - 2), False);
2474 Append (Result, ')');
2476 when PC_Assign_Imm =>
2477 Delete_Ampersand;
2478 Append (Result, "* " & Str_VP (Refs (E.Index).VP));
2480 when PC_Assign_OnM =>
2481 Delete_Ampersand;
2482 Append (Result, "** " & Str_VP (Refs (E.Index).VP));
2484 when PC_Any_CH =>
2485 Append (Result, "Any ('" & E.Char & "')");
2487 when PC_Bal =>
2488 Append (Result, "Bal");
2490 when PC_Break_CH =>
2491 Append (Result, "Break ('" & E.Char & "')");
2493 when PC_Break_CS =>
2494 Append (Result, "Break (" & Image (To_Sequence (E.CS)) & ')');
2496 when PC_Break_VF =>
2497 Append (Result, "Break (" & Str_VF (E.VF) & ')');
2499 when PC_Break_VP =>
2500 Append (Result, "Break (" & Str_VP (E.VP) & ')');
2502 when PC_BreakX_CH =>
2503 Append (Result, "BreakX ('" & E.Char & "')");
2504 ER := ER.Pthen;
2506 when PC_BreakX_CS =>
2507 Append (Result, "BreakX (" & Image (To_Sequence (E.CS)) & ')');
2508 ER := ER.Pthen;
2510 when PC_BreakX_VF =>
2511 Append (Result, "BreakX (" & Str_VF (E.VF) & ')');
2512 ER := ER.Pthen;
2514 when PC_BreakX_VP =>
2515 Append (Result, "BreakX (" & Str_VP (E.VP) & ')');
2516 ER := ER.Pthen;
2518 when PC_Char =>
2519 Append (Result, ''' & E.Char & ''');
2521 when PC_Fail =>
2522 Append (Result, "Fail");
2524 when PC_Fence =>
2525 Append (Result, "Fence");
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;
2533 when PC_Len_Nat =>
2534 Append (Result, "Len (" & E.Nat & ')');
2536 when PC_Len_NF =>
2537 Append (Result, "Len (" & Str_NF (E.NF) & ')');
2539 when PC_Len_NP =>
2540 Append (Result, "Len (" & Str_NP (E.NP) & ')');
2542 when PC_NotAny_CH =>
2543 Append (Result, "NotAny ('" & E.Char & "')");
2545 when PC_NotAny_CS =>
2546 Append (Result, "NotAny (" & Image (To_Sequence (E.CS)) & ')');
2548 when PC_NotAny_VF =>
2549 Append (Result, "NotAny (" & Str_VF (E.VF) & ')');
2551 when PC_NotAny_VP =>
2552 Append (Result, "NotAny (" & Str_VP (E.VP) & ')');
2554 when PC_NSpan_CH =>
2555 Append (Result, "NSpan ('" & E.Char & "')");
2557 when PC_NSpan_CS =>
2558 Append (Result, "NSpan (" & Image (To_Sequence (E.CS)) & ')');
2560 when PC_NSpan_VF =>
2561 Append (Result, "NSpan (" & Str_VF (E.VF) & ')');
2563 when PC_NSpan_VP =>
2564 Append (Result, "NSpan (" & Str_VP (E.VP) & ')');
2566 when PC_Null =>
2567 Append (Result, """""");
2569 when PC_Pos_Nat =>
2570 Append (Result, "Pos (" & E.Nat & ')');
2572 when PC_Pos_NF =>
2573 Append (Result, "Pos (" & Str_NF (E.NF) & ')');
2575 when PC_Pos_NP =>
2576 Append (Result, "Pos (" & Str_NP (E.NP) & ')');
2578 when PC_R_Enter =>
2579 Kill_Ampersand := True;
2581 when PC_Rest =>
2582 Append (Result, "Rest");
2584 when PC_Rpat =>
2585 Append (Result, "(+ " & Str_PP (E.PP) & ')');
2587 when PC_Pred_Func =>
2588 Append (Result, "(+ " & Str_BF (E.BF) & ')');
2590 when PC_RPos_Nat =>
2591 Append (Result, "RPos (" & E.Nat & ')');
2593 when PC_RPos_NF =>
2594 Append (Result, "RPos (" & Str_NF (E.NF) & ')');
2596 when PC_RPos_NP =>
2597 Append (Result, "RPos (" & Str_NP (E.NP) & ')');
2599 when PC_RTab_Nat =>
2600 Append (Result, "RTab (" & E.Nat & ')');
2602 when PC_RTab_NF =>
2603 Append (Result, "RTab (" & Str_NF (E.NF) & ')');
2605 when PC_RTab_NP =>
2606 Append (Result, "RTab (" & Str_NP (E.NP) & ')');
2608 when PC_Setcur =>
2609 Append (Result, "Setcur (" & Str_NP (E.Var) & ')');
2611 when PC_Span_CH =>
2612 Append (Result, "Span ('" & E.Char & "')");
2614 when PC_Span_CS =>
2615 Append (Result, "Span (" & Image (To_Sequence (E.CS)) & ')');
2617 when PC_Span_VF =>
2618 Append (Result, "Span (" & Str_VF (E.VF) & ')');
2620 when PC_Span_VP =>
2621 Append (Result, "Span (" & Str_VP (E.VP) & ')');
2623 when PC_String =>
2624 Append (Result, Image (E.Str.all));
2626 when PC_String_2 =>
2627 Append (Result, Image (E.Str2));
2629 when PC_String_3 =>
2630 Append (Result, Image (E.Str3));
2632 when PC_String_4 =>
2633 Append (Result, Image (E.Str4));
2635 when PC_String_5 =>
2636 Append (Result, Image (E.Str5));
2638 when PC_String_6 =>
2639 Append (Result, Image (E.Str6));
2641 when PC_String_VF =>
2642 Append (Result, "(+" & Str_VF (E.VF) & ')');
2644 when PC_String_VP =>
2645 Append (Result, "(+" & Str_VP (E.VP) & ')');
2647 when PC_Succeed =>
2648 Append (Result, "Succeed");
2650 when PC_Tab_Nat =>
2651 Append (Result, "Tab (" & E.Nat & ')');
2653 when PC_Tab_NF =>
2654 Append (Result, "Tab (" & Str_NF (E.NF) & ')');
2656 when PC_Tab_NP =>
2657 Append (Result, "Tab (" & Str_NP (E.NP) & ')');
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;
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;
2671 -- Other pattern codes should not appear as leading elements
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, "???");
2684 end case;
2686 E := ER;
2687 end Image_One;
2689 ---------------
2690 -- Image_Seq --
2691 ---------------
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;
2698 begin
2699 -- The image of EOP is "" (the null string)
2701 if E = EOP then
2702 Append (Result, """""");
2704 -- Else generate appropriate concatenation sequence
2706 else
2707 loop
2708 Image_One (E1);
2709 exit when E1 = Succ;
2710 exit when E1 = EOP;
2711 Mult := True;
2713 if Kill_Ampersand then
2714 Kill_Ampersand := False;
2715 else
2716 Append (Result, " & ");
2717 end if;
2718 end loop;
2719 end if;
2721 if Mult and Paren then
2722 Insert (Result, Indx + 1, "(");
2723 Append (Result, ")");
2724 end if;
2725 end Image_Seq;
2727 -- Start of processing for Image
2729 begin
2730 Build_Ref_Array (P.P, Refs);
2731 Image_Seq (P.P, EOP, False);
2732 return Result;
2733 end Image;
2735 -----------
2736 -- Is_In --
2737 -----------
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;
2747 return False;
2748 end Is_In;
2750 ---------
2751 -- Len --
2752 ---------
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).
2760 if Count = 0 then
2761 return (AFC with 0, new PE'(PC_Null, 1, EOP));
2763 else
2764 return (AFC with 0, new PE'(PC_Len_Nat, 1, EOP, Count));
2765 end if;
2766 end Len;
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;
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;
2778 -----------------
2779 -- Logic_Error --
2780 -----------------
2782 procedure Logic_Error is
2783 begin
2784 raise Program_Error with
2785 "Internal logic error in GNAT.Spitbol.Patterns";
2786 end Logic_Error;
2788 -----------
2789 -- Match --
2790 -----------
2792 function Match
2793 (Subject : VString;
2794 Pat : Pattern) return Boolean
2796 S : Big_String_Access;
2797 L : Natural;
2798 Start : Natural;
2799 Stop : Natural;
2800 pragma Unreferenced (Stop);
2802 begin
2803 Get_String (Subject, S, L);
2805 if Debug_Mode then
2806 XMatchD (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2807 else
2808 XMatch (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2809 end if;
2811 return Start /= 0;
2812 end Match;
2814 function Match
2815 (Subject : String;
2816 Pat : Pattern) return Boolean
2818 Start, Stop : Natural;
2819 pragma Unreferenced (Stop);
2821 subtype String1 is String (1 .. Subject'Length);
2823 begin
2824 if Debug_Mode then
2825 XMatchD (String1 (Subject), Pat.P, Pat.Stk, Start, Stop);
2826 else
2827 XMatch (String1 (Subject), Pat.P, Pat.Stk, Start, Stop);
2828 end if;
2830 return Start /= 0;
2831 end Match;
2833 function Match
2834 (Subject : VString_Var;
2835 Pat : Pattern;
2836 Replace : VString) return Boolean
2838 Start : Natural;
2839 Stop : Natural;
2840 S : Big_String_Access;
2841 L : Natural;
2843 begin
2844 Get_String (Subject, S, L);
2846 if Debug_Mode then
2847 XMatchD (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2848 else
2849 XMatch (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2850 end if;
2852 if Start = 0 then
2853 return False;
2854 else
2855 Get_String (Replace, S, L);
2856 Replace_Slice
2857 (Subject'Unrestricted_Access.all, Start, Stop, S (1 .. L));
2858 return True;
2859 end if;
2860 end Match;
2862 function Match
2863 (Subject : VString_Var;
2864 Pat : Pattern;
2865 Replace : String) return Boolean
2867 Start : Natural;
2868 Stop : Natural;
2869 S : Big_String_Access;
2870 L : Natural;
2872 begin
2873 Get_String (Subject, S, L);
2875 if Debug_Mode then
2876 XMatchD (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2877 else
2878 XMatch (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2879 end if;
2881 if Start = 0 then
2882 return False;
2883 else
2884 Replace_Slice
2885 (Subject'Unrestricted_Access.all, Start, Stop, Replace);
2886 return True;
2887 end if;
2888 end Match;
2890 procedure Match
2891 (Subject : VString;
2892 Pat : Pattern)
2894 S : Big_String_Access;
2895 L : Natural;
2897 Start : Natural;
2898 Stop : Natural;
2899 pragma Unreferenced (Start, Stop);
2901 begin
2902 Get_String (Subject, S, L);
2904 if Debug_Mode then
2905 XMatchD (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2906 else
2907 XMatch (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2908 end if;
2909 end Match;
2911 procedure Match
2912 (Subject : String;
2913 Pat : Pattern)
2915 Start, Stop : Natural;
2916 pragma Unreferenced (Start, Stop);
2918 subtype String1 is String (1 .. Subject'Length);
2920 begin
2921 if Debug_Mode then
2922 XMatchD (String1 (Subject), Pat.P, Pat.Stk, Start, Stop);
2923 else
2924 XMatch (String1 (Subject), Pat.P, Pat.Stk, Start, Stop);
2925 end if;
2926 end Match;
2928 procedure Match
2929 (Subject : in out VString;
2930 Pat : Pattern;
2931 Replace : VString)
2933 Start : Natural;
2934 Stop : Natural;
2935 S : Big_String_Access;
2936 L : Natural;
2938 begin
2939 Get_String (Subject, S, L);
2941 if Debug_Mode then
2942 XMatchD (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2943 else
2944 XMatch (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2945 end if;
2947 if Start /= 0 then
2948 Get_String (Replace, S, L);
2949 Replace_Slice (Subject, Start, Stop, S (1 .. L));
2950 end if;
2951 end Match;
2953 procedure Match
2954 (Subject : in out VString;
2955 Pat : Pattern;
2956 Replace : String)
2958 Start : Natural;
2959 Stop : Natural;
2960 S : Big_String_Access;
2961 L : Natural;
2963 begin
2964 Get_String (Subject, S, L);
2966 if Debug_Mode then
2967 XMatchD (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2968 else
2969 XMatch (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
2970 end if;
2972 if Start /= 0 then
2973 Replace_Slice (Subject, Start, Stop, Replace);
2974 end if;
2975 end Match;
2977 function Match
2978 (Subject : VString;
2979 Pat : PString) return Boolean
2981 Pat_Len : constant Natural := Pat'Length;
2982 S : Big_String_Access;
2983 L : Natural;
2985 begin
2986 Get_String (Subject, S, L);
2988 if Anchored_Mode then
2989 if Pat_Len > L then
2990 return False;
2991 else
2992 return Pat = S (1 .. Pat_Len);
2993 end if;
2995 else
2996 for J in 1 .. L - Pat_Len + 1 loop
2997 if Pat = S (J .. J + (Pat_Len - 1)) then
2998 return True;
2999 end if;
3000 end loop;
3002 return False;
3003 end if;
3004 end Match;
3006 function Match
3007 (Subject : String;
3008 Pat : PString) return Boolean
3010 Pat_Len : constant Natural := Pat'Length;
3011 Sub_Len : constant Natural := Subject'Length;
3012 SFirst : constant Natural := Subject'First;
3014 begin
3015 if Anchored_Mode then
3016 if Pat_Len > Sub_Len then
3017 return False;
3018 else
3019 return Pat = Subject (SFirst .. SFirst + Pat_Len - 1);
3020 end if;
3022 else
3023 for J in SFirst .. SFirst + Sub_Len - Pat_Len loop
3024 if Pat = Subject (J .. J + (Pat_Len - 1)) then
3025 return True;
3026 end if;
3027 end loop;
3029 return False;
3030 end if;
3031 end Match;
3033 function Match
3034 (Subject : VString_Var;
3035 Pat : PString;
3036 Replace : VString) return Boolean
3038 Start : Natural;
3039 Stop : Natural;
3040 S : Big_String_Access;
3041 L : Natural;
3043 begin
3044 Get_String (Subject, S, L);
3046 if Debug_Mode then
3047 XMatchD (S (1 .. L), S_To_PE (Pat), 0, Start, Stop);
3048 else
3049 XMatch (S (1 .. L), S_To_PE (Pat), 0, Start, Stop);
3050 end if;
3052 if Start = 0 then
3053 return False;
3054 else
3055 Get_String (Replace, S, L);
3056 Replace_Slice
3057 (Subject'Unrestricted_Access.all, Start, Stop, S (1 .. L));
3058 return True;
3059 end if;
3060 end Match;
3062 function Match
3063 (Subject : VString_Var;
3064 Pat : PString;
3065 Replace : String) return Boolean
3067 Start : Natural;
3068 Stop : Natural;
3069 S : Big_String_Access;
3070 L : Natural;
3072 begin
3073 Get_String (Subject, S, L);
3075 if Debug_Mode then
3076 XMatchD (S (1 .. L), S_To_PE (Pat), 0, Start, Stop);
3077 else
3078 XMatch (S (1 .. L), S_To_PE (Pat), 0, Start, Stop);
3079 end if;
3081 if Start = 0 then
3082 return False;
3083 else
3084 Replace_Slice
3085 (Subject'Unrestricted_Access.all, Start, Stop, Replace);
3086 return True;
3087 end if;
3088 end Match;
3090 procedure Match
3091 (Subject : VString;
3092 Pat : PString)
3094 S : Big_String_Access;
3095 L : Natural;
3097 Start : Natural;
3098 Stop : Natural;
3099 pragma Unreferenced (Start, Stop);
3101 begin
3102 Get_String (Subject, S, L);
3104 if Debug_Mode then
3105 XMatchD (S (1 .. L), S_To_PE (Pat), 0, Start, Stop);
3106 else
3107 XMatch (S (1 .. L), S_To_PE (Pat), 0, Start, Stop);
3108 end if;
3109 end Match;
3111 procedure Match
3112 (Subject : String;
3113 Pat : PString)
3115 Start, Stop : Natural;
3116 pragma Unreferenced (Start, Stop);
3118 subtype String1 is String (1 .. Subject'Length);
3120 begin
3121 if Debug_Mode then
3122 XMatchD (String1 (Subject), S_To_PE (Pat), 0, Start, Stop);
3123 else
3124 XMatch (String1 (Subject), S_To_PE (Pat), 0, Start, Stop);
3125 end if;
3126 end Match;
3128 procedure Match
3129 (Subject : in out VString;
3130 Pat : PString;
3131 Replace : VString)
3133 Start : Natural;
3134 Stop : Natural;
3135 S : Big_String_Access;
3136 L : Natural;
3138 begin
3139 Get_String (Subject, S, L);
3141 if Debug_Mode then
3142 XMatchD (S (1 .. L), S_To_PE (Pat), 0, Start, Stop);
3143 else
3144 XMatch (S (1 .. L), S_To_PE (Pat), 0, Start, Stop);
3145 end if;
3147 if Start /= 0 then
3148 Get_String (Replace, S, L);
3149 Replace_Slice (Subject, Start, Stop, S (1 .. L));
3150 end if;
3151 end Match;
3153 procedure Match
3154 (Subject : in out VString;
3155 Pat : PString;
3156 Replace : String)
3158 Start : Natural;
3159 Stop : Natural;
3160 S : Big_String_Access;
3161 L : Natural;
3163 begin
3164 Get_String (Subject, S, L);
3166 if Debug_Mode then
3167 XMatchD (S (1 .. L), S_To_PE (Pat), 0, Start, Stop);
3168 else
3169 XMatch (S (1 .. L), S_To_PE (Pat), 0, Start, Stop);
3170 end if;
3172 if Start /= 0 then
3173 Replace_Slice (Subject, Start, Stop, Replace);
3174 end if;
3175 end Match;
3177 function Match
3178 (Subject : VString_Var;
3179 Pat : Pattern;
3180 Result : Match_Result_Var) return Boolean
3182 Start : Natural;
3183 Stop : Natural;
3184 S : Big_String_Access;
3185 L : Natural;
3187 begin
3188 Get_String (Subject, S, L);
3190 if Debug_Mode then
3191 XMatchD (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
3192 else
3193 XMatch (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
3194 end if;
3196 if Start = 0 then
3197 Result'Unrestricted_Access.all.Var := null;
3198 return False;
3200 else
3201 Result'Unrestricted_Access.all.Var := Subject'Unrestricted_Access;
3202 Result'Unrestricted_Access.all.Start := Start;
3203 Result'Unrestricted_Access.all.Stop := Stop;
3204 return True;
3205 end if;
3206 end Match;
3208 procedure Match
3209 (Subject : in out VString;
3210 Pat : Pattern;
3211 Result : out Match_Result)
3213 Start : Natural;
3214 Stop : Natural;
3215 S : Big_String_Access;
3216 L : Natural;
3218 begin
3219 Get_String (Subject, S, L);
3221 if Debug_Mode then
3222 XMatchD (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
3223 else
3224 XMatch (S (1 .. L), Pat.P, Pat.Stk, Start, Stop);
3225 end if;
3227 if Start = 0 then
3228 Result.Var := null;
3229 else
3230 Result.Var := Subject'Unrestricted_Access;
3231 Result.Start := Start;
3232 Result.Stop := Stop;
3233 end if;
3234 end Match;
3236 ---------------
3237 -- New_LineD --
3238 ---------------
3240 procedure New_LineD is
3241 begin
3242 if Internal_Debug then
3243 New_Line;
3244 end if;
3245 end New_LineD;
3247 ------------
3248 -- NotAny --
3249 ------------
3251 function NotAny (Str : String) return Pattern is
3252 begin
3253 return (AFC with 0, new PE'(PC_NotAny_CS, 1, EOP, To_Set (Str)));
3254 end NotAny;
3256 function NotAny (Str : VString) return Pattern is
3257 begin
3258 return NotAny (S (Str));
3259 end NotAny;
3261 function NotAny (Str : Character) return Pattern is
3262 begin
3263 return (AFC with 0, new PE'(PC_NotAny_CH, 1, EOP, Str));
3264 end NotAny;
3266 function NotAny (Str : Character_Set) return Pattern is
3267 begin
3268 return (AFC with 0, new PE'(PC_NotAny_CS, 1, EOP, Str));
3269 end NotAny;
3271 function NotAny (Str : not null access VString) return Pattern is
3272 begin
3273 return (AFC with 0, new PE'(PC_NotAny_VP, 1, EOP, VString_Ptr (Str)));
3274 end NotAny;
3276 function NotAny (Str : VString_Func) return Pattern is
3277 begin
3278 return (AFC with 0, new PE'(PC_NotAny_VF, 1, EOP, Str));
3279 end NotAny;
3281 -----------
3282 -- NSpan --
3283 -----------
3285 function NSpan (Str : String) return Pattern is
3286 begin
3287 return (AFC with 0, new PE'(PC_NSpan_CS, 1, EOP, To_Set (Str)));
3288 end NSpan;
3290 function NSpan (Str : VString) return Pattern is
3291 begin
3292 return NSpan (S (Str));
3293 end NSpan;
3295 function NSpan (Str : Character) return Pattern is
3296 begin
3297 return (AFC with 0, new PE'(PC_NSpan_CH, 1, EOP, Str));
3298 end NSpan;
3300 function NSpan (Str : Character_Set) return Pattern is
3301 begin
3302 return (AFC with 0, new PE'(PC_NSpan_CS, 1, EOP, Str));
3303 end NSpan;
3305 function NSpan (Str : not null access VString) return Pattern is
3306 begin
3307 return (AFC with 0, new PE'(PC_NSpan_VP, 1, EOP, VString_Ptr (Str)));
3308 end NSpan;
3310 function NSpan (Str : VString_Func) return Pattern is
3311 begin
3312 return (AFC with 0, new PE'(PC_NSpan_VF, 1, EOP, Str));
3313 end NSpan;
3315 ---------
3316 -- Pos --
3317 ---------
3319 function Pos (Count : Natural) return Pattern is
3320 begin
3321 return (AFC with 0, new PE'(PC_Pos_Nat, 1, EOP, Count));
3322 end Pos;
3324 function Pos (Count : Natural_Func) return Pattern is
3325 begin
3326 return (AFC with 0, new PE'(PC_Pos_NF, 1, EOP, Count));
3327 end Pos;
3329 function Pos (Count : not null access Natural) return Pattern is
3330 begin
3331 return (AFC with 0, new PE'(PC_Pos_NP, 1, EOP, Natural_Ptr (Count)));
3332 end Pos;
3334 ----------
3335 -- PutD --
3336 ----------
3338 procedure PutD (Str : String) is
3339 begin
3340 if Internal_Debug then
3341 Put (Str);
3342 end if;
3343 end PutD;
3345 ---------------
3346 -- Put_LineD --
3347 ---------------
3349 procedure Put_LineD (Str : String) is
3350 begin
3351 if Internal_Debug then
3352 Put_Line (Str);
3353 end if;
3354 end Put_LineD;
3356 -------------
3357 -- Replace --
3358 -------------
3360 procedure Replace
3361 (Result : in out Match_Result;
3362 Replace : VString)
3364 S : Big_String_Access;
3365 L : Natural;
3367 begin
3368 Get_String (Replace, S, L);
3370 if Result.Var /= null then
3371 Replace_Slice (Result.Var.all, Result.Start, Result.Stop, S (1 .. L));
3372 Result.Var := null;
3373 end if;
3374 end Replace;
3376 ----------
3377 -- Rest --
3378 ----------
3380 function Rest return Pattern is
3381 begin
3382 return (AFC with 0, new PE'(PC_Rest, 1, EOP));
3383 end Rest;
3385 ----------
3386 -- Rpos --
3387 ----------
3389 function Rpos (Count : Natural) return Pattern is
3390 begin
3391 return (AFC with 0, new PE'(PC_RPos_Nat, 1, EOP, Count));
3392 end Rpos;
3394 function Rpos (Count : Natural_Func) return Pattern is
3395 begin
3396 return (AFC with 0, new PE'(PC_RPos_NF, 1, EOP, Count));
3397 end Rpos;
3399 function Rpos (Count : not null access Natural) return Pattern is
3400 begin
3401 return (AFC with 0, new PE'(PC_RPos_NP, 1, EOP, Natural_Ptr (Count)));
3402 end Rpos;
3404 ----------
3405 -- Rtab --
3406 ----------
3408 function Rtab (Count : Natural) return Pattern is
3409 begin
3410 return (AFC with 0, new PE'(PC_RTab_Nat, 1, EOP, Count));
3411 end Rtab;
3413 function Rtab (Count : Natural_Func) return Pattern is
3414 begin
3415 return (AFC with 0, new PE'(PC_RTab_NF, 1, EOP, Count));
3416 end Rtab;
3418 function Rtab (Count : not null access Natural) return Pattern is
3419 begin
3420 return (AFC with 0, new PE'(PC_RTab_NP, 1, EOP, Natural_Ptr (Count)));
3421 end Rtab;
3423 -------------
3424 -- S_To_PE --
3425 -------------
3427 function S_To_PE (Str : PString) return PE_Ptr is
3428 Len : constant Natural := Str'Length;
3430 begin
3431 case Len is
3432 when 0 =>
3433 return new PE'(PC_Null, 1, EOP);
3435 when 1 =>
3436 return new PE'(PC_Char, 1, EOP, Str (Str'First));
3438 when 2 =>
3439 return new PE'(PC_String_2, 1, EOP, Str);
3441 when 3 =>
3442 return new PE'(PC_String_3, 1, EOP, Str);
3444 when 4 =>
3445 return new PE'(PC_String_4, 1, EOP, Str);
3447 when 5 =>
3448 return new PE'(PC_String_5, 1, EOP, Str);
3450 when 6 =>
3451 return new PE'(PC_String_6, 1, EOP, Str);
3453 when others =>
3454 return new PE'(PC_String, 1, EOP, new String'(Str));
3456 end case;
3457 end S_To_PE;
3459 -------------------
3460 -- Set_Successor --
3461 -------------------
3463 -- Note: this procedure is not used by the normal concatenation circuit,
3464 -- since other fixups are required on the left operand in this case, and
3465 -- they might as well be done all together.
3467 procedure Set_Successor (Pat : PE_Ptr; Succ : PE_Ptr) is
3468 begin
3469 if Pat = null then
3470 Uninitialized_Pattern;
3472 elsif Pat = EOP then
3473 Logic_Error;
3475 else
3476 declare
3477 Refs : Ref_Array (1 .. Pat.Index);
3478 -- We build a reference array for L whose N'th element points to
3479 -- the pattern element of L whose original Index value is N.
3481 P : PE_Ptr;
3483 begin
3484 Build_Ref_Array (Pat, Refs);
3486 for J in Refs'Range loop
3487 P := Refs (J);
3489 if P.Pthen = EOP then
3490 P.Pthen := Succ;
3491 end if;
3493 if P.Pcode in PC_Has_Alt and then P.Alt = EOP then
3494 P.Alt := Succ;
3495 end if;
3496 end loop;
3497 end;
3498 end if;
3499 end Set_Successor;
3501 ------------
3502 -- Setcur --
3503 ------------
3505 function Setcur (Var : not null access Natural) return Pattern is
3506 begin
3507 return (AFC with 0, new PE'(PC_Setcur, 1, EOP, Natural_Ptr (Var)));
3508 end Setcur;
3510 ----------
3511 -- Span --
3512 ----------
3514 function Span (Str : String) return Pattern is
3515 begin
3516 return (AFC with 0, new PE'(PC_Span_CS, 1, EOP, To_Set (Str)));
3517 end Span;
3519 function Span (Str : VString) return Pattern is
3520 begin
3521 return Span (S (Str));
3522 end Span;
3524 function Span (Str : Character) return Pattern is
3525 begin
3526 return (AFC with 0, new PE'(PC_Span_CH, 1, EOP, Str));
3527 end Span;
3529 function Span (Str : Character_Set) return Pattern is
3530 begin
3531 return (AFC with 0, new PE'(PC_Span_CS, 1, EOP, Str));
3532 end Span;
3534 function Span (Str : not null access VString) return Pattern is
3535 begin
3536 return (AFC with 0, new PE'(PC_Span_VP, 1, EOP, VString_Ptr (Str)));
3537 end Span;
3539 function Span (Str : VString_Func) return Pattern is
3540 begin
3541 return (AFC with 0, new PE'(PC_Span_VF, 1, EOP, Str));
3542 end Span;
3544 ------------
3545 -- Str_BF --
3546 ------------
3548 function Str_BF (A : Boolean_Func) return String is
3549 function To_A is new Ada.Unchecked_Conversion (Boolean_Func, Address);
3550 begin
3551 return "BF(" & Image (To_A (A)) & ')';
3552 end Str_BF;
3554 ------------
3555 -- Str_FP --
3556 ------------
3558 function Str_FP (A : File_Ptr) return String is
3559 begin
3560 return "FP(" & Image (A.all'Address) & ')';
3561 end Str_FP;
3563 ------------
3564 -- Str_NF --
3565 ------------
3567 function Str_NF (A : Natural_Func) return String is
3568 function To_A is new Ada.Unchecked_Conversion (Natural_Func, Address);
3569 begin
3570 return "NF(" & Image (To_A (A)) & ')';
3571 end Str_NF;
3573 ------------
3574 -- Str_NP --
3575 ------------
3577 function Str_NP (A : Natural_Ptr) return String is
3578 begin
3579 return "NP(" & Image (A.all'Address) & ')';
3580 end Str_NP;
3582 ------------
3583 -- Str_PP --
3584 ------------
3586 function Str_PP (A : Pattern_Ptr) return String is
3587 begin
3588 return "PP(" & Image (A.all'Address) & ')';
3589 end Str_PP;
3591 ------------
3592 -- Str_VF --
3593 ------------
3595 function Str_VF (A : VString_Func) return String is
3596 function To_A is new Ada.Unchecked_Conversion (VString_Func, Address);
3597 begin
3598 return "VF(" & Image (To_A (A)) & ')';
3599 end Str_VF;
3601 ------------
3602 -- Str_VP --
3603 ------------
3605 function Str_VP (A : VString_Ptr) return String is
3606 begin
3607 return "VP(" & Image (A.all'Address) & ')';
3608 end Str_VP;
3610 -------------
3611 -- Succeed --
3612 -------------
3614 function Succeed return Pattern is
3615 begin
3616 return (AFC with 1, new PE'(PC_Succeed, 1, EOP));
3617 end Succeed;
3619 ---------
3620 -- Tab --
3621 ---------
3623 function Tab (Count : Natural) return Pattern is
3624 begin
3625 return (AFC with 0, new PE'(PC_Tab_Nat, 1, EOP, Count));
3626 end Tab;
3628 function Tab (Count : Natural_Func) return Pattern is
3629 begin
3630 return (AFC with 0, new PE'(PC_Tab_NF, 1, EOP, Count));
3631 end Tab;
3633 function Tab (Count : not null access Natural) return Pattern is
3634 begin
3635 return (AFC with 0, new PE'(PC_Tab_NP, 1, EOP, Natural_Ptr (Count)));
3636 end Tab;
3638 ---------------------------
3639 -- Uninitialized_Pattern --
3640 ---------------------------
3642 procedure Uninitialized_Pattern is
3643 begin
3644 raise Program_Error with
3645 "uninitialized value of type GNAT.Spitbol.Patterns.Pattern";
3646 end Uninitialized_Pattern;
3648 ------------
3649 -- XMatch --
3650 ------------
3652 procedure XMatch
3653 (Subject : String;
3654 Pat_P : PE_Ptr;
3655 Pat_S : Natural;
3656 Start : out Natural;
3657 Stop : out Natural)
3659 Node : PE_Ptr;
3660 -- Pointer to current pattern node. Initialized from Pat_P, and then
3661 -- updated as the match proceeds through its constituent elements.
3663 Length : constant Natural := Subject'Length;
3664 -- Length of string (= Subject'Last, since Subject'First is always 1)
3666 Cursor : Integer := 0;
3667 -- If the value is non-negative, then this value is the index showing
3668 -- the current position of the match in the subject string. The next
3669 -- character to be matched is at Subject (Cursor + 1). Note that since
3670 -- our view of the subject string in XMatch always has a lower bound
3671 -- of one, regardless of original bounds, that this definition exactly
3672 -- corresponds to the cursor value as referenced by functions like Pos.
3674 -- If the value is negative, then this is a saved stack pointer,
3675 -- typically a base pointer of an inner or outer region. Cursor
3676 -- temporarily holds such a value when it is popped from the stack
3677 -- by Fail. In all cases, Cursor is reset to a proper non-negative
3678 -- cursor value before the match proceeds (e.g. by propagating the
3679 -- failure and popping a "real" cursor value from the stack.
3681 PE_Unanchored : aliased PE := (PC_Unanchored, 0, Pat_P);
3682 -- Dummy pattern element used in the unanchored case
3684 Stack : Stack_Type;
3685 -- The pattern matching failure stack for this call to Match
3687 Stack_Ptr : Stack_Range;
3688 -- Current stack pointer. This points to the top element of the stack
3689 -- that is currently in use. At the outer level this is the special
3690 -- entry placed on the stack according to the anchor mode.
3692 Stack_Init : constant Stack_Range := Stack'First + 1;
3693 -- This is the initial value of the Stack_Ptr and Stack_Base. The
3694 -- initial (Stack'First) element of the stack is not used so that
3695 -- when we pop the last element off, Stack_Ptr is still in range.
3697 Stack_Base : Stack_Range;
3698 -- This value is the stack base value, i.e. the stack pointer for the
3699 -- first history stack entry in the current stack region. See separate
3700 -- section on handling of recursive pattern matches.
3702 Assign_OnM : Boolean := False;
3703 -- Set True if assign-on-match or write-on-match operations may be
3704 -- present in the history stack, which must then be scanned on a
3705 -- successful match.
3707 procedure Pop_Region;
3708 pragma Inline (Pop_Region);
3709 -- Used at the end of processing of an inner region. If the inner
3710 -- region left no stack entries, then all trace of it is removed.
3711 -- Otherwise a PC_Restore_Region entry is pushed to ensure proper
3712 -- handling of alternatives in the inner region.
3714 procedure Push (Node : PE_Ptr);
3715 pragma Inline (Push);
3716 -- Make entry in pattern matching stack with current cursor value
3718 procedure Push_Region;
3719 pragma Inline (Push_Region);
3720 -- This procedure makes a new region on the history stack. The
3721 -- caller first establishes the special entry on the stack, but
3722 -- does not push the stack pointer. Then this call stacks a
3723 -- PC_Remove_Region node, on top of this entry, using the cursor
3724 -- field of the PC_Remove_Region entry to save the outer level
3725 -- stack base value, and resets the stack base to point to this
3726 -- PC_Remove_Region node.
3728 ----------------
3729 -- Pop_Region --
3730 ----------------
3732 procedure Pop_Region is
3733 begin
3734 -- If nothing was pushed in the inner region, we can just get
3735 -- rid of it entirely, leaving no traces that it was ever there
3737 if Stack_Ptr = Stack_Base then
3738 Stack_Ptr := Stack_Base - 2;
3739 Stack_Base := Stack (Stack_Ptr + 2).Cursor;
3741 -- If stuff was pushed in the inner region, then we have to
3742 -- push a PC_R_Restore node so that we properly handle possible
3743 -- rematches within the region.
3745 else
3746 Stack_Ptr := Stack_Ptr + 1;
3747 Stack (Stack_Ptr).Cursor := Stack_Base;
3748 Stack (Stack_Ptr).Node := CP_R_Restore'Access;
3749 Stack_Base := Stack (Stack_Base).Cursor;
3750 end if;
3751 end Pop_Region;
3753 ----------
3754 -- Push --
3755 ----------
3757 procedure Push (Node : PE_Ptr) is
3758 begin
3759 Stack_Ptr := Stack_Ptr + 1;
3760 Stack (Stack_Ptr).Cursor := Cursor;
3761 Stack (Stack_Ptr).Node := Node;
3762 end Push;
3764 -----------------
3765 -- Push_Region --
3766 -----------------
3768 procedure Push_Region is
3769 begin
3770 Stack_Ptr := Stack_Ptr + 2;
3771 Stack (Stack_Ptr).Cursor := Stack_Base;
3772 Stack (Stack_Ptr).Node := CP_R_Remove'Access;
3773 Stack_Base := Stack_Ptr;
3774 end Push_Region;
3776 -- Start of processing for XMatch
3778 begin
3779 if Pat_P = null then
3780 Uninitialized_Pattern;
3781 end if;
3783 -- Check we have enough stack for this pattern. This check deals with
3784 -- every possibility except a match of a recursive pattern, where we
3785 -- make a check at each recursion level.
3787 if Pat_S >= Stack_Size - 1 then
3788 raise Pattern_Stack_Overflow;
3789 end if;
3791 -- In anchored mode, the bottom entry on the stack is an abort entry
3793 if Anchored_Mode then
3794 Stack (Stack_Init).Node := CP_Cancel'Access;
3795 Stack (Stack_Init).Cursor := 0;
3797 -- In unanchored more, the bottom entry on the stack references
3798 -- the special pattern element PE_Unanchored, whose Pthen field
3799 -- points to the initial pattern element. The cursor value in this
3800 -- entry is the number of anchor moves so far.
3802 else
3803 Stack (Stack_Init).Node := PE_Unanchored'Unchecked_Access;
3804 Stack (Stack_Init).Cursor := 0;
3805 end if;
3807 Stack_Ptr := Stack_Init;
3808 Stack_Base := Stack_Ptr;
3809 Cursor := 0;
3810 Node := Pat_P;
3811 goto Match;
3813 -----------------------------------------
3814 -- Main Pattern Matching State Control --
3815 -----------------------------------------
3817 -- This is a state machine which uses gotos to change state. The
3818 -- initial state is Match, to initiate the matching of the first
3819 -- element, so the goto Match above starts the match. In the
3820 -- following descriptions, we indicate the global values that
3821 -- are relevant for the state transition.
3823 -- Come here if entire match fails
3825 <<Match_Fail>>
3826 Start := 0;
3827 Stop := 0;
3828 return;
3830 -- Come here if entire match succeeds
3832 -- Cursor current position in subject string
3834 <<Match_Succeed>>
3835 Start := Stack (Stack_Init).Cursor + 1;
3836 Stop := Cursor;
3838 -- Scan history stack for deferred assignments or writes
3840 if Assign_OnM then
3841 for S in Stack_Init .. Stack_Ptr loop
3842 if Stack (S).Node = CP_Assign'Access then
3843 declare
3844 Inner_Base : constant Stack_Range :=
3845 Stack (S + 1).Cursor;
3846 Special_Entry : constant Stack_Range :=
3847 Inner_Base - 1;
3848 Node_OnM : constant PE_Ptr :=
3849 Stack (Special_Entry).Node;
3850 Start : constant Natural :=
3851 Stack (Special_Entry).Cursor + 1;
3852 Stop : constant Natural := Stack (S).Cursor;
3854 begin
3855 if Node_OnM.Pcode = PC_Assign_OnM then
3856 Set_String (Node_OnM.VP.all, Subject (Start .. Stop));
3858 elsif Node_OnM.Pcode = PC_Write_OnM then
3859 Put_Line (Node_OnM.FP.all, Subject (Start .. Stop));
3861 else
3862 Logic_Error;
3863 end if;
3864 end;
3865 end if;
3866 end loop;
3867 end if;
3869 return;
3871 -- Come here if attempt to match current element fails
3873 -- Stack_Base current stack base
3874 -- Stack_Ptr current stack pointer
3876 <<Fail>>
3877 Cursor := Stack (Stack_Ptr).Cursor;
3878 Node := Stack (Stack_Ptr).Node;
3879 Stack_Ptr := Stack_Ptr - 1;
3880 goto Match;
3882 -- Come here if attempt to match current element succeeds
3884 -- Cursor current position in subject string
3885 -- Node pointer to node successfully matched
3886 -- Stack_Base current stack base
3887 -- Stack_Ptr current stack pointer
3889 <<Succeed>>
3890 Node := Node.Pthen;
3892 -- Come here to match the next pattern element
3894 -- Cursor current position in subject string
3895 -- Node pointer to node to be matched
3896 -- Stack_Base current stack base
3897 -- Stack_Ptr current stack pointer
3899 <<Match>>
3901 --------------------------------------------------
3902 -- Main Pattern Match Element Matching Routines --
3903 --------------------------------------------------
3905 -- Here is the case statement that processes the current node. The
3906 -- processing for each element does one of five things:
3908 -- goto Succeed to move to the successor
3909 -- goto Match_Succeed if the entire match succeeds
3910 -- goto Match_Fail if the entire match fails
3911 -- goto Fail to signal failure of current match
3913 -- Processing is NOT allowed to fall through
3915 case Node.Pcode is
3917 -- Cancel
3919 when PC_Cancel =>
3920 goto Match_Fail;
3922 -- Alternation
3924 when PC_Alt =>
3925 Push (Node.Alt);
3926 Node := Node.Pthen;
3927 goto Match;
3929 -- Any (one character case)
3931 when PC_Any_CH =>
3932 if Cursor < Length
3933 and then Subject (Cursor + 1) = Node.Char
3934 then
3935 Cursor := Cursor + 1;
3936 goto Succeed;
3937 else
3938 goto Fail;
3939 end if;
3941 -- Any (character set case)
3943 when PC_Any_CS =>
3944 if Cursor < Length
3945 and then Is_In (Subject (Cursor + 1), Node.CS)
3946 then
3947 Cursor := Cursor + 1;
3948 goto Succeed;
3949 else
3950 goto Fail;
3951 end if;
3953 -- Any (string function case)
3955 when PC_Any_VF => declare
3956 U : constant VString := Node.VF.all;
3957 S : Big_String_Access;
3958 L : Natural;
3960 begin
3961 Get_String (U, S, L);
3963 if Cursor < Length
3964 and then Is_In (Subject (Cursor + 1), S (1 .. L))
3965 then
3966 Cursor := Cursor + 1;
3967 goto Succeed;
3968 else
3969 goto Fail;
3970 end if;
3971 end;
3973 -- Any (string pointer case)
3975 when PC_Any_VP => declare
3976 U : constant VString := Node.VP.all;
3977 S : Big_String_Access;
3978 L : Natural;
3980 begin
3981 Get_String (U, S, L);
3983 if Cursor < Length
3984 and then Is_In (Subject (Cursor + 1), S (1 .. L))
3985 then
3986 Cursor := Cursor + 1;
3987 goto Succeed;
3988 else
3989 goto Fail;
3990 end if;
3991 end;
3993 -- Arb (initial match)
3995 when PC_Arb_X =>
3996 Push (Node.Alt);
3997 Node := Node.Pthen;
3998 goto Match;
4000 -- Arb (extension)
4002 when PC_Arb_Y =>
4003 if Cursor < Length then
4004 Cursor := Cursor + 1;
4005 Push (Node);
4006 goto Succeed;
4007 else
4008 goto Fail;
4009 end if;
4011 -- Arbno_S (simple Arbno initialize). This is the node that
4012 -- initiates the match of a simple Arbno structure.
4014 when PC_Arbno_S =>
4015 Push (Node.Alt);
4016 Node := Node.Pthen;
4017 goto Match;
4019 -- Arbno_X (Arbno initialize). This is the node that initiates
4020 -- the match of a complex Arbno structure.
4022 when PC_Arbno_X =>
4023 Push (Node.Alt);
4024 Node := Node.Pthen;
4025 goto Match;
4027 -- Arbno_Y (Arbno rematch). This is the node that is executed
4028 -- following successful matching of one instance of a complex
4029 -- Arbno pattern.
4031 when PC_Arbno_Y => declare
4032 Null_Match : constant Boolean :=
4033 Cursor = Stack (Stack_Base - 1).Cursor;
4035 begin
4036 Pop_Region;
4038 -- If arbno extension matched null, then immediately fail
4040 if Null_Match then
4041 goto Fail;
4042 end if;
4044 -- Here we must do a stack check to make sure enough stack
4045 -- is left. This check will happen once for each instance of
4046 -- the Arbno pattern that is matched. The Nat field of a
4047 -- PC_Arbno pattern contains the maximum stack entries needed
4048 -- for the Arbno with one instance and the successor pattern
4050 if Stack_Ptr + Node.Nat >= Stack'Last then
4051 raise Pattern_Stack_Overflow;
4052 end if;
4054 goto Succeed;
4055 end;
4057 -- Assign. If this node is executed, it means the assign-on-match
4058 -- or write-on-match operation will not happen after all, so we
4059 -- is propagate the failure, removing the PC_Assign node.
4061 when PC_Assign =>
4062 goto Fail;
4064 -- Assign immediate. This node performs the actual assignment
4066 when PC_Assign_Imm =>
4067 Set_String
4068 (Node.VP.all,
4069 Subject (Stack (Stack_Base - 1).Cursor + 1 .. Cursor));
4070 Pop_Region;
4071 goto Succeed;
4073 -- Assign on match. This node sets up for the eventual assignment
4075 when PC_Assign_OnM =>
4076 Stack (Stack_Base - 1).Node := Node;
4077 Push (CP_Assign'Access);
4078 Pop_Region;
4079 Assign_OnM := True;
4080 goto Succeed;
4082 -- Bal
4084 when PC_Bal =>
4085 if Cursor >= Length or else Subject (Cursor + 1) = ')' then
4086 goto Fail;
4088 elsif Subject (Cursor + 1) = '(' then
4089 declare
4090 Paren_Count : Natural := 1;
4092 begin
4093 loop
4094 Cursor := Cursor + 1;
4096 if Cursor >= Length then
4097 goto Fail;
4099 elsif Subject (Cursor + 1) = '(' then
4100 Paren_Count := Paren_Count + 1;
4102 elsif Subject (Cursor + 1) = ')' then
4103 Paren_Count := Paren_Count - 1;
4104 exit when Paren_Count = 0;
4105 end if;
4106 end loop;
4107 end;
4108 end if;
4110 Cursor := Cursor + 1;
4111 Push (Node);
4112 goto Succeed;
4114 -- Break (one character case)
4116 when PC_Break_CH =>
4117 while Cursor < Length loop
4118 if Subject (Cursor + 1) = Node.Char then
4119 goto Succeed;
4120 else
4121 Cursor := Cursor + 1;
4122 end if;
4123 end loop;
4125 goto Fail;
4127 -- Break (character set case)
4129 when PC_Break_CS =>
4130 while Cursor < Length loop
4131 if Is_In (Subject (Cursor + 1), Node.CS) then
4132 goto Succeed;
4133 else
4134 Cursor := Cursor + 1;
4135 end if;
4136 end loop;
4138 goto Fail;
4140 -- Break (string function case)
4142 when PC_Break_VF => declare
4143 U : constant VString := Node.VF.all;
4144 S : Big_String_Access;
4145 L : Natural;
4147 begin
4148 Get_String (U, S, L);
4150 while Cursor < Length loop
4151 if Is_In (Subject (Cursor + 1), S (1 .. L)) then
4152 goto Succeed;
4153 else
4154 Cursor := Cursor + 1;
4155 end if;
4156 end loop;
4158 goto Fail;
4159 end;
4161 -- Break (string pointer case)
4163 when PC_Break_VP => declare
4164 U : constant VString := Node.VP.all;
4165 S : Big_String_Access;
4166 L : Natural;
4168 begin
4169 Get_String (U, S, L);
4171 while Cursor < Length loop
4172 if Is_In (Subject (Cursor + 1), S (1 .. L)) then
4173 goto Succeed;
4174 else
4175 Cursor := Cursor + 1;
4176 end if;
4177 end loop;
4179 goto Fail;
4180 end;
4182 -- BreakX (one character case)
4184 when PC_BreakX_CH =>
4185 while Cursor < Length loop
4186 if Subject (Cursor + 1) = Node.Char then
4187 goto Succeed;
4188 else
4189 Cursor := Cursor + 1;
4190 end if;
4191 end loop;
4193 goto Fail;
4195 -- BreakX (character set case)
4197 when PC_BreakX_CS =>
4198 while Cursor < Length loop
4199 if Is_In (Subject (Cursor + 1), Node.CS) then
4200 goto Succeed;
4201 else
4202 Cursor := Cursor + 1;
4203 end if;
4204 end loop;
4206 goto Fail;
4208 -- BreakX (string function case)
4210 when PC_BreakX_VF => declare
4211 U : constant VString := Node.VF.all;
4212 S : Big_String_Access;
4213 L : Natural;
4215 begin
4216 Get_String (U, S, L);
4218 while Cursor < Length loop
4219 if Is_In (Subject (Cursor + 1), S (1 .. L)) then
4220 goto Succeed;
4221 else
4222 Cursor := Cursor + 1;
4223 end if;
4224 end loop;
4226 goto Fail;
4227 end;
4229 -- BreakX (string pointer case)
4231 when PC_BreakX_VP => declare
4232 U : constant VString := Node.VP.all;
4233 S : Big_String_Access;
4234 L : Natural;
4236 begin
4237 Get_String (U, S, L);
4239 while Cursor < Length loop
4240 if Is_In (Subject (Cursor + 1), S (1 .. L)) then
4241 goto Succeed;
4242 else
4243 Cursor := Cursor + 1;
4244 end if;
4245 end loop;
4247 goto Fail;
4248 end;
4250 -- BreakX_X (BreakX extension). See section on "Compound Pattern
4251 -- Structures". This node is the alternative that is stacked to
4252 -- skip past the break character and extend the break.
4254 when PC_BreakX_X =>
4255 Cursor := Cursor + 1;
4256 goto Succeed;
4258 -- Character (one character string)
4260 when PC_Char =>
4261 if Cursor < Length
4262 and then Subject (Cursor + 1) = Node.Char
4263 then
4264 Cursor := Cursor + 1;
4265 goto Succeed;
4266 else
4267 goto Fail;
4268 end if;
4270 -- End of Pattern
4272 when PC_EOP =>
4273 if Stack_Base = Stack_Init then
4274 goto Match_Succeed;
4276 -- End of recursive inner match. See separate section on
4277 -- handing of recursive pattern matches for details.
4279 else
4280 Node := Stack (Stack_Base - 1).Node;
4281 Pop_Region;
4282 goto Match;
4283 end if;
4285 -- Fail
4287 when PC_Fail =>
4288 goto Fail;
4290 -- Fence (built in pattern)
4292 when PC_Fence =>
4293 Push (CP_Cancel'Access);
4294 goto Succeed;
4296 -- Fence function node X. This is the node that gets control
4297 -- after a successful match of the fenced pattern.
4299 when PC_Fence_X =>
4300 Stack_Ptr := Stack_Ptr + 1;
4301 Stack (Stack_Ptr).Cursor := Stack_Base;
4302 Stack (Stack_Ptr).Node := CP_Fence_Y'Access;
4303 Stack_Base := Stack (Stack_Base).Cursor;
4304 goto Succeed;
4306 -- Fence function node Y. This is the node that gets control on
4307 -- a failure that occurs after the fenced pattern has matched.
4309 -- Note: the Cursor at this stage is actually the inner stack
4310 -- base value. We don't reset this, but we do use it to strip
4311 -- off all the entries made by the fenced pattern.
4313 when PC_Fence_Y =>
4314 Stack_Ptr := Cursor - 2;
4315 goto Fail;
4317 -- Len (integer case)
4319 when PC_Len_Nat =>
4320 if Cursor + Node.Nat > Length then
4321 goto Fail;
4322 else
4323 Cursor := Cursor + Node.Nat;
4324 goto Succeed;
4325 end if;
4327 -- Len (Integer function case)
4329 when PC_Len_NF => declare
4330 N : constant Natural := Node.NF.all;
4331 begin
4332 if Cursor + N > Length then
4333 goto Fail;
4334 else
4335 Cursor := Cursor + N;
4336 goto Succeed;
4337 end if;
4338 end;
4340 -- Len (integer pointer case)
4342 when PC_Len_NP =>
4343 if Cursor + Node.NP.all > Length then
4344 goto Fail;
4345 else
4346 Cursor := Cursor + Node.NP.all;
4347 goto Succeed;
4348 end if;
4350 -- NotAny (one character case)
4352 when PC_NotAny_CH =>
4353 if Cursor < Length
4354 and then Subject (Cursor + 1) /= Node.Char
4355 then
4356 Cursor := Cursor + 1;
4357 goto Succeed;
4358 else
4359 goto Fail;
4360 end if;
4362 -- NotAny (character set case)
4364 when PC_NotAny_CS =>
4365 if Cursor < Length
4366 and then not Is_In (Subject (Cursor + 1), Node.CS)
4367 then
4368 Cursor := Cursor + 1;
4369 goto Succeed;
4370 else
4371 goto Fail;
4372 end if;
4374 -- NotAny (string function case)
4376 when PC_NotAny_VF => declare
4377 U : constant VString := Node.VF.all;
4378 S : Big_String_Access;
4379 L : Natural;
4381 begin
4382 Get_String (U, S, L);
4384 if Cursor < Length
4385 and then
4386 not Is_In (Subject (Cursor + 1), S (1 .. L))
4387 then
4388 Cursor := Cursor + 1;
4389 goto Succeed;
4390 else
4391 goto Fail;
4392 end if;
4393 end;
4395 -- NotAny (string pointer case)
4397 when PC_NotAny_VP => declare
4398 U : constant VString := Node.VP.all;
4399 S : Big_String_Access;
4400 L : Natural;
4402 begin
4403 Get_String (U, S, L);
4405 if Cursor < Length
4406 and then
4407 not Is_In (Subject (Cursor + 1), S (1 .. L))
4408 then
4409 Cursor := Cursor + 1;
4410 goto Succeed;
4411 else
4412 goto Fail;
4413 end if;
4414 end;
4416 -- NSpan (one character case)
4418 when PC_NSpan_CH =>
4419 while Cursor < Length
4420 and then Subject (Cursor + 1) = Node.Char
4421 loop
4422 Cursor := Cursor + 1;
4423 end loop;
4425 goto Succeed;
4427 -- NSpan (character set case)
4429 when PC_NSpan_CS =>
4430 while Cursor < Length
4431 and then Is_In (Subject (Cursor + 1), Node.CS)
4432 loop
4433 Cursor := Cursor + 1;
4434 end loop;
4436 goto Succeed;
4438 -- NSpan (string function case)
4440 when PC_NSpan_VF => declare
4441 U : constant VString := Node.VF.all;
4442 S : Big_String_Access;
4443 L : Natural;
4445 begin
4446 Get_String (U, S, L);
4448 while Cursor < Length
4449 and then Is_In (Subject (Cursor + 1), S (1 .. L))
4450 loop
4451 Cursor := Cursor + 1;
4452 end loop;
4454 goto Succeed;
4455 end;
4457 -- NSpan (string pointer case)
4459 when PC_NSpan_VP => declare
4460 U : constant VString := Node.VP.all;
4461 S : Big_String_Access;
4462 L : Natural;
4464 begin
4465 Get_String (U, S, L);
4467 while Cursor < Length
4468 and then Is_In (Subject (Cursor + 1), S (1 .. L))
4469 loop
4470 Cursor := Cursor + 1;
4471 end loop;
4473 goto Succeed;
4474 end;
4476 -- Null string
4478 when PC_Null =>
4479 goto Succeed;
4481 -- Pos (integer case)
4483 when PC_Pos_Nat =>
4484 if Cursor = Node.Nat then
4485 goto Succeed;
4486 else
4487 goto Fail;
4488 end if;
4490 -- Pos (Integer function case)
4492 when PC_Pos_NF => declare
4493 N : constant Natural := Node.NF.all;
4494 begin
4495 if Cursor = N then
4496 goto Succeed;
4497 else
4498 goto Fail;
4499 end if;
4500 end;
4502 -- Pos (integer pointer case)
4504 when PC_Pos_NP =>
4505 if Cursor = Node.NP.all then
4506 goto Succeed;
4507 else
4508 goto Fail;
4509 end if;
4511 -- Predicate function
4513 when PC_Pred_Func =>
4514 if Node.BF.all then
4515 goto Succeed;
4516 else
4517 goto Fail;
4518 end if;
4520 -- Region Enter. Initiate new pattern history stack region
4522 when PC_R_Enter =>
4523 Stack (Stack_Ptr + 1).Cursor := Cursor;
4524 Push_Region;
4525 goto Succeed;
4527 -- Region Remove node. This is the node stacked by an R_Enter.
4528 -- It removes the special format stack entry right underneath, and
4529 -- then restores the outer level stack base and signals failure.
4531 -- Note: the cursor value at this stage is actually the (negative)
4532 -- stack base value for the outer level.
4534 when PC_R_Remove =>
4535 Stack_Base := Cursor;
4536 Stack_Ptr := Stack_Ptr - 1;
4537 goto Fail;
4539 -- Region restore node. This is the node stacked at the end of an
4540 -- inner level match. Its function is to restore the inner level
4541 -- region, so that alternatives in this region can be sought.
4543 -- Note: the Cursor at this stage is actually the negative of the
4544 -- inner stack base value, which we use to restore the inner region.
4546 when PC_R_Restore =>
4547 Stack_Base := Cursor;
4548 goto Fail;
4550 -- Rest
4552 when PC_Rest =>
4553 Cursor := Length;
4554 goto Succeed;
4556 -- Initiate recursive match (pattern pointer case)
4558 when PC_Rpat =>
4559 Stack (Stack_Ptr + 1).Node := Node.Pthen;
4560 Push_Region;
4562 if Stack_Ptr + Node.PP.all.Stk >= Stack_Size then
4563 raise Pattern_Stack_Overflow;
4564 else
4565 Node := Node.PP.all.P;
4566 goto Match;
4567 end if;
4569 -- RPos (integer case)
4571 when PC_RPos_Nat =>
4572 if Cursor = (Length - Node.Nat) then
4573 goto Succeed;
4574 else
4575 goto Fail;
4576 end if;
4578 -- RPos (integer function case)
4580 when PC_RPos_NF => declare
4581 N : constant Natural := Node.NF.all;
4582 begin
4583 if Length - Cursor = N then
4584 goto Succeed;
4585 else
4586 goto Fail;
4587 end if;
4588 end;
4590 -- RPos (integer pointer case)
4592 when PC_RPos_NP =>
4593 if Cursor = (Length - Node.NP.all) then
4594 goto Succeed;
4595 else
4596 goto Fail;
4597 end if;
4599 -- RTab (integer case)
4601 when PC_RTab_Nat =>
4602 if Cursor <= (Length - Node.Nat) then
4603 Cursor := Length - Node.Nat;
4604 goto Succeed;
4605 else
4606 goto Fail;
4607 end if;
4609 -- RTab (integer function case)
4611 when PC_RTab_NF => declare
4612 N : constant Natural := Node.NF.all;
4613 begin
4614 if Length - Cursor >= N then
4615 Cursor := Length - N;
4616 goto Succeed;
4617 else
4618 goto Fail;
4619 end if;
4620 end;
4622 -- RTab (integer pointer case)
4624 when PC_RTab_NP =>
4625 if Cursor <= (Length - Node.NP.all) then
4626 Cursor := Length - Node.NP.all;
4627 goto Succeed;
4628 else
4629 goto Fail;
4630 end if;
4632 -- Cursor assignment
4634 when PC_Setcur =>
4635 Node.Var.all := Cursor;
4636 goto Succeed;
4638 -- Span (one character case)
4640 when PC_Span_CH => declare
4641 P : Natural;
4643 begin
4644 P := Cursor;
4645 while P < Length
4646 and then Subject (P + 1) = Node.Char
4647 loop
4648 P := P + 1;
4649 end loop;
4651 if P /= Cursor then
4652 Cursor := P;
4653 goto Succeed;
4654 else
4655 goto Fail;
4656 end if;
4657 end;
4659 -- Span (character set case)
4661 when PC_Span_CS => declare
4662 P : Natural;
4664 begin
4665 P := Cursor;
4666 while P < Length
4667 and then Is_In (Subject (P + 1), Node.CS)
4668 loop
4669 P := P + 1;
4670 end loop;
4672 if P /= Cursor then
4673 Cursor := P;
4674 goto Succeed;
4675 else
4676 goto Fail;
4677 end if;
4678 end;
4680 -- Span (string function case)
4682 when PC_Span_VF => declare
4683 U : constant VString := Node.VF.all;
4684 S : Big_String_Access;
4685 L : Natural;
4686 P : Natural;
4688 begin
4689 Get_String (U, S, L);
4691 P := Cursor;
4692 while P < Length
4693 and then Is_In (Subject (P + 1), S (1 .. L))
4694 loop
4695 P := P + 1;
4696 end loop;
4698 if P /= Cursor then
4699 Cursor := P;
4700 goto Succeed;
4701 else
4702 goto Fail;
4703 end if;
4704 end;
4706 -- Span (string pointer case)
4708 when PC_Span_VP => declare
4709 U : constant VString := Node.VP.all;
4710 S : Big_String_Access;
4711 L : Natural;
4712 P : Natural;
4714 begin
4715 Get_String (U, S, L);
4717 P := Cursor;
4718 while P < Length
4719 and then Is_In (Subject (P + 1), S (1 .. L))
4720 loop
4721 P := P + 1;
4722 end loop;
4724 if P /= Cursor then
4725 Cursor := P;
4726 goto Succeed;
4727 else
4728 goto Fail;
4729 end if;
4730 end;
4732 -- String (two character case)
4734 when PC_String_2 =>
4735 if (Length - Cursor) >= 2
4736 and then Subject (Cursor + 1 .. Cursor + 2) = Node.Str2
4737 then
4738 Cursor := Cursor + 2;
4739 goto Succeed;
4740 else
4741 goto Fail;
4742 end if;
4744 -- String (three character case)
4746 when PC_String_3 =>
4747 if (Length - Cursor) >= 3
4748 and then Subject (Cursor + 1 .. Cursor + 3) = Node.Str3
4749 then
4750 Cursor := Cursor + 3;
4751 goto Succeed;
4752 else
4753 goto Fail;
4754 end if;
4756 -- String (four character case)
4758 when PC_String_4 =>
4759 if (Length - Cursor) >= 4
4760 and then Subject (Cursor + 1 .. Cursor + 4) = Node.Str4
4761 then
4762 Cursor := Cursor + 4;
4763 goto Succeed;
4764 else
4765 goto Fail;
4766 end if;
4768 -- String (five character case)
4770 when PC_String_5 =>
4771 if (Length - Cursor) >= 5
4772 and then Subject (Cursor + 1 .. Cursor + 5) = Node.Str5
4773 then
4774 Cursor := Cursor + 5;
4775 goto Succeed;
4776 else
4777 goto Fail;
4778 end if;
4780 -- String (six character case)
4782 when PC_String_6 =>
4783 if (Length - Cursor) >= 6
4784 and then Subject (Cursor + 1 .. Cursor + 6) = Node.Str6
4785 then
4786 Cursor := Cursor + 6;
4787 goto Succeed;
4788 else
4789 goto Fail;
4790 end if;
4792 -- String (case of more than six characters)
4794 when PC_String => declare
4795 Len : constant Natural := Node.Str'Length;
4796 begin
4797 if (Length - Cursor) >= Len
4798 and then Node.Str.all = Subject (Cursor + 1 .. Cursor + Len)
4799 then
4800 Cursor := Cursor + Len;
4801 goto Succeed;
4802 else
4803 goto Fail;
4804 end if;
4805 end;
4807 -- String (function case)
4809 when PC_String_VF => declare
4810 U : constant VString := Node.VF.all;
4811 S : Big_String_Access;
4812 L : Natural;
4814 begin
4815 Get_String (U, S, L);
4817 if (Length - Cursor) >= L
4818 and then S (1 .. L) = Subject (Cursor + 1 .. Cursor + L)
4819 then
4820 Cursor := Cursor + L;
4821 goto Succeed;
4822 else
4823 goto Fail;
4824 end if;
4825 end;
4827 -- String (pointer case)
4829 when PC_String_VP => declare
4830 U : constant VString := Node.VP.all;
4831 S : Big_String_Access;
4832 L : Natural;
4834 begin
4835 Get_String (U, S, L);
4837 if (Length - Cursor) >= L
4838 and then S (1 .. L) = Subject (Cursor + 1 .. Cursor + L)
4839 then
4840 Cursor := Cursor + L;
4841 goto Succeed;
4842 else
4843 goto Fail;
4844 end if;
4845 end;
4847 -- Succeed
4849 when PC_Succeed =>
4850 Push (Node);
4851 goto Succeed;
4853 -- Tab (integer case)
4855 when PC_Tab_Nat =>
4856 if Cursor <= Node.Nat then
4857 Cursor := Node.Nat;
4858 goto Succeed;
4859 else
4860 goto Fail;
4861 end if;
4863 -- Tab (integer function case)
4865 when PC_Tab_NF => declare
4866 N : constant Natural := Node.NF.all;
4867 begin
4868 if Cursor <= N then
4869 Cursor := N;
4870 goto Succeed;
4871 else
4872 goto Fail;
4873 end if;
4874 end;
4876 -- Tab (integer pointer case)
4878 when PC_Tab_NP =>
4879 if Cursor <= Node.NP.all then
4880 Cursor := Node.NP.all;
4881 goto Succeed;
4882 else
4883 goto Fail;
4884 end if;
4886 -- Unanchored movement
4888 when PC_Unanchored =>
4890 -- All done if we tried every position
4892 if Cursor > Length then
4893 goto Match_Fail;
4895 -- Otherwise extend the anchor point, and restack ourself
4897 else
4898 Cursor := Cursor + 1;
4899 Push (Node);
4900 goto Succeed;
4901 end if;
4903 -- Write immediate. This node performs the actual write
4905 when PC_Write_Imm =>
4906 Put_Line
4907 (Node.FP.all,
4908 Subject (Stack (Stack_Base - 1).Cursor + 1 .. Cursor));
4909 Pop_Region;
4910 goto Succeed;
4912 -- Write on match. This node sets up for the eventual write
4914 when PC_Write_OnM =>
4915 Stack (Stack_Base - 1).Node := Node;
4916 Push (CP_Assign'Access);
4917 Pop_Region;
4918 Assign_OnM := True;
4919 goto Succeed;
4921 end case;
4923 -- We are NOT allowed to fall though this case statement, since every
4924 -- match routine must end by executing a goto to the appropriate point
4925 -- in the finite state machine model.
4927 pragma Warnings (Off);
4928 Logic_Error;
4929 pragma Warnings (On);
4930 end XMatch;
4932 -------------
4933 -- XMatchD --
4934 -------------
4936 -- Maintenance note: There is a LOT of code duplication between XMatch
4937 -- and XMatchD. This is quite intentional, the point is to avoid any
4938 -- unnecessary debugging overhead in the XMatch case, but this does mean
4939 -- that any changes to XMatchD must be mirrored in XMatch. In case of
4940 -- any major changes, the proper approach is to delete XMatch, make the
4941 -- changes to XMatchD, and then make a copy of XMatchD, removing all
4942 -- calls to Dout, and all Put and Put_Line operations. This copy becomes
4943 -- the new XMatch.
4945 procedure XMatchD
4946 (Subject : String;
4947 Pat_P : PE_Ptr;
4948 Pat_S : Natural;
4949 Start : out Natural;
4950 Stop : out Natural)
4952 Node : PE_Ptr;
4953 -- Pointer to current pattern node. Initialized from Pat_P, and then
4954 -- updated as the match proceeds through its constituent elements.
4956 Length : constant Natural := Subject'Length;
4957 -- Length of string (= Subject'Last, since Subject'First is always 1)
4959 Cursor : Integer := 0;
4960 -- If the value is non-negative, then this value is the index showing
4961 -- the current position of the match in the subject string. The next
4962 -- character to be matched is at Subject (Cursor + 1). Note that since
4963 -- our view of the subject string in XMatch always has a lower bound
4964 -- of one, regardless of original bounds, that this definition exactly
4965 -- corresponds to the cursor value as referenced by functions like Pos.
4967 -- If the value is negative, then this is a saved stack pointer,
4968 -- typically a base pointer of an inner or outer region. Cursor
4969 -- temporarily holds such a value when it is popped from the stack
4970 -- by Fail. In all cases, Cursor is reset to a proper non-negative
4971 -- cursor value before the match proceeds (e.g. by propagating the
4972 -- failure and popping a "real" cursor value from the stack.
4974 PE_Unanchored : aliased PE := (PC_Unanchored, 0, Pat_P);
4975 -- Dummy pattern element used in the unanchored case
4977 Region_Level : Natural := 0;
4978 -- Keeps track of recursive region level. This is used only for
4979 -- debugging, it is the number of saved history stack base values.
4981 Stack : Stack_Type;
4982 -- The pattern matching failure stack for this call to Match
4984 Stack_Ptr : Stack_Range;
4985 -- Current stack pointer. This points to the top element of the stack
4986 -- that is currently in use. At the outer level this is the special
4987 -- entry placed on the stack according to the anchor mode.
4989 Stack_Init : constant Stack_Range := Stack'First + 1;
4990 -- This is the initial value of the Stack_Ptr and Stack_Base. The
4991 -- initial (Stack'First) element of the stack is not used so that
4992 -- when we pop the last element off, Stack_Ptr is still in range.
4994 Stack_Base : Stack_Range;
4995 -- This value is the stack base value, i.e. the stack pointer for the
4996 -- first history stack entry in the current stack region. See separate
4997 -- section on handling of recursive pattern matches.
4999 Assign_OnM : Boolean := False;
5000 -- Set True if assign-on-match or write-on-match operations may be
5001 -- present in the history stack, which must then be scanned on a
5002 -- successful match.
5004 procedure Dout (Str : String);
5005 -- Output string to standard error with bars indicating region level
5007 procedure Dout (Str : String; A : Character);
5008 -- Calls Dout with the string S ('A')
5010 procedure Dout (Str : String; A : Character_Set);
5011 -- Calls Dout with the string S ("A")
5013 procedure Dout (Str : String; A : Natural);
5014 -- Calls Dout with the string S (A)
5016 procedure Dout (Str : String; A : String);
5017 -- Calls Dout with the string S ("A")
5019 function Img (P : PE_Ptr) return String;
5020 -- Returns a string of the form #nnn where nnn is P.Index
5022 procedure Pop_Region;
5023 pragma Inline (Pop_Region);
5024 -- Used at the end of processing of an inner region. If the inner
5025 -- region left no stack entries, then all trace of it is removed.
5026 -- Otherwise a PC_Restore_Region entry is pushed to ensure proper
5027 -- handling of alternatives in the inner region.
5029 procedure Push (Node : PE_Ptr);
5030 pragma Inline (Push);
5031 -- Make entry in pattern matching stack with current cursor value
5033 procedure Push_Region;
5034 pragma Inline (Push_Region);
5035 -- This procedure makes a new region on the history stack. The
5036 -- caller first establishes the special entry on the stack, but
5037 -- does not push the stack pointer. Then this call stacks a
5038 -- PC_Remove_Region node, on top of this entry, using the cursor
5039 -- field of the PC_Remove_Region entry to save the outer level
5040 -- stack base value, and resets the stack base to point to this
5041 -- PC_Remove_Region node.
5043 ----------
5044 -- Dout --
5045 ----------
5047 procedure Dout (Str : String) is
5048 begin
5049 for J in 1 .. Region_Level loop
5050 Put ("| ");
5051 end loop;
5053 Put_Line (Str);
5054 end Dout;
5056 procedure Dout (Str : String; A : Character) is
5057 begin
5058 Dout (Str & " ('" & A & "')");
5059 end Dout;
5061 procedure Dout (Str : String; A : Character_Set) is
5062 begin
5063 Dout (Str & " (" & Image (To_Sequence (A)) & ')');
5064 end Dout;
5066 procedure Dout (Str : String; A : Natural) is
5067 begin
5068 Dout (Str & " (" & A & ')');
5069 end Dout;
5071 procedure Dout (Str : String; A : String) is
5072 begin
5073 Dout (Str & " (" & Image (A) & ')');
5074 end Dout;
5076 ---------
5077 -- Img --
5078 ---------
5080 function Img (P : PE_Ptr) return String is
5081 begin
5082 return "#" & Integer (P.Index) & " ";
5083 end Img;
5085 ----------------
5086 -- Pop_Region --
5087 ----------------
5089 procedure Pop_Region is
5090 begin
5091 Region_Level := Region_Level - 1;
5093 -- If nothing was pushed in the inner region, we can just get
5094 -- rid of it entirely, leaving no traces that it was ever there
5096 if Stack_Ptr = Stack_Base then
5097 Stack_Ptr := Stack_Base - 2;
5098 Stack_Base := Stack (Stack_Ptr + 2).Cursor;
5100 -- If stuff was pushed in the inner region, then we have to
5101 -- push a PC_R_Restore node so that we properly handle possible
5102 -- rematches within the region.
5104 else
5105 Stack_Ptr := Stack_Ptr + 1;
5106 Stack (Stack_Ptr).Cursor := Stack_Base;
5107 Stack (Stack_Ptr).Node := CP_R_Restore'Access;
5108 Stack_Base := Stack (Stack_Base).Cursor;
5109 end if;
5110 end Pop_Region;
5112 ----------
5113 -- Push --
5114 ----------
5116 procedure Push (Node : PE_Ptr) is
5117 begin
5118 Stack_Ptr := Stack_Ptr + 1;
5119 Stack (Stack_Ptr).Cursor := Cursor;
5120 Stack (Stack_Ptr).Node := Node;
5121 end Push;
5123 -----------------
5124 -- Push_Region --
5125 -----------------
5127 procedure Push_Region is
5128 begin
5129 Region_Level := Region_Level + 1;
5130 Stack_Ptr := Stack_Ptr + 2;
5131 Stack (Stack_Ptr).Cursor := Stack_Base;
5132 Stack (Stack_Ptr).Node := CP_R_Remove'Access;
5133 Stack_Base := Stack_Ptr;
5134 end Push_Region;
5136 -- Start of processing for XMatchD
5138 begin
5139 New_Line;
5140 Put_Line ("Initiating pattern match, subject = " & Image (Subject));
5141 Put ("--------------------------------------");
5143 for J in 1 .. Length loop
5144 Put ('-');
5145 end loop;
5147 New_Line;
5148 Put_Line ("subject length = " & Length);
5150 if Pat_P = null then
5151 Uninitialized_Pattern;
5152 end if;
5154 -- Check we have enough stack for this pattern. This check deals with
5155 -- every possibility except a match of a recursive pattern, where we
5156 -- make a check at each recursion level.
5158 if Pat_S >= Stack_Size - 1 then
5159 raise Pattern_Stack_Overflow;
5160 end if;
5162 -- In anchored mode, the bottom entry on the stack is an abort entry
5164 if Anchored_Mode then
5165 Stack (Stack_Init).Node := CP_Cancel'Access;
5166 Stack (Stack_Init).Cursor := 0;
5168 -- In unanchored more, the bottom entry on the stack references
5169 -- the special pattern element PE_Unanchored, whose Pthen field
5170 -- points to the initial pattern element. The cursor value in this
5171 -- entry is the number of anchor moves so far.
5173 else
5174 Stack (Stack_Init).Node := PE_Unanchored'Unchecked_Access;
5175 Stack (Stack_Init).Cursor := 0;
5176 end if;
5178 Stack_Ptr := Stack_Init;
5179 Stack_Base := Stack_Ptr;
5180 Cursor := 0;
5181 Node := Pat_P;
5182 goto Match;
5184 -----------------------------------------
5185 -- Main Pattern Matching State Control --
5186 -----------------------------------------
5188 -- This is a state machine which uses gotos to change state. The
5189 -- initial state is Match, to initiate the matching of the first
5190 -- element, so the goto Match above starts the match. In the
5191 -- following descriptions, we indicate the global values that
5192 -- are relevant for the state transition.
5194 -- Come here if entire match fails
5196 <<Match_Fail>>
5197 Dout ("match fails");
5198 New_Line;
5199 Start := 0;
5200 Stop := 0;
5201 return;
5203 -- Come here if entire match succeeds
5205 -- Cursor current position in subject string
5207 <<Match_Succeed>>
5208 Dout ("match succeeds");
5209 Start := Stack (Stack_Init).Cursor + 1;
5210 Stop := Cursor;
5211 Dout ("first matched character index = " & Start);
5212 Dout ("last matched character index = " & Stop);
5213 Dout ("matched substring = " & Image (Subject (Start .. Stop)));
5215 -- Scan history stack for deferred assignments or writes
5217 if Assign_OnM then
5218 for S in Stack'First .. Stack_Ptr loop
5219 if Stack (S).Node = CP_Assign'Access then
5220 declare
5221 Inner_Base : constant Stack_Range :=
5222 Stack (S + 1).Cursor;
5223 Special_Entry : constant Stack_Range :=
5224 Inner_Base - 1;
5225 Node_OnM : constant PE_Ptr :=
5226 Stack (Special_Entry).Node;
5227 Start : constant Natural :=
5228 Stack (Special_Entry).Cursor + 1;
5229 Stop : constant Natural := Stack (S).Cursor;
5231 begin
5232 if Node_OnM.Pcode = PC_Assign_OnM then
5233 Set_String (Node_OnM.VP.all, Subject (Start .. Stop));
5234 Dout
5235 (Img (Stack (S).Node) &
5236 "deferred assignment of " &
5237 Image (Subject (Start .. Stop)));
5239 elsif Node_OnM.Pcode = PC_Write_OnM then
5240 Put_Line (Node_OnM.FP.all, Subject (Start .. Stop));
5241 Dout
5242 (Img (Stack (S).Node) &
5243 "deferred write of " &
5244 Image (Subject (Start .. Stop)));
5246 else
5247 Logic_Error;
5248 end if;
5249 end;
5250 end if;
5251 end loop;
5252 end if;
5254 New_Line;
5255 return;
5257 -- Come here if attempt to match current element fails
5259 -- Stack_Base current stack base
5260 -- Stack_Ptr current stack pointer
5262 <<Fail>>
5263 Cursor := Stack (Stack_Ptr).Cursor;
5264 Node := Stack (Stack_Ptr).Node;
5265 Stack_Ptr := Stack_Ptr - 1;
5267 if Cursor >= 0 then
5268 Dout ("failure, cursor reset to " & Cursor);
5269 end if;
5271 goto Match;
5273 -- Come here if attempt to match current element succeeds
5275 -- Cursor current position in subject string
5276 -- Node pointer to node successfully matched
5277 -- Stack_Base current stack base
5278 -- Stack_Ptr current stack pointer
5280 <<Succeed>>
5281 Dout ("success, cursor = " & Cursor);
5282 Node := Node.Pthen;
5284 -- Come here to match the next pattern element
5286 -- Cursor current position in subject string
5287 -- Node pointer to node to be matched
5288 -- Stack_Base current stack base
5289 -- Stack_Ptr current stack pointer
5291 <<Match>>
5293 --------------------------------------------------
5294 -- Main Pattern Match Element Matching Routines --
5295 --------------------------------------------------
5297 -- Here is the case statement that processes the current node. The
5298 -- processing for each element does one of five things:
5300 -- goto Succeed to move to the successor
5301 -- goto Match_Succeed if the entire match succeeds
5302 -- goto Match_Fail if the entire match fails
5303 -- goto Fail to signal failure of current match
5305 -- Processing is NOT allowed to fall through
5307 case Node.Pcode is
5309 -- Cancel
5311 when PC_Cancel =>
5312 Dout (Img (Node) & "matching Cancel");
5313 goto Match_Fail;
5315 -- Alternation
5317 when PC_Alt =>
5318 Dout
5319 (Img (Node) & "setting up alternative " & Img (Node.Alt));
5320 Push (Node.Alt);
5321 Node := Node.Pthen;
5322 goto Match;
5324 -- Any (one character case)
5326 when PC_Any_CH =>
5327 Dout (Img (Node) & "matching Any", Node.Char);
5329 if Cursor < Length
5330 and then Subject (Cursor + 1) = Node.Char
5331 then
5332 Cursor := Cursor + 1;
5333 goto Succeed;
5334 else
5335 goto Fail;
5336 end if;
5338 -- Any (character set case)
5340 when PC_Any_CS =>
5341 Dout (Img (Node) & "matching Any", Node.CS);
5343 if Cursor < Length
5344 and then Is_In (Subject (Cursor + 1), Node.CS)
5345 then
5346 Cursor := Cursor + 1;
5347 goto Succeed;
5348 else
5349 goto Fail;
5350 end if;
5352 -- Any (string function case)
5354 when PC_Any_VF => declare
5355 U : constant VString := Node.VF.all;
5356 S : Big_String_Access;
5357 L : Natural;
5359 begin
5360 Get_String (U, S, L);
5362 Dout (Img (Node) & "matching Any", S (1 .. L));
5364 if Cursor < Length
5365 and then Is_In (Subject (Cursor + 1), S (1 .. L))
5366 then
5367 Cursor := Cursor + 1;
5368 goto Succeed;
5369 else
5370 goto Fail;
5371 end if;
5372 end;
5374 -- Any (string pointer case)
5376 when PC_Any_VP => declare
5377 U : constant VString := Node.VP.all;
5378 S : Big_String_Access;
5379 L : Natural;
5381 begin
5382 Get_String (U, S, L);
5383 Dout (Img (Node) & "matching Any", S (1 .. L));
5385 if Cursor < Length
5386 and then Is_In (Subject (Cursor + 1), S (1 .. L))
5387 then
5388 Cursor := Cursor + 1;
5389 goto Succeed;
5390 else
5391 goto Fail;
5392 end if;
5393 end;
5395 -- Arb (initial match)
5397 when PC_Arb_X =>
5398 Dout (Img (Node) & "matching Arb");
5399 Push (Node.Alt);
5400 Node := Node.Pthen;
5401 goto Match;
5403 -- Arb (extension)
5405 when PC_Arb_Y =>
5406 Dout (Img (Node) & "extending Arb");
5408 if Cursor < Length then
5409 Cursor := Cursor + 1;
5410 Push (Node);
5411 goto Succeed;
5412 else
5413 goto Fail;
5414 end if;
5416 -- Arbno_S (simple Arbno initialize). This is the node that
5417 -- initiates the match of a simple Arbno structure.
5419 when PC_Arbno_S =>
5420 Dout (Img (Node) &
5421 "setting up Arbno alternative " & Img (Node.Alt));
5422 Push (Node.Alt);
5423 Node := Node.Pthen;
5424 goto Match;
5426 -- Arbno_X (Arbno initialize). This is the node that initiates
5427 -- the match of a complex Arbno structure.
5429 when PC_Arbno_X =>
5430 Dout (Img (Node) &
5431 "setting up Arbno alternative " & Img (Node.Alt));
5432 Push (Node.Alt);
5433 Node := Node.Pthen;
5434 goto Match;
5436 -- Arbno_Y (Arbno rematch). This is the node that is executed
5437 -- following successful matching of one instance of a complex
5438 -- Arbno pattern.
5440 when PC_Arbno_Y => declare
5441 Null_Match : constant Boolean :=
5442 Cursor = Stack (Stack_Base - 1).Cursor;
5444 begin
5445 Dout (Img (Node) & "extending Arbno");
5446 Pop_Region;
5448 -- If arbno extension matched null, then immediately fail
5450 if Null_Match then
5451 Dout ("Arbno extension matched null, so fails");
5452 goto Fail;
5453 end if;
5455 -- Here we must do a stack check to make sure enough stack
5456 -- is left. This check will happen once for each instance of
5457 -- the Arbno pattern that is matched. The Nat field of a
5458 -- PC_Arbno pattern contains the maximum stack entries needed
5459 -- for the Arbno with one instance and the successor pattern
5461 if Stack_Ptr + Node.Nat >= Stack'Last then
5462 raise Pattern_Stack_Overflow;
5463 end if;
5465 goto Succeed;
5466 end;
5468 -- Assign. If this node is executed, it means the assign-on-match
5469 -- or write-on-match operation will not happen after all, so we
5470 -- is propagate the failure, removing the PC_Assign node.
5472 when PC_Assign =>
5473 Dout (Img (Node) & "deferred assign/write cancelled");
5474 goto Fail;
5476 -- Assign immediate. This node performs the actual assignment
5478 when PC_Assign_Imm =>
5479 Dout
5480 (Img (Node) & "executing immediate assignment of " &
5481 Image (Subject (Stack (Stack_Base - 1).Cursor + 1 .. Cursor)));
5482 Set_String
5483 (Node.VP.all,
5484 Subject (Stack (Stack_Base - 1).Cursor + 1 .. Cursor));
5485 Pop_Region;
5486 goto Succeed;
5488 -- Assign on match. This node sets up for the eventual assignment
5490 when PC_Assign_OnM =>
5491 Dout (Img (Node) & "registering deferred assignment");
5492 Stack (Stack_Base - 1).Node := Node;
5493 Push (CP_Assign'Access);
5494 Pop_Region;
5495 Assign_OnM := True;
5496 goto Succeed;
5498 -- Bal
5500 when PC_Bal =>
5501 Dout (Img (Node) & "matching or extending Bal");
5502 if Cursor >= Length or else Subject (Cursor + 1) = ')' then
5503 goto Fail;
5505 elsif Subject (Cursor + 1) = '(' then
5506 declare
5507 Paren_Count : Natural := 1;
5509 begin
5510 loop
5511 Cursor := Cursor + 1;
5513 if Cursor >= Length then
5514 goto Fail;
5516 elsif Subject (Cursor + 1) = '(' then
5517 Paren_Count := Paren_Count + 1;
5519 elsif Subject (Cursor + 1) = ')' then
5520 Paren_Count := Paren_Count - 1;
5521 exit when Paren_Count = 0;
5522 end if;
5523 end loop;
5524 end;
5525 end if;
5527 Cursor := Cursor + 1;
5528 Push (Node);
5529 goto Succeed;
5531 -- Break (one character case)
5533 when PC_Break_CH =>
5534 Dout (Img (Node) & "matching Break", Node.Char);
5536 while Cursor < Length loop
5537 if Subject (Cursor + 1) = Node.Char then
5538 goto Succeed;
5539 else
5540 Cursor := Cursor + 1;
5541 end if;
5542 end loop;
5544 goto Fail;
5546 -- Break (character set case)
5548 when PC_Break_CS =>
5549 Dout (Img (Node) & "matching Break", Node.CS);
5551 while Cursor < Length loop
5552 if Is_In (Subject (Cursor + 1), Node.CS) then
5553 goto Succeed;
5554 else
5555 Cursor := Cursor + 1;
5556 end if;
5557 end loop;
5559 goto Fail;
5561 -- Break (string function case)
5563 when PC_Break_VF => declare
5564 U : constant VString := Node.VF.all;
5565 S : Big_String_Access;
5566 L : Natural;
5568 begin
5569 Get_String (U, S, L);
5570 Dout (Img (Node) & "matching Break", S (1 .. L));
5572 while Cursor < Length loop
5573 if Is_In (Subject (Cursor + 1), S (1 .. L)) then
5574 goto Succeed;
5575 else
5576 Cursor := Cursor + 1;
5577 end if;
5578 end loop;
5580 goto Fail;
5581 end;
5583 -- Break (string pointer case)
5585 when PC_Break_VP => declare
5586 U : constant VString := Node.VP.all;
5587 S : Big_String_Access;
5588 L : Natural;
5590 begin
5591 Get_String (U, S, L);
5592 Dout (Img (Node) & "matching Break", S (1 .. L));
5594 while Cursor < Length loop
5595 if Is_In (Subject (Cursor + 1), S (1 .. L)) then
5596 goto Succeed;
5597 else
5598 Cursor := Cursor + 1;
5599 end if;
5600 end loop;
5602 goto Fail;
5603 end;
5605 -- BreakX (one character case)
5607 when PC_BreakX_CH =>
5608 Dout (Img (Node) & "matching BreakX", Node.Char);
5610 while Cursor < Length loop
5611 if Subject (Cursor + 1) = Node.Char then
5612 goto Succeed;
5613 else
5614 Cursor := Cursor + 1;
5615 end if;
5616 end loop;
5618 goto Fail;
5620 -- BreakX (character set case)
5622 when PC_BreakX_CS =>
5623 Dout (Img (Node) & "matching BreakX", Node.CS);
5625 while Cursor < Length loop
5626 if Is_In (Subject (Cursor + 1), Node.CS) then
5627 goto Succeed;
5628 else
5629 Cursor := Cursor + 1;
5630 end if;
5631 end loop;
5633 goto Fail;
5635 -- BreakX (string function case)
5637 when PC_BreakX_VF => declare
5638 U : constant VString := Node.VF.all;
5639 S : Big_String_Access;
5640 L : Natural;
5642 begin
5643 Get_String (U, S, L);
5644 Dout (Img (Node) & "matching BreakX", S (1 .. L));
5646 while Cursor < Length loop
5647 if Is_In (Subject (Cursor + 1), S (1 .. L)) then
5648 goto Succeed;
5649 else
5650 Cursor := Cursor + 1;
5651 end if;
5652 end loop;
5654 goto Fail;
5655 end;
5657 -- BreakX (string pointer case)
5659 when PC_BreakX_VP => declare
5660 U : constant VString := Node.VP.all;
5661 S : Big_String_Access;
5662 L : Natural;
5664 begin
5665 Get_String (U, S, L);
5666 Dout (Img (Node) & "matching BreakX", S (1 .. L));
5668 while Cursor < Length loop
5669 if Is_In (Subject (Cursor + 1), S (1 .. L)) then
5670 goto Succeed;
5671 else
5672 Cursor := Cursor + 1;
5673 end if;
5674 end loop;
5676 goto Fail;
5677 end;
5679 -- BreakX_X (BreakX extension). See section on "Compound Pattern
5680 -- Structures". This node is the alternative that is stacked
5681 -- to skip past the break character and extend the break.
5683 when PC_BreakX_X =>
5684 Dout (Img (Node) & "extending BreakX");
5685 Cursor := Cursor + 1;
5686 goto Succeed;
5688 -- Character (one character string)
5690 when PC_Char =>
5691 Dout (Img (Node) & "matching '" & Node.Char & ''');
5693 if Cursor < Length
5694 and then Subject (Cursor + 1) = Node.Char
5695 then
5696 Cursor := Cursor + 1;
5697 goto Succeed;
5698 else
5699 goto Fail;
5700 end if;
5702 -- End of Pattern
5704 when PC_EOP =>
5705 if Stack_Base = Stack_Init then
5706 Dout ("end of pattern");
5707 goto Match_Succeed;
5709 -- End of recursive inner match. See separate section on
5710 -- handing of recursive pattern matches for details.
5712 else
5713 Dout ("terminating recursive match");
5714 Node := Stack (Stack_Base - 1).Node;
5715 Pop_Region;
5716 goto Match;
5717 end if;
5719 -- Fail
5721 when PC_Fail =>
5722 Dout (Img (Node) & "matching Fail");
5723 goto Fail;
5725 -- Fence (built in pattern)
5727 when PC_Fence =>
5728 Dout (Img (Node) & "matching Fence");
5729 Push (CP_Cancel'Access);
5730 goto Succeed;
5732 -- Fence function node X. This is the node that gets control
5733 -- after a successful match of the fenced pattern.
5735 when PC_Fence_X =>
5736 Dout (Img (Node) & "matching Fence function");
5737 Stack_Ptr := Stack_Ptr + 1;
5738 Stack (Stack_Ptr).Cursor := Stack_Base;
5739 Stack (Stack_Ptr).Node := CP_Fence_Y'Access;
5740 Stack_Base := Stack (Stack_Base).Cursor;
5741 Region_Level := Region_Level - 1;
5742 goto Succeed;
5744 -- Fence function node Y. This is the node that gets control on
5745 -- a failure that occurs after the fenced pattern has matched.
5747 -- Note: the Cursor at this stage is actually the inner stack
5748 -- base value. We don't reset this, but we do use it to strip
5749 -- off all the entries made by the fenced pattern.
5751 when PC_Fence_Y =>
5752 Dout (Img (Node) & "pattern matched by Fence caused failure");
5753 Stack_Ptr := Cursor - 2;
5754 goto Fail;
5756 -- Len (integer case)
5758 when PC_Len_Nat =>
5759 Dout (Img (Node) & "matching Len", Node.Nat);
5761 if Cursor + Node.Nat > Length then
5762 goto Fail;
5763 else
5764 Cursor := Cursor + Node.Nat;
5765 goto Succeed;
5766 end if;
5768 -- Len (Integer function case)
5770 when PC_Len_NF => declare
5771 N : constant Natural := Node.NF.all;
5773 begin
5774 Dout (Img (Node) & "matching Len", N);
5776 if Cursor + N > Length then
5777 goto Fail;
5778 else
5779 Cursor := Cursor + N;
5780 goto Succeed;
5781 end if;
5782 end;
5784 -- Len (integer pointer case)
5786 when PC_Len_NP =>
5787 Dout (Img (Node) & "matching Len", Node.NP.all);
5789 if Cursor + Node.NP.all > Length then
5790 goto Fail;
5791 else
5792 Cursor := Cursor + Node.NP.all;
5793 goto Succeed;
5794 end if;
5796 -- NotAny (one character case)
5798 when PC_NotAny_CH =>
5799 Dout (Img (Node) & "matching NotAny", Node.Char);
5801 if Cursor < Length
5802 and then Subject (Cursor + 1) /= Node.Char
5803 then
5804 Cursor := Cursor + 1;
5805 goto Succeed;
5806 else
5807 goto Fail;
5808 end if;
5810 -- NotAny (character set case)
5812 when PC_NotAny_CS =>
5813 Dout (Img (Node) & "matching NotAny", Node.CS);
5815 if Cursor < Length
5816 and then not Is_In (Subject (Cursor + 1), Node.CS)
5817 then
5818 Cursor := Cursor + 1;
5819 goto Succeed;
5820 else
5821 goto Fail;
5822 end if;
5824 -- NotAny (string function case)
5826 when PC_NotAny_VF => declare
5827 U : constant VString := Node.VF.all;
5828 S : Big_String_Access;
5829 L : Natural;
5831 begin
5832 Get_String (U, S, L);
5833 Dout (Img (Node) & "matching NotAny", S (1 .. L));
5835 if Cursor < Length
5836 and then
5837 not Is_In (Subject (Cursor + 1), S (1 .. L))
5838 then
5839 Cursor := Cursor + 1;
5840 goto Succeed;
5841 else
5842 goto Fail;
5843 end if;
5844 end;
5846 -- NotAny (string pointer case)
5848 when PC_NotAny_VP => declare
5849 U : constant VString := Node.VP.all;
5850 S : Big_String_Access;
5851 L : Natural;
5853 begin
5854 Get_String (U, S, L);
5855 Dout (Img (Node) & "matching NotAny", S (1 .. L));
5857 if Cursor < Length
5858 and then
5859 not Is_In (Subject (Cursor + 1), S (1 .. L))
5860 then
5861 Cursor := Cursor + 1;
5862 goto Succeed;
5863 else
5864 goto Fail;
5865 end if;
5866 end;
5868 -- NSpan (one character case)
5870 when PC_NSpan_CH =>
5871 Dout (Img (Node) & "matching NSpan", Node.Char);
5873 while Cursor < Length
5874 and then Subject (Cursor + 1) = Node.Char
5875 loop
5876 Cursor := Cursor + 1;
5877 end loop;
5879 goto Succeed;
5881 -- NSpan (character set case)
5883 when PC_NSpan_CS =>
5884 Dout (Img (Node) & "matching NSpan", Node.CS);
5886 while Cursor < Length
5887 and then Is_In (Subject (Cursor + 1), Node.CS)
5888 loop
5889 Cursor := Cursor + 1;
5890 end loop;
5892 goto Succeed;
5894 -- NSpan (string function case)
5896 when PC_NSpan_VF => declare
5897 U : constant VString := Node.VF.all;
5898 S : Big_String_Access;
5899 L : Natural;
5901 begin
5902 Get_String (U, S, L);
5903 Dout (Img (Node) & "matching NSpan", S (1 .. L));
5905 while Cursor < Length
5906 and then Is_In (Subject (Cursor + 1), S (1 .. L))
5907 loop
5908 Cursor := Cursor + 1;
5909 end loop;
5911 goto Succeed;
5912 end;
5914 -- NSpan (string pointer case)
5916 when PC_NSpan_VP => declare
5917 U : constant VString := Node.VP.all;
5918 S : Big_String_Access;
5919 L : Natural;
5921 begin
5922 Get_String (U, S, L);
5923 Dout (Img (Node) & "matching NSpan", S (1 .. L));
5925 while Cursor < Length
5926 and then Is_In (Subject (Cursor + 1), S (1 .. L))
5927 loop
5928 Cursor := Cursor + 1;
5929 end loop;
5931 goto Succeed;
5932 end;
5934 when PC_Null =>
5935 Dout (Img (Node) & "matching null");
5936 goto Succeed;
5938 -- Pos (integer case)
5940 when PC_Pos_Nat =>
5941 Dout (Img (Node) & "matching Pos", Node.Nat);
5943 if Cursor = Node.Nat then
5944 goto Succeed;
5945 else
5946 goto Fail;
5947 end if;
5949 -- Pos (Integer function case)
5951 when PC_Pos_NF => declare
5952 N : constant Natural := Node.NF.all;
5954 begin
5955 Dout (Img (Node) & "matching Pos", N);
5957 if Cursor = N then
5958 goto Succeed;
5959 else
5960 goto Fail;
5961 end if;
5962 end;
5964 -- Pos (integer pointer case)
5966 when PC_Pos_NP =>
5967 Dout (Img (Node) & "matching Pos", Node.NP.all);
5969 if Cursor = Node.NP.all then
5970 goto Succeed;
5971 else
5972 goto Fail;
5973 end if;
5975 -- Predicate function
5977 when PC_Pred_Func =>
5978 Dout (Img (Node) & "matching predicate function");
5980 if Node.BF.all then
5981 goto Succeed;
5982 else
5983 goto Fail;
5984 end if;
5986 -- Region Enter. Initiate new pattern history stack region
5988 when PC_R_Enter =>
5989 Dout (Img (Node) & "starting match of nested pattern");
5990 Stack (Stack_Ptr + 1).Cursor := Cursor;
5991 Push_Region;
5992 goto Succeed;
5994 -- Region Remove node. This is the node stacked by an R_Enter.
5995 -- It removes the special format stack entry right underneath, and
5996 -- then restores the outer level stack base and signals failure.
5998 -- Note: the cursor value at this stage is actually the (negative)
5999 -- stack base value for the outer level.
6001 when PC_R_Remove =>
6002 Dout ("failure, match of nested pattern terminated");
6003 Stack_Base := Cursor;
6004 Region_Level := Region_Level - 1;
6005 Stack_Ptr := Stack_Ptr - 1;
6006 goto Fail;
6008 -- Region restore node. This is the node stacked at the end of an
6009 -- inner level match. Its function is to restore the inner level
6010 -- region, so that alternatives in this region can be sought.
6012 -- Note: the Cursor at this stage is actually the negative of the
6013 -- inner stack base value, which we use to restore the inner region.
6015 when PC_R_Restore =>
6016 Dout ("failure, search for alternatives in nested pattern");
6017 Region_Level := Region_Level + 1;
6018 Stack_Base := Cursor;
6019 goto Fail;
6021 -- Rest
6023 when PC_Rest =>
6024 Dout (Img (Node) & "matching Rest");
6025 Cursor := Length;
6026 goto Succeed;
6028 -- Initiate recursive match (pattern pointer case)
6030 when PC_Rpat =>
6031 Stack (Stack_Ptr + 1).Node := Node.Pthen;
6032 Push_Region;
6033 Dout (Img (Node) & "initiating recursive match");
6035 if Stack_Ptr + Node.PP.all.Stk >= Stack_Size then
6036 raise Pattern_Stack_Overflow;
6037 else
6038 Node := Node.PP.all.P;
6039 goto Match;
6040 end if;
6042 -- RPos (integer case)
6044 when PC_RPos_Nat =>
6045 Dout (Img (Node) & "matching RPos", Node.Nat);
6047 if Cursor = (Length - Node.Nat) then
6048 goto Succeed;
6049 else
6050 goto Fail;
6051 end if;
6053 -- RPos (integer function case)
6055 when PC_RPos_NF => declare
6056 N : constant Natural := Node.NF.all;
6058 begin
6059 Dout (Img (Node) & "matching RPos", N);
6061 if Length - Cursor = N then
6062 goto Succeed;
6063 else
6064 goto Fail;
6065 end if;
6066 end;
6068 -- RPos (integer pointer case)
6070 when PC_RPos_NP =>
6071 Dout (Img (Node) & "matching RPos", Node.NP.all);
6073 if Cursor = (Length - Node.NP.all) then
6074 goto Succeed;
6075 else
6076 goto Fail;
6077 end if;
6079 -- RTab (integer case)
6081 when PC_RTab_Nat =>
6082 Dout (Img (Node) & "matching RTab", Node.Nat);
6084 if Cursor <= (Length - Node.Nat) then
6085 Cursor := Length - Node.Nat;
6086 goto Succeed;
6087 else
6088 goto Fail;
6089 end if;
6091 -- RTab (integer function case)
6093 when PC_RTab_NF => declare
6094 N : constant Natural := Node.NF.all;
6096 begin
6097 Dout (Img (Node) & "matching RPos", N);
6099 if Length - Cursor >= N then
6100 Cursor := Length - N;
6101 goto Succeed;
6102 else
6103 goto Fail;
6104 end if;
6105 end;
6107 -- RTab (integer pointer case)
6109 when PC_RTab_NP =>
6110 Dout (Img (Node) & "matching RPos", Node.NP.all);
6112 if Cursor <= (Length - Node.NP.all) then
6113 Cursor := Length - Node.NP.all;
6114 goto Succeed;
6115 else
6116 goto Fail;
6117 end if;
6119 -- Cursor assignment
6121 when PC_Setcur =>
6122 Dout (Img (Node) & "matching Setcur");
6123 Node.Var.all := Cursor;
6124 goto Succeed;
6126 -- Span (one character case)
6128 when PC_Span_CH => declare
6129 P : Natural := Cursor;
6131 begin
6132 Dout (Img (Node) & "matching Span", Node.Char);
6134 while P < Length
6135 and then Subject (P + 1) = Node.Char
6136 loop
6137 P := P + 1;
6138 end loop;
6140 if P /= Cursor then
6141 Cursor := P;
6142 goto Succeed;
6143 else
6144 goto Fail;
6145 end if;
6146 end;
6148 -- Span (character set case)
6150 when PC_Span_CS => declare
6151 P : Natural := Cursor;
6153 begin
6154 Dout (Img (Node) & "matching Span", Node.CS);
6156 while P < Length
6157 and then Is_In (Subject (P + 1), Node.CS)
6158 loop
6159 P := P + 1;
6160 end loop;
6162 if P /= Cursor then
6163 Cursor := P;
6164 goto Succeed;
6165 else
6166 goto Fail;
6167 end if;
6168 end;
6170 -- Span (string function case)
6172 when PC_Span_VF => declare
6173 U : constant VString := Node.VF.all;
6174 S : Big_String_Access;
6175 L : Natural;
6176 P : Natural;
6178 begin
6179 Get_String (U, S, L);
6180 Dout (Img (Node) & "matching Span", S (1 .. L));
6182 P := Cursor;
6183 while P < Length
6184 and then Is_In (Subject (P + 1), S (1 .. L))
6185 loop
6186 P := P + 1;
6187 end loop;
6189 if P /= Cursor then
6190 Cursor := P;
6191 goto Succeed;
6192 else
6193 goto Fail;
6194 end if;
6195 end;
6197 -- Span (string pointer case)
6199 when PC_Span_VP => declare
6200 U : constant VString := Node.VP.all;
6201 S : Big_String_Access;
6202 L : Natural;
6203 P : Natural;
6205 begin
6206 Get_String (U, S, L);
6207 Dout (Img (Node) & "matching Span", S (1 .. L));
6209 P := Cursor;
6210 while P < Length
6211 and then Is_In (Subject (P + 1), S (1 .. L))
6212 loop
6213 P := P + 1;
6214 end loop;
6216 if P /= Cursor then
6217 Cursor := P;
6218 goto Succeed;
6219 else
6220 goto Fail;
6221 end if;
6222 end;
6224 -- String (two character case)
6226 when PC_String_2 =>
6227 Dout (Img (Node) & "matching " & Image (Node.Str2));
6229 if (Length - Cursor) >= 2
6230 and then Subject (Cursor + 1 .. Cursor + 2) = Node.Str2
6231 then
6232 Cursor := Cursor + 2;
6233 goto Succeed;
6234 else
6235 goto Fail;
6236 end if;
6238 -- String (three character case)
6240 when PC_String_3 =>
6241 Dout (Img (Node) & "matching " & Image (Node.Str3));
6243 if (Length - Cursor) >= 3
6244 and then Subject (Cursor + 1 .. Cursor + 3) = Node.Str3
6245 then
6246 Cursor := Cursor + 3;
6247 goto Succeed;
6248 else
6249 goto Fail;
6250 end if;
6252 -- String (four character case)
6254 when PC_String_4 =>
6255 Dout (Img (Node) & "matching " & Image (Node.Str4));
6257 if (Length - Cursor) >= 4
6258 and then Subject (Cursor + 1 .. Cursor + 4) = Node.Str4
6259 then
6260 Cursor := Cursor + 4;
6261 goto Succeed;
6262 else
6263 goto Fail;
6264 end if;
6266 -- String (five character case)
6268 when PC_String_5 =>
6269 Dout (Img (Node) & "matching " & Image (Node.Str5));
6271 if (Length - Cursor) >= 5
6272 and then Subject (Cursor + 1 .. Cursor + 5) = Node.Str5
6273 then
6274 Cursor := Cursor + 5;
6275 goto Succeed;
6276 else
6277 goto Fail;
6278 end if;
6280 -- String (six character case)
6282 when PC_String_6 =>
6283 Dout (Img (Node) & "matching " & Image (Node.Str6));
6285 if (Length - Cursor) >= 6
6286 and then Subject (Cursor + 1 .. Cursor + 6) = Node.Str6
6287 then
6288 Cursor := Cursor + 6;
6289 goto Succeed;
6290 else
6291 goto Fail;
6292 end if;
6294 -- String (case of more than six characters)
6296 when PC_String => declare
6297 Len : constant Natural := Node.Str'Length;
6299 begin
6300 Dout (Img (Node) & "matching " & Image (Node.Str.all));
6302 if (Length - Cursor) >= Len
6303 and then Node.Str.all = Subject (Cursor + 1 .. Cursor + Len)
6304 then
6305 Cursor := Cursor + Len;
6306 goto Succeed;
6307 else
6308 goto Fail;
6309 end if;
6310 end;
6312 -- String (function case)
6314 when PC_String_VF => declare
6315 U : constant VString := Node.VF.all;
6316 S : Big_String_Access;
6317 L : Natural;
6319 begin
6320 Get_String (U, S, L);
6321 Dout (Img (Node) & "matching " & Image (S (1 .. L)));
6323 if (Length - Cursor) >= L
6324 and then S (1 .. L) = Subject (Cursor + 1 .. Cursor + L)
6325 then
6326 Cursor := Cursor + L;
6327 goto Succeed;
6328 else
6329 goto Fail;
6330 end if;
6331 end;
6333 -- String (vstring pointer case)
6335 when PC_String_VP => declare
6336 U : constant VString := Node.VP.all;
6337 S : Big_String_Access;
6338 L : Natural;
6340 begin
6341 Get_String (U, S, L);
6342 Dout (Img (Node) & "matching " & Image (S (1 .. L)));
6344 if (Length - Cursor) >= L
6345 and then S (1 .. L) = Subject (Cursor + 1 .. Cursor + L)
6346 then
6347 Cursor := Cursor + L;
6348 goto Succeed;
6349 else
6350 goto Fail;
6351 end if;
6352 end;
6354 -- Succeed
6356 when PC_Succeed =>
6357 Dout (Img (Node) & "matching Succeed");
6358 Push (Node);
6359 goto Succeed;
6361 -- Tab (integer case)
6363 when PC_Tab_Nat =>
6364 Dout (Img (Node) & "matching Tab", Node.Nat);
6366 if Cursor <= Node.Nat then
6367 Cursor := Node.Nat;
6368 goto Succeed;
6369 else
6370 goto Fail;
6371 end if;
6373 -- Tab (integer function case)
6375 when PC_Tab_NF => declare
6376 N : constant Natural := Node.NF.all;
6378 begin
6379 Dout (Img (Node) & "matching Tab ", N);
6381 if Cursor <= N then
6382 Cursor := N;
6383 goto Succeed;
6384 else
6385 goto Fail;
6386 end if;
6387 end;
6389 -- Tab (integer pointer case)
6391 when PC_Tab_NP =>
6392 Dout (Img (Node) & "matching Tab ", Node.NP.all);
6394 if Cursor <= Node.NP.all then
6395 Cursor := Node.NP.all;
6396 goto Succeed;
6397 else
6398 goto Fail;
6399 end if;
6401 -- Unanchored movement
6403 when PC_Unanchored =>
6404 Dout ("attempting to move anchor point");
6406 -- All done if we tried every position
6408 if Cursor > Length then
6409 goto Match_Fail;
6411 -- Otherwise extend the anchor point, and restack ourself
6413 else
6414 Cursor := Cursor + 1;
6415 Push (Node);
6416 goto Succeed;
6417 end if;
6419 -- Write immediate. This node performs the actual write
6421 when PC_Write_Imm =>
6422 Dout (Img (Node) & "executing immediate write of " &
6423 Subject (Stack (Stack_Base - 1).Cursor + 1 .. Cursor));
6425 Put_Line
6426 (Node.FP.all,
6427 Subject (Stack (Stack_Base - 1).Cursor + 1 .. Cursor));
6428 Pop_Region;
6429 goto Succeed;
6431 -- Write on match. This node sets up for the eventual write
6433 when PC_Write_OnM =>
6434 Dout (Img (Node) & "registering deferred write");
6435 Stack (Stack_Base - 1).Node := Node;
6436 Push (CP_Assign'Access);
6437 Pop_Region;
6438 Assign_OnM := True;
6439 goto Succeed;
6441 end case;
6443 -- We are NOT allowed to fall though this case statement, since every
6444 -- match routine must end by executing a goto to the appropriate point
6445 -- in the finite state machine model.
6447 pragma Warnings (Off);
6448 Logic_Error;
6449 pragma Warnings (On);
6450 end XMatchD;
6452 end GNAT.Spitbol.Patterns;