home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / adav313.zip / gnat-3_13p-os2-bin-20010916.zip / emx / gnatlib / g-spipat.adb < prev    next >
Text File  |  2000-07-19  |  194KB  |  6,290 lines

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