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-regpat.adb < prev    next >
Text File  |  2000-07-19  |  108KB  |  3,265 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT LIBRARY COMPONENTS                          --
  4. --                                                                          --
  5. --                          G N A T . R E G P A T                           --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.13 $
  10. --                                                                          --
  11. --               Copyright (C) 1986 by University of Toronto.               --
  12. --           Copyright (C) 1996-2000 Ada Core Technologies, Inc.            --
  13. --                                                                          --
  14. -- GNAT is free software;  you can  redistribute it  and/or modify it under --
  15. -- terms of the  GNU General Public License as published  by the Free Soft- --
  16. -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
  17. -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  18. -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  19. -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
  20. -- for  more details.  You should have  received  a copy of the GNU General --
  21. -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
  22. -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
  23. -- MA 02111-1307, USA.                                                      --
  24. --                                                                          --
  25. -- As a special exception,  if other files  instantiate  generics from this --
  26. -- unit, or you link  this unit with other files  to produce an executable, --
  27. -- this  unit  does not  by itself cause  the resulting  executable  to  be --
  28. -- covered  by the  GNU  General  Public  License.  This exception does not --
  29. -- however invalidate  any other reasons why  the executable file  might be --
  30. -- covered by the  GNU Public License.                                      --
  31. --                                                                          --
  32. -- GNAT is maintained by Ada Core Technologies Inc (http://www.gnat.com).   --
  33. --                                                                          --
  34. ------------------------------------------------------------------------------
  35.  
  36. --  This is an altered Ada 95 version of the original V8 style regular
  37. --  expression library written in C by Henry Spencer. Apart from the
  38. --  translation to Ada, the interface has been considerably changed to
  39. --  use the Ada String type instead of C-style nul-terminated strings.
  40.  
  41. --  Beware that some of this code is subtly aware of the way operator
  42. --  precedence is structured in regular expressions. Serious changes in
  43. --  regular-expression syntax might require a total rethink.
  44.  
  45. with System.IO;                use System.IO;
  46. with Ada.Characters.Handling;  use Ada.Characters.Handling;
  47.  
  48. package body GNAT.Regpat is
  49.  
  50.    MAGIC : constant Character := Character'Val (10#0234#);
  51.    --  The first byte of the regexp internal "program" is actually
  52.    --  this magic number; the start node begins in the second byte.
  53.    --
  54.    --  This is used to make sure that a regular expression was correctly
  55.    --  compiled.
  56.  
  57.    ----------------------------
  58.    -- Implementation details --
  59.    ----------------------------
  60.  
  61.    --  This is essentially a linear encoding of a nondeterministic
  62.    --  finite-state machine, also known as syntax charts or
  63.    --  "railroad normal form" in parsing technology.
  64.  
  65.    --  Each node is an opcode plus a "next" pointer, possibly plus an
  66.    --  operand. "Next" pointers of all nodes except BRANCH implement
  67.    --  concatenation; a "next" pointer with a BRANCH on both ends of it
  68.    --  is connecting two alternatives.
  69.  
  70.    --  The operand of some types of node is a literal string; for others,
  71.    --  it is a node leading into a sub-FSM. In particular, the operand of
  72.    --  a BRANCH node is the first node of the branch.
  73.    --  (NB this is *not* a tree structure:  the tail of the branch connects
  74.    --  to the thing following the set of BRANCHes).
  75.  
  76.    --  You can see the exact byte-compiled version by using the Dump
  77.    --  subprogram. However, here are a few examples:
  78.    --  (a|b):  1 : MAGIC
  79.    --          2 : BRANCH  (next at  10)
  80.    --          5 :    EXACT  (next at  18)   operand=a
  81.    --         10 : BRANCH  (next at  18)
  82.    --         13 :    EXACT  (next at  18)   operand=b
  83.    --         18 : EOP  (next at 0)
  84.    --
  85.    --  (ab)*:  1 : MAGIC
  86.    --          2 : CURLYX  (next at  26)  { 0, 32767}
  87.    --          9 :    OPEN 1  (next at  13)
  88.    --         13 :       EXACT  (next at  19)   operand=ab
  89.    --         19 :    CLOSE 1  (next at  23)
  90.    --         23 :    WHILEM  (next at 0)
  91.    --         26 : NOTHING  (next at  29)
  92.    --         29 : EOP  (next at 0)
  93.  
  94.  
  95.  
  96.    --  The opcodes are:
  97.  
  98.    type Opcode is
  99.    --    Name        Operand?  Meaning
  100.      (EOP,        -- no        End of program
  101.       MINMOD,     -- no        Next operator is not greedy
  102.  
  103.       --  Classes of characters
  104.       ANY,        -- no        Match any one character except newline
  105.       SANY,       -- no        Match any character, including new line
  106.       ANYOF,      -- class     Match any character in this class
  107.       EXACT,      -- str       Match this string exactly
  108.       EXACTF,     -- str       Match this string (case-folding is one)
  109.       NOTHING,    -- no        Match empty string
  110.       SPACE,      -- no        Match any whitespace character
  111.       NSPACE,     -- no        Match any non-whitespace character
  112.       DIGIT,      -- no        Match any numeric character
  113.       NDIGIT,     -- no        Match any non-numeric character
  114.       ALNUM,      -- no        Match any alphanumeric character
  115.       NALNUM,     -- no        Match any non-alphanumeric character
  116.  
  117.       --  Branches
  118.       BRANCH,     -- node      Match this alternative, or the next
  119.  
  120.       --  Simple loops (when the following node is one character in length)
  121.  
  122.       STAR,       -- node      Match this simple thing 0 or more times
  123.       PLUS,       -- node      Match this simple thing 1 or more times
  124.       CURLY,      -- 2num node Match this simple thing between n and m times.
  125.  
  126.       --  Complex loops
  127.  
  128.       CURLYX,     -- 2num node Match this complex thing {n,m} times
  129.       --                       The nums are coded on two characters each.
  130.       WHILEM,     -- no        Do curly processing and see if rest matches
  131.  
  132.       --  Matches after or before a word
  133.  
  134.       BOL,        -- no        Match "" at beginning of line
  135.       MBOL,       -- no        Same, assuming mutiline (match after \n)
  136.       SBOL,       -- no        Same, assuming single line (don't match at \n)
  137.       EOL,        -- no        Match "" at end of line
  138.       MEOL,       -- no        Same, assuming mutiline (match before \n)
  139.       SEOL,       -- no        Same, assuming single line (don't match at \n)
  140.  
  141.       BOUND,      -- no        Match "" at any word boundary
  142.       NBOUND,     -- no        Match "" at any word non-boundary
  143.  
  144.       --  Parenthesis groups handling
  145.  
  146.       REFF,       -- num       Match some already matched string, folded
  147.       OPEN,       -- num       Mark this point in input as start of #n
  148.       CLOSE);     -- num       Analogous to OPEN
  149.  
  150.    for Opcode'Size use 8;
  151.  
  152.  
  153.    --  Opcode notes:
  154.  
  155.    --  BRANCH
  156.    --    The set of branches constituting a single choice are hooked
  157.    --    together with their "next" pointers, since precedence prevents
  158.    --    anything being concatenated to any individual branch. The
  159.    --    "next" pointer of the last BRANCH in a choice points to the
  160.    --    thing following the whole choice. This is also where the
  161.    --    final "next" pointer of each individual branch points; each
  162.    --    branch starts with the operand node of a BRANCH node.
  163.  
  164.    --  STAR,PLUS
  165.    --    '?', and complex '*' and '+', are implemented with CURLYX.
  166.    --    branches. Simple cases (one character per match) are implemented with
  167.    --    STAR and PLUS for speed and to minimize recursive plunges.
  168.  
  169.    --  OPEN,CLOSE
  170.    --    ...are numbered at compile time.
  171.  
  172.    --  EXACT, EXACTF
  173.    --    There are in fact two arguments, the first one is the length (minus
  174.    --    one of the string argument), coded on one character, the second
  175.    --    argument is the string itself, coded on length + 1 characters.
  176.  
  177.    --  A node is one char of opcode followed by two chars of "next" pointer.
  178.    --  "Next" pointers are stored as two 8-bit pieces, high order first. The
  179.    --  value is a positive offset from the opcode of the node containing it.
  180.    --  An operand, if any, simply follows the node. (Note that much of the
  181.    --  code generation knows about this implicit relationship.)
  182.  
  183.    --  Using two bytes for the "next" pointer is vast overkill for most
  184.    --  things, but allows patterns to get big without disasters.
  185.  
  186.    -----------------------
  187.    -- Character classes --
  188.    -----------------------
  189.    --  This is the implementation for character classes ([...]) in the
  190.    --  syntax for regular expressions. Each character (0..256) has an
  191.    --  entry into the table. This makes for a very fast matching
  192.    --  algorithm.
  193.  
  194.    type Class_Byte is mod 256;
  195.    type Character_Class is array (Class_Byte range 0 .. 31) of Class_Byte;
  196.  
  197.    type Bit_Conversion_Array is array (Class_Byte range 0 .. 7) of Class_Byte;
  198.    Bit_Conversion : constant Bit_Conversion_Array
  199.      := (1, 2, 4, 8, 16, 32, 64, 128);
  200.  
  201.    type Std_Class is (ANYOF_NONE,
  202.                       ANYOF_ALNUM,   --  Alphanumeric class [a-zA-Z0-9]
  203.                       ANYOF_NALNUM,
  204.                       ANYOF_SPACE,   --  Space class [ \t\n\r\f]
  205.                       ANYOF_NSPACE,
  206.                       ANYOF_DIGIT,   --  Digit class [0-9]
  207.                       ANYOF_NDIGIT,
  208.                       ANYOF_ALNUMC,  --  Alphanumeric class [a-zA-Z0-9]
  209.                       ANYOF_NALNUMC,
  210.                       ANYOF_ALPHA,   --  Alpha class [a-zA-Z]
  211.                       ANYOF_NALPHA,
  212.                       ANYOF_ASCII,   --  Ascii class (7 bits) 0..127
  213.                       ANYOF_NASCII,
  214.                       ANYOF_CNTRL,   --  Control class
  215.                       ANYOF_NCNTRL,
  216.                       ANYOF_GRAPH,   --  Graphic class
  217.                       ANYOF_NGRAPH,
  218.                       ANYOF_LOWER,   --  Lower case class [a-z]
  219.                       ANYOF_NLOWER,
  220.                       ANYOF_PRINT,   --  printable class
  221.                       ANYOF_NPRINT,
  222.                       ANYOF_PUNCT,   --
  223.                       ANYOF_NPUNCT,
  224.                       ANYOF_UPPER,   --  Upper case class [A-Z]
  225.                       ANYOF_NUPPER,
  226.                       ANYOF_XDIGIT,  --  Hexadecimal digit
  227.                       ANYOF_NXDIGIT
  228.                       );
  229.  
  230.    procedure Set_In_Class (Bitmap : in out Character_Class;
  231.                            C      : Character);
  232.    --  Set the entry to True for C in the class Bitmap.
  233.  
  234.    function Get_From_Class (Bitmap : Character_Class;
  235.                             C      : Character)
  236.                            return Boolean;
  237.    --  Return True if the entry is set for C in the class Bitmap.
  238.  
  239.    procedure Reset_Class (Bitmap : in out Character_Class);
  240.    --  Clear all the entries in the class Bitmap.
  241.  
  242.    pragma Inline (Set_In_Class);
  243.    pragma Inline (Get_From_Class);
  244.    pragma Inline (Reset_Class);
  245.  
  246.    -----------------------
  247.    -- Local Subprograms --
  248.    -----------------------
  249.  
  250.    function "+" (Left : Opcode;    Right : Integer) return Opcode;
  251.    function "-" (Left : Opcode;    Right : Opcode) return Integer;
  252.    function "=" (Left : Character; Right : Opcode) return Boolean;
  253.  
  254.    function Is_Alnum (C : Character) return Boolean;
  255.    --  Return True if C is an alphanum character or an underscore ('_')
  256.  
  257.    function Is_Space (C : Character) return Boolean;
  258.    --  Return True if C is a whitespace character
  259.  
  260.    function Is_Printable (C : Character) return Boolean;
  261.    --  Return True if C is a printable character
  262.  
  263.    function Operand (P : Pointer) return Pointer;
  264.    --  Return a pointer to the first operand of the node at P
  265.  
  266.    function String_Length (Program : Program_Data;
  267.                            P : Pointer)
  268.                           return Program_Size;
  269.    --  Return the length of the string argument of the node at P
  270.  
  271.    function String_Operand (P : Pointer) return Pointer;
  272.    --  Return a pointer to the string argument of the node at P
  273.  
  274.    function Bitmap_Operand (Program : Program_Data;
  275.                             P : Pointer)
  276.                            return Character_Class;
  277.    --  Return a pointer to the string argument of the node at P
  278.  
  279.    function Get_Next_Offset
  280.      (Program : Program_Data;
  281.       IP      : Pointer) return Pointer;
  282.    --  Get the offset field of a node. Used by Get_Next.
  283.  
  284.    function Get_Next
  285.      (Program : Program_Data;
  286.       IP      : Pointer) return Pointer;
  287.    --  Dig the next instruction pointer out of a node
  288.  
  289.    procedure Optimize
  290.      (Self              : in out Pattern_Matcher);
  291.    --  Optimize a Pattern_Matcher by noting certain special cases
  292.  
  293.    function Read_Natural (Program : Program_Data;
  294.                           IP : Pointer)
  295.                          return Natural;
  296.    --  Return the 2-byte natural coded at position IP.
  297.  
  298.  
  299.    --  All of the subprograms above are tiny and should be inlined
  300.  
  301.    pragma Inline ("+");
  302.    pragma Inline ("-");
  303.    pragma Inline ("=");
  304.    pragma Inline (Is_Alnum);
  305.    pragma Inline (Is_Space);
  306.    pragma Inline (Get_Next);
  307.    pragma Inline (Get_Next_Offset);
  308.    pragma Inline (Operand);
  309.    pragma Inline (Read_Natural);
  310.    pragma Inline (String_Length);
  311.    pragma Inline (String_Operand);
  312.  
  313.    type Expression_Flags is record
  314.       Has_Width,            -- Known never to match null string
  315.       Simple,               -- Simple enough to be STAR/PLUS operand
  316.       SP_Start  : Boolean;  -- Starts with * or +
  317.    end record;
  318.  
  319.    Worst_Expression : constant Expression_Flags := (others => False);
  320.    --  Worst case
  321.  
  322.    ---------
  323.    -- "=" --
  324.    ---------
  325.  
  326.    function "=" (Left : Character; Right : Opcode) return Boolean is
  327.    begin
  328.       return Character'Pos (Left) = Opcode'Pos (Right);
  329.    end "=";
  330.  
  331.    ---------
  332.    -- "+" --
  333.    ---------
  334.  
  335.    function "+" (Left : Opcode; Right : Integer) return Opcode is
  336.    begin
  337.       return Opcode'Val (Opcode'Pos (Left) + Right);
  338.    end "+";
  339.  
  340.    ---------
  341.    -- "-" --
  342.    ---------
  343.  
  344.    function "-" (Left : Opcode; Right : Opcode) return Integer is
  345.    begin
  346.       return Opcode'Pos (Left) - Opcode'Pos (Right);
  347.    end "-";
  348.  
  349.    --------------
  350.    -- Is_Alnum --
  351.    --------------
  352.  
  353.    function Is_Alnum (C : Character) return Boolean is
  354.    begin
  355.       return Is_Alphanumeric (C) or else C = '_';
  356.    end Is_Alnum;
  357.  
  358.    ------------------
  359.    -- Is_Printable --
  360.    ------------------
  361.  
  362.    function Is_Printable (C : Character) return Boolean is
  363.       Value : constant Natural := Character'Pos (C);
  364.    begin
  365.       return (Value > 32 and then Value < 127)
  366.         or else Is_Space (C);
  367.    end Is_Printable;
  368.  
  369.    --------------
  370.    -- Is_Space --
  371.    --------------
  372.  
  373.    function Is_Space (C : Character) return Boolean is
  374.    begin
  375.       return C = ' '
  376.         or else C = ASCII.HT
  377.         or else C = ASCII.CR
  378.         or else C = ASCII.LF
  379.         or else C = ASCII.VT
  380.         or else C = ASCII.FF;
  381.    end Is_Space;
  382.  
  383.    -------------
  384.    -- Operand --
  385.    -------------
  386.  
  387.    function Operand (P : Pointer) return Pointer is
  388.    begin
  389.       return P + 3;
  390.    end Operand;
  391.  
  392.    --------------------
  393.    -- String_Operand --
  394.    --------------------
  395.  
  396.    function String_Operand (P : Pointer) return Pointer is
  397.    begin
  398.       return P + 4;
  399.    end String_Operand;
  400.  
  401.    --------------------
  402.    -- Bitmap_Operand --
  403.    --------------------
  404.  
  405.    function Bitmap_Operand (Program : Program_Data;
  406.                             P : Pointer)
  407.                            return Character_Class
  408.    is
  409.       Bitmap : Character_Class;
  410.    begin
  411.       for J in 0 .. Class_Byte'(31) loop
  412.          Bitmap (J) := Character'Pos (Program (P + 3 + Program_Size (J)));
  413.       end loop;
  414.       return Bitmap;
  415.    end Bitmap_Operand;
  416.  
  417.    -------------------
  418.    -- String_Length --
  419.    -------------------
  420.  
  421.    function String_Length (Program : Program_Data;
  422.                            P : Pointer)
  423.                           return Program_Size
  424.    is
  425.    begin
  426.       pragma Assert (Program (P) = EXACT or else Program (P) = EXACTF);
  427.       return Character'Pos (Program (P + 3));
  428.    end String_Length;
  429.  
  430.    ------------------
  431.    -- Read_Natural --
  432.    ------------------
  433.  
  434.    function Read_Natural (Program : Program_Data;
  435.                           IP : Pointer)
  436.                          return Natural
  437.    is
  438.    begin
  439.       return Character'Pos (Program (IP))
  440.         + 256 * Character'Pos (Program (IP + 1));
  441.    end Read_Natural;
  442.  
  443.    ---------------------
  444.    -- Get_Next_Offset --
  445.    ---------------------
  446.  
  447.    function Get_Next_Offset
  448.      (Program : Program_Data;
  449.       IP      : Pointer)
  450.       return    Pointer
  451.    is
  452.    begin
  453.       return Pointer (Read_Natural (Program, IP + 1));
  454.    end Get_Next_Offset;
  455.  
  456.    --------------
  457.    -- Get_Next --
  458.    --------------
  459.  
  460.    function Get_Next (Program : Program_Data; IP : Pointer) return Pointer is
  461.       Offset : constant Pointer := Get_Next_Offset (Program, IP);
  462.  
  463.    begin
  464.       if Offset = 0 then
  465.          return 0;
  466.       else
  467.          return IP + Offset;
  468.       end if;
  469.    end Get_Next;
  470.  
  471.    ------------------
  472.    -- Set_In_Class --
  473.    ------------------
  474.  
  475.    procedure Set_In_Class (Bitmap : in out Character_Class;
  476.                            C      : Character)
  477.    is
  478.       Value : constant Class_Byte := Character'Pos (C);
  479.    begin
  480.       Bitmap (Value / 8) := Bitmap (Value / 8)
  481.         or Bit_Conversion (Value mod 8);
  482.    end Set_In_Class;
  483.  
  484.    --------------------
  485.    -- Get_From_Class --
  486.    --------------------
  487.  
  488.    function Get_From_Class (Bitmap : Character_Class;
  489.                             C      : Character)
  490.                            return Boolean
  491.    is
  492.       Value : constant Class_Byte := Character'Pos (C);
  493.    begin
  494.       return (Bitmap (Value / 8)
  495.               and Bit_Conversion (Value mod 8)) /= 0;
  496.    end Get_From_Class;
  497.  
  498.    -----------------
  499.    -- Reset_Class --
  500.    -----------------
  501.  
  502.    procedure Reset_Class (Bitmap : in out Character_Class) is
  503.    begin
  504.       Bitmap := (others => 0);
  505.    end Reset_Class;
  506.  
  507.    -------------
  508.    -- Compile --
  509.    -------------
  510.  
  511.    procedure Compile
  512.      (Matcher         : out Pattern_Matcher;
  513.       Expression      : String;
  514.       Final_Code_Size : out Program_Size;
  515.       Flags           : Regexp_Flags := No_Flags)
  516.    is
  517.       --  We can't allocate space until we know how big the compiled form
  518.       --  will be, but we can't compile it (and thus know how big it is)
  519.       --  until we've got a place to put the code. So we cheat: we compile
  520.       --  it twice, once with code generation turned off and size counting
  521.       --  turned on, and once "for real".
  522.  
  523.       --  This also means that we don't allocate space until we are sure
  524.       --  that the thing really will compile successfully, and we never
  525.       --  have to move the code and thus invalidate pointers into it.
  526.  
  527.       --  Beware that the optimization-preparation code in here knows
  528.       --  about some of the structure of the compiled regexp.
  529.  
  530.       PM        : Pattern_Matcher renames Matcher;
  531.       Program   : Program_Data renames PM.Program;
  532.  
  533.       Emit_Code : constant Boolean := PM.Size > 0;
  534.       Emit_Ptr  : Pointer := Program_First;
  535.  
  536.       Parse_Pos : Natural := Expression'First; -- Input-scan pointer
  537.       Parse_End : Natural := Expression'Last;
  538.  
  539.       ----------------------------
  540.       -- Subprograms for Create --
  541.       ----------------------------
  542.  
  543.       procedure Emit (B : Character);
  544.       --  Output the Character to the Program.
  545.       --  If code-generation is disables, simply increments the program
  546.       --  counter.
  547.  
  548.       function  Emit_Node (Op : Opcode) return Pointer;
  549.       --  If code-generation is enabled, Emit_Node outputs the
  550.       --  opcode and reserves space for a pointer to the next node.
  551.       --  Return value is the location of new opcode, ie old Emit_Ptr.
  552.  
  553.       procedure Emit_Natural (IP : Pointer; N : Natural);
  554.       --  Split N on two characters at position IP.
  555.  
  556.       procedure Emit_Class (Bitmap : Character_Class);
  557.       --  Emits a character class.
  558.  
  559.       procedure Case_Emit (C : Character);
  560.       --  Emit C, after converting is to lower-case if the regular
  561.       --  expression is case insensitive.
  562.  
  563.       procedure Parse
  564.         (Parenthesized : Boolean;
  565.          Flags         : in out Expression_Flags;
  566.          IP            : out Pointer);
  567.       --  Parse regular expression, i.e. main body or parenthesized thing
  568.       --  Caller must absorb opening parenthesis.
  569.  
  570.       procedure Parse_Branch
  571.         (Flags         : in out Expression_Flags;
  572.          First         : Boolean;
  573.          IP            : out Pointer);
  574.       --  Implements the concatenation operator and handles '|'
  575.       --  First should be true if this is the first item of the alternative.
  576.  
  577.       procedure Parse_Piece
  578.         (Expr_Flags : in out Expression_Flags; IP : out Pointer);
  579.       --  Parse something followed by possible [*+?]
  580.  
  581.       procedure Parse_Atom
  582.         (Expr_Flags : in out Expression_Flags; IP : out Pointer);
  583.       --  Parse_Atom is the lowest level parse procedure.
  584.       --  Optimization:  gobbles an entire sequence of ordinary characters
  585.       --  so that it can turn them into a single node, which is smaller to
  586.       --  store and faster to run. Backslashed characters are exceptions,
  587.       --  each becoming a separate node; the code is simpler that way and
  588.       --  it's not worth fixing.
  589.  
  590.       procedure Insert_Operator (Op       : Opcode;
  591.                                  Operand  : Pointer;
  592.                                  Greedy   : Boolean := True);
  593.       --  Insert_Operator inserts an operator in front of an
  594.       --  already-emitted operand and relocates the operand.
  595.       --  This applies to PLUS and STAR.
  596.       --  If Minmod is True, then the operator is non-greedy.
  597.  
  598.       procedure Insert_CURLY_Operator (Op      : Opcode;
  599.                                        Min     : Natural;
  600.                                        Max     : Natural;
  601.                                        Operand : Pointer;
  602.                                        Greedy  : Boolean := True);
  603.       --  Insert an operator for CURLY ({Min}, {Min,} or {Min,Max}).
  604.       --  If Minmod is True, then the operator is non-greedy.
  605.  
  606.       procedure Link_Tail (P, Val : Pointer);
  607.       --  Link_Tail sets the next-pointer at the end of a node chain
  608.  
  609.       procedure Link_Operand_Tail (P, Val : Pointer);
  610.       --  Link_Tail on operand of first argument; nop if operandless
  611.  
  612.       function  Next_Instruction (P : Pointer) return Pointer;
  613.       --  Dig the "next" pointer out of a node
  614.  
  615.       procedure Fail (M : in String);
  616.       --  Fail with a diagnostic message, if possible
  617.  
  618.       function Is_Curly_Operator (IP : Natural) return Boolean;
  619.       --  Return True if IP is looking at a '{' that is the beginning
  620.       --  of a curly operator, ie it matches {\d+,?\d*}
  621.  
  622.       function Is_Mult (IP : Natural) return Boolean;
  623.       --  Return True if C is a regexp multiplier: '+', '*' or '?'
  624.  
  625.       procedure Get_Curly_Arguments (IP     : Natural;
  626.                                      Min    : out Natural;
  627.                                      Max    : out Natural;
  628.                                      Greedy : out Boolean);
  629.       --  Parse the argument list for a curly operator.
  630.       --  It is assumed that IP is indeed pointing at a valid operator.
  631.  
  632.       procedure Parse_Character_Class (IP : out Pointer);
  633.       --  Parse a character class.
  634.       --  The calling subprogram should consume the opening '[' before.
  635.  
  636.       procedure Parse_Literal (Expr_Flags : in out Expression_Flags;
  637.                                IP : out Pointer);
  638.       --  Parse_Literal encodes a string of characters
  639.       --  to be matched exactly.
  640.  
  641.       function Parse_Posix_Character_Class return Std_Class;
  642.       --  Parse a posic character class, like [:alpha:] or [:^alpha:].
  643.       --  The called is suppoed to absorbe the opening [.
  644.  
  645.       pragma Inline (Is_Mult);
  646.       pragma Inline (Emit_Natural);
  647.       pragma Inline (Parse_Character_Class); --  since used only once
  648.  
  649.       -------------
  650.       -- Is_Mult --
  651.       -------------
  652.  
  653.       function Is_Mult (IP : Natural) return Boolean is
  654.          C : constant Character := Expression (IP);
  655.       begin
  656.          return     C = '*'
  657.            or else  C = '+'
  658.            or else  C = '?'
  659.            or else (C = '{' and then Is_Curly_Operator (IP));
  660.       end Is_Mult;
  661.  
  662.       -----------------------
  663.       -- Is_Curly_Operator --
  664.       -----------------------
  665.  
  666.       function Is_Curly_Operator (IP : Natural) return Boolean is
  667.          Scan : Natural := IP;
  668.       begin
  669.          if Expression (Scan) /= '{'
  670.            or else Scan + 2 > Expression'Last
  671.            or else not Is_Digit (Expression (Scan + 1))
  672.          then
  673.             return False;
  674.          end if;
  675.  
  676.          Scan := Scan + 1;
  677.  
  678.          --  The first digit
  679.  
  680.          loop
  681.             Scan := Scan + 1;
  682.             if Scan > Expression'Last then
  683.                return False;
  684.             end if;
  685.             exit when not Is_Digit (Expression (Scan));
  686.          end loop;
  687.  
  688.          if Expression (Scan) = ',' then
  689.             loop
  690.                Scan := Scan + 1;
  691.                if Scan > Expression'Last then
  692.                   return False;
  693.                end if;
  694.                exit when not Is_Digit (Expression (Scan));
  695.             end loop;
  696.          end if;
  697.  
  698.          return Expression (Scan) = '}';
  699.       end Is_Curly_Operator;
  700.  
  701.       -------------------------
  702.       -- Get_Curly_Arguments --
  703.       -------------------------
  704.  
  705.       procedure Get_Curly_Arguments (IP     : Natural;
  706.                                      Min    : out Natural;
  707.                                      Max    : out Natural;
  708.                                      Greedy : out Boolean)
  709.       is
  710.          Save_Pos : Natural := Parse_Pos + 1;
  711.  
  712.       begin
  713.          Min := 0;
  714.          Max := Max_Curly_Repeat;
  715.  
  716.          while Expression (Parse_Pos) /= '}'
  717.            and then Expression (Parse_Pos) /= ','
  718.          loop
  719.             Parse_Pos := Parse_Pos + 1;
  720.          end loop;
  721.  
  722.          Min := Natural'Value (Expression (Save_Pos .. Parse_Pos - 1));
  723.  
  724.          if Expression (Parse_Pos) = ',' then
  725.             Save_Pos := Parse_Pos + 1;
  726.             while Expression (Parse_Pos) /= '}' loop
  727.                Parse_Pos := Parse_Pos + 1;
  728.             end loop;
  729.             if Save_Pos /= Parse_Pos then
  730.                Max := Natural'Value (Expression (Save_Pos .. Parse_Pos - 1));
  731.             end if;
  732.          else
  733.             Max := Min;
  734.          end if;
  735.  
  736.          if Parse_Pos < Expression'Last
  737.            and then Expression (Parse_Pos + 1) = '?'
  738.          then
  739.             Greedy := False;
  740.             Parse_Pos := Parse_Pos + 1;
  741.          else
  742.             Greedy := True;
  743.          end if;
  744.       end Get_Curly_Arguments;
  745.  
  746.       ------------------
  747.       -- Emit_Natural --
  748.       ------------------
  749.  
  750.       procedure Emit_Natural (IP : Pointer; N : Natural) is
  751.       begin
  752.          if Emit_Code then
  753.             Program (IP + 1) := Character'Val (N / 256);
  754.             Program (IP) := Character'Val (N mod 256);
  755.          end if;
  756.       end Emit_Natural;
  757.  
  758.       ----------
  759.       -- Fail --
  760.       ----------
  761.  
  762.       procedure Fail (M : in String) is
  763.       begin
  764.          raise Expression_Error;
  765.       end Fail;
  766.  
  767.       -----------
  768.       -- Parse --
  769.       -----------
  770.  
  771.       --  Combining parenthesis handling with the base level
  772.       --  of regular expression is a trifle forced, but the
  773.       --  need to tie the tails of the branches to what follows
  774.       --  makes it hard to avoid.
  775.  
  776.       procedure Parse
  777.         (Parenthesized  : in Boolean;
  778.          Flags          : in out Expression_Flags;
  779.          IP             : out Pointer)
  780.       is
  781.          E              : String renames Expression;
  782.          Br             : Pointer;
  783.          Ender          : Pointer;
  784.          Par_No         : Natural;
  785.          New_Flags      : Expression_Flags;
  786.          Have_Branch    : Boolean := False;
  787.  
  788.       begin
  789.          Flags := (Has_Width => True, others => False);  -- Tentatively
  790.  
  791.          --  Make an OPEN node, if parenthesized
  792.  
  793.          if Parenthesized then
  794.             if Matcher.Num_Parenthesis > Max_Parenthesis then
  795.                Fail ("too many ()");
  796.             end if;
  797.  
  798.             Par_No := Matcher.Num_Parenthesis + 1;
  799.             Matcher.Num_Parenthesis := Matcher.Num_Parenthesis + 1;
  800.             IP := Emit_Node (OPEN);
  801.             Emit (Character'Val (Par_No));
  802.          else
  803.             IP := 0;
  804.          end if;
  805.  
  806.          --  Pick up the branches, linking them together
  807.  
  808.          Parse_Branch (New_Flags, True, Br);
  809.  
  810.          if Br = 0 then
  811.             IP := 0;
  812.             return;
  813.          end if;
  814.  
  815.          if Parse_Pos <= Parse_End
  816.            and then E (Parse_Pos) = '|'
  817.          then
  818.             Insert_Operator (BRANCH, Br);
  819.             Have_Branch := True;
  820.          end if;
  821.  
  822.          if IP /= 0 then
  823.             Link_Tail (IP, Br);   -- OPEN -> first
  824.          else
  825.             IP := Br;
  826.          end if;
  827.  
  828.          if not New_Flags.Has_Width then
  829.             Flags.Has_Width := False;
  830.          end if;
  831.  
  832.          Flags.SP_Start := Flags.SP_Start or New_Flags.SP_Start;
  833.  
  834.          while Parse_Pos <= Parse_End
  835.            and then (E (Parse_Pos) = '|')
  836.          loop
  837.             Parse_Pos := Parse_Pos + 1;
  838.             Parse_Branch (New_Flags, False, Br);
  839.  
  840.             if Br = 0 then
  841.                IP := 0;
  842.                return;
  843.             end if;
  844.  
  845.             Link_Tail (IP, Br);   -- BRANCH -> BRANCH
  846.  
  847.             if not New_Flags.Has_Width then
  848.                Flags.Has_Width := False;
  849.             end if;
  850.  
  851.             Flags.SP_Start := Flags.SP_Start or New_Flags.SP_Start;
  852.          end loop;
  853.  
  854.          --  Make a closing node, and hook it on the end
  855.  
  856.          if Parenthesized then
  857.             Ender := Emit_Node (CLOSE);
  858.             Emit (Character'Val (Par_No));
  859.          else
  860.             Ender := Emit_Node (EOP);
  861.          end if;
  862.  
  863.          Link_Tail (IP, Ender);
  864.  
  865.          if Have_Branch then
  866.  
  867.             --  Hook the tails of the branches to the closing node
  868.  
  869.             Br := IP;
  870.             loop
  871.                exit when Br = 0;
  872.                Link_Operand_Tail (Br, Ender);
  873.                Br := Next_Instruction (Br);
  874.             end loop;
  875.          end if;
  876.  
  877.          --  Check for proper termination
  878.  
  879.          if Parenthesized then
  880.             if Parse_Pos > Parse_End or else E (Parse_Pos) /= ')' then
  881.                Fail ("unmatched ()");
  882.             end if;
  883.  
  884.             Parse_Pos := Parse_Pos + 1;
  885.  
  886.          elsif Parse_Pos <= Parse_End then
  887.             if E (Parse_Pos) = ')'  then
  888.                Fail ("unmatched ()");
  889.             else
  890.                Fail ("junk on end");         -- "Can't happen"
  891.             end if;
  892.          end if;
  893.       end Parse;
  894.  
  895.       ------------------
  896.       -- Parse_Branch --
  897.       ------------------
  898.  
  899.       procedure Parse_Branch
  900.         (Flags : in out Expression_Flags;
  901.          First : Boolean;
  902.          IP    : out Pointer)
  903.       is
  904.          E         : String renames Expression;
  905.          Chain     : Pointer;
  906.          Last      : Pointer;
  907.          New_Flags : Expression_Flags;
  908.          Dummy     : Pointer;
  909.  
  910.       begin
  911.          Flags := Worst_Expression;    -- Tentatively
  912.  
  913.          if First then
  914.             IP := Emit_Ptr;
  915.          else
  916.             IP := Emit_Node (BRANCH);
  917.          end if;
  918.          Chain := 0;
  919.  
  920.          while Parse_Pos <= Parse_End
  921.            and then E (Parse_Pos) /= ')'
  922.            and then E (Parse_Pos) /= ASCII.LF
  923.            and then E (Parse_Pos) /= '|'
  924.          loop
  925.             Parse_Piece (New_Flags, Last);
  926.  
  927.             if Last = 0 then
  928.                IP := 0;
  929.                return;
  930.             end if;
  931.  
  932.             Flags.Has_Width := Flags.Has_Width or New_Flags.Has_Width;
  933.  
  934.             if Chain = 0 then            -- First piece
  935.                Flags.SP_Start := Flags.SP_Start or New_Flags.SP_Start;
  936.             else
  937.                Link_Tail (Chain, Last);
  938.             end if;
  939.  
  940.             Chain := Last;
  941.          end loop;
  942.  
  943.          if Chain = 0 then            -- Loop ran zero CURLY
  944.             Dummy := Emit_Node (NOTHING);
  945.          end if;
  946.  
  947.       end Parse_Branch;
  948.  
  949.       -----------------
  950.       -- Parse_Piece --
  951.       -----------------
  952.  
  953.       --  Note that the branching code sequences used for '?' and the
  954.       --  general cases of '*' and + are somewhat optimized: they use
  955.       --  the same NOTHING node as both the endmarker for their branch
  956.       --  list and the body of the last branch. It might seem that
  957.       --  this node could be dispensed with entirely, but the endmarker
  958.       --  role is not redundant.
  959.  
  960.       procedure Parse_Piece
  961.         (Expr_Flags : in out Expression_Flags;
  962.          IP    : out Pointer)
  963.       is
  964.          Op        : Character;
  965.          New_Flags : Expression_Flags;
  966.          Greedy    : Boolean := True;
  967.  
  968.       begin
  969.          Parse_Atom (New_Flags, IP);
  970.  
  971.          if IP = 0 then
  972.             return;
  973.          end if;
  974.  
  975.          if Parse_Pos > Parse_End
  976.            or else not Is_Mult (Parse_Pos)
  977.          then
  978.             Expr_Flags := New_Flags;
  979.             return;
  980.          end if;
  981.  
  982.          Op := Expression (Parse_Pos);
  983.  
  984.          if Op /= '+' then
  985.             Expr_Flags := (SP_Start => True, others => False);
  986.          else
  987.             Expr_Flags := (Has_Width => True, others => False);
  988.          end if;
  989.  
  990.          --  Detect non greedy operators in the easy cases
  991.  
  992.          if Op /= '{'
  993.            and then Parse_Pos + 1 <= Parse_End
  994.            and then Expression (Parse_Pos + 1) = '?'
  995.          then
  996.             Greedy := False;
  997.             Parse_Pos := Parse_Pos + 1;
  998.          end if;
  999.  
  1000.          --  Generate the byte code
  1001.  
  1002.          case Op is
  1003.             when '*' =>
  1004.  
  1005.                if New_Flags.Simple then
  1006.                   Insert_Operator (STAR, IP, Greedy);
  1007.  
  1008.                else
  1009.  
  1010.                   --  This is just like a CURLY operator with a minimal
  1011.                   --  number of repetition of 0.
  1012.  
  1013.                   Link_Tail (IP, Emit_Node (WHILEM));
  1014.                   Insert_CURLY_Operator (CURLYX, 0, Max_Curly_Repeat, IP,
  1015.                                          Greedy);
  1016.                   Link_Tail (IP, Emit_Node (NOTHING));
  1017.                end if;
  1018.  
  1019.             when '+' =>
  1020.  
  1021.                if New_Flags.Simple then
  1022.                   Insert_Operator (PLUS, IP, Greedy);
  1023.  
  1024.                else
  1025.                   --  This is just like a CURLY operator with a minimal
  1026.                   --  number of repetition of 1.
  1027.  
  1028.                   Link_Tail (IP, Emit_Node (WHILEM));
  1029.                   Insert_CURLY_Operator (CURLYX, 1, Max_Curly_Repeat, IP,
  1030.                                          Greedy);
  1031.                   Link_Tail (IP, Emit_Node (NOTHING));
  1032.  
  1033.                end if;
  1034.  
  1035.             when '?' =>
  1036.  
  1037.                Link_Tail (IP, Emit_Node (WHILEM));
  1038.                Insert_CURLY_Operator (CURLYX, 0, 1, IP, Greedy);
  1039.                Link_Tail (IP, Emit_Node (NOTHING));
  1040.  
  1041.             when '{' =>
  1042.                declare
  1043.                   Min, Max : Natural;
  1044.                begin
  1045.                   Get_Curly_Arguments (Parse_Pos, Min, Max, Greedy);
  1046.  
  1047.                   if New_Flags.Simple then
  1048.                      Insert_CURLY_Operator (CURLY, Min, Max, IP, Greedy);
  1049.                   else
  1050.                      Link_Tail (IP, Emit_Node (WHILEM));
  1051.                      Insert_CURLY_Operator (CURLYX, Min, Max, IP, Greedy);
  1052.                      Link_Tail (IP, Emit_Node (NOTHING));
  1053.                   end if;
  1054.                end;
  1055.  
  1056.             when others =>
  1057.                null;
  1058.          end case;
  1059.  
  1060.          Parse_Pos := Parse_Pos + 1;
  1061.  
  1062.          if Parse_Pos <= Parse_End
  1063.            and then Is_Mult (Parse_Pos)
  1064.          then
  1065.             Fail ("nested *+{");
  1066.          end if;
  1067.       end Parse_Piece;
  1068.  
  1069.       ---------------------------------
  1070.       -- Parse_Posix_Character_Class --
  1071.       ---------------------------------
  1072.  
  1073.       function Parse_Posix_Character_Class return Std_Class is
  1074.          Invert : Boolean := False;
  1075.          Class  : Std_Class := ANYOF_NONE;
  1076.          E : String renames Expression;
  1077.       begin
  1078.          if Parse_Pos <= Parse_End
  1079.            and then Expression (Parse_Pos) = ':'
  1080.          then
  1081.             Parse_Pos := Parse_Pos + 1;
  1082.  
  1083.             --  Do we have something like:  [[:^alpha:]]
  1084.  
  1085.             if Parse_Pos <= Parse_End
  1086.               and then Expression (Parse_Pos) = '^'
  1087.             then
  1088.                Invert := True;
  1089.                Parse_Pos := Parse_Pos + 1;
  1090.             end if;
  1091.  
  1092.             --  All classes have 6 characters at least
  1093.             if Parse_Pos + 6 <= Parse_End then
  1094.  
  1095.                case Expression (Parse_Pos) is
  1096.                   when 'a' =>
  1097.                      if E (Parse_Pos .. Parse_Pos + 4) = "alnum:]" then
  1098.                         if Invert then
  1099.                            Class := ANYOF_NALNUMC;
  1100.                         else
  1101.                            Class := ANYOF_ALNUMC;
  1102.                         end if;
  1103.  
  1104.                      elsif E (Parse_Pos .. Parse_Pos + 6) = "alpha:]" then
  1105.                         if Invert then
  1106.                            Class := ANYOF_NALPHA;
  1107.                         else
  1108.                            Class := ANYOF_ALPHA;
  1109.                         end if;
  1110.  
  1111.                      elsif E (Parse_Pos .. Parse_Pos + 6) = "ascii:]" then
  1112.                         if Invert then
  1113.                            Class := ANYOF_NASCII;
  1114.                         else
  1115.                            Class := ANYOF_ASCII;
  1116.                         end if;
  1117.  
  1118.                      end if;
  1119.  
  1120.                   when 'c' =>
  1121.                      if E (Parse_Pos .. Parse_Pos + 6) = "cntrl:]" then
  1122.                         if Invert then
  1123.                            Class := ANYOF_NCNTRL;
  1124.                         else
  1125.                            Class := ANYOF_CNTRL;
  1126.                         end if;
  1127.                      end if;
  1128.  
  1129.                   when 'd' =>
  1130.  
  1131.                      if E (Parse_Pos .. Parse_Pos + 6) = "digit:]" then
  1132.                         if Invert then
  1133.                            Class := ANYOF_NDIGIT;
  1134.                         else
  1135.                            Class := ANYOF_DIGIT;
  1136.                         end if;
  1137.                      end if;
  1138.  
  1139.                   when 'g' =>
  1140.  
  1141.                      if E (Parse_Pos .. Parse_Pos + 6) = "graph:]" then
  1142.                         if Invert then
  1143.                            Class := ANYOF_NGRAPH;
  1144.                         else
  1145.                            Class := ANYOF_GRAPH;
  1146.                         end if;
  1147.                      end if;
  1148.  
  1149.                   when 'l' =>
  1150.  
  1151.                      if E (Parse_Pos .. Parse_Pos + 6) = "lower:]" then
  1152.                         if Invert then
  1153.                            Class := ANYOF_NLOWER;
  1154.                         else
  1155.                            Class := ANYOF_LOWER;
  1156.                         end if;
  1157.                      end if;
  1158.  
  1159.                   when 'p' =>
  1160.  
  1161.                      if E (Parse_Pos .. Parse_Pos + 6) = "print:]" then
  1162.                         if Invert then
  1163.                            Class := ANYOF_NPRINT;
  1164.                         else
  1165.                            Class := ANYOF_PRINT;
  1166.                         end if;
  1167.  
  1168.                      elsif E (Parse_Pos .. Parse_Pos + 6) = "punct:]" then
  1169.                         if Invert then
  1170.                            Class := ANYOF_NPUNCT;
  1171.                         else
  1172.                            Class := ANYOF_PUNCT;
  1173.                         end if;
  1174.                      end if;
  1175.  
  1176.                   when 's' =>
  1177.  
  1178.                      if E (Parse_Pos .. Parse_Pos + 6) = "space:]" then
  1179.                         if Invert then
  1180.                            Class := ANYOF_NSPACE;
  1181.                         else
  1182.                            Class := ANYOF_SPACE;
  1183.                         end if;
  1184.                      end if;
  1185.  
  1186.                   when 'u' =>
  1187.  
  1188.                      if E (Parse_Pos .. Parse_Pos + 6) = "upper:]" then
  1189.                         if Invert then
  1190.                            Class := ANYOF_NUPPER;
  1191.                         else
  1192.                            Class := ANYOF_UPPER;
  1193.                         end if;
  1194.                      end if;
  1195.  
  1196.                   when 'w' =>
  1197.  
  1198.                      if E (Parse_Pos .. Parse_Pos + 5) = "word:]" then
  1199.                         if Invert then
  1200.                            Class := ANYOF_NALNUM;
  1201.                         else
  1202.                            Class := ANYOF_ALNUM;
  1203.                         end if;
  1204.                         Parse_Pos := Parse_Pos - 1;
  1205.                      end if;
  1206.  
  1207.                   when 'x' =>
  1208.  
  1209.                      if Parse_Pos + 7 <= Parse_End
  1210.                        and then E (Parse_Pos .. Parse_Pos + 7) = "xdigit:]"
  1211.                      then
  1212.                         if Invert then
  1213.                            Class := ANYOF_NXDIGIT;
  1214.                         else
  1215.                            Class := ANYOF_XDIGIT;
  1216.                         end if;
  1217.                         Parse_Pos := Parse_Pos + 1;
  1218.                      end if;
  1219.  
  1220.                   when others =>
  1221.                      Class := ANYOF_NONE;
  1222.  
  1223.                end case;
  1224.                if Class /= ANYOF_NONE then
  1225.                   Parse_Pos := Parse_Pos + 7;
  1226.                end if;
  1227.             else
  1228.                Fail ("Invalid character class");
  1229.             end if;
  1230.          else
  1231.             return ANYOF_NONE;
  1232.          end if;
  1233.          return Class;
  1234.       end Parse_Posix_Character_Class;
  1235.  
  1236.       ---------------------------
  1237.       -- Parse_Character_Class --
  1238.       ---------------------------
  1239.  
  1240.       procedure Parse_Character_Class (IP : out Pointer) is
  1241.          Bitmap      : Character_Class;
  1242.          Invert      : Boolean := False;
  1243.          In_Range    : Boolean := False;
  1244.          Named_Class : Std_Class := ANYOF_NONE;
  1245.          Value       : Character;
  1246.          Last_Value  : Character := ASCII.Nul;
  1247.  
  1248.       begin
  1249.          Reset_Class (Bitmap);
  1250.  
  1251.          --  Do we have an invert character class ?
  1252.  
  1253.          if Parse_Pos <= Parse_End
  1254.            and then Expression (Parse_Pos) = '^'
  1255.          then
  1256.             Invert := True;
  1257.             Parse_Pos := Parse_Pos + 1;
  1258.          end if;
  1259.  
  1260.          --  First character can be ] or -, without closing the class.
  1261.  
  1262.          if Parse_Pos <= Parse_End
  1263.            and then (Expression (Parse_Pos) = ']'
  1264.                      or else Expression (Parse_Pos) = '-')
  1265.          then
  1266.             Set_In_Class (Bitmap, Expression (Parse_Pos));
  1267.             Parse_Pos := Parse_Pos + 1;
  1268.          end if;
  1269.  
  1270.          --  While we don't have the end of the class
  1271.  
  1272.          while Parse_Pos <= Parse_End
  1273.            and then Expression (Parse_Pos) /= ']'
  1274.          loop
  1275.             Named_Class := ANYOF_NONE;
  1276.             Value := Expression (Parse_Pos);
  1277.             Parse_Pos := Parse_Pos + 1;
  1278.  
  1279.             --  Do we have a Posix character class
  1280.             if Value = '[' then
  1281.                Named_Class := Parse_Posix_Character_Class;
  1282.  
  1283.             elsif Value = '\' then
  1284.                if Parse_Pos = Parse_End then
  1285.                   Fail ("Trailing \");
  1286.                end if;
  1287.                Value := Expression (Parse_Pos);
  1288.                Parse_Pos := Parse_Pos + 1;
  1289.  
  1290.                case Value is
  1291.                   when 'w' => Named_Class := ANYOF_ALNUM;
  1292.                   when 'W' => Named_Class := ANYOF_NALNUM;
  1293.                   when 's' => Named_Class := ANYOF_SPACE;
  1294.                   when 'S' => Named_Class := ANYOF_NSPACE;
  1295.                   when 'd' => Named_Class := ANYOF_DIGIT;
  1296.                   when 'D' => Named_Class := ANYOF_NDIGIT;
  1297.                   when 'n' => Value := ASCII.LF;
  1298.                   when 'r' => Value := ASCII.CR;
  1299.                   when 't' => Value := ASCII.HT;
  1300.                   when 'f' => Value := ASCII.FF;
  1301.                   when 'e' => Value := ASCII.ESC;
  1302.                   when 'a' => Value := ASCII.BEL;
  1303.  
  1304.                   --  when 'x'  => ??? hexadecimal value
  1305.                   --  when 'c'  => ??? control character
  1306.                   --  when '0'..'9' => ??? octal character
  1307.  
  1308.                   when others => null;
  1309.                end case;
  1310.             end if;
  1311.  
  1312.             --  Do we have a character class ?
  1313.  
  1314.             if Named_Class /= ANYOF_NONE then
  1315.  
  1316.                --  A range like 'a-\d' or 'a-[:digit:] is not a range
  1317.                if In_Range then
  1318.                   Set_In_Class (Bitmap, Last_Value);
  1319.                   Set_In_Class (Bitmap, '-');
  1320.                   In_Range := False;
  1321.                end if;
  1322.  
  1323.                --  Expand the range
  1324.                case Named_Class is
  1325.                   when ANYOF_NONE => null;
  1326.  
  1327.                   when ANYOF_ALNUM | ANYOF_ALNUMC =>
  1328.                      for Value in Class_Byte'Range loop
  1329.                         if Is_Alnum (Character'Val (Value)) then
  1330.                            Set_In_Class (Bitmap, Character'Val (Value));
  1331.                         end if;
  1332.                      end loop;
  1333.  
  1334.                   when ANYOF_NALNUM | ANYOF_NALNUMC =>
  1335.                      for Value in Class_Byte'Range loop
  1336.                         if not Is_Alnum (Character'Val (Value)) then
  1337.                            Set_In_Class (Bitmap, Character'Val (Value));
  1338.                         end if;
  1339.                      end loop;
  1340.  
  1341.                   when ANYOF_SPACE =>
  1342.                      for Value in Class_Byte'Range loop
  1343.                         if Is_Space (Character'Val (Value)) then
  1344.                            Set_In_Class (Bitmap, Character'Val (Value));
  1345.                         end if;
  1346.                      end loop;
  1347.  
  1348.                   when ANYOF_NSPACE =>
  1349.                      for Value in Class_Byte'Range loop
  1350.                         if not Is_Space (Character'Val (Value)) then
  1351.                            Set_In_Class (Bitmap, Character'Val (Value));
  1352.                         end if;
  1353.                      end loop;
  1354.  
  1355.                   when ANYOF_DIGIT =>
  1356.                      for Value in Class_Byte'Range loop
  1357.                         if Is_Digit (Character'Val (Value)) then
  1358.                            Set_In_Class (Bitmap, Character'Val (Value));
  1359.                         end if;
  1360.                      end loop;
  1361.  
  1362.                   when ANYOF_NDIGIT =>
  1363.                      for Value in Class_Byte'Range loop
  1364.                         if not Is_Digit (Character'Val (Value)) then
  1365.                            Set_In_Class (Bitmap, Character'Val (Value));
  1366.                         end if;
  1367.                      end loop;
  1368.  
  1369.                   when ANYOF_ALPHA =>
  1370.                      for Value in Class_Byte'Range loop
  1371.                         if Is_Letter (Character'Val (Value)) then
  1372.                            Set_In_Class (Bitmap, Character'Val (Value));
  1373.                         end if;
  1374.                      end loop;
  1375.  
  1376.                   when ANYOF_NALPHA =>
  1377.                      for Value in Class_Byte'Range loop
  1378.                         if not Is_Letter (Character'Val (Value)) then
  1379.                            Set_In_Class (Bitmap, Character'Val (Value));
  1380.                         end if;
  1381.                      end loop;
  1382.  
  1383.                   when ANYOF_ASCII =>
  1384.                      for Value in 0 .. 127 loop
  1385.                         Set_In_Class (Bitmap, Character'Val (Value));
  1386.                      end loop;
  1387.  
  1388.                   when ANYOF_NASCII =>
  1389.                      for Value in 128 .. 255 loop
  1390.                         Set_In_Class (Bitmap, Character'Val (Value));
  1391.                      end loop;
  1392.  
  1393.                   when ANYOF_CNTRL =>
  1394.                      for Value in Class_Byte'Range loop
  1395.                         if Is_Control (Character'Val (Value)) then
  1396.                            Set_In_Class (Bitmap, Character'Val (Value));
  1397.                         end if;
  1398.                      end loop;
  1399.  
  1400.                   when ANYOF_NCNTRL =>
  1401.                      for Value in Class_Byte'Range loop
  1402.                         if not Is_Control (Character'Val (Value)) then
  1403.                            Set_In_Class (Bitmap, Character'Val (Value));
  1404.                         end if;
  1405.                      end loop;
  1406.  
  1407.                   when ANYOF_GRAPH =>
  1408.                      for Value in Class_Byte'Range loop
  1409.                         if Is_Graphic (Character'Val (Value)) then
  1410.                            Set_In_Class (Bitmap, Character'Val (Value));
  1411.                         end if;
  1412.                      end loop;
  1413.  
  1414.                   when ANYOF_NGRAPH =>
  1415.                      for Value in Class_Byte'Range loop
  1416.                         if not Is_Graphic (Character'Val (Value)) then
  1417.                            Set_In_Class (Bitmap, Character'Val (Value));
  1418.                         end if;
  1419.                      end loop;
  1420.  
  1421.                   when ANYOF_LOWER =>
  1422.                      for Value in Class_Byte'Range loop
  1423.                         if Is_Lower (Character'Val (Value)) then
  1424.                            Set_In_Class (Bitmap, Character'Val (Value));
  1425.                         end if;
  1426.                      end loop;
  1427.  
  1428.                   when ANYOF_NLOWER =>
  1429.                      for Value in Class_Byte'Range loop
  1430.                         if not Is_Lower (Character'Val (Value)) then
  1431.                            Set_In_Class (Bitmap, Character'Val (Value));
  1432.                         end if;
  1433.                      end loop;
  1434.  
  1435.                   when ANYOF_PRINT =>
  1436.                      for Value in Class_Byte'Range loop
  1437.                         if Is_Printable (Character'Val (Value)) then
  1438.                            Set_In_Class (Bitmap, Character'Val (Value));
  1439.                         end if;
  1440.                      end loop;
  1441.  
  1442.                   when ANYOF_NPRINT =>
  1443.                      for Value in Class_Byte'Range loop
  1444.                         if not Is_Printable (Character'Val (Value)) then
  1445.                            Set_In_Class (Bitmap, Character'Val (Value));
  1446.                         end if;
  1447.                      end loop;
  1448.  
  1449.                   when ANYOF_PUNCT =>
  1450.                      for Value in Class_Byte'Range loop
  1451.                         if Is_Printable (Character'Val (Value))
  1452.                           and then not Is_Space (Character'Val (Value))
  1453.                           and then not Is_Alnum (Character'Val (Value))
  1454.                         then
  1455.                            Set_In_Class (Bitmap, Character'Val (Value));
  1456.                         end if;
  1457.                      end loop;
  1458.  
  1459.                   when ANYOF_NPUNCT =>
  1460.                      for Value in Class_Byte'Range loop
  1461.                         if not Is_Printable (Character'Val (Value))
  1462.                           or else Is_Space (Character'Val (Value))
  1463.                           or else Is_Alnum (Character'Val (Value))
  1464.                         then
  1465.                            Set_In_Class (Bitmap, Character'Val (Value));
  1466.                         end if;
  1467.                      end loop;
  1468.  
  1469.                   when ANYOF_UPPER =>
  1470.                      for Value in Class_Byte'Range loop
  1471.                         if Is_Upper (Character'Val (Value)) then
  1472.                            Set_In_Class (Bitmap, Character'Val (Value));
  1473.                         end if;
  1474.                      end loop;
  1475.  
  1476.                   when ANYOF_NUPPER =>
  1477.                      for Value in Class_Byte'Range loop
  1478.                         if not Is_Upper (Character'Val (Value)) then
  1479.                            Set_In_Class (Bitmap, Character'Val (Value));
  1480.                         end if;
  1481.                      end loop;
  1482.  
  1483.                   when ANYOF_XDIGIT =>
  1484.                      for Value in Class_Byte'Range loop
  1485.                         if Is_Hexadecimal_Digit (Character'Val (Value)) then
  1486.                            Set_In_Class (Bitmap, Character'Val (Value));
  1487.                         end if;
  1488.                      end loop;
  1489.  
  1490.                   when ANYOF_NXDIGIT =>
  1491.                      for Value in Class_Byte'Range loop
  1492.                         if not Is_Hexadecimal_Digit
  1493.                           (Character'Val (Value))
  1494.                         then
  1495.                            Set_In_Class (Bitmap, Character'Val (Value));
  1496.                         end if;
  1497.                      end loop;
  1498.  
  1499.                end case;
  1500.  
  1501.             --  Not a character range
  1502.  
  1503.             elsif not In_Range then
  1504.                Last_Value := Value;
  1505.                if Expression (Parse_Pos) = '-'
  1506.                  and then Parse_Pos < Parse_End
  1507.                  and then Expression (Parse_Pos + 1) /= ']'
  1508.                then
  1509.                   Parse_Pos := Parse_Pos + 1;
  1510.  
  1511.                   --  Do we have a range like '\d-a' and '[:space:]-a'
  1512.                   --  which is not a real range
  1513.  
  1514.                   if Named_Class /= ANYOF_NONE then
  1515.                      Set_In_Class (Bitmap, '-');
  1516.                   else
  1517.                      In_Range := True;
  1518.                   end if;
  1519.  
  1520.                else
  1521.                   Set_In_Class (Bitmap, Value);
  1522.  
  1523.                end if;
  1524.  
  1525.             --  Else in a character range
  1526.  
  1527.             else
  1528.                if Last_Value > Value then
  1529.                   Fail ("Invalid Range [" & Last_Value'Img
  1530.                         & "-" & Value'Img & "]");
  1531.                end if;
  1532.  
  1533.                while Last_Value <= Value loop
  1534.                   Set_In_Class (Bitmap, Last_Value);
  1535.                   Last_Value := Character'Succ (Last_Value);
  1536.                end loop;
  1537.  
  1538.                In_Range := False;
  1539.  
  1540.             end if;
  1541.  
  1542.          end loop;
  1543.  
  1544.          --  Optimize case-insensitive ranges (put the upper case or lower
  1545.          --  case character into the bitmap)
  1546.  
  1547.          if (Flags and Case_Insensitive) /= 0 then
  1548.             for C in Character'Range loop
  1549.                if Get_From_Class (Bitmap, C) then
  1550.                   Set_In_Class (Bitmap, To_Lower (C));
  1551.                   Set_In_Class (Bitmap, To_Upper (C));
  1552.                end if;
  1553.             end loop;
  1554.          end if;
  1555.  
  1556.          --  Optimize inverted classes
  1557.          if Invert then
  1558.             for J in Bitmap'Range loop
  1559.                Bitmap (J) := not Bitmap (J);
  1560.             end loop;
  1561.          end if;
  1562.  
  1563.          Parse_Pos := Parse_Pos + 1;
  1564.  
  1565.          --  Emit the class
  1566.          IP := Emit_Node (ANYOF);
  1567.          Emit_Class (Bitmap);
  1568.       end Parse_Character_Class;
  1569.  
  1570.       -------------------
  1571.       -- Parse_Literal --
  1572.       -------------------
  1573.       --  This is a bit tricky due to quoted chars and due to
  1574.       --  the multiplier characters '*', '+', and '?' that
  1575.       --  take the SINGLE char previous as their operand.
  1576.       --
  1577.       --  On entry, the character at Parse_Pos - 1 is going to go
  1578.       --  into the string, no matter what it is. It could be
  1579.       --  following a \ if Parse_Atom was entered from the '\' case.
  1580.       --
  1581.       --  Basic idea is to pick up a good char in C and examine
  1582.       --  the next char. If Is_Mult (C) then twiddle, if it's a \
  1583.       --  then frozzle and if it's another magic char then push C and
  1584.       --  terminate the string. If none of the above, push C on the
  1585.       --  string and go around again.
  1586.       --
  1587.       --  Start_Pos is used to remember where "the current character"
  1588.       --  starts in the string, if due to an Is_Mult we need to back
  1589.       --  up and put the current char in a separate 1-character string.
  1590.       --  When Start_Pos is 0, C is the only char in the string;
  1591.       --  this is used in Is_Mult handling, and in setting the SIMPLE
  1592.       --  flag at the end.
  1593.  
  1594.       procedure Parse_Literal (Expr_Flags : in out Expression_Flags;
  1595.                                IP : out Pointer)
  1596.       is
  1597.          Start_Pos  : Natural := 0;
  1598.          C          : Character;
  1599.          Length_Ptr : Pointer;
  1600.  
  1601.       begin
  1602.          Parse_Pos := Parse_Pos - 1;      --  Look at current character
  1603.          if (Flags and Case_Insensitive) /= 0 then
  1604.             IP := Emit_Node (EXACTF);
  1605.          else
  1606.             IP := Emit_Node (EXACT);
  1607.          end if;
  1608.  
  1609.          Length_Ptr := Emit_Ptr;
  1610.          Emit_Ptr := String_Operand (IP);
  1611.  
  1612.          Parse_Loop :
  1613.          loop
  1614.             <<continue>>
  1615.  
  1616.             --  Can not have more than 255 characters in a single cst
  1617.             exit when Emit_Ptr - Length_Ptr = 255;
  1618.  
  1619.             C := Expression (Parse_Pos);  -- Get current character
  1620.             Parse_Pos := Parse_Pos + 1;
  1621.  
  1622.             if Parse_Pos > Parse_End then
  1623.                Case_Emit (C);             -- dump current character
  1624.                exit Parse_Loop;           -- and we are done
  1625.             end if;
  1626.  
  1627.             case Expression (Parse_Pos) is  -- look at next one
  1628.  
  1629.                --  ??? Chars '$' and '^' should not always be magic
  1630.                when '.' | '[' | '(' | ')' | '|' | ASCII.LF
  1631.                  | '$' | '^' =>
  1632.  
  1633.                   Case_Emit (C);          -- dump cur char
  1634.                   exit Parse_Loop;        -- and we are done
  1635.  
  1636.                when '?' | '+' | '*' | '{' =>
  1637.  
  1638.                   --  Are we looking at an operator, or is this
  1639.                   --  simply a normal character ?
  1640.  
  1641.                   if not Is_Mult (Parse_Pos) then
  1642.                      Case_Emit (C);
  1643.                   else
  1644.                      if Start_Pos = 0 then   -- If just C in str,
  1645.                         Case_Emit (C);       -- dump cur char
  1646.                         exit Parse_Loop;     -- and we are done
  1647.                      end if;
  1648.  
  1649.                      --  End mult-char string one early
  1650.  
  1651.                      Parse_Pos := Start_Pos; -- Back up parse
  1652.                      exit Parse_Loop;
  1653.                   end if;
  1654.  
  1655.                when '\' =>
  1656.                   Case_Emit (C);
  1657.                   if Parse_Pos + 1 > Parse_End then
  1658.                      Fail ("Trailing \");
  1659.                   else
  1660.                      case Expression (Parse_Pos + 1) is
  1661.                         when 'b' | 'B' | 's' | 'S' | 'd' | 'D'
  1662.                           | 'w' | 'W' | '0' .. '9' | 'G' | 'A'
  1663.                           => exit Parse_Loop;
  1664.                         when 'n'         => Emit (ASCII.LF);
  1665.                         when 't'         => Emit (ASCII.HT);
  1666.                         when 'r'         => Emit (ASCII.CR);
  1667.                         when others      => Emit (Expression (Parse_Pos + 1));
  1668.                      end case;
  1669.                      Parse_Pos := Parse_Pos + 2;
  1670.                   end if;
  1671.                   exit Parse_Loop;
  1672.  
  1673.                when others =>
  1674.                   Case_Emit (C);
  1675.             end case;
  1676.  
  1677.             Start_Pos := Parse_Pos;
  1678.  
  1679.          end loop Parse_Loop;
  1680.  
  1681.          if Emit_Code then
  1682.             Program (Length_Ptr)
  1683.               := Character'Val (Emit_Ptr - Length_Ptr - 2);
  1684.          end if;
  1685.          Expr_Flags.Has_Width := True;
  1686.  
  1687.          if Emit_Ptr = Length_Ptr + 2 then            --  One character?
  1688.             Expr_Flags.Simple := True;
  1689.          end if;
  1690.       end Parse_Literal;
  1691.  
  1692.       ----------------
  1693.       -- Parse_Atom --
  1694.       ----------------
  1695.  
  1696.       procedure Parse_Atom
  1697.         (Expr_Flags : in out Expression_Flags;
  1698.          IP         : out Pointer)
  1699.       is
  1700.          C : Character;
  1701.  
  1702.       begin
  1703.          --  Tentatively set worst expression case
  1704.  
  1705.          Expr_Flags := Worst_Expression;
  1706.  
  1707.          C := Expression (Parse_Pos);
  1708.          Parse_Pos := Parse_Pos + 1;
  1709.  
  1710.          case (C) is
  1711.             when '^' =>
  1712.                if (Flags and Multiple_Lines) /= 0  then
  1713.                   IP := Emit_Node (MBOL);
  1714.                elsif (Flags and Single_Line) /= 0 then
  1715.                   IP := Emit_Node (SBOL);
  1716.                else
  1717.                   IP := Emit_Node (BOL);
  1718.                end if;
  1719.             when '$' =>
  1720.                if (Flags and Multiple_Lines) /= 0  then
  1721.                   IP := Emit_Node (MEOL);
  1722.                elsif (Flags and Single_Line) /= 0 then
  1723.                   IP := Emit_Node (SEOL);
  1724.                else
  1725.                   IP := Emit_Node (EOL);
  1726.                end if;
  1727.  
  1728.             when '.' =>
  1729.                if (Flags and Single_Line) /= 0 then
  1730.                   IP := Emit_Node (SANY);
  1731.                else
  1732.                   IP := Emit_Node (ANY);
  1733.                end if;
  1734.                Expr_Flags.Has_Width := True;
  1735.                Expr_Flags.Simple := True;
  1736.  
  1737.             when '[' =>
  1738.                Parse_Character_Class (IP);
  1739.  
  1740.             when '(' =>
  1741.                declare
  1742.                   New_Flags : Expression_Flags;
  1743.                begin
  1744.                   Parse (True, New_Flags, IP);
  1745.  
  1746.                   if IP = 0 then
  1747.                      return;
  1748.                   end if;
  1749.  
  1750.                   Expr_Flags.Has_Width :=
  1751.                     Expr_Flags.Has_Width or New_Flags.Has_Width;
  1752.                   Expr_Flags.SP_Start :=
  1753.                     Expr_Flags.SP_Start or New_Flags.SP_Start;
  1754.                end;
  1755.  
  1756.             when '|' | ASCII.LF | ')' =>
  1757.                Fail ("internal urp");  --  Supposed to be caught earlier
  1758.  
  1759.             when '?' | '+' | '*' | '{' =>
  1760.                Fail ("?+*{ follows nothing");
  1761.  
  1762.             when '\' =>
  1763.                if Parse_Pos > Parse_End then
  1764.                   Fail ("trailing \");
  1765.                end if;
  1766.  
  1767.                Parse_Pos := Parse_Pos + 1;
  1768.                case Expression (Parse_Pos - 1) is
  1769.                   when 'b'        => IP := Emit_Node (BOUND);
  1770.                   when 'B'        => IP := Emit_Node (NBOUND);
  1771.                   when 's'        => IP := Emit_Node (SPACE);
  1772.                   when 'S'        => IP := Emit_Node (NSPACE);
  1773.                   when 'd'        => IP := Emit_Node (DIGIT);
  1774.                   when 'D'        => IP := Emit_Node (NDIGIT);
  1775.                   when 'w'        => IP := Emit_Node (ALNUM);
  1776.                   when 'W'        => IP := Emit_Node (NALNUM);
  1777.                   when 'A'        => IP := Emit_Node (SBOL);
  1778.                   when 'G'        => IP := Emit_Node (SEOL);
  1779.                   when '0' .. '9' =>
  1780.                      IP := Emit_Node (REFF);
  1781.                      declare
  1782.                         Save : Natural := Parse_Pos - 1;
  1783.                      begin
  1784.                         while Parse_Pos <= Expression'Last
  1785.                           and then Is_Digit (Expression (Parse_Pos))
  1786.                         loop
  1787.                            Parse_Pos := Parse_Pos + 1;
  1788.                         end loop;
  1789.                         Emit (Character'Val (Natural'Value
  1790.                                (Expression (Save .. Parse_Pos - 1))));
  1791.                      end;
  1792.  
  1793.                   when others => Parse_Literal (Expr_Flags, IP);
  1794.                end case;
  1795.  
  1796.             when others => Parse_Literal (Expr_Flags, IP);
  1797.          end case;
  1798.       end Parse_Atom;
  1799.  
  1800.       ---------------
  1801.       -- Emit_Node --
  1802.       ---------------
  1803.  
  1804.       function Emit_Node (Op : Opcode) return Pointer is
  1805.          Result : constant Pointer := Emit_Ptr;
  1806.  
  1807.       begin
  1808.          if Emit_Code then
  1809.             Program (Emit_Ptr) := Character'Val (Opcode'Pos (Op));
  1810.             Program (Emit_Ptr + 1) := ASCII.NUL;
  1811.             Program (Emit_Ptr + 2) := ASCII.NUL;
  1812.          end if;
  1813.  
  1814.          Emit_Ptr := Emit_Ptr + 3;
  1815.          return Result;
  1816.       end Emit_Node;
  1817.  
  1818.       ----------
  1819.       -- Emit --
  1820.       ----------
  1821.  
  1822.       procedure Emit (B : Character) is
  1823.       begin
  1824.          if Emit_Code then
  1825.             Program (Emit_Ptr) := B;
  1826.          end if;
  1827.          Emit_Ptr := Emit_Ptr + 1;
  1828.       end Emit;
  1829.  
  1830.       ---------------
  1831.       -- Case_Emit --
  1832.       ---------------
  1833.  
  1834.       procedure Case_Emit (C : Character) is
  1835.       begin
  1836.          if (Flags and Case_Insensitive) /= 0 then
  1837.             Emit (To_Lower (C));
  1838.          else
  1839.             Emit (C);                  -- dump current character
  1840.          end if;
  1841.       end Case_Emit;
  1842.  
  1843.       ----------------
  1844.       -- Emit_Class --
  1845.       ----------------
  1846.  
  1847.       procedure Emit_Class (Bitmap : Character_Class) is
  1848.       begin
  1849.          for J in 0 .. Class_Byte'(31) loop
  1850.             if Emit_Code then
  1851.                Program (Emit_Ptr) := Character'Val (Bitmap (J));
  1852.             end if;
  1853.             Emit_Ptr := Emit_Ptr + 1;
  1854.          end loop;
  1855.       end Emit_Class;
  1856.  
  1857.       ---------------------------
  1858.       -- Insert_CURLY_Operator --
  1859.       ---------------------------
  1860.  
  1861.       procedure Insert_CURLY_Operator (Op      : Opcode;
  1862.                                        Min     : Natural;
  1863.                                        Max     : Natural;
  1864.                                        Operand : Pointer;
  1865.                                        Greedy  : Boolean := True)
  1866.       is
  1867.          Dest   : constant Pointer := Emit_Ptr;
  1868.          Old    : Pointer;
  1869.          Size   : Pointer := 7;
  1870.  
  1871.       begin
  1872.          --  If the operand is not greedy, insert an extra operand before it
  1873.          if not Greedy then
  1874.             Size := Size + 3;
  1875.          end if;
  1876.  
  1877.          --  Move the operand in the byte-compilation, so that we can insert
  1878.          --  the operator before it.
  1879.  
  1880.          if Emit_Code then
  1881.             Program (Operand + Size .. Emit_Ptr + Size)
  1882.               := Program (Operand .. Emit_Ptr);
  1883.          end if;
  1884.  
  1885.          --  Insert the operator at the position previously occupied by the
  1886.          --  operand.
  1887.  
  1888.          Emit_Ptr := Operand;
  1889.  
  1890.          if not Greedy then
  1891.             Old := Emit_Node (MINMOD);
  1892.             Link_Tail (Old, Old + 3);
  1893.          end if;
  1894.  
  1895.          Old := Emit_Node (Op);
  1896.          Emit_Natural (Old + 3, Min);
  1897.          Emit_Natural (Old + 5, Max);
  1898.  
  1899.          Emit_Ptr := Dest + Size;
  1900.       end Insert_CURLY_Operator;
  1901.  
  1902.       ---------------------
  1903.       -- Insert_Operator --
  1904.       ---------------------
  1905.  
  1906.       procedure Insert_Operator (Op      : Opcode;
  1907.                                  Operand : Pointer;
  1908.                                  Greedy  : Boolean := True)
  1909.       is
  1910.          Dest   : constant Pointer := Emit_Ptr;
  1911.          Old    : Pointer;
  1912.          Size   : Pointer := 3;
  1913.  
  1914.       begin
  1915.          --  If not greedy, we have to emit another opcode first
  1916.          if not Greedy then
  1917.             Size := Size + 3;
  1918.          end if;
  1919.  
  1920.          --  Move the operand in the byte-compilation, so that we can insert
  1921.          --  the operator before it.
  1922.  
  1923.          if Emit_Code then
  1924.             Program (Operand + Size .. Emit_Ptr + Size)
  1925.               := Program (Operand .. Emit_Ptr);
  1926.          end if;
  1927.  
  1928.          --  Insert the operator at the position previously occupied by the
  1929.          --  operand.
  1930.  
  1931.          Emit_Ptr := Operand;
  1932.          if not Greedy then
  1933.             Old := Emit_Node (MINMOD);
  1934.             Link_Tail (Old, Old + 3);
  1935.          end if;
  1936.          Old := Emit_Node (Op);
  1937.          Emit_Ptr := Dest + Size;
  1938.       end Insert_Operator;
  1939.  
  1940.       ---------------
  1941.       -- Link_Tail --
  1942.       ---------------
  1943.  
  1944.       procedure Link_Tail (P, Val : Pointer) is
  1945.          Scan   : Pointer;
  1946.          Temp   : Pointer;
  1947.          Offset : Pointer;
  1948.  
  1949.       begin
  1950.          if not Emit_Code then
  1951.             return;
  1952.          end if;
  1953.  
  1954.          --  Find last node
  1955.  
  1956.          Scan := P;
  1957.          loop
  1958.             Temp := Next_Instruction (Scan);
  1959.             exit when Temp = 0;
  1960.             Scan := Temp;
  1961.          end loop;
  1962.  
  1963.          Offset := Val - Scan;
  1964.  
  1965.          Emit_Natural (Scan + 1, Natural (Offset));
  1966.       end Link_Tail;
  1967.  
  1968.       -----------------------
  1969.       -- Link_Operand_Tail --
  1970.       -----------------------
  1971.  
  1972.       procedure Link_Operand_Tail (P, Val : Pointer) is
  1973.       begin
  1974.          if Emit_Code and then Program (P) = BRANCH then
  1975.             Link_Tail (Operand (P), Val);
  1976.          end if;
  1977.       end Link_Operand_Tail;
  1978.  
  1979.       ----------------------
  1980.       -- Next_Instruction --
  1981.       ----------------------
  1982.  
  1983.       function Next_Instruction (P : Pointer) return Pointer is
  1984.          Offset : Pointer;
  1985.  
  1986.       begin
  1987.          if not Emit_Code then
  1988.             return 0;
  1989.          end if;
  1990.  
  1991.          Offset := Get_Next_Offset (Program, P);
  1992.  
  1993.          if Offset = 0 then
  1994.             return 0;
  1995.          end if;
  1996.  
  1997.          return P + Offset;
  1998.       end Next_Instruction;
  1999.  
  2000.       Expr_Flags : Expression_Flags;
  2001.       Result     : Pointer;
  2002.  
  2003.    --  Start of processing for Compile
  2004.  
  2005.    begin
  2006.       Emit (MAGIC);
  2007.       Parse (False, Expr_Flags, Result);
  2008.  
  2009.       if Result = 0 then
  2010.          Fail ("Couldn't compile expression");
  2011.       end if;
  2012.  
  2013.       Final_Code_Size := Emit_Ptr - 1;
  2014.  
  2015.       --  Do we want to actually compile the expression, or simply get the
  2016.       --  code size ?
  2017.       if Emit_Code then
  2018.          Optimize (PM);
  2019.       end if;
  2020.  
  2021.       PM.Flags := Flags;
  2022.    end Compile;
  2023.  
  2024.    -------------
  2025.    -- Compile --
  2026.    -------------
  2027.  
  2028.    function Compile (Expression : String;
  2029.                      Flags      : Regexp_Flags := No_Flags)
  2030.                     return       Pattern_Matcher
  2031.    is
  2032.       Size  : Program_Size;
  2033.       Dummy : Pattern_Matcher (0);
  2034.    begin
  2035.       Compile (Dummy, Expression, Size, Flags);
  2036.  
  2037.       declare
  2038.          Result : Pattern_Matcher (Size);
  2039.       begin
  2040.          Compile (Result, Expression, Size, Flags);
  2041.          return Result;
  2042.       end;
  2043.    end Compile;
  2044.  
  2045.    -------------
  2046.    -- Compile --
  2047.    -------------
  2048.  
  2049.    procedure Compile (Matcher    : out Pattern_Matcher;
  2050.                       Expression : String;
  2051.                       Flags      : Regexp_Flags := No_Flags)
  2052.    is
  2053.       Size : Program_Size;
  2054.    begin
  2055.       Compile (Matcher, Expression, Size, Flags);
  2056.    end Compile;
  2057.  
  2058.    --------------
  2059.    -- Optimize --
  2060.    --------------
  2061.  
  2062.    procedure Optimize (Self : in out Pattern_Matcher) is
  2063.       Max_Length  : Program_Size;
  2064.       This_Length : Program_Size;
  2065.       Longest     : Pointer;
  2066.       Scan        : Pointer;
  2067.       Program     : Program_Data renames Self.Program;
  2068.  
  2069.    --  Start of processing for Optimize
  2070.  
  2071.    begin
  2072.       --  Start with safe defaults (no optimization):
  2073.       --    *  No known first character of match
  2074.       --    *  Does not necessarily start at beginning of line
  2075.       --    *  No string known that has to appear in data
  2076.  
  2077.       Self.First := ASCII.NUL;
  2078.       Self.Anchored := False;
  2079.       Self.Must_Have := Program'Last + 1;
  2080.       Self.Must_Have_Length := 0;
  2081.  
  2082.       Scan := Program_First + 1;  --  First instruction (can be anything)
  2083.  
  2084.       if Program (Scan) = EXACT then
  2085.          Self.First := Program (String_Operand (Scan));
  2086.  
  2087.       elsif Program (Scan) = BOL
  2088.         or else Program (Scan) = SBOL
  2089.       then
  2090.          Self.Anchored := True;
  2091.       end if;
  2092.  
  2093.       --  If there's something expensive in the regexp, find the
  2094.       --  longest literal string that must appear and make it the
  2095.       --  regmust. Resolve ties in favor of later strings, since
  2096.       --  the regstart check works with the beginning of the regexp.
  2097.       --  and avoiding duplication strengthens checking. Not a
  2098.       --  strong reason, but sufficient in the absence of others.
  2099.  
  2100.       if False then -- if Flags.SP_Start then ???
  2101.          Longest := 0;
  2102.          Max_Length := 0;
  2103.          while Scan /= 0 loop
  2104.             if Program (Scan) = EXACT or else Program (Scan) = EXACTF then
  2105.                This_Length := String_Length (Program, Scan);
  2106.  
  2107.                if This_Length >= Max_Length then
  2108.                   Longest := String_Operand (Scan);
  2109.                   Max_Length := This_Length;
  2110.                end if;
  2111.             end if;
  2112.  
  2113.             Scan := Get_Next (Program, Scan);
  2114.          end loop;
  2115.  
  2116.          Self.Must_Have        := Longest;
  2117.          Self.Must_Have_Length := Natural (Max_Length) + 1;
  2118.       end if;
  2119.    end Optimize;
  2120.  
  2121.    -----------
  2122.    -- Match --
  2123.    -----------
  2124.  
  2125.    procedure Match
  2126.      (Self    : Pattern_Matcher;
  2127.       Data    : String;
  2128.       Matches : out Match_Array)
  2129.    is
  2130.       Program   : Program_Data renames Self.Program; -- Shorter notation
  2131.  
  2132.       --  Global work variables
  2133.  
  2134.       Input_Pos : Natural;          -- String-input pointer
  2135.       BOL_Pos   : Natural;          -- Beginning of input, for ^ check
  2136.       Matched   : Boolean := False;  -- Until proven True
  2137.  
  2138.       Matches_Full : Match_Array (0 .. Natural'Max (Self.Num_Parenthesis,
  2139.                                                     Matches'Last));
  2140.       --  Stores the value of all the parenthesis pairs.
  2141.       --  We do not use directly Matches, so that we can also use back
  2142.       --  references (REFF) even if Matches is too small.
  2143.  
  2144.       Matches_Tmp : Match_Array (Matches_Full'Range);
  2145.       --  Save the opening position of parenthesis.
  2146.  
  2147.       Last_Paren  : Natural := 0;
  2148.       --  Last parenthesis seen
  2149.  
  2150.       Greedy : Boolean := True;
  2151.       --  True if the next operator should be greedy
  2152.  
  2153.       type Current_Curly_Record;
  2154.       type Current_Curly_Access is access all Current_Curly_Record;
  2155.       type Current_Curly_Record is record
  2156.          Paren_Floor : Natural;  --  How far back to strip parenthesis data
  2157.          Cur         : Integer;  --  How many instances of scan we've matched
  2158.          Min         : Natural;  --  Minimal number of scans to match
  2159.          Max         : Natural;  --  Maximal number of scans to match
  2160.          Greedy      : Boolean;  --  Whether to work our way up or down
  2161.          Scan        : Pointer;  --  The thing to match
  2162.          Next        : Pointer;  --  What has to match after it
  2163.          Lastloc     : Natural;  --  Where we started matching this scan
  2164.          Old_Cc      : Current_Curly_Access; --  Before we started this one
  2165.       end record;
  2166.       --  Data used to handle the curly operator and the plus and star
  2167.       --  operators for complex expressions.
  2168.  
  2169.       Current_Curly : Current_Curly_Access := null;
  2170.       --  The curly currently being processed.
  2171.  
  2172.       -----------------------
  2173.       -- Local Subprograms --
  2174.       -----------------------
  2175.  
  2176.       function Index (Start : Positive; C : Character) return Natural;
  2177.       --  Find character C in Data starting at Start and return position
  2178.  
  2179.       function Repeat (IP : Pointer;
  2180.                        Max : Natural := Natural'Last)
  2181.                       return Natural;
  2182.       --  Repeatedly match something simple, report how many
  2183.       --  It only matches on things of length 1.
  2184.       --  Starting from Input_Pos, it matches at most Max CURLY.
  2185.  
  2186.       function Try (Pos : in Positive) return Boolean;
  2187.       --  Try to match at specific point
  2188.  
  2189.       function Match (IP : Pointer) return Boolean;
  2190.       --  This is the main matching routine. Conceptually the strategy
  2191.       --  is simple:  check to see whether the current node matches,
  2192.       --  call self recursively to see whether the rest matches,
  2193.       --  and then act accordingly.
  2194.       --
  2195.       --  In practice Match makes some effort to avoid recursion, in
  2196.       --  particular by going through "ordinary" nodes (that don't
  2197.       --  need to know whether the rest of the match failed) by
  2198.       --  using a loop instead of recursion.
  2199.  
  2200.       function Match_Whilem (IP     : Pointer) return Boolean;
  2201.       --  Return True if a WHILEM matches
  2202.  
  2203.       function Match_Simple_Operator (Op     : Opcode;
  2204.                                       Scan   : Pointer;
  2205.                                       Next   : Pointer;
  2206.                                       Greedy : Boolean)
  2207.                                      return Boolean;
  2208.       --  Return True it the simple operator (possibly non-greedy) matches
  2209.  
  2210.  
  2211.       pragma Inline (Index);
  2212.       pragma Inline (Repeat);
  2213.  
  2214.       --  These are two complex functions, but used only once.
  2215.       pragma Inline (Match_Whilem);
  2216.       pragma Inline (Match_Simple_Operator);
  2217.  
  2218.       -----------
  2219.       -- Index --
  2220.       -----------
  2221.  
  2222.       function Index (Start : Positive;
  2223.                       C     : Character)
  2224.                      return  Natural
  2225.       is
  2226.       begin
  2227.          for J in Start .. Data'Last loop
  2228.             if Data (J) = C then
  2229.                return J;
  2230.             end if;
  2231.          end loop;
  2232.  
  2233.          return 0;
  2234.       end Index;
  2235.  
  2236.       ------------
  2237.       -- Repeat --
  2238.       ------------
  2239.  
  2240.       function Repeat (IP : Pointer;
  2241.                        Max : Natural := Natural'Last)
  2242.                       return Natural
  2243.       is
  2244.          Scan  : Natural := Input_Pos;
  2245.          Last  : Natural;
  2246.          Op    : constant Opcode := Opcode'Val (Character'Pos (Program (IP)));
  2247.          Count : Natural;
  2248.          C     : Character;
  2249.  
  2250.       begin
  2251.          if Max = Natural'Last or else Scan + Max - 1 > Data'Last then
  2252.             Last := Data'Last;
  2253.          else
  2254.             Last := Scan + Max - 1;
  2255.          end if;
  2256.  
  2257.          case Op is
  2258.             when ANY =>
  2259.                while Scan <= Last
  2260.                  and then Data (Scan) /= ASCII.LF
  2261.                loop
  2262.                   Scan := Scan + 1;
  2263.                end loop;
  2264.  
  2265.             when SANY =>
  2266.                Scan := Last + 1;
  2267.  
  2268.             when EXACT =>
  2269.                --  The string has only one character if Repeat was called
  2270.                C := Program (String_Operand (IP));
  2271.                while Scan <= Last
  2272.                  and then C = Data (Scan)
  2273.                loop
  2274.                   Scan := Scan + 1;
  2275.                end loop;
  2276.  
  2277.             when EXACTF =>
  2278.                --  The string has only one character if Repeat was called
  2279.                C := Program (String_Operand (IP));
  2280.                while Scan <= Last
  2281.                  and then To_Lower (C) = Data (Scan)
  2282.                loop
  2283.                   Scan := Scan + 1;
  2284.                end loop;
  2285.  
  2286.             when ANYOF =>
  2287.                declare
  2288.                   Bitmap : constant Character_Class
  2289.                     := Bitmap_Operand (Program, IP);
  2290.                begin
  2291.                   while Scan <= Last
  2292.                     and then Get_From_Class (Bitmap, Data (Scan))
  2293.                   loop
  2294.                      Scan := Scan + 1;
  2295.                   end loop;
  2296.                end;
  2297.  
  2298.             when others =>
  2299.  
  2300.                --  Repeat was called inappropriately, internal error
  2301.  
  2302.                raise Program_Error;
  2303.          end case;
  2304.  
  2305.          Count := Scan - Input_Pos;
  2306.          Input_Pos := Scan;
  2307.          return Count;
  2308.       end Repeat;
  2309.  
  2310.       ------------------
  2311.       -- Match_Whilem --
  2312.       ------------------
  2313.       --  This is really hard to understand, because after we match what we're
  2314.       --  trying to match, we must make sure the rest of the REx is going to
  2315.       --  match for sure, and to do that we have to go back UP the parse tree
  2316.       --  by recursing ever deeper.  And if it fails, we have to reset our
  2317.       --  parent's current state that we can try again after backing off.
  2318.  
  2319.       function Match_Whilem (IP : Pointer) return Boolean is
  2320.          Cc : Current_Curly_Access := Current_Curly;
  2321.          N  : Natural := Cc.Cur + 1;
  2322.          Ln : Natural;
  2323.          Lastloc : Natural := Cc.Lastloc;  --  detection of 0-len.
  2324.  
  2325.       begin
  2326.  
  2327.          --  If degenerate scan matches "", assume scan done.
  2328.          if Input_Pos = Cc.Lastloc
  2329.            and then N >= Cc.Min
  2330.          then
  2331.             --  Temporarily restore the old context, and check that we
  2332.             --  match was comes after CURLYX.
  2333.  
  2334.             Current_Curly := Cc.Old_Cc;
  2335.             if Current_Curly /= null then
  2336.                Ln := Current_Curly.Cur;
  2337.             end if;
  2338.             if Match (Cc.Next) then
  2339.                return True;
  2340.             end if;
  2341.             if Current_Curly /= null then
  2342.                Current_Curly.Cur := Ln;
  2343.             end if;
  2344.             Current_Curly := Cc;
  2345.             return False;
  2346.          end if;
  2347.  
  2348.          --  First, just match a string of min scans.
  2349.  
  2350.          if N < Cc.Min then
  2351.             Cc.Cur := N;
  2352.             Cc.Lastloc := Input_Pos;
  2353.             if Match (Cc.Scan) then
  2354.                return True;
  2355.             end if;
  2356.             Cc.Cur := N - 1;
  2357.             Cc.Lastloc := Lastloc;
  2358.             return False;
  2359.          end if;
  2360.  
  2361.          --  Prefer next over scan for minimal matching.
  2362.  
  2363.          if not Cc.Greedy then
  2364.             Current_Curly := Cc.Old_Cc;
  2365.             if Current_Curly /= null then
  2366.                Ln := Current_Curly.Cur;
  2367.             end if;
  2368.  
  2369.             if Match (Cc.Next) then
  2370.                return True;
  2371.             end if;
  2372.  
  2373.             if Current_Curly /= null then
  2374.                Current_Curly.Cur := Ln;
  2375.             end if;
  2376.             Current_Curly := Cc;
  2377.  
  2378.             --  Maximum greed exceeded ?
  2379.             if N >= Cc.Max then
  2380.                return False;
  2381.             end if;
  2382.  
  2383.             --  Try scanning more and see if it helps
  2384.             Cc.Cur := N;
  2385.             Cc.Lastloc := Input_Pos;
  2386.             if Match (Cc.Scan) then
  2387.                return True;
  2388.             end if;
  2389.             Cc.Cur := N - 1;
  2390.             Cc.Lastloc := Lastloc;
  2391.             return False;
  2392.          end if;
  2393.  
  2394.          --  Prefer scan over next for maximal matching
  2395.  
  2396.          if N < Cc.Max then   --  more greed allowed ?
  2397.             Cc.Cur := N;
  2398.             Cc.Lastloc := Input_Pos;
  2399.             if Match (Cc.Scan) then
  2400.                return True;
  2401.             end if;
  2402.          end if;
  2403.  
  2404.          --  Failed deeper matches of scan, so see if this one works
  2405.          Current_Curly := Cc.Old_Cc;
  2406.          if Current_Curly /= null then
  2407.             Ln := Current_Curly.Cur;
  2408.          end if;
  2409.  
  2410.          if Match (Cc.Next) then
  2411.             return True;
  2412.          end if;
  2413.  
  2414.          if Current_Curly /= null then
  2415.             Current_Curly.Cur := Ln;
  2416.          end if;
  2417.  
  2418.          Current_Curly := Cc;
  2419.          Cc.Cur := N - 1;
  2420.          Cc.Lastloc := Lastloc;
  2421.          return False;
  2422.  
  2423.       end Match_Whilem;
  2424.  
  2425.       ---------------------------
  2426.       -- Match_Simple_Operator --
  2427.       ---------------------------
  2428.  
  2429.       function Match_Simple_Operator (Op     : Opcode;
  2430.                                       Scan   : Pointer;
  2431.                                       Next   : Pointer;
  2432.                                       Greedy : Boolean)
  2433.                                      return Boolean
  2434.       is
  2435.          Next_Char : Character := ASCII.Nul;
  2436.          Next_Char_Known : Boolean := False;
  2437.          No        : Integer;  --  Has to be negative
  2438.          Min       : Natural;
  2439.          Max       : Natural := Natural'Last;
  2440.          Operand_Code : Pointer;
  2441.          Old       : Natural;
  2442.          Last_Pos  : Natural;
  2443.          Save      : Natural := Input_Pos;
  2444.       begin
  2445.          --  Lookahead to avoid useless match attempts
  2446.          --  when we know what character comes next.
  2447.  
  2448.          if Program (Next) = EXACT then
  2449.             Next_Char := Program (String_Operand (Next));
  2450.             Next_Char_Known := True;
  2451.          end if;
  2452.  
  2453.          --  Find the minimal and maximal values for the operator
  2454.  
  2455.          case Op is
  2456.             when STAR =>
  2457.                Min := 0;
  2458.                Operand_Code := Operand (Scan);
  2459.  
  2460.             when PLUS =>
  2461.                Min := 1;
  2462.                Operand_Code := Operand (Scan);
  2463.  
  2464.             when others =>
  2465.                Min := Read_Natural (Program, Scan + 3);
  2466.                Max := Read_Natural (Program, Scan + 5);
  2467.                Operand_Code := Scan + 7;
  2468.          end case;
  2469.  
  2470.          --  Non greedy operators
  2471.  
  2472.          if not Greedy then
  2473.  
  2474.             --  Test the minimal repetitions
  2475.  
  2476.             if Min /= 0
  2477.               and then Repeat (Operand_Code, Min) < Min
  2478.             then
  2479.                return False;
  2480.             end if;
  2481.  
  2482.             Old := Input_Pos;
  2483.  
  2484.             --  Find the place where 'next' could work
  2485.  
  2486.             if Next_Char_Known then
  2487.  
  2488.                --  Last position to check
  2489.                Last_Pos := Input_Pos + Max;
  2490.                if Last_Pos > Data'Last
  2491.                  or else Max = Natural'Last
  2492.                then
  2493.                   Last_Pos := Data'Last;
  2494.                end if;
  2495.  
  2496.                --  Look for the first possible opportunity
  2497.                loop
  2498.  
  2499.                   Input_Pos := Old;
  2500.  
  2501.                   --  Find the next possible position
  2502.                   while Input_Pos <= Last_Pos
  2503.                     and then Data (Input_Pos) /= Next_Char
  2504.                   loop
  2505.                      Input_Pos := Input_Pos + 1;
  2506.                   end loop;
  2507.  
  2508.                   if Input_Pos > Last_Pos then
  2509.                      return False;
  2510.                   end if;
  2511.  
  2512.                   --  Check that we still match if we stop
  2513.                   --  at the position we just found.
  2514.                   declare
  2515.                      Num : constant Natural := Input_Pos - Old;
  2516.                   begin
  2517.                      Input_Pos := Old;
  2518.                      if Repeat (Operand_Code, Num) < Num then
  2519.                         return False;
  2520.                      end if;
  2521.                   end;
  2522.  
  2523.                   --  Input_Pos now points to the new position
  2524.                   if Match (Get_Next (Program, Scan)) then
  2525.                      return True;
  2526.                   end if;
  2527.  
  2528.                   Old := Input_Pos;
  2529.                   Input_Pos := Input_Pos + 1;
  2530.                end loop;
  2531.  
  2532.             --  We know what the next character is
  2533.             else
  2534.  
  2535.                while Max >= Min loop
  2536.  
  2537.                   --  If the next character matches
  2538.                   if Match (Next) then
  2539.                      return True;
  2540.                   end if;
  2541.  
  2542.                   Input_Pos := Save + Min;
  2543.                   --  Could not or did not match -- move forward
  2544.                   if Repeat (Operand_Code, 1) /= 0 then
  2545.                      Min := Min + 1;
  2546.                   else
  2547.                      return False;
  2548.                   end if;
  2549.                end loop;
  2550.             end if;
  2551.             return False;
  2552.  
  2553.             --  Greedy operators
  2554.          else
  2555.             No := Repeat (Operand_Code, Max);
  2556.  
  2557.             --  ???Perl has some special code here in case the
  2558.             --  next instruction is of type EOL, since $ and \Z
  2559.             --  can match before *and* after newline at the end.
  2560.  
  2561.             --  ???Perl has some special code here in case (paren)
  2562.             --  is True.
  2563.  
  2564.             --  Else, if we don't have any parenthesis
  2565.  
  2566.             while No >= Min loop
  2567.                if not Next_Char_Known
  2568.                  or else (Input_Pos <= Data'Last
  2569.                           and then Data (Input_Pos) = Next_Char)
  2570.                then
  2571.                   if Match (Next) then
  2572.                      return True;
  2573.                   end if;
  2574.                end if;
  2575.  
  2576.                --  Could not or did not work, we back up
  2577.                No := No - 1;
  2578.                Input_Pos := Save + No;
  2579.             end loop;
  2580.             return False;
  2581.          end if;
  2582.       end Match_Simple_Operator;
  2583.  
  2584.       -----------
  2585.       -- Match --
  2586.       -----------
  2587.  
  2588.       function Match (IP   : Pointer) return Boolean is
  2589.          Scan   : Pointer := IP;
  2590.          Next   : Pointer;
  2591.          Save   : Natural;
  2592.          Op     : Opcode;
  2593.  
  2594.       begin
  2595.          State_Machine :
  2596.          loop
  2597.             pragma Assert (Scan /= 0);
  2598.  
  2599.             --  Determine current opcode and count its usage in debug mode
  2600.  
  2601.             Op := Opcode'Val (Character'Pos (Program (Scan)));
  2602.  
  2603.             --  Calculate offset of next instruction.
  2604.             --  Second character is most significant in Program_Data.
  2605.  
  2606.             Next := Get_Next (Program, Scan);
  2607.  
  2608.             case Op is
  2609.                when EOP =>
  2610.                   return True;  --  Success !
  2611.  
  2612.                when BRANCH =>
  2613.                   if Program (Next) /= BRANCH then
  2614.                      Next := Operand (Scan); -- No choice, avoid recursion
  2615.  
  2616.                   else
  2617.                      if Input_Pos > Data'Last then
  2618.                         return False;
  2619.                      end if;
  2620.  
  2621.                      loop
  2622.                         Save := Input_Pos;
  2623.  
  2624.                         if Match (Operand (Scan)) then
  2625.                            return True;
  2626.                         end if;
  2627.  
  2628.                         Input_Pos := Save;
  2629.                         Scan := Get_Next (Program, Scan);
  2630.                         exit when Scan = 0 or Program (Scan) /= BRANCH;
  2631.                      end loop;
  2632.  
  2633.                      exit State_Machine;
  2634.                   end if;
  2635.  
  2636.                when NOTHING =>
  2637.                   null;
  2638.  
  2639.                when BOL =>
  2640.                   exit State_Machine when
  2641.                     Input_Pos /= BOL_Pos
  2642.                     and then ((Self.Flags and Multiple_Lines) = 0
  2643.                               or else Data (Input_Pos - 1) /= ASCII.LF);
  2644.  
  2645.                when MBOL =>
  2646.                   exit State_Machine when
  2647.                     Input_Pos /= BOL_Pos
  2648.                     and then Data (Input_Pos - 1) /= ASCII.LF;
  2649.  
  2650.                when SBOL =>
  2651.                   exit State_Machine when Input_Pos /= BOL_Pos;
  2652.  
  2653.                when EOL =>
  2654.                   exit State_Machine when
  2655.                     Input_Pos <= Data'Last
  2656.                     and then ((Self.Flags and Multiple_Lines) = 0
  2657.                               or else Data (Input_Pos) /= ASCII.LF);
  2658.  
  2659.                when MEOL =>
  2660.                   exit State_Machine when
  2661.                     Input_Pos <= Data'Last
  2662.                     and then Data (Input_Pos) /= ASCII.LF;
  2663.  
  2664.                when SEOL =>
  2665.                   exit State_Machine when Input_Pos <= Data'Last;
  2666.  
  2667.                when BOUND | NBOUND =>
  2668.                   --  Was last char in word ?
  2669.                   declare
  2670.                      N  : Boolean := False;
  2671.                      Ln : Boolean := False;
  2672.                   begin
  2673.                      if Input_Pos /= Data'First then
  2674.                         N := Is_Alnum (Data (Input_Pos - 1));
  2675.                      end if;
  2676.                      if Input_Pos > Data'Last then
  2677.                         Ln := False;
  2678.                      else
  2679.                         Ln := Is_Alnum (Data (Input_Pos));
  2680.                      end if;
  2681.                      if Op = BOUND then
  2682.                         if N = Ln then
  2683.                            exit State_Machine;
  2684.                         end if;
  2685.                      else
  2686.                         if N /= Ln then
  2687.                            exit State_Machine;
  2688.                         end if;
  2689.                      end if;
  2690.                   end;
  2691.  
  2692.                when SPACE =>
  2693.                   exit State_Machine when
  2694.                     Input_Pos > Data'Last
  2695.                     or else not Is_Space (Data (Input_Pos));
  2696.                   Input_Pos := Input_Pos + 1;
  2697.  
  2698.                when NSPACE =>
  2699.                   exit State_Machine when
  2700.                     Input_Pos > Data'Last
  2701.                     or else Is_Space (Data (Input_Pos));
  2702.                   Input_Pos := Input_Pos + 1;
  2703.  
  2704.                when DIGIT =>
  2705.                   exit State_Machine when
  2706.                     Input_Pos > Data'Last
  2707.                     or else not Is_Digit (Data (Input_Pos));
  2708.                   Input_Pos := Input_Pos + 1;
  2709.  
  2710.                when NDIGIT =>
  2711.                   exit State_Machine when
  2712.                     Input_Pos > Data'Last
  2713.                     or else Is_Digit (Data (Input_Pos));
  2714.                   Input_Pos := Input_Pos + 1;
  2715.  
  2716.                when ALNUM =>
  2717.                   exit State_Machine when
  2718.                     Input_Pos > Data'Last
  2719.                     or else not Is_Alnum (Data (Input_Pos));
  2720.                   Input_Pos := Input_Pos + 1;
  2721.  
  2722.                when NALNUM =>
  2723.                   exit State_Machine when
  2724.                     Input_Pos > Data'Last
  2725.                     or else Is_Alnum (Data (Input_Pos));
  2726.                   Input_Pos := Input_Pos + 1;
  2727.  
  2728.                when ANY =>
  2729.                   exit State_Machine when Input_Pos > Data'Last
  2730.                     or else Data (Input_Pos) = ASCII.LF;
  2731.                   Input_Pos := Input_Pos + 1;
  2732.  
  2733.                when SANY =>
  2734.                   exit State_Machine when Input_Pos > Data'Last;
  2735.                   Input_Pos := Input_Pos + 1;
  2736.  
  2737.                when EXACT =>
  2738.                   declare
  2739.                      Opnd    : Pointer := String_Operand (Scan);
  2740.                      Current : Positive := Input_Pos;
  2741.                      Last    : constant Pointer
  2742.                        := Opnd + String_Length (Program, Scan);
  2743.  
  2744.                   begin
  2745.                      while Opnd <= Last loop
  2746.                         exit State_Machine when Current > Data'Last
  2747.                           or else Program (Opnd) /= Data (Current);
  2748.                         Current := Current + 1;
  2749.                         Opnd := Opnd + 1;
  2750.                      end loop;
  2751.  
  2752.                      Input_Pos := Current;
  2753.                   end;
  2754.  
  2755.                when EXACTF =>
  2756.                   declare
  2757.                      Opnd    : Pointer := String_Operand (Scan);
  2758.                      Current : Positive := Input_Pos;
  2759.                      Last    : constant Pointer
  2760.                        := Opnd + String_Length (Program, Scan);
  2761.  
  2762.                   begin
  2763.                      while Opnd <= Last loop
  2764.                         exit State_Machine when Current > Data'Last
  2765.                           or else Program (Opnd) /= To_Lower (Data (Current));
  2766.                         Current := Current + 1;
  2767.                         Opnd := Opnd + 1;
  2768.                      end loop;
  2769.  
  2770.                      Input_Pos := Current;
  2771.                   end;
  2772.  
  2773.                when ANYOF =>
  2774.                   declare
  2775.                      Bitmap : constant Character_Class
  2776.                        := Bitmap_Operand (Program, IP);
  2777.                   begin
  2778.                      exit State_Machine when
  2779.                        Input_Pos > Data'Last
  2780.                        or else not Get_From_Class (Bitmap, Data (Input_Pos));
  2781.                      Input_Pos := Input_Pos + 1;
  2782.                   end;
  2783.  
  2784.                when OPEN =>
  2785.                   declare
  2786.                      No : constant Natural
  2787.                        := Character'Pos (Program (Operand (Scan)));
  2788.                   begin
  2789.                      Matches_Tmp (No).First := Input_Pos;
  2790.                   end;
  2791.  
  2792.                when CLOSE =>
  2793.                   declare
  2794.                      No : constant Natural
  2795.                        := Character'Pos (Program (Operand (Scan)));
  2796.                   begin
  2797.                      Matches_Full (No) := (First => Matches_Tmp (No).First,
  2798.                                            Last  => Input_Pos - 1);
  2799.                      if Last_Paren < No then
  2800.                         Last_Paren := No;
  2801.                      end if;
  2802.                   end;
  2803.  
  2804.                when REFF =>
  2805.                   declare
  2806.                      No : constant Natural
  2807.                        := Character'Pos (Program (Operand (Scan)));
  2808.                      Data_Pos : Natural;
  2809.                   begin
  2810.                      --  If we haven't seen that parenthesis yet.
  2811.                      if Last_Paren < No then
  2812.                         return False;
  2813.                      end if;
  2814.  
  2815.                      Data_Pos := Matches_Full (No).First;
  2816.                      while Data_Pos <= Matches_Full (No).Last loop
  2817.                         if Input_Pos > Data'Last
  2818.                           or else Data (Input_Pos) /= Data (Data_Pos)
  2819.                         then
  2820.                            return False;
  2821.                         end if;
  2822.                         Input_Pos := Input_Pos + 1;
  2823.                         Data_Pos := Data_Pos + 1;
  2824.                      end loop;
  2825.                   end;
  2826.  
  2827.                when MINMOD =>
  2828.                   Greedy := False;
  2829.  
  2830.                when STAR | PLUS | CURLY =>
  2831.                   declare
  2832.                      Greed : constant Boolean := Greedy;
  2833.                   begin
  2834.                      Greedy := True;
  2835.                      return Match_Simple_Operator (Op, Scan, Next, Greed);
  2836.                   end;
  2837.  
  2838.                when CURLYX =>
  2839.                   --  Looking at something like:
  2840.                   --    1: CURLYX {n,m}  (->4)
  2841.                   --    2:   code for complex thing  (->3)
  2842.                   --    3:   WHILEM (->0)
  2843.                   --    4: NOTHING
  2844.  
  2845.                   declare
  2846.                      Cc : aliased Current_Curly_Record;
  2847.                      Min : Natural := Read_Natural (Program, Scan + 3);
  2848.                      Max : Natural := Read_Natural (Program, Scan + 5);
  2849.                      Has_Match : Boolean;
  2850.                   begin
  2851.                      Cc := (Paren_Floor => Last_Paren,
  2852.                             Cur         => -1,
  2853.                             Min         => Min,
  2854.                             Max         => Max,
  2855.                             Greedy      => Greedy,
  2856.                             Scan        => Scan + 7,
  2857.                             Next        => Next,
  2858.                             Lastloc     => 0,
  2859.                             Old_Cc      => Current_Curly);
  2860.                      Current_Curly := Cc'Unchecked_Access;
  2861.  
  2862.                      Has_Match := Match (Next - 3);
  2863.                      --  Start on the WHILEM
  2864.  
  2865.                      Current_Curly := Cc.Old_Cc;
  2866.                      return Has_Match;
  2867.                   end;
  2868.  
  2869.                when WHILEM =>
  2870.                   return Match_Whilem (IP);
  2871.  
  2872.                when others =>
  2873.                   raise Expression_Error;           -- Invalid instruction
  2874.             end case;
  2875.  
  2876.             Scan := Next;
  2877.          end loop State_Machine;
  2878.  
  2879.          --  If we get here, there is no match.
  2880.          --  For successful matches when EOP is the terminating point.
  2881.  
  2882.          return False;
  2883.       end Match;
  2884.  
  2885.       ---------
  2886.       -- Try --
  2887.       ---------
  2888.  
  2889.       function Try (Pos : in Positive) return Boolean is
  2890.       begin
  2891.          Input_Pos  := Pos;
  2892.          Last_Paren := 0;
  2893.          Matches_Full := (others => No_Match);
  2894.  
  2895.          if Match (Program_First + 1) then
  2896.             Matches_Full (0) := (Pos, Input_Pos - 1);
  2897.             return True;
  2898.          end if;
  2899.  
  2900.          return False;
  2901.       end Try;
  2902.  
  2903.    --  Start of processing for Match
  2904.  
  2905.    begin
  2906.       --  Check validity of program
  2907.  
  2908.       pragma Assert
  2909.         (Program (Program_First) = MAGIC,
  2910.          "Corrupted Pattern_Matcher");
  2911.  
  2912.       --  If there is a "must appear" string, look for it
  2913.  
  2914.       if Self.Must_Have_Length > 0 then
  2915.          declare
  2916.             First      : constant Character := Program (Self.Must_Have);
  2917.             Must_First : constant Pointer := Self.Must_Have;
  2918.             Must_Last  : constant Pointer :=
  2919.                            Must_First + Pointer (Self.Must_Have_Length - 1);
  2920.             Next_Try   : Natural := Index (Data'First, First);
  2921.  
  2922.          begin
  2923.             while Next_Try /= 0
  2924.               and then Data (Next_Try .. Next_Try + Self.Must_Have_Length - 1)
  2925.                 = String (Program (Must_First .. Must_Last))
  2926.             loop
  2927.                Next_Try := Index (Next_Try + 1, First);
  2928.             end loop;
  2929.  
  2930.             if Next_Try = 0 then
  2931.                Matches_Full := (others => No_Match);
  2932.                return;                  -- Not present
  2933.             end if;
  2934.          end;
  2935.       end if;
  2936.  
  2937.       --  Mark beginning of line for ^
  2938.  
  2939.       BOL_Pos := Data'First;
  2940.  
  2941.       --  Simplest case first: an anchored match need be tried only once
  2942.  
  2943.       if Self.Anchored then
  2944.          Matched := Try (Data'First);
  2945.  
  2946.       elsif Self.First /= ASCII.NUL then
  2947.  
  2948.          --  We know what char it must start with
  2949.  
  2950.          declare
  2951.             Next_Try : Natural := Index (Data'First, Self.First);
  2952.  
  2953.          begin
  2954.             while Next_Try /= 0 loop
  2955.                Matched := Try (Next_Try);
  2956.                exit when Matched;
  2957.                Next_Try := Index (Next_Try + 1, Self.First);
  2958.             end loop;
  2959.          end;
  2960.  
  2961.       else
  2962.          --  Messy cases: try all locations
  2963.  
  2964.          for S in Data'Range loop
  2965.             Matched := Try (S);
  2966.             exit when Matched;
  2967.          end loop;
  2968.       end if;
  2969.  
  2970.       --  Matched has its value
  2971.       Matches := Matches_Full (Matches'Range);
  2972.       return;
  2973.    end Match;
  2974.  
  2975.    -----------
  2976.    -- Match --
  2977.    -----------
  2978.  
  2979.    function  Match
  2980.      (Self : Pattern_Matcher;
  2981.       Data : String)
  2982.       return Natural
  2983.    is
  2984.       Matches : Match_Array (0 .. 0);
  2985.  
  2986.    begin
  2987.       Match (Self, Data, Matches);
  2988.  
  2989.       if Matches (0).First < Data'First then
  2990.          return Data'First - 1;
  2991.       end if;
  2992.  
  2993.       return Matches (0).First;
  2994.    end Match;
  2995.  
  2996.    -----------
  2997.    -- Match --
  2998.    -----------
  2999.  
  3000.    procedure Match
  3001.      (Expression : String;
  3002.       Data       : String;
  3003.       Matches    : out Match_Array;
  3004.       Size       : Program_Size := 0)
  3005.    is
  3006.       PM            : Pattern_Matcher (Size);
  3007.       Finalize_Size : Program_Size;
  3008.    begin
  3009.       if Size = 0 then
  3010.          Match (Compile (Expression), Data, Matches);
  3011.       else
  3012.          Compile (PM, Expression, Finalize_Size);
  3013.          Match (PM, Data, Matches);
  3014.       end if;
  3015.    end Match;
  3016.  
  3017.    -----------
  3018.    -- Match --
  3019.    -----------
  3020.  
  3021.    function  Match
  3022.      (Expression : String;
  3023.       Data       : String;
  3024.       Size       : Program_Size := 0)
  3025.       return       Natural
  3026.    is
  3027.       PM         : Pattern_Matcher (Size);
  3028.       Final_Size : Program_Size; -- unused
  3029.  
  3030.    begin
  3031.       if Size = 0 then
  3032.          return Match (Compile (Expression), Data);
  3033.       else
  3034.          Compile (PM, Expression, Final_Size);
  3035.          return Match (PM, Data);
  3036.       end if;
  3037.    end Match;
  3038.  
  3039.    -----------
  3040.    -- Match --
  3041.    -----------
  3042.  
  3043.    function  Match
  3044.      (Expression : String;
  3045.       Data       : String;
  3046.       Size       : Program_Size := 0)
  3047.       return       Boolean
  3048.    is
  3049.       Matches    : Match_Array (0 .. 0);
  3050.       PM         : Pattern_Matcher (Size);
  3051.       Final_Size : Program_Size; -- unused
  3052.  
  3053.    begin
  3054.       if Size = 0 then
  3055.          Match (Compile (Expression), Data, Matches);
  3056.       else
  3057.          Compile (PM, Expression, Final_Size);
  3058.          Match (PM, Data, Matches);
  3059.       end if;
  3060.       return Matches (0).First >= Data'First;
  3061.    end Match;
  3062.  
  3063.    ----------
  3064.    -- Dump --
  3065.    ----------
  3066.  
  3067.    procedure Dump (Self : Pattern_Matcher) is
  3068.       --  Index  : Pointer := Program_First + 1;
  3069.       Op     : Opcode;
  3070.       Program : Program_Data renames Self.Program;
  3071.  
  3072.       procedure Dump_Until (Start  : Pointer;
  3073.                             Till   : Pointer;
  3074.                             Indent : Natural := 0);
  3075.       --  Dump the program until the node Till (not included) is
  3076.       --  met.
  3077.       --  Every line is indented with Index spaces at the beginning
  3078.       --  Dumps till the end if Till is 0.
  3079.  
  3080.       ----------------
  3081.       -- Dump_Until --
  3082.       ----------------
  3083.  
  3084.       procedure Dump_Until (Start  : Pointer;
  3085.                             Till   : Pointer;
  3086.                             Indent : Natural := 0)
  3087.       is
  3088.          Next : Pointer;
  3089.          Index : Pointer := Start;
  3090.          Local_Indent : Natural := Indent;
  3091.          Length : Pointer;
  3092.       begin
  3093.          loop
  3094.             exit when Index >= Till;
  3095.  
  3096.             Op := Opcode'Val (Character'Pos ((Self.Program (Index))));
  3097.  
  3098.             if Op = CLOSE then
  3099.                Local_Indent := Local_Indent - 3;
  3100.             end if;
  3101.  
  3102.             declare
  3103.                Point : String := Pointer'Image (Index);
  3104.             begin
  3105.                for J in 1 .. 6 - Point'Length loop
  3106.                   Put (' ');
  3107.                end loop;
  3108.                Put (Point
  3109.                     & " : "
  3110.                     & (1 .. Local_Indent => ' ')
  3111.                     & Opcode'Image (Op));
  3112.             end;
  3113.  
  3114.             --  Print the parenthesis number
  3115.             if Op = OPEN or else Op = CLOSE or else Op = REFF then
  3116.                Put (Natural'Image (Character'Pos (Program (Index + 3))));
  3117.             end if;
  3118.  
  3119.             Next := Index + Get_Next_Offset (Program, Index);
  3120.             if Next = Index then
  3121.                Put ("  (next at 0)");
  3122.             else
  3123.                Put ("  (next at " & Pointer'Image (Next) & ")");
  3124.             end if;
  3125.  
  3126.             case Op is
  3127.                --  character class operand
  3128.                when ANYOF =>  null;
  3129.                   declare
  3130.                      Bitmap : constant Character_Class
  3131.                        := Bitmap_Operand (Program, Index);
  3132.                      Last    : Character := ASCII.Nul;
  3133.                      Current : Natural := 0;
  3134.                      Current_Char : Character;
  3135.                   begin
  3136.                      Put ("   operand=");
  3137.                      while Current <= 255 loop
  3138.                         Current_Char := Character'Val (Current);
  3139.  
  3140.                         --  First item in a range
  3141.                         if Get_From_Class (Bitmap, Current_Char) then
  3142.                            Last := Current_Char;
  3143.  
  3144.                            --  Search for the last item in the range
  3145.                            loop
  3146.                               Current := Current + 1;
  3147.                               exit when Current > 255;
  3148.                               Current_Char := Character'Val (Current);
  3149.                               exit when
  3150.                                 not Get_From_Class (Bitmap, Current_Char);
  3151.  
  3152.                            end loop;
  3153.  
  3154.                            if Last <= ' ' then
  3155.                               Put (Last'Img);
  3156.                            else
  3157.                               Put (Last);
  3158.                            end if;
  3159.                            if Character'Succ (Last) /= Current_Char then
  3160.                               Put ("-" & Character'Pred (Current_Char));
  3161.                            end if;
  3162.                         else
  3163.                            Current := Current + 1;
  3164.                         end if;
  3165.                      end loop;
  3166.                      New_Line;
  3167.                      Index := Index + 3 + Bitmap'Length;
  3168.                   end;
  3169.  
  3170.                --  string operand
  3171.                when EXACT | EXACTF =>
  3172.                   Length := String_Length (Program, Index);
  3173.                   Put ("   operand (length:" & Program_Size'Image (Length + 1)
  3174.                        & ") ="
  3175.                        & String (Program (String_Operand (Index)
  3176.                                           .. String_Operand (Index)
  3177.                                           + Length)));
  3178.                   Index := String_Operand (Index) + Length + 1;
  3179.                   New_Line;
  3180.  
  3181.                   --  node operand
  3182.                when BRANCH | STAR | PLUS =>
  3183.                   New_Line;
  3184.                   Dump_Until (Index + 3, Next, Local_Indent + 3);
  3185.                   Index := Next;
  3186.  
  3187.                when CURLY | CURLYX =>
  3188.                   Put ("  {"
  3189.                        & Natural'Image (Read_Natural (Program, Index + 3))
  3190.                        & ","
  3191.                        & Natural'Image (Read_Natural (Program, Index + 5))
  3192.                        & "}");
  3193.                   New_Line;
  3194.                   Dump_Until (Index + 7, Next, Local_Indent + 3);
  3195.                   Index := Next;
  3196.  
  3197.                when OPEN =>
  3198.                   New_Line;
  3199.                   Index := Index + 4;
  3200.                   Local_Indent := Local_Indent + 3;
  3201.  
  3202.                when CLOSE | REFF =>
  3203.                   New_Line;
  3204.                   Index := Index + 4;
  3205.  
  3206.                when EOP =>
  3207.                   Index := Index + 3;
  3208.                   New_Line;
  3209.                   exit;
  3210.  
  3211.                   --  no operand
  3212.                when others =>
  3213.                   Index := Index + 3;
  3214.                   New_Line;
  3215.             end case;
  3216.          end loop;
  3217.       end Dump_Until;
  3218.    begin
  3219.       pragma Assert (Self.Program (Program_First) = MAGIC,
  3220.                      "Corrupted Pattern_Matcher");
  3221.  
  3222.       Put_Line ("Must start with (Self.First) = "
  3223.                 & Character'Image (Self.First));
  3224.       if (Self.Flags and Case_Insensitive) /= 0 then
  3225.          Put_Line ("  Case_Insensitive mode");
  3226.       end if;
  3227.       if (Self.Flags and Single_Line) /= 0 then
  3228.          Put_Line ("  Single_Line mode");
  3229.       end if;
  3230.       if (Self.Flags and Multiple_Lines) /= 0 then
  3231.          Put_Line ("  Multiple_Lines mode");
  3232.       end if;
  3233.  
  3234.       Put_Line ("     1 : MAGIC");
  3235.       Dump_Until (Program_First + 1, Self.Program'Last + 1);
  3236.    end Dump;
  3237.  
  3238.    -----------
  3239.    -- Quote --
  3240.    -----------
  3241.  
  3242.    function Quote (Str : String) return String is
  3243.       S    : String (1 .. Str'Length * 2);
  3244.       Last : Natural := 0;
  3245.    begin
  3246.       for J in Str'Range loop
  3247.          case Str (J) is
  3248.             when '^' | '$' | '|' | '*' | '+' | '?' | '{'
  3249.               | '}' | '[' | ']' | '\' =>
  3250.  
  3251.                S (Last + 1) := '\';
  3252.                S (Last + 2) := Str (J);
  3253.                Last := Last + 2;
  3254.  
  3255.             when others =>
  3256.                S (Last + 1) := Str (J);
  3257.                Last := Last + 1;
  3258.          end case;
  3259.       end loop;
  3260.       return S (1 .. Last);
  3261.    end Quote;
  3262.  
  3263. end GNAT.Regpat;
  3264.  
  3265.