[Pcre-svn] [555] code/trunk: Major refactoring of pcre2_comp…

Top Page
Delete this message
Author: Subversion repository
Date:  
To: pcre-svn
Subject: [Pcre-svn] [555] code/trunk: Major refactoring of pcre2_compile.c; see ChangeLog and HACKING.
Revision: 555
          http://www.exim.org/viewvc/pcre2?view=rev&revision=555
Author:   ph10
Date:     2016-10-02 17:01:01 +0100 (Sun, 02 Oct 2016)
Log Message:
-----------
Major refactoring of pcre2_compile.c; see ChangeLog and HACKING.


Modified Paths:
--------------
    code/trunk/ChangeLog
    code/trunk/HACKING
    code/trunk/Makefile.am
    code/trunk/RunTest
    code/trunk/doc/pcre2api.3
    code/trunk/doc/pcre2callout.3
    code/trunk/doc/pcre2compat.3
    code/trunk/doc/pcre2limits.3
    code/trunk/doc/pcre2pattern.3
    code/trunk/doc/pcre2syntax.3
    code/trunk/perltest.sh
    code/trunk/src/pcre2_compile.c
    code/trunk/src/pcre2_error.c
    code/trunk/src/pcre2_internal.h
    code/trunk/src/pcre2_intmodedep.h
    code/trunk/src/pcre2_substitute.c
    code/trunk/src/pcre2test.c
    code/trunk/testdata/testinput1
    code/trunk/testdata/testinput15
    code/trunk/testdata/testinput17
    code/trunk/testdata/testinput2
    code/trunk/testdata/testinput5
    code/trunk/testdata/testinput6
    code/trunk/testdata/testinput8
    code/trunk/testdata/testoutput1
    code/trunk/testdata/testoutput12-16
    code/trunk/testdata/testoutput15
    code/trunk/testdata/testoutput17
    code/trunk/testdata/testoutput18
    code/trunk/testdata/testoutput2
    code/trunk/testdata/testoutput21
    code/trunk/testdata/testoutput22-16
    code/trunk/testdata/testoutput22-8
    code/trunk/testdata/testoutput23
    code/trunk/testdata/testoutput5
    code/trunk/testdata/testoutput6
    code/trunk/testdata/testoutput8-16-2
    code/trunk/testdata/testoutput8-16-3
    code/trunk/testdata/testoutput8-16-4
    code/trunk/testdata/testoutput8-32-2
    code/trunk/testdata/testoutput8-32-3
    code/trunk/testdata/testoutput8-32-4
    code/trunk/testdata/testoutput8-8-2
    code/trunk/testdata/testoutput8-8-3
    code/trunk/testdata/testoutput8-8-4
    code/trunk/testdata/testoutput9


Modified: code/trunk/ChangeLog
===================================================================
--- code/trunk/ChangeLog    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/ChangeLog    2016-10-02 16:01:01 UTC (rev 555)
@@ -14,7 +14,47 @@
 There was a bug that caused this not to happen if a Unicode property item was
 added to such a class, for example [\D\P{Nd}] or [\W\pL].


+3. There has been a major re-factoring of the pcre2_compile.c file. Most syntax
+checking is now done in the pre-pass that identifies capturing groups. This has
+reduced the amount of duplication and made the code tidier. While doing this,
+some minor bugs and Perl incompatibilities were fixed, including:

+  (a) \Q\E in the middle of a quantifier such as A+\Q\E+ is now ignored instead
+      of giving an invalid quantifier error.
+  (b) {0} can now be used after a group in a lookbehind assertion; previously
+      this caused an "assertion is not fixed length" error.
+  (c) Perl always treats (?(DEFINE) as a "define" group, even if a group with 
+      the name "DEFINE" exists. PCRE2 now does likewise.
+  (d) A recursion condition test such as (?(R2)...) must now refer to an 
+      existing subpattern.
+
+One effect of the refactoring is that some error numbers and messages have 
+changed, and the pattern offset given for compiling errors is not always the
+right-most character that has been read. In particular, for a variable-length
+lookbehind assertion it now points to the start of the assertion. Another
+change is that when a callout appears before a group, the "length of next
+pattern item" that is passed now just gives the length of the opening
+parenthesis item, not the length of the whole group. A length of zero is now
+given only for a callout at the end of the pattern. Automatic callouts are no 
+longer inserted before and after explicit callouts in the pattern.
+
+4. Back references are now permitted in lookbehind assertions when there are 
+no duplicated group numbers (that is, (?| has not been used), and, if the 
+reference is by name, there is only one group of that name. The referenced
+group must, of course be of fixed length.
+
+5. pcre2test has been upgraded so that, when run under valgrind with valgrind 
+support enabled, reading past the end of the pattern is detected, both when 
+compiling and during callout processing.
+
+6. \g{+<number>} (e.g. \g{+2)} ) is now supported. It is a "forward back 
+reference" and can be useful in repetitions (compare \g{-<number>}). Perl does 
+not recognize this syntax.
+
+7. Automatic callouts are no longer generated before and after callouts in the 
+pattern.
+
+
 Version 10.22 29-July-2016
 --------------------------



Modified: code/trunk/HACKING
===================================================================
--- code/trunk/HACKING    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/HACKING    2016-10-02 16:01:01 UTC (rev 555)
@@ -7,8 +7,8 @@
 library is referred to as PCRE1 below. For information about testing PCRE2, see
 the pcre2test documentation and the comment at the head of the RunTest file.


-PCRE1 releases were up to 8.3x when PCRE2 was developed. The 8.xx series will
-continue for bugfixes if necessary. PCRE2 releases started at 10.00 to avoid
+PCRE1 releases were up to 8.3x when PCRE2 was developed, and later bug fix
+releases remain in the 8.xx series. PCRE2 releases started at 10.00 to avoid
confusion with PCRE1.


@@ -16,19 +16,20 @@
-----------------

Many years ago I implemented some regular expression functions to an algorithm
-suggested by Martin Richards. These were not Unix-like in form, and were quite
-restricted in what they could do by comparison with Perl. The interesting part
-about the algorithm was that the amount of space required to hold the compiled
-form of an expression was known in advance. The code to apply an expression did
-not operate by backtracking, as the original Henry Spencer code and current
-PCRE2 and Perl code does, but instead checked all possibilities simultaneously
-by keeping a list of current states and checking all of them as it advanced
-through the subject string. In the terminology of Jeffrey Friedl's book, it was
-a "DFA algorithm", though it was not a traditional Finite State Machine (FSM).
-When the pattern was all used up, all remaining states were possible matches,
-and the one matching the longest subset of the subject string was chosen. This
-did not necessarily maximize the individual wild portions of the pattern, as is
-expected in Unix and Perl-style regular expressions.
+suggested by Martin Richards. The rather simple patterns were not Unix-like in
+form, and were quite restricted in what they could do by comparison with Perl.
+The interesting part about the algorithm was that the amount of space required
+to hold the compiled form of an expression was known in advance. The code to
+apply an expression did not operate by backtracking, as the original Henry
+Spencer code and current PCRE2 and Perl code does, but instead checked all
+possibilities simultaneously by keeping a list of current states and checking
+all of them as it advanced through the subject string. In the terminology of
+Jeffrey Friedl's book, it was a "DFA algorithm", though it was not a
+traditional Finite State Machine (FSM). When the pattern was all used up, all
+remaining states were possible matches, and the one matching the longest subset
+of the subject string was chosen. This did not necessarily maximize the
+individual wild portions of the pattern, as is expected in Unix and Perl-style
+regular expressions.


Historical note 2
@@ -85,7 +86,7 @@
things I did for 6.8 was to fix Yet Another Bug in the memory computation. Then
I had a flash of inspiration as to how I could run the real compile function in
a "fake" mode that enables it to compute how much memory it would need, while
-actually only ever using a few hundred bytes of working memory, and without too
+in most cases only ever using a small amount of working memory, and without too
many tests of the mode that might slow it down. So I refactored the compiling
functions to work this way. This got rid of about 600 lines of source. It
should make future maintenance and development easier. As this was such a major
@@ -104,22 +105,206 @@
for nested parenthesized groups. This is a safety feature for environments with
small stacks where the patterns are provided by users.

-History repeated itself for release 10.20. A number of bugs relating to named
-subpatterns had been discovered by fuzzers. Most of these were related to the
-handling of forward references when it was not known if the named pattern was
+
+Yet another pattern scan
+------------------------
+
+History repeated itself for PCRE2 release 10.20. A number of bugs relating to
+named subpatterns had been discovered by fuzzers. Most of these were related to
+the handling of forward references when it was not known if the named group was
unique. (References to non-unique names use a different opcode and more
memory.) The use of duplicate group numbers (the (?| facility) also caused
-issues.
+issues.

-To get around these problems I adopted a new approach by adding a third pass,
-really a "pre-pass", over the pattern, which does nothing other than identify
-all the named subpatterns and their corresponding group numbers. This means
-that the actual compile (both pre-pass and real compile) have full knowledge of
-group names and numbers throughout. Several dozen lines of messy code were
-eliminated, though the new pre-pass is not short (skipping over [] classes is
-complicated).
+To get around these problems I adopted a new approach by adding a third pass
+over the pattern (really a "pre-pass"), which did nothing other than identify
+all the named subpatterns and their corresponding group numbers. This means
+that the actual compile (both the memory-computing dummy run and the real
+compile) has full knowledge of group names and numbers throughout. Several
+dozen lines of messy code were eliminated, though the new pre-pass was not
+short. In particular, parsing and skipping over [] classes is complicated.

+While working on 10.22 I realized that I could simplify yet again by moving
+more of the parsing into the pre-pass, thus avoiding doing it in two places, so
+after 10.22 was released, the code underwent yet another big refactoring. This
+is how it is from 10.23 onwards:

+The function called parse_regex() scans the pattern characters, parsing them 
+into literal data and meta characters. It converts escapes such as \x{123} 
+into literals, handles \Q...\E, and skips over comments and non-significant 
+white space. The result of the scanning is put into a vector of 32-bit unsigned 
+integers. Values less than 0x80000000 are literal data. Higher values represent 
+meta-characters. The top 16-bits of such values identify the meta-character,
+and these are given names such as META_CAPTURE. The lower 16-bits are available
+for data, for example, the capturing group number. The only situation in which 
+literal data values greater than 0x7fffffff can appear is when the 32-bit 
+library is running in non-UTF mode. This is handled by having a special 
+meta-character that is followed by the 32-bit data value.
+
+The size of the parsed pattern vector, when auto-callouts are not enabled, is
+bounded by the length of the pattern (with one exception). The code is written 
+so that each item in the pattern uses no more vector elements than the number 
+of code units in the item itself. The exception is the aforementioned large
+32-bit number handling. For this reason, 32-bit non-UTF patterns are scanned in
+advance to check for such values. When auto-callouts are enabled, the generous
+assumption is made that there will be a callout for each pattern code unit
+(which of course is only actually true if all code units are literals) plus one 
+at the end. There is a default parsed pattern vector on the stack, but if this
+is not big enough, heap memory is used.
+
+As before, the actual compiling function is run twice, the first time to 
+determine the amount of memory needed for the final compiled pattern. It 
+now processes the parsed pattern vector, not the pattern itself, although some
+of the parsed items refer to strings in the pattern - for example, group
+names. As escapes and comments have already been processed, the code is a bit 
+simpler than before.
+
+Most errors can be diagnosed during the parsing scan. For those that cannot
+(for example, "lookbehind assertion is not fixed length"), the parsed code
+contains offsets into the pattern so that the actual compiling code can
+identify where errors occur.
+
+
+The elements of the parsed pattern vector
+-----------------------------------------
+
+The word "offset" below means a code unit offset into the pattern. When 
+PCRE2_SIZE (which is usually size_t) is no bigger than uint32_t, an offset is
+stored in a single parsed pattern element. Otherwise (typically on 64-bit
+systems) it occupies two elements. The following meta items occupy just one
+element, with no data:
+
+META_ACCEPT           (*ACCEPT)
+META_ALT              | alternation 
+META_ASTERISK         *  
+META_ASTERISK_PLUS    *+ 
+META_ASTERISK_QUERY   *? 
+META_ATOMIC           (?> start of atomic group 
+META_CIRCUMFLEX       ^ metacharacter 
+META_CLASS            [ start of non-empty class 
+META_CLASS_EMPTY      [] empty class - only with PCRE2_ALLOW_EMPTY_CLASS 
+META_CLASS_EMPTY_NOT  [^] negative empty class - ditto
+META_CLASS_END        ] end of non-empty class 
+META_CLASS_NOT        [^ start non-empty negative class 
+META_COMMIT           (*COMMIT)
+META_DOLLAR           $ metacharacter 
+META_DOT              . metacharacter 
+META_END              End of pattern (this value is 0x80000000)
+META_FAIL             (*FAIL)
+META_KET              ) closing parenthesis 
+META_LOOKAHEAD        (?= start of lookahead
+META_LOOKAHEADNOT     (?! start of negative lookahead
+META_NOCAPTURE        (?: no capture parens 
+META_PLUS             +  
+META_PLUS_PLUS        ++ 
+META_PLUS_QUERY       +? 
+META_PRUNE            (*PRUNE) - no argument
+META_QUERY            ?  
+META_QUERY_PLUS       ?+ 
+META_QUERY_QUERY      ?? 
+META_RANGE_ESCAPED    hyphen in class range with at least one escape 
+META_RANGE_LITERAL    hyphen in class range defined literally 
+META_SKIP             (*SKIP) - no argument
+META_THEN             (*THEN) - no argument
+
+The two RANGE values occur only in character classes. They are positioned 
+between two literals that define the start and end of the range. In an EBCDIC 
+evironment it is necessary to know whether either of the range values was 
+specified as an escape. In an ASCII/Unicode environment the distinction is not 
+relevant.
+
+The following have data in the lower 16 bits, and may be followed by other data 
+elements:
+
+META_BACKREF
+META_CAPTURE
+META_ESCAPE
+META_RECURSE
+
+META_BACKREF, META_CAPTURE, and META_RECURSE have the capture group number as
+their data in the lower 16 bits of the element.
+
+META_BACKREF is followed by an offset if the back reference group number is 10
+or more. The offsets of the first ocurrences of references to groups whose 
+numbers are less than 10 are put in cb->small_ref_offset[] (only the first
+occurrence is useful). On 64-bit systems this avoids using more than two parsed
+pattern elements for items such as \3. The offset is used when an error is
+given for a reference to a non-existent group.
+
+META_RECURSE is always followed by an offset, for use in error messages.
+
+META_ESCAPE has an ESC_xxx value as its data. For ESC_P and ESC_p, the next
+element contains the 16-bit type and data property values, packed together.
+ESC_g and ESC_k are used only for named references - numerical ones are turned
+into META_RECURSE or META_BACKREF as appropriate. They are followed by a length
+and an offset into the pattern to specify the name.
+
+The following have one data item that follows in the next vector element:
+
+META_BIGVALUE         Next is a literal >= META_END 
+META_OPTIONS          (?i) and friends (data is new option bits)
+META_POSIX            POSIX class item (data identifies the class)
+META_POSIX_NEG        negative POSIX class item (ditto)
+
+The following are followed by a length element, then a number of character code
+values (which should match with the length):
+
+META_MARK             (*MARK:xxxx) 
+META_PRUNE_ARG        (*PRUNE:xxx)
+META_SKIP_ARG         (*SKIP:xxxx)
+META_THEN_ARG         (*THEN:xxxx)
+
+The following are followed by a length element, then an offset in the pattern 
+that identifies the name:
+
+META_COND_NAME        (?(<name>) or (?('name') or (?(name) 
+META_COND_RNAME       (?(R&name) 
+META_COND_RNUMBER     (?(Rdigits)
+META_RECURSE_BYNAME   (?&name) 
+META_BACKREF_BYNAME   \k'name' 
+
+META_COND_RNUMBER is used for names that start with R and continue with digits,
+because this is an ambiguous case. It could be a back reference to a group with
+that name, or it could be a recursion test on a numbered group.
+
+This one is followed by an offset, for use in error messages, then a number:
+
+META_COND_NUMBER       (?([+-]digits) 
+
+The following are followed just by an offset, for use in error messages:
+
+META_COND_ASSERT      (?(?assertion)
+META_COND_DEFINE      (?(DEFINE)
+META_LOOKBEHIND       (?<= 
+META_LOOKBEHINDNOT    (?<!
+
+In fact, META_COND_ASSERT is used for any group starting (?( that does not 
+match any of the other META_COND cases. The check that this group is an 
+assertion (optionally preceded by a callout) happens at compile time. 
+
+The following are followed by two values, the minimum and maximum. Repeat
+values are limited to 65535 (MAX_REPEAT). A maximum value of "unlimited" is
+represented by UNLIMITED_REPEAT, which is bigger than MAX_REPEAT:
+
+META_MINMAX           {n,m}  repeat 
+META_MINMAX_PLUS      {n,m}+ repeat 
+META_MINMAX_QUERY     {n,m}? repeat 
+
+This one is followed by three elements. The first is 0 for '>' and 1 for '>=';
+the next two are the major and minor numbers:
+
+META_COND_VERSION     (?(VERSION<op>x.y)
+
+Callouts are converted into one of two items:
+
+META_CALLOUT_NUMBER   (?C with numerical argument 
+META_CALLOUT_STRING   (?C with string argument 
+
+In both cases, the next two elements contain the offset and length of the next 
+item in the pattern. Then there is either one callout number, or a length and 
+an offset for the string argument. The length includes both delimiters.
+
+
 Traditional matching function
 -----------------------------


@@ -606,4 +791,4 @@
correct length, in order to catch updating errors.

Philip Hazel
-June 2016
+September 2016

Modified: code/trunk/Makefile.am
===================================================================
--- code/trunk/Makefile.am    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/Makefile.am    2016-10-02 16:01:01 UTC (rev 555)
@@ -65,6 +65,7 @@
   doc/html/pcre2_set_character_tables.html \
   doc/html/pcre2_set_compile_recursion_guard.html \
   doc/html/pcre2_set_match_limit.html \
+  doc/html/pcre2_set_max_pattern_length.html \
   doc/html/pcre2_set_offset_limit.html \
   doc/html/pcre2_set_newline.html \
   doc/html/pcre2_set_parens_nest_limit.html \
@@ -146,6 +147,7 @@
   doc/pcre2_set_character_tables.3 \
   doc/pcre2_set_compile_recursion_guard.3 \
   doc/pcre2_set_match_limit.3 \
+  doc/pcre2_set_max_pattern_length.3 \
   doc/pcre2_set_offset_limit.3 \
   doc/pcre2_set_newline.3 \
   doc/pcre2_set_parens_nest_limit.3 \


Modified: code/trunk/RunTest
===================================================================
--- code/trunk/RunTest    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/RunTest    2016-10-02 16:01:01 UTC (rev 555)
@@ -502,7 +502,7 @@
     for opt in "" $jitopt; do
       $sim $valgrind ${opt:+$vjs} ./pcre2test -q $test2stack $bmode $opt $testdata/testinput2 testtry
       if [ $? = 0 ] ; then
-        $sim $valgrind ${opt:+$vjs} ./pcre2test -q $bmode $opt -error -63,-62,-2,-1,0,100,188,189 >>testtry
+        $sim $valgrind ${opt:+$vjs} ./pcre2test -q $bmode $opt -error -63,-62,-2,-1,0,100,188,189,190 >>testtry
         checkresult $? 2 "$opt"
       else
         echo " "


Modified: code/trunk/doc/pcre2api.3
===================================================================
--- code/trunk/doc/pcre2api.3    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/doc/pcre2api.3    2016-10-02 16:01:01 UTC (rev 555)
@@ -1,4 +1,4 @@
-.TH PCRE2API 3 "17 June 2016" "PCRE2 10.22"
+.TH PCRE2API 3 "30 September 2016" "PCRE2 10.23"
 .SH NAME
 PCRE2 - Perl-compatible regular expressions (revised API)
 .sp
@@ -693,7 +693,8 @@
 .sp
 This parameter ajusts the limit, set when PCRE2 is built (default 250), on the
 depth of parenthesis nesting in a pattern. This limit stops rogue patterns
-using up too much system stack when being compiled.
+using up too much system stack when being compiled. The limit applies to 
+parentheses of all kinds, not just capturing parentheses.
 .sp
 .nf
 .B int pcre2_set_compile_recursion_guard(pcre2_compile_context *\fIccontext\fP,
@@ -1091,8 +1092,14 @@
 error code and an offset (number of code units) within the pattern,
 respectively, when \fBpcre2_compile()\fP returns NULL because a compilation
 error has occurred. The values are not defined when compilation is successful
-and \fBpcre2_compile()\fP returns a non-NULL value.
+and \fBpcre2_compile()\fP returns a non-NULL value. 
 .P
+The value returned in \fIerroroffset\fP is an indication of where in the
+pattern the error occurred. It is not necessarily the furthest point in the
+pattern that was read. For example, after the error "lookbehind assertion is
+not fixed length", the error offset points to the start of the failing
+assertion.
+.P
 The \fBpcre2_get_error_message()\fP function (see "Obtaining a textual error
 message"
 .\" HTML <a href="#geterrormessage">
@@ -1184,8 +1191,8 @@
   PCRE2_AUTO_CALLOUT
 .sp
 If this bit is set, \fBpcre2_compile()\fP automatically inserts callout items,
-all with number 255, before each pattern item. For discussion of the callout
-facility, see the
+all with number 255, before each pattern item, except immediately before or
+after a callout in the pattern. For discussion of the callout facility, see the
 .\" HREF
 \fBpcre2callout\fP
 .\"
@@ -3292,6 +3299,6 @@
 .rs
 .sp
 .nf
-Last updated: 17 June 2016
+Last updated: 30 September 2016
 Copyright (c) 1997-2016 University of Cambridge.
 .fi


Modified: code/trunk/doc/pcre2callout.3
===================================================================
--- code/trunk/doc/pcre2callout.3    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/doc/pcre2callout.3    2016-10-02 16:01:01 UTC (rev 555)
@@ -1,4 +1,4 @@
-.TH PCRE2CALLOUT 3 "23 March 2015" "PCRE2 10.20"
+.TH PCRE2CALLOUT 3 "29 September 2016" "PCRE2 10.23"
 .SH NAME
 PCRE2 - Perl-compatible regular expressions (revised API)
 .SH SYNOPSIS
@@ -40,12 +40,21 @@
 .sp
 If the PCRE2_AUTO_CALLOUT option bit is set when a pattern is compiled, PCRE2
 automatically inserts callouts, all with number 255, before each item in the
-pattern. For example, if PCRE2_AUTO_CALLOUT is used with the pattern
+pattern except for immediately before or after a callout item in the pattern.
+For example, if PCRE2_AUTO_CALLOUT is used with the pattern
 .sp
-  A(\ed{2}|--)
+  A(?C3)B
 .sp
 it is processed as if it were
 .sp
+  (?C255)A(?C3)B(?C255)   
+.sp
+Here is a more complicated example:
+.sp
+  A(\ed{2}|--)
+.sp
+With PCRE2_AUTO_CALLOUT, this pattern is processed as if it were
+.sp
 (?C255)A(?C255)((?C255)\ed{2}(?C255)|(?C255)-(?C255)-(?C255))(?C255)
 .sp
 Notice that there is a callout before and after each parenthesis and
@@ -91,10 +100,10 @@
   No match
 .sp
 This indicates that when matching [bc] fails, there is no backtracking into a+
-and therefore the callouts that would be taken for the backtracks do not occur.
-You can disable the auto-possessify feature by passing PCRE2_NO_AUTO_POSSESS to
-\fBpcre2_compile()\fP, or starting the pattern with (*NO_AUTO_POSSESS). In this
-case, the output changes to this:
+(because it is being treated as a++) and therefore the callouts that would be
+taken for the backtracks do not occur. You can disable the auto-possessify
+feature by passing PCRE2_NO_AUTO_POSSESS to \fBpcre2_compile()\fP, or starting
+the pattern with (*NO_AUTO_POSSESS). In this case, the output changes to this:
 .sp
   --->aaaa
    +0 ^        a+
@@ -220,8 +229,8 @@
 .sp
 For a numerical callout, \fIcallout_string\fP is NULL, and \fIcallout_number\fP
 contains the number of the callout, in the range 0-255. This is the number
-that follows (?C for manual callouts; it is 255 for automatically generated
-callouts.
+that follows (?C for callouts that part of the pattern; it is 255 for
+automatically generated callouts.
 .
 .
 .SS "Fields for string callouts"
@@ -286,10 +295,15 @@
 the next item to be matched.
 .P
 The \fInext_item_length\fP field contains the length of the next item to be
-matched in the pattern string. When the callout immediately precedes an
-alternation bar, a closing parenthesis, or the end of the pattern, the length
-is zero. When the callout precedes an opening parenthesis, the length is that
-of the entire subpattern.
+processed in the pattern string. When the callout is at the end of the pattern,
+the length is zero. When the callout precedes an opening parenthesis, the
+length includes meta characters that follow the parenthesis. For example, in a
+callout before an assertion such as (?=ab) the length is 3. For an an
+alternation bar or a closing parenthesis, the length is one, unless a closing
+parenthesis is followed by a quantifier, in which case its length is included.
+(This changed in release 10.23. In earlier releases, before an opening
+parenthesis the length was that of the entire subpattern, and before an
+alternation bar or a closing parenthesis the length was zero.)
 .P
 The \fIpattern_position\fP and \fInext_item_length\fP fields are intended to
 help in distinguishing between different automatic callouts, which all have the
@@ -382,6 +396,6 @@
 .rs
 .sp
 .nf
-Last updated: 23 March 2015
-Copyright (c) 1997-2015 University of Cambridge.
+Last updated: 29 September 2016
+Copyright (c) 1997-2016 University of Cambridge.
 .fi


Modified: code/trunk/doc/pcre2compat.3
===================================================================
--- code/trunk/doc/pcre2compat.3    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/doc/pcre2compat.3    2016-10-02 16:01:01 UTC (rev 555)
@@ -1,4 +1,4 @@
-.TH PCRE2COMPAT 3 "15 March 2015" "PCRE2 10.20"
+.TH PCRE2COMPAT 3 "30 September 2016" "PCRE2 10.23"
 .SH NAME
 PCRE2 - Perl-compatible regular expressions (revised API)
 .SH "DIFFERENCES BETWEEN PCRE2 AND PERL"
@@ -96,7 +96,7 @@
 one that is backtracked onto acts. For example, in the pattern
 A(*COMMIT)B(*PRUNE)C a failure in B triggers (*COMMIT), but a failure in C
 triggers (*PRUNE). Perl's behaviour is more complex; in many cases it is the
-same as PCRE2, but there are examples where it differs.
+same as PCRE2, but there are cases where it differs.
 .P
 11. Most backtracking verbs in assertions have their normal actions. They are
 not confined to the assertion.
@@ -116,10 +116,11 @@
 names map to capturing subpattern number 1. To avoid this confusing situation,
 an error is given at compile time.
 .P
-14. Perl recognizes comments in some places that PCRE2 does not, for example,
-between the ( and ? at the start of a subpattern. If the /x modifier is set,
-Perl allows white space between ( and ? (though current Perls warn that this is
-deprecated) but PCRE2 never does, even if the PCRE2_EXTENDED option is set.
+14. Perl used to recognize comments in some places that PCRE2 does not, for
+example, between the ( and ? at the start of a subpattern. If the /x modifier
+is set, Perl allowed white space between ( and ? though the latest Perls give 
+an error (for a while it was just deprecated). There may still be some cases 
+where Perl behaves differently.
 .P
 15. Perl, when in warning mode, gives warnings for character classes such as
 [A-\ed] or [a-[:digit:]]. It then treats the hyphens as literals. PCRE2 has no
@@ -139,35 +140,39 @@
 .sp
 (a) Although lookbehind assertions in PCRE2 must match fixed length strings,
 each alternative branch of a lookbehind assertion can match a different length
-of string. Perl requires them all to have the same length.
+of string. Perl requires them all to have the same length. 
 .sp
-(b) If PCRE2_DOLLAR_ENDONLY is set and PCRE2_MULTILINE is not set, the $
+(b) From PCRE2 10.23, back references to groups of fixed length are supported
+in lookbehinds, provided that there is no possibility of referencing a
+non-unique number or name. Perl does not support backreferences in lookbehinds.
+.sp
+(c) If PCRE2_DOLLAR_ENDONLY is set and PCRE2_MULTILINE is not set, the $
 meta-character matches only at the very end of the string.
 .sp
-(c) A backslash followed by a letter with no special meaning is faulted. (Perl
+(d) A backslash followed by a letter with no special meaning is faulted. (Perl
 can be made to issue a warning.)
 .sp
-(d) If PCRE2_UNGREEDY is set, the greediness of the repetition quantifiers is
+(e) If PCRE2_UNGREEDY is set, the greediness of the repetition quantifiers is
 inverted, that is, by default they are not greedy, but if followed by a
 question mark they are.
 .sp
-(e) PCRE2_ANCHORED can be used at matching time to force a pattern to be tried
+(f) PCRE2_ANCHORED can be used at matching time to force a pattern to be tried
 only at the first matching position in the subject string.
 .sp
-(f) The PCRE2_NOTBOL, PCRE2_NOTEOL, PCRE2_NOTEMPTY, PCRE2_NOTEMPTY_ATSTART, and
+(g) The PCRE2_NOTBOL, PCRE2_NOTEOL, PCRE2_NOTEMPTY, PCRE2_NOTEMPTY_ATSTART, and
 PCRE2_NO_AUTO_CAPTURE options have no Perl equivalents.
 .sp
-(g) The \eR escape sequence can be restricted to match only CR, LF, or CRLF
+(h) The \eR escape sequence can be restricted to match only CR, LF, or CRLF
 by the PCRE2_BSR_ANYCRLF option.
 .sp
-(h) The callout facility is PCRE2-specific.
+(i) The callout facility is PCRE2-specific.
 .sp
-(i) The partial matching facility is PCRE2-specific.
+(j) The partial matching facility is PCRE2-specific.
 .sp
-(j) The alternative matching function (\fBpcre2_dfa_match()\fP matches in a
+(k) The alternative matching function (\fBpcre2_dfa_match()\fP matches in a
 different way and is not Perl-compatible.
 .sp
-(k) PCRE2 recognizes some special sequences such as (*CR) at the start of
+(l) PCRE2 recognizes some special sequences such as (*CR) at the start of
 a pattern that set overall options that cannot be changed within the pattern.
 .
 .
@@ -185,6 +190,6 @@
 .rs
 .sp
 .nf
-Last updated: 15 March 2015
-Copyright (c) 1997-2015 University of Cambridge.
+Last updated: 30 September 2016
+Copyright (c) 1997-2016 University of Cambridge.
 .fi


Modified: code/trunk/doc/pcre2limits.3
===================================================================
--- code/trunk/doc/pcre2limits.3    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/doc/pcre2limits.3    2016-10-02 16:01:01 UTC (rev 555)
@@ -1,4 +1,4 @@
-.TH PCRE2LIMITS 3 "05 November 2015" "PCRE2 10.21"
+.TH PCRE2LIMITS 3 "29 September 2016" "PCRE2 10.23"
 .SH NAME
 PCRE2 - Perl-compatible regular expressions (revised API)
 .SH "SIZE AND OTHER LIMITATIONS"
@@ -46,19 +46,19 @@
 There is no limit to the number of parenthesized subpatterns, but there can be
 no more than 65535 capturing subpatterns. There is, however, a limit to the
 depth of nesting of parenthesized subpatterns of all kinds. This is imposed in
-order to limit the amount of system stack used at compile time. The limit can
-be specified when PCRE2 is built; the default is 250.
+order to limit the amount of system stack used at compile time. The default
+limit can be specified when PCRE2 is built; the default default is 250. An 
+application can change this limit by calling pcre2_set_parens_nest_limit() to 
+set the limit in a compile context.
 .P
-There is a limit to the number of forward references to subsequent subpatterns
-of around 200,000. Repeated forward references with fixed upper limits, for
-example, (?2){0,100} when subpattern number 2 is to the right, are included in
-the count. There is no limit to the number of backward references.
-.P
 The maximum length of name for a named subpattern is 32 code units, and the
 maximum number of named subpatterns is 10000.
 .P
 The maximum length of a name in a (*MARK), (*PRUNE), (*SKIP), or (*THEN) verb
 is 255 for the 8-bit library and 65535 for the 16-bit and 32-bit libraries.
+.P
+The maximum length of a string argument to a callout is the largest number a 
+32-bit unsigned integer can hold.
 .
 .
 .SH AUTHOR
@@ -75,6 +75,6 @@
 .rs
 .sp
 .nf
-Last updated: 05 November 2015
-Copyright (c) 1997-2015 University of Cambridge.
+Last updated: 29 September 2016
+Copyright (c) 1997-2016 University of Cambridge.
 .fi


Modified: code/trunk/doc/pcre2pattern.3
===================================================================
--- code/trunk/doc/pcre2pattern.3    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/doc/pcre2pattern.3    2016-10-02 16:01:01 UTC (rev 555)
@@ -1,4 +1,4 @@
-.TH PCRE2PATTERN 3 "20 June 2016" "PCRE2 10.22"
+.TH PCRE2PATTERN 3 "30 September 2016" "PCRE2 10.23"
 .SH NAME
 PCRE2 - Perl-compatible regular expressions (revised API)
 .SH "PCRE2 REGULAR EXPRESSION DETAILS"
@@ -508,9 +508,9 @@
 .SS "Absolute and relative back references"
 .rs
 .sp
-The sequence \eg followed by an unsigned or a negative number, optionally
-enclosed in braces, is an absolute or relative back reference. A named back
-reference can be coded as \eg{name}. Back references are discussed
+The sequence \eg followed by a signed or unsigned number, optionally enclosed
+in braces, is an absolute or relative back reference. A named back reference
+can be coded as \eg{name}. Back references are discussed
 .\" HTML <a href="#backreferences">
 .\" </a>
 later,
@@ -1325,14 +1325,34 @@
 whatever setting of the PCRE2_DOTALL and PCRE2_MULTILINE options is used. A
 class such as [^a] always matches one of these characters.
 .P
+The character escape sequences \ed, \eD, \eh, \eH, \ep, \eP, \es, \eS, \ev,
+\eV, \ew, and \eW may appear in a character class, and add the characters that
+they match to the class. For example, [\edABCDEF] matches any hexadecimal
+digit. In UTF modes, the PCRE2_UCP option affects the meanings of \ed, \es, \ew
+and their upper case partners, just as it does when they appear outside a
+character class, as described in the section entitled
+.\" HTML <a href="#genericchartypes">
+.\" </a>
+"Generic character types"
+.\"
+above. The escape sequence \eb has a different meaning inside a character
+class; it matches the backspace character. The sequences \eB, \eN, \eR, and \eX
+are not special inside a character class. Like any other unrecognized escape
+sequences, they cause an error.
+.P
 The minus (hyphen) character can be used to specify a range of characters in a
 character class. For example, [d-m] matches any letter between d and m,
 inclusive. If a minus character is required in a class, it must be escaped with
 a backslash or appear in a position where it cannot be interpreted as
-indicating a range, typically as the first or last character in the class, or
-immediately after a range. For example, [b-d-z] matches letters in the range b
-to d, a hyphen character, or z.
+indicating a range, typically as the first or last character in the class,
+or immediately after a range. For example, [b-d-z] matches letters in the range
+b to d, a hyphen character, or z.
 .P
+Perl treats a hyphen as a literal if it appears before a POSIX class (see
+below) or a character type escape such as as \ed, but gives a warning in its 
+warning mode, as this is most likely a user error. As PCRE2 has no facility for
+warning, an error is given in these cases.
+.P
 It is not possible to have the literal character "]" as the end character of a
 range. A pattern such as [W-]46] is interpreted as a class of two characters
 ("W" and "-") followed by a literal string "46]", so it would match "W46]" or
@@ -1341,11 +1361,6 @@
 followed by two other characters. The octal or hexadecimal representation of
 "]" can also be used to end a range.
 .P
-An error is generated if a POSIX character class (see below) or an escape
-sequence other than one that defines a single character appears at a point
-where a range ending character is expected. For example, [z-\exff] is valid,
-but [A-\ed] and [A-[:digit:]] are not.
-.P
 Ranges normally include all code points between the start and end characters,
 inclusive. They can also be used for code points specified numerically, for
 example [\e000-\e037]. Ranges can include any characters that are valid for the
@@ -1365,21 +1380,6 @@
 tables for a French locale are in use, [\exc8-\excb] matches accented E
 characters in both cases.
 .P
-The character escape sequences \ed, \eD, \eh, \eH, \ep, \eP, \es, \eS, \ev,
-\eV, \ew, and \eW may appear in a character class, and add the characters that
-they match to the class. For example, [\edABCDEF] matches any hexadecimal
-digit. In UTF modes, the PCRE2_UCP option affects the meanings of \ed, \es, \ew
-and their upper case partners, just as it does when they appear outside a
-character class, as described in the section entitled
-.\" HTML <a href="#genericchartypes">
-.\" </a>
-"Generic character types"
-.\"
-above. The escape sequence \eb has a different meaning inside a character
-class; it matches the backspace character. The sequences \eB, \eN, \eR, and \eX
-are not special inside a character class. Like any other unrecognized escape
-sequences, they cause an error.
-.P
 A circumflex can conveniently be used with the upper case character types to
 specify a more restricted set of characters than the matching lower case type.
 For example, the class [^\eW_] matches any letter or digit, but not underscore,
@@ -2096,9 +2096,9 @@
 subpattern is possible using named parentheses (see below).
 .P
 Another way of avoiding the ambiguity inherent in the use of digits following a
-backslash is to use the \eg escape sequence. This escape must be followed by an
-unsigned number or a negative number, optionally enclosed in braces. These
-examples are all identical:
+backslash is to use the \eg escape sequence. This escape must be followed by a 
+signed or unsigned number, optionally enclosed in braces. These examples are
+all identical:
 .sp
   (ring), \e1
   (ring), \eg1
@@ -2106,8 +2106,7 @@
 .sp
 An unsigned number specifies an absolute reference without the ambiguity that
 is present in the older syntax. It is also useful when literal digits follow
-the reference. A negative number is a relative reference. Consider this
-example:
+the reference. A signed number is a relative reference. Consider this example:
 .sp
   (abc(def)ghi)\eg{-1}
 .sp
@@ -2117,6 +2116,10 @@
 can be helpful in long patterns, and also in patterns that are created by
 joining together fragments that contain references within themselves.
 .P
+The sequence \eg{+1} is a reference to the next capturing subpattern. This kind 
+of forward reference can be useful it patterns that repeat. Perl does not 
+support the use of + in this way.
+.P
 A back reference matches whatever actually matched the capturing subpattern in
 the current subject string, rather than anything matching the subpattern
 itself (see
@@ -2321,11 +2324,11 @@
 match. If there are insufficient characters before the current position, the
 assertion fails.
 .P
-In a UTF mode, PCRE2 does not allow the \eC escape (which matches a single code
-unit even in a UTF mode) to appear in lookbehind assertions, because it makes
-it impossible to calculate the length of the lookbehind. The \eX and \eR
-escapes, which can match different numbers of code units, are also not
-permitted.
+In UTF-8 and UTF-16 modes, PCRE2 does not allow the \eC escape (which matches a
+single code unit even in a UTF mode) to appear in lookbehind assertions,
+because it makes it impossible to calculate the length of the lookbehind. The
+\eX and \eR escapes, which can match different numbers of code units, are never
+permitted in lookbehinds.
 .P
 .\" HTML <a href="#subpatternsassubroutines">
 .\" </a>
@@ -2332,13 +2335,24 @@
 "Subroutine"
 .\"
 calls (see below) such as (?2) or (?&X) are permitted in lookbehinds, as long
-as the subpattern matches a fixed-length string.
+as the subpattern matches a fixed-length string. However,
 .\" HTML <a href="#recursion">
 .\" </a>
-Recursion,
+recursion,
 .\"
-however, is not supported.
+that is, a "subroutine" call into a group that is already active,
+is not supported.
 .P
+Perl does not support back references in lookbehinds. PCRE2 does support them,
+but only if certain conditions are met. The PCRE2_MATCH_UNSET_BACKREF option
+must not be set, there must be no use of (?| in the pattern (it creates
+duplicate subpattern numbers), and if the back reference is by name, the name
+must be unique. Of course, the referenced subpattern must itself be of fixed
+length. The following pattern matches words containing at least two characters
+that begin and end with the same character:
+.sp
+   \eb(\ew)\ew++(?<=\e1)
+.P
 Possessive quantifiers can be used in conjunction with lookbehind assertions to
 specify efficient matching of fixed-length strings at the end of subject
 strings. Consider a simple pattern such as
@@ -2476,7 +2490,9 @@
 .sp
 Perl uses the syntax (?(<name>)...) or (?('name')...) to test for a used
 subpattern by name. For compatibility with earlier versions of PCRE1, which had
-this facility before Perl, the syntax (?(name)...) is also recognized.
+this facility before Perl, the syntax (?(name)...) is also recognized. Note, 
+however, that undelimited names consisting of the letter R followed by digits
+are ambiguous (see the following section).
 .P
 Rewriting the above example to use a named subpattern gives this:
 .sp
@@ -2490,25 +2506,47 @@
 .SS "Checking for pattern recursion"
 .rs
 .sp
-If the condition is the string (R), and there is no subpattern with the name R,
-the condition is true if a recursive call to the whole pattern or any
-subpattern has been made. If digits or a name preceded by ampersand follow the
-letter R, for example:
+"Recursion" in this sense refers to any subroutine-like call from one part of
+the pattern to another, whether or not it is actually recursive. See the
+sections entitled
+.\" HTML <a href="#recursion">
+.\" </a>
+"Recursive patterns"
+.\"
+and
+.\" HTML <a href="#subpatternsassubroutines">
+.\" </a>
+"Subpatterns as subroutines"
+.\"
+below for details of recursion and subpattern calls.
+.P
+If a condition is the string (R), and there is no subpattern with the name R,
+the condition is true if matching is currently in a recursion or subroutine
+call to the whole pattern or any subpattern. If digits follow the letter R, and
+there is no subpattern with that name, the condition is true if the most recent
+call is into a subpattern with the given number, which must exist somewhere in 
+the overall pattern. This is a contrived example that is equivalent to a+b:
 .sp
-  (?(R3)...) or (?(R&name)...)
+  ((?(R1)a+|(?1)b))
+.sp   
+However, in both cases, if there is a subpattern with a matching name, the
+condition tests for its being set, as described in the section above, instead
+of testing for recursion. For example, creating a group with the name R1 by
+adding (?<R1>) to the above pattern completely changes its meaning.
+.P
+If a name preceded by ampersand follows the letter R, for example:
 .sp
-the condition is true if the most recent recursion is into a subpattern whose
-number or name is given. This condition does not check the entire recursion
-stack. If the name used in a condition of this kind is a duplicate, the test is
-applied to all subpatterns of the same name, and is true if any one of them is
-the most recent recursion.
+  (?(R&name)...)
+.sp
+the condition is true if the most recent recursion is into a subpattern of that 
+name (which must exist within the pattern).
 .P
+This condition does not check the entire recursion stack. It tests only the 
+current level. If the name used in a condition of this kind is a duplicate, the
+test is applied to all subpatterns of the same name, and is true if any one of
+them is the most recent recursion.
+.P
 At "top level", all these recursion test conditions are false.
-.\" HTML <a href="#recursion">
-.\" </a>
-The syntax for recursive patterns
-.\"
-is described below.
 .
 .
 .\" HTML <a name="subdefine"></a>
@@ -2515,8 +2553,8 @@
 .SS "Defining subpatterns for use by reference only"
 .rs
 .sp
-If the condition is the string (DEFINE), and there is no subpattern with the
-name DEFINE, the condition is always false. In this case, there may be only one
+If the condition is the string (DEFINE), the condition is always false, even if
+there is a group with the name DEFINE. In this case, there may be only one
 alternative in the subpattern. It is always skipped if control reaches this
 point in the pattern; the idea of DEFINE is that it can be used to define
 subroutines that can be referenced from elsewhere. (The use of
@@ -2994,13 +3032,21 @@
 By default, for compatibility with Perl, a name is any sequence of characters
 that does not include a closing parenthesis. The name is not processed in
 any way, and it is not possible to include a closing parenthesis in the name.
-However, if the PCRE2_ALT_VERBNAMES option is set, normal backslash processing
-is applied to verb names and only an unescaped closing parenthesis terminates
-the name. A closing parenthesis can be included in a name either as \e) or
-between \eQ and \eE. If the PCRE2_EXTENDED option is set, unescaped whitespace
-in verb names is skipped and #-comments are recognized, exactly as in the rest
-of the pattern.
+This can be changed by setting the PCRE2_ALT_VERBNAMES option, but the result 
+is no longer Perl-compatible. 
 .P
+When PCRE2_ALT_VERBNAMES is set, backslash processing is applied to verb names
+and only an unescaped closing parenthesis terminates the name. However, the 
+only backslash items that are permitted are \eQ, \eE, and sequences such as 
+\ex{100} that define character code points. Character type escapes such as \ed 
+are faulted.
+.P
+A closing parenthesis can be included in a name either as \e) or between \eQ
+and \eE. In addition to backslash processing, if the PCRE2_EXTENDED option is
+also set, unescaped whitespace in verb names is skipped, and #-comments are
+recognized, exactly as in the rest of the pattern. PCRE2_EXTENDED does not 
+affect verb names unless PCRE2_ALT_VERBNAMES is also set.
+.P
 The maximum length of a name is 255 in the 8-bit library and 65535 in the
 16-bit and 32-bit libraries. If the name is empty, that is, if the closing
 parenthesis immediately follows the colon, the effect is as if the colon were
@@ -3429,6 +3475,6 @@
 .rs
 .sp
 .nf
-Last updated: 20 June 2016
+Last updated: 30 September 2016
 Copyright (c) 1997-2016 University of Cambridge.
 .fi


Modified: code/trunk/doc/pcre2syntax.3
===================================================================
--- code/trunk/doc/pcre2syntax.3    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/doc/pcre2syntax.3    2016-10-02 16:01:01 UTC (rev 555)
@@ -1,4 +1,4 @@
-.TH PCRE2SYNTAX 3 "16 October 2015" "PCRE2 10.21"
+.TH PCRE2SYNTAX 3 "28 September 2016" "PCRE2 10.23"
 .SH NAME
 PCRE2 - Perl-compatible regular expressions (revised API)
 .SH "PCRE2 REGULAR EXPRESSION SYNTAX SUMMARY"
@@ -473,6 +473,9 @@
   \en              reference by number (can be ambiguous)
   \egn             reference by number
   \eg{n}           reference by number
+  \eg+n            relative reference by number (PCRE2 extension)
+  \eg-n            relative reference by number
+  \eg{+n}          relative reference by number (PCRE2 extension) 
   \eg{-n}          relative reference by number
   \ek<name>        reference by name (Perl)
   \ek'name'        reference by name (Perl)
@@ -511,13 +514,17 @@
   (?(-n)              relative reference condition
   (?(<name>)          named reference condition (Perl)
   (?('name')          named reference condition (Perl)
-  (?(name)            named reference condition (PCRE2)
+  (?(name)            named reference condition (PCRE2, deprecated)
   (?(R)               overall recursion condition
-  (?(Rn)              specific group recursion condition
-  (?(R&name)          specific recursion condition
+  (?(Rn)              specific numbered group recursion condition
+  (?(R&name)          specific named group recursion condition
   (?(DEFINE)          define subpattern for reference
   (?(VERSION[>]=n.m)  test PCRE2 version
   (?(assert)          assertion condition
+.sp
+Note the ambiguity of (?(R) and (?(Rn) which might be named reference 
+conditions or recursion tests. Such a condition is interpreted as a reference
+condition if the relevant named group exists.
 .
 .
 .SH "BACKTRACKING CONTROL"
@@ -577,6 +584,6 @@
 .rs
 .sp
 .nf
-Last updated: 16 October 2015
-Copyright (c) 1997-2015 University of Cambridge.
+Last updated: 28 September 2016
+Copyright (c) 1997-2016 University of Cambridge.
 .fi


Modified: code/trunk/perltest.sh
===================================================================
--- code/trunk/perltest.sh    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/perltest.sh    2016-10-02 16:01:01 UTC (rev 555)
@@ -1,14 +1,17 @@
 #! /bin/sh


# Script for testing regular expressions with perl to check that PCRE2 handles
-# them the same. The Perl code has to have "use utf8" and "require Encode" at
-# the start when running UTF-8 tests, but *not* for non-utf8 tests. (The
-# "require" would actually be OK for non-utf8-tests, but is not always
-# installed, so this way the script will always run for these tests.)
+# them the same. If the first argument to this script is "-w", Perl is also
+# called with "-w", which turns on its warning mode.
#
+# The Perl code has to have "use utf8" and "require Encode" at the start when
+# running UTF-8 tests, but *not* for non-utf8 tests. (The "require" would
+# actually be OK for non-utf8-tests, but is not always installed, so this way
+# the script will always run for these tests.)
+#
# The desired effect is achieved by making this a shell script that passes the
-# Perl script to Perl through a pipe. If the first argument is "-utf8", a
-# suitable prefix is set up.
+# Perl script to Perl through a pipe. If the first argument (possibly after
+# removing "-w") is "-utf8", a suitable prefix is set up.
#
# The remaining arguments, if any, are passed to Perl. They are an input file
# and an output file. If there is one argument, the output is written to
@@ -17,7 +20,14 @@
# of the contorted piping input.)

perl=perl
+perlarg=''
prefix=''
+
+if [ $# -gt 0 -a "$1" = "-w" ] ; then
+ perlarg="-w"
+ shift
+fi
+
if [ $# -gt 0 -a "$1" = "-utf8" ] ; then
prefix="use utf8; require Encode;"
shift
@@ -292,6 +302,6 @@
# printf $outfile "\n";

PERLEND
-) | $perl - $@
+) | $perl $perlarg - $@

# End

Modified: code/trunk/src/pcre2_compile.c
===================================================================
--- code/trunk/src/pcre2_compile.c    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/src/pcre2_compile.c    2016-10-02 16:01:01 UTC (rev 555)
@@ -58,9 +58,14 @@
 #define PRINTABLE(c) ((c) >= 32 && (c) < 127)
 #endif
 #include "pcre2_printint.c"
-#define CALL_PRINTINT
+#define DEBUG_CALL_PRINTINT
 #endif


+/* Other debugging code can be enabled by these defines. */
+
+// #define DEBUG_SHOW_CAPTURES
+// #define DEBUG_SHOW_PARSED
+
/* There are a few things that vary with different code unit sizes. Handle them
by defining macros in order to minimize #if usage. */

@@ -79,6 +84,36 @@
#endif
#endif

+/* Macros to store and retrieve a PCRE2_SIZE value in the parsed pattern, which
+consists of uint32_t elements. Assume that if uint32_t can't hold it, two of
+them will be able to (i.e. assume a 64-bit world). */
+
+#if PCRE2_SIZE_MAX <= UINT32_MAX
+#define PUTOFFSET(s,p) *p++ = s
+#define GETOFFSET(s,p) s = *p++
+#define GETPLUSOFFSET(s,p) s = *(++p)
+#define READPLUSOFFSET(s,p) s = p[1]
+#define SKIPOFFSET(p) p++
+#define SIZEOFFSET 1
+#else
+#define PUTOFFSET(s,p) \
+ { *p++ = (uint32_t)(s >> 32); *p++ = (uint32_t)(s & 0xffffffff); }
+#define GETOFFSET(s,p) \
+ { s = ((PCRE2_SIZE)p[0] << 32) | (PCRE2_SIZE)p[1]; p += 2; }
+#define GETPLUSOFFSET(s,p) \
+ { s = ((PCRE2_SIZE)p[1] << 32) | (PCRE2_SIZE)p[2]; p += 2; }
+#define READPLUSOFFSET(s,p) \
+ { s = ((PCRE2_SIZE)p[1] << 32) | (PCRE2_SIZE)p[2]; }
+#define SKIPOFFSET(p) p += 2
+#define SIZEOFFSET 2
+#endif
+
+/* Macros for manipulating elements of the parsed pattern vector. */
+
+#define META_CODE(x) (x & 0xffff0000u)
+#define META_DATA(x) (x & 0x0000ffffu)
+#define META_DIFF(x,y) ((x-y)>>16)
+
/* Function definitions to allow mutual recursion */

 static unsigned int
@@ -86,20 +121,34 @@
     const uint32_t *, unsigned int);


 static BOOL
-  compile_regex(uint32_t, PCRE2_UCHAR **, PCRE2_SPTR *, int *, BOOL, BOOL,
-    uint32_t, int, uint32_t *, int32_t *, uint32_t *, int32_t *,
-    branch_chain *, compile_block *, size_t *);
+  compile_regex(uint32_t, PCRE2_UCHAR **, uint32_t **, int *, uint32_t,
+    uint32_t *, int32_t *, uint32_t *, int32_t *, branch_chain *,
+    compile_block *, PCRE2_SIZE *);


+static int
+  get_branchlength(uint32_t **, int *, int *, parsed_recurse_check *,
+    compile_block *);


+static BOOL
+  set_lookbehind_lengths(uint32_t **, int *, int *, parsed_recurse_check *,
+    compile_block *);


+
+
 /*************************************************
 *      Code parameters and static tables         *
 *************************************************/


-/* This value specifies the size of stack workspace, which is used in different
-ways in the different pattern scans. The group-identifying pre-scan uses it to
-handle nesting, and needs it to be 16-bit aligned.
+#define MAX_GROUP_NUMBER 65535u
+#define MAX_REPEAT_COUNT 65535u
+#define REPEAT_UNLIMITED (MAX_REPEAT_COUNT+1)

+/* COMPILE_WORK_SIZE specifies the size of stack workspace, which is used in
+different ways in the different pattern scans. The parsing and group-
+identifying pre-scan uses it to handle nesting, and needs it to be 16-bit
+aligned for this. Having defined the size in code units, we set up
+C16_WORK_SIZE as the number of elements in the 16-bit vector.
+
During the first compiling phase, when determining how much memory is required,
the regex is partly compiled into this space, but the compiled parts are
discarded as soon as they can be, so that hopefully there will never be an
@@ -107,17 +156,19 @@
pathological patterns. The size of the workspace depends on LINK_SIZE because
the length of compiled items varies with this.

-In the real compile phase, the workspace is used for remembering data about
-numbered groups, provided there are not too many of them (if there are, extra
-memory is acquired). For this phase the memory must be 32-bit aligned. Having
-defined the size in code units, we set up C32_WORK_SIZE as the number of
-elements in the 32-bit vector. */
+In the real compile phase, this workspace is not currently used. */

#define COMPILE_WORK_SIZE (2048*LINK_SIZE) /* Size in code units */

-#define C32_WORK_SIZE \
- ((COMPILE_WORK_SIZE * sizeof(PCRE2_UCHAR))/sizeof(uint32_t))
+#define C16_WORK_SIZE \
+ ((COMPILE_WORK_SIZE * sizeof(PCRE2_UCHAR))/sizeof(uint16_t))

+/* A uint32_t vector is used for caching information about the size of
+capturing groups, to improve performance. A default is created on the stack of
+this size. */
+
+#define GROUPINFO_DEFAULT_SIZE 256
+
/* The overrun tests check for a slightly smaller size so that they detect the
overrun before it actually does run off the end of the data block. */

@@ -130,25 +181,106 @@

#define NAMED_GROUP_LIST_SIZE 20

-/* The original PCRE required patterns to be zero-terminated, and it simplifies
-the compiling code if it is guaranteed that there is a zero code unit at the
-end of the pattern, because this means that tests for coding sequences such as
-(*SKIP) or even just (?<= can check a sequence of code units without having to
-keep checking for the end of the pattern. The new PCRE2 API allows zero code
-units within patterns if a positive length is given, but in order to keep most
-of the compiling code as it was, we copy such patterns and add a zero on the
-end. This value determines the size of space on the stack that is used if the
-pattern fits; if not, heap memory is used. */
+/* The pre-compiling pass over the pattern creates a parsed pattern in a vector
+of uint32_t. For short patterns this lives on the stack, with this size. Heap
+memory is used for longer patterns. */

-#define COPIED_PATTERN_SIZE 1024
+#define PARSED_PATTERN_DEFAULT_SIZE 1024

/* Maximum length value to check against when making sure that the variable
that holds the compiled pattern length does not overflow. We make it a bit less
-than INT_MAX to allow for adding in group terminating bytes, so that we don't
-have to check them every time. */
+than INT_MAX to allow for adding in group terminating code units, so that we
+don't have to check them every time. */

#define OFLOW_MAX (INT_MAX - 20)

+/* Code values for parsed patterns, which are stored in a vector of 32-bit
+unsigned ints. Values less than META_END are literal data values. The coding
+for identifying the item is in the top 16-bits, leaving 16 bits for the
+additional data that some of them need. The META_CODE, META_DATA, and META_DIFF
+macros are used to manipulate parsed pattern elements. */
+
+#define META_END              0x80000000u  /* End of pattern */
+
+#define META_ALT              0x80010000u  /* alternation */
+#define META_ATOMIC           0x80020000u  /* atomic group */
+#define META_BACKREF          0x80030000u  /* Back ref */
+#define META_BACKREF_BYNAME   0x80040000u  /* \k'name' */
+#define META_BIGVALUE         0x80050000u  /* Next is a literal > META_END */
+#define META_CALLOUT_NUMBER   0x80060000u  /* (?C with numerical argument */
+#define META_CALLOUT_STRING   0x80070000u  /* (?C with string argument */
+#define META_CAPTURE          0x80080000u  /* Capturing parenthesis */
+#define META_CIRCUMFLEX       0x80090000u  /* ^ metacharacter */
+#define META_CLASS            0x800a0000u  /* start non-empty class */
+#define META_CLASS_EMPTY      0x800b0000u  /* empty class */
+#define META_CLASS_EMPTY_NOT  0x800c0000u  /* negative empty class */
+#define META_CLASS_END        0x800d0000u  /* end of non-empty class */
+#define META_CLASS_NOT        0x800e0000u  /* start non-empty negative class */
+#define META_COND_ASSERT      0x800f0000u  /* (?(?assertion)... */
+#define META_COND_DEFINE      0x80100000u  /* (?(DEFINE)... */
+#define META_COND_NAME        0x80110000u  /* (?(<name>)... */
+#define META_COND_NUMBER      0x80120000u  /* (?(digits)... */
+#define META_COND_RNAME       0x80130000u  /* (?(R&name)... */
+#define META_COND_RNUMBER     0x80140000u  /* (?(Rdigits)... */
+#define META_COND_VERSION     0x80150000u  /* (?(VERSION<op>x.y)... */
+#define META_DOLLAR           0x80160000u  /* $ metacharacter */
+#define META_DOT              0x80170000u  /* . metacharacter */
+#define META_ESCAPE           0x80180000u  /* \d and friends */
+#define META_KET              0x80190000u  /* closing parenthesis */
+#define META_NOCAPTURE        0x801a0000u  /* no capture parens */
+#define META_OPTIONS          0x801b0000u  /* (?i) and friends */
+#define META_POSIX            0x801c0000u  /* POSIX class item */
+#define META_POSIX_NEG        0x801d0000u  /* negative POSIX class item */
+#define META_RANGE_ESCAPED    0x801e0000u  /* range with at least one escape */
+#define META_RANGE_LITERAL    0x801f0000u  /* range defined literally */
+#define META_RECURSE          0x80200000u  /* Recursion */
+#define META_RECURSE_BYNAME   0x80210000u  /* (?&name) */
+
+/* These must be kept together to make it easy to check that an assertion
+is present where expected in a conditional group. */
+
+#define META_LOOKAHEAD        0x80220000u  /* (?= */
+#define META_LOOKAHEADNOT     0x80230000u  /* (?! */
+#define META_LOOKBEHIND       0x80240000u  /* (?<= */
+#define META_LOOKBEHINDNOT    0x80250000u  /* (?<! */
+
+/* These must be kept in this order, with consecutive values, and the _ARG
+versions of PRUNE, SKIP, and THEN immediately after their non-argument
+versions. */
+
+#define META_MARK             0x80260000u  /* (*MARK) */
+#define META_ACCEPT           0x80270000u  /* (*ACCEPT) */
+#define META_COMMIT           0x80280000u  /* (*COMMIT) */
+#define META_FAIL             0x80290000u  /* (*FAIL) */
+#define META_PRUNE            0x802a0000u  /* These pairs must    */
+#define META_PRUNE_ARG        0x802b0000u  /*   be                */
+#define META_SKIP             0x802c0000u  /*     kept            */
+#define META_SKIP_ARG         0x802d0000u  /*         in          */
+#define META_THEN             0x802e0000u  /*           this      */
+#define META_THEN_ARG         0x802f0000u  /*               order */
+
+/* These must be kept in groups of adjacent 3 values, and all together. */
+
+#define META_ASTERISK         0x80300000u  /* *  */
+#define META_ASTERISK_PLUS    0x80310000u  /* *+ */
+#define META_ASTERISK_QUERY   0x80320000u  /* *? */
+#define META_PLUS             0x80330000u  /* +  */
+#define META_PLUS_PLUS        0x80340000u  /* ++ */
+#define META_PLUS_QUERY       0x80350000u  /* +? */
+#define META_QUERY            0x80360000u  /* ?  */
+#define META_QUERY_PLUS       0x80370000u  /* ?+ */
+#define META_QUERY_QUERY      0x80380000u  /* ?? */
+#define META_MINMAX           0x80390000u  /* {n,m}  repeat */
+#define META_MINMAX_PLUS      0x803a0000u  /* {n,m}+ repeat */
+#define META_MINMAX_QUERY     0x803b0000u  /* {n,m}? repeat */
+
+#define META_FIRST_QUANTIFIER META_ASTERISK
+#define META_LAST_QUANTIFIER  META_MINMAX_QUERY
+
+/* Types for skipping parts of a parsed pattern. */
+
+enum { PSKIP_ALT, PSKIP_CLASS, PSKIP_KET };
+
 /* Macro for setting individual bits in class bitmaps. It took some
 experimenting to figure out how to stop gcc 5.3.0 from warning with
 -Wconversion. This version gets a warning:
@@ -176,11 +308,6 @@
 #define GI_SET_FIXED_LENGTH    0x10000000u
 #define GI_FIXED_LENGTH_MASK   0x0000ffffu


-/* This bit (which is greater than any UTF value) is used to indicate that a
-variable contains a number of code units instead of an actual code point. */
-
-#define UTF_LENGTH     0x10000000l
-
 /* This simple test for a decimal digit works for both ASCII/Unicode and EBCDIC
 and is fast (a good compiler can turn it into a subtraction and unsigned
 comparison). */
@@ -380,9 +507,9 @@
 platforms. */


 typedef struct verbitem {
-  int   len;                 /* Length of verb name */
-  int   op;                  /* Op when no arg, or -1 if arg mandatory */
-  int   op_arg;              /* Op when arg present, or -1 if not allowed */
+  unsigned int len;          /* Length of verb name */
+  uint32_t meta;             /* Base META_ code */
+  int has_arg;               /* Argument requirement */
 } verbitem;


static const char verbnames[] =
@@ -397,33 +524,31 @@
STRING_THEN;

 static const verbitem verbs[] = {
-  { 0, -1,        OP_MARK },
-  { 4, -1,        OP_MARK },
-  { 6, OP_ACCEPT, -1 },
-  { 6, OP_COMMIT, -1 },
-  { 1, OP_FAIL,   -1 },
-  { 4, OP_FAIL,   -1 },
-  { 5, OP_PRUNE,  OP_PRUNE_ARG },
-  { 4, OP_SKIP,   OP_SKIP_ARG  },
-  { 4, OP_THEN,   OP_THEN_ARG  }
+  { 0, META_MARK,   +1 },  /* > 0 => must have an argument */
+  { 4, META_MARK,   +1 },
+  { 6, META_ACCEPT, -1 },  /* < 0 => must not have an argument */
+  { 6, META_COMMIT, -1 },
+  { 1, META_FAIL,   -1 },
+  { 4, META_FAIL,   -1 },
+  { 5, META_PRUNE,   0 },  /* Argument is optional; bump META code if found */
+  { 4, META_SKIP,    0 },
+  { 4, META_THEN,    0 }
 };


static const int verbcount = sizeof(verbs)/sizeof(verbitem);

+/* Verb opcodes, indexed by their META code offset from META_MARK. */

-/* Substitutes for [[:<:]] and [[:>:]], which mean start and end of word in
-another regex library. */
+static const uint32_t verbops[] = {
+ OP_MARK, OP_ACCEPT, OP_COMMIT, OP_FAIL, OP_PRUNE, OP_PRUNE_ARG, OP_SKIP,
+ OP_SKIP_ARG, OP_THEN, OP_THEN_ARG };

-static const PCRE2_UCHAR sub_start_of_word[] = {
- CHAR_BACKSLASH, CHAR_b, CHAR_LEFT_PARENTHESIS, CHAR_QUESTION_MARK,
- CHAR_EQUALS_SIGN, CHAR_BACKSLASH, CHAR_w, CHAR_RIGHT_PARENTHESIS, '\0' };
+/* Offsets from OP_STAR for case-independent and negative repeat opcodes. */

-static const PCRE2_UCHAR sub_end_of_word[] = {
-  CHAR_BACKSLASH, CHAR_b, CHAR_LEFT_PARENTHESIS, CHAR_QUESTION_MARK,
-  CHAR_LESS_THAN_SIGN, CHAR_EQUALS_SIGN, CHAR_BACKSLASH, CHAR_w,
-  CHAR_RIGHT_PARENTHESIS, '\0' };
+static uint32_t chartypeoffset[] = {
+  OP_STAR - OP_STAR,    OP_STARI - OP_STAR,
+  OP_NOTSTAR - OP_STAR, OP_NOTSTARI - OP_STAR };


-
/* Tables of names of POSIX character classes and their lengths. The names are
now all in a single string, to reduce the number of relocations when a shared
library is dynamically loaded. The list of lengths is terminated by a zero
@@ -444,7 +569,6 @@
#define PC_PRINT 9
#define PC_PUNCT 10

-
 /* Table of class bit maps for each POSIX class. Each class is formed from a
 base map, with an optional addition or removal of another map. Then, for some
 classes, there is some additional tweaking: for [:blank:] the vertical space
@@ -472,117 +596,28 @@
   cbit_xdigit,-1,          0              /* xdigit */
 };


-/* Table of substitutes for \d etc when PCRE2_UCP is set. They are replaced by
-Unicode property escapes. */
-
#ifdef SUPPORT_UNICODE
-static const PCRE2_UCHAR string_PNd[] = {
- CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
- CHAR_N, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const PCRE2_UCHAR string_pNd[] = {
- CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
- CHAR_N, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const PCRE2_UCHAR string_PXsp[] = {
- CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
- CHAR_X, CHAR_s, CHAR_p, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const PCRE2_UCHAR string_pXsp[] = {
- CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
- CHAR_X, CHAR_s, CHAR_p, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const PCRE2_UCHAR string_PXwd[] = {
- CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
- CHAR_X, CHAR_w, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const PCRE2_UCHAR string_pXwd[] = {
- CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
- CHAR_X, CHAR_w, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' };

-static PCRE2_SPTR substitutes[] = {
-  string_PNd,           /* \D */
-  string_pNd,           /* \d */
-  string_PXsp,          /* \S */   /* Xsp is Perl space, but from 8.34, Perl */
-  string_pXsp,          /* \s */   /* space and POSIX space are the same. */
-  string_PXwd,          /* \W */
-  string_pXwd           /* \w */
-};
+/* The POSIX class Unicode property substitutes that are used in UCP mode must
+be in the order of the POSIX class names, defined above. */


-/* The POSIX class substitutes must be in the order of the POSIX class names,
-defined above, and there are both positive and negative cases. NULL means no
-general substitute of a Unicode property escape (\p or \P). However, for some
-POSIX classes (e.g. graph, print, punct) a special property code is compiled
-directly. */
-
-static const PCRE2_UCHAR string_pCc[] =  {
-  CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
-  CHAR_C, CHAR_c, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const PCRE2_UCHAR string_pL[] =   {
-  CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
-  CHAR_L, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const PCRE2_UCHAR string_pLl[] =  {
-  CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
-  CHAR_L, CHAR_l, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const PCRE2_UCHAR string_pLu[] =  {
-  CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
-  CHAR_L, CHAR_u, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const PCRE2_UCHAR string_pXan[] = {
-  CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
-  CHAR_X, CHAR_a, CHAR_n, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const PCRE2_UCHAR string_h[] =    {
-  CHAR_BACKSLASH, CHAR_h, '\0' };
-static const PCRE2_UCHAR string_pXps[] = {
-  CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
-  CHAR_X, CHAR_p, CHAR_s, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const PCRE2_UCHAR string_PCc[] =  {
-  CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
-  CHAR_C, CHAR_c, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const PCRE2_UCHAR string_PL[] =   {
-  CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
-  CHAR_L, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const PCRE2_UCHAR string_PLl[] =  {
-  CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
-  CHAR_L, CHAR_l, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const PCRE2_UCHAR string_PLu[] =  {
-  CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
-  CHAR_L, CHAR_u, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const PCRE2_UCHAR string_PXan[] = {
-  CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
-  CHAR_X, CHAR_a, CHAR_n, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const PCRE2_UCHAR string_H[] =    {
-  CHAR_BACKSLASH, CHAR_H, '\0' };
-static const PCRE2_UCHAR string_PXps[] = {
-  CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
-  CHAR_X, CHAR_p, CHAR_s, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-
-static PCRE2_SPTR posix_substitutes[] = {
-  string_pL,            /* alpha */
-  string_pLl,           /* lower */
-  string_pLu,           /* upper */
-  string_pXan,          /* alnum */
-  NULL,                 /* ascii */
-  string_h,             /* blank */
-  string_pCc,           /* cntrl */
-  string_pNd,           /* digit */
-  NULL,                 /* graph */
-  NULL,                 /* print */
-  NULL,                 /* punct */
-  string_pXps,          /* space */   /* Xps is POSIX space, but from 8.34 */
-  string_pXwd,          /* word  */   /* Perl and POSIX space are the same */
-  NULL,                 /* xdigit */
-  /* Negated cases */
-  string_PL,            /* ^alpha */
-  string_PLl,           /* ^lower */
-  string_PLu,           /* ^upper */
-  string_PXan,          /* ^alnum */
-  NULL,                 /* ^ascii */
-  string_H,             /* ^blank */
-  string_PCc,           /* ^cntrl */
-  string_PNd,           /* ^digit */
-  NULL,                 /* ^graph */
-  NULL,                 /* ^print */
-  NULL,                 /* ^punct */
-  string_PXps,          /* ^space */  /* Xps is POSIX space, but from 8.34 */
-  string_PXwd,          /* ^word */   /* Perl and POSIX space are the same */
-  NULL                  /* ^xdigit */
+static int posix_substitutes[] = {
+  PT_GC, ucp_L,     /* alpha */
+  PT_PC, ucp_Ll,    /* lower */
+  PT_PC, ucp_Lu,    /* upper */
+  PT_ALNUM, 0,      /* alnum */
+  -1, 0,            /* ascii, treat as non-UCP */
+  -1, 1,            /* blank, treat as \h */
+  PT_PC, ucp_Cc,    /* cntrl */
+  PT_PC, ucp_Nd,    /* digit */
+  PT_PXGRAPH, 0,    /* graph */
+  PT_PXPRINT, 0,    /* print */
+  PT_PXPUNCT, 0,    /* punct */
+  PT_PXSPACE, 0,    /* space */   /* Xps is POSIX space, but from 8.34 */
+  PT_WORD, 0,       /* word  */   /* Perl and POSIX space are the same */
+  -1, 0             /* xdigit, treat as non-UCP */
 };
-#define POSIX_SUBSIZE (sizeof(posix_substitutes) / sizeof(PCRE2_UCHAR *))
+#define POSIX_SUBSIZE (sizeof(posix_substitutes) / (2*sizeof(uint32_t)))
 #endif  /* SUPPORT_UNICODE */


 /* Masks for checking option settings. */
@@ -611,22 +646,8 @@
        ERR51, ERR52, ERR53, ERR54, ERR55, ERR56, ERR57, ERR58, ERR59, ERR60,
        ERR61, ERR62, ERR63, ERR64, ERR65, ERR66, ERR67, ERR68, ERR69, ERR70,
        ERR71, ERR72, ERR73, ERR74, ERR75, ERR76, ERR77, ERR78, ERR79, ERR80,
-       ERR81, ERR82, ERR83, ERR84, ERR85, ERR86, ERR87, ERR88 };
+       ERR81, ERR82, ERR83, ERR84, ERR85, ERR86, ERR87, ERR88, ERR89 };


-/* Error codes that correspond to negative error codes returned by
-find_fixedlength(). */
-
-static int fixed_length_errors[] =
-  {
-  ERR0,    /* Not an error */
-  ERR0,    /* Not an error; -1 is used for "process later" */
-  ERR25,   /* Lookbehind is not fixed length */
-  ERR36,   /* \C in lookbehind is not allowed */
-  ERR87,   /* Lookbehind is too long */
-  ERR86,   /* Pattern too complicated */
-  ERR70    /* Internal error: unknown opcode encountered */
-  };
-
 /* This is a table of start-of-pattern options such as (*UTF) and settings such
 as (*LIMIT_MATCH=nnnn) and (*CRLF). For completeness and backward
 compatibility, (*UTFn) is supported in the relevant libraries, but (*UTF) is
@@ -728,1056 +749,490 @@
 };



-
+#ifdef DEBUG_SHOW_PARSED
 /*************************************************
-*               Copy compiled code               *
+*     Show the parsed pattern for debugging      *
 *************************************************/


-/* Compiled JIT code cannot be copied, so the new compiled block has no
-associated JIT data. */
+/* For debugging the pre-scan, this code, which outputs the parsed data vector,
+can be enabled. */

-PCRE2_EXP_DEFN pcre2_code * PCRE2_CALL_CONVENTION
-pcre2_code_copy(const pcre2_code *code)
+static void show_parsed(compile_block *cb)
{
-PCRE2_SIZE* ref_count;
-pcre2_code *newcode;
+uint32_t *pptr = cb->parsed_pattern;

-if (code == NULL) return NULL;
-newcode = code->memctl.malloc(code->blocksize, code->memctl.memory_data);
-if (newcode == NULL) return NULL;
-memcpy(newcode, code, code->blocksize);
-newcode->executable_jit = NULL;
-
-/* If the code is one that has been deserialized, increment the reference count
-in the decoded tables. */
-
-if ((code->flags & PCRE2_DEREF_TABLES) != 0)
+for (;;)
{
- ref_count = (PCRE2_SIZE *)(code->tables + tables_length);
- (*ref_count)++;
- }
+ int max, min;
+ PCRE2_SIZE offset;
+ uint32_t i;
+ uint32_t length;
+ uint32_t meta_arg = META_DATA(*pptr);

-return newcode;
-}
+ fprintf(stderr, "+++ %02d %.8x ", (int)(pptr - cb->parsed_pattern), *pptr);

+  if (*pptr < META_END)
+    {
+    if (*pptr > 32 && *pptr < 128) fprintf(stderr, "%c", *pptr);
+    pptr++;
+    }


+  else switch (META_CODE(*pptr++))
+    {
+    default:
+    fprintf(stderr, "**** OOPS - unknown META value - giving up ****\n");
+    return;


-/*************************************************
-*               Free compiled code               *
-*************************************************/
+    case META_END:
+    fprintf(stderr, "META_END\n");
+    return;


-PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
-pcre2_code_free(pcre2_code *code)
-{
-PCRE2_SIZE* ref_count;
+    case META_CAPTURE:
+    fprintf(stderr, "META_CAPTURE %d", meta_arg);
+    break;


-if (code != NULL)
-  {
-  if (code->executable_jit != NULL)
-    PRIV(jit_free)(code->executable_jit, &code->memctl);
+    case META_RECURSE:
+    GETOFFSET(offset, pptr);
+    fprintf(stderr, "META_RECURSE %d %zd", meta_arg, offset);
+    break;


-  if ((code->flags & PCRE2_DEREF_TABLES) != 0)
-    {
-    /* Decoded tables belong to the codes after deserialization, and they must
-    be freed when there are no more reference to them. The *ref_count should
-    always be > 0. */
+    case META_BACKREF:
+    if (meta_arg < 10)
+      offset = cb->small_ref_offset[meta_arg];
+    else
+      GETOFFSET(offset, pptr);
+    fprintf(stderr, "META_BACKREF %d %zd", meta_arg, offset);
+    break;


-    ref_count = (PCRE2_SIZE *)(code->tables + tables_length);
-    if (*ref_count > 0)
+    case META_ESCAPE:
+    if (meta_arg == ESC_P || meta_arg == ESC_p)
       {
-      (*ref_count)--;
-      if (*ref_count == 0)
-        code->memctl.free((void *)code->tables, code->memctl.memory_data);
+      uint32_t ptype = *pptr >> 16;
+      uint32_t pvalue = *pptr++ & 0xffff;
+      fprintf(stderr, "META \\%c %d %d", (meta_arg == ESC_P)? 'P':'p',
+        ptype, pvalue);
       }
-    }
+    else
+      {
+      uint32_t cc;
+      /* There's just one escape we might have here that isn't negated in the
+      escapes table. */
+      if (meta_arg == ESC_g) cc = CHAR_g;
+      else for (cc = ESCAPES_FIRST; cc <= ESCAPES_LAST; cc++)
+        {
+        if (meta_arg == (uint32_t)(-escapes[cc - ESCAPES_FIRST])) break;
+        }
+      if (cc > ESCAPES_LAST) cc = CHAR_QUESTION_MARK;
+      fprintf(stderr, "META \\%c", cc);
+      }
+    break;


-  code->memctl.free(code, code->memctl.memory_data);
-  }
-}
+    case META_MINMAX:
+    min = *pptr++;
+    max = *pptr++;
+    if (max != REPEAT_UNLIMITED)
+      fprintf(stderr, "META {%d,%d}", min, max);
+    else
+      fprintf(stderr, "META {%d,}", min);
+    break;


+    case META_MINMAX_QUERY:
+    min = *pptr++;
+    max = *pptr++;
+    if (max != REPEAT_UNLIMITED)
+      fprintf(stderr, "META {%d,%d}?", min, max);
+    else
+      fprintf(stderr, "META {%d,}?", min);
+    break;


+    case META_MINMAX_PLUS:
+    min = *pptr++;
+    max = *pptr++;
+    if (max != REPEAT_UNLIMITED)
+      fprintf(stderr, "META {%d,%d}+", min, max);
+    else
+      fprintf(stderr, "META {%d,}+", min);
+    break;


-/*************************************************
-*        Insert an automatic callout point       *
-*************************************************/
+    case META_BIGVALUE: fprintf(stderr, "META_BIGVALUE %.8x", *pptr++); break;
+    case META_CIRCUMFLEX: fprintf(stderr, "META_CIRCUMFLEX"); break;
+    case META_DOLLAR: fprintf(stderr, "META_DOLLAR"); break;
+    case META_DOT: fprintf(stderr, "META_DOT"); break;
+    case META_ASTERISK: fprintf(stderr, "META *"); break;
+    case META_ASTERISK_QUERY: fprintf(stderr, "META *?"); break;
+    case META_ASTERISK_PLUS: fprintf(stderr, "META *+"); break;
+    case META_PLUS: fprintf(stderr, "META +"); break;
+    case META_PLUS_QUERY: fprintf(stderr, "META +?"); break;
+    case META_PLUS_PLUS: fprintf(stderr, "META ++"); break;
+    case META_QUERY: fprintf(stderr, "META ?"); break;
+    case META_QUERY_QUERY: fprintf(stderr, "META ??"); break;
+    case META_QUERY_PLUS: fprintf(stderr, "META ?+"); break;


-/* This function is called when the PCRE2_AUTO_CALLOUT option is set, to insert
-callout points before each pattern item.
+    case META_ATOMIC: fprintf(stderr, "META (?>"); break;
+    case META_NOCAPTURE: fprintf(stderr, "META (?:"); break;
+    case META_LOOKAHEAD: fprintf(stderr, "META (?="); break;
+    case META_LOOKAHEADNOT: fprintf(stderr, "META (?!"); break;
+    case META_KET: fprintf(stderr, "META )"); break;
+    case META_ALT: fprintf(stderr, "META | %d", meta_arg); break;


-Arguments:
-  code           current code pointer
-  ptr            current pattern pointer
-  cb             general compile-time data
+    case META_CLASS: fprintf(stderr, "META ["); break;
+    case META_CLASS_NOT: fprintf(stderr, "META [^"); break;
+    case META_CLASS_END: fprintf(stderr, "META ]"); break;
+    case META_CLASS_EMPTY: fprintf(stderr, "META []"); break;
+    case META_CLASS_EMPTY_NOT: fprintf(stderr, "META [^]"); break;


-Returns:         new code pointer
-*/
+    case META_RANGE_LITERAL: fprintf(stderr, "META - (literal)"); break;
+    case META_RANGE_ESCAPED: fprintf(stderr, "META - (escaped)"); break;


-static PCRE2_UCHAR *
-auto_callout(PCRE2_UCHAR *code, PCRE2_SPTR ptr, compile_block *cb)
-{
-code[0] = OP_CALLOUT;
-PUT(code, 1, ptr - cb->start_pattern);  /* Pattern offset */
-PUT(code, 1 + LINK_SIZE, 0);            /* Default length */
-code[1 + 2*LINK_SIZE] = 255;
-return code + PRIV(OP_lengths)[OP_CALLOUT];
-}
+    case META_POSIX: fprintf(stderr, "META_POSIX %d", *pptr++); break;
+    case META_POSIX_NEG: fprintf(stderr, "META_POSIX_NEG %d", *pptr++); break;


+    case META_ACCEPT: fprintf(stderr, "META (*ACCEPT)"); break;
+    case META_COMMIT: fprintf(stderr, "META (*COMMIT)"); break;
+    case META_FAIL: fprintf(stderr, "META (*FAIL)"); break;
+    case META_PRUNE: fprintf(stderr, "META (*PRUNE)"); break;
+    case META_SKIP: fprintf(stderr, "META (*SKIP)"); break;
+    case META_THEN: fprintf(stderr, "META (*THEN)"); break;


+    case META_OPTIONS: fprintf(stderr, "META_OPTIONS 0x%02x", *pptr++); break;


-/*************************************************
-*         Complete a callout item                *
-*************************************************/
+    case META_LOOKBEHIND:
+    fprintf(stderr, "META (?<= %d offset=", meta_arg);
+    GETOFFSET(offset, pptr);
+    fprintf(stderr, "%zd", offset);
+    break;


-/* A callout item contains the length of the next item in the pattern, which
-we can't fill in till after we have reached the relevant point. This is used
-for both automatic and manual callouts.
+    case META_LOOKBEHINDNOT:
+    fprintf(stderr, "META (?<! %d offset=", meta_arg);
+    GETOFFSET(offset, pptr);
+    fprintf(stderr, "%zd", offset);
+    break;


-Arguments:
-  previous_callout   points to previous callout item
-  ptr                current pattern pointer
-  cb                 general compile-time data
-
-Returns:             nothing
-*/
-
-static void
-complete_callout(PCRE2_UCHAR *previous_callout, PCRE2_SPTR ptr,
-  compile_block *cb)
-{
-size_t length = (size_t)(ptr - cb->start_pattern - GET(previous_callout, 1));
-PUT(previous_callout, 1 + LINK_SIZE, length);
-}
-
-
-
-/*************************************************
-*        Find the fixed length of a branch       *
-*************************************************/
-
-/* Scan a branch and compute the fixed length of subject that will match it, if
-the length is fixed. This is needed for dealing with lookbehind assertions. In
-UTF mode, the result is in code units rather than bytes. The branch is
-temporarily terminated with OP_END when this function is called.
-
-This function is called when a lookbehind assertion is encountered, so that if
-it fails, the error message can point to the correct place in the pattern.
-However, we cannot do this when the assertion contains subroutine calls,
-because they can be forward references. We solve this by remembering this case
-and doing the check at the end; a flag specifies which mode we are running in.
-
-Lookbehind lengths are held in 16-bit fields and the maximum value is defined
-as LOOKBEHIND_MAX.
-
-Arguments:
-  code        points to the start of the pattern (the bracket)
-  utf         TRUE in UTF mode
-  atend       TRUE if called when the pattern is complete
-  cb          the "compile data" structure
-  recurses    chain of recurse_check to catch mutual recursion
-  countptr    pointer to counter, to catch over-complexity
-
-Returns:   if non-negative, the fixed length,
-             or -1 if an OP_RECURSE item was encountered and atend is FALSE
-             or -2 if there is no fixed length,
-             or -3 if \C was encountered (in UTF mode only)
-             or -4 if length is too long
-             or -5 if regex is too complicated
-             or -6 if an unknown opcode was encountered (internal error)
-*/
-
-#define FFL_LATER           (-1)
-#define FFL_NOTFIXED        (-2)
-#define FFL_BACKSLASHC      (-3)
-#define FFL_TOOLONG         (-4)
-#define FFL_TOOCOMPLICATED  (-5)
-#define FFL_UNKNOWNOP       (-6)
-
-static int
-find_fixedlength(PCRE2_UCHAR *code, BOOL utf, BOOL atend, compile_block *cb,
-  recurse_check *recurses, int *countptr)
-{
-uint32_t length = 0xffffffffu;   /* Unset */
-uint32_t group = 0;
-uint32_t groupinfo = 0;
-recurse_check this_recurse;
-register uint32_t branchlength = 0;
-register PCRE2_UCHAR *cc = code + 1 + LINK_SIZE;
-
-/* If this is a capturing group, we may have the answer cached, but we can only
-use this information if there are no (?| groups in the pattern, because
-otherwise group numbers are not unique. */
-
-if (*code == OP_CBRA || *code == OP_CBRAPOS || *code == OP_SCBRA ||
-    *code == OP_SCBRAPOS)
-  {
-  group = GET2(cc, 0);
-  cc += IMM2_SIZE;
-  groupinfo = cb->groupinfo[group];
-  if ((cb->external_flags & PCRE2_DUPCAPUSED) == 0)
-    {
-    if ((groupinfo & GI_NOT_FIXED_LENGTH) != 0) return FFL_NOTFIXED;
-    if ((groupinfo & GI_SET_FIXED_LENGTH) != 0)
-      return groupinfo & GI_FIXED_LENGTH_MASK;
-    }
-  }
-
-/* A large and/or complex regex can take too long to process. This can happen
-more often when (?| groups are present in the pattern. */
-
-if ((*countptr)++ > 2000) return FFL_TOOCOMPLICATED;
-
-/* Scan along the opcodes for this branch. If we get to the end of the
-branch, check the length against that of the other branches. */
-
-for (;;)
-  {
-  int d;
-  PCRE2_UCHAR *ce, *cs;
-  register PCRE2_UCHAR op = *cc;
-
-  if (branchlength > LOOKBEHIND_MAX) return FFL_TOOLONG;
-
-  switch (op)
-    {
-    /* We only need to continue for OP_CBRA (normal capturing bracket) and
-    OP_BRA (normal non-capturing bracket) because the other variants of these
-    opcodes are all concerned with unlimited repeated groups, which of course
-    are not of fixed length. */
-
-    case OP_CBRA:
-    case OP_BRA:
-    case OP_ONCE:
-    case OP_ONCE_NC:
-    case OP_COND:
-    d = find_fixedlength(cc, utf, atend, cb, recurses, countptr);
-    if (d < 0) return d;
-    branchlength += (uint32_t)d;
-    do cc += GET(cc, 1); while (*cc == OP_ALT);
-    cc += 1 + LINK_SIZE;
+    case META_CALLOUT_NUMBER:
+    fprintf(stderr, "META (?C%d) next=%d/%d", pptr[2], pptr[0],
+       pptr[1]);
+    pptr += 3;
     break;


-    /* Reached end of a branch; if it's a ket it is the end of a nested call.
-    If it's ALT it is an alternation in a nested call. An ACCEPT is effectively
-    an ALT. If it is END it's the end of the outer call. All can be handled by
-    the same code. Note that we must not include the OP_KETRxxx opcodes here,
-    because they all imply an unlimited repeat. */
-
-    case OP_ALT:
-    case OP_KET:
-    case OP_END:
-    case OP_ACCEPT:
-    case OP_ASSERT_ACCEPT:
-    if (length == 0xffffffffu) length = branchlength;
-      else if (length != branchlength) goto ISNOTFIXED;
-    if (*cc != OP_ALT)
+    case META_CALLOUT_STRING:
       {
-      if (group > 0)
-        {
-        groupinfo |= (uint32_t)(GI_SET_FIXED_LENGTH | length);
-        cb->groupinfo[group] = groupinfo;
-        }
-      return (int)length;
+      uint32_t patoffset = *pptr++;    /* Offset of next pattern item */
+      uint32_t patlength = *pptr++;    /* Length of next pattern item */
+      fprintf(stderr, "META (?Cstring) length=%d offset=", *pptr++);
+      GETOFFSET(offset, pptr);
+      fprintf(stderr, "%zd next=%d/%d", offset, patoffset, patlength);
       }
-    cc += 1 + LINK_SIZE;
-    branchlength = 0;
     break;


-    /* A true recursion implies not fixed length, but a subroutine call may
-    be OK. If the subroutine is a forward reference, we can't deal with
-    it until the end of the pattern, so return FFL_LATER. */
-
-    case OP_RECURSE:
-    if (!atend) return FFL_LATER;
-    cs = ce = (PCRE2_UCHAR *)cb->start_code + GET(cc, 1); /* Start subpattern */
-    do ce += GET(ce, 1); while (*ce == OP_ALT);           /* End subpattern */
-    if (cc > cs && cc < ce) goto ISNOTFIXED;          /* Recursion */
-    else   /* Check for mutual recursion */
-      {
-      recurse_check *r = recurses;
-      for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break;
-      if (r != NULL) goto ISNOTFIXED;   /* Mutual recursion */
-      }
-    this_recurse.prev = recurses;
-    this_recurse.group = cs;
-    d = find_fixedlength(cs, utf, atend, cb, &this_recurse, countptr);
-    if (d < 0) return d;
-    branchlength += (uint32_t)d;
-    cc += 1 + LINK_SIZE;
+    case META_RECURSE_BYNAME:
+    fprintf(stderr, "META (?(&name) length=%d offset=", *pptr++);
+    GETOFFSET(offset, pptr);
+    fprintf(stderr, "%zd", offset);
     break;


-    /* Skip over assertive subpatterns. Note that we must increment cc by
-    1 + LINK_SIZE at the end, not by OP_length[*cc] because in a recursive
-    situation this assertion may be the one that is ultimately being checked
-    for having a fixed length, in which case its terminating OP_KET will have
-    been temporarily replaced by OP_END. */
-
-    case OP_ASSERT:
-    case OP_ASSERT_NOT:
-    case OP_ASSERTBACK:
-    case OP_ASSERTBACK_NOT:
-    do cc += GET(cc, 1); while (*cc == OP_ALT);
-    cc += 1 + LINK_SIZE;
+    case META_BACKREF_BYNAME:
+    fprintf(stderr, "META_BACKREF_BYNAME length=%d offset=", *pptr++);
+    GETOFFSET(offset, pptr);
+    fprintf(stderr, "%zd", offset);
     break;


-    /* Skip over things that don't match chars */
-
-    case OP_MARK:
-    case OP_PRUNE_ARG:
-    case OP_SKIP_ARG:
-    case OP_THEN_ARG:
-    cc += cc[1] + PRIV(OP_lengths)[*cc];
+    case META_COND_NUMBER:
+    fprintf(stderr, "META_COND_NUMBER %d offset=", pptr[SIZEOFFSET]);
+    GETOFFSET(offset, pptr);
+    fprintf(stderr, "%zd", offset);
+    pptr++;
     break;


-    case OP_CALLOUT:
-    case OP_CIRC:
-    case OP_CIRCM:
-    case OP_CLOSE:
-    case OP_COMMIT:
-    case OP_CREF:
-    case OP_FALSE:
-    case OP_TRUE:
-    case OP_DNCREF:
-    case OP_DNRREF:
-    case OP_DOLL:
-    case OP_DOLLM:
-    case OP_EOD:
-    case OP_EODN:
-    case OP_FAIL:
-    case OP_NOT_WORD_BOUNDARY:
-    case OP_PRUNE:
-    case OP_REVERSE:
-    case OP_RREF:
-    case OP_SET_SOM:
-    case OP_SKIP:
-    case OP_SOD:
-    case OP_SOM:
-    case OP_THEN:
-    case OP_WORD_BOUNDARY:
-    cc += PRIV(OP_lengths)[*cc];
+    case META_COND_DEFINE:
+    fprintf(stderr, "META (?(DEFINE) offset=");
+    GETOFFSET(offset, pptr);
+    fprintf(stderr, "%zd", offset);
     break;


-    case OP_CALLOUT_STR:
-    cc += GET(cc, 1 + 2*LINK_SIZE);
+    case META_COND_ASSERT:
+    fprintf(stderr, "META_COND_ASSERT offset=");
+    GETOFFSET(offset, pptr);
+    fprintf(stderr, "%zd", offset);
     break;


-    /* Handle literal characters */
-
-    case OP_CHAR:
-    case OP_CHARI:
-    case OP_NOT:
-    case OP_NOTI:
-    branchlength++;
-    cc += 2;
-#ifdef SUPPORT_UNICODE
-    if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
-#endif
+    case META_COND_VERSION:
+    fprintf(stderr, "META (?(VERSION%s", (*pptr++ == 0)? "=" : ">=");
+    fprintf(stderr, "%d.", *pptr++);
+    fprintf(stderr, "%d)", *pptr++);
     break;


-    /* Handle exact repetitions. The count is already in characters, but we
-    need to skip over a multibyte character in UTF8 mode.  */
-
-    case OP_EXACT:
-    case OP_EXACTI:
-    case OP_NOTEXACT:
-    case OP_NOTEXACTI:
-    branchlength += GET2(cc,1);
-    cc += 2 + IMM2_SIZE;
-#ifdef SUPPORT_UNICODE
-    if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
-#endif
+    case META_COND_NAME:
+    fprintf(stderr, "META (?(<name>) length=%d offset=", *pptr++);
+    GETOFFSET(offset, pptr);
+    fprintf(stderr, "%zd", offset);
     break;


-    case OP_TYPEEXACT:
-    branchlength += GET2(cc,1);
-    if (cc[1 + IMM2_SIZE] == OP_PROP || cc[1 + IMM2_SIZE] == OP_NOTPROP)
-      cc += 2;
-    cc += 1 + IMM2_SIZE + 1;
+    case META_COND_RNAME:
+    fprintf(stderr, "META (?(R&name) length=%d offset=", *pptr++);
+    GETOFFSET(offset, pptr);
+    fprintf(stderr, "%zd", offset);
     break;


-    /* Handle single-char matchers */
+    /* This is kept as a name, because it might be. */


-    case OP_PROP:
-    case OP_NOTPROP:
-    cc += 2;
-    /* Fall through */
-
-    case OP_HSPACE:
-    case OP_VSPACE:
-    case OP_NOT_HSPACE:
-    case OP_NOT_VSPACE:
-    case OP_NOT_DIGIT:
-    case OP_DIGIT:
-    case OP_NOT_WHITESPACE:
-    case OP_WHITESPACE:
-    case OP_NOT_WORDCHAR:
-    case OP_WORDCHAR:
-    case OP_ANY:
-    case OP_ALLANY:
-    branchlength++;
-    cc++;
+    case META_COND_RNUMBER:
+    fprintf(stderr, "META (?(Rnumber) length=%d offset=", *pptr++);
+    GETOFFSET(offset, pptr);
+    fprintf(stderr, "%zd", offset);
     break;


-    /* The single-byte matcher isn't allowed. This only happens in UTF-8 or
-    UTF-16 mode; otherwise \C is coded as OP_ALLANY. */
+    case META_MARK:
+    fprintf(stderr, "META (*MARK:");
+    goto SHOWARG;


-    case OP_ANYBYTE:
-    return FFL_BACKSLASHC;
+    case META_PRUNE_ARG:
+    fprintf(stderr, "META (*PRUNE:");
+    goto SHOWARG;


-    /* Check a class for variable quantification */
+    case META_SKIP_ARG:
+    fprintf(stderr, "META (*SKIP:");
+    goto SHOWARG;


-    case OP_CLASS:
-    case OP_NCLASS:
-#ifdef SUPPORT_WIDE_CHARS
-    case OP_XCLASS:
-    /* The original code caused an unsigned overflow in 64 bit systems,
-    so now we use a conditional statement. */
-    if (op == OP_XCLASS)
-      cc += GET(cc, 1);
-    else
-      cc += PRIV(OP_lengths)[OP_CLASS];
-#else
-    cc += PRIV(OP_lengths)[OP_CLASS];
-#endif
-
-    switch (*cc)
+    case META_THEN_ARG:
+    fprintf(stderr, "META (*THEN:");
+    SHOWARG:
+    length = *pptr++;
+    for (i = 0; i < length; i++)
       {
-      case OP_CRSTAR:
-      case OP_CRMINSTAR:
-      case OP_CRPLUS:
-      case OP_CRMINPLUS:
-      case OP_CRQUERY:
-      case OP_CRMINQUERY:
-      case OP_CRPOSSTAR:
-      case OP_CRPOSPLUS:
-      case OP_CRPOSQUERY:
-      goto ISNOTFIXED;
-
-      case OP_CRRANGE:
-      case OP_CRMINRANGE:
-      case OP_CRPOSRANGE:
-      if (GET2(cc,1) != GET2(cc,1+IMM2_SIZE)) goto ISNOTFIXED;
-      branchlength += GET2(cc,1);
-      cc += 1 + 2 * IMM2_SIZE;
-      break;
-
-      default:
-      branchlength++;
+      uint32_t cc = *pptr++;
+      if (cc > 32 && cc < 128) fprintf(stderr, "%c", cc);
+        else fprintf(stderr, "\\x{%x}", cc);
       }
+    fprintf(stderr, ") length=%u", length);
     break;
+    }
+  fprintf(stderr, "\n");
+  }
+return;
+}
+#endif  /* DEBUG_SHOW_PARSED */


-    /* Anything else is variable length */


-    case OP_ANYNL:
-    case OP_BRAMINZERO:
-    case OP_BRAPOS:
-    case OP_BRAPOSZERO:
-    case OP_BRAZERO:
-    case OP_CBRAPOS:
-    case OP_EXTUNI:
-    case OP_KETRMAX:
-    case OP_KETRMIN:
-    case OP_KETRPOS:
-    case OP_MINPLUS:
-    case OP_MINPLUSI:
-    case OP_MINQUERY:
-    case OP_MINQUERYI:
-    case OP_MINSTAR:
-    case OP_MINSTARI:
-    case OP_MINUPTO:
-    case OP_MINUPTOI:
-    case OP_NOTMINPLUS:
-    case OP_NOTMINPLUSI:
-    case OP_NOTMINQUERY:
-    case OP_NOTMINQUERYI:
-    case OP_NOTMINSTAR:
-    case OP_NOTMINSTARI:
-    case OP_NOTMINUPTO:
-    case OP_NOTMINUPTOI:
-    case OP_NOTPLUS:
-    case OP_NOTPLUSI:
-    case OP_NOTPOSPLUS:
-    case OP_NOTPOSPLUSI:
-    case OP_NOTPOSQUERY:
-    case OP_NOTPOSQUERYI:
-    case OP_NOTPOSSTAR:
-    case OP_NOTPOSSTARI:
-    case OP_NOTPOSUPTO:
-    case OP_NOTPOSUPTOI:
-    case OP_NOTQUERY:
-    case OP_NOTQUERYI:
-    case OP_NOTSTAR:
-    case OP_NOTSTARI:
-    case OP_NOTUPTO:
-    case OP_NOTUPTOI:
-    case OP_PLUS:
-    case OP_PLUSI:
-    case OP_POSPLUS:
-    case OP_POSPLUSI:
-    case OP_POSQUERY:
-    case OP_POSQUERYI:
-    case OP_POSSTAR:
-    case OP_POSSTARI:
-    case OP_POSUPTO:
-    case OP_POSUPTOI:
-    case OP_QUERY:
-    case OP_QUERYI:
-    case OP_REF:
-    case OP_REFI:
-    case OP_DNREF:
-    case OP_DNREFI:
-    case OP_SBRA:
-    case OP_SBRAPOS:
-    case OP_SCBRA:
-    case OP_SCBRAPOS:
-    case OP_SCOND:
-    case OP_SKIPZERO:
-    case OP_STAR:
-    case OP_STARI:
-    case OP_TYPEMINPLUS:
-    case OP_TYPEMINQUERY:
-    case OP_TYPEMINSTAR:
-    case OP_TYPEMINUPTO:
-    case OP_TYPEPLUS:
-    case OP_TYPEPOSPLUS:
-    case OP_TYPEPOSQUERY:
-    case OP_TYPEPOSSTAR:
-    case OP_TYPEPOSUPTO:
-    case OP_TYPEQUERY:
-    case OP_TYPESTAR:
-    case OP_TYPEUPTO:
-    case OP_UPTO:
-    case OP_UPTOI:
-    goto ISNOTFIXED;


-    /* Catch unrecognized opcodes so that when new ones are added they
-    are not forgotten, as has happened in the past. */
+/*************************************************
+*               Copy compiled code               *
+*************************************************/


-    default:
-    return FFL_UNKNOWNOP;
-    }
-  }
-/* Control never gets here except by goto. */
+/* Compiled JIT code cannot be copied, so the new compiled block has no
+associated JIT data. */


-ISNOTFIXED:
-if (group > 0)
+PCRE2_EXP_DEFN pcre2_code * PCRE2_CALL_CONVENTION
+pcre2_code_copy(const pcre2_code *code)
+{
+PCRE2_SIZE* ref_count;
+pcre2_code *newcode;
+
+if (code == NULL) return NULL;
+newcode = code->memctl.malloc(code->blocksize, code->memctl.memory_data);
+if (newcode == NULL) return NULL;
+memcpy(newcode, code, code->blocksize);
+newcode->executable_jit = NULL;
+
+/* If the code is one that has been deserialized, increment the reference count
+in the decoded tables. */
+
+if ((code->flags & PCRE2_DEREF_TABLES) != 0)
{
- groupinfo |= GI_NOT_FIXED_LENGTH;
- cb->groupinfo[group] = groupinfo;
+ ref_count = (PCRE2_SIZE *)(code->tables + tables_length);
+ (*ref_count)++;
}
-return FFL_NOTFIXED;
+
+return newcode;
}



 /*************************************************
-*      Find first significant op code            *
+*               Free compiled code               *
 *************************************************/


-/* This is called by several functions that scan a compiled expression looking
-for a fixed first character, or an anchoring op code etc. It skips over things
-that do not influence this. For some calls, it makes sense to skip negative
-forward and all backward assertions, and also the \b assertion; for others it
-does not.
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_code_free(pcre2_code *code)
+{
+PCRE2_SIZE* ref_count;

-Arguments:
-  code         pointer to the start of the group
-  skipassert   TRUE if certain assertions are to be skipped
+if (code != NULL)
+  {
+  if (code->executable_jit != NULL)
+    PRIV(jit_free)(code->executable_jit, &code->memctl);


-Returns:       pointer to the first significant opcode
-*/
-
-static const PCRE2_UCHAR*
-first_significant_code(PCRE2_SPTR code, BOOL skipassert)
-{
-for (;;)
-  {
-  switch ((int)*code)
+  if ((code->flags & PCRE2_DEREF_TABLES) != 0)
     {
-    case OP_ASSERT_NOT:
-    case OP_ASSERTBACK:
-    case OP_ASSERTBACK_NOT:
-    if (!skipassert) return code;
-    do code += GET(code, 1); while (*code == OP_ALT);
-    code += PRIV(OP_lengths)[*code];
-    break;
+    /* Decoded tables belong to the codes after deserialization, and they must
+    be freed when there are no more reference to them. The *ref_count should
+    always be > 0. */


-    case OP_WORD_BOUNDARY:
-    case OP_NOT_WORD_BOUNDARY:
-    if (!skipassert) return code;
-    /* Fall through */
+    ref_count = (PCRE2_SIZE *)(code->tables + tables_length);
+    if (*ref_count > 0)
+      {
+      (*ref_count)--;
+      if (*ref_count == 0)
+        code->memctl.free((void *)code->tables, code->memctl.memory_data);
+      }
+    }


-    case OP_CALLOUT:
-    case OP_CREF:
-    case OP_DNCREF:
-    case OP_RREF:
-    case OP_DNRREF:
-    case OP_FALSE:
-    case OP_TRUE:
-    code += PRIV(OP_lengths)[*code];
-    break;
-
-    case OP_CALLOUT_STR:
-    code += GET(code, 1 + 2*LINK_SIZE);
-    break;
-
-    default:
-    return code;
-    }
+  code->memctl.free(code, code->memctl.memory_data);
   }
-/* Control never reaches here */
 }




 /*************************************************
-*    Scan compiled branch for non-emptiness      *
+*         Read a number, possibly signed         *
 *************************************************/


-/* This function scans through a branch of a compiled pattern to see whether it
-can match the empty string. It is called at the end of compiling to check the
-entire pattern, and from compile_branch() when checking for an unlimited repeat
-of a group that can match nothing. In the latter case it is called only when
-doing the real compile, not during the pre-compile that measures the size of
-the compiled pattern.
+/* This function is used to read numbers in the pattern. The initial pointer
+must be the sign or first digit of the number. When relative values (introduced
+by + or -) are allowed, they are relative group numbers, and the result must be
+greater than zero.

-Note that first_significant_code() skips over backward and negative forward
-assertions when its final argument is TRUE. If we hit an unclosed bracket, we
-return "empty" - this means we've struck an inner bracket whose current branch
-will already have been scanned.
-
 Arguments:
-  code        points to start of search
-  endcode     points to where to stop
-  utf         TRUE if in UTF mode
-  cb          compile data
-  atend       TRUE if being called to check an entire pattern
-  recurses    chain of recurse_check to catch mutual recursion
-  countptr    pointer to count to catch over-complicated pattern
+  ptrptr      points to the character pointer variable
+  ptrend      points to the end of the input string
+  allow_sign  if < 0, sign not allowed; if >= 0, sign is relative to this
+  max_value   the largest number allowed
+  max_error   the error to give for an over-large number
+  intptr      where to put the result
+  errcodeptr  where to put an error code


-Returns:      0 if what is matched cannot be empty
-              1 if what is matched could be empty
-             -1 if the pattern is too complicated
+Returns:      TRUE  - a number was read
+              FALSE - errorcode == 0 => no number was found
+                      errorcode != 0 => an error occurred
 */


-#define CBE_NOTEMPTY          0
-#define CBE_EMPTY             1
-#define CBE_TOOCOMPLICATED  (-1)
-
-
-static int
-could_be_empty_branch(PCRE2_SPTR code, PCRE2_SPTR endcode, BOOL utf,
-  compile_block *cb, BOOL atend, recurse_check *recurses, int *countptr)
+static BOOL
+read_number(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, int32_t allow_sign,
+  uint32_t max_value, uint32_t max_error, int *intptr, int *errorcodeptr)
 {
-uint32_t group = 0;
-uint32_t groupinfo = 0;
-register PCRE2_UCHAR c;
-recurse_check this_recurse;
+int sign = 0;
+uint32_t n = 0;
+PCRE2_SPTR ptr = *ptrptr;
+BOOL yield = FALSE;


-/* If what we are checking has already been set as "could be empty", we know
-the answer. */
+*errorcodeptr = 0;

-if (*code >= OP_SBRA && *code <= OP_SCOND) return CBE_EMPTY;
+if (allow_sign >= 0 && ptr < ptrend &&
+    (*ptr == CHAR_PLUS || *ptr == CHAR_MINUS))
+  sign = (*ptr++ == CHAR_MINUS)? -1 : +1;


-/* If this is a capturing group, we may have the answer cached, but we can only
-use this information if there are no (?| groups in the pattern, because
-otherwise group numbers are not unique. */
-
-if ((cb->external_flags & PCRE2_DUPCAPUSED) == 0 &&
-    (*code == OP_CBRA || *code == OP_CBRAPOS))
+if (ptr >= ptrend || !IS_DIGIT(*ptr)) return FALSE;
+while (ptr < ptrend && IS_DIGIT(*ptr))
   {
-  group = GET2(code, 1 + LINK_SIZE);
-  groupinfo = cb->groupinfo[group];
-  if ((groupinfo & GI_SET_COULD_BE_EMPTY) != 0)
-    return ((groupinfo & GI_COULD_BE_EMPTY) != 0)? CBE_EMPTY : CBE_NOTEMPTY;
+  n = n * 10 + *ptr++ - CHAR_0;
+  if (n > max_value)
+    {
+    *errorcodeptr = max_error;
+    goto EXIT;
+    }
   }


-/* A large and/or complex regex can take too long to process. We have to assume
-it can match an empty string. This can happen more often when (?| groups are
-present in the pattern and the caching is disabled. Setting the cap at 1100
-allows the test for more than 1023 capturing patterns to work. */
-
-if ((*countptr)++ > 1100) return CBE_TOOCOMPLICATED;
-
-/* Scan the opcodes for this branch. */
-
-for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
-     code < endcode;
-     code = first_significant_code(code + PRIV(OP_lengths)[c], TRUE))
+if (allow_sign >= 0 && sign != 0)
   {
-  PCRE2_SPTR ccode;
-
-  c = *code;
-
-  /* Skip over forward assertions; the other assertions are skipped by
-  first_significant_code() with a TRUE final argument. */
-
-  if (c == OP_ASSERT)
+  if (n == 0)
     {
-    do code += GET(code, 1); while (*code == OP_ALT);
-    c = *code;
-    continue;
+    *errorcodeptr = ERR26;  /* +0 and -0 are not allowed */
+    goto EXIT;
     }


-  /* For a recursion/subroutine call we can scan the recursion when this
-  function is called at the end, to check a complete pattern. Before then,
-  recursions just have the group number as their argument and in any case may
-  be forward references. In that situation, we return CBE_EMPTY, just in case.
-  It means that unlimited repeats of groups that contain recursions are always
-  treated as "could be empty" - which just adds a bit more processing time
-  because of the runtime check. */
-
-  if (c == OP_RECURSE)
+  if (sign > 0) n += allow_sign;
+  else if ((int)n > allow_sign)
     {
-    PCRE2_SPTR scode, endgroup;
-    BOOL empty_branch;
+    *errorcodeptr = ERR15;  /* Non-existent subpattern */
+    goto EXIT;
+    }
+  else n = allow_sign + 1 - n;
+  }


-    if (!atend) goto ISTRUE;
-    scode = cb->start_code + GET(code, 1);
-    endgroup = scode;
+yield = TRUE;


-    /* We need to detect whether this is a recursive call, as otherwise there
-    will be an infinite loop. If it is a recursion, just skip over it. Simple
-    recursions are easily detected. For mutual recursions we keep a chain on
-    the stack. */
+EXIT:
+*intptr = n;
+*ptrptr = ptr;
+return yield;
+}


-    do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT);
-    if (code >= scode && code <= endgroup) continue;  /* Simple recursion */
-    else
-      {
-      recurse_check *r = recurses;
-      for (r = recurses; r != NULL; r = r->prev)
-        if (r->group == scode) break;
-      if (r != NULL) continue;   /* Mutual recursion */
-      }


-    /* Scan the referenced group, remembering it on the stack chain to detect
-    mutual recursions. */


-    empty_branch = FALSE;
-    this_recurse.prev = recurses;
-    this_recurse.group = scode;
+/*************************************************
+*         Read repeat counts                     *
+*************************************************/


-    do
-      {
-      int rc = could_be_empty_branch(scode, endcode, utf, cb, atend,
-        &this_recurse, countptr);
-      if (rc < 0) return rc;
-      if (rc > 0)
-        {
-        empty_branch = TRUE;
-        break;
-        }
-      scode += GET(scode, 1);
-      }
-    while (*scode == OP_ALT);
+/* Read an item of the form {n,m} and return the values if non-NULL pointers
+are supplied. Repeat counts must be less than 65536 (MAX_REPEAT_COUNT); a
+larger value is used for "unlimited". We have to use signed arguments for
+read_number() because it is capable of returning a signed value.


-    if (!empty_branch) goto ISFALSE;  /* All branches are non-empty */
-    continue;
-    }
+Arguments:
+  ptrptr         points to pointer to character after'{'
+  ptrend         pointer to end of input
+  minp           if not NULL, pointer to int for min
+  maxp           if not NULL, pointer to int for max (-1 if no max)
+                 returned as -1 if no max
+  errorcodeptr   points to error code variable


-  /* Groups with zero repeats can of course be empty; skip them. */
+Returns:         FALSE if not a repeat quantifier, errorcode set zero
+                 FALSE on error, with errorcode set non-zero
+                 TRUE on success, with pointer updated to point after '}'
+*/


-  if (c == OP_BRAZERO || c == OP_BRAMINZERO || c == OP_SKIPZERO ||
-      c == OP_BRAPOSZERO)
-    {
-    code += PRIV(OP_lengths)[c];
-    do code += GET(code, 1); while (*code == OP_ALT);
-    c = *code;
-    continue;
-    }
+static BOOL
+read_repeat_counts(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, uint32_t *minp,
+  uint32_t *maxp, int *errorcodeptr)
+{
+PCRE2_SPTR p = *ptrptr;
+BOOL yield = FALSE;
+int32_t min = 0;
+int32_t max = REPEAT_UNLIMITED;  /* This value is larger than MAX_REPAT_COUNT */


- /* A nested group that is already marked as "could be empty" can just be
- skipped. */
+/* NB read_number() initializes the error code to zero. The only error is for a
+number that is too big. */

-  if (c == OP_SBRA  || c == OP_SBRAPOS ||
-      c == OP_SCBRA || c == OP_SCBRAPOS)
-    {
-    do code += GET(code, 1); while (*code == OP_ALT);
-    c = *code;
-    continue;
-    }
+if (!read_number(&p, ptrend, -1, MAX_REPEAT_COUNT, ERR5, &min, errorcodeptr))
+  goto EXIT;


- /* For other groups, scan the branches. */
+if (p >= ptrend) goto EXIT;

-  if (c == OP_BRA  || c == OP_BRAPOS ||
-      c == OP_CBRA || c == OP_CBRAPOS ||
-      c == OP_ONCE || c == OP_ONCE_NC ||
-      c == OP_COND || c == OP_SCOND)
-    {
-    BOOL empty_branch;
-    if (GET(code, 1) == 0) goto ISTRUE;    /* Hit unclosed bracket */
+if (*p == CHAR_RIGHT_CURLY_BRACKET)
+  {
+  p++;
+  max = min;
+  }


-    /* If a conditional group has only one branch, there is a second, implied,
-    empty branch, so just skip over the conditional, because it could be empty.
-    Otherwise, scan the individual branches of the group. */
-
-    if (c == OP_COND && code[GET(code, 1)] != OP_ALT)
-      code += GET(code, 1);
-    else
-      {
-      empty_branch = FALSE;
-      do
-        {
-        if (!empty_branch)
-          {
-          int rc = could_be_empty_branch(code, endcode, utf, cb, atend,
-            recurses, countptr);
-          if (rc < 0) return rc;
-          if (rc > 0) empty_branch = TRUE;
-          }
-        code += GET(code, 1);
-        }
-      while (*code == OP_ALT);
-      if (!empty_branch) goto ISFALSE;   /* All branches are non-empty */
-      }
-
-    c = *code;
-    continue;
-    }
-
-  /* Handle the other opcodes */
-
-  switch (c)
+else
+  {
+  if (*p++ != CHAR_COMMA || p >= ptrend) goto EXIT;
+  if (*p != CHAR_RIGHT_CURLY_BRACKET)
     {
-    /* Check for quantifiers after a class. XCLASS is used for classes that
-    cannot be represented just by a bit map. This includes negated single
-    high-valued characters. The length in PRIV(OP_lengths)[] is zero; the
-    actual length is stored in the compiled code, so we must update "code"
-    here. */
-
-#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
-    case OP_XCLASS:
-    ccode = code += GET(code, 1);
-    goto CHECK_CLASS_REPEAT;
-#endif
-
-    case OP_CLASS:
-    case OP_NCLASS:
-    ccode = code + PRIV(OP_lengths)[OP_CLASS];
-
-#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
-    CHECK_CLASS_REPEAT:
-#endif
-
-    switch (*ccode)
+    if (!read_number(&p, ptrend, -1, MAX_REPEAT_COUNT, ERR5, &max,
+        errorcodeptr) || *p != CHAR_RIGHT_CURLY_BRACKET)
+      goto EXIT;
+    if (max < min)
       {
-      case OP_CRSTAR:            /* These could be empty; continue */
-      case OP_CRMINSTAR:
-      case OP_CRQUERY:
-      case OP_CRMINQUERY:
-      case OP_CRPOSSTAR:
-      case OP_CRPOSQUERY:
-      break;
-
-      default:                   /* Non-repeat => class must match */
-      case OP_CRPLUS:            /* These repeats aren't empty */
-      case OP_CRMINPLUS:
-      case OP_CRPOSPLUS:
-      goto ISFALSE;
-
-      case OP_CRRANGE:
-      case OP_CRMINRANGE:
-      case OP_CRPOSRANGE:
-      if (GET2(ccode, 1) > 0) goto ISFALSE;  /* Minimum > 0 */
-      break;
+      *errorcodeptr = ERR4;
+      goto EXIT;
       }
-    break;
-
-    /* Opcodes that must match a character */
-
-    case OP_ANY:
-    case OP_ALLANY:
-    case OP_ANYBYTE:
-
-    case OP_PROP:
-    case OP_NOTPROP:
-    case OP_ANYNL:
-
-    case OP_NOT_HSPACE:
-    case OP_HSPACE:
-    case OP_NOT_VSPACE:
-    case OP_VSPACE:
-    case OP_EXTUNI:
-
-    case OP_NOT_DIGIT:
-    case OP_DIGIT:
-    case OP_NOT_WHITESPACE:
-    case OP_WHITESPACE:
-    case OP_NOT_WORDCHAR:
-    case OP_WORDCHAR:
-
-    case OP_CHAR:
-    case OP_CHARI:
-    case OP_NOT:
-    case OP_NOTI:
-
-    case OP_PLUS:
-    case OP_PLUSI:
-    case OP_MINPLUS:
-    case OP_MINPLUSI:
-
-    case OP_NOTPLUS:
-    case OP_NOTPLUSI:
-    case OP_NOTMINPLUS:
-    case OP_NOTMINPLUSI:
-
-    case OP_POSPLUS:
-    case OP_POSPLUSI:
-    case OP_NOTPOSPLUS:
-    case OP_NOTPOSPLUSI:
-
-    case OP_EXACT:
-    case OP_EXACTI:
-    case OP_NOTEXACT:
-    case OP_NOTEXACTI:
-
-    case OP_TYPEPLUS:
-    case OP_TYPEMINPLUS:
-    case OP_TYPEPOSPLUS:
-    case OP_TYPEEXACT:
-    goto ISFALSE;
-
-    /* These are going to continue, as they may be empty, but we have to
-    fudge the length for the \p and \P cases. */
-
-    case OP_TYPESTAR:
-    case OP_TYPEMINSTAR:
-    case OP_TYPEPOSSTAR:
-    case OP_TYPEQUERY:
-    case OP_TYPEMINQUERY:
-    case OP_TYPEPOSQUERY:
-    if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2;
-    break;
-
-    /* Same for these */
-
-    case OP_TYPEUPTO:
-    case OP_TYPEMINUPTO:
-    case OP_TYPEPOSUPTO:
-    if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
-      code += 2;
-    break;
-
-    /* End of branch */
-
-    case OP_KET:
-    case OP_KETRMAX:
-    case OP_KETRMIN:
-    case OP_KETRPOS:
-    case OP_ALT:
-    goto ISTRUE;
-
-    /* In UTF-8 or UTF-16 mode, STAR, MINSTAR, POSSTAR, QUERY, MINQUERY,
-    POSQUERY, UPTO, MINUPTO, and POSUPTO and their caseless and negative
-    versions may be followed by a multibyte character. */
-
-#ifdef MAYBE_UTF_MULTI
-    case OP_STAR:
-    case OP_STARI:
-    case OP_NOTSTAR:
-    case OP_NOTSTARI:
-
-    case OP_MINSTAR:
-    case OP_MINSTARI:
-    case OP_NOTMINSTAR:
-    case OP_NOTMINSTARI:
-
-    case OP_POSSTAR:
-    case OP_POSSTARI:
-    case OP_NOTPOSSTAR:
-    case OP_NOTPOSSTARI:
-
-    case OP_QUERY:
-    case OP_QUERYI:
-    case OP_NOTQUERY:
-    case OP_NOTQUERYI:
-
-    case OP_MINQUERY:
-    case OP_MINQUERYI:
-    case OP_NOTMINQUERY:
-    case OP_NOTMINQUERYI:
-
-    case OP_POSQUERY:
-    case OP_POSQUERYI:
-    case OP_NOTPOSQUERY:
-    case OP_NOTPOSQUERYI:
-    if (utf && HAS_EXTRALEN(code[1])) code += GET_EXTRALEN(code[1]);
-    break;
-
-    case OP_UPTO:
-    case OP_UPTOI:
-    case OP_NOTUPTO:
-    case OP_NOTUPTOI:
-
-    case OP_MINUPTO:
-    case OP_MINUPTOI:
-    case OP_NOTMINUPTO:
-    case OP_NOTMINUPTOI:
-
-    case OP_POSUPTO:
-    case OP_POSUPTOI:
-    case OP_NOTPOSUPTO:
-    case OP_NOTPOSUPTOI:
-    if (utf && HAS_EXTRALEN(code[1 + IMM2_SIZE])) code += GET_EXTRALEN(code[1 + IMM2_SIZE]);
-    break;
-#endif  /* MAYBE_UTF_MULTI */
-
-    /* MARK, and PRUNE/SKIP/THEN with an argument must skip over the argument
-    string. */
-
-    case OP_MARK:
-    case OP_PRUNE_ARG:
-    case OP_SKIP_ARG:
-    case OP_THEN_ARG:
-    code += code[1];
-    break;
-
-    /* None of the remaining opcodes are required to match a character. */
-
-    default:
-    break;
     }
+  p++;
   }


-ISTRUE:
-groupinfo |= GI_COULD_BE_EMPTY;
+yield = TRUE;
+if (minp != NULL) *minp = (uint32_t)min;
+if (maxp != NULL) *maxp = (uint32_t)max;

-ISFALSE:
-if (group > 0) cb->groupinfo[group] = groupinfo | GI_SET_COULD_BE_EMPTY;
+/* Update the pattern pointer on success, or after an error, but not when
+the result is "not a repeat quantifier". */

-return ((groupinfo & GI_COULD_BE_EMPTY) != 0)? CBE_EMPTY : CBE_NOTEMPTY;
-}
+EXIT:
+if (yield || *errorcodeptr != 0) *ptrptr = p;
+return yield;



-/*************************************************
-*            Check for counted repeat            *
-*************************************************/
-
-/* This function is called when a '{' is encountered in a place where it might
-start a quantifier. It looks ahead to see if it really is a quantifier, that
-is, one of the forms {ddd} {ddd,} or {ddd,ddd} where the ddds are digits.
-
-Argument:   pointer to the first char after '{'
-Returns:    TRUE or FALSE
-*/
-
-static BOOL
-is_counted_repeat(PCRE2_SPTR p)
-{
-if (!IS_DIGIT(*p)) return FALSE;
-p++;
-while (IS_DIGIT(*p)) p++;
-if (*p == CHAR_RIGHT_CURLY_BRACKET) return TRUE;
-
-if (*p++ != CHAR_COMMA) return FALSE;
-if (*p == CHAR_RIGHT_CURLY_BRACKET) return TRUE;
-
-if (!IS_DIGIT(*p)) return FALSE;
-p++;
-while (IS_DIGIT(*p)) p++;
-
-return (*p == CHAR_RIGHT_CURLY_BRACKET);
 }



@@ -1789,8 +1244,8 @@
/* This function is called when a \ has been encountered. It either returns a
positive value for a simple escape such as \d, or 0 for a data character, which
is placed in chptr. A backreference to group n is returned as negative n. On
-entry, ptr is pointing at the \. On exit, it points the final code unit of the
-escape sequence.
+entry, ptr is pointing at the character after \. On exit, it points after the
+final code unit of the escape sequence.

This function is also called from pcre2_substitute() to handle escape sequences
in replacement strings. In this case, the cb argument is NULL, and only
@@ -1798,13 +1253,6 @@
not relevant, but the options argument is the final value of the compiled
pattern's options.

-There is one "trick" case: when a sequence such as [[:>:]] or \s in UCP mode is
-processed, it is replaced by a nested alternative sequence. If this contains a
-backslash (which is usually does), ptrend does not point to its end - it still
-points to the end of the whole pattern. However, we can detect this case
-because cb->nestptr[0] will be non-NULL. The nested sequences are all zero-
-terminated and there are only ever two levels of nesting.
-
 Arguments:
   ptrptr         points to the input position pointer
   ptrend         points to the end of the input
@@ -1816,7 +1264,7 @@


 Returns:         zero => a data character
                  positive => a special escape sequence
-                 negative => a back reference
+                 negative => a numerical back reference
                  on error, errorcodeptr is set non-zero
 */


@@ -1825,16 +1273,11 @@
int *errorcodeptr, uint32_t options, BOOL isclass, compile_block *cb)
{
BOOL utf = (options & PCRE2_UTF) != 0;
-PCRE2_SPTR ptr = *ptrptr + 1;
-register uint32_t c, cc;
+PCRE2_SPTR ptr = *ptrptr;
+uint32_t c, cc;
int escape = 0;
int i;

-/* Find the end of a nested insert. */
-
-if (cb != NULL && cb->nestptr[0] != NULL)
- ptrend = ptr + PRIV(strlen)(ptr);
-
/* If backslash is at the end of the string, it's an error. */

if (ptr >= ptrend)
@@ -1844,7 +1287,7 @@
}

 GETCHARINCTEST(c, ptr);         /* Get character value, increment pointer */
-ptr--;                          /* Set pointer back to the last code unit */
+*errorcodeptr = 0;              /* Be optimistic */


/* Non-alphanumerics are literals, so we just leave the value in c. An initial
value test saves a memory lookup for code points outside the alphanumeric
@@ -1870,8 +1313,8 @@
else
{
PCRE2_SPTR oldptr;
- BOOL braced, negated, overflow;
- unsigned int s;
+ BOOL overflow;
+ int s;

/* Filter calls from pcre2_substitute(). */

@@ -1900,12 +1343,13 @@
     if ((options & PCRE2_ALT_BSUX) == 0) *errorcodeptr = ERR37; else
       {
       uint32_t xc;
-      if ((cc = XDIGIT(ptr[1])) == 0xff) break;  /* Not a hex digit */
+      if (ptrend - ptr < 4) break;              /* Less than 4 chars */
+      if ((cc = XDIGIT(ptr[0])) == 0xff) break;  /* Not a hex digit */
+      if ((xc = XDIGIT(ptr[1])) == 0xff) break;  /* Not a hex digit */
+      cc = (cc << 4) | xc;
       if ((xc = XDIGIT(ptr[2])) == 0xff) break;  /* Not a hex digit */
       cc = (cc << 4) | xc;
       if ((xc = XDIGIT(ptr[3])) == 0xff) break;  /* Not a hex digit */
-      cc = (cc << 4) | xc;
-      if ((xc = XDIGIT(ptr[4])) == 0xff) break;  /* Not a hex digit */
       c = (cc << 4) | xc;
       ptr += 4;
       if (utf)
@@ -1917,9 +1361,10 @@
       }
     break;


-    case CHAR_U:
     /* \U is unrecognized unless PCRE2_ALT_BSUX is set, in which case it is an
     upper case letter. */
+
+    case CHAR_U:
     if ((options & PCRE2_ALT_BSUX) == 0) *errorcodeptr = ERR37;
     break;


@@ -1933,87 +1378,71 @@
     (2) Perl 5.10 also supports \g{name} as a reference to a named group. This
     is part of Perl's movement towards a unified syntax for back references. As
     this is synonymous with \k{name}, we fudge it up by pretending it really
-    was \k.
+    was \k{name}.


     (3) For Oniguruma compatibility we also support \g followed by a name or a
     number either in angle brackets or in single quotes. However, these are
-    (possibly recursive) subroutine calls, _not_ backreferences. Just return
-    the ESC_g code (cf \k). */
+    (possibly recursive) subroutine calls, _not_ backreferences. We return
+    the ESC_g code.


+    Summary: Return a negative number for a numerical back reference, ESC_k for
+    a named back reference, and ESC_g for a named or numbered subroutine call.
+    */
+
     case CHAR_g:
     if (isclass) break;
-    if (ptr[1] == CHAR_LESS_THAN_SIGN || ptr[1] == CHAR_APOSTROPHE)
+
+    if (ptr >= ptrend)
       {
+      *errorcodeptr = ERR57;
+      break;
+      }
+
+    if (*ptr == CHAR_LESS_THAN_SIGN || *ptr == CHAR_APOSTROPHE)
+      {
       escape = ESC_g;
       break;
       }


-    /* Handle the Perl-compatible cases */
+    /* If there is a brace delimiter, try to read a numerical reference. If
+    there isn't one, assume we have a name and treat it as \k. */


-    if (ptr[1] == CHAR_LEFT_CURLY_BRACKET)
+    if (*ptr == CHAR_LEFT_CURLY_BRACKET)
       {
-      PCRE2_SPTR p;
-      for (p = ptr+2; *p != CHAR_NULL && *p != CHAR_RIGHT_CURLY_BRACKET; p++)
-        if (*p != CHAR_MINUS && !IS_DIGIT(*p)) break;
-      if (*p != CHAR_NULL && *p != CHAR_RIGHT_CURLY_BRACKET)
+      PCRE2_SPTR p = ptr + 1;
+      if (!read_number(&p, ptrend, cb->bracount, MAX_GROUP_NUMBER, ERR61, &s,
+          errorcodeptr))
         {
-        escape = ESC_k;
+        if (*errorcodeptr == 0) escape = ESC_k;  /* No number found */
         break;
         }
-      braced = TRUE;
-      ptr++;
+      if (p >= ptrend || *p != CHAR_RIGHT_CURLY_BRACKET)
+        {
+        *errorcodeptr = ERR57;
+        break;
+        }
+      ptr = p + 1;
       }
-    else braced = FALSE;


-    if (ptr[1] == CHAR_MINUS)
-      {
-      negated = TRUE;
-      ptr++;
-      }
-    else negated = FALSE;
+    /* Read an undelimited number */


-    /* The integer range is limited by the machine's int representation. */
-    s = 0;
-    overflow = FALSE;
-    while (IS_DIGIT(ptr[1]))
+    else
       {
-      if (s > INT_MAX / 10 - 1) /* Integer overflow */
+      if (!read_number(&ptr, ptrend, cb->bracount, MAX_GROUP_NUMBER, ERR61, &s,
+          errorcodeptr))
         {
-        overflow = TRUE;
+        if (*errorcodeptr == 0) *errorcodeptr = ERR57;  /* No number found */
         break;
         }
-      s = s * 10 + (unsigned int)(*(++ptr) - CHAR_0);
       }
-    if (overflow) /* Integer overflow */
-      {
-      while (IS_DIGIT(ptr[1])) ptr++;
-      *errorcodeptr = ERR61;
-      break;
-      }


-    if (braced && *(++ptr) != CHAR_RIGHT_CURLY_BRACKET)
+    if (s <= 0)
       {
-      *errorcodeptr = ERR57;
+      *errorcodeptr = ERR15;
       break;
       }


-    if (s == 0)
-      {
-      *errorcodeptr = ERR58;
-      break;
-      }
-
-    if (negated)
-      {
-      if (s > cb->bracount)
-        {
-        *errorcodeptr = ERR15;
-        break;
-        }
-      s = cb->bracount - (s - 1);
-      }
-
-    escape = -(int)s;
+    escape = -s;
     break;


     /* The handling of escape sequences consisting of a string of digits
@@ -2036,31 +1465,18 @@
     if (!isclass)
       {
       oldptr = ptr;
-      /* The integer range is limited by the machine's int representation. */
-      s = c - CHAR_0;
-      overflow = FALSE;
-      while (IS_DIGIT(ptr[1]))
-        {
-        if (s > INT_MAX / 10 - 1) /* Integer overflow */
-          {
-          overflow = TRUE;
-          break;
-          }
-        s = s * 10 + (unsigned int)(*(++ptr) - CHAR_0);
-        }
-      if (overflow) /* Integer overflow */
-        {
-        while (IS_DIGIT(ptr[1])) ptr++;
-        *errorcodeptr = ERR61;
+      ptr--;   /* Back to the digit */
+      if (!read_number(&ptr, ptrend, -1, INT_MAX/10 - 1, ERR61, &s,
+          errorcodeptr))
         break;
-        }


       /* \1 to \9 are always back references. \8x and \9x are too; \1x to \7x
       are octal escapes if there are not that many previous captures. */


-      if (s < 10 || *oldptr >= CHAR_8 || s <= cb->bracount)
+      if (s < 10 || oldptr[-1] >= CHAR_8 || s <= (int)cb->bracount)
         {
-        escape = -(int)s;     /* Indicates a back reference */
+        if (s > (int)MAX_GROUP_NUMBER) *errorcodeptr = ERR61;
+          else escape = -s;     /* Indicates a back reference */
         break;
         }
       ptr = oldptr;      /* Put the pointer back and fall through */
@@ -2068,11 +1484,10 @@


     /* Handle a digit following \ when the number is not a back reference, or
     we are within a character class. If the first digit is 8 or 9, Perl used to
-    generate a binary zero byte and then treat the digit as a following
-    literal. At least by Perl 5.18 this changed so as not to insert the binary
-    zero. */
+    generate a binary zero and then treat the digit as a following literal. At
+    least by Perl 5.18 this changed so as not to insert the binary zero. */


-    if ((c = *ptr) >= CHAR_8) break;
+    if (c >= CHAR_8) break;


     /* Fall through with a digit less than 8 */


@@ -2084,8 +1499,8 @@

     case CHAR_0:
     c -= CHAR_0;
-    while(i++ < 2 && ptr[1] >= CHAR_0 && ptr[1] <= CHAR_7)
-        c = c * 8 + *(++ptr) - CHAR_0;
+    while(i++ < 2 && ptr < ptrend && *ptr >= CHAR_0 && *ptr <= CHAR_7)
+        c = c * 8 + *ptr++ - CHAR_0;
 #if PCRE2_CODE_UNIT_WIDTH == 8
     if (!utf && c > 0xff) *errorcodeptr = ERR51;
 #endif
@@ -2095,13 +1510,18 @@
     specifying character codes in octal. The only supported form is \o{ddd}. */


     case CHAR_o:
-    if (ptr[1] != CHAR_LEFT_CURLY_BRACKET) *errorcodeptr = ERR55; else
-    if (ptr[2] == CHAR_RIGHT_CURLY_BRACKET) *errorcodeptr = ERR78; else
+    if (ptr >= ptrend || *ptr++ != CHAR_LEFT_CURLY_BRACKET)
       {
-      ptr += 2;
+      ptr--;
+      *errorcodeptr = ERR55;
+      }
+    else if (ptr >= ptrend || *ptr == CHAR_RIGHT_CURLY_BRACKET)
+      *errorcodeptr = ERR78;
+    else
+      {
       c = 0;
       overflow = FALSE;
-      while (*ptr >= CHAR_0 && *ptr <= CHAR_7)
+      while (ptr < ptrend && *ptr >= CHAR_0 && *ptr <= CHAR_7)
         {
         cc = *ptr++;
         if (c == 0 && cc == CHAR_0) continue;     /* Leading zeroes */
@@ -2119,14 +1539,22 @@
         }
       if (overflow)
         {
-        while (*ptr >= CHAR_0 && *ptr <= CHAR_7) ptr++;
+        while (ptr < ptrend && *ptr >= CHAR_0 && *ptr <= CHAR_7) ptr++;
         *errorcodeptr = ERR34;
         }
-      else if (*ptr == CHAR_RIGHT_CURLY_BRACKET)
+      else if (ptr < ptrend && *ptr++ == CHAR_RIGHT_CURLY_BRACKET)
         {
-        if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73;
+        if (utf && c >= 0xd800 && c <= 0xdfff)
+          {
+          ptr--;
+          *errorcodeptr = ERR73;
+          }
         }
-      else *errorcodeptr = ERR64;
+      else
+        {
+        ptr--;
+        *errorcodeptr = ERR64;
+        }
       }
     break;


@@ -2137,8 +1565,9 @@
     if ((options & PCRE2_ALT_BSUX) != 0)
       {
       uint32_t xc;
-      if ((cc = XDIGIT(ptr[1])) == 0xff) break;  /* Not a hex digit */
-      if ((xc = XDIGIT(ptr[2])) == 0xff) break;  /* Not a hex digit */
+      if (ptrend - ptr < 2) break;               /* Less than 2 characters */
+      if ((cc = XDIGIT(ptr[0])) == 0xff) break;  /* Not a hex digit */
+      if ((xc = XDIGIT(ptr[1])) == 0xff) break;  /* Not a hex digit */
       c = (cc << 4) | xc;
       ptr += 2;
       }    /* End PCRE2_ALT_BSUX handling */
@@ -2152,10 +1581,9 @@


     else
       {
-      if (ptr[1] == CHAR_LEFT_CURLY_BRACKET)
+      if (ptr < ptrend && *ptr == CHAR_LEFT_CURLY_BRACKET)
         {
-        ptr += 2;
-        if (*ptr == CHAR_RIGHT_CURLY_BRACKET)
+        if (++ptr >= ptrend || *ptr == CHAR_RIGHT_CURLY_BRACKET)
           {
           *errorcodeptr = ERR78;
           break;
@@ -2163,7 +1591,7 @@
         c = 0;
         overflow = FALSE;


-        while ((cc = XDIGIT(*ptr)) != 0xff)
+        while (ptr < ptrend && (cc = XDIGIT(*ptr)) != 0xff)
           {
           ptr++;
           if (c == 0 && cc == 0) continue;   /* Leading zeroes */
@@ -2180,12 +1608,16 @@


         if (overflow)
           {
-          while (XDIGIT(*ptr) != 0xff) ptr++;
+          while (ptr < ptrend && XDIGIT(*ptr) != 0xff) ptr++;
           *errorcodeptr = ERR34;
           }
-        else if (*ptr == CHAR_RIGHT_CURLY_BRACKET)
+        else if (ptr < ptrend && *ptr++ == CHAR_RIGHT_CURLY_BRACKET)
           {
-          if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73;
+          if (utf && c >= 0xd800 && c <= 0xdfff)
+            {
+            ptr--;
+            *errorcodeptr = ERR73;
+            }
           }


         /* If the sequence of hex digits does not end with '}', give an error.
@@ -2193,18 +1625,22 @@
         \x handling, but nowadays Perl gives an error, which seems much more
         sensible, so we do too. */


-        else *errorcodeptr = ERR67;
+        else
+          {
+          ptr--;
+          *errorcodeptr = ERR67;
+          }
         }   /* End of \x{} processing */


-      /* Read a single-byte hex-defined char (up to two hex digits after \x) */
+      /* Read a up to two hex digits after \x */


       else
         {
         c = 0;
-        if ((cc = XDIGIT(ptr[1])) == 0xff) break;  /* Not a hex digit */
+        if (ptr >= ptrend || (cc = XDIGIT(*ptr)) == 0xff) break;  /* Not a hex digit */
         ptr++;
         c = cc;
-        if ((cc = XDIGIT(ptr[1])) == 0xff) break;  /* Not a hex digit */
+        if (ptr >= ptrend || (cc = XDIGIT(*ptr)) == 0xff) break;  /* Not a hex digit */
         ptr++;
         c = (c << 4) | cc;
         }     /* End of \xdd handling */
@@ -2230,14 +1666,13 @@
 #else
     case CHAR_c:
 #endif
-
-    c = *(++ptr);
-    if (c >= CHAR_a && c <= CHAR_z) c = UPPER_CASE(c);
-    if (c == CHAR_NULL && ptr >= ptrend)
+    if (ptr >= ptrend)
       {
       *errorcodeptr = ERR2;
       break;
       }
+    c = *ptr;
+    if (c >= CHAR_a && c <= CHAR_z) c = UPPER_CASE(c);


     /* Handle \c in an ASCII/Unicode environment. */


@@ -2267,6 +1702,7 @@
       }
 #endif  /* EBCDIC */


+    ptr++;
     break;


     /* Any other alphanumeric following \ is an error. Perl gives an error only
@@ -2274,7 +1710,8 @@


     default:
     *errorcodeptr = ERR3;
-    break;
+    *ptrptr = ptr - 1;     /* Point to the character at fault */
+    return 0;
     }
   }


@@ -2282,17 +1719,17 @@
newline". PCRE does not support \N{name}. However, it does support
quantification such as \N{2,3}. */

-if (escape == ESC_N && ptr[1] == CHAR_LEFT_CURLY_BRACKET &&
-     !is_counted_repeat(ptr+2))
-  *errorcodeptr = ERR37;
+if (escape == ESC_N && ptr < ptrend && *ptr == CHAR_LEFT_CURLY_BRACKET &&
+    ptrend - ptr > 2)
+  {
+  PCRE2_SPTR p = ptr + 1;
+  if (!read_repeat_counts(&p, ptrend, NULL, NULL, errorcodeptr) &&
+       *errorcodeptr == 0)
+    *errorcodeptr = ERR37;
+  }


-/* If PCRE2_UCP is set, we change the values for \d etc. */
+/* Set the pointer to the next character before returning. */

-if ((options & PCRE2_UCP) != 0 && escape >= ESC_D && escape <= ESC_w)
- escape += (ESC_DU - ESC_D);
-
-/* Set the pointer to the final character before returning. */
-
*ptrptr = ptr;
*chptr = c;
return escape;
@@ -2307,8 +1744,8 @@

/* This function is called after \P or \p has been encountered, provided that
PCRE2 is compiled with support for UTF and Unicode properties. On entry, the
-contents of ptrptr are pointing at the P or p. On exit, it is left pointing at
-the final code unit of the escape sequence.
+contents of ptrptr are pointing after the P or p. On exit, it is left pointing
+after the final code unit of the escape sequence.

 Arguments:
   ptrptr         the pattern position pointer
@@ -2322,16 +1759,17 @@
 */


static BOOL
-get_ucp(PCRE2_SPTR *ptrptr, BOOL *negptr, unsigned int *ptypeptr,
- unsigned int *pdataptr, int *errorcodeptr, compile_block *cb)
+get_ucp(PCRE2_SPTR *ptrptr, BOOL *negptr, uint16_t *ptypeptr,
+ uint16_t *pdataptr, int *errorcodeptr, compile_block *cb)
{
-register PCRE2_UCHAR c;
-size_t i, bot, top;
+PCRE2_UCHAR c;
+PCRE2_SIZE i, bot, top;
PCRE2_SPTR ptr = *ptrptr;
PCRE2_UCHAR name[32];

+if (ptr >= cb->end_pattern) goto ERROR_RETURN;
+c = *ptr++;
*negptr = FALSE;
-c = *(++ptr);

/* \P or \p can be followed by a name in {}, optionally preceded by ^ for
negation. */
@@ -2338,7 +1776,8 @@

 if (c == CHAR_LEFT_CURLY_BRACKET)
   {
-  if (ptr[1] == CHAR_CIRCUMFLEX_ACCENT)
+  if (ptr >= cb->end_pattern) goto ERROR_RETURN;
+  if (*ptr == CHAR_CIRCUMFLEX_ACCENT)
     {
     *negptr = TRUE;
     ptr++;
@@ -2345,7 +1784,8 @@
     }
   for (i = 0; i < (int)(sizeof(name) / sizeof(PCRE2_UCHAR)) - 1; i++)
     {
-    c = *(++ptr);
+    if (ptr >= cb->end_pattern) goto ERROR_RETURN;
+    c = *ptr++;
     if (c == CHAR_NULL) goto ERROR_RETURN;
     if (c == CHAR_RIGHT_CURLY_BRACKET) break;
     name[i] = c;
@@ -2397,217 +1837,6 @@



 /*************************************************
-*         Read repeat counts                     *
-*************************************************/
-
-/* Read an item of the form {n,m} and return the values. This is called only
-after is_counted_repeat() has confirmed that a repeat-count quantifier exists,
-so the syntax is guaranteed to be correct, but we need to check the values.
-
-Arguments:
-  p              pointer to first char after '{'
-  minp           pointer to int for min
-  maxp           pointer to int for max
-                 returned as -1 if no max
-  errorcodeptr   points to error code variable
-
-Returns:         pointer to '}' on success;
-                 current ptr on error, with errorcodeptr set non-zero
-*/
-
-static PCRE2_SPTR
-read_repeat_counts(PCRE2_SPTR p, int *minp, int *maxp, int *errorcodeptr)
-{
-int min = 0;
-int max = -1;
-
-while (IS_DIGIT(*p))
-  {
-  min = min * 10 + (int)(*p++ - CHAR_0);
-  if (min > 65535)
-    {
-    *errorcodeptr = ERR5;
-    return p;
-    }
-  }
-
-if (*p == CHAR_RIGHT_CURLY_BRACKET) max = min; else
-  {
-  if (*(++p) != CHAR_RIGHT_CURLY_BRACKET)
-    {
-    max = 0;
-    while(IS_DIGIT(*p))
-      {
-      max = max * 10 + (int)(*p++ - CHAR_0);
-      if (max > 65535)
-        {
-        *errorcodeptr = ERR5;
-        return p;
-        }
-      }
-    if (max < min)
-      {
-      *errorcodeptr = ERR4;
-      return p;
-      }
-    }
-  }
-
-*minp = min;
-*maxp = max;
-return p;
-}
-
-
-
-/*************************************************
-*   Scan compiled regex for recursion reference  *
-*************************************************/
-
-/* This function scans through a compiled pattern until it finds an instance of
-OP_RECURSE.
-
-Arguments:
-  code        points to start of expression
-  utf         TRUE in UTF mode
-
-Returns:      pointer to the opcode for OP_RECURSE, or NULL if not found
-*/
-
-static PCRE2_SPTR
-find_recurse(PCRE2_SPTR code, BOOL utf)
-{
-for (;;)
-  {
-  register PCRE2_UCHAR c = *code;
-  if (c == OP_END) return NULL;
-  if (c == OP_RECURSE) return code;
-
-  /* XCLASS is used for classes that cannot be represented just by a bit map.
-  This includes negated single high-valued characters. CALLOUT_STR is used for
-  callouts with string arguments. In both cases the length in the table is
-  zero; the actual length is stored in the compiled code. */
-
-  if (c == OP_XCLASS) code += GET(code, 1);
-    else if (c == OP_CALLOUT_STR) code += GET(code, 1 + 2*LINK_SIZE);
-
-  /* Otherwise, we can get the item's length from the table, except that for
-  repeated character types, we have to test for \p and \P, which have an extra
-  two bytes of parameters, and for MARK/PRUNE/SKIP/THEN with an argument, we
-  must add in its length. */
-
-  else
-    {
-    switch(c)
-      {
-      case OP_TYPESTAR:
-      case OP_TYPEMINSTAR:
-      case OP_TYPEPLUS:
-      case OP_TYPEMINPLUS:
-      case OP_TYPEQUERY:
-      case OP_TYPEMINQUERY:
-      case OP_TYPEPOSSTAR:
-      case OP_TYPEPOSPLUS:
-      case OP_TYPEPOSQUERY:
-      if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2;
-      break;
-
-      case OP_TYPEPOSUPTO:
-      case OP_TYPEUPTO:
-      case OP_TYPEMINUPTO:
-      case OP_TYPEEXACT:
-      if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
-        code += 2;
-      break;
-
-      case OP_MARK:
-      case OP_PRUNE_ARG:
-      case OP_SKIP_ARG:
-      case OP_THEN_ARG:
-      code += code[1];
-      break;
-      }
-
-    /* Add in the fixed length from the table */
-
-    code += PRIV(OP_lengths)[c];
-
-    /* In UTF-8 and UTF-16 modes, opcodes that are followed by a character may
-    be followed by a multi-unit character. The length in the table is a
-    minimum, so we have to arrange to skip the extra units. */
-
-#ifdef MAYBE_UTF_MULTI
-    if (utf) switch(c)
-      {
-      case OP_CHAR:
-      case OP_CHARI:
-      case OP_NOT:
-      case OP_NOTI:
-      case OP_EXACT:
-      case OP_EXACTI:
-      case OP_NOTEXACT:
-      case OP_NOTEXACTI:
-      case OP_UPTO:
-      case OP_UPTOI:
-      case OP_NOTUPTO:
-      case OP_NOTUPTOI:
-      case OP_MINUPTO:
-      case OP_MINUPTOI:
-      case OP_NOTMINUPTO:
-      case OP_NOTMINUPTOI:
-      case OP_POSUPTO:
-      case OP_POSUPTOI:
-      case OP_NOTPOSUPTO:
-      case OP_NOTPOSUPTOI:
-      case OP_STAR:
-      case OP_STARI:
-      case OP_NOTSTAR:
-      case OP_NOTSTARI:
-      case OP_MINSTAR:
-      case OP_MINSTARI:
-      case OP_NOTMINSTAR:
-      case OP_NOTMINSTARI:
-      case OP_POSSTAR:
-      case OP_POSSTARI:
-      case OP_NOTPOSSTAR:
-      case OP_NOTPOSSTARI:
-      case OP_PLUS:
-      case OP_PLUSI:
-      case OP_NOTPLUS:
-      case OP_NOTPLUSI:
-      case OP_MINPLUS:
-      case OP_MINPLUSI:
-      case OP_NOTMINPLUS:
-      case OP_NOTMINPLUSI:
-      case OP_POSPLUS:
-      case OP_POSPLUSI:
-      case OP_NOTPOSPLUS:
-      case OP_NOTPOSPLUSI:
-      case OP_QUERY:
-      case OP_QUERYI:
-      case OP_NOTQUERY:
-      case OP_NOTQUERYI:
-      case OP_MINQUERY:
-      case OP_MINQUERYI:
-      case OP_NOTMINQUERY:
-      case OP_NOTMINQUERYI:
-      case OP_POSQUERY:
-      case OP_POSQUERYI:
-      case OP_NOTPOSQUERY:
-      case OP_NOTPOSQUERYI:
-      if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]);
-      break;
-      }
-#else
-    (void)(utf);  /* Keep compiler happy by referencing function argument */
-#endif  /* MAYBE_UTF_MULTI */
-    }
-  }
-}
-
-
-
-/*************************************************
 *           Check for POSIX class syntax         *
 *************************************************/


@@ -2645,7 +1874,8 @@
names.

 Arguments:
-  ptr      pointer to the initial [
+  ptr      pointer to the character after the initial [ (colon, dot, equals)
+  ptrend   pointer to the end of the pattern
   endptr   where to return a pointer to the terminating ':', '.', or '='


Returns: TRUE or FALSE
@@ -2652,18 +1882,20 @@
*/

 static BOOL
-check_posix_syntax(PCRE2_SPTR ptr, PCRE2_SPTR *endptr)
+check_posix_syntax(PCRE2_SPTR ptr, PCRE2_SPTR ptrend, PCRE2_SPTR *endptr)
 {
 PCRE2_UCHAR terminator;  /* Don't combine these lines; the Solaris cc */
-terminator = *(++ptr);   /* compiler warns about "non-constant" initializer. */
+terminator = *ptr++;     /* compiler warns about "non-constant" initializer. */


-for (++ptr; *ptr != CHAR_NULL; ptr++)
+for (; ptrend - ptr >= 2; ptr++)
   {
   if (*ptr == CHAR_BACKSLASH &&
       (ptr[1] == CHAR_RIGHT_SQUARE_BRACKET || ptr[1] == CHAR_BACKSLASH))
     ptr++;
+
   else if ((*ptr == CHAR_LEFT_SQUARE_BRACKET && ptr[1] == terminator) ||
             *ptr == CHAR_RIGHT_SQUARE_BRACKET) return FALSE;
+
   else if (*ptr == terminator && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET)
     {
     *endptr = ptr;
@@ -2694,7 +1926,7 @@
 check_posix_name(PCRE2_SPTR ptr, int len)
 {
 const char *pn = posix_names;
-register int yield = 0;
+int yield = 0;
 while (posix_name_lengths[yield] != 0)
   {
   if (len == posix_name_lengths[yield] &&
@@ -2707,646 +1939,806 @@




-#ifdef SUPPORT_UNICODE
 /*************************************************
-*           Get othercase range                  *
+*       Read a subpattern or VERB name           *
 *************************************************/


-/* This function is passed the start and end of a class range in UCT mode. It
-searches up the characters, looking for ranges of characters in the "other"
-case. Each call returns the next one, updating the start address. A character
-with multiple other cases is returned on its own with a special return value.
+/* This function is called from parse_regex() below whenever it needs to read
+the name of a subpattern or a (*VERB). The initial pointer must be to the
+character before the name. If that character is '*' we are reading a verb name.
+The pointer is updated to point after the name, for a VERB, or after tha name's
+terminator for a subpattern name. Returning both the offset and the name
+pointer is redundant information, but some callers use one and some the other,
+so it is simplest just to return both.

 Arguments:
-  cptr        points to starting character value; updated
-  d           end value
-  ocptr       where to put start of othercase range
-  odptr       where to put end of othercase range
+  ptrptr      points to the character pointer variable
+  ptrend      points to the end of the input string
+  terminator  the terminator of a subpattern name must be this
+  offsetptr   where to put the offset from the start of the pattern
+  nameptr     where to put a pointer to the name in the input
+  namelenptr  where to put the length of the name
+  errcodeptr  where to put an error code
+  cb          pointer to the compile data block


-Yield:        -1 when no more
-               0 when a range is returned
-              >0 the CASESET offset for char with multiple other cases
-                in this case, ocptr contains the original
+Returns:    TRUE if a name was read
+            FALSE otherwise, with error code set
 */


-static int
-get_othercase_range(uint32_t *cptr, uint32_t d, uint32_t *ocptr,
- uint32_t *odptr)
+static BOOL
+read_name(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, uint32_t terminator,
+ PCRE2_SIZE *offsetptr, PCRE2_SPTR *nameptr, uint32_t *namelenptr,
+ int *errorcodeptr, compile_block *cb)
{
-uint32_t c, othercase, next;
-unsigned int co;
+PCRE2_SPTR ptr = *ptrptr;
+BOOL is_verb = (*ptr == CHAR_ASTERISK);
+uint32_t namelen = 0;
+uint32_t ctype = is_verb? ctype_letter : ctype_word;

-/* Find the first character that has an other case. If it has multiple other
-cases, return its case offset value. */
+if (++ptr >= ptrend)
+  {
+  *errorcodeptr = is_verb? ERR60:  /* Verb not recognized or malformed */
+                           ERR62;  /* Subpattern name expected */
+  goto FAILED;
+  }


-for (c = *cptr; c <= d; c++)
+*nameptr = ptr;
+*offsetptr = (PCRE2_SIZE)(ptr - cb->start_pattern);
+
+if (IS_DIGIT(*ptr))
   {
-  if ((co = UCD_CASESET(c)) != 0)
+  *errorcodeptr = ERR44;   /* Group name must not start with digit */
+  goto FAILED;
+  }
+
+while (ptr < ptrend && MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype) != 0)
+  {
+  ptr++;
+  namelen++;
+  if (namelen > MAX_NAME_SIZE)
     {
-    *ocptr = c++;   /* Character that has the set */
-    *cptr = c;      /* Rest of input range */
-    return (int)co;
+    *errorcodeptr = ERR48;
+    goto FAILED;
     }
-  if ((othercase = UCD_OTHERCASE(c)) != c) break;
   }


-if (c > d) return -1; /* Reached end of range */
+/* Subpattern names must not be empty, and their terminator is checked here.
+(What follows a verb name is checked separately.) */

-/* Found a character that has a single other case. Search for the end of the
-range, which is either the end of the input range, or a character that has zero
-or more than one other cases. */
-
-*ocptr = othercase;
-next = othercase + 1;
-
-for (++c; c <= d; c++)
+if (!is_verb)
   {
-  if ((co = UCD_CASESET(c)) != 0 || UCD_OTHERCASE(c) != next) break;
-  next++;
+  if (namelen == 0)
+    {
+    *errorcodeptr = ERR62;   /* Subpattern name expected */
+    goto FAILED;
+    }
+  if (ptr >= ptrend || *ptr != (PCRE2_UCHAR)terminator)
+    {
+    *errorcodeptr = ERR42;
+    goto FAILED;
+    }
+  ptr++;
   }


-*odptr = next - 1;     /* End of othercase range */
-*cptr = c;             /* Rest of input range */
-return 0;
+*namelenptr = namelen;
+*ptrptr = ptr;
+return TRUE;
+
+FAILED:
+*ptrptr = ptr;
+return FALSE;
 }
-#endif  /* SUPPORT_UNICODE */




 /*************************************************
-*        Add a character or range to a class     *
+*          Manage callouts at start of cycle     *
 *************************************************/


-/* This function packages up the logic of adding a character or range of
-characters to a class. The character values in the arguments will be within the
-valid values for the current mode (8-bit, 16-bit, UTF, etc). This function is
-mutually recursive with the function immediately below.
+/* At the start of a new item in parse_regex() we are able to record the
+details of the previous item in a prior callout, and also to set up an
+automatic callout if enabled. Avoid having two adjacent automatic callouts,
+which would otherwise happen for items such as \Q that contribute nothing to
+the parsed pattern.

 Arguments:
-  classbits     the bit map for characters < 256
-  uchardptr     points to the pointer for extra data
-  options       the options word
-  cb            compile data
-  start         start of range character
-  end           end of range character
+  ptr              current pattern pointer
+  pcalloutptr      points to a pointer to previous callout, or NULL
+  options          the compiling options
+  parsed_pattern   the parsed pattern pointer
+  cb               compile block


-Returns:        the number of < 256 characters added
-                the pointer to extra data is updated
+Returns: possibly updated parsed_pattern pointer.
 */


-static unsigned int
-add_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, uint32_t options,
- compile_block *cb, uint32_t start, uint32_t end)
+static uint32_t *
+manage_callouts(PCRE2_SPTR ptr, uint32_t **pcalloutptr, uint32_t options,
+ uint32_t *parsed_pattern, compile_block *cb)
{
-uint32_t c;
-uint32_t classbits_end = (end <= 0xff ? end : 0xff);
-unsigned int n8 = 0;
+uint32_t *previous_callout = *pcalloutptr;

-/* If caseless matching is required, scan the range and process alternate
-cases. In Unicode, there are 8-bit characters that have alternate cases that
-are greater than 255 and vice-versa. Sometimes we can just extend the original
-range. */
+if (previous_callout != NULL) previous_callout[2] = ptr - cb->start_pattern -
+ (PCRE2_SIZE)previous_callout[1];

-if ((options & PCRE2_CASELESS) != 0)
+if ((options & PCRE2_AUTO_CALLOUT) == 0) previous_callout = NULL; else
   {
-#ifdef SUPPORT_UNICODE
-  if ((options & PCRE2_UTF) != 0)
+  if (previous_callout == NULL ||
+      previous_callout != parsed_pattern - 4 ||
+      previous_callout[3] != 255)
     {
-    int rc;
-    uint32_t oc, od;
+    previous_callout = parsed_pattern;  /* Set up new automatic callout */
+    parsed_pattern += 4;
+    previous_callout[0] = META_CALLOUT_NUMBER;
+    previous_callout[2] = 0;
+    previous_callout[3] = 255;
+    }
+  previous_callout[1] = (uint32_t)(ptr - cb->start_pattern);
+  }


-    options &= ~PCRE2_CASELESS;   /* Remove for recursive calls */
-    c = start;
+*pcalloutptr = previous_callout;
+return parsed_pattern;
+}


-    while ((rc = get_othercase_range(&c, end, &oc, &od)) >= 0)
-      {
-      /* Handle a single character that has more than one other case. */


-      if (rc > 0) n8 += add_list_to_class(classbits, uchardptr, options, cb,
-        PRIV(ucd_caseless_sets) + rc, oc);


-      /* Do nothing if the other case range is within the original range. */
+/*************************************************
+*      Parse regex and identify named groups     *
+*************************************************/


-      else if (oc >= start && od <= end) continue;
+/* This function is called first of all. It scans the pattern and does two
+things: (1) It identifies capturing groups and makes a table of named capturing
+groups so that information about them is fully available to both the compiling
+scans. (2) It writes a parsed version of the pattern with comments omitted and
+escapes processed into the parsed_pattern vector.


-      /* Extend the original range if there is overlap, noting that if oc < c, we
-      can't have od > end because a subrange is always shorter than the basic
-      range. Otherwise, use a recursive call to add the additional range. */
+Arguments:
+  ptr             points to the start of the pattern
+  options         compiling dynamic options (may change during the scan)
+  has_lookbehind  points to a boolean, set TRUE if a lookbehind is found
+  cb              pointer to the compile data block


-      else if (oc < start && od >= start - 1) start = oc; /* Extend downwards */
-      else if (od > end && oc <= end + 1)
-        {
-        end = od;       /* Extend upwards */
-        if (end > classbits_end) classbits_end = (end <= 0xff ? end : 0xff);
-        }
-      else n8 += add_to_class(classbits, uchardptr, options, cb, oc, od);
-      }
-    }
-  else
-#endif  /* SUPPORT_UNICODE */
+Returns:   zero on success or a non-zero error code, with the
+             error offset placed in the cb field
+*/


- /* Not UTF mode */
+/* A structure and some flags for dealing with nested groups. */

-  for (c = start; c <= classbits_end; c++)
-    {
-    SETBIT(classbits, cb->fcc[c]);
-    n8++;
-    }
-  }
+typedef struct nest_save {
+  uint16_t  nest_depth;
+  uint16_t  reset_group;
+  uint16_t  max_group;
+  uint16_t  flags;
+} nest_save;


-/* Now handle the original range. Adjust the final value according to the bit
-length - this means that the same lists of (e.g.) horizontal spaces can be used
-in all cases. */
+#define NSF_RESET      0x0001u
+#define NSF_EXTENDED   0x0002u
+#define NSF_DUPNAMES   0x0004u
+#define NSF_CONDASSERT 0x0008u


-if ((options & PCRE2_UTF) == 0 && end > MAX_NON_UTF_CHAR)
- end = MAX_NON_UTF_CHAR;
+/* States used for analyzing ranges in character classes. The two OK values
+must be last. */

-/* Use the bitmap for characters < 256. Otherwise use extra data.*/
+enum { RANGE_NO, RANGE_STARTED, RANGE_OK_ESCAPED, RANGE_OK_LITERAL };

-for (c = start; c <= classbits_end; c++)
- {
- /* Regardless of start, c will always be <= 255. */
- SETBIT(classbits, c);
- n8++;
+/* Only in 32-bit mode can there be literals > META_END. A macros encapsulates
+the storing of literal values in the parsed pattern. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 32
+#define PARSED_LITERAL(c, p) \
+ { \
+ if (c >= META_END) *p++ = META_BIGVALUE; \
+ *p++ = c; \
+ okquantifier = TRUE; \
}
+#else
+#define PARSED_LITERAL(c, p) *p++ = c; okquantifier = TRUE;
+#endif

-#ifdef SUPPORT_WIDE_CHARS
-if (start <= 0xff) start = 0xff + 1;
+/* Here's the actual function. */

-if (end >= start)
+static int parse_regex(PCRE2_SPTR ptr, uint32_t options, BOOL *has_lookbehind,
+  compile_block *cb)
+{
+uint32_t c;
+uint32_t delimiter;
+uint32_t namelen;
+uint32_t class_range_state;
+uint32_t *verblengthptr = NULL;     /* Value avoids compiler warning */
+uint32_t *previous_callout = NULL;
+uint32_t *parsed_pattern = cb->parsed_pattern;
+uint32_t meta_quantifier = 0;
+uint16_t nest_depth = 0;
+int after_manual_callout = 0;
+int expect_cond_assert = 0;
+int errorcode = 0;
+int escape;
+int i;
+BOOL inescq = FALSE;
+BOOL inverbname = FALSE;
+BOOL utf = (options & PCRE2_UTF) != 0;
+BOOL isdupname;
+BOOL negate_class;
+BOOL okquantifier = FALSE;
+PCRE2_SPTR name;
+PCRE2_SPTR ptrend = cb->end_pattern;
+named_group *ng;
+nest_save *top_nest = NULL;
+nest_save *end_nests = (nest_save *)(cb->start_workspace + cb->workspace_size);
+
+/* The size of the nest_save structure might not be a factor of the size of the
+workspace. Therefore we must round down end_nests so as to correctly avoid
+creating a nest_save that spans the end of the workspace. */
+
+end_nests = (nest_save *)((char *)end_nests -
+  ((cb->workspace_size * sizeof(PCRE2_UCHAR)) % sizeof(nest_save)));
+
+/* Now scan the pattern */
+
+*has_lookbehind = FALSE;
+
+while (ptr < ptrend)
   {
-  PCRE2_UCHAR *uchardata = *uchardptr;
+  int prev_expect_cond_assert;
+  uint32_t min_repeat, max_repeat;
+  uint32_t set, unset, *optset;
+  uint32_t terminator;
+  uint32_t prev_meta_quantifier;
+  BOOL prev_okquantifier;
+  PCRE2_SPTR tempptr;
+  PCRE2_SPTR thisptr;
+  PCRE2_SIZE offset;


-#ifdef SUPPORT_UNICODE
-  if ((options & PCRE2_UTF) != 0)
+  if (nest_depth > cb->cx->parens_nest_limit)
     {
-    if (start < end)
+    errorcode = ERR19;
+    goto FAILED;
+    }
+
+  /* Get next input character, save its position for callout handling. */
+
+  thisptr = ptr;
+  GETCHARINCTEST(c, ptr);
+
+  /* Copy quoted literals until \E, allowing for the possibility of automatic
+  callouts. */
+
+  if (inescq)
+    {
+    if (c == CHAR_BACKSLASH && ptr < ptrend && *ptr == CHAR_E)
       {
-      *uchardata++ = XCL_RANGE;
-      uchardata += PRIV(ord2utf)(start, uchardata);
-      uchardata += PRIV(ord2utf)(end, uchardata);
+      inescq = FALSE;
+      ptr++;   /* Skip E */
       }
-    else if (start == end)
+    else
       {
-      *uchardata++ = XCL_SINGLE;
-      uchardata += PRIV(ord2utf)(start, uchardata);
+      if (after_manual_callout-- <= 0)
+        parsed_pattern = manage_callouts(thisptr, &previous_callout, options,
+          parsed_pattern, cb);
+      PARSED_LITERAL(c, parsed_pattern);
       }
+    continue;  /* Next character */
     }
-  else
-#endif  /* SUPPORT_UNICODE */


- /* Without UTF support, character values are constrained by the bit length,
- and can only be > 256 for 16-bit and 32-bit libraries. */
+ /* If we are processing the "name" part of a (*VERB:NAME) item, all
+ characters up to the closing parenthesis are literals except when
+ PCRE2_ALT_VERBNAMES is set. That causes backslash interpretation, but only \Q
+ and \E and escaped characters are allowed (no character types such as \d). If
+ PCRE2_EXTENDED is also set, we must ignore white space and # comments. Do
+ this by not entering the special (*VERB:NAME) processing - they are then
+ picked up below. */

-#if PCRE2_CODE_UNIT_WIDTH == 8
-    {}
-#else
-  if (start < end)
+  if (inverbname &&
+       (
+        /* EITHER: not both options set */
+        ((options & (PCRE2_EXTENDED | PCRE2_ALT_VERBNAMES)) !=
+                    (PCRE2_EXTENDED | PCRE2_ALT_VERBNAMES)) ||
+        /* OR: character > 255 */
+        !MAX_255(c) ||
+        /* OR: not a # comment or white space */
+        (c != CHAR_NUMBER_SIGN && (cb->ctypes[c] & ctype_space) == 0)
+       ))
     {
-    *uchardata++ = XCL_RANGE;
-    *uchardata++ = start;
-    *uchardata++ = end;
-    }
-  else if (start == end)
-    {
-    *uchardata++ = XCL_SINGLE;
-    *uchardata++ = start;
-    }
-#endif
-  *uchardptr = uchardata;   /* Updata extra data pointer */
-  }
-#else
-  (void)uchardptr;          /* Avoid compiler warning */
-#endif /* SUPPORT_WIDE_CHARS */
+    PCRE2_SIZE verbnamelength;


-return n8;    /* Number of 8-bit characters */
-}
+    switch(c)
+      {
+      default:
+      PARSED_LITERAL(c, parsed_pattern);
+      break;


+      case CHAR_RIGHT_PARENTHESIS:
+      inverbname = FALSE;
+      verbnamelength = (PCRE2_SIZE)(parsed_pattern - verblengthptr - 1);
+      if (verbnamelength > MAX_MARK)
+        {
+        ptr--;
+        errorcode = ERR76;
+        goto FAILED;
+        }
+      *verblengthptr = (uint32_t)verbnamelength;
+      break;


+      case CHAR_BACKSLASH:
+      if ((options & PCRE2_ALT_VERBNAMES) != 0)
+        {
+        escape = PRIV(check_escape)(&ptr, ptrend, &c, &errorcode, options,
+          FALSE, cb);
+        if (errorcode != 0) goto FAILED;
+        }
+      else escape = 0;   /* Treat all as literal */


-/*************************************************
-*        Add a list of characters to a class     *
-*************************************************/
+      switch(escape)
+        {
+        case 0:
+        PARSED_LITERAL(c, parsed_pattern);
+        break;


-/* This function is used for adding a list of case-equivalent characters to a
-class, and also for adding a list of horizontal or vertical whitespace. If the
-list is in order (which it should be), ranges of characters are detected and
-handled appropriately. This function is mutually recursive with the function
-above.
+        case ESC_Q:
+        inescq = TRUE;
+        break;


-Arguments:
-  classbits     the bit map for characters < 256
-  uchardptr     points to the pointer for extra data
-  options       the options word
-  cb            contains pointers to tables etc.
-  p             points to row of 32-bit values, terminated by NOTACHAR
-  except        character to omit; this is used when adding lists of
-                  case-equivalent characters to avoid including the one we
-                  already know about
+        case ESC_E:           /* Ignore */
+        break;


-Returns:        the number of < 256 characters added
-                the pointer to extra data is updated
-*/
+        default:
+        errorcode = ERR40;    /* Invalid in verb name */
+        goto FAILED;
+        }
+      }
+    continue;   /* Next character in pattern */
+    }


-static unsigned int
-add_list_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, uint32_t options,
-  compile_block *cb, const uint32_t *p, unsigned int except)
-{
-unsigned int n8 = 0;
-while (p[0] < NOTACHAR)
-  {
-  unsigned int n = 0;
-  if (p[0] != except)
+  /* At the point we must process everything that must not change the
+  qualification state. This is mainly comments, but we handle \Q and \E here as
+  well, so that an item such as A\Q\E+ is treated as A+, as in Perl. An
+  isolated \E is ignored. */
+
+  if (c == CHAR_BACKSLASH && ptr < ptrend)
     {
-    while(p[n+1] == p[0] + n + 1) n++;
-    n8 += add_to_class(classbits, uchardptr, options, cb, p[0], p[n]);
+    if (*ptr == CHAR_Q || *ptr == CHAR_E)
+      {
+      inescq = *ptr == CHAR_Q;
+      ptr++;
+      continue;
+      }
     }
-  p += n + 1;
-  }
-return n8;
-}


+ /* Skip over whitespace and # comments in extended mode. */

+  if ((options & PCRE2_EXTENDED) != 0)
+    {
+    if (MAX_255(c) && (cb->ctypes[c] & ctype_space) != 0) continue;
+    if (c == CHAR_NUMBER_SIGN)
+      {
+      while (ptr < ptrend)
+        {
+        if (IS_NEWLINE(ptr))      /* For non-fixed-length newline cases, */
+          {                       /* IS_NEWLINE sets cb->nllen. */
+          ptr += cb->nllen;
+          break;
+          }
+        ptr++;
+#ifdef SUPPORT_UNICODE
+        if (utf) FORWARDCHAR(ptr);
+#endif
+        }
+      continue;  /* Next character in pattern */
+      }
+    }


-/*************************************************
-*    Add characters not in a list to a class     *
-*************************************************/
+  /* Skip over bracketed comments */


-/* This function is used for adding the complement of a list of horizontal or
-vertical whitespace to a class. The list must be in order.
+  if (c == CHAR_LEFT_PARENTHESIS && ptrend - ptr >= 2 &&
+      ptr[0] == CHAR_QUESTION_MARK && ptr[1] == CHAR_NUMBER_SIGN)
+    {
+    while (++ptr < ptrend && *ptr != CHAR_RIGHT_PARENTHESIS);
+    if (ptr >= ptrend)
+      {
+      errorcode = ERR18;  /* A special error for missing ) in a comment */
+      goto FAILED;        /* to make it easier to debug. */
+      }
+    ptr++;
+    continue;  /* Next character in pattern */
+    }


-Arguments:
-  classbits     the bit map for characters < 256
-  uchardptr     points to the pointer for extra data
-  options       the options word
-  cb            contains pointers to tables etc.
-  p             points to row of 32-bit values, terminated by NOTACHAR
+  /* If the next item is not a quantifier, fill in length of any previous
+  callout and create an auto callout if required. */


-Returns:        the number of < 256 characters added
-                the pointer to extra data is updated
-*/
+  if (c != CHAR_ASTERISK && c != CHAR_PLUS && c != CHAR_QUESTION_MARK &&
+       (c != CHAR_LEFT_CURLY_BRACKET ||
+         (tempptr = ptr,
+         !read_repeat_counts(&tempptr, ptrend, NULL, NULL, &errorcode))))
+    {
+    if (after_manual_callout-- <= 0)
+      parsed_pattern = manage_callouts(thisptr, &previous_callout, options,
+        parsed_pattern, cb);
+    }


-static unsigned int
-add_not_list_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr,
-  uint32_t options, compile_block *cb, const uint32_t *p)
-{
-BOOL utf = (options & PCRE2_UTF) != 0;
-unsigned int n8 = 0;
-if (p[0] > 0)
-  n8 += add_to_class(classbits, uchardptr, options, cb, 0, p[0] - 1);
-while (p[0] < NOTACHAR)
-  {
-  while (p[1] == p[0] + 1) p++;
-  n8 += add_to_class(classbits, uchardptr, options, cb, p[0] + 1,
-    (p[1] == NOTACHAR) ? (utf ? 0x10ffffu : 0xffffffffu) : p[1] - 1);
-  p++;
-  }
-return n8;
-}
+  /* Remember whether we are expecting a conditional assertion, and set the
+  default for this item. */


+ prev_expect_cond_assert = expect_cond_assert;
+ expect_cond_assert = 0;

+ /* Remember quantification status for the previous significant item, then set
+ default for this item. */

-/*************************************************
-*       Process (*VERB) name for escapes         *
-*************************************************/
+  prev_okquantifier = okquantifier;
+  prev_meta_quantifier = meta_quantifier;
+  okquantifier = FALSE;
+  meta_quantifier = 0;


-/* This function is called when the PCRE2_ALT_VERBNAMES option is set, to
-process the characters in a verb's name argument. It is called twice, once with
-codeptr == NULL, to find out the length of the processed name, and again to put
-the name into memory.
+ /* If the previous significant item was a quantifier, adjust the parsed code
+ if there is a following modifier. The base meta value is always followed by
+ the PLUS and QUERY values, in that order. We do this here rather than after
+ reading a quantifier so that intervening comments and /x whitespace can be
+ ignored without having to replicate code. */

-Arguments:
-  ptrptr        pointer to the input pointer
-  codeptr       pointer to the compiled code pointer
-  errorcodeptr  pointer to the error code
-  options       the options bits
-  utf           TRUE if processing UTF
-  cb            compile data block
+  if (prev_meta_quantifier != 0 && (c == CHAR_QUESTION_MARK || c == CHAR_PLUS))
+    {
+    parsed_pattern[(prev_meta_quantifier == META_MINMAX)? -3 : -1] =
+      prev_meta_quantifier + ((c == CHAR_QUESTION_MARK)?
+        0x00020000u : 0x00010000u);
+    continue;  /* Next character in pattern */
+    }


-Returns:        length of the processed name, or < 0 on error
-*/


-static int
-process_verb_name(PCRE2_SPTR *ptrptr, PCRE2_UCHAR **codeptr, int *errorcodeptr,
- uint32_t options, BOOL utf, compile_block *cb)
-{
-int32_t arglen = 0;
-BOOL inescq = FALSE;
-PCRE2_SPTR ptr = *ptrptr;
-PCRE2_UCHAR *code = (codeptr == NULL)? NULL : *codeptr;
+ /* Process the next item in the main part of a pattern. */

-for (; ptr < cb->end_pattern; ptr++)
-  {
-  uint32_t x = *ptr;
+  switch(c)
+    {
+    default:              /* Non-special character */
+    PARSED_LITERAL(c, parsed_pattern);
+    break;


- /* Skip over literals */

-  if (inescq)
-    {
-    if (x == CHAR_BACKSLASH && ptr[1] == CHAR_E)
+    /* ---- Escape sequence ---- */
+
+    case CHAR_BACKSLASH:
+    escape = PRIV(check_escape)(&ptr, ptrend, &c, &errorcode, options,
+      FALSE, cb);
+    if (errorcode != 0) goto FAILED;
+
+    /* The escape was a data character. */
+
+    if (escape == 0)
       {
-      inescq = FALSE;
-      ptr++;;
-      continue;
+      PARSED_LITERAL(c, parsed_pattern);
       }
-    }


-  else  /* Not a literal character */
-    {
-    if (x == CHAR_RIGHT_PARENTHESIS) break;
+    /* The escape was a back (or forward) reference. We keep the offset in
+    order to give a more useful diagnostic for a bad forward reference. For
+    references to groups numbered less than 10 we can't use more than two items
+    in parsed_pattern because they may be just two characters in the input (and
+    in a 64-bit world an offset may need two elements). So for them, the offset
+    of the first occurrent is held in a special vector. */


-    /* Skip over comments and whitespace in extended mode. */
-
-    if ((options & PCRE2_EXTENDED) != 0)
+    else if (escape < 0)
       {
-      PCRE2_SPTR wscptr = ptr;
-      while (MAX_255(x) && (cb->ctypes[x] & ctype_space) != 0) x = *(++ptr);
-      if (x == CHAR_NUMBER_SIGN)
+      offset = (PCRE2_SIZE)(ptr - cb->start_pattern - 1);
+      escape = -escape;
+      *parsed_pattern++ = META_BACKREF | (uint32_t)escape;
+      if (escape < 10)
         {
-        ptr++;
-        while (*ptr != CHAR_NULL || ptr < cb->end_pattern)
-          {
-          if (IS_NEWLINE(ptr))       /* For non-fixed-length newline cases, */
-            {                        /* IS_NEWLINE sets cb->nllen. */
-            ptr += cb->nllen;
-            break;
-            }
-          ptr++;
-#ifdef SUPPORT_UNICODE
-          if (utf) FORWARDCHAR(ptr);
-#endif
-          }
+        if (cb->small_ref_offset[escape] == PCRE2_UNSET)
+          cb->small_ref_offset[escape] = offset;
         }
-
-      /* If we have skipped any characters, restart the loop. */
-
-      if (ptr > wscptr)
+      else
         {
-        ptr--;
-        continue;
+        PUTOFFSET(offset, parsed_pattern);
         }
+      okquantifier = TRUE;
       }


-    /* Process escapes */
+    /* The escape was a character class such as \d etc. or other special
+    escape indicator such as \A or \X. Most of them generate just a single
+    parsed item, but \P and \p are followed by a 16-bit type and a 16-bit
+    value. They are supported only when Unicode is available. The type and
+    value are packed into a single 32-bit value so that the whole sequences
+    uses only two elements in the parsed_vector. This is because the same
+    coding is used if \d (for example) is turned into \p{Nd} when PCRE2_UCP is
+    set.


-    if (x == '\\')
+    There are also some cases where the escape sequence is followed by a name:
+    \k{name}, \k<name>, and \k'name' are backreferences by name, and \g<name>
+    and \g'name' are subroutine calls by name; \g{name} is a synonym for
+    \k{name}. Note that \g<number> and \g'number' are handled by check_escape()
+    and returned as a negative value (handled above). A name is coded as an
+    offset into the pattern and a length. */
+
+    else switch (escape)
       {
-      int rc;
-      *errorcodeptr = 0;
-      rc = PRIV(check_escape)(&ptr, cb->end_pattern, &x, errorcodeptr, options,
-        FALSE, cb);
-      *ptrptr = ptr;   /* For possible error */
-      if (*errorcodeptr != 0) return -1;
-      if (rc != 0)
+      case ESC_C:
+#ifdef NEVER_BACKSLASH_C
+      errorcode = ERR85;
+      goto FAILED;
+#else
+      if ((options & PCRE2_NEVER_BACKSLASH_C) != 0)
         {
-        if (rc == ESC_Q)
+        errorcode = ERR83;
+        goto FAILED;
+        }
+#endif
+      okquantifier = TRUE;
+      *parsed_pattern++ = META_ESCAPE + escape;
+      break;
+
+      case ESC_X:
+#ifndef SUPPORT_UNICODE
+      errorcode = ERR45;   /* Supported only with Unicode support */
+      goto FAILED;
+#endif
+      case ESC_H:
+      case ESC_h:
+      case ESC_N:
+      case ESC_R:
+      case ESC_V:
+      case ESC_v:
+      okquantifier = TRUE;
+      *parsed_pattern++ = META_ESCAPE + escape;
+      break;
+
+      default:  /* \A, \B, \b, \G, \K, \Z, \z cannot be quantified. */
+      *parsed_pattern++ = META_ESCAPE + escape;
+      break;
+
+      /* Escapes that change in UCP mode. Note that PCRE2_UCP will never be set
+      without Unicode support because it is checked when pcre2_compile() is
+      called. */
+
+      case ESC_d:
+      case ESC_D:
+      case ESC_s:
+      case ESC_S:
+      case ESC_w:
+      case ESC_W:
+      okquantifier = TRUE;
+      if ((options & PCRE2_UCP) == 0)
+        {
+        *parsed_pattern++ = META_ESCAPE + escape;
+        }
+      else
+        {
+        *parsed_pattern++ = META_ESCAPE +
+          ((escape == ESC_d || escape == ESC_s || escape == ESC_w)?
+            ESC_p : ESC_P);
+        switch(escape)
           {
-          inescq = TRUE;
-          continue;
+          case ESC_d:
+          case ESC_D:
+          *parsed_pattern++ = (PT_PC << 16) | ucp_Nd;
+          break;
+
+          case ESC_s:
+          case ESC_S:
+          *parsed_pattern++ = PT_SPACE << 16;
+          break;
+
+          case ESC_w:
+          case ESC_W:
+          *parsed_pattern++ = PT_WORD << 16;
+          break;
           }
-        if (rc == ESC_E) continue;
-        *errorcodeptr = ERR40;
-        return -1;
         }
-      }
-    }
+      break;


-  /* We have the next character in the name. */
+      /* Unicode property matching */


+      case ESC_P:
+      case ESC_p:
 #ifdef SUPPORT_UNICODE
-  if (utf)
-    {
-    if (code == NULL)   /* Just want the length */
-      {
-#if PCRE2_CODE_UNIT_WIDTH == 8
-      int i;
-      for (i = 0; i < PRIV(utf8_table1_size); i++)
-        if ((int)x <= PRIV(utf8_table1)[i]) break;
-      arglen += i;
-#elif PCRE2_CODE_UNIT_WIDTH == 16
-      if (x > 0xffff) arglen++;
+        {
+        BOOL negated;
+        uint16_t ptype = 0, pdata = 0;
+        if (!get_ucp(&ptr, &negated, &ptype, &pdata, &errorcode, cb))
+          goto FAILED;
+        if (negated) escape = (escape == ESC_P)? ESC_p : ESC_P;
+        *parsed_pattern++ = META_ESCAPE + escape;
+        *parsed_pattern++ = (ptype << 16) | pdata;
+        okquantifier = TRUE;
+        }
+#else
+      errorcode = ERR45;
+      goto FAILED;
 #endif
-      }
-    else
-      {
-      PCRE2_UCHAR cbuff[8];
-      x = PRIV(ord2utf)(x, cbuff);
-      memcpy(code, cbuff, CU2BYTES(x));
-      code += x;
-      }
-    }
-  else
-#endif  /* SUPPORT_UNICODE */
+      break;  /* End \P and \p */


-  /* Not UTF */
-    {
-    if (code != NULL) *code++ = (PCRE2_UCHAR)x;
-    }
+      /* When \g is used with quotes or angle brackets as delimiters, it is a
+      numerical or named subroutine call, and control comes here. When used
+      with brace delimiters it is a numberical back reference and does not come
+      here because check_escape() returns it directly as a reference. \k is
+      always a named back reference. */


-  arglen++;
+      case ESC_g:
+      case ESC_k:
+      if (ptr >= ptrend || (*ptr != CHAR_LEFT_CURLY_BRACKET &&
+          *ptr != CHAR_LESS_THAN_SIGN && *ptr != CHAR_APOSTROPHE))
+        {
+        errorcode = (escape == ESC_g)? ERR57 : ERR69;
+        goto FAILED;
+        }
+      terminator = (*ptr == CHAR_LESS_THAN_SIGN)?
+        CHAR_GREATER_THAN_SIGN : (*ptr == CHAR_APOSTROPHE)?
+        CHAR_APOSTROPHE : CHAR_RIGHT_CURLY_BRACKET;


-  if ((unsigned int)arglen > MAX_MARK)
-    {
-    *errorcodeptr = ERR76;
-    *ptrptr = ptr;
-    return -1;
-    }
-  }
+      /* For a non-braced \g, check for a numerical recursion. */


-/* Update the pointers before returning. */
+      if (escape == ESC_g && terminator != CHAR_RIGHT_CURLY_BRACKET)
+        {
+        PCRE2_SPTR p = ptr + 1;


-*ptrptr = ptr;
-if (codeptr != NULL) *codeptr = code;
-return arglen;
-}
+        if (read_number(&p, ptrend, cb->bracount, MAX_GROUP_NUMBER, ERR61, &i,
+            &errorcode))
+          {
+          if (*p != terminator)
+            {
+            errorcode = ERR57;
+            goto FAILED;
+            }
+          ptr = p;
+          goto SET_RECURSION;
+          }
+        if (errorcode != 0) goto FAILED;
+        }


+      /* Not a numerical recursion */


+      if (!read_name(&ptr, ptrend, terminator, &offset, &name, &namelen,
+          &errorcode, cb)) goto FAILED;


-/*************************************************
-*          Macro for the next two functions      *
-*************************************************/
+      /* \k and \g when used with braces are back references, whereas \g used
+      with quotes or angle brackets is a recursion */


-/* Both scan_for_captures() and compile_branch() use this macro to generate a
-fragment of code that reads the characters of a name and sets its length
-(checking for not being too long). Count the characters dynamically, to avoid
-the possibility of integer overflow. The same macro is used for reading *VERB
-names. */
+      *parsed_pattern++ =
+        (escape == ESC_k || terminator == CHAR_RIGHT_CURLY_BRACKET)?
+          META_BACKREF_BYNAME : META_RECURSE_BYNAME;
+      *parsed_pattern++ = namelen;


-#define READ_NAME(ctype, errno, errset)                      \
-  namelen = 0;                                               \
-  while (MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype) != 0)   \
-    {                                                        \
-    ptr++;                                                   \
-    namelen++;                                               \
-    if (namelen > MAX_NAME_SIZE)                             \
-      {                                                      \
-      errset = errno;                                        \
-      goto FAILED;                                           \
-      }                                                      \
-    }
+      PUTOFFSET(offset, parsed_pattern);
+      okquantifier = TRUE;
+      break;
+      }
+    break;    /* End escape sequence processing */



+    /* ---- Single-character special items ---- */


-/*************************************************
-*      Scan regex to identify named groups       *
-*************************************************/
+    case CHAR_CIRCUMFLEX_ACCENT:
+    *parsed_pattern++ = META_CIRCUMFLEX;
+    break;


-/* This function is called first of all, to scan for named capturing groups so
-that information about them is fully available to both the compiling scans.
-It skips over everything except parenthesized items.
+    case CHAR_DOLLAR_SIGN:
+    *parsed_pattern++ = META_DOLLAR;
+    break;


-Arguments:
-  ptrptr   points to pointer to the start of the pattern
-  options  compiling dynamic options
-  cb       pointer to the compile data block
+    case CHAR_DOT:
+    *parsed_pattern++ = META_DOT;
+    okquantifier = TRUE;
+    break;


-Returns: zero on success or a non-zero error code, with pointer updated
-*/

-typedef struct nest_save {
-  uint16_t  nest_depth;
-  uint16_t  reset_group;
-  uint16_t  max_group;
-  uint16_t  flags;
-} nest_save;
+    /* ---- Single-character quantifiers ---- */


-#define NSF_RESET    0x0001u
-#define NSF_EXTENDED 0x0002u
-#define NSF_DUPNAMES 0x0004u
+    case CHAR_ASTERISK:
+    meta_quantifier = META_ASTERISK;
+    goto CHECK_QUANTIFIER;


-static int scan_for_captures(PCRE2_SPTR *ptrptr, uint32_t options,
-  compile_block *cb)
-{
-uint32_t c;
-uint32_t delimiter;
-uint32_t set, unset, *optset;
-uint32_t skiptoket = 0;
-uint16_t nest_depth = 0;
-int errorcode = 0;
-int escape;
-int namelen;
-int i;
-BOOL inescq = FALSE;
-BOOL isdupname;
-BOOL utf = (options & PCRE2_UTF) != 0;
-BOOL negate_class;
-PCRE2_SPTR name;
-PCRE2_SPTR start;
-PCRE2_SPTR ptr = *ptrptr;
-named_group *ng;
-nest_save *top_nest = NULL;
-nest_save *end_nests = (nest_save *)(cb->start_workspace + cb->workspace_size);
+    case CHAR_PLUS:
+    meta_quantifier = META_PLUS;
+    goto CHECK_QUANTIFIER;


-/* The size of the nest_save structure might not be a factor of the size of the
-workspace. Therefore we must round down end_nests so as to correctly avoid
-creating a nest_save that spans the end of the workspace. */
+    case CHAR_QUESTION_MARK:
+    meta_quantifier = META_QUERY;
+    goto CHECK_QUANTIFIER;


-end_nests = (nest_save *)((char *)end_nests -
- ((cb->workspace_size * sizeof(PCRE2_UCHAR)) % sizeof(nest_save)));

-/* Now scan the pattern */
+    /* ---- Potential {n,m} quantifier ---- */


-for (; ptr < cb->end_pattern; ptr++)
-  {
-  c = *ptr;
+    case CHAR_LEFT_CURLY_BRACKET:
+    if (!read_repeat_counts(&ptr, ptrend, &min_repeat, &max_repeat,
+        &errorcode))
+      {
+      if (errorcode != 0) goto FAILED;     /* Error in quantifier. */
+      PARSED_LITERAL(c, parsed_pattern);   /* Not a quantifier */
+      break;                               /* No more quantifier processing */
+      }
+    meta_quantifier = META_MINMAX;
+    /* Fall through */


- /* Parenthesized groups set skiptoket when all following characters up to the
- next closing parenthesis must be ignored. The parenthesis itself must be
- processed (to end the nested parenthesized item). */

-  if (skiptoket != 0)
-    {
-    if (c != CHAR_RIGHT_PARENTHESIS) continue;
-    skiptoket = 0;
-    }
+    /* ---- Quantifier post-processing ---- */


-  /* Skip over literals */
+    /* Check that a quantifier is allowed after the previous item. */


-  if (inescq)
-    {
-    if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E)
+    CHECK_QUANTIFIER:
+    if (!prev_okquantifier)
       {
-      inescq = FALSE;
-      ptr++;
+      errorcode = ERR9;
+      goto FAILED_BACK;
       }
-    continue;
-    }


-  /* Skip over # comments and whitespace in extended mode. */
+    /* Now we can put the quantifier into the parsed pattern vector. At this
+    stage, we have only the basic quantifier. The check for a following + or ?
+    modifier happens at the top of the loop, after any intervening comments
+    have been removed. */


-  if ((options & PCRE2_EXTENDED) != 0)
-    {
-    PCRE2_SPTR wscptr = ptr;
-    while (MAX_255(c) && (cb->ctypes[c] & ctype_space) != 0) c = *(++ptr);
-    if (c == CHAR_NUMBER_SIGN)
+    *parsed_pattern++ = meta_quantifier;
+    if (c == CHAR_LEFT_CURLY_BRACKET)
       {
-      ptr++;
-      while (ptr < cb->end_pattern)
-        {
-        if (IS_NEWLINE(ptr))         /* For non-fixed-length newline cases, */
-          {                          /* IS_NEWLINE sets cb->nllen. */
-          ptr += cb->nllen;
-          break;
-          }
-        ptr++;
-#ifdef SUPPORT_UNICODE
-        if (utf) FORWARDCHAR(ptr);
-#endif
-        }
+      *parsed_pattern++ = min_repeat;
+      *parsed_pattern++ = max_repeat;
       }
+    break;


-    /* If we skipped any characters, restart the loop. Otherwise, we didn't see
-    a comment. */


-    if (ptr > wscptr)
-      {
-      ptr--;
-      continue;
-      }
-    }
+    /* ---- Character class ---- */


-  /* Process the next pattern item. */
+    case CHAR_LEFT_SQUARE_BRACKET:
+    okquantifier = TRUE;


-  switch(c)
-    {
-    default:              /* Most characters are just skipped */
-    break;
+    /* In another (POSIX) regex library, the ugly syntax [[:<:]] and [[:>:]] is
+    used for "start of word" and "end of word". As these are otherwise illegal
+    sequences, we don't break anything by recognizing them. They are replaced
+    by \b(?=\w) and \b(?<=\w) respectively. Sequences like [a[:<:]] are
+    erroneous and are handled by the normal code below. */


-    /* Skip escapes except for \Q */
+    if (ptrend - ptr >= 6 &&
+         (PRIV(strncmp_c8)(ptr, STRING_WEIRD_STARTWORD, 6) == 0 ||
+          PRIV(strncmp_c8)(ptr, STRING_WEIRD_ENDWORD, 6) == 0))
+      {
+      *parsed_pattern++ = META_ESCAPE + ESC_b;


-    case CHAR_BACKSLASH:
-    errorcode = 0;
-    escape = PRIV(check_escape)(&ptr, cb->end_pattern, &c, &errorcode, options,
-      FALSE, cb);
-    if (errorcode != 0) goto FAILED;
-    if (escape == ESC_Q) inescq = TRUE;
-    break;
+      if (ptr[2] == CHAR_LESS_THAN_SIGN)
+        {
+        *parsed_pattern++ = META_LOOKAHEAD;
+        }
+      else
+        {
+        *parsed_pattern++ = META_LOOKBEHIND;
+        *has_lookbehind = TRUE;


-    /* Skip a character class. The syntax is complicated so we have to
-    replicate some of what happens when a class is processed for real. */
+        /* The offset is used only for the "non-fixed length" error; this won't
+        occur here, so just store zero. */


-    case CHAR_LEFT_SQUARE_BRACKET:
-    if (PRIV(strncmp_c8)(ptr+1, STRING_WEIRD_STARTWORD, 6) == 0 ||
-        PRIV(strncmp_c8)(ptr+1, STRING_WEIRD_ENDWORD, 6) == 0)
-      {
+        PUTOFFSET((PCRE2_SIZE)0, parsed_pattern);
+        }
+
+      if ((options & PCRE2_UCP) == 0)
+        *parsed_pattern++ = META_ESCAPE + ESC_w;
+      else
+        {
+        *parsed_pattern++ = META_ESCAPE + ESC_p;
+        *parsed_pattern++ = PT_WORD << 16;
+        }
+      *parsed_pattern++ = META_KET;
       ptr += 6;
       break;
       }


-    /* If the first character is '^', set the negation flag (not actually used
-    here, except to recognize only one ^) and skip it. If the first few
-    characters (either before or after ^) are \Q\E or \E we skip them too. This
-    makes for compatibility with Perl. */
+    /* PCRE supports POSIX class stuff inside a class. Perl gives an error if
+    they are encountered at the top level, so we'll do that too. */


+    if (ptr < ptrend && (*ptr == CHAR_COLON || *ptr == CHAR_DOT ||
+         *ptr == CHAR_EQUALS_SIGN) &&
+        check_posix_syntax(ptr, ptrend, &tempptr))
+      {
+      errorcode = (*ptr-- == CHAR_COLON)? ERR12 : ERR13;
+      goto FAILED;
+      }
+
+    /* Process a regular character class. If the first character is '^', set
+    the negation flag. If the first few characters (either before or after ^)
+    are \Q\E or \E we skip them too. This makes for compatibility with Perl. */
+
     negate_class = FALSE;
-    for (;;)
+    while (ptr < ptrend)
       {
-      c = *(++ptr);   /* First character in class */
+      GETCHARINCTEST(c, ptr);
       if (c == CHAR_BACKSLASH)
         {
-        if (ptr[1] == CHAR_E)
-          ptr++;
-        else if (PRIV(strncmp_c8)(ptr + 1, STR_Q STR_BACKSLASH STR_E, 3) == 0)
+        if (ptr < ptrend && *ptr == CHAR_E) ptr++;
+        else if (ptrend - ptr >= 3 &&
+             PRIV(strncmp_c8)(ptr, STR_Q STR_BACKSLASH STR_E, 3) == 0)
           ptr += 3;
         else
           break;
@@ -3356,116 +2748,438 @@
       else break;
       }


+    /* Now the real contents of the class; c has the first "real" character.
+    Empty classes are permitted only if the option is set. */
+
     if (c == CHAR_RIGHT_SQUARE_BRACKET &&
         (cb->external_options & PCRE2_ALLOW_EMPTY_CLASS) != 0)
-      break;
+      {
+      *parsed_pattern++ = negate_class? META_CLASS_EMPTY_NOT : META_CLASS_EMPTY;
+      break;  /* End of class processing */
+      }


+    /* Process a non-empty class. */
+
+    *parsed_pattern++ = negate_class? META_CLASS_NOT : META_CLASS;
+    class_range_state = RANGE_NO;
+
+    /* In an EBCDIC environment, Perl treats alphabetic ranges specially
+    because there are holes in the encoding, and simply using the range A-Z
+    (for example) would include the characters in the holes. This applies only
+    to ranges where both values are literal; [\xC1-\xE9] is different to [A-Z]
+    in this respect. In order to accommodate this, we keep track of whether
+    character values are literal or not, and a state variable for handling
+    ranges. */
+
     /* Loop for the contents of the class */


     for (;;)
       {
-      PCRE2_SPTR tempptr;
+      BOOL char_is_literal = TRUE;


-      if (c == CHAR_NULL && ptr >= cb->end_pattern)
-        {
-        errorcode = ERR6;  /* Missing terminating ']' */
-        goto FAILED;
-        }
-
-#ifdef SUPPORT_UNICODE
-      if (utf && HAS_EXTRALEN(c))
-        {                           /* Braces are required because the */
-        GETCHARLEN(c, ptr, ptr);    /* macro generates multiple statements */
-        }
-#endif
-
       /* Inside \Q...\E everything is literal except \E */


       if (inescq)
         {
-        if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E)  /* If we are at \E */
+        if (c == CHAR_BACKSLASH && ptr < ptrend && *ptr == CHAR_E)
           {
           inescq = FALSE;                   /* Reset literal state */
           ptr++;                            /* Skip the 'E' */
+          goto CLASS_CONTINUE;
           }
-        goto CONTINUE_CLASS;
+        goto CLASS_LITERAL;
         }


-      /* Skip POSIX class names. */
+      /* Handle POSIX class names. Perl allows a negation extension of the
+      form [:^name:]. A square bracket that doesn't match the syntax is
+      treated as a literal. We also recognize the POSIX constructions
+      [.ch.] and [=ch=] ("collating elements") and fault them, as Perl
+      5.6 and 5.8 do. */
+
       if (c == CHAR_LEFT_SQUARE_BRACKET &&
-          (ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT ||
-           ptr[1] == CHAR_EQUALS_SIGN) && check_posix_syntax(ptr, &tempptr))
+          ptrend - ptr >= 3 &&
+          (*ptr == CHAR_COLON || *ptr == CHAR_DOT ||
+           *ptr == CHAR_EQUALS_SIGN) &&
+          check_posix_syntax(ptr, ptrend, &tempptr))
         {
-        ptr = tempptr + 1;
+        BOOL posix_negate = FALSE;
+        int posix_class;
+
+        /* Perl treats a hyphen before a POSIX class as a literal, not the
+        start of a range. However, it gives a warning in its warning mode. PCRE
+        does not have a warning mode, so we give an error, because this is
+        likely an error on the user's part. */
+
+        if (class_range_state == RANGE_STARTED)
+          {
+          errorcode = ERR50;
+          goto FAILED;
+          }
+
+        if (*ptr != CHAR_COLON)
+          {
+          errorcode = ERR13;
+          goto FAILED_BACK;
+          }
+
+        if (*(++ptr) == CHAR_CIRCUMFLEX_ACCENT)
+          {
+          posix_negate = TRUE;
+          ptr++;
+          }
+
+        posix_class = check_posix_name(ptr, (int)(tempptr - ptr));
+        if (posix_class < 0)
+          {
+          errorcode = ERR30;
+          goto FAILED;
+          }
+        ptr = tempptr + 2;
+
+        /* When PCRE2_UCP is set, some of the POSIX classes are converted to
+        use Unicode properties \p or \P or, in one case, \h or \H. The
+        substitutes table has two values per class, containing the type and
+        value of a \p or \P item. The special cases are specified with a
+        negative type: a non-zero value causes \h or \H to be used, and a zero
+        value falls through to behave like a non-UCP POSIX class. */
+
+#ifdef SUPPORT_UNICODE
+        if ((options & PCRE2_UCP) != 0)
+          {
+          int ptype = posix_substitutes[2*posix_class];
+          int pvalue = posix_substitutes[2*posix_class + 1];
+          if (ptype >= 0)
+            {
+            *parsed_pattern++ = META_ESCAPE + (posix_negate? ESC_P : ESC_p);
+            *parsed_pattern++ = (ptype << 16) | pvalue;
+            goto CLASS_CONTINUE;
+            }
+
+          if (pvalue != 0)
+            {
+            *parsed_pattern++ = META_ESCAPE + (posix_negate? ESC_H : ESC_h);
+            goto CLASS_CONTINUE;
+            }
+
+          /* Fall through */
+          }
+#endif  /* SUPPORT_UNICODE */
+
+        /* Non-UCP POSIX class */
+
+        *parsed_pattern++ = posix_negate? META_POSIX_NEG : META_POSIX;
+        *parsed_pattern++ = posix_class;
         }
-      else if (c == CHAR_BACKSLASH)
+
+      /* Handle potential start of range */
+
+      else if (c == CHAR_MINUS && class_range_state >= RANGE_OK_ESCAPED)
         {
-        errorcode = 0;
-        escape = PRIV(check_escape)(&ptr, cb->end_pattern, &c, &errorcode,
+        *parsed_pattern++ = (class_range_state == RANGE_OK_LITERAL)?
+          META_RANGE_LITERAL : META_RANGE_ESCAPED;
+        class_range_state = RANGE_STARTED;
+        }
+
+      /* Handle a literal character */
+
+      else if (c != CHAR_BACKSLASH)
+        {
+        CLASS_LITERAL:
+        if (class_range_state == RANGE_STARTED)
+          {
+          if (c == parsed_pattern[-2])       /* Optimize one-char range */
+            parsed_pattern--;
+          else if (parsed_pattern[-2] > c)   /* Check range is in order */
+            {
+            errorcode = ERR8;
+            goto FAILED_BACK;
+            }
+          else
+            {
+            if (!char_is_literal && parsed_pattern[-1] == META_RANGE_LITERAL)
+              parsed_pattern[-1] = META_RANGE_ESCAPED;
+            PARSED_LITERAL(c, parsed_pattern);
+            }
+          class_range_state = RANGE_NO;
+          }
+        else  /* Potential start of range */
+          {
+          class_range_state = char_is_literal?
+            RANGE_OK_LITERAL : RANGE_OK_ESCAPED;
+          PARSED_LITERAL(c, parsed_pattern);
+          }
+        }
+
+      /* Handle escapes in a class */
+
+      else
+        {
+        escape = PRIV(check_escape)(&ptr, ptrend, &c, &errorcode,
           options, TRUE, cb);
+
         if (errorcode != 0) goto FAILED;
-        if (escape == ESC_Q) inescq = TRUE;
+        if (escape == 0)  /* Escaped character code point is in c */
+          {
+          char_is_literal = FALSE;
+          goto CLASS_LITERAL;
+          }
+
+        /* These three escapes do not alter the class range state. */
+
+        if (escape == ESC_b)
+          {
+          c = CHAR_BS;   /* \b is backspace in a class */
+          char_is_literal = FALSE;
+          goto CLASS_LITERAL;
+          }
+
+        else if (escape == ESC_Q)
+          {
+          inescq = TRUE;  /* Enter literal mode */
+          goto CLASS_CONTINUE;
+          }
+
+        else if (escape == ESC_E)  /* Ignore orphan \E */
+          goto CLASS_CONTINUE;
+
+        /* The second part of a range can be a single-character escape
+        sequence (detected above), but not any of the other escapes. Perl
+        treats a hyphen as a literal in such circumstances. However, in Perl's
+        warning mode, a warning is given, so PCRE now faults it, as it is
+        almost certainly a mistake on the user's part. */
+
+        if (class_range_state == RANGE_STARTED)
+          {
+          errorcode = ERR50;
+          goto FAILED;
+          }
+
+        /* Of the remaining escapes, only those that define characters are
+        allowed in a class. None may start a range. */
+
+        class_range_state = RANGE_NO;
+        switch(escape)
+          {
+          case ESC_N:
+          errorcode = ERR71;  /* Not supported in a class */
+          goto FAILED;
+
+          case ESC_H:
+          case ESC_h:
+          case ESC_V:
+          case ESC_v:
+          *parsed_pattern++ = META_ESCAPE + escape;
+          break;
+
+          /* These escapes are converted to Unicode property tests when
+          PCRE2_UCP is set. */
+
+          case ESC_d:
+          case ESC_D:
+          case ESC_s:
+          case ESC_S:
+          case ESC_w:
+          case ESC_W:
+          if ((options & PCRE2_UCP) == 0)
+            {
+            *parsed_pattern++ = META_ESCAPE + escape;
+            }
+          else
+            {
+            *parsed_pattern++ = META_ESCAPE +
+              ((escape == ESC_d || escape == ESC_s || escape == ESC_w)?
+                ESC_p : ESC_P);
+            switch(escape)
+              {
+              case ESC_d:
+              case ESC_D:
+              *parsed_pattern++ = (PT_PC << 16) | ucp_Nd;
+              break;
+
+              case ESC_s:
+              case ESC_S:
+              *parsed_pattern++ = PT_SPACE << 16;
+              break;
+
+              case ESC_w:
+              case ESC_W:
+              *parsed_pattern++ = PT_WORD << 16;
+              break;
+              }
+            }
+          break;
+
+          /* Explicit Unicode property matching */
+
+          case ESC_P:
+          case ESC_p:
+#ifdef SUPPORT_UNICODE
+            {
+            BOOL negated;
+            uint16_t ptype = 0, pdata = 0;
+            if (!get_ucp(&ptr, &negated, &ptype, &pdata, &errorcode, cb))
+              goto FAILED;
+            if (negated) escape = (escape == ESC_P)? ESC_p : ESC_P;
+            *parsed_pattern++ = META_ESCAPE + escape;
+            *parsed_pattern++ = (ptype << 16) | pdata;
+            }
+#else
+          errorcode = ERR45;
+          goto FAILED;
+#endif
+          break;  /* End \P and \p */
+
+          default:    /* All others are not allowed in a class */
+          errorcode = ERR7;
+          goto FAILED_BACK;
+          }
         }


-      CONTINUE_CLASS:
-      c = *(++ptr);
+      /* Proceed to next thing in the class. */
+
+      CLASS_CONTINUE:
+      if (ptr >= ptrend)
+        {
+        errorcode = ERR6;  /* Missing terminating ']' */
+        goto FAILED;
+        }
+      GETCHARINCTEST(c, ptr);
       if (c == CHAR_RIGHT_SQUARE_BRACKET && !inescq) break;
       }     /* End of class-processing loop */
-    break;


-    /* This is the real work of this function - handling parentheses. */
+    if (class_range_state == RANGE_STARTED)
+      {
+      parsed_pattern[-1] = CHAR_MINUS;
+      class_range_state = RANGE_NO;
+      }


+    *parsed_pattern++ = META_CLASS_END;
+    break;  /* End of character class */
+
+
+    /* ---- Opening parenthesis ---- */
+
     case CHAR_LEFT_PARENTHESIS:
-    nest_depth++;
+    if (ptr >= ptrend) goto UNCLOSED_PARENTHESIS;


-    if (ptr[1] != CHAR_QUESTION_MARK)
+    /* If ( is not followed by ? it is either a capture or a special verb. */
+
+    if (*ptr != CHAR_QUESTION_MARK)
       {
-      if (ptr[1] != CHAR_ASTERISK)
+      const char *vn;
+
+      /* Handle capturing brackets (or non-capturing if auto-capture is turned
+      off). */
+
+      if (*ptr != CHAR_ASTERISK)
         {
-        if ((options & PCRE2_NO_AUTO_CAPTURE) == 0) cb->bracount++;
+        nest_depth++;
+        if ((options & PCRE2_NO_AUTO_CAPTURE) == 0)
+          {
+          cb->bracount++;
+          *parsed_pattern++ = META_CAPTURE | cb->bracount;
+          }
+        else *parsed_pattern++ = META_NOCAPTURE;
         }


-      /* (*something) - skip over a name, and then just skip to closing ket
-      unless PCRE2_ALT_VERBNAMES is set, in which case we have to process
-      escapes in the string after a verb name terminated by a colon. */


-      else
+      /* ---- Handle (*VERB) and (*VERB:NAME) ---- */
+
+      /* Do nothing for (*) so it gives a "bad quantifier" error rather than
+      "(*MARK) must have an argument". */
+
+      else if (ptrend - ptr > 1 && ptr[1] != CHAR_RIGHT_PARENTHESIS)
         {
-        ptr += 2;
-        while (MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype_word) != 0) ptr++;
-        if (*ptr == CHAR_COLON && (options & PCRE2_ALT_VERBNAMES) != 0)
+        vn = verbnames;
+        if (!read_name(&ptr, ptrend, 0, &offset, &name, &namelen, &errorcode,
+          cb)) goto FAILED;
+        if (ptr >= ptrend || (*ptr != CHAR_COLON &&
+                              *ptr != CHAR_RIGHT_PARENTHESIS))
           {
-          ptr++;
-          if (process_verb_name(&ptr, NULL, &errorcode, options, utf, cb) < 0)
+          errorcode = ERR60;  /* Malformed */
+          goto FAILED;
+          }
+
+        /* Scan the table of verb names */
+
+        for (i = 0; i < verbcount; i++)
+          {
+          if (namelen == verbs[i].len &&
+              PRIV(strncmp_c8)(name, vn, namelen) == 0)
+            break;
+          vn += verbs[i].len + 1;
+          }
+
+        if (i >= verbcount)
+          {
+          errorcode = ERR60;  /* Verb not recognized */
+          goto FAILED;
+          }
+
+        /* An empty argument is treated as no argument. */
+
+        if (*ptr == CHAR_COLON && ptr + 1 < ptrend &&
+             ptr[1] == CHAR_RIGHT_PARENTHESIS)
+          ptr++;    /* Advance to the closing parens */
+
+        /* Check for mandatory non-empty argument; this is (*MARK) */
+
+        if (verbs[i].has_arg > 0 && *ptr != CHAR_COLON)
+          {
+          errorcode = ERR66;
+          goto FAILED;
+          }
+
+        /* It appears that Perl allows any characters whatsoever, other than a
+        closing parenthesis, to appear in arguments ("names"), so we no longer
+        insist on letters, digits, and underscores. Perl does not, however, do
+        any interpretation within arguments, and has no means of including a
+        closing parenthesis. PCRE supports escape processing but only when it
+        is requested by an option. We set inverbname TRUE here, and let the
+        main loop take care of this so that escape and \x processing is done by
+        the main code above. */
+
+        if (*ptr++ == CHAR_COLON)   /* Skip past : or ) */
+          {
+          if (verbs[i].has_arg < 0)  /* Argument is forbidden */
+            {
+            errorcode = ERR59;
             goto FAILED;
+            }
+          *parsed_pattern++ = verbs[i].meta +
+            ((verbs[i].meta != META_MARK)? 0x00010000u:0);
+          verblengthptr = parsed_pattern++;
+          inverbname = TRUE;
           }
-        else
+        else  /* No verb "name" argument */
           {
-          while (ptr < cb->end_pattern && *ptr != CHAR_RIGHT_PARENTHESIS)
-            ptr++;
+          *parsed_pattern++ = verbs[i].meta;
           }
-        nest_depth--;
-        }
-      }
+        }     /* End of (*VERB) handling */
+      break;  /* Done with this parenthesis */
+      }       /* End of groups that don't start with (? */


-    /* Handle (?...) groups */


-    else switch(ptr[2])
+    /* ---- Items starting (? ---- */
+
+    /* The type of item is determined by what follows (?. Handle (?| and option
+    changes under "default" because both need a new block on the nest stack.
+    Comments starting with (?# are handled above. Note that there is some
+    ambiguity about the sequence (?- because if a digit follows it's a relative
+    recursion or subroutine call whereas otherwise it's an option unsetting. */
+
+    if (++ptr >= ptrend) goto UNCLOSED_PARENTHESIS;
+
+    switch(*ptr)
       {
       default:
-      ptr += 2;
-      if (ptr[0] == CHAR_R ||                           /* (?R) */
-          ptr[0] == CHAR_NUMBER_SIGN ||                 /* (?#) */
-          IS_DIGIT(ptr[0]) ||                           /* (?n) */
-          (ptr[0] == CHAR_MINUS && IS_DIGIT(ptr[1])))   /* (?-n) */
-        {
-        skiptoket = ptr[0];
-        break;
-        }
+      if (*ptr == CHAR_MINUS && ptrend - ptr > 1 && IS_DIGIT(ptr[1]))
+        goto RECURSION_BYNUMBER;  /* The + case is handled by CHAR_PLUS */


-      /* Handle (?| and (?imsxJU: which are the only other valid forms. Both
-      need a new block on the nest stack. */
+      /* We now have either (?| or a (possibly empty) option setting,
+      optionally followed by a non-capturing group. */


+      nest_depth++;
       if (top_nest == NULL) top_nest = (nest_save *)(cb->start_workspace);
       else if (++top_nest >= end_nests)
         {
@@ -3477,6 +3191,9 @@
       if ((options & PCRE2_EXTENDED) != 0) top_nest->flags |= NSF_EXTENDED;
       if ((options & PCRE2_DUPNAMES) != 0) top_nest->flags |= NSF_DUPNAMES;


+      /* Start of non-capturing group that resets the capture count for each
+      branch. */
+
       if (*ptr == CHAR_VERTICAL_LINE)
         {
         top_nest->reset_group = (uint16_t)cb->bracount;
@@ -3483,76 +3200,208 @@
         top_nest->max_group = (uint16_t)cb->bracount;
         top_nest->flags |= NSF_RESET;
         cb->external_flags |= PCRE2_DUPCAPUSED;
-        break;
+        *parsed_pattern++ = META_NOCAPTURE;
+        ptr++;
         }


-      /* Scan options */
+      /* Scan for options imsxJU. We need to keep track of (?x) and (?J) for
+      use while scanning. The other options are used during the compiling
+      phases. */


-      top_nest->reset_group = 0;
-      top_nest->max_group = 0;
+      else
+        {
+        top_nest->reset_group = 0;
+        top_nest->max_group = 0;
+        set = unset = 0;
+        optset = &set;


-      set = unset = 0;
-      optset = &set;
+        while (ptr < ptrend && *ptr != CHAR_RIGHT_PARENTHESIS &&
+                               *ptr != CHAR_COLON)
+          {
+          switch (*ptr++)
+            {
+            case CHAR_MINUS: optset = &unset; break;


-      /* Need only track (?x: and (?J: at this stage */
+            case CHAR_J:  /* Record that it changed in the external options */
+            *optset |= PCRE2_DUPNAMES;
+            cb->external_flags |= PCRE2_JCHANGED;
+            break;


-      while (*ptr != CHAR_RIGHT_PARENTHESIS && *ptr != CHAR_COLON)
-        {
-        switch (*ptr++)
+            case CHAR_i: *optset |= PCRE2_CASELESS; break;
+            case CHAR_m: *optset |= PCRE2_MULTILINE; break;
+            case CHAR_s: *optset |= PCRE2_DOTALL; break;
+            case CHAR_x: *optset |= PCRE2_EXTENDED; break;
+            case CHAR_U: *optset |= PCRE2_UNGREEDY; break;
+
+            default:
+            errorcode = ERR11;
+            ptr--;    /* Correct the offset */
+            goto FAILED;
+            }
+          }
+        options = (options | set) & (~unset);
+
+        /* If the options ended with ')' this is not the start of a nested
+        group with option changes, so the options change at this level.
+        In this case, if the previous level set up a nest block, discard the
+        one we have just created. Otherwise adjust it for the previous level.
+        If the options ended with ':' we are starting a non-capturing group,
+        possibly with an options setting. */
+
+        if (ptr >= ptrend) goto UNCLOSED_PARENTHESIS;
+        if (*ptr++ == CHAR_RIGHT_PARENTHESIS)
           {
-          case CHAR_MINUS: optset = &unset; break;
+          nest_depth--;  /* This is not a nested group after all. */
+          if (top_nest > (nest_save *)(cb->start_workspace) &&
+              (top_nest-1)->nest_depth == nest_depth) top_nest--;
+          else top_nest->nest_depth = nest_depth;
+          }
+        else *parsed_pattern++ = META_NOCAPTURE;


-          case CHAR_x: *optset |= PCRE2_EXTENDED; break;
+        /* If nothing changed, no need to record. */


-          case CHAR_J:
-          *optset |= PCRE2_DUPNAMES;
-          cb->external_flags |= PCRE2_JCHANGED;
-          break;
+        if (set != 0 || unset != 0)
+          {
+          *parsed_pattern++ = META_OPTIONS;
+          *parsed_pattern++ = options;
+          }
+        }     /* End options processing */
+      break;  /* End default case after (? */


-          case CHAR_i:
-          case CHAR_m:
-          case CHAR_s:
-          case CHAR_U:
-          break;


-          default:
-          errorcode = ERR11;
-          ptr--;    /* Correct the offset */
-          goto FAILED;
-          }
+      /* ---- Python syntax support ---- */
+
+      case CHAR_P:
+      if (++ptr >= ptrend) goto UNCLOSED_PARENTHESIS;
+
+      /* (?P<name> is the same as (?<name>, which defines a named group. */
+
+      if (*ptr == CHAR_LESS_THAN_SIGN)
+        {
+        terminator = CHAR_GREATER_THAN_SIGN;
+        goto DEFINE_NAME;
         }


-      options = (options | set) & (~unset);
+      /* (?P>name) is the same as (?&name), which is a recursion or subroutine
+      call. */


-      /* If the options ended with ')' this is not the start of a nested
-      group with option changes, so the options change at this level. If the
-      previous level set up a nest block, discard the one we have just created.
-      Otherwise adjust it for the previous level. */
+      if (*ptr == CHAR_GREATER_THAN_SIGN) goto RECURSE_BY_NAME;


-      if (*ptr == CHAR_RIGHT_PARENTHESIS)
+      /* (?P=name) is the same as \k<name>, a back reference by name. Anything
+      else after (?P is an error. */
+
+      if (*ptr != CHAR_EQUALS_SIGN)
         {
-        nest_depth--;
-        if (top_nest > (nest_save *)(cb->start_workspace) &&
-            (top_nest-1)->nest_depth == nest_depth) top_nest --;
-        else top_nest->nest_depth = nest_depth;
+        errorcode = ERR41;
+        goto FAILED;
         }
-      break;
+      if (!read_name(&ptr, ptrend, CHAR_RIGHT_PARENTHESIS, &offset, &name,
+          &namelen, &errorcode, cb)) goto FAILED;
+      *parsed_pattern++ = META_BACKREF_BYNAME;
+      *parsed_pattern++ = namelen;
+      PUTOFFSET(offset, parsed_pattern);
+      okquantifier = TRUE;
+      break;   /* End of (?P processing */


-      /* Skip over a numerical or string argument for a callout. */


-      case CHAR_C:
-      ptr += 2;
-      if (ptr[1] == CHAR_RIGHT_PARENTHESIS) break;
-      if (IS_DIGIT(ptr[1]))
+      /* ---- Recursion/subroutine calls by number ---- */
+
+      case CHAR_R:
+      i = 0;         /* (?R) == (?R0) */
+      ptr++;
+      if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS)
         {
-        while (IS_DIGIT(ptr[1])) ptr++;
+        errorcode = ERR58;
+        goto FAILED;  
+        }  
+      goto SET_RECURSION;
+
+      /* An item starting (?- followed by a digit comes here via the "default"
+      case because (?- followed by a non-digit is an options setting. */
+
+      case CHAR_PLUS:
+      if (ptrend - ptr < 2 || !IS_DIGIT(ptr[1]))
+        {
+        errorcode = ERR29;   /* Missing number */
+        goto FAILED;
         }
+      /* Fall through */


-      /* Handle a string argument */
+      case CHAR_0: case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4:
+      case CHAR_5: case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9:
+      RECURSION_BYNUMBER:
+      if (!read_number(&ptr, ptrend,
+          (IS_DIGIT(*ptr))? -1:(int)(cb->bracount), /* + and - are relative */
+          MAX_GROUP_NUMBER, ERR61,
+          &i, &errorcode)) goto FAILED;
+      if (i < 0)  /* NB (?0) is permitted */
+        {
+        errorcode = ERR15;   /* Unknown group */
+        goto FAILED_BACK;
+        }
+      if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS)
+        goto UNCLOSED_PARENTHESIS;


-      else
+      SET_RECURSION:
+      *parsed_pattern++ = META_RECURSE | (uint32_t)i;
+      offset = (PCRE2_SIZE)(ptr - cb->start_pattern);
+      ptr++;
+      PUTOFFSET(offset, parsed_pattern);
+      okquantifier = TRUE;
+      break;  /* End of recursive call by number handling */
+
+
+      /* ---- Recursion/subroutine calls by name ---- */
+
+      case CHAR_AMPERSAND:
+      RECURSE_BY_NAME:
+      if (!read_name(&ptr, ptrend, CHAR_RIGHT_PARENTHESIS, &offset, &name,
+          &namelen, &errorcode, cb)) goto FAILED;
+      *parsed_pattern++ = META_RECURSE_BYNAME;
+      *parsed_pattern++ = namelen;
+      PUTOFFSET(offset, parsed_pattern);
+      okquantifier = TRUE;
+      break;
+
+      /* ---- Callout with numerical or string argument ---- */
+
+      case CHAR_C:
+      if (++ptr >= ptrend) goto UNCLOSED_PARENTHESIS;
+
+      /* If the previous item was a condition starting (?(? an assertion,
+      optionally preceded by a callout, is expected. This is checked later on,
+      during actual compilation. However we need to identify this kind of
+      assertion in this pass because it must not be qualified. The value of
+      expect_cond_assert is set to 2 after (?(? is processed. We decrement it
+      for a callout - still leaving a positive value that identifies the
+      assertion. Multiple callouts or any other items will make it zero or
+      less, which doesn't matter because they will cause an error later. */
+
+      expect_cond_assert = prev_expect_cond_assert - 1;
+
+      /* If previous_callout is not NULL, it means this follows a previous
+      callout. If it was a manual callout, do nothing; this means its "length
+      of next pattern item" field will remain zero. If it was an automatic
+      callout, abolish it. */
+
+      if (previous_callout != NULL && (options & PCRE2_AUTO_CALLOUT) != 0 &&
+          previous_callout == parsed_pattern - 4 &&
+          parsed_pattern[-1] == 255)
+        parsed_pattern = previous_callout;
+
+      /* Save for updating next pattern item length, and skip one item before
+      completing. */
+
+      previous_callout = parsed_pattern;
+      after_manual_callout = 1;
+
+      /* Handle a string argument; specific delimiter is required. */
+
+      if (*ptr != CHAR_RIGHT_PARENTHESIS && !IS_DIGIT(*ptr))
         {
-        ptr++;
+        PCRE2_SIZE calloutlength;
+        PCRE2_SPTR startptr = ptr;
+
         delimiter = 0;
         for (i = 0; PRIV(callout_start_delims)[i] != 0; i++)
           {
@@ -3562,7 +3411,6 @@
             break;
             }
           }
-
         if (delimiter == 0)
           {
           errorcode = ERR82;
@@ -3569,124 +3417,335 @@
           goto FAILED;
           }


-        start = ptr;
-        do
+        *parsed_pattern = META_CALLOUT_STRING;
+        parsed_pattern += 3;   /* Skip pattern info */
+
+        for (;;)
           {
-          if (++ptr >= cb->end_pattern)
+          if (++ptr >= ptrend)
             {
             errorcode = ERR81;
-            ptr = start;   /* To give a more useful message */
+            ptr = startptr;   /* To give a more useful message */
             goto FAILED;
             }
-          if (ptr[0] == delimiter && ptr[1] == delimiter) ptr += 2;
+          if (*ptr == delimiter && (++ptr > ptrend || *ptr != delimiter)) break;
           }
-        while (ptr[0] != delimiter);
+
+        calloutlength = (PCRE2_SIZE)(ptr - startptr);
+        if (calloutlength > UINT32_MAX)
+          {
+          errorcode = ERR72;
+          goto FAILED;
+          }
+        *parsed_pattern++ = (uint32_t)calloutlength;
+        offset = (PCRE2_SIZE)(startptr - cb->start_pattern);
+        PUTOFFSET(offset, parsed_pattern);
         }


-      /* Check terminating ) */
+      /* Handle a callout with an optional numerical argument, which must be
+      less than or equal to 255. A missing argument gives 0. */


-      if (ptr[1] != CHAR_RIGHT_PARENTHESIS)
+      else
         {
-        errorcode = ERR39;
-        ptr++;
-        goto FAILED;
+        int n = 0;
+        *parsed_pattern = META_CALLOUT_NUMBER;     /* Numerical callout */
+        parsed_pattern += 3;                       /* Skip pattern info */
+        while (ptr < ptrend && IS_DIGIT(*ptr))
+          {
+          n = n * 10 + *ptr++ - CHAR_0;
+          if (n > 255)
+            {
+            errorcode = ERR38;
+            goto FAILED;
+            }
+          }
+        *parsed_pattern++ = n;
         }
-      break;


-      /* Conditional group */
+      /* Both formats must have a closing parenthesis */


-      case CHAR_LEFT_PARENTHESIS:
-      if (ptr[3] != CHAR_QUESTION_MARK)   /* Not assertion or callout */
+      if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS)
         {
-        nest_depth++;
-        ptr += 2;
-        break;
+        errorcode = ERR39;
+        goto FAILED;
         }
+      ptr++;


-      /* Must be an assertion or a callout */
+      /* Remember the offset to the next item in the pattern, and set a default
+      length. This should get updated after the next item is read. */


-      switch(ptr[4])
-       {
-       case CHAR_LESS_THAN_SIGN:
-       if (ptr[5] != CHAR_EXCLAMATION_MARK && ptr[5] != CHAR_EQUALS_SIGN)
-         goto MISSING_ASSERTION;
-       /* Fall through */
+      previous_callout[1] = ptr - cb->start_pattern;
+      previous_callout[2] = 0;
+      break;                  /* End callout */


-       case CHAR_C:
-       case CHAR_EXCLAMATION_MARK:
-       case CHAR_EQUALS_SIGN:
-       ptr++;
-       break;


-       default:
-       MISSING_ASSERTION:
-       ptr += 3;            /* To improve error message */
-       errorcode = ERR28;
-       goto FAILED;
-       }
-      break;
+      /* ---- Conditional group ---- */


-      case CHAR_COLON:
-      case CHAR_GREATER_THAN_SIGN:
-      case CHAR_EQUALS_SIGN:
-      case CHAR_EXCLAMATION_MARK:
-      case CHAR_AMPERSAND:
-      case CHAR_PLUS:
-      ptr += 2;
-      break;
+      /* A condition can be an assertion, a number (referring to a numbered
+      group's having been set), a name (referring to a named group), or 'R',
+      referring to overall recursion. R<digits> and R&name are also permitted
+      for recursion state tests. Numbers may be preceded by + or - to specify a
+      relative group number.


-      case CHAR_P:
-      if (ptr[3] != CHAR_LESS_THAN_SIGN)
+      There are several syntaxes for testing a named group: (?(name)) is used
+      by Python; Perl 5.10 onwards uses (?(<name>) or (?('name')).
+
+      There are two unfortunate ambiguities. 'R' can be the recursive thing or
+      the name 'R' (and similarly for 'R' followed by digits). 'DEFINE' can be
+      the Perl DEFINE feature or the Python named test. We look for a name
+      first; if not found, we try the other case.
+
+      For compatibility with auto-callouts, we allow a callout to be specified
+      before a condition that is an assertion. */
+
+      case CHAR_LEFT_PARENTHESIS:
+      if (++ptr >= ptrend) goto UNCLOSED_PARENTHESIS;
+      nest_depth++;
+
+      /* If the next character is ? there must be an assertion next (optionally
+      preceded by a callout). We do not check this here, but instead we just
+      preserve the offset so that the later check can give a sensible error
+      message. Pull back the pointer to the start of the assertion (or
+      callout), and set expect_cond_assert to 2. If this is still greater than
+      zero (callouts decrement it) when the next assertion is read, it will be
+      marked as a condition that must not be repeated. */
+
+      if (*ptr == CHAR_QUESTION_MARK)
         {
-        ptr += 3;
-        break;
+        *parsed_pattern++ = META_COND_ASSERT;
+        offset = (PCRE2_SIZE)(--ptr - cb->start_pattern - 2);
+        PUTOFFSET(offset, parsed_pattern);
+        expect_cond_assert = 2;
+        break;  /* End of conditional */
         }
-      ptr++;
-      c = CHAR_GREATER_THAN_SIGN;   /* Terminator */
-      goto DEFINE_NAME;


-      case CHAR_LESS_THAN_SIGN:
-      if (ptr[3] == CHAR_EQUALS_SIGN || ptr[3] == CHAR_EXCLAMATION_MARK)
+      /* Handle (?([+-]number)... */
+
+      if (read_number(&ptr, ptrend, cb->bracount, MAX_GROUP_NUMBER, ERR61, &i,
+          &errorcode))
         {
-        ptr += 3;
-        break;
+        if (i <= 0)
+          {
+          errorcode = ERR15;
+          goto FAILED;
+          }
+        *parsed_pattern++ = META_COND_NUMBER;
+        offset = (PCRE2_SIZE)(ptr - cb->start_pattern - 2);
+        PUTOFFSET(offset, parsed_pattern);
+        *parsed_pattern++ = i;
         }
-      c = CHAR_GREATER_THAN_SIGN;   /* Terminator */
-      goto DEFINE_NAME;
+      else if (errorcode != 0) goto FAILED;   /* Number too big */


-      case CHAR_APOSTROPHE:
-      c = CHAR_APOSTROPHE;    /* Terminator */
+      /* No number found. Handle the special case (?(VERSION[>]=n.m)... */


-      DEFINE_NAME:
-      name = ptr = ptr + 3;
+      else if (ptrend - ptr >= 10 &&
+               PRIV(strncmp_c8)(ptr, STRING_VERSION, 7) == 0 &&
+               ptr[7] != CHAR_RIGHT_PARENTHESIS)
+        {
+        uint32_t ge = 0;
+        int major = 0;
+        int minor = 0;


-      if (*ptr == c)          /* Empty name */
-        {
-        errorcode = ERR62;
-        goto FAILED;
+        ptr += 7;
+        if (*ptr == CHAR_GREATER_THAN_SIGN)
+          {
+          ge = 1;
+          ptr++;
+          }
+
+        /* NOTE: cannot write IS_DIGIT(*(++ptr)) here because IS_DIGIT
+        references its argument twice. */
+
+        if (*ptr != CHAR_EQUALS_SIGN || (ptr++, !IS_DIGIT(*ptr)))
+          goto BAD_VERSION_CONDITION;
+
+        if (!read_number(&ptr, ptrend, -1, 1000, ERR79, &major, &errorcode))
+          goto FAILED;
+
+        if (ptr >= ptrend) goto BAD_VERSION_CONDITION;
+        if (*ptr == CHAR_DOT)
+          {
+          if (++ptr >= ptrend || !IS_DIGIT(*ptr)) goto BAD_VERSION_CONDITION;
+          if (!read_number(&ptr, ptrend, -1, 99 , ERR79, &minor, &errorcode))
+            goto FAILED;
+          if (minor < 10) minor *= 10;
+          if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS)
+            goto BAD_VERSION_CONDITION;
+          }
+
+        *parsed_pattern++ = META_COND_VERSION;
+        *parsed_pattern++ = ge;
+        *parsed_pattern++ = major;
+        *parsed_pattern++ = minor;
         }


-      if (IS_DIGIT(*ptr))
+      /* All the remaining cases now require us to read a name. We cannot at
+      this stage distinguish ambiguous cases such as (?(R12) which might be a
+      recursion test by number or a name, because the named groups have not yet
+      all been identified. Those cases are treated as names, but given a
+      different META code. */
+
+      else
         {
-        errorcode = ERR44;   /* Group name must start with non-digit */
-        goto FAILED;
-        }
+        BOOL was_r_ampersand = FALSE;


-      if (MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype_word) == 0)
+        if (*ptr == CHAR_R && ptrend - ptr > 1 && ptr[1] == CHAR_AMPERSAND)
+          {
+          terminator = CHAR_RIGHT_PARENTHESIS;
+          was_r_ampersand = TRUE;
+          ptr++;
+          }
+        else if (*ptr == CHAR_LESS_THAN_SIGN)
+          terminator = CHAR_GREATER_THAN_SIGN;
+        else if (*ptr == CHAR_APOSTROPHE)
+          terminator = CHAR_APOSTROPHE;
+        else
+          {
+          terminator = CHAR_RIGHT_PARENTHESIS;
+          ptr--;   /* Point to char before name */
+          }
+        if (!read_name(&ptr, ptrend, terminator, &offset, &name, &namelen,
+            &errorcode, cb)) goto FAILED;
+
+        /* Handle (?(R&name) */
+
+        if (was_r_ampersand)
+          {
+          *parsed_pattern = META_COND_RNAME;
+          ptr--;   /* Back to closing parens */
+          }
+
+        /* Handle (?(name). If the name is "DEFINE" we identify it with a
+        special code. Likewise if the name consists of R followed only by
+        digits. Otherwise, handle it like a quoted name. */
+
+        else if (terminator == CHAR_RIGHT_PARENTHESIS)
+          {
+          if (namelen == 6 && PRIV(strncmp_c8)(name, STRING_DEFINE, 6) == 0)
+            *parsed_pattern = META_COND_DEFINE;
+          else
+            {
+            for (i = 1; i < (int)namelen; i++)
+              if (!IS_DIGIT(name[i])) break;
+            *parsed_pattern = (*name == CHAR_R && i >= (int)namelen)?
+              META_COND_RNUMBER : META_COND_NAME;
+            }
+          ptr--;   /* Back to closing parens */
+          }
+
+        /* Handle (?('name') or (?(<name>) */
+
+        else *parsed_pattern = META_COND_NAME;
+
+        /* All these cases except DEFINE end with the name length and offset;
+        DEFINE just has an offset (for the "too many branches" error). */
+
+        if (*parsed_pattern++ != META_COND_DEFINE) *parsed_pattern++ = namelen;
+        PUTOFFSET(offset, parsed_pattern);
+        }  /* End cases that read a name */
+
+      /* Check the closing parenthesis of the condition */
+
+      if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS)
         {
         errorcode = ERR24;
         goto FAILED;
         }
+      ptr++;
+      break;  /* End of condition processing */


-      /* Advance ptr, set namelen and check its length. */
-      READ_NAME(ctype_word, ERR48, errorcode);


-      if (*ptr != c)
+      /* ---- Atomic group ---- */
+
+      case CHAR_GREATER_THAN_SIGN:
+      *parsed_pattern++ = META_ATOMIC;
+      nest_depth++;
+      ptr++;
+      break;
+
+
+      /* ---- Lookahead assertions ---- */
+
+      case CHAR_EQUALS_SIGN:
+      *parsed_pattern++ = META_LOOKAHEAD;
+      ptr++;
+      goto POST_ASSERTION;
+
+      case CHAR_EXCLAMATION_MARK:
+      *parsed_pattern++ = META_LOOKAHEADNOT;
+      ptr++;
+      goto POST_ASSERTION;
+
+
+      /* ---- Lookbehind assertions ---- */
+
+      /* (?< followed by = or ! is a lookbehind assertion. Otherwise (?< is the
+      start of the name of a capturing group. */
+
+      case CHAR_LESS_THAN_SIGN:
+      if (ptrend - ptr <= 1 ||
+         (ptr[1] != CHAR_EQUALS_SIGN && ptr[1] != CHAR_EXCLAMATION_MARK))
         {
-        errorcode = ERR42;
-        goto FAILED;
+        terminator = CHAR_GREATER_THAN_SIGN;
+        goto DEFINE_NAME;
         }
+      *parsed_pattern++ = (ptr[1] == CHAR_EQUALS_SIGN)?
+        META_LOOKBEHIND : META_LOOKBEHINDNOT;
+      *has_lookbehind = TRUE;
+      offset = (PCRE2_SIZE)(ptr - cb->start_pattern - 2);
+      PUTOFFSET(offset, parsed_pattern);
+      ptr += 2;
+      /* Fall through */


+      /* If the previous item was a condition starting (?(? an assertion,
+      optionally preceded by a callout, is expected. This is checked later on,
+      during actual compilation. However we need to identify this kind of
+      assertion in this pass because it must not be qualified. The value of
+      expect_cond_assert is set to 2 after (?(? is processed. We decrement it
+      for a callout - still leaving a positive value that identifies the
+      assertion. Multiple callouts or any other items will make it zero or
+      less, which doesn't matter because they will cause an error later. */
+
+      POST_ASSERTION:
+      nest_depth++;
+      if (prev_expect_cond_assert > 0)
+        {
+        if (top_nest == NULL) top_nest = (nest_save *)(cb->start_workspace);
+        else if (++top_nest >= end_nests)
+          {
+          errorcode = ERR84;
+          goto FAILED;
+          }
+        top_nest->nest_depth = nest_depth;
+        top_nest->flags = NSF_CONDASSERT;
+        if ((options & PCRE2_EXTENDED) != 0) top_nest->flags |= NSF_EXTENDED;
+        if ((options & PCRE2_DUPNAMES) != 0) top_nest->flags |= NSF_DUPNAMES;
+        }
+      break;
+
+
+      /* ---- Define a named group ---- */
+
+      /* A named group may be defined as (?'name') or (?<name>). In the latter
+      case we jump to DEFINE_NAME from the disambiguation of (?< above with the
+      terminator set to '>'. */
+
+      case CHAR_APOSTROPHE:
+      terminator = CHAR_APOSTROPHE;    /* Terminator */
+
+      DEFINE_NAME:
+      if (!read_name(&ptr, ptrend, terminator, &offset, &name, &namelen,
+          &errorcode, cb)) goto FAILED;
+
+      /* We have a name for this capturing group. It is also assigned a number,
+      which is its primary means of identification. */
+
+      cb->bracount++;
+      *parsed_pattern++ = META_CAPTURE | cb->bracount;
+      nest_depth++;
+
+      /* Check not too many names */
+
       if (cb->names_found >= MAX_NAME_COUNT)
         {
         errorcode = ERR49;
@@ -3693,13 +3752,11 @@
         goto FAILED;
         }


+      /* Adjust the entry size to accommodate the longest name found. */
+
       if (namelen + IMM2_SIZE + 1 > cb->name_entry_size)
         cb->name_entry_size = (uint16_t)(namelen + IMM2_SIZE + 1);


-      /* We have a valid name for this capturing group. */
-
-      cb->bracount++;
-
       /* Scan the list to check for duplicates. For duplicate names, if the
       number is the same, break the loop, which causes the name to be
       discarded; otherwise, if DUPNAMES is not set, give an error.
@@ -3712,7 +3769,7 @@
       for (i = 0; i < cb->names_found; i++, ng++)
         {
         if (namelen == ng->length &&
-            PRIV(strncmp)(name, ng->name, (size_t)namelen) == 0)
+            PRIV(strncmp)(name, ng->name, (PCRE2_SIZE)namelen) == 0)
           {
           if (ng->number == cb->bracount) break;
           if ((options & PCRE2_DUPNAMES) == 0)
@@ -3766,8 +3823,11 @@
       }        /* End of (? switch */
     break;     /* End of ( handling */


-    /* At an alternation, reset the capture count if we are in a (?| group. */


+    /* ---- Branch terminators ---- */
+
+    /* Alternation: reset the capture count if we are in a (?| group. */
+
     case CHAR_VERTICAL_LINE:
     if (top_nest != NULL && top_nest->nest_depth == nest_depth &&
         (top_nest->flags & NSF_RESET) != 0)
@@ -3776,12 +3836,15 @@
         top_nest->max_group = (uint16_t)cb->bracount;
       cb->bracount = top_nest->reset_group;
       }
+    *parsed_pattern++ = META_ALT;
     break;


-    /* At a right parenthesis, reset the capture count to the maximum if we
-    are in a (?| group and/or reset the extended option. */
+    /* End of group; reset the capture count to the maximum if we are in a (?|
+    group and/or reset the extended and dupnames options. Disallow quantifier
+    for a condition that is an assertion. */


     case CHAR_RIGHT_PARENTHESIS:
+    okquantifier = TRUE;
     if (top_nest != NULL && top_nest->nest_depth == nest_depth)
       {
       if ((top_nest->flags & NSF_RESET) != 0 &&
@@ -3791,6 +3854,8 @@
         else options &= ~PCRE2_EXTENDED;
       if ((top_nest->flags & NSF_DUPNAMES) != 0) options |= PCRE2_DUPNAMES;
         else options &= ~PCRE2_DUPNAMES;
+      if ((top_nest->flags & NSF_CONDASSERT) != 0)
+        okquantifier = FALSE;
       if (top_nest == (nest_save *)(cb->start_workspace)) top_nest = NULL;
         else top_nest--;
       }
@@ -3797,45 +3862,921 @@
     if (nest_depth == 0)    /* Unmatched closing parenthesis */
       {
       errorcode = ERR22;
-      goto FAILED;
+      goto FAILED_BACK;
       }
     nest_depth--;
+    *parsed_pattern++ = META_KET;
     break;
-    }
-  }
+    }  /* End of switch on pattern character */
+  }    /* End of main character scan loop */


-if (nest_depth == 0)
+/* End of pattern reached. Check for missing ) at the end of a verb name. */
+
+if (inverbname && ptr >= ptrend)
{
- cb->final_bracount = cb->bracount;
- return 0;
+ errorcode = ERR60;
+ goto FAILED;
}

-/* We give a special error for a missing closing parentheses after (?# because
-it might otherwise be hard to see where the missing character is. */
+/* Manage callout for the final item */

-errorcode = (skiptoket == CHAR_NUMBER_SIGN)? ERR18 : ERR14;
+parsed_pattern = manage_callouts(ptr, &previous_callout, options,
+ parsed_pattern, cb);

+/* Terminate the parsed pattern, then return success if all groups are closed.
+Otherwise we have unclosed parentheses. */
+
+*parsed_pattern = META_END;
+if (nest_depth == 0) return 0;
+
+UNCLOSED_PARENTHESIS:
+errorcode = ERR14;
+
+/* Come here for all failures. */
+
FAILED:
-*ptrptr = ptr;
+cb->erroroffset = (PCRE2_SIZE)(ptr - cb->start_pattern);
return errorcode;
+
+/* Some errors need to indicate the previous character. */
+
+FAILED_BACK:
+ptr--;
+goto FAILED;
+
+/* This failure happens several times. */
+
+BAD_VERSION_CONDITION:
+errorcode = ERR79;
+goto FAILED;
}



 /*************************************************
+*      Find first significant op code            *
+*************************************************/
+
+/* This is called by several functions that scan a compiled expression looking
+for a fixed first character, or an anchoring op code etc. It skips over things
+that do not influence this. For some calls, it makes sense to skip negative
+forward and all backward assertions, and also the \b assertion; for others it
+does not.
+
+Arguments:
+  code         pointer to the start of the group
+  skipassert   TRUE if certain assertions are to be skipped
+
+Returns:       pointer to the first significant opcode
+*/
+
+static const PCRE2_UCHAR*
+first_significant_code(PCRE2_SPTR code, BOOL skipassert)
+{
+for (;;)
+  {
+  switch ((int)*code)
+    {
+    case OP_ASSERT_NOT:
+    case OP_ASSERTBACK:
+    case OP_ASSERTBACK_NOT:
+    if (!skipassert) return code;
+    do code += GET(code, 1); while (*code == OP_ALT);
+    code += PRIV(OP_lengths)[*code];
+    break;
+
+    case OP_WORD_BOUNDARY:
+    case OP_NOT_WORD_BOUNDARY:
+    if (!skipassert) return code;
+    /* Fall through */
+
+    case OP_CALLOUT:
+    case OP_CREF:
+    case OP_DNCREF:
+    case OP_RREF:
+    case OP_DNRREF:
+    case OP_FALSE:
+    case OP_TRUE:
+    code += PRIV(OP_lengths)[*code];
+    break;
+
+    case OP_CALLOUT_STR:
+    code += GET(code, 1 + 2*LINK_SIZE);
+    break;
+
+    default:
+    return code;
+    }
+  }
+/* Control never reaches here */
+}
+
+
+
+/*************************************************
+*    Scan compiled branch for non-emptiness      *
+*************************************************/
+
+/* This function scans through a branch of a compiled pattern to see whether it
+can match the empty string. It is called at the end of compiling to check the
+entire pattern, and from compile_branch() when checking for an unlimited repeat
+of a group that can match nothing. In the latter case it is called only when
+doing the real compile, not during the pre-compile that measures the size of
+the compiled pattern.
+
+Note that first_significant_code() skips over backward and negative forward
+assertions when its final argument is TRUE. If we hit an unclosed bracket, we
+return "empty" - this means we've struck an inner bracket whose current branch
+will already have been scanned.
+
+Arguments:
+  code        points to start of search
+  endcode     points to where to stop
+  utf         TRUE if in UTF mode
+  cb          compile data
+  atend       TRUE if being called to check an entire pattern
+  recurses    chain of recurse_check to catch mutual recursion
+  countptr    pointer to count to catch over-complicated pattern
+
+Returns:      0 if what is matched cannot be empty
+              1 if what is matched could be empty
+             -1 if the pattern is too complicated
+*/
+
+#define CBE_NOTEMPTY          0
+#define CBE_EMPTY             1
+#define CBE_TOOCOMPLICATED  (-1)
+
+
+static int
+could_be_empty_branch(PCRE2_SPTR code, PCRE2_SPTR endcode, BOOL utf,
+  compile_block *cb, BOOL atend, recurse_check *recurses, int *countptr)
+{
+uint32_t group = 0;
+uint32_t groupinfo = 0;
+PCRE2_UCHAR c;
+recurse_check this_recurse;
+
+/* If what we are checking has already been set as "could be empty", we know
+the answer. */
+
+if (*code >= OP_SBRA && *code <= OP_SCOND) return CBE_EMPTY;
+
+/* If this is a capturing group, we may have the answer cached, but we can only
+use this information if there are no (?| groups in the pattern, because
+otherwise group numbers are not unique. */
+
+if ((cb->external_flags & PCRE2_DUPCAPUSED) == 0 &&
+    (*code == OP_CBRA || *code == OP_CBRAPOS))
+  {
+  group = GET2(code, 1 + LINK_SIZE);
+  groupinfo = cb->groupinfo[group];
+  if ((groupinfo & GI_SET_COULD_BE_EMPTY) != 0)
+    return ((groupinfo & GI_COULD_BE_EMPTY) != 0)? CBE_EMPTY : CBE_NOTEMPTY;
+  }
+
+/* A large and/or complex regex can take too long to process. We have to assume
+it can match an empty string. This can happen more often when (?| groups are
+present in the pattern and the caching is disabled. Setting the cap at 1100
+allows the test for more than 1023 capturing patterns to work. */
+
+if ((*countptr)++ > 1100) return CBE_TOOCOMPLICATED;
+
+/* Scan the opcodes for this branch. */
+
+for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
+     code < endcode;
+     code = first_significant_code(code + PRIV(OP_lengths)[c], TRUE))
+  {
+  PCRE2_SPTR ccode;
+
+  c = *code;
+
+  /* Skip over forward assertions; the other assertions are skipped by
+  first_significant_code() with a TRUE final argument. */
+
+  if (c == OP_ASSERT)
+    {
+    do code += GET(code, 1); while (*code == OP_ALT);
+    c = *code;
+    continue;
+    }
+
+  /* For a recursion/subroutine call we can scan the recursion when this
+  function is called at the end, to check a complete pattern. Before then,
+  recursions just have the group number as their argument and in any case may
+  be forward references. In that situation, we return CBE_EMPTY, just in case.
+  It means that unlimited repeats of groups that contain recursions are always
+  treated as "could be empty" - which just adds a bit more processing time
+  because of the runtime check. */
+
+  if (c == OP_RECURSE)
+    {
+    PCRE2_SPTR scode, endgroup;
+    BOOL empty_branch;
+
+    if (!atend) goto ISTRUE;
+    scode = cb->start_code + GET(code, 1);
+    endgroup = scode;
+
+    /* We need to detect whether this is a recursive call, as otherwise there
+    will be an infinite loop. If it is a recursion, just skip over it. Simple
+    recursions are easily detected. For mutual recursions we keep a chain on
+    the stack. */
+
+    do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT);
+    if (code >= scode && code <= endgroup) continue;  /* Simple recursion */
+    else
+      {
+      recurse_check *r = recurses;
+      for (r = recurses; r != NULL; r = r->prev)
+        if (r->group == scode) break;
+      if (r != NULL) continue;   /* Mutual recursion */
+      }
+
+    /* Scan the referenced group, remembering it on the stack chain to detect
+    mutual recursions. */
+
+    empty_branch = FALSE;
+    this_recurse.prev = recurses;
+    this_recurse.group = scode;
+
+    do
+      {
+      int rc = could_be_empty_branch(scode, endcode, utf, cb, atend,
+        &this_recurse, countptr);
+      if (rc < 0) return rc;
+      if (rc > 0)
+        {
+        empty_branch = TRUE;
+        break;
+        }
+      scode += GET(scode, 1);
+      }
+    while (*scode == OP_ALT);
+
+    if (!empty_branch) goto ISFALSE;  /* All branches are non-empty */
+    continue;
+    }
+
+  /* Groups with zero repeats can of course be empty; skip them. */
+
+  if (c == OP_BRAZERO || c == OP_BRAMINZERO || c == OP_SKIPZERO ||
+      c == OP_BRAPOSZERO)
+    {
+    code += PRIV(OP_lengths)[c];
+    do code += GET(code, 1); while (*code == OP_ALT);
+    c = *code;
+    continue;
+    }
+
+  /* A nested group that is already marked as "could be empty" can just be
+  skipped. */
+
+  if (c == OP_SBRA  || c == OP_SBRAPOS ||
+      c == OP_SCBRA || c == OP_SCBRAPOS)
+    {
+    do code += GET(code, 1); while (*code == OP_ALT);
+    c = *code;
+    continue;
+    }
+
+  /* For other groups, scan the branches. */
+
+  if (c == OP_BRA  || c == OP_BRAPOS ||
+      c == OP_CBRA || c == OP_CBRAPOS ||
+      c == OP_ONCE || c == OP_ONCE_NC ||
+      c == OP_COND || c == OP_SCOND)
+    {
+    BOOL empty_branch;
+    if (GET(code, 1) == 0) goto ISTRUE;    /* Hit unclosed bracket */
+
+    /* If a conditional group has only one branch, there is a second, implied,
+    empty branch, so just skip over the conditional, because it could be empty.
+    Otherwise, scan the individual branches of the group. */
+
+    if (c == OP_COND && code[GET(code, 1)] != OP_ALT)
+      code += GET(code, 1);
+    else
+      {
+      empty_branch = FALSE;
+      do
+        {
+        if (!empty_branch)
+          {
+          int rc = could_be_empty_branch(code, endcode, utf, cb, atend,
+            recurses, countptr);
+          if (rc < 0) return rc;
+          if (rc > 0) empty_branch = TRUE;
+          }
+        code += GET(code, 1);
+        }
+      while (*code == OP_ALT);
+      if (!empty_branch) goto ISFALSE;   /* All branches are non-empty */
+      }
+
+    c = *code;
+    continue;
+    }
+
+  /* Handle the other opcodes */
+
+  switch (c)
+    {
+    /* Check for quantifiers after a class. XCLASS is used for classes that
+    cannot be represented just by a bit map. This includes negated single
+    high-valued characters. The length in PRIV(OP_lengths)[] is zero; the
+    actual length is stored in the compiled code, so we must update "code"
+    here. */
+
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+    case OP_XCLASS:
+    ccode = code += GET(code, 1);
+    goto CHECK_CLASS_REPEAT;
+#endif
+
+    case OP_CLASS:
+    case OP_NCLASS:
+    ccode = code + PRIV(OP_lengths)[OP_CLASS];
+
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+    CHECK_CLASS_REPEAT:
+#endif
+
+    switch (*ccode)
+      {
+      case OP_CRSTAR:            /* These could be empty; continue */
+      case OP_CRMINSTAR:
+      case OP_CRQUERY:
+      case OP_CRMINQUERY:
+      case OP_CRPOSSTAR:
+      case OP_CRPOSQUERY:
+      break;
+
+      default:                   /* Non-repeat => class must match */
+      case OP_CRPLUS:            /* These repeats aren't empty */
+      case OP_CRMINPLUS:
+      case OP_CRPOSPLUS:
+      goto ISFALSE;
+
+      case OP_CRRANGE:
+      case OP_CRMINRANGE:
+      case OP_CRPOSRANGE:
+      if (GET2(ccode, 1) > 0) goto ISFALSE;  /* Minimum > 0 */
+      break;
+      }
+    break;
+
+    /* Opcodes that must match a character */
+
+    case OP_ANY:
+    case OP_ALLANY:
+    case OP_ANYBYTE:
+
+    case OP_PROP:
+    case OP_NOTPROP:
+    case OP_ANYNL:
+
+    case OP_NOT_HSPACE:
+    case OP_HSPACE:
+    case OP_NOT_VSPACE:
+    case OP_VSPACE:
+    case OP_EXTUNI:
+
+    case OP_NOT_DIGIT:
+    case OP_DIGIT:
+    case OP_NOT_WHITESPACE:
+    case OP_WHITESPACE:
+    case OP_NOT_WORDCHAR:
+    case OP_WORDCHAR:
+
+    case OP_CHAR:
+    case OP_CHARI:
+    case OP_NOT:
+    case OP_NOTI:
+
+    case OP_PLUS:
+    case OP_PLUSI:
+    case OP_MINPLUS:
+    case OP_MINPLUSI:
+
+    case OP_NOTPLUS:
+    case OP_NOTPLUSI:
+    case OP_NOTMINPLUS:
+    case OP_NOTMINPLUSI:
+
+    case OP_POSPLUS:
+    case OP_POSPLUSI:
+    case OP_NOTPOSPLUS:
+    case OP_NOTPOSPLUSI:
+
+    case OP_EXACT:
+    case OP_EXACTI:
+    case OP_NOTEXACT:
+    case OP_NOTEXACTI:
+
+    case OP_TYPEPLUS:
+    case OP_TYPEMINPLUS:
+    case OP_TYPEPOSPLUS:
+    case OP_TYPEEXACT:
+    goto ISFALSE;
+
+    /* These are going to continue, as they may be empty, but we have to
+    fudge the length for the \p and \P cases. */
+
+    case OP_TYPESTAR:
+    case OP_TYPEMINSTAR:
+    case OP_TYPEPOSSTAR:
+    case OP_TYPEQUERY:
+    case OP_TYPEMINQUERY:
+    case OP_TYPEPOSQUERY:
+    if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2;
+    break;
+
+    /* Same for these */
+
+    case OP_TYPEUPTO:
+    case OP_TYPEMINUPTO:
+    case OP_TYPEPOSUPTO:
+    if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
+      code += 2;
+    break;
+
+    /* End of branch */
+
+    case OP_KET:
+    case OP_KETRMAX:
+    case OP_KETRMIN:
+    case OP_KETRPOS:
+    case OP_ALT:
+    goto ISTRUE;
+
+    /* In UTF-8 or UTF-16 mode, STAR, MINSTAR, POSSTAR, QUERY, MINQUERY,
+    POSQUERY, UPTO, MINUPTO, and POSUPTO and their caseless and negative
+    versions may be followed by a multi-code-unit character. */
+
+#ifdef MAYBE_UTF_MULTI
+    case OP_STAR:
+    case OP_STARI:
+    case OP_NOTSTAR:
+    case OP_NOTSTARI:
+
+    case OP_MINSTAR:
+    case OP_MINSTARI:
+    case OP_NOTMINSTAR:
+    case OP_NOTMINSTARI:
+
+    case OP_POSSTAR:
+    case OP_POSSTARI:
+    case OP_NOTPOSSTAR:
+    case OP_NOTPOSSTARI:
+
+    case OP_QUERY:
+    case OP_QUERYI:
+    case OP_NOTQUERY:
+    case OP_NOTQUERYI:
+
+    case OP_MINQUERY:
+    case OP_MINQUERYI:
+    case OP_NOTMINQUERY:
+    case OP_NOTMINQUERYI:
+
+    case OP_POSQUERY:
+    case OP_POSQUERYI:
+    case OP_NOTPOSQUERY:
+    case OP_NOTPOSQUERYI:
+    if (utf && HAS_EXTRALEN(code[1])) code += GET_EXTRALEN(code[1]);
+    break;
+
+    case OP_UPTO:
+    case OP_UPTOI:
+    case OP_NOTUPTO:
+    case OP_NOTUPTOI:
+
+    case OP_MINUPTO:
+    case OP_MINUPTOI:
+    case OP_NOTMINUPTO:
+    case OP_NOTMINUPTOI:
+
+    case OP_POSUPTO:
+    case OP_POSUPTOI:
+    case OP_NOTPOSUPTO:
+    case OP_NOTPOSUPTOI:
+    if (utf && HAS_EXTRALEN(code[1 + IMM2_SIZE])) code += GET_EXTRALEN(code[1 + IMM2_SIZE]);
+    break;
+#endif  /* MAYBE_UTF_MULTI */
+
+    /* MARK, and PRUNE/SKIP/THEN with an argument must skip over the argument
+    string. */
+
+    case OP_MARK:
+    case OP_PRUNE_ARG:
+    case OP_SKIP_ARG:
+    case OP_THEN_ARG:
+    code += code[1];
+    break;
+
+    /* None of the remaining opcodes are required to match a character. */
+
+    default:
+    break;
+    }
+  }
+
+ISTRUE:
+groupinfo |= GI_COULD_BE_EMPTY;
+
+ISFALSE:
+if (group > 0) cb->groupinfo[group] = groupinfo | GI_SET_COULD_BE_EMPTY;
+
+return ((groupinfo & GI_COULD_BE_EMPTY) != 0)? CBE_EMPTY : CBE_NOTEMPTY;
+}
+
+
+
+#ifdef SUPPORT_UNICODE
+/*************************************************
+*           Get othercase range                  *
+*************************************************/
+
+/* This function is passed the start and end of a class range in UCP mode. It
+searches up the characters, looking for ranges of characters in the "other"
+case. Each call returns the next one, updating the start address. A character
+with multiple other cases is returned on its own with a special return value.
+
+Arguments:
+  cptr        points to starting character value; updated
+  d           end value
+  ocptr       where to put start of othercase range
+  odptr       where to put end of othercase range
+
+Yield:        -1 when no more
+               0 when a range is returned
+              >0 the CASESET offset for char with multiple other cases
+                in this case, ocptr contains the original
+*/
+
+static int
+get_othercase_range(uint32_t *cptr, uint32_t d, uint32_t *ocptr,
+  uint32_t *odptr)
+{
+uint32_t c, othercase, next;
+unsigned int co;
+
+/* Find the first character that has an other case. If it has multiple other
+cases, return its case offset value. */
+
+for (c = *cptr; c <= d; c++)
+  {
+  if ((co = UCD_CASESET(c)) != 0)
+    {
+    *ocptr = c++;   /* Character that has the set */
+    *cptr = c;      /* Rest of input range */
+    return (int)co;
+    }
+  if ((othercase = UCD_OTHERCASE(c)) != c) break;
+  }
+
+if (c > d) return -1;  /* Reached end of range */
+
+/* Found a character that has a single other case. Search for the end of the
+range, which is either the end of the input range, or a character that has zero
+or more than one other cases. */
+
+*ocptr = othercase;
+next = othercase + 1;
+
+for (++c; c <= d; c++)
+  {
+  if ((co = UCD_CASESET(c)) != 0 || UCD_OTHERCASE(c) != next) break;
+  next++;
+  }
+
+*odptr = next - 1;     /* End of othercase range */
+*cptr = c;             /* Rest of input range */
+return 0;
+}
+#endif  /* SUPPORT_UNICODE */
+
+
+
+/*************************************************
+*        Add a character or range to a class     *
+*************************************************/
+
+/* This function packages up the logic of adding a character or range of
+characters to a class. The character values in the arguments will be within the
+valid values for the current mode (8-bit, 16-bit, UTF, etc). This function is
+mutually recursive with the function immediately below.
+
+Arguments:
+  classbits     the bit map for characters < 256
+  uchardptr     points to the pointer for extra data
+  options       the options word
+  cb            compile data
+  start         start of range character
+  end           end of range character
+
+Returns:        the number of < 256 characters added
+                the pointer to extra data is updated
+*/
+
+static unsigned int
+add_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, uint32_t options,
+  compile_block *cb, uint32_t start, uint32_t end)
+{
+uint32_t c;
+uint32_t classbits_end = (end <= 0xff ? end : 0xff);
+unsigned int n8 = 0;
+
+/* If caseless matching is required, scan the range and process alternate
+cases. In Unicode, there are 8-bit characters that have alternate cases that
+are greater than 255 and vice-versa. Sometimes we can just extend the original
+range. */
+
+if ((options & PCRE2_CASELESS) != 0)
+  {
+#ifdef SUPPORT_UNICODE
+  if ((options & PCRE2_UTF) != 0)
+    {
+    int rc;
+    uint32_t oc, od;
+
+    options &= ~PCRE2_CASELESS;   /* Remove for recursive calls */
+    c = start;
+
+    while ((rc = get_othercase_range(&c, end, &oc, &od)) >= 0)
+      {
+      /* Handle a single character that has more than one other case. */
+
+      if (rc > 0) n8 += add_list_to_class(classbits, uchardptr, options, cb,
+        PRIV(ucd_caseless_sets) + rc, oc);
+
+      /* Do nothing if the other case range is within the original range. */
+
+      else if (oc >= start && od <= end) continue;
+
+      /* Extend the original range if there is overlap, noting that if oc < c, we
+      can't have od > end because a subrange is always shorter than the basic
+      range. Otherwise, use a recursive call to add the additional range. */
+
+      else if (oc < start && od >= start - 1) start = oc; /* Extend downwards */
+      else if (od > end && oc <= end + 1)
+        {
+        end = od;       /* Extend upwards */
+        if (end > classbits_end) classbits_end = (end <= 0xff ? end : 0xff);
+        }
+      else n8 += add_to_class(classbits, uchardptr, options, cb, oc, od);
+      }
+    }
+  else
+#endif  /* SUPPORT_UNICODE */
+
+  /* Not UTF mode */
+
+  for (c = start; c <= classbits_end; c++)
+    {
+    SETBIT(classbits, cb->fcc[c]);
+    n8++;
+    }
+  }
+
+/* Now handle the original range. Adjust the final value according to the bit
+length - this means that the same lists of (e.g.) horizontal spaces can be used
+in all cases. */
+
+if ((options & PCRE2_UTF) == 0 && end > MAX_NON_UTF_CHAR)
+  end = MAX_NON_UTF_CHAR;
+
+/* Use the bitmap for characters < 256. Otherwise use extra data.*/
+
+for (c = start; c <= classbits_end; c++)
+  {
+  /* Regardless of start, c will always be <= 255. */
+  SETBIT(classbits, c);
+  n8++;
+  }
+
+#ifdef SUPPORT_WIDE_CHARS
+if (start <= 0xff) start = 0xff + 1;
+
+if (end >= start)
+  {
+  PCRE2_UCHAR *uchardata = *uchardptr;
+
+#ifdef SUPPORT_UNICODE
+  if ((options & PCRE2_UTF) != 0)
+    {
+    if (start < end)
+      {
+      *uchardata++ = XCL_RANGE;
+      uchardata += PRIV(ord2utf)(start, uchardata);
+      uchardata += PRIV(ord2utf)(end, uchardata);
+      }
+    else if (start == end)
+      {
+      *uchardata++ = XCL_SINGLE;
+      uchardata += PRIV(ord2utf)(start, uchardata);
+      }
+    }
+  else
+#endif  /* SUPPORT_UNICODE */
+
+  /* Without UTF support, character values are constrained by the bit length,
+  and can only be > 256 for 16-bit and 32-bit libraries. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+    {}
+#else
+  if (start < end)
+    {
+    *uchardata++ = XCL_RANGE;
+    *uchardata++ = start;
+    *uchardata++ = end;
+    }
+  else if (start == end)
+    {
+    *uchardata++ = XCL_SINGLE;
+    *uchardata++ = start;
+    }
+#endif
+  *uchardptr = uchardata;   /* Updata extra data pointer */
+  }
+#else
+  (void)uchardptr;          /* Avoid compiler warning */
+#endif /* SUPPORT_WIDE_CHARS */
+
+return n8;    /* Number of 8-bit characters */
+}
+
+
+
+/*************************************************
+*        Add a list of characters to a class     *
+*************************************************/
+
+/* This function is used for adding a list of case-equivalent characters to a
+class, and also for adding a list of horizontal or vertical whitespace. If the
+list is in order (which it should be), ranges of characters are detected and
+handled appropriately. This function is mutually recursive with the function
+above.
+
+Arguments:
+  classbits     the bit map for characters < 256
+  uchardptr     points to the pointer for extra data
+  options       the options word
+  cb            contains pointers to tables etc.
+  p             points to row of 32-bit values, terminated by NOTACHAR
+  except        character to omit; this is used when adding lists of
+                  case-equivalent characters to avoid including the one we
+                  already know about
+
+Returns:        the number of < 256 characters added
+                the pointer to extra data is updated
+*/
+
+static unsigned int
+add_list_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, uint32_t options,
+  compile_block *cb, const uint32_t *p, unsigned int except)
+{
+unsigned int n8 = 0;
+while (p[0] < NOTACHAR)
+  {
+  unsigned int n = 0;
+  if (p[0] != except)
+    {
+    while(p[n+1] == p[0] + n + 1) n++;
+    n8 += add_to_class(classbits, uchardptr, options, cb, p[0], p[n]);
+    }
+  p += n + 1;
+  }
+return n8;
+}
+
+
+
+/*************************************************
+*    Add characters not in a list to a class     *
+*************************************************/
+
+/* This function is used for adding the complement of a list of horizontal or
+vertical whitespace to a class. The list must be in order.
+
+Arguments:
+  classbits     the bit map for characters < 256
+  uchardptr     points to the pointer for extra data
+  options       the options word
+  cb            contains pointers to tables etc.
+  p             points to row of 32-bit values, terminated by NOTACHAR
+
+Returns:        the number of < 256 characters added
+                the pointer to extra data is updated
+*/
+
+static unsigned int
+add_not_list_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr,
+  uint32_t options, compile_block *cb, const uint32_t *p)
+{
+BOOL utf = (options & PCRE2_UTF) != 0;
+unsigned int n8 = 0;
+if (p[0] > 0)
+  n8 += add_to_class(classbits, uchardptr, options, cb, 0, p[0] - 1);
+while (p[0] < NOTACHAR)
+  {
+  while (p[1] == p[0] + 1) p++;
+  n8 += add_to_class(classbits, uchardptr, options, cb, p[0] + 1,
+    (p[1] == NOTACHAR) ? (utf ? 0x10ffffu : 0xffffffffu) : p[1] - 1);
+  p++;
+  }
+return n8;
+}
+
+
+
+/*************************************************
+*    Find details of duplicate group names       *
+*************************************************/
+
+/* This is called from compile_branch() when it needs to know the index and
+count of duplicates in the names table when processing named backreferences,
+either directly, or as conditions.
+
+Arguments:
+  name          points to the name
+  length        the length of the name
+  indexptr      where to put the index
+  countptr      where to put the count of duplicates
+  errorcodeptr  where to put an error code
+  cb            the compile block
+
+Returns:        TRUE if OK, FALSE if not, error code set
+*/
+
+static BOOL
+find_dupname_details(PCRE2_SPTR name, uint32_t length, int *indexptr,
+  int *countptr, int *errorcodeptr, compile_block *cb)
+{
+uint32_t i, groupnumber;
+int count;
+PCRE2_UCHAR *slot = cb->name_table;
+
+/* Find the first entry in the table */
+
+for (i = 0; i < cb->names_found; i++)
+  {
+  if (PRIV(strncmp)(name, slot+IMM2_SIZE, length) == 0 &&
+      slot[IMM2_SIZE+length] == 0) break;
+  slot += cb->name_entry_size;
+  }
+
+/* This should not occur, because this function is called only when we know we
+have duplicate names. Give an internal error. */
+
+if (i >= cb->names_found)
+  {
+  *errorcodeptr = ERR53;
+  cb->erroroffset = name - cb->start_pattern;
+  return FALSE;
+  }
+
+/* Record the index and then see how many duplicates there are, updating the
+backref map and maximum back reference as we do. */
+
+*indexptr = i;
+count = 0;
+
+for (;;)
+  {
+  count++;
+  groupnumber = GET2(slot,0);
+  cb->backref_map |= (groupnumber < 32)? (1u << groupnumber) : 1;
+  if (groupnumber > cb->top_backref) cb->top_backref = groupnumber;
+  if (++i >= cb->names_found) break;
+  slot += cb->name_entry_size;
+  if (PRIV(strncmp)(name, slot+IMM2_SIZE, length) != 0 ||
+    (slot+IMM2_SIZE)[length] != 0) break;
+  }
+
+*countptr = count;
+return TRUE;
+}
+
+
+
+/*************************************************
 *           Compile one branch                   *
 *************************************************/


-/* Scan the pattern, compiling it into the a vector. If the options are
-changed during the branch, the pointer is used to change the external options
-bits. This function is used during the pre-compile phase when we are trying
-to find out the amount of memory needed, as well as during the real compile
-phase. The value of lengthptr distinguishes the two phases.
+/* Scan the parsed pattern, compiling it into the a vector of PCRE2_UCHAR. If
+the options are changed during the branch, the pointer is used to change the
+external options bits. This function is used during the pre-compile phase when
+we are trying to find out the amount of memory needed, as well as during the
+real compile phase. The value of lengthptr distinguishes the two phases.

 Arguments:
   optionsptr        pointer to the option bits
   codeptr           points to the pointer to the current code point
-  ptrptr            points to the current pattern pointer
+  pptrptr           points to the current parsed pattern pointer
   errorcodeptr      points to error code variable
   firstcuptr        place to put the first required code unit
   firstcuflagsptr   place to put the first code unit flags, or a negative number
@@ -3842,7 +4783,6 @@
   reqcuptr          place to put the last required code unit
   reqcuflagsptr     place to put the last required code unit flags, or a negative number
   bcptr             points to current branch chain
-  cond_depth        conditional nesting depth
   cb                contains pointers to tables etc.
   lengthptr         NULL during the real compile phase
                     points to length accumulator during pre-compile phase
@@ -3852,37 +4792,34 @@
 */


 static BOOL
-compile_branch(uint32_t *optionsptr, PCRE2_UCHAR **codeptr,
-  PCRE2_SPTR *ptrptr, int *errorcodeptr,
-  uint32_t *firstcuptr, int32_t *firstcuflagsptr,
-  uint32_t *reqcuptr, int32_t *reqcuflagsptr,
-  branch_chain *bcptr, int cond_depth,
-  compile_block *cb, size_t *lengthptr)
+compile_branch(uint32_t *optionsptr, PCRE2_UCHAR **codeptr, uint32_t **pptrptr,
+  int *errorcodeptr, uint32_t *firstcuptr, int32_t *firstcuflagsptr,
+  uint32_t *reqcuptr, int32_t *reqcuflagsptr, branch_chain *bcptr,
+  compile_block *cb, PCRE2_SIZE *lengthptr)
 {
-int repeat_min = 0, repeat_max = 0;      /* To please picky compilers */
 int bravalue = 0;
+uint32_t repeat_min = 0, repeat_max = 0;      /* To please picky compilers */
 uint32_t greedy_default, greedy_non_default;
 uint32_t repeat_type, op_type;
 uint32_t options = *optionsptr;               /* May change dynamically */
 uint32_t firstcu, reqcu;
+uint32_t zeroreqcu, zerofirstcu;
+uint32_t escape;
+uint32_t *pptr = *pptrptr;
+uint32_t meta, meta_arg;
 int32_t firstcuflags, reqcuflags;
-uint32_t zeroreqcu, zerofirstcu;
 int32_t zeroreqcuflags, zerofirstcuflags;
 int32_t req_caseopt, reqvary, tempreqvary;
-int after_manual_callout = 0;
-int escape;
-size_t length_prevgroup = 0;
-register uint32_t c;
-register PCRE2_UCHAR *code = *codeptr;
+PCRE2_SIZE offset = 0;
+PCRE2_SIZE length_prevgroup = 0;
+PCRE2_UCHAR *code = *codeptr;
 PCRE2_UCHAR *last_code = code;
 PCRE2_UCHAR *orig_code = code;
 PCRE2_UCHAR *tempcode;
-BOOL inescq = FALSE;
+PCRE2_UCHAR *previous = NULL;
+PCRE2_UCHAR op_previous;
 BOOL groupsetfirstcu = FALSE;
-PCRE2_SPTR ptr = *ptrptr;
-PCRE2_SPTR tempptr;
-PCRE2_UCHAR *previous = NULL;
-PCRE2_UCHAR *previous_callout = NULL;
+const uint8_t *cbits = cb->cbits;
 uint8_t classbits[32];


/* We can fish out the UTF setting once and for all into a BOOL, but we must
@@ -3891,10 +4828,6 @@

 #ifdef SUPPORT_UNICODE
 BOOL utf = (options & PCRE2_UTF) != 0;
-#if PCRE2_CODE_UNIT_WIDTH != 32
-PCRE2_UCHAR utf_units[6];      /* For setting up multi-cu chars */
-#endif
-
 #else  /* No UTF support */
 BOOL utf = FALSE;
 #endif
@@ -3935,57 +4868,36 @@


req_caseopt = ((options & PCRE2_CASELESS) != 0)? REQ_CASELESS:0;

-/* Switch on next character until the end of the branch */
+/* Switch on next META item until the end of the branch */

-for (;; ptr++)
+for (;; pptr++)
   {
+#ifdef SUPPORT_WIDE_CHARS
+  BOOL xclass_has_prop;
+#endif
   BOOL negate_class;
   BOOL should_flip_negation;
   BOOL match_all_or_no_wide_chars;
   BOOL possessive_quantifier;
-  BOOL is_quantifier;
-  BOOL is_recurse;
-  BOOL is_dupname;
-  BOOL reset_bracount;
   int class_has_8bitchar;
-  int class_one_char;
-#ifdef SUPPORT_WIDE_CHARS
-  BOOL xclass_has_prop;
-#endif
-  int recno;                               /* Must be signed */
-  int refsign;                             /* Must be signed */
-  int terminator;                          /* Must be signed */
-  unsigned int mclength;
-  unsigned int tempbracount;
-  uint32_t ec;
-  uint32_t newoptions;
+  int i;
+  uint32_t mclength;
+  uint32_t templastcapture;
   uint32_t skipunits;
   uint32_t subreqcu, subfirstcu;
+  uint32_t groupnumber;
+  uint32_t verbarglen, verbculen;
   int32_t subreqcuflags, subfirstcuflags;  /* Must be signed */
+  open_capitem *oc;
   PCRE2_UCHAR mcbuffer[8];


- /* Come here to restart the loop. */
+ /* Get next META item in the pattern and its potential argument. */

- REDO_LOOP:
+ meta = META_CODE(*pptr);
+ meta_arg = META_DATA(*pptr);

-  /* Get next character in the pattern */
-
-  c = *ptr;
-
-  /* If we are at the end of a nested substitution, revert to the outer level
-  string. Nesting only happens one or two levels deep, and the inserted string
-  is always zero terminated. */
-
-  if (c == CHAR_NULL && cb->nestptr[0] != NULL)
-    {
-    ptr = cb->nestptr[0];
-    cb->nestptr[0] = cb->nestptr[1];
-    cb->nestptr[1] = NULL;
-    c = *ptr;
-    }
-
   /* If we are in the pre-compile phase, accumulate the length used for the
-  previous cycle of this loop. */
+  previous cycle of this loop, unless the next item is a quantifier. */


   if (lengthptr != NULL)
     {
@@ -3994,193 +4906,61 @@
       {
       *errorcodeptr = (code >= cb->start_workspace + cb->workspace_size)?
         ERR52 : ERR86;
-      goto FAILED;
+      return FALSE;
       }


     /* There is at least one situation where code goes backwards: this is the
-    case of a zero quantifier after a class (e.g. [ab]{0}). At compile time,
-    the class is simply eliminated. However, it is created first, so we have to
-    allow memory for it. Therefore, don't ever reduce the length at this point.
-    */
+    case of a zero quantifier after a class (e.g. [ab]{0}). When the quantifier
+    is processed, the whole class is eliminated. However, it is created first,
+    so we have to allow memory for it. Therefore, don't ever reduce the length
+    at this point. */


     if (code < last_code) code = last_code;


-    /* Paranoid check for integer overflow */
+    /* If the next thing is not a quantifier, we add the length of the previous
+    item into the total, and reset the code pointer to the start of the
+    workspace. Otherwise leave the previous item available to be quantified. */


-    if (OFLOW_MAX - *lengthptr < (size_t)(code - last_code))
+    if (meta < META_ASTERISK || meta > META_MINMAX_QUERY)
       {
-      *errorcodeptr = ERR20;
-      goto FAILED;
-      }
-    *lengthptr += (size_t)(code - last_code);
-
-    /* If "previous" is set and it is not at the start of the work space, move
-    it back to there, in order to avoid filling up the work space. Otherwise,
-    if "previous" is NULL, reset the current code pointer to the start. */
-
-    if (previous != NULL)
-      {
-      if (previous > orig_code)
+      if (OFLOW_MAX - *lengthptr < (PCRE2_SIZE)(code - orig_code))
         {
-        memmove(orig_code, previous, (size_t)CU2BYTES(code - previous));
-        code -= previous - orig_code;
-        previous = orig_code;
+        *errorcodeptr = ERR20;   /* Integer overflow */
+        return FALSE;
         }
+      *lengthptr += (PCRE2_SIZE)(code - orig_code);
+      code = orig_code;
       }
-    else code = orig_code;


-    /* Remember where this code item starts so we can pick up the length
-    next time round. */
+    /* Remember where this code item starts so we can catch the "backwards"
+    case above next time round. */


     last_code = code;
     }


- /* Before doing anything else we must handle all the special items that do
- nothing, and which may come between an item and its quantifier. Otherwise,
- when auto-callouts are enabled, a callout gets incorrectly inserted before
- the quantifier is recognized. After recognizing a "do nothing" item, restart
- the loop in case another one follows. */
+ /* Process the next parsed pattern item. If it is not a quantifier, remember
+ where it starts so that it can be quantified when a quantifier follows.
+ Checking for the legality of quantifiers happens in parse_regex(), except for
+ a quantifier after an assertion that is a condition. */

- /* If c is not NULL we are not at the end of the pattern. If it is NULL, we
- may still be in the pattern with a NULL data item. In these cases, if we are
- in \Q...\E, check for the \E that ends the literal string; if not, we have a
- literal character. If not in \Q...\E, an isolated \E is ignored. */
+ if (meta < META_ASTERISK || meta > META_MINMAX_QUERY) previous = code;

-  if (c != CHAR_NULL || ptr < cb->end_pattern)
-    {
-    if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E)
-      {
-      inescq = FALSE;
-      ptr++;
-      continue;
-      }
-    else if (inescq)   /* Literal character */
-      {
-      if (previous_callout != NULL)
-        {
-        if (lengthptr == NULL)  /* Don't attempt in pre-compile phase */
-          complete_callout(previous_callout, ptr, cb);
-        previous_callout = NULL;
-        }
-      if ((options & PCRE2_AUTO_CALLOUT) != 0)
-        {
-        previous_callout = code;
-        code = auto_callout(code, ptr, cb);
-        }
-      goto NORMAL_CHAR;
-      }
+  skipunits = 0;  /* Default value for most subgroups */


-    /* Check for the start of a \Q...\E sequence. We must do this here rather
-    than later in case it is immediately followed by \E, which turns it into a
-    "do nothing" sequence. */
-
-    if (c == CHAR_BACKSLASH && ptr[1] == CHAR_Q)
-      {
-      inescq = TRUE;
-      ptr++;
-      continue;
-      }
-    }
-
-  /* In extended mode, skip white space and #-comments that end at newline. */
-
-  if ((options & PCRE2_EXTENDED) != 0)
+  switch(meta)
     {
-    PCRE2_SPTR wscptr = ptr;
-    while (MAX_255(c) && (cb->ctypes[c] & ctype_space) != 0) c = *(++ptr);
-    if (c == CHAR_NUMBER_SIGN)
-      {
-      ptr++;
-      while (ptr < cb->end_pattern)
-        {
-        if (IS_NEWLINE(ptr))         /* For non-fixed-length newline cases, */
-          {                          /* IS_NEWLINE sets cb->nllen. */
-          ptr += cb->nllen;
-          break;
-          }
-        ptr++;
-#ifdef SUPPORT_UNICODE
-        if (utf) FORWARDCHAR(ptr);
-#endif
-        }
-      }
-
-    /* If we skipped any characters, restart the loop. Otherwise, we didn't see
-    a comment. */
-
-    if (ptr > wscptr) goto REDO_LOOP;
-    }
-
-  /* Skip over (?# comments. */
-
-  if (c == CHAR_LEFT_PARENTHESIS && ptr[1] == CHAR_QUESTION_MARK &&
-      ptr[2] == CHAR_NUMBER_SIGN)
-    {
-    ptr += 3;
-    while (ptr < cb->end_pattern && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++;
-    if (*ptr != CHAR_RIGHT_PARENTHESIS)
-      {
-      *errorcodeptr = ERR18;
-      goto FAILED;
-      }
-    continue;
-    }
-
-  /* End of processing "do nothing" items. See if the next thing is a
-  quantifier. */
-
-  is_quantifier =
-    c == CHAR_ASTERISK || c == CHAR_PLUS || c == CHAR_QUESTION_MARK ||
-     (c == CHAR_LEFT_CURLY_BRACKET && is_counted_repeat(ptr+1));
-
-  /* Fill in length of a previous callout and create an auto callout if
-  required, except when the next thing is a quantifier or when processing a
-  property substitution string for \w etc in UCP mode. */
-
-  if (!is_quantifier && cb->nestptr[0] == NULL)
-    {
-    if (previous_callout != NULL && after_manual_callout-- <= 0)
-      {
-      if (lengthptr == NULL)      /* Don't attempt in pre-compile phase */
-        complete_callout(previous_callout, ptr, cb);
-      previous_callout = NULL;
-      }
-
-    if ((options & PCRE2_AUTO_CALLOUT) != 0)
-      {
-      previous_callout = code;
-      code = auto_callout(code, ptr, cb);
-      }
-    }
-
-  /* Process the next pattern item. */
-
-  switch(c)
-    {
     /* ===================================================================*/
-    /* The branch terminates at string end or | or ) */
+    /* The branch terminates at pattern end or | or ) */


-    case CHAR_NULL:
-    if (ptr < cb->end_pattern) goto NORMAL_CHAR;   /* Zero data character */
-    /* Fall through */
-
-    case CHAR_VERTICAL_LINE:
-    case CHAR_RIGHT_PARENTHESIS:
+    case META_END:
+    case META_ALT:
+    case META_KET:
     *firstcuptr = firstcu;
     *firstcuflagsptr = firstcuflags;
     *reqcuptr = reqcu;
     *reqcuflagsptr = reqcuflags;
     *codeptr = code;
-    *ptrptr = ptr;
-    if (lengthptr != NULL)
-      {
-      if (OFLOW_MAX - *lengthptr < (size_t)(code - last_code))
-        {
-        *errorcodeptr = ERR20;
-        goto FAILED;
-        }
-      *lengthptr += (size_t)(code - last_code);  /* To include callout length */
-      }
+    *pptrptr = pptr;
     return TRUE;



@@ -4188,8 +4968,7 @@
     /* Handle single-character metacharacters. In multiline mode, ^ disables
     the setting of any following char as a first character. */


-    case CHAR_CIRCUMFLEX_ACCENT:
-    previous = NULL;
+    case META_CIRCUMFLEX:
     if ((options & PCRE2_MULTILINE) != 0)
       {
       if (firstcuflags == REQ_UNSET)
@@ -4199,8 +4978,7 @@
     else *code++ = OP_CIRC;
     break;


-    case CHAR_DOLLAR_SIGN:
-    previous = NULL;
+    case META_DOLLAR:
     *code++ = ((options & PCRE2_MULTILINE) != 0)? OP_DOLLM : OP_DOLL;
     break;


@@ -4207,109 +4985,102 @@
     /* There can never be a first char if '.' is first, whatever happens about
     repeats. The value of reqcu doesn't change either. */


-    case CHAR_DOT:
+    case META_DOT:
     if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
     zerofirstcu = firstcu;
     zerofirstcuflags = firstcuflags;
     zeroreqcu = reqcu;
     zeroreqcuflags = reqcuflags;
-    previous = code;
     *code++ = ((options & PCRE2_DOTALL) != 0)? OP_ALLANY: OP_ANY;
     break;



     /* ===================================================================*/
-    /* Character classes. If the included characters are all < 256, we build a
-    32-byte bitmap of the permitted characters, except in the special case
-    where there is only one such character. For negated classes, we build the
-    map as usual, then invert it at the end. However, we use a different opcode
-    so that data characters > 255 can be handled correctly.
+    /* Empty character classes are allowed if PCRE2_ALLOW_EMPTY_CLASS is set.
+    Otherwise, an initial ']' is taken as a data character. When empty classes
+    are allowed, [] must always fail, so generate OP_FAIL, whereas [^] must
+    match any character, so generate OP_ALLANY. */


+    case META_CLASS_EMPTY:
+    case META_CLASS_EMPTY_NOT:
+    *code++ = (meta == META_CLASS_EMPTY_NOT)? OP_ALLANY : OP_FAIL;
+    if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+    zerofirstcu = firstcu;
+    zerofirstcuflags = firstcuflags;
+    break;
+
+
+    /* ===================================================================*/
+    /* Non-empty character class. If the included characters are all < 256, we
+    build a 32-byte bitmap of the permitted characters, except in the special
+    case where there is only one such character. For negated classes, we build
+    the map as usual, then invert it at the end. However, we use a different
+    opcode so that data characters > 255 can be handled correctly.
+
     If the class contains characters outside the 0-255 range, a different
     opcode is compiled. It may optionally have a bit map for characters < 256,
-    but those above are are explicitly listed afterwards. A flag byte tells
-    whether the bitmap is present, and whether this is a negated class or not.
+    but those above are are explicitly listed afterwards. A flag code unit
+    tells whether the bitmap is present, and whether this is a negated class or
+    not. */


-    An isolated ']' character is not treated specially, so is just another data
-    character. In earlier versions of PCRE that used the original API there was
-    a "JavaScript compatibility mode" in which it gave an error. However,
-    JavaScript itself has changed in this respect so there is no longer any
-    need for this special handling.
+    case META_CLASS_NOT:
+    case META_CLASS:
+    negate_class = meta == META_CLASS_NOT;


-    In another (POSIX) regex library, the ugly syntax [[:<:]] and [[:>:]] is
-    used for "start of word" and "end of word". As these are otherwise illegal
-    sequences, we don't break anything by recognizing them. They are replaced
-    by \b(?=\w) and \b(?<=\w) respectively. This can only happen at the top
-    nesting level, as no other inserted sequences will contains these oddities.
-    Sequences like [a[:<:]] are erroneous and are handled by the normal code
-    below. */
+    /* We can optimize the case of a single character in a class by generating
+    OP_CHAR or OP_CHARI if it's positive, or OP_NOT or OP_NOTI if it's
+    negative. In the negative case there can be no first char if this item is
+    first, whatever repeat count may follow. In the case of reqcu, save the
+    previous value for reinstating. */


-    case CHAR_LEFT_SQUARE_BRACKET:
-    if (PRIV(strncmp_c8)(ptr+1, STRING_WEIRD_STARTWORD, 6) == 0)
-      {
-      cb->nestptr[0] = ptr + 7;
-      ptr = sub_start_of_word;
-      goto REDO_LOOP;
-      }
+    /* NOTE: at present this optimization is not effective if the only
+    character in a class in 32-bit, non-UCP mode has its top bit set. */


-    if (PRIV(strncmp_c8)(ptr+1, STRING_WEIRD_ENDWORD, 6) == 0)
+    if (pptr[1] < META_END && pptr[2] == META_CLASS_END)
       {
-      cb->nestptr[0] = ptr + 7;
-      ptr = sub_end_of_word;
-      goto REDO_LOOP;
-      }
+#ifdef SUPPORT_UNICODE
+      uint32_t d;
+#endif
+      uint32_t c = pptr[1];


-    /* Handle a real character class. */
+      pptr += 2;                 /* Move on to class end */
+      if (meta == META_CLASS)    /* A positive one-char class can be */
+        {                        /* handled as a normal literal character. */
+        meta = c;                /* Set up the character */
+        goto NORMAL_CHAR_SET;
+        }


-    previous = code;
+      /* Handle a negative one-character class */


-    /* PCRE supports POSIX class stuff inside a class. Perl gives an error if
-    they are encountered at the top level, so we'll do that too. */
+      zeroreqcu = reqcu;
+      zeroreqcuflags = reqcuflags;
+      if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+      zerofirstcu = firstcu;
+      zerofirstcuflags = firstcuflags;


-    if ((ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT ||
-         ptr[1] == CHAR_EQUALS_SIGN) &&
-        check_posix_syntax(ptr, &tempptr))
-      {
-      *errorcodeptr = (ptr[1] == CHAR_COLON)? ERR12 : ERR13;
-      goto FAILED;
-      }
+      /* For caseless UTF mode, check whether this character has more than
+      one other case. If so, generate a special OP_NOTPROP item instead of
+      OP_NOTI. */


-    /* If the first character is '^', set the negation flag and skip it. Also,
-    if the first few characters (either before or after ^) are \Q\E or \E we
-    skip them too. This makes for compatibility with Perl. */
-
-    negate_class = FALSE;
-    for (;;)
-      {
-      c = *(++ptr);
-      if (c == CHAR_BACKSLASH)
+#ifdef SUPPORT_UNICODE
+      if (utf && (options & PCRE2_CASELESS) != 0 &&
+          (d = UCD_CASESET(c)) != 0)
         {
-        if (ptr[1] == CHAR_E)
-          ptr++;
-        else if (PRIV(strncmp_c8)(ptr + 1, STR_Q STR_BACKSLASH STR_E, 3) == 0)
-          ptr += 3;
-        else
-          break;
+        *code++ = OP_NOTPROP;
+        *code++ = PT_CLIST;
+        *code++ = d;
+        break;   /* We are finished with this class */
         }
-      else if (!negate_class && c == CHAR_CIRCUMFLEX_ACCENT)
-        negate_class = TRUE;
-      else break;
-      }
+#endif
+      /* Char has only one other case, or UCP not available */


-    /* Empty classes are allowed if PCRE2_ALLOW_EMPTY_CLASS is set. Otherwise,
-    an initial ']' is taken as a data character -- the code below handles
-    that. When empty classes are allowed, [] must always fail, so generate
-    OP_FAIL, whereas [^] must match any character, so generate OP_ALLANY. */
+      *code++ = ((options & PCRE2_CASELESS) != 0)? OP_NOTI: OP_NOT;
+      code += PUTCHAR(c, code);
+      break;   /* We are finished with this class */
+      }        /* End of 1-char optimization */


-    if (c == CHAR_RIGHT_SQUARE_BRACKET &&
-        (cb->external_options & PCRE2_ALLOW_EMPTY_CLASS) != 0)
-      {
-      *code++ = negate_class? OP_ALLANY : OP_FAIL;
-      if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
-      zerofirstcu = firstcu;
-      zerofirstcuflags = firstcuflags;
-      break;
-      }
+    /* Handle character classes that contain more than just one literal
+    character. */


     /* If a non-extended class contains a negative special such as \S, we need
     to flip the negation flag at the end, so that support for characters > 255
@@ -4329,13 +5100,11 @@
 #endif


     /* For optimization purposes, we track some properties of the class:
-    class_has_8bitchar will be non-zero if the class contains at least one 256
-    character with a code point less than 256; class_one_char will be 1 if the
-    class contains just one character; xclass_has_prop will be TRUE if Unicode
-    property checks are present in the class. */
+    class_has_8bitchar will be non-zero if the class contains at least one
+    character with a code point less than 256; xclass_has_prop will be TRUE if
+    Unicode property checks are present in the class. */


     class_has_8bitchar = 0;
-    class_one_char = 0;
 #ifdef SUPPORT_WIDE_CHARS
     xclass_has_prop = FALSE;
 #endif
@@ -4347,156 +5116,73 @@


     memset(classbits, 0, 32 * sizeof(uint8_t));


-    /* Process characters until ] is reached. As the test is at the end of the
-    loop, an initial ] is taken as a data character. At the start of the loop,
-    c contains the first code unit of the character. If it is zero, check for
-    the end of the pattern, to allow binary zero as data. */
+    /* Process items until META_CLASS_END is reached. */


-    for(;;)
+    while ((meta = *(++pptr)) != META_CLASS_END)
       {
-      PCRE2_SPTR oldptr;
-#ifdef EBCDIC
-      BOOL range_is_literal = TRUE;
-#endif
+      /* Handle POSIX classes such as [:alpha:] etc. */


-      if (c == CHAR_NULL && ptr >= cb->end_pattern)
+      if (meta == META_POSIX || meta == META_POSIX_NEG)
         {
-        *errorcodeptr = ERR6;  /* Missing terminating ']' */
-        goto FAILED;
-        }
-
-#ifdef SUPPORT_UNICODE
-      if (utf && HAS_EXTRALEN(c))
-        {                           /* Braces are required because the */
-        GETCHARLEN(c, ptr, ptr);    /* macro generates multiple statements */
-        }
-#endif
-
-      /* Inside \Q...\E everything is literal except \E */
-
-      if (inescq)
-        {
-        if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E)  /* If we are at \E */
-          {
-          inescq = FALSE;                   /* Reset literal state */
-          ptr++;                            /* Skip the 'E' */
-          goto CONTINUE_CLASS;              /* Carry on with next char */
-          }
-        goto CHECK_RANGE;                   /* Could be range if \E follows */
-        }
-
-      /* Handle POSIX class names. Perl allows a negation extension of the
-      form [:^name:]. A square bracket that doesn't match the syntax is
-      treated as a literal. We also recognize the POSIX constructions
-      [.ch.] and [=ch=] ("collating elements") and fault them, as Perl
-      5.6 and 5.8 do. */
-
-      if (c == CHAR_LEFT_SQUARE_BRACKET &&
-          (ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT ||
-           ptr[1] == CHAR_EQUALS_SIGN) && check_posix_syntax(ptr, &tempptr))
-        {
-        BOOL local_negate = FALSE;
-        int posix_class, taboffset, tabopt;
-        register const uint8_t *cbits = cb->cbits;
+        BOOL local_negate = (meta == META_POSIX_NEG);
+        int posix_class = *(++pptr);
+        int taboffset, tabopt;
         uint8_t pbits[32];


-        if (ptr[1] != CHAR_COLON)
-          {
-          *errorcodeptr = ERR13;
-          goto FAILED;
-          }
+        should_flip_negation = local_negate;  /* Note negative special */


-        ptr += 2;
-        if (*ptr == CHAR_CIRCUMFLEX_ACCENT)
-          {
-          local_negate = TRUE;
-          should_flip_negation = TRUE;  /* Note negative special */
-          ptr++;
-          }
+        /* If matching is caseless, upper and lower are converted to alpha.
+        This relies on the fact that the class table starts with alpha,
+        lower, upper as the first 3 entries. */


-        posix_class = check_posix_name(ptr, (int)(tempptr - ptr));
-        if (posix_class < 0)
-          {
-          *errorcodeptr = ERR30;
-          goto FAILED;
-          }
-
-        /* If matching is caseless, upper and lower are converted to
-        alpha. This relies on the fact that the class table starts with
-        alpha, lower, upper as the first 3 entries. */
-
         if ((options & PCRE2_CASELESS) != 0 && posix_class <= 2)
           posix_class = 0;


         /* When PCRE2_UCP is set, some of the POSIX classes are converted to
-        different escape sequences that use Unicode properties \p or \P. Others
-        that are not available via \p or \P generate XCL_PROP/XCL_NOTPROP
-        directly. UCP support is not available unless UTF support is.*/
+        different escape sequences that use Unicode properties \p or \P.
+        Others that are not available via \p or \P have to generate
+        XCL_PROP/XCL_NOTPROP directly, which is done here. */


 #ifdef SUPPORT_UNICODE
-        if ((options & PCRE2_UCP) != 0)
+        if ((options & PCRE2_UCP) != 0) switch(posix_class)
           {
-          unsigned int ptype = 0;
-          int pc = posix_class + ((local_negate)? POSIX_SUBSIZE/2 : 0);
+          case PC_GRAPH:
+          case PC_PRINT:
+          case PC_PUNCT:
+          *class_uchardata++ = local_negate? XCL_NOTPROP : XCL_PROP;
+          *class_uchardata++ = (PCRE2_UCHAR)
+            ((posix_class == PC_GRAPH)? PT_PXGRAPH :
+             (posix_class == PC_PRINT)? PT_PXPRINT : PT_PXPUNCT);
+          *class_uchardata++ = 0;
+          xclass_has_prop = TRUE;
+          goto CONTINUE_CLASS;


-          /* The posix_substitutes table specifies which POSIX classes can be
-          converted to \p or \P items. This can only happen at top nestling
-          level, as there will never be a POSIX class in a string that is
-          substituted for something else. */
+          /* For the other POSIX classes (ascii, xdigit) we are going to
+          fall through to the non-UCP case and build a bit map for
+          characters with code points less than 256. However, if we are in
+          a negated POSIX class, characters with code points greater than
+          255 must either all match or all not match, depending on whether
+          the whole class is not or is negated. For example, for
+          [[:^ascii:]... they must all match, whereas for [^[:^xdigit:]...
+          they must not.


-          if (posix_substitutes[pc] != NULL)
-            {
-            cb->nestptr[0] = tempptr + 1;
-            ptr = posix_substitutes[pc] - 1;
-            goto CONTINUE_CLASS;
-            }
+          In the special case where there are no xclass items, this is
+          automatically handled by the use of OP_CLASS or OP_NCLASS, but an
+          explicit range is needed for OP_XCLASS. Setting a flag here
+          causes the range to be generated later when it is known that
+          OP_XCLASS is required. */


-          /* There are three other classes that generate special property calls
-          that are recognized only in an XCLASS. */
-
-          else switch(posix_class)
-            {
-            case PC_GRAPH:
-            ptype = PT_PXGRAPH;
-            /* Fall through */
-            case PC_PRINT:
-            if (ptype == 0) ptype = PT_PXPRINT;
-            /* Fall through */
-            case PC_PUNCT:
-            if (ptype == 0) ptype = PT_PXPUNCT;
-            *class_uchardata++ = local_negate? XCL_NOTPROP : XCL_PROP;
-            *class_uchardata++ = (PCRE2_UCHAR)ptype;
-            *class_uchardata++ = 0;
-            xclass_has_prop = TRUE;
-            ptr = tempptr + 1;
-            goto CONTINUE_CLASS;
-
-            /* For the other POSIX classes (ascii, xdigit) we are going to fall
-            through to the non-UCP case and build a bit map for characters with
-            code points less than 256. However, if we are in a negated POSIX
-            class, characters with code points greater than 255 must either all
-            match or all not match, depending on whether the whole class is not
-            or is negated. For example, for [[:^ascii:]... they must all match,
-            whereas for [^[:^xdigit:]... they must not.
-
-            In the special case where there are no xclass items, this is
-            automatically handled by the use of OP_CLASS or OP_NCLASS, but an
-            explicit range is needed for OP_XCLASS. Setting a flag here causes
-            the range to be generated later when it is known that OP_XCLASS is
-            required. */
-
-            default:
-            match_all_or_no_wide_chars |= local_negate;
-            break;
-            }
+          default:
+          match_all_or_no_wide_chars |= local_negate;
+          break;
           }
 #endif  /* SUPPORT_UNICODE */


         /* In the non-UCP case, or when UCP makes no difference, we build the
-        bit map for the POSIX class in a chunk of local store because we may be
-        adding and subtracting from it, and we don't want to subtract bits that
-        may be in the main map already. At the end we or the result into the
-        bit map that is being built. */
+        bit map for the POSIX class in a chunk of local store because we may
+        be adding and subtracting from it, and we don't want to subtract bits
+        that may be in the main map already. At the end we or the result into
+        the bit map that is being built. */


         posix_class *= 3;


@@ -4513,9 +5199,9 @@
         if (taboffset >= 0)
           {
           if (tabopt >= 0)
-            for (c = 0; c < 32; c++) pbits[c] |= cbits[(int)c + taboffset];
+            for (i = 0; i < 32; i++) pbits[i] |= cbits[(int)i + taboffset];
           else
-            for (c = 0; c < 32; c++) pbits[c] &= ~cbits[(int)c + taboffset];
+            for (i = 0; i < 32; i++) pbits[i] &= ~cbits[(int)i + taboffset];
           }


         /* Now see if we need to remove any special characters. An option
@@ -4529,432 +5215,214 @@
         being built and we are done. */


         if (local_negate)
-          for (c = 0; c < 32; c++) classbits[c] |= ~pbits[c];
+          for (i = 0; i < 32; i++) classbits[i] |= ~pbits[i];
         else
-          for (c = 0; c < 32; c++) classbits[c] |= pbits[c];
+          for (i = 0; i < 32; i++) classbits[i] |= pbits[i];


-        ptr = tempptr + 1;
         /* Every class contains at least one < 256 character. */
+
         class_has_8bitchar = 1;
-        /* Every class contains at least two characters. */
-        class_one_char = 2;
-        goto CONTINUE_CLASS;    /* End of POSIX syntax handling */
+        goto CONTINUE_CLASS;    /* End of POSIX handling */
         }


-      /* Backslash may introduce a single character, or it may introduce one
-      of the specials, which just set a flag. The sequence \b is a special
-      case. Inside a class (and only there) it is treated as backspace. We
-      assume that other escapes have more than one character in them, so
-      speculatively set both class_has_8bitchar and class_one_char bigger
-      than one. Unrecognized escapes fall through and are faulted. */
+      /* Other than POSIX classes, the only items we should encounter are
+      \d-type escapes and literal characters (possibly as ranges). */


-      if (c == CHAR_BACKSLASH)
+      if (meta == META_BIGVALUE)
         {
-        escape = PRIV(check_escape)(&ptr, cb->end_pattern, &ec, errorcodeptr,
-          options, TRUE, cb);
-        if (*errorcodeptr != 0) goto FAILED;
-        if (escape == 0)    /* Escaped single char */
+        meta = *(++pptr);
+        goto CLASS_LITERAL;
+        }
+
+      /* Any other non-literal must be an escape */
+
+      if (meta > META_END)
+        {
+        if (META_CODE(meta) != META_ESCAPE)
           {
-          c = ec;
-#ifdef EBCDIC
-          range_is_literal = FALSE;
+#ifdef DEBUG_SHOW_PARSED
+          fprintf(stderr, "** Unrecognized parsed pattern item 0x%.8x "
+                          "in character class", meta);
 #endif
+          *errorcodeptr = ERR89;  /* Internal error - unrecognized. */
+          return FALSE;
           }
-        else if (escape == ESC_b) c = CHAR_BS; /* \b is backspace in a class */
-        else if (escape == ESC_N)          /* \N is not supported in a class */
-          {
-          *errorcodeptr = ERR71;
-          goto FAILED;
-          }
-        else if (escape == ESC_Q)            /* Handle start of quoted string */
-          {
-          if (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E)
-            {
-            ptr += 2; /* avoid empty string */
-            }
-          else inescq = TRUE;
-          goto CONTINUE_CLASS;
-          }
-        else if (escape == ESC_E) goto CONTINUE_CLASS;  /* Ignore orphan \E */
+        escape = META_DATA(meta);


-        else  /* Handle \d-type escapes */
-          {
-          register const uint8_t *cbits = cb->cbits;
-          /* Every class contains at least two < 256 characters. */
-          class_has_8bitchar++;
-          /* Every class contains at least two characters. */
-          class_one_char += 2;
+        /* Every class contains at least one < 256 character. */


-          switch (escape)
-            {
-#ifdef SUPPORT_UNICODE
-            case ESC_du:     /* These are the values given for \d etc */
-            case ESC_DU:     /* when PCRE2_UCP is set. We replace the */
-            case ESC_wu:     /* escape sequence with an appropriate \p */
-            case ESC_WU:     /* or \P to test Unicode properties instead */
-            case ESC_su:     /* of the default ASCII testing. This might be */
-            case ESC_SU:     /* a 2nd-level nesting for [[:<:]] or [[:>:]]. */
-            cb->nestptr[1] = cb->nestptr[0];
-            cb->nestptr[0] = ptr;
-            ptr = substitutes[escape - ESC_DU] - 1;  /* Just before substitute */
-            class_has_8bitchar--;                /* Undo! */
-            break;
-#endif
-            case ESC_d:
-            for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_digit];
-            break;
+        class_has_8bitchar++;


-            case ESC_D:
-            should_flip_negation = TRUE;
-            for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_digit];
-            break;
+        switch(escape)
+          {
+          case ESC_d:
+          for (i = 0; i < 32; i++) classbits[i] |= cbits[i+cbit_digit];
+          break;


-            case ESC_w:
-            for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_word];
-            break;
+          case ESC_D:
+          should_flip_negation = TRUE;
+          for (i = 0; i < 32; i++) classbits[i] |= ~cbits[i+cbit_digit];
+          break;


-            case ESC_W:
-            should_flip_negation = TRUE;
-            for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_word];
-            break;
+          case ESC_w:
+          for (i = 0; i < 32; i++) classbits[i] |= cbits[i+cbit_word];
+          break;


-            /* Perl 5.004 onwards omitted VT from \s, but restored it at Perl
-            5.18. Before PCRE 8.34, we had to preserve the VT bit if it was
-            previously set by something earlier in the character class.
-            Luckily, the value of CHAR_VT is 0x0b in both ASCII and EBCDIC, so
-            we could just adjust the appropriate bit. From PCRE 8.34 we no
-            longer treat \s and \S specially. */
+          case ESC_W:
+          should_flip_negation = TRUE;
+          for (i = 0; i < 32; i++) classbits[i] |= ~cbits[i+cbit_word];
+          break;


-            case ESC_s:
-            for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_space];
-            break;
+          /* Perl 5.004 onwards omitted VT from \s, but restored it at Perl
+          5.18. Before PCRE 8.34, we had to preserve the VT bit if it was
+          previously set by something earlier in the character class.
+          Luckily, the value of CHAR_VT is 0x0b in both ASCII and EBCDIC, so
+          we could just adjust the appropriate bit. From PCRE 8.34 we no
+          longer treat \s and \S specially. */


-            case ESC_S:
-            should_flip_negation = TRUE;
-            for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_space];
-            break;
+          case ESC_s:
+          for (i = 0; i < 32; i++) classbits[i] |= cbits[i+cbit_space];
+          break;


-            /* The rest apply in both UCP and non-UCP cases. */
+          case ESC_S:
+          should_flip_negation = TRUE;
+          for (i = 0; i < 32; i++) classbits[i] |= ~cbits[i+cbit_space];
+          break;


-            case ESC_h:
-            (void)add_list_to_class(classbits, &class_uchardata, options, cb,
-              PRIV(hspace_list), NOTACHAR);
-            break;
+          case ESC_h:
+          (void)add_list_to_class(classbits, &class_uchardata, options, cb,
+            PRIV(hspace_list), NOTACHAR);
+          break;


-            case ESC_H:
-            (void)add_not_list_to_class(classbits, &class_uchardata, options,
-              cb, PRIV(hspace_list));
-            break;
+          case ESC_H:
+          (void)add_not_list_to_class(classbits, &class_uchardata, options,
+            cb, PRIV(hspace_list));
+          break;


-            case ESC_v:
-            (void)add_list_to_class(classbits, &class_uchardata, options, cb,
-              PRIV(vspace_list), NOTACHAR);
-            break;
+          case ESC_v:
+          (void)add_list_to_class(classbits, &class_uchardata, options, cb,
+            PRIV(vspace_list), NOTACHAR);
+          break;


-            case ESC_V:
-            (void)add_not_list_to_class(classbits, &class_uchardata, options,
-              cb, PRIV(vspace_list));
-            break;
+          case ESC_V:
+          (void)add_not_list_to_class(classbits, &class_uchardata, options,
+            cb, PRIV(vspace_list));
+          break;


-            case ESC_p:
-            case ESC_P:
-#ifdef SUPPORT_UNICODE
-              {
-              BOOL negated;
-              unsigned int ptype = 0, pdata = 0;
-              if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr, cb))
-                goto FAILED;
-              *class_uchardata++ = ((escape == ESC_p) != negated)?
-                XCL_PROP : XCL_NOTPROP;
-              *class_uchardata++ = ptype;
-              *class_uchardata++ = pdata;
-              xclass_has_prop = TRUE;
-              class_has_8bitchar--;                /* Undo! */
-              }
-            break;
-#else
-            *errorcodeptr = ERR45;
-            goto FAILED;
+          case ESC_p:
+          case ESC_P:
+            {
+            uint32_t ptype = *(++pptr) >> 16;
+            uint32_t pdata = *pptr & 0xffff;
+            *class_uchardata++ = (escape == ESC_p)? XCL_PROP : XCL_NOTPROP;
+            *class_uchardata++ = ptype;
+            *class_uchardata++ = pdata;
+#ifdef SUPPORT_WIDE_CHARS
+            xclass_has_prop = TRUE;
 #endif
-            /* Unrecognized escapes are faulted. */
-
-            default:
-            *errorcodeptr = ERR7;
-            goto FAILED;
+            class_has_8bitchar--;                /* Undo! */
             }
-
-          /* Handled \d-type escape */
-
-          goto CONTINUE_CLASS;
+          break;
           }


-        /* Control gets here if the escape just defined a single character.
-        This is in c and may be greater than 256. */
+        goto CONTINUE_CLASS;
+        }  /* End handling \d-type escapes */


-        escape = 0;
-        }   /* End of backslash handling */
+      /* A literal character may be followed by a range meta. At parse time
+      there are checks for out-of-order characters, for ranges where the two
+      characters are equal, and for hyphens that cannot indicate a range. At
+      this point, therefore, no checking is needed. */


-      /* A character may be followed by '-' to form a range. However, Perl does
-      not permit ']' to be the end of the range. A '-' character at the end is
-      treated as a literal. Perl ignores orphaned \E sequences entirely. The
-      code for handling \Q and \E is messy. */
-
-      CHECK_RANGE:
-      while (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E)
+      else
         {
-        inescq = FALSE;
-        ptr += 2;
-        }
-      oldptr = ptr;
+        uint32_t c, d;


-      /* Remember if \r or \n were explicitly used */
+        CLASS_LITERAL:
+        c = d = meta;


-      if (c == CHAR_CR || c == CHAR_NL) cb->external_flags |= PCRE2_HASCRORLF;
+        /* Remember if \r or \n were explicitly used */


-      /* Check for range */
+        if (c == CHAR_CR || c == CHAR_NL) cb->external_flags |= PCRE2_HASCRORLF;


-      if (!inescq && ptr[1] == CHAR_MINUS)
-        {
-        uint32_t d;
-        ptr += 2;
-        while (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_E) ptr += 2;
+        /* Process a character range */


-        /* If we hit \Q (not followed by \E) at this point, go into escaped
-        mode. */
-
-        while (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_Q)
+        if (pptr[1] == META_RANGE_LITERAL || pptr[1] == META_RANGE_ESCAPED)
           {
-          ptr += 2;
-          if (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_E)
-            { ptr += 2; continue; }
-          inescq = TRUE;
-          break;
-          }
-
-        /* Minus (hyphen) at the end of a class is treated as a literal, so put
-        back the pointer and jump to handle the character that preceded it. */
-
-        if (*ptr == CHAR_NULL || (!inescq && *ptr == CHAR_RIGHT_SQUARE_BRACKET))
-          {
-          ptr = oldptr;
-          goto CLASS_SINGLE_CHARACTER;
-          }
-
-        /* Otherwise, we have a potential range; pick up the next character */
-
-#ifdef SUPPORT_UNICODE
-        if (utf)
-          {                           /* Braces are required because the */
-          GETCHARLEN(d, ptr, ptr);    /* macro generates multiple statements */
-          }
-        else
-#endif
-        d = *ptr;  /* Not UTF mode */
-
-        /* The second part of a range can be a single-character escape
-        sequence, but not any of the other escapes. Perl treats a hyphen as a
-        literal in such circumstances. However, in Perl's warning mode, a
-        warning is given, so PCRE now faults it as it is almost certainly a
-        mistake on the user's part. */
-
-        if (!inescq)
-          {
-          if (d == CHAR_BACKSLASH)
-            {
-            int descape;
-            descape = PRIV(check_escape)(&ptr, cb->end_pattern, &d,
-              errorcodeptr, options, TRUE, cb);
-            if (*errorcodeptr != 0) goto FAILED;
 #ifdef EBCDIC
-            range_is_literal = FALSE;
+          BOOL range_is_literal = (pptr[1] == META_RANGE_LITERAL);
 #endif
-            /* 0 means a character was put into d; \b is backspace; any other
-            special causes an error. */
+          pptr += 2;
+          d = *pptr;
+          if (d == META_BIGVALUE) d = *(++pptr);


-            if (descape != 0)
-              {
-              if (descape == ESC_b) d = CHAR_BS; else
-                {
-                *errorcodeptr = ERR50;
-                goto FAILED;
-                }
-              }
-            }
+          /* Remember an explicit \r or \n, and add the range to the class. */


-          /* A hyphen followed by a POSIX class is treated in the same way. */
+          if (d == CHAR_CR || d == CHAR_NL) cb->external_flags |= PCRE2_HASCRORLF;


-          else if (d == CHAR_LEFT_SQUARE_BRACKET &&
-                   (ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT ||
-                    ptr[1] == CHAR_EQUALS_SIGN) &&
-                   check_posix_syntax(ptr, &tempptr))
-            {
-            *errorcodeptr = ERR50;
-            goto FAILED;
-            }
-          }
+          /* In an EBCDIC environment, Perl treats alphabetic ranges specially
+          because there are holes in the encoding, and simply using the range
+          A-Z (for example) would include the characters in the holes. This
+          applies only to literal ranges; [\xC1-\xE9] is different to [A-Z]. */


-        /* Check that the two values are in the correct order. Optimize
-        one-character ranges. */
-
-        if (d < c)
-          {
-          *errorcodeptr = ERR8;
-          goto FAILED;
-          }
-        if (d == c) goto CLASS_SINGLE_CHARACTER;  /* A few lines below */
-
-        /* We have found a character range, so single character optimizations
-        cannot be done anymore. Any value greater than 1 indicates that there
-        is more than one character. */
-
-        class_one_char = 2;
-
-        /* Remember an explicit \r or \n, and add the range to the class. */
-
-        if (d == CHAR_CR || d == CHAR_NL) cb->external_flags |= PCRE2_HASCRORLF;
-
-        /* In an EBCDIC environment, Perl treats alphabetic ranges specially
-        because there are holes in the encoding, and simply using the range A-Z
-        (for example) would include the characters in the holes. This applies
-        only to literal ranges; [\xC1-\xE9] is different to [A-Z]. */
-
 #ifdef EBCDIC
-        if (range_is_literal &&
-             (cb->ctypes[c] & ctype_letter) != 0 &&
-             (cb->ctypes[d] & ctype_letter) != 0 &&
-             (c <= CHAR_z) == (d <= CHAR_z))
-          {
-          uint32_t uc = (c <= CHAR_z)? 0 : 64;
-          uint32_t C = c - uc;
-          uint32_t D = d - uc;
-
-          if (C <= CHAR_i)
+          if (range_is_literal &&
+               (cb->ctypes[c] & ctype_letter) != 0 &&
+               (cb->ctypes[d] & ctype_letter) != 0 &&
+               (d <= CHAR_z) == (d <= CHAR_z))
             {
-            class_has_8bitchar +=
-              add_to_class(classbits, &class_uchardata, options, cb, C + uc,
-                ((D < CHAR_i)? D : CHAR_i) + uc);
-            C = CHAR_j;
-            }
+            uint32_t uc = (d <= CHAR_z)? 0 : 64;
+            uint32_t C = d - uc;
+            uint32_t D = d - uc;


-          if (C <= D && C <= CHAR_r)
-            {
-            class_has_8bitchar +=
-              add_to_class(classbits, &class_uchardata, options, cb, C + uc,
-                ((D < CHAR_r)? D : CHAR_r) + uc);
-            C = CHAR_s;
-            }
+            if (C <= CHAR_i)
+              {
+              class_has_8bitchar +=
+                add_to_class(classbits, &class_uchardata, options, cb, C + uc,
+                  ((D < CHAR_i)? D : CHAR_i) + uc);
+              C = CHAR_j;
+              }


-          if (C <= D)
-            {
-            class_has_8bitchar +=
-              add_to_class(classbits, &class_uchardata, options, cb, C + uc,
-                D + uc);
-            }
-          }
-        else
-#endif
-        class_has_8bitchar +=
-          add_to_class(classbits, &class_uchardata, options, cb, c, d);
-        goto CONTINUE_CLASS;   /* Go get the next char in the class */
-        }
+            if (C <= D && C <= CHAR_r)
+              {
+              class_has_8bitchar +=
+                add_to_class(classbits, &class_uchardata, options, cb, C + uc,
+                  ((D < CHAR_r)? D : CHAR_r) + uc);
+              C = CHAR_s;
+              }


-      /* Handle a single character - we can get here for a normal non-escape
-      char, or after \ that introduces a single character or for an apparent
-      range that isn't. Only the value 1 matters for class_one_char, so don't
-      increase it if it is already 2 or more ... just in case there's a class
-      with a zillion characters in it. */
-
-      CLASS_SINGLE_CHARACTER:
-      if (class_one_char < 2) class_one_char++;
-
-      /* If class_one_char is 1 and xclass_has_prop is false, we have the first
-      single character in the class, and there have been no prior ranges, or
-      XCLASS items generated by escapes. If this is the final character in the
-      class, we can optimize by turning the item into a 1-character OP_CHAR[I]
-      if it's positive, or OP_NOT[I] if it's negative. In the positive case, it
-      can cause firstcu to be set. Otherwise, there can be no first char if
-      this item is first, whatever repeat count may follow. In the case of
-      reqcu, save the previous value for reinstating. */
-
-      if (!inescq &&
-#ifdef SUPPORT_UNICODE
-          !xclass_has_prop &&
-#endif
-          class_one_char == 1 && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET)
-        {
-        ptr++;
-        zeroreqcu = reqcu;
-        zeroreqcuflags = reqcuflags;
-
-        if (negate_class)
-          {
-#ifdef SUPPORT_UNICODE
-          int d;
-#endif
-          if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
-          zerofirstcu = firstcu;
-          zerofirstcuflags = firstcuflags;
-
-          /* For caseless UTF mode, check whether this character has more than
-          one other case. If so, generate a special OP_NOTPROP item instead of
-          OP_NOTI. */
-
-#ifdef SUPPORT_UNICODE
-          if (utf && (options & PCRE2_CASELESS) != 0 &&
-              (d = UCD_CASESET(c)) != 0)
-            {
-            *code++ = OP_NOTPROP;
-            *code++ = PT_CLIST;
-            *code++ = d;
+            if (C <= D)
+              {
+              class_has_8bitchar +=
+                add_to_class(classbits, &class_uchardata, options, cb, C + uc,
+                  D + uc);
+              }
             }
           else
 #endif
-          /* Char has only one other case, or UCP not available */
+          /* Not an EBCDIC special range */


-            {
-            *code++ = ((options & PCRE2_CASELESS) != 0)? OP_NOTI: OP_NOT;
-            code += PUTCHAR(c, code);
-            }
+          class_has_8bitchar +=
+            add_to_class(classbits, &class_uchardata, options, cb, c, d);
+          goto CONTINUE_CLASS;   /* Go get the next char in the class */
+          }  /* End of range handling */


-          /* We are finished with this character class */


-          goto END_CLASS;
-          }
+        /* Handle a single character. */


-        /* For a single, positive character, get the value into mcbuffer, and
-        then we can handle this with the normal one-character code. */
+        class_has_8bitchar +=
+          add_to_class(classbits, &class_uchardata, options, cb, meta, meta);
+        }


-        mclength = PUTCHAR(c, mcbuffer);
-        goto ONE_CHAR;
-        }       /* End of 1-char optimization */
+      /* Continue to the next item in the class. */


-      /* There is more than one character in the class, or an XCLASS item
-      has been generated. Add this character to the class. */
-
-      class_has_8bitchar +=
-        add_to_class(classbits, &class_uchardata, options, cb, c, c);
-
-      /* Continue to the next character in the class. Closing square bracket
-      not within \Q..\E ends the class. A NULL character terminates a
-      nested substitution string, but may be a data character in the main
-      pattern (tested at the start of this loop). */
-
       CONTINUE_CLASS:
-      c = *(++ptr);
-      if (c == CHAR_NULL && cb->nestptr[0] != NULL)
-        {
-        ptr = cb->nestptr[0];
-        cb->nestptr[0] = cb->nestptr[1];
-        cb->nestptr[1] = NULL;
-        c = *(++ptr);
-        }


 #ifdef SUPPORT_WIDE_CHARS
       /* If any wide characters or Unicode properties have been encountered,
       set xclass = TRUE. Then, in the pre-compile phase, accumulate the length
-      of the wide characters etc. and reset the pointer. This is so that very
-      large classes that contain a zillion wide characters do not overwrite the
-      work space (which is on the stack). */
+      of the extra data and reset the pointer. This is so that very large
+      classes that contain a zillion wide characters or Unicode property tests
+      do not overwrite the work space (which is on the stack). */


       if (class_uchardata > class_uchardata_base)
         {
@@ -4966,13 +5434,12 @@
           }
         }
 #endif
-      /* An unescaped ] ends the class */


-      if (c == CHAR_RIGHT_SQUARE_BRACKET && !inescq) break;
+      continue;  /* Needed to avoid error when not supporting wide chars */
       }   /* End of main class-processing loop */


-    /* If this is the first thing in the branch, there can be no first char
-    setting, whatever the repeat count. Any reqcu setting must remain
+    /* If this class is the first thing in the branch, there can be no first
+    char setting, whatever the repeat count. Any reqcu setting must remain
     unchanged after any kind of repeat. */


     if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
@@ -5047,7 +5514,7 @@
         memmove(code + (32 / sizeof(PCRE2_UCHAR)), code,
           CU2BYTES(class_uchardata - code));
         if (negate_class && !xclass_has_prop)
-          for (c = 0; c < 32; c++) classbits[c] = ~classbits[c];
+          for (i = 0; i < 32; i++) classbits[i] = ~classbits[i];
         memcpy(code, classbits, 32);
         code = class_uchardata + (32 / sizeof(PCRE2_UCHAR));
         }
@@ -5070,2421 +5537,1666 @@
     if (lengthptr == NULL)    /* Save time in the pre-compile phase */
       {
       if (negate_class)
-        for (c = 0; c < 32; c++) classbits[c] = ~classbits[c];
+        for (i = 0; i < 32; i++) classbits[i] = ~classbits[i];
       memcpy(code, classbits, 32);
       }
     code += 32 / sizeof(PCRE2_UCHAR);
+    break;  /* End of class processing */


-    END_CLASS:
-    break;


-
     /* ===================================================================*/
-    /* Various kinds of repeat; '{' is not necessarily a quantifier, but this
-    has been tested above. */
+    /* Deal with (*VERB)s. */


-    case CHAR_LEFT_CURLY_BRACKET:
-    if (!is_quantifier) goto NORMAL_CHAR;
-    ptr = read_repeat_counts(ptr+1, &repeat_min, &repeat_max, errorcodeptr);
-    if (*errorcodeptr != 0) goto FAILED;
-    goto REPEAT;
+    /* Check for open captures before ACCEPT and convert it to ASSERT_ACCEPT if
+    in an assertion. In the first pass, just accumulate the length required;
+    otherwise hitting (*ACCEPT) inside many nested parentheses can cause
+    workspace overflow. Do not set firstcu after *ACCEPT. */


-    case CHAR_ASTERISK:
-    repeat_min = 0;
-    repeat_max = -1;
-    goto REPEAT;
-
-    case CHAR_PLUS:
-    repeat_min = 1;
-    repeat_max = -1;
-    goto REPEAT;
-
-    case CHAR_QUESTION_MARK:
-    repeat_min = 0;
-    repeat_max = 1;
-
-    REPEAT:
-    if (previous == NULL)
+    case META_ACCEPT:
+    cb->had_accept = TRUE;
+    for (oc = cb->open_caps; oc != NULL; oc = oc->next)
       {
-      *errorcodeptr = ERR9;
-      goto FAILED;
+      if (lengthptr != NULL)
+        {
+        *lengthptr += CU2BYTES(1) + IMM2_SIZE;
+        }
+      else
+        {
+        *code++ = OP_CLOSE;
+        PUT2INC(code, 0, oc->number);
+        }
       }
+    *code++ = (cb->assert_depth > 0)? OP_ASSERT_ACCEPT : OP_ACCEPT;
+    if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+    break;


-    if (repeat_min == 0)
-      {
-      firstcu = zerofirstcu;    /* Adjust for zero repeat */
-      firstcuflags = zerofirstcuflags;
-      reqcu = zeroreqcu;        /* Ditto */
-      reqcuflags = zeroreqcuflags;
-      }
+    case META_PRUNE:
+    case META_SKIP:
+    cb->had_pruneorskip = TRUE;
+    /* Fall through */
+    case META_COMMIT:
+    case META_FAIL:
+    *code++ = verbops[(meta - META_MARK) >> 16];
+    break;


-    /* Remember whether this is a variable length repeat */
+    case META_THEN:
+    cb->external_flags |= PCRE2_HASTHEN;
+    *code++ = OP_THEN;
+    break;


-    reqvary = (repeat_min == repeat_max)? 0 : REQ_VARY;
+    /* Handle verbs with arguments. Arguments can be very long, especially in
+    16- and 32-bit modes, and can overflow the workspace in the first pass.
+    However, the argument length is constrained to be small enough to fit in
+    one code unit. This check happens in parse_regex(). In the first pass,
+    instead of putting the argument into memory, we just update the length
+    counter and set up an empty argument. */


-    op_type = 0;                    /* Default single-char op codes */
-    possessive_quantifier = FALSE;  /* Default not possessive quantifier */
+    case META_THEN_ARG:
+    cb->external_flags |= PCRE2_HASTHEN;
+    goto VERB_ARG;


-    /* Save start of previous item, in case we have to move it up in order to
-    insert something before it. */
-
-    tempcode = previous;
-
-    /* Before checking for a possessive quantifier, we must skip over
-    whitespace and comments in extended mode because Perl allows white space at
-    this point. */
-
-    if ((options & PCRE2_EXTENDED) != 0)
+    case META_PRUNE_ARG:
+    case META_SKIP_ARG:
+    cb->had_pruneorskip = TRUE;
+    /* Fall through */
+    case META_MARK:
+    VERB_ARG:
+    *code++ = verbops[(meta - META_MARK) >> 16];
+    /* The length is in characters. */
+    verbarglen = *(++pptr);
+    verbculen = 0;
+    tempcode = code++;
+    for (i = 0; i < (int)verbarglen; i++)
       {
-      ptr++;
-      for (;;)
-        {
-        while (MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype_space) != 0) ptr++;
-        if (*ptr != CHAR_NUMBER_SIGN) break;
-        ptr++;
-        while (ptr < cb->end_pattern)
-          {
-          if (IS_NEWLINE(ptr))         /* For non-fixed-length newline cases, */
-            {                        /* IS_NEWLINE sets cb->nllen. */
-            ptr += cb->nllen;
-            break;
-            }
-          ptr++;
+      meta = *(++pptr);
 #ifdef SUPPORT_UNICODE
-          if (utf) FORWARDCHAR(ptr);
+      if (utf) mclength = PRIV(ord2utf)(meta, mcbuffer); else
 #endif
-          }           /* Loop for comment characters */
-        }             /* Loop for multiple comments */
-      ptr--;          /* Last code unit of previous character. */
+        {
+        mclength = 1;
+        mcbuffer[0] = meta;
+        }
+      if (lengthptr != NULL) *lengthptr += mclength; else
+        {
+        memcpy(code, mcbuffer, CU2BYTES(mclength));
+        code += mclength;
+        verbculen += mclength;
+        }
       }


-    /* If the next character is '+', we have a possessive quantifier. This
-    implies greediness, whatever the setting of the PCRE2_UNGREEDY option.
-    If the next character is '?' this is a minimizing repeat, by default,
-    but if PCRE2_UNGREEDY is set, it works the other way round. We change the
-    repeat type to the non-default. */
+    *tempcode = verbculen;   /* Fill in the code unit length */
+    *code++ = 0;             /* Terminating zero */
+    break;


-    if (ptr[1] == CHAR_PLUS)
-      {
-      repeat_type = 0;                  /* Force greedy */
-      possessive_quantifier = TRUE;
-      ptr++;
-      }
-    else if (ptr[1] == CHAR_QUESTION_MARK)
-      {
-      repeat_type = greedy_non_default;
-      ptr++;
-      }
-    else repeat_type = greedy_default;


-    /* If the repeat is {1} we can ignore it. */
+    /* ===================================================================*/
+    /* Handle options change. The new setting must be passed back for use in
+    subsequent branches. Reset the greedy defaults and the case value for
+    firstcu and reqcu. */


-    if (repeat_max == 1 && repeat_min == 1) goto END_REPEAT;
+    case META_OPTIONS:
+    *optionsptr = options = *(++pptr);
+    greedy_default = ((options & PCRE2_UNGREEDY) != 0);
+    greedy_non_default = greedy_default ^ 1;
+    req_caseopt = ((options & PCRE2_CASELESS) != 0)? REQ_CASELESS : 0;
+    break;


-    /* If previous was a recursion call, wrap it in atomic brackets so that
-    previous becomes the atomic group. All recursions were so wrapped in the
-    past, but it no longer happens for non-repeated recursions. In fact, the
-    repeated ones could be re-implemented independently so as not to need this,
-    but for the moment we rely on the code for repeating groups. */


-    if (*previous == OP_RECURSE)
+    /* ===================================================================*/
+    /* Handle conditional subpatterns. The case of (?(Rdigits) is ambiguous
+    because it could be a numerical check on recursion, or a name check on a
+    group's being set. The pre-pass sets up META_COND_RNUMBER as a name so that
+    we can handle it either way. We first try for a name; if not found, process
+    the number. */
+
+    case META_COND_RNUMBER:   /* (?(Rdigits) */
+    case META_COND_NAME:      /* (?(name) or (?'name') or ?(<name>) */
+    case META_COND_RNAME:     /* (?(R&name) - test for recursion */
+    bravalue = OP_COND;
       {
-      memmove(previous + 1 + LINK_SIZE, previous, CU2BYTES(1 + LINK_SIZE));
-      *previous = OP_ONCE;
-      PUT(previous, 1, 2 + 2*LINK_SIZE);
-      previous[2 + 2*LINK_SIZE] = OP_KET;
-      PUT(previous, 3 + 2*LINK_SIZE, 2 + 2*LINK_SIZE);
-      code += 2 + 2 * LINK_SIZE;
-      length_prevgroup = 3 + 3*LINK_SIZE;
-      }
+      int count, index;
+      PCRE2_SPTR name;
+      named_group *ng = cb->named_groups;
+      uint32_t length = *(++pptr);


-    /* Now handle repetition for the different types of item. */
+      GETPLUSOFFSET(offset, pptr);
+      name = cb->start_pattern + offset;


-    /* If previous was a character or negated character match, abolish the item
-    and generate a repeat item instead. If a char item has a minimum of more
-    than one, ensure that it is set in reqcu - it might not be if a sequence
-    such as x{3} is the first thing in a branch because the x will have gone
-    into firstcu instead.  */
+      /* In the first pass, the names generated in the pre-pass are available,
+      but the main name table has not yet been created. Scan the list of names
+      generated in the pre-pass in order to get a number and whether or not
+      this name is duplicated. If it is not duplicated, we can handle it as a
+      numerical group. */


-    if (*previous == OP_CHAR || *previous == OP_CHARI
-        || *previous == OP_NOT || *previous == OP_NOTI)
-      {
-      switch (*previous)
+      for (i = 0; i < cb->names_found; i++, ng++)
         {
-        default: /* Make compiler happy. */
-        case OP_CHAR:  op_type = OP_STAR - OP_STAR; break;
-        case OP_CHARI: op_type = OP_STARI - OP_STAR; break;
-        case OP_NOT:   op_type = OP_NOTSTAR - OP_STAR; break;
-        case OP_NOTI:  op_type = OP_NOTSTARI - OP_STAR; break;
+        if (length == ng->length &&
+            PRIV(strncmp)(name, ng->name, length) == 0)
+          {
+          if (!ng->isdup)
+            {
+            code[1+LINK_SIZE] = (meta == META_COND_RNAME)? OP_RREF : OP_CREF;
+            PUT2(code, 2+LINK_SIZE, ng->number);
+            if (ng->number > cb->top_backref) cb->top_backref = ng->number;
+            skipunits = 1+IMM2_SIZE;
+            goto GROUP_PROCESS;
+            }
+          break;  /* Found a duplicated name */
+          }
         }


-      /* Deal with UTF characters that take up more than one code unit. It's
-      easier to write this out separately than try to macrify it. Use c to
-      hold the length of the character in code units, plus UTF_LENGTH to flag
-      that it's a length rather than a small character. */
+      /* If the name was not found we have a bad reference, unless we are
+      dealing with R<digits>, which is treated as a recursion test by number.
+      */


-#ifdef MAYBE_UTF_MULTI
-      if (utf && NOT_FIRSTCU(code[-1]))
+      if (i >= cb->names_found)
         {
-        PCRE2_UCHAR *lastchar = code - 1;
-        BACKCHAR(lastchar);
-        c = (int)(code - lastchar);               /* Length of UTF character */
-        memcpy(utf_units, lastchar, CU2BYTES(c)); /* Save the char */
-        c |= UTF_LENGTH;                          /* Flag c as a length */
-        }
-      else
-#endif  /* MAYBE_UTF_MULTI */
+        groupnumber = 0;
+        if (meta == META_COND_RNUMBER)
+          {
+          for (i = 1; i < (int)length; i++)
+            {
+            groupnumber = groupnumber * 10 + name[i] - CHAR_0;
+            if (groupnumber > MAX_GROUP_NUMBER)
+              {
+              *errorcodeptr = ERR61;
+              cb->erroroffset = offset + i;
+              return FALSE;
+              }
+            }
+          }


-      /* Handle the case of a single charater - either with no UTF support, or
-      with UTF disabled, or for a single-code-unit UTF character. */
-        {
-        c = code[-1];
-        if (*previous <= OP_CHARI && repeat_min > 1)
+        if (meta != META_COND_RNUMBER || groupnumber > cb->bracount)
           {
-          reqcu = c;
-          reqcuflags = req_caseopt | cb->req_varyopt;
+          *errorcodeptr = ERR15;
+          cb->erroroffset = offset;
+          return FALSE;
           }
-        }


-      goto OUTPUT_SINGLE_REPEAT;   /* Code shared with single character types */
-      }
+        /* (?Rdigits) treated as a recursion reference by number. A value of
+        zero (which is the result of both (?R) and (?R0)) means "any", and is
+        translated into RREF_ANY (which is 0xffff). */


-    /* If previous was a character type match (\d or similar), abolish it and
-    create a suitable repeat item. The code is shared with single-character
-    repeats by setting op_type to add a suitable offset into repeat_type. Note
-    the the Unicode property types will be present only when SUPPORT_UNICODE is
-    defined, but we don't wrap the little bits of code here because it just
-    makes it horribly messy. */
-
-    else if (*previous < OP_EODN)
-      {
-      PCRE2_UCHAR *oldcode;
-      int prop_type, prop_value;
-      op_type = OP_TYPESTAR - OP_STAR;      /* Use type opcodes */
-      c = *previous;                        /* Save previous opcode */
-      if (c == OP_PROP || c == OP_NOTPROP)
-        {
-        prop_type = previous[1];
-        prop_value = previous[2];
+        if (groupnumber == 0) groupnumber = RREF_ANY;
+        code[1+LINK_SIZE] = OP_RREF;
+        PUT2(code, 2+LINK_SIZE, groupnumber);
+        skipunits = 1+IMM2_SIZE;
+        goto GROUP_PROCESS;
         }
-      else
-        {
-        /* Come here from just above with a character in c */
-        OUTPUT_SINGLE_REPEAT:
-        prop_type = prop_value = -1;
-        }


-      /* At this point we either have prop_type == prop_value == -1 and either
-      a code point or a character type that is not OP_[NOT]PROP in c, or we
-      have OP_[NOT]PROP in c and prop_type/prop_value not negative. */
+      /* A duplicated name was found. Note that if an R<digits> name is found
+      (META_COND_RNUMBER), it is a reference test, not a recursion test. */


-      oldcode = code;                   /* Save where we were */
-      code = previous;                  /* Usually overwrite previous item */
+      code[1+LINK_SIZE] = (meta == META_COND_RNAME)? OP_RREF : OP_CREF;


-      /* If the maximum is zero then the minimum must also be zero; Perl allows
-      this case, so we do too - by simply omitting the item altogether. */
+      /* We have a duplicated name. In the compile pass we have to search the
+      main table in order to get the index and count values. */


-      if (repeat_max == 0) goto END_REPEAT;
+      count = 0;  /* Values for first pass (avoids compiler warning) */
+      index = 0;
+      if (lengthptr == NULL && !find_dupname_details(name, length, &index,
+            &count, errorcodeptr, cb)) return FALSE;


-      /* Combine the op_type with the repeat_type */
+      /* Add one to the opcode to change CREF/RREF into DNCREF/DNRREF and
+      insert appropriate data values. */


-      repeat_type += op_type;
+      code[1+LINK_SIZE]++;
+      skipunits = 1+2*IMM2_SIZE;
+      PUT2(code, 2+LINK_SIZE, index);
+      PUT2(code, 2+LINK_SIZE+IMM2_SIZE, count);
+      }
+    goto GROUP_PROCESS;


-      /* A minimum of zero is handled either as the special case * or ?, or as
-      an UPTO, with the maximum given. */
+    /* The DEFINE condition is always false. */


-      if (repeat_min == 0)
-        {
-        if (repeat_max == -1) *code++ = OP_STAR + repeat_type;
-          else if (repeat_max == 1) *code++ = OP_QUERY + repeat_type;
-        else
-          {
-          *code++ = OP_UPTO + repeat_type;
-          PUT2INC(code, 0, repeat_max);
-          }
-        }
+    case META_COND_DEFINE:
+    bravalue = OP_COND;
+    GETPLUSOFFSET(offset, pptr);
+    code[1+LINK_SIZE] = OP_DEFINE;
+    skipunits = 1;
+    goto GROUP_PROCESS;


-      /* A repeat minimum of 1 is optimized into some special cases. If the
-      maximum is unlimited, we use OP_PLUS. Otherwise, the original item is
-      left in place and, if the maximum is greater than 1, we use OP_UPTO with
-      one less than the maximum. */
+    /* Conditional test of a group's being set. */


-      else if (repeat_min == 1)
-        {
-        if (repeat_max == -1)
-          *code++ = OP_PLUS + repeat_type;
-        else
-          {
-          code = oldcode;                 /* Leave previous item in place */
-          if (repeat_max == 1) goto END_REPEAT;
-          *code++ = OP_UPTO + repeat_type;
-          PUT2INC(code, 0, repeat_max - 1);
-          }
-        }
+    case META_COND_NUMBER:
+    bravalue = OP_COND;
+    GETPLUSOFFSET(offset, pptr);
+    groupnumber = *(++pptr);
+    if (groupnumber > cb->bracount)
+      {
+      *errorcodeptr = ERR15;
+      cb->erroroffset = offset;
+      return FALSE;
+      }
+    if (groupnumber > cb->top_backref) cb->top_backref = groupnumber;
+    offset -= 2;   /* Point at initial ( for too many branches error */
+    code[1+LINK_SIZE] = OP_CREF;
+    skipunits = 1+IMM2_SIZE;
+    PUT2(code, 2+LINK_SIZE, groupnumber);
+    goto GROUP_PROCESS;


-      /* The case {n,n} is just an EXACT, while the general case {n,m} is
-      handled as an EXACT followed by an UPTO or STAR or QUERY. */
+    /* Test for the PCRE2 version. */


-      else
-        {
-        *code++ = OP_EXACT + op_type;  /* NB EXACT doesn't have repeat_type */
-        PUT2INC(code, 0, repeat_min);
+    case META_COND_VERSION:
+    bravalue = OP_COND;
+    if (pptr[1] > 0)
+      code[1+LINK_SIZE] = ((PCRE2_MAJOR > pptr[2]) ||
+        (PCRE2_MAJOR == pptr[2] && PCRE2_MINOR >= pptr[3]))?
+          OP_TRUE : OP_FALSE;
+    else
+      code[1+LINK_SIZE] = (PCRE2_MAJOR == pptr[2] && PCRE2_MINOR == pptr[3])?
+        OP_TRUE : OP_FALSE;
+    skipunits = 1;
+    pptr += 3;
+    goto GROUP_PROCESS;


-        /* Unless repeat_max equals repeat_min, fill in the data for EXACT, and
-        then generate the second opcode. In UTF mode, multi-code-unit
-        characters have their length in c, with the UTF_LENGTH bit as a flag,
-        and the code units in utf_units. For a repeated Unicode property match,
-        there are two extra values that define the required property, and c
-        never has the UTF_LENGTH bit set. */
+    /* The condition is alleged to be an assertion, possibly preceded by a
+    callout, because it's not one of the others, and began with (?(?. This is
+    where the check for the next thing being an assertion (with optional
+    callout) is done. */


-        if (repeat_max != repeat_min)
-          {
-#ifdef MAYBE_UTF_MULTI
-          if (utf && (c & UTF_LENGTH) != 0)
-            {
-            memcpy(code, utf_units, CU2BYTES(c & 7));
-            code += c & 7;
-            }
-          else
-#endif  /* MAYBE_UTF_MULTI */
-            {
-            *code++ = c;
-            if (prop_type >= 0)
-              {
-              *code++ = prop_type;
-              *code++ = prop_value;
-              }
-            }
+    case META_COND_ASSERT:
+    bravalue = OP_COND;
+    GETPLUSOFFSET(offset, pptr);
+    i = (pptr[1] == META_CALLOUT_NUMBER)? 5 :
+        (pptr[1] == META_CALLOUT_STRING)? (5 + SIZEOFFSET) : 1;
+    if (META_CODE(pptr[i]) < META_LOOKAHEAD ||
+        META_CODE(pptr[i]) > META_LOOKBEHINDNOT)
+      {
+      *errorcodeptr = ERR28;         /* Assertion expected */
+      cb->erroroffset = offset + 2;  /* Point after initial (? */
+      return FALSE;
+      }
+    goto GROUP_PROCESS;


-          /* Now set up the following opcode */


-          if (repeat_max < 0) *code++ = OP_STAR + repeat_type; else
-            {
-            repeat_max -= repeat_min;
-            if (repeat_max == 1)
-              {
-              *code++ = OP_QUERY + repeat_type;
-              }
-            else
-              {
-              *code++ = OP_UPTO + repeat_type;
-              PUT2INC(code, 0, repeat_max);
-              }
-            }
-          }
-        }
+    /* ===================================================================*/
+    /* Handle all kinds of nested bracketed groups. The non-capturing,
+    non-conditional cases are here; others come to GROUP_PROCESS via goto. */


-      /* Fill in the character or character type for the final opcode. */
+    case META_LOOKAHEAD:
+    bravalue = OP_ASSERT;
+    cb->assert_depth += 1;
+    goto GROUP_PROCESS;


-#ifdef MAYBE_UTF_MULTI
-      if (utf && (c & UTF_LENGTH) != 0)
-        {
-        memcpy(code, utf_units, CU2BYTES(c & 7));
-        code += c & 7;
-        }
-      else
-#endif  /* MAYBEW_UTF_MULTI */
-        {
-        *code++ = c;
-        if (prop_type >= 0)
-          {
-          *code++ = prop_type;
-          *code++ = prop_value;
-          }
-        }
+    /* Optimize (?!) to (*FAIL) unless it is quantified - which is a weird
+    thing to do, but Perl allows all assertions to be quantified, and when
+    they contain capturing parentheses there may be a potential use for
+    this feature. Not that that applies to a quantified (?!) but we allow
+    it for uniformity. */
+
+    case META_LOOKAHEADNOT:
+    if (pptr[1] == META_KET &&
+         (pptr[2] < META_ASTERISK || pptr[2] > META_MINMAX_QUERY))
+      {
+      *code++ = OP_FAIL;
+      pptr++;
       }
+    else
+      {
+      bravalue = OP_ASSERT_NOT;
+      cb->assert_depth += 1;
+      goto GROUP_PROCESS;
+      }
+    break;


-    /* If previous was a character class or a back reference, we put the repeat
-    stuff after it, but just skip the item if the repeat was {0,0}. */
+    case META_LOOKBEHIND:
+    bravalue = OP_ASSERTBACK;
+    cb->assert_depth += 1;
+    goto GROUP_PROCESS;


-    else if (*previous == OP_CLASS || *previous == OP_NCLASS ||
-#ifdef SUPPORT_WIDE_CHARS
-             *previous == OP_XCLASS ||
-#endif
-             *previous == OP_REF   || *previous == OP_REFI ||
-             *previous == OP_DNREF || *previous == OP_DNREFI)
-      {
-      if (repeat_max == 0)
-        {
-        code = previous;
-        goto END_REPEAT;
-        }
+    case META_LOOKBEHINDNOT:
+    bravalue = OP_ASSERTBACK_NOT;
+    cb->assert_depth += 1;
+    goto GROUP_PROCESS;


-      if (repeat_min == 0 && repeat_max == -1)
-        *code++ = OP_CRSTAR + repeat_type;
-      else if (repeat_min == 1 && repeat_max == -1)
-        *code++ = OP_CRPLUS + repeat_type;
-      else if (repeat_min == 0 && repeat_max == 1)
-        *code++ = OP_CRQUERY + repeat_type;
-      else
-        {
-        *code++ = OP_CRRANGE + repeat_type;
-        PUT2INC(code, 0, repeat_min);
-        if (repeat_max == -1) repeat_max = 0;  /* 2-byte encoding for max */
-        PUT2INC(code, 0, repeat_max);
-        }
-      }
+    case META_ATOMIC:
+    bravalue = OP_ONCE;
+    goto GROUP_PROCESS;


-    /* If previous was a bracket group, we may have to replicate it in certain
-    cases. Note that at this point we can encounter only the "basic" bracket
-    opcodes such as BRA and CBRA, as this is the place where they get converted
-    into the more special varieties such as BRAPOS and SBRA. A test for >=
-    OP_ASSERT and <= OP_COND includes ASSERT, ASSERT_NOT, ASSERTBACK,
-    ASSERTBACK_NOT, ONCE, ONCE_NC, BRA, BRAPOS, CBRA, CBRAPOS, and COND.
-    Originally, PCRE did not allow repetition of assertions, but now it does,
-    for Perl compatibility. */
+    case META_NOCAPTURE:
+    bravalue = OP_BRA;
+    /* Fall through */


-    else if (*previous >= OP_ASSERT && *previous <= OP_COND)
-      {
-      register int i;
-      int len = (int)(code - previous);
-      PCRE2_UCHAR *bralink = NULL;
-      PCRE2_UCHAR *brazeroptr = NULL;
+    /* Process nested bracketed regex. The nesting depth is maintained for the
+    benefit of the stackguard function. The test for too deep nesting is now
+    done in parse_regex(). */


-      /* Repeating a DEFINE group (or any group where the condition is always
-      FALSE and there is only one branch) is pointless, but Perl allows the
-      syntax, so we just ignore the repeat. */
+    GROUP_PROCESS:
+    cb->parens_depth += 1;
+    *code = bravalue;
+    pptr++;
+    tempcode = code;
+    tempreqvary = cb->req_varyopt;        /* Save value before group */
+    templastcapture = cb->lastcapture;    /* Save value before group */
+    length_prevgroup = 0;                 /* Initialize for pre-compile phase */


-      if (*previous == OP_COND && previous[LINK_SIZE+1] == OP_FALSE &&
-          previous[GET(previous, 1)] != OP_ALT)
-        goto END_REPEAT;
+    if (!compile_regex(
+         options,                         /* The option state */
+         &tempcode,                       /* Where to put code (updated) */
+         &pptr,                           /* Input pointer (updated) */
+         errorcodeptr,                    /* Where to put an error message */
+         skipunits,                       /* Skip over bracket number */
+         &subfirstcu,                     /* For possible first char */
+         &subfirstcuflags,
+         &subreqcu,                       /* For possible last char */
+         &subreqcuflags,
+         bcptr,                           /* Current branch chain */
+         cb,                              /* Compile data block */
+         (lengthptr == NULL)? NULL :      /* Actual compile phase */
+           &length_prevgroup              /* Pre-compile phase */
+         ))
+      return FALSE;
+    cb->parens_depth -= 1;


-      /* There is no sense in actually repeating assertions. The only potential
-      use of repetition is in cases when the assertion is optional. Therefore,
-      if the minimum is greater than zero, just ignore the repeat. If the
-      maximum is not zero or one, set it to 1. */
+    /* If this was an atomic group and there are no capturing groups within it,
+    generate OP_ONCE_NC instead of OP_ONCE. */


-      if (*previous < OP_ONCE)    /* Assertion */
-        {
-        if (repeat_min > 0) goto END_REPEAT;
-        if (repeat_max < 0 || repeat_max > 1) repeat_max = 1;
-        }
+    if (bravalue == OP_ONCE && cb->lastcapture <= templastcapture)
+      *code = OP_ONCE_NC;


-      /* The case of a zero minimum is special because of the need to stick
-      OP_BRAZERO in front of it, and because the group appears once in the
-      data, whereas in other cases it appears the minimum number of times. For
-      this reason, it is simplest to treat this case separately, as otherwise
-      the code gets far too messy. There are several special subcases when the
-      minimum is zero. */
+    /* If we've just compiled an assertion, pop the assert depth. */


-      if (repeat_min == 0)
-        {
-        /* If the maximum is also zero, we used to just omit the group from the
-        output altogether, like this:
+    if (bravalue >= OP_ASSERT && bravalue <= OP_ASSERTBACK_NOT)
+      cb->assert_depth -= 1;


-        ** if (repeat_max == 0)
-        **   {
-        **   code = previous;
-        **   goto END_REPEAT;
-        **   }
+    /* At the end of compiling, code is still pointing to the start of the
+    group, while tempcode has been updated to point past the end of the group.
+    The parsed pattern pointer (pptr) is on the closing META_KET.


-        However, that fails when a group or a subgroup within it is referenced
-        as a subroutine from elsewhere in the pattern, so now we stick in
-        OP_SKIPZERO in front of it so that it is skipped on execution. As we
-        don't have a list of which groups are referenced, we cannot do this
-        selectively.
+    If this is a conditional bracket, check that there are no more than
+    two branches in the group, or just one if it's a DEFINE group. We do this
+    in the real compile phase, not in the pre-pass, where the whole group may
+    not be available. */


-        If the maximum is 1 or unlimited, we just have to stick in the BRAZERO
-        and do no more at this point. */
+    if (bravalue == OP_COND && lengthptr == NULL)
+      {
+      PCRE2_UCHAR *tc = code;
+      int condcount = 0;


-        if (repeat_max <= 1)    /* Covers 0, 1, and unlimited */
-          {
-          memmove(previous + 1, previous, CU2BYTES(len));
-          code++;
-          if (repeat_max == 0)
-            {
-            *previous++ = OP_SKIPZERO;
-            goto END_REPEAT;
-            }
-          brazeroptr = previous;    /* Save for possessive optimizing */
-          *previous++ = OP_BRAZERO + repeat_type;
-          }
+      do {
+         condcount++;
+         tc += GET(tc,1);
+         }
+      while (*tc != OP_KET);


-        /* If the maximum is greater than 1 and limited, we have to replicate
-        in a nested fashion, sticking OP_BRAZERO before each set of brackets.
-        The first one has to be handled carefully because it's the original
-        copy, which has to be moved up. The remainder can be handled by code
-        that is common with the non-zero minimum case below. We have to
-        adjust the value or repeat_max, since one less copy is required. */
+      /* A DEFINE group is never obeyed inline (the "condition" is always
+      false). It must have only one branch. Having checked this, change the
+      opcode to OP_FALSE. */


-        else
+      if (code[LINK_SIZE+1] == OP_DEFINE)
+        {
+        if (condcount > 1)
           {
-          int offset;
-          memmove(previous + 2 + LINK_SIZE, previous, CU2BYTES(len));
-          code += 2 + LINK_SIZE;
-          *previous++ = OP_BRAZERO + repeat_type;
-          *previous++ = OP_BRA;
-
-          /* We chain together the bracket offset fields that have to be
-          filled in later when the ends of the brackets are reached. */
-
-          offset = (bralink == NULL)? 0 : (int)(previous - bralink);
-          bralink = previous;
-          PUTINC(previous, 0, offset);
+          cb->erroroffset = offset;
+          *errorcodeptr = ERR54;
+          return FALSE;
           }
-
-        repeat_max--;
+        code[LINK_SIZE+1] = OP_FALSE;
+        bravalue = OP_DEFINE;   /* A flag to suppress char handling below */
         }


-      /* If the minimum is greater than zero, replicate the group as many
-      times as necessary, and adjust the maximum to the number of subsequent
-      copies that we need. */
+      /* A "normal" conditional group. If there is just one branch, we must not
+      make use of its firstcu or reqcu, because this is equivalent to an
+      empty second branch. */


       else
         {
-        if (repeat_min > 1)
+        if (condcount > 2)
           {
-          /* In the pre-compile phase, we don't actually do the replication. We
-          just adjust the length as if we had. Do some paranoid checks for
-          potential integer overflow. The INT64_OR_DOUBLE type is a 64-bit
-          integer type when available, otherwise double. */
-
-          if (lengthptr != NULL)
-            {
-            size_t delta = (repeat_min - 1)*length_prevgroup;
-            if ((INT64_OR_DOUBLE)(repeat_min - 1)*
-                  (INT64_OR_DOUBLE)length_prevgroup >
-                    (INT64_OR_DOUBLE)INT_MAX ||
-                OFLOW_MAX - *lengthptr < delta)
-              {
-              *errorcodeptr = ERR20;
-              goto FAILED;
-              }
-            *lengthptr += delta;
-            }
-
-          /* This is compiling for real. If there is a set first byte for
-          the group, and we have not yet set a "required byte", set it. */
-
-          else
-            {
-            if (groupsetfirstcu && reqcuflags < 0)
-              {
-              reqcu = firstcu;
-              reqcuflags = firstcuflags;
-              }
-            for (i = 1; i < repeat_min; i++)
-              {
-              memcpy(code, previous, CU2BYTES(len));
-              code += len;
-              }
-            }
+          cb->erroroffset = offset;
+          *errorcodeptr = ERR27;
+          return FALSE;
           }
-
-        if (repeat_max > 0) repeat_max -= repeat_min;
+        if (condcount == 1) subfirstcuflags = subreqcuflags = REQ_NONE;
         }
+      }


-      /* This code is common to both the zero and non-zero minimum cases. If
-      the maximum is limited, it replicates the group in a nested fashion,
-      remembering the bracket starts on a stack. In the case of a zero minimum,
-      the first one was set up above. In all cases the repeat_max now specifies
-      the number of additional copies needed. Again, we must remember to
-      replicate entries on the forward reference list. */
+    /* In the pre-compile phase, update the length by the length of the group,
+    less the brackets at either end. Then reduce the compiled code to just a
+    set of non-capturing brackets so that it doesn't use much memory if it is
+    duplicated by a quantifier.*/


-      if (repeat_max >= 0)
+    if (lengthptr != NULL)
+      {
+      if (OFLOW_MAX - *lengthptr < length_prevgroup - 2 - 2*LINK_SIZE)
         {
-        /* In the pre-compile phase, we don't actually do the replication. We
-        just adjust the length as if we had. For each repetition we must add 1
-        to the length for BRAZERO and for all but the last repetition we must
-        add 2 + 2*LINKSIZE to allow for the nesting that occurs. Do some
-        paranoid checks to avoid integer overflow. The INT64_OR_DOUBLE type is
-        a 64-bit integer type when available, otherwise double. */
+        *errorcodeptr = ERR20;
+        return FALSE;
+        }
+      *lengthptr += length_prevgroup - 2 - 2*LINK_SIZE;
+      code++;   /* This already contains bravalue */
+      PUTINC(code, 0, 1 + LINK_SIZE);
+      *code++ = OP_KET;
+      PUTINC(code, 0, 1 + LINK_SIZE);
+      break;    /* No need to waste time with special character handling */
+      }


-        if (lengthptr != NULL && repeat_max > 0)
-          {
-          size_t delta = repeat_max*(length_prevgroup + 1 + 2 + 2*LINK_SIZE) -
-                      2 - 2*LINK_SIZE;   /* Last one doesn't nest */
-          if ((INT64_OR_DOUBLE)repeat_max *
-                (INT64_OR_DOUBLE)(length_prevgroup + 1 + 2 + 2*LINK_SIZE)
-                  > (INT64_OR_DOUBLE)INT_MAX ||
-              OFLOW_MAX - *lengthptr < delta)
-            {
-            *errorcodeptr = ERR20;
-            goto FAILED;
-            }
-          *lengthptr += delta;
-          }
+    /* Otherwise update the main code pointer to the end of the group. */


-        /* This is compiling for real */
+    code = tempcode;


-        else for (i = repeat_max - 1; i >= 0; i--)
-          {
-          *code++ = OP_BRAZERO + repeat_type;
+    /* For a DEFINE group, required and first character settings are not
+    relevant. */


-          /* All but the final copy start a new nesting, maintaining the
-          chain of brackets outstanding. */
+    if (bravalue == OP_DEFINE) break;


-          if (i != 0)
-            {
-            int offset;
-            *code++ = OP_BRA;
-            offset = (bralink == NULL)? 0 : (int)(code - bralink);
-            bralink = code;
-            PUTINC(code, 0, offset);
-            }
+    /* Handle updating of the required and first code units for other types of
+    group. Update for normal brackets of all kinds, and conditions with two
+    branches (see code above). If the bracket is followed by a quantifier with
+    zero repeat, we have to back off. Hence the definition of zeroreqcu and
+    zerofirstcu outside the main loop so that they can be accessed for the back
+    off. */


-          memcpy(code, previous, CU2BYTES(len));
-          code += len;
-          }
+    zeroreqcu = reqcu;
+    zeroreqcuflags = reqcuflags;
+    zerofirstcu = firstcu;
+    zerofirstcuflags = firstcuflags;
+    groupsetfirstcu = FALSE;


-        /* Now chain through the pending brackets, and fill in their length
-        fields (which are holding the chain links pro tem). */
+    if (bravalue >= OP_ONCE)
+      {
+      /* If we have not yet set a firstcu in this branch, take it from the
+      subpattern, remembering that it was set here so that a repeat of more
+      than one can replicate it as reqcu if necessary. If the subpattern has
+      no firstcu, set "none" for the whole branch. In both cases, a zero
+      repeat forces firstcu to "none". */


-        while (bralink != NULL)
+      if (firstcuflags == REQ_UNSET && subfirstcuflags != REQ_UNSET)
+        {
+        if (subfirstcuflags >= 0)
           {
-          int oldlinkoffset;
-          int offset = (int)(code - bralink + 1);
-          PCRE2_UCHAR *bra = code - offset;
-          oldlinkoffset = GET(bra, 1);
-          bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset;
-          *code++ = OP_KET;
-          PUTINC(code, 0, offset);
-          PUT(bra, 1, offset);
+          firstcu = subfirstcu;
+          firstcuflags = subfirstcuflags;
+          groupsetfirstcu = TRUE;
           }
+        else firstcuflags = REQ_NONE;
+        zerofirstcuflags = REQ_NONE;
         }


-      /* If the maximum is unlimited, set a repeater in the final copy. For
-      ONCE brackets, that's all we need to do. However, possessively repeated
-      ONCE brackets can be converted into non-capturing brackets, as the
-      behaviour of (?:xx)++ is the same as (?>xx)++ and this saves having to
-      deal with possessive ONCEs specially.
+      /* If firstcu was previously set, convert the subpattern's firstcu
+      into reqcu if there wasn't one, using the vary flag that was in
+      existence beforehand. */


-      Otherwise, when we are doing the actual compile phase, check to see
-      whether this group is one that could match an empty string. If so,
-      convert the initial operator to the S form (e.g. OP_BRA -> OP_SBRA) so
-      that runtime checking can be done. [This check is also applied to ONCE
-      groups at runtime, but in a different way.]
+      else if (subfirstcuflags >= 0 && subreqcuflags < 0)
+        {
+        subreqcu = subfirstcu;
+        subreqcuflags = subfirstcuflags | tempreqvary;
+        }


-      Then, if the quantifier was possessive and the bracket is not a
-      conditional, we convert the BRA code to the POS form, and the KET code to
-      KETRPOS. (It turns out to be convenient at runtime to detect this kind of
-      subpattern at both the start and at the end.) The use of special opcodes
-      makes it possible to reduce greatly the stack usage in pcre2_match(). If
-      the group is preceded by OP_BRAZERO, convert this to OP_BRAPOSZERO.
+      /* If the subpattern set a required code unit (or set a first code unit
+      that isn't really the first code unit - see above), set it. */


-      Then, if the minimum number of matches is 1 or 0, cancel the possessive
-      flag so that the default action below, of wrapping everything inside
-      atomic brackets, does not happen. When the minimum is greater than 1,
-      there will be earlier copies of the group, and so we still have to wrap
-      the whole thing. */
-
-      else
+      if (subreqcuflags >= 0)
         {
-        PCRE2_UCHAR *ketcode = code - 1 - LINK_SIZE;
-        PCRE2_UCHAR *bracode = ketcode - GET(ketcode, 1);
+        reqcu = subreqcu;
+        reqcuflags = subreqcuflags;
+        }
+      }


-        /* Convert possessive ONCE brackets to non-capturing */
+    /* For a forward assertion, we take the reqcu, if set. This can be
+    helpful if the pattern that follows the assertion doesn't set a different
+    char. For example, it's useful for /(?=abcde).+/. We can't set firstcu
+    for an assertion, however because it leads to incorrect effect for patterns
+    such as /(?=a)a.+/ when the "real" "a" would then become a reqcu instead
+    of a firstcu. This is overcome by a scan at the end if there's no
+    firstcu, looking for an asserted first char. */


-        if ((*bracode == OP_ONCE || *bracode == OP_ONCE_NC) &&
-            possessive_quantifier) *bracode = OP_BRA;
+    else if (bravalue == OP_ASSERT && subreqcuflags >= 0)
+      {
+      reqcu = subreqcu;
+      reqcuflags = subreqcuflags;
+      }


-        /* For non-possessive ONCE brackets, all we need to do is to
-        set the KET. */
+    break;  /* End of nested group handling */


-        if (*bracode == OP_ONCE || *bracode == OP_ONCE_NC)
-          *ketcode = OP_KETRMAX + repeat_type;


-        /* Handle non-ONCE brackets and possessive ONCEs (which have been
-        converted to non-capturing above). */
+    /* ===================================================================*/
+    /* Handle named backreferences and recursions. */


-        else
-          {
-          /* In the compile phase, check whether the group could match an empty
-          string. */
+    case META_BACKREF_BYNAME:
+    case META_RECURSE_BYNAME:
+      {
+      int count, index;
+      PCRE2_SPTR name;
+      BOOL is_dupname = FALSE;
+      named_group *ng = cb->named_groups;
+      uint32_t length = *(++pptr);


-          if (lengthptr == NULL)
-            {
-            PCRE2_UCHAR *scode = bracode;
-            do
-              {
-              int count = 0;
-              int rc = could_be_empty_branch(scode, ketcode, utf, cb, FALSE,
-                NULL, &count);
-              if (rc < 0)
-                {
-                *errorcodeptr = ERR86;
-                goto FAILED;
-                }
-              if (rc > 0)
-                {
-                *bracode += OP_SBRA - OP_BRA;
-                break;
-                }
-              scode += GET(scode, 1);
-              }
-            while (*scode == OP_ALT);
+      GETPLUSOFFSET(offset, pptr);
+      name = cb->start_pattern + offset;


-            /* A conditional group with only one branch has an implicit empty
-            alternative branch. */
+      /* In the first pass, the names generated in the pre-pass are available,
+      but the main name table has not yet been created. Scan the list of names
+      generated in the pre-pass in order to get a number and whether or not
+      this name is duplicated. */


-            if (*bracode == OP_COND && bracode[GET(bracode,1)] != OP_ALT)
-              *bracode = OP_SCOND;
-            }
+      groupnumber = 0;
+      for (i = 0; i < cb->names_found; i++, ng++)
+        {
+        if (length == ng->length &&
+            PRIV(strncmp)(name, ng->name, length) == 0)
+          {
+          is_dupname = ng->isdup;
+          groupnumber = ng->number;


-          /* Handle possessive quantifiers. */
+          /* For a recursion, that's all that is needed. We can now go to
+          the code above that handles numerical recursion, applying it to
+          the first group with the given name. */


-          if (possessive_quantifier)
+          if (meta == META_RECURSE_BYNAME)
             {
-            /* For COND brackets, we wrap the whole thing in a possessively
-            repeated non-capturing bracket, because we have not invented POS
-            versions of the COND opcodes. */
+            meta_arg = groupnumber;
+            goto HANDLE_NUMERICAL_RECURSION;
+            }


-            if (*bracode == OP_COND || *bracode == OP_SCOND)
-              {
-              int nlen = (int)(code - bracode);
-              memmove(bracode + 1 + LINK_SIZE, bracode, CU2BYTES(nlen));
-              code += 1 + LINK_SIZE;
-              nlen += 1 + LINK_SIZE;
-              *bracode = (*bracode == OP_COND)? OP_BRAPOS : OP_SBRAPOS;
-              *code++ = OP_KETRPOS;
-              PUTINC(code, 0, nlen);
-              PUT(bracode, 1, nlen);
-              }
+          /* For a back reference, update the back reference map and the
+          maximum back reference. Then, for each group, we must check to
+          see if it is recursive, that is, it is inside the group that it
+          references. A flag is set so that the group can be made atomic.
+          */


-            /* For non-COND brackets, we modify the BRA code and use KETRPOS. */
+          cb->backref_map |= (groupnumber < 32)? (1u << groupnumber) : 1;
+          if (groupnumber > cb->top_backref)
+            cb->top_backref = groupnumber;


-            else
+          for (oc = cb->open_caps; oc != NULL; oc = oc->next)
+            {
+            if (oc->number == groupnumber)
               {
-              *bracode += 1;              /* Switch to xxxPOS opcodes */
-              *ketcode = OP_KETRPOS;
+              oc->flag = TRUE;
+              break;
               }
-
-            /* If the minimum is zero, mark it as possessive, then unset the
-            possessive flag when the minimum is 0 or 1. */
-
-            if (brazeroptr != NULL) *brazeroptr = OP_BRAPOSZERO;
-            if (repeat_min < 2) possessive_quantifier = FALSE;
             }
-
-          /* Non-possessive quantifier */
-
-          else *ketcode = OP_KETRMAX + repeat_type;
           }
         }
-      }


-    /* If previous is OP_FAIL, it was generated by an empty class []
-    (PCRE2_ALLOW_EMPTY_CLASS is set). The other ways in which OP_FAIL can be
-    generated, that is by (*FAIL) or (?!), set previous to NULL, which gives a
-    "nothing to repeat" error above. We can just ignore the repeat in empty
-    class case. */
+      /* If the name was not found we have a bad reference. */


-    else if (*previous == OP_FAIL) goto END_REPEAT;
-
-    /* Else there's some kind of shambles */
-
-    else
-      {
-      *errorcodeptr = ERR10;
-      goto FAILED;
-      }
-
-    /* If the character following a repeat is '+', possessive_quantifier is
-    TRUE. For some opcodes, there are special alternative opcodes for this
-    case. For anything else, we wrap the entire repeated item inside OP_ONCE
-    brackets. Logically, the '+' notation is just syntactic sugar, taken from
-    Sun's Java package, but the special opcodes can optimize it.
-
-    Some (but not all) possessively repeated subpatterns have already been
-    completely handled in the code just above. For them, possessive_quantifier
-    is always FALSE at this stage. Note that the repeated item starts at
-    tempcode, not at previous, which might be the first part of a string whose
-    (former) last char we repeated. */
-
-    if (possessive_quantifier)
-      {
-      int len;
-
-      /* Possessifying an EXACT quantifier has no effect, so we can ignore it.
-      However, QUERY, STAR, or UPTO may follow (for quantifiers such as {5,6},
-      {5,}, or {5,10}). We skip over an EXACT item; if the length of what
-      remains is greater than zero, there's a further opcode that can be
-      handled. If not, do nothing, leaving the EXACT alone. */
-
-      switch(*tempcode)
+      if (groupnumber == 0)
         {
-        case OP_TYPEEXACT:
-        tempcode += PRIV(OP_lengths)[*tempcode] +
-          ((tempcode[1 + IMM2_SIZE] == OP_PROP
-          || tempcode[1 + IMM2_SIZE] == OP_NOTPROP)? 2 : 0);
-        break;
-
-        /* CHAR opcodes are used for exacts whose count is 1. */
-
-        case OP_CHAR:
-        case OP_CHARI:
-        case OP_NOT:
-        case OP_NOTI:
-        case OP_EXACT:
-        case OP_EXACTI:
-        case OP_NOTEXACT:
-        case OP_NOTEXACTI:
-        tempcode += PRIV(OP_lengths)[*tempcode];
-#ifdef SUPPORT_UNICODE
-        if (utf && HAS_EXTRALEN(tempcode[-1]))
-          tempcode += GET_EXTRALEN(tempcode[-1]);
-#endif
-        break;
-
-        /* For the class opcodes, the repeat operator appears at the end;
-        adjust tempcode to point to it. */
-
-        case OP_CLASS:
-        case OP_NCLASS:
-        tempcode += 1 + 32/sizeof(PCRE2_UCHAR);
-        break;
-
-#ifdef SUPPORT_WIDE_CHARS
-        case OP_XCLASS:
-        tempcode += GET(tempcode, 1);
-        break;
-#endif
+        *errorcodeptr = ERR15;
+        cb->erroroffset = offset;
+        return FALSE;
         }


-      /* If tempcode is equal to code (which points to the end of the repeated
-      item), it means we have skipped an EXACT item but there is no following
-      QUERY, STAR, or UPTO; the value of len will be 0, and we do nothing. In
-      all other cases, tempcode will be pointing to the repeat opcode, and will
-      be less than code, so the value of len will be greater than 0. */
+      /* If a back reference name is not duplicated, we can handle it as
+      a numerical reference. */


-      len = (int)(code - tempcode);
-      if (len > 0)
+      if (!is_dupname)
         {
-        unsigned int repcode = *tempcode;
+        meta_arg = groupnumber;
+        goto HANDLE_SINGLE_REFERENCE;
+        }


-        /* There is a table for possessifying opcodes, all of which are less
-        than OP_CALLOUT. A zero entry means there is no possessified version.
-        */
+      /* If a back reference name is duplicated, we generate a different
+      opcode to a numerical back reference. In the second pass we must
+      search for the index and count in the final name table. */


-        if (repcode < OP_CALLOUT && opcode_possessify[repcode] > 0)
-          *tempcode = opcode_possessify[repcode];
+      count = 0;  /* Values for first pass (avoids compiler warning) */
+      index = 0;
+      if (lengthptr == NULL && !find_dupname_details(name, length, &index,
+            &count, errorcodeptr, cb)) return FALSE;


-        /* For opcode without a special possessified version, wrap the item in
-        ONCE brackets. */
-
-        else
-          {
-          memmove(tempcode + 1 + LINK_SIZE, tempcode, CU2BYTES(len));
-          code += 1 + LINK_SIZE;
-          len += 1 + LINK_SIZE;
-          tempcode[0] = OP_ONCE;
-          *code++ = OP_KET;
-          PUTINC(code, 0, len);
-          PUT(tempcode, 1, len);
-          }
-        }
+      if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+      *code++ = ((options & PCRE2_CASELESS) != 0)? OP_DNREFI : OP_DNREF;
+      PUT2INC(code, 0, index);
+      PUT2INC(code, 0, count);
       }
+    break;


-    /* In all case we no longer have a previous item. We also set the
-    "follows varying string" flag for subsequently encountered reqcus if
-    it isn't already set and we have just passed a varying length item. */


-    END_REPEAT:
-    previous = NULL;
-    cb->req_varyopt |= reqvary;
+    /* ===================================================================*/
+    /* Handle a numerical callout. */
+
+    case META_CALLOUT_NUMBER:
+    code[0] = OP_CALLOUT;
+    PUT(code, 1, pptr[1]);               /* Offset to next pattern item */
+    PUT(code, 1 + LINK_SIZE, pptr[2]);   /* Length of next pattern item */
+    code[1 + 2*LINK_SIZE] = pptr[3];
+    pptr += 3;
+    code += PRIV(OP_lengths)[OP_CALLOUT];
     break;



     /* ===================================================================*/
-    /* Start of nested parenthesized sub-expression, or lookahead or lookbehind
-    or option setting or condition or all the other extended parenthesis forms.
-    We must save the current high-water-mark for the forward reference list so
-    that we know where they start for this group. However, because the list may
-    be extended when there are very many forward references (usually the result
-    of a replicated inner group), we must use an offset rather than an absolute
-    address. Note that (?# comments are dealt with at the top of the loop;
-    they do not get this far. */
+    /* Handle a callout with a string argument. In the pre-pass we just compute
+    the length without generating anything. The length in pptr[3] includes both
+    delimiters; in the actual compile only the first one is copied, but a
+    terminating zero is added. Any doubled delimiters within the string make
+    this an overestimate, but it is not worth bothering about. */


-    case CHAR_LEFT_PARENTHESIS:
-    ptr++;
+    case META_CALLOUT_STRING:
+    if (lengthptr != NULL)
+      {
+      *lengthptr += pptr[3] + (1 + 4*LINK_SIZE);
+      pptr += 3;
+      SKIPOFFSET(pptr);
+      }


-    /* Deal with various "verbs" that can be introduced by '*'. */
+    /* In the real compile we can copy the string. The starting delimiter is
+     included so that the client can discover it if they want. We also pass the
+     start offset to help a script language give better error messages. */


-    if (ptr[0] == CHAR_ASTERISK && (ptr[1] == ':'
-         || (MAX_255(ptr[1]) && ((cb->ctypes[ptr[1]] & ctype_letter) != 0))))
+    else
       {
-      int i, namelen;
-      int arglen = 0;
-      const char *vn = verbnames;
-      PCRE2_SPTR name = ptr + 1;
-      PCRE2_SPTR arg = NULL;
-      previous = NULL;
-      ptr++;
+      PCRE2_SPTR pp;
+      uint32_t delimiter;
+      uint32_t length = pptr[3];
+      PCRE2_UCHAR *callout_string = code + (1 + 4*LINK_SIZE);


-      /* Increment ptr, set namelen, check length */
+      code[0] = OP_CALLOUT_STR;
+      PUT(code, 1, pptr[1]);               /* Offset to next pattern item */
+      PUT(code, 1 + LINK_SIZE, pptr[2]);   /* Length of next pattern item */


-      READ_NAME(ctype_letter, ERR60, *errorcodeptr);
+      pptr += 3;
+      GETPLUSOFFSET(offset, pptr);         /* Offset to string in pattern */
+      pp = cb->start_pattern + offset;
+      delimiter = *callout_string++ = *pp++;
+      if (delimiter == CHAR_LEFT_CURLY_BRACKET)
+        delimiter = CHAR_RIGHT_CURLY_BRACKET;
+      PUT(code, 1 + 3*LINK_SIZE, (int)(offset + 1));  /* One after delimiter */


-      /* It appears that Perl allows any characters whatsoever, other than
-      a closing parenthesis, to appear in arguments, so we no longer insist on
-      letters, digits, and underscores. Perl does not, however, do any
-      interpretation within arguments, and has no means of including a closing
-      parenthesis. PCRE supports escape processing but only when it is
-      requested by an option. Note that check_escape() will not return values
-      greater than the code unit maximum when not in UTF mode. */
+      /* The syntax of the pattern was checked in the parsing scan. The length
+      includes both delimiters, but we have passed the opening one just above,
+      so we reduce length before testing it. The test is for > 1 because we do
+      not want to copy the final delimiter. This also ensures that pp[1] is
+      accessible. */


-      if (*ptr == CHAR_COLON)
+      while (--length > 1)
         {
-        arg = ++ptr;
-
-        if ((options & PCRE2_ALT_VERBNAMES) == 0)
+        if (*pp == delimiter && pp[1] == delimiter)
           {
-          arglen = 0;
-          while (ptr < cb->end_pattern && *ptr != CHAR_RIGHT_PARENTHESIS)
-            {
-            ptr++;                                /* Check length as we go */
-            arglen++;                             /* along, to avoid the   */
-            if ((unsigned int)arglen > MAX_MARK)  /* possibility of overflow. */
-              {
-              *errorcodeptr = ERR76;
-              goto FAILED;
-              }
-            }
+          *callout_string++ = delimiter;
+          pp += 2;
+          length--;
           }
-        else
-          {
-          /* The length check is in process_verb_names() */
-          arglen = process_verb_name(&ptr, NULL, errorcodeptr, options,
-            utf, cb);
-          if (arglen < 0) goto FAILED;
-          }
+        else *callout_string++ = *pp++;
         }
+      *callout_string++ = CHAR_NULL;


-      if (*ptr != CHAR_RIGHT_PARENTHESIS)
-        {
-        *errorcodeptr = ERR60;
-        goto FAILED;
-        }
+      /* Set the length of the entire item, the advance to its end. */


-      /* Scan the table of verb names */
+      PUT(code, 1 + 2*LINK_SIZE, (int)(callout_string - code));
+      code = callout_string;
+      }
+    break;


-      for (i = 0; i < verbcount; i++)
-        {
-        if (namelen == verbs[i].len &&
-            PRIV(strncmp_c8)(name, vn, namelen) == 0)
-          {
-          int setverb;


-          /* Check for open captures before ACCEPT and convert it to
-          ASSERT_ACCEPT if in an assertion. */
+    /* ===================================================================*/
+    /* Handle repetition. The different types are all sorted out in the parsing
+    pass. */


-          if (verbs[i].op == OP_ACCEPT)
-            {
-            open_capitem *oc;
-            if (arglen != 0)
-              {
-              *errorcodeptr = ERR59;
-              goto FAILED;
-              }
-            cb->had_accept = TRUE;
+    case META_MINMAX_PLUS:
+    case META_MINMAX_QUERY:
+    case META_MINMAX:
+    repeat_min = *(++pptr);
+    repeat_max = *(++pptr);
+    goto REPEAT;


-            /* In the first pass, just accumulate the length required;
-            otherwise hitting (*ACCEPT) inside many nested parentheses can
-            cause workspace overflow. */
+    case META_ASTERISK:
+    case META_ASTERISK_PLUS:
+    case META_ASTERISK_QUERY:
+    repeat_min = 0;
+    repeat_max = REPEAT_UNLIMITED;
+    goto REPEAT;


-            for (oc = cb->open_caps; oc != NULL; oc = oc->next)
-              {
-              if (lengthptr != NULL)
-                {
-                *lengthptr += CU2BYTES(1) + IMM2_SIZE;
-                }
-              else
-                {
-                *code++ = OP_CLOSE;
-                PUT2INC(code, 0, oc->number);
-                }
-              }
-            setverb = *code++ =
-              (cb->assert_depth > 0)? OP_ASSERT_ACCEPT : OP_ACCEPT;
+    case META_PLUS:
+    case META_PLUS_PLUS:
+    case META_PLUS_QUERY:
+    repeat_min = 1;
+    repeat_max = REPEAT_UNLIMITED;
+    goto REPEAT;


-            /* Do not set firstcu after *ACCEPT */
-            if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
-            }
+    case META_QUERY:
+    case META_QUERY_PLUS:
+    case META_QUERY_QUERY:
+    repeat_min = 0;
+    repeat_max = 1;


-          /* Handle other cases with/without an argument */
+    REPEAT:


-          else if (arglen == 0)    /* There is no argument */
-            {
-            if (verbs[i].op < 0)   /* Argument is mandatory */
-              {
-              *errorcodeptr = ERR66;
-              goto FAILED;
-              }
-            setverb = *code++ = verbs[i].op;
-            }
+    /* Remember whether this is a variable length repeat, and default to
+    single-char opcodes. */


-          else                        /* An argument is present */
-            {
-            if (verbs[i].op_arg < 0)  /* Argument is forbidden */
-              {
-              *errorcodeptr = ERR59;
-              goto FAILED;
-              }
-            setverb = *code++ = verbs[i].op_arg;
+    reqvary = (repeat_min == repeat_max)? 0 : REQ_VARY;
+    op_type = 0;


-            /* Arguments can be very long, especially in 16- and 32-bit modes,
-            and can overflow the workspace in the first pass. Instead of
-            putting the argument into memory, we just update the length counter
-            and set up an empty argument. */
+    /* If the repeat is {1} we can ignore it. */


-            if (lengthptr != NULL)
-              {
-              *lengthptr += arglen;
-              *code++ = 0;
-              }
-            else
-              {
-              *code++ = arglen;
-              if ((options & PCRE2_ALT_VERBNAMES) != 0)
-                {
-                PCRE2_UCHAR *memcode = code;  /* code is "register" */
-                (void)process_verb_name(&arg, &memcode, errorcodeptr, options,
-                  utf, cb);
-                code = memcode;
-                }
-              else   /* No argument processing */
-                {
-                memcpy(code, arg, CU2BYTES(arglen));
-                code += arglen;
-                }
-              }
+    if (repeat_max == 1 && repeat_min == 1) goto END_REPEAT;


-            *code++ = 0;
-            }
+    /* Adjust first and required code units for a zero repeat. */


-          switch (setverb)
-            {
-            case OP_THEN:
-            case OP_THEN_ARG:
-            cb->external_flags |= PCRE2_HASTHEN;
-            break;
+    if (repeat_min == 0)
+      {
+      firstcu = zerofirstcu;
+      firstcuflags = zerofirstcuflags;
+      reqcu = zeroreqcu;
+      reqcuflags = zeroreqcuflags;
+      }


-            case OP_PRUNE:
-            case OP_PRUNE_ARG:
-            case OP_SKIP:
-            case OP_SKIP_ARG:
-            cb->had_pruneorskip = TRUE;
-            break;
-            }
+    /* Note the greediness and possessiveness. */


-          break;  /* Found verb, exit loop */
-          }
+    switch (meta)
+      {
+      case META_MINMAX_PLUS:
+      case META_ASTERISK_PLUS:
+      case META_PLUS_PLUS:
+      case META_QUERY_PLUS:
+      repeat_type = 0;                  /* Force greedy */
+      possessive_quantifier = TRUE;
+      break;


-        vn += verbs[i].len + 1;
-        }
+      case META_MINMAX_QUERY:
+      case META_ASTERISK_QUERY:
+      case META_PLUS_QUERY:
+      case META_QUERY_QUERY:
+      repeat_type = greedy_non_default;
+      possessive_quantifier = FALSE;
+      break;


-      if (i < verbcount) continue;    /* Successfully handled a verb */
-      *errorcodeptr = ERR60;          /* Verb not recognized */
-      goto FAILED;
+      default:
+      repeat_type = greedy_default;
+      possessive_quantifier = FALSE;
+      break;
       }


-    /* Initialization for "real" parentheses */
+    /* Save start of previous item, in case we have to move it up in order to
+    insert something before it, and remember what it was. */


-    newoptions = options;
-    skipunits = 0;
-    bravalue = OP_CBRA;
-    reset_bracount = FALSE;
+    tempcode = previous;
+    op_previous = *previous;


-    /* Deal with the extended parentheses; all are introduced by '?', and the
-    appearance of any of them means that this is not a capturing group. */
+    /* If previous was a recursion call, wrap it in atomic brackets so that
+    previous becomes the atomic group. All recursions were so wrapped in the
+    past, but it no longer happens for non-repeated recursions. In fact, the
+    repeated ones could be re-implemented independently so as not to need this,
+    but for the moment we rely on the code for repeating groups. */


-    if (*ptr == CHAR_QUESTION_MARK)
+    if (op_previous == OP_RECURSE)
       {
-      int i, count;
-      int namelen;                /* Must be signed */
-      uint32_t index;
-      uint32_t set, unset, *optset;
-      named_group *ng;
-      PCRE2_SPTR name;
-      PCRE2_UCHAR *slot;
+      memmove(previous + 1 + LINK_SIZE, previous, CU2BYTES(1 + LINK_SIZE));
+      op_previous = *previous = OP_ONCE;
+      PUT(previous, 1, 2 + 2*LINK_SIZE);
+      previous[2 + 2*LINK_SIZE] = OP_KET;
+      PUT(previous, 3 + 2*LINK_SIZE, 2 + 2*LINK_SIZE);
+      code += 2 + 2 * LINK_SIZE;
+      length_prevgroup = 3 + 3*LINK_SIZE;
+      }


-      switch (*(++ptr))
-        {
-        /* ------------------------------------------------------------ */
-        case CHAR_VERTICAL_LINE:  /* Reset capture count for each branch */
-        reset_bracount = TRUE;
-        /* Fall through */
+    /* Now handle repetition for the different types of item. */


-        /* ------------------------------------------------------------ */
-        case CHAR_COLON:          /* Non-capturing bracket */
-        bravalue = OP_BRA;
-        ptr++;
-        break;
+    switch (op_previous)
+      {
+      /* If previous was a character or negated character match, abolish the
+      item and generate a repeat item instead. If a char item has a minimum of
+      more than one, ensure that it is set in reqcu - it might not be if a
+      sequence such as x{3} is the first thing in a branch because the x will
+      have gone into firstcu instead.  */


-        /* ------------------------------------------------------------ */
-        case CHAR_LEFT_PARENTHESIS:
-        bravalue = OP_COND;       /* Conditional group */
-        tempptr = ptr;
+      case OP_CHAR:
+      case OP_CHARI:
+      case OP_NOT:
+      case OP_NOTI:
+      op_type = chartypeoffset[op_previous - OP_CHAR];


-        /* A condition can be an assertion, a number (referring to a numbered
-        group's having been set), a name (referring to a named group), or 'R',
-        referring to recursion. R<digits> and R&name are also permitted for
-        recursion tests.
+      /* Deal with UTF characters that take up more than one code unit. */


-        There are ways of testing a named group: (?(name)) is used by Python;
-        Perl 5.10 onwards uses (?(<name>) or (?('name')).
+#ifdef MAYBE_UTF_MULTI
+      if (utf && NOT_FIRSTCU(code[-1]))
+        {
+        PCRE2_UCHAR *lastchar = code - 1;
+        BACKCHAR(lastchar);
+        mclength = (uint32_t)(code - lastchar);   /* Length of UTF character */
+        memcpy(mcbuffer, lastchar, CU2BYTES(mclength));  /* Save the char */
+        }
+      else
+#endif  /* MAYBE_UTF_MULTI */


-        There is one unfortunate ambiguity, caused by history. 'R' can be the
-        recursive thing or the name 'R' (and similarly for 'R' followed by
-        digits). We look for a name first; if not found, we try the other case.
-
-        For compatibility with auto-callouts, we allow a callout to be
-        specified before a condition that is an assertion. First, check for the
-        syntax of a callout; if found, adjust the temporary pointer that is
-        used to check for an assertion condition. That's all that is needed! */
-
-        if (ptr[1] == CHAR_QUESTION_MARK && ptr[2] == CHAR_C)
+      /* Handle the case of a single code unit - either with no UTF support, or
+      with UTF disabled, or for a single-code-unit UTF character. */
+        {
+        mcbuffer[0] = code[-1];
+        mclength = 1;
+        if (op_previous <= OP_CHARI && repeat_min > 1)
           {
-          if (IS_DIGIT(ptr[3]) || ptr[3] == CHAR_RIGHT_PARENTHESIS)
-            {
-            for (i = 3;; i++) if (!IS_DIGIT(ptr[i])) break;
-            if (ptr[i] == CHAR_RIGHT_PARENTHESIS)
-              tempptr += i + 1;
-            }
-          else
-            {
-            uint32_t delimiter = 0;
-            for (i = 0; PRIV(callout_start_delims)[i] != 0; i++)
-              {
-              if (ptr[3] == PRIV(callout_start_delims)[i])
-                {
-                delimiter = PRIV(callout_end_delims)[i];
-                break;
-                }
-              }
-            if (delimiter != 0)
-              {
-              for (i = 4; ptr + i < cb->end_pattern; i++)
-                {
-                if (ptr[i] == delimiter)
-                  {
-                  if (ptr[i+1] == delimiter) i++;
-                  else
-                    {
-                    if (ptr[i+1] == CHAR_RIGHT_PARENTHESIS) tempptr += i + 2;
-                    break;
-                    }
-                  }
-                }
-              }
-            }
-
-          /* tempptr should now be pointing to the opening parenthesis of the
-          assertion condition. */
-
-          if (*tempptr != CHAR_LEFT_PARENTHESIS)
-            {
-            *errorcodeptr = ERR28;
-            goto FAILED;
-            }
+          reqcu = mcbuffer[0];
+          reqcuflags = req_caseopt | cb->req_varyopt;
           }
+        }
+      goto OUTPUT_SINGLE_REPEAT;  /* Code shared with single character types */


-        /* For conditions that are assertions, check the syntax, and then exit
-        the switch. This will take control down to where bracketed groups
-        are processed. The assertion will be handled as part of the group,
-        but we need to identify this case because the conditional assertion may
-        not be quantifier. */
+      /* If previous was a character class or a back reference, we put the
+      repeat stuff after it, but just skip the item if the repeat was {0,0}. */


-        if (tempptr[1] == CHAR_QUESTION_MARK &&
-              (tempptr[2] == CHAR_EQUALS_SIGN ||
-               tempptr[2] == CHAR_EXCLAMATION_MARK ||
-                 (tempptr[2] == CHAR_LESS_THAN_SIGN &&
-                   (tempptr[3] == CHAR_EQUALS_SIGN ||
-                    tempptr[3] == CHAR_EXCLAMATION_MARK))))
-          {
-          cb->iscondassert = TRUE;
-          break;
-          }
+#ifdef SUPPORT_WIDE_CHARS
+      case OP_XCLASS:
+#endif
+      case OP_CLASS:
+      case OP_NCLASS:
+      case OP_REF:
+      case OP_REFI:
+      case OP_DNREF:
+      case OP_DNREFI:


-        /* Other conditions use OP_CREF/OP_DNCREF/OP_RREF/OP_DNRREF, and all
-        need to skip at least 1+IMM2_SIZE bytes at the start of the group. */
+      if (repeat_max == 0)
+        {
+        code = previous;
+        goto END_REPEAT;
+        }


-        code[1+LINK_SIZE] = OP_CREF;
-        skipunits = 1+IMM2_SIZE;
-        refsign = -1;     /* => not a number */
-        namelen = -1;     /* => not a name; must set to avoid warning */
-        name = NULL;      /* Always set to avoid warning */
-        recno = 0;        /* Always set to avoid warning */
+      if (repeat_min == 0 && repeat_max == REPEAT_UNLIMITED)
+        *code++ = OP_CRSTAR + repeat_type;
+      else if (repeat_min == 1 && repeat_max == REPEAT_UNLIMITED)
+        *code++ = OP_CRPLUS + repeat_type;
+      else if (repeat_min == 0 && repeat_max == 1)
+        *code++ = OP_CRQUERY + repeat_type;
+      else
+        {
+        *code++ = OP_CRRANGE + repeat_type;
+        PUT2INC(code, 0, repeat_min);
+        if (repeat_max == REPEAT_UNLIMITED) repeat_max = 0;  /* 2-byte encoding for max */
+        PUT2INC(code, 0, repeat_max);
+        }
+      break;


-        /* Point at character after (?( */
+      /* If previous is OP_FAIL, it was generated by an empty class []
+      (PCRE2_ALLOW_EMPTY_CLASS is set). The other ways in which OP_FAIL can be
+      generated, that is by (*FAIL) or (?!), disallow a quantifier at parse
+      time. We can just ignore this repeat. */


-        ptr++;
+      case OP_FAIL:
+      goto END_REPEAT;


-        /* Check for (?(VERSION[>]=n.m), which is a facility whereby indirect
-        users of PCRE2 via an application can discover which release of PCRE2
-        is being used. */
+      /* If previous was a bracket group, we may have to replicate it in
+      certain cases. Note that at this point we can encounter only the "basic"
+      bracket opcodes such as BRA and CBRA, as this is the place where they get
+      converted into the more special varieties such as BRAPOS and SBRA.
+      Originally, PCRE did not allow repetition of assertions, but now it does,
+      for Perl compatibility. */


-        if (PRIV(strncmp_c8)(ptr, STRING_VERSION, 7) == 0 &&
-            ptr[7] != CHAR_RIGHT_PARENTHESIS)
-          {
-          BOOL ge = FALSE;
-          int major = 0;
-          int minor = 0;
+      case OP_ASSERT:
+      case OP_ASSERT_NOT:
+      case OP_ASSERTBACK:
+      case OP_ASSERTBACK_NOT:
+      case OP_ONCE:
+      case OP_ONCE_NC:
+      case OP_BRA:
+      case OP_CBRA:
+      case OP_COND:
+        {
+        int len = (int)(code - previous);
+        PCRE2_UCHAR *bralink = NULL;
+        PCRE2_UCHAR *brazeroptr = NULL;


-          ptr += 7;
-          if (*ptr == CHAR_GREATER_THAN_SIGN)
-            {
-            ge = TRUE;
-            ptr++;
-            }
+        /* Repeating a DEFINE group (or any group where the condition is always
+        FALSE and there is only one branch) is pointless, but Perl allows the
+        syntax, so we just ignore the repeat. */


-          /* NOTE: cannot write IS_DIGIT(*(++ptr)) here because IS_DIGIT
-          references its argument twice. */
+        if (op_previous == OP_COND && previous[LINK_SIZE+1] == OP_FALSE &&
+            previous[GET(previous, 1)] != OP_ALT)
+          goto END_REPEAT;


-          if (*ptr != CHAR_EQUALS_SIGN || (ptr++, !IS_DIGIT(*ptr)))
-            {
-            *errorcodeptr = ERR79;
-            goto FAILED;
-            }
+        /* There is no sense in actually repeating assertions. The only potential
+        use of repetition is in cases when the assertion is optional. Therefore,
+        if the minimum is greater than zero, just ignore the repeat. If the
+        maximum is not zero or one, set it to 1. */


-          while (IS_DIGIT(*ptr)) major = major * 10 + *ptr++ - '0';
-          if (*ptr == CHAR_DOT)
-            {
-            ptr++;
-            while (IS_DIGIT(*ptr)) minor = minor * 10 + *ptr++ - '0';
-            if (minor < 10) minor *= 10;
-            }
-
-          if (*ptr != CHAR_RIGHT_PARENTHESIS || minor > 99)
-            {
-            *errorcodeptr = ERR79;
-            goto FAILED;
-            }
-
-          if (ge)
-            code[1+LINK_SIZE] = ((PCRE2_MAJOR > major) ||
-              (PCRE2_MAJOR == major && PCRE2_MINOR >= minor))?
-                OP_TRUE : OP_FALSE;
-          else
-            code[1+LINK_SIZE] = (PCRE2_MAJOR == major && PCRE2_MINOR == minor)?
-              OP_TRUE : OP_FALSE;
-
-          ptr++;
-          skipunits = 1;
-          break;  /* End of condition processing */
+        if (op_previous < OP_ONCE)    /* Assertion */
+          {
+          if (repeat_min > 0) goto END_REPEAT;
+          if (repeat_max > 1) repeat_max = 1;
           }


-        /* Check for a test for recursion in a named group. */
+        /* The case of a zero minimum is special because of the need to stick
+        OP_BRAZERO in front of it, and because the group appears once in the
+        data, whereas in other cases it appears the minimum number of times. For
+        this reason, it is simplest to treat this case separately, as otherwise
+        the code gets far too messy. There are several special subcases when the
+        minimum is zero. */


-        if (*ptr == CHAR_R && ptr[1] == CHAR_AMPERSAND)
+        if (repeat_min == 0)
           {
-          terminator = -1;
-          ptr += 2;
-          code[1+LINK_SIZE] = OP_RREF;    /* Change the type of test */
-          }
+          /* If the maximum is also zero, we used to just omit the group from
+          the output altogether, like this:


-        /* Check for a test for a named group's having been set, using the Perl
-        syntax (?(<name>) or (?('name'), and also allow for the original PCRE
-        syntax of (?(name) or for (?(+n), (?(-n), and just (?(n). */
+          ** if (repeat_max == 0)
+          **   {
+          **   code = previous;
+          **   goto END_REPEAT;
+          **   }


-        else if (*ptr == CHAR_LESS_THAN_SIGN)
-          {
-          terminator = CHAR_GREATER_THAN_SIGN;
-          ptr++;
-          }
-        else if (*ptr == CHAR_APOSTROPHE)
-          {
-          terminator = CHAR_APOSTROPHE;
-          ptr++;
-          }
-        else
-          {
-          terminator = CHAR_NULL;
-          if (*ptr == CHAR_MINUS || *ptr == CHAR_PLUS) refsign = *ptr++;
-            else if (IS_DIGIT(*ptr)) refsign = 0;
-          }
+          However, that fails when a group or a subgroup within it is
+          referenced as a subroutine from elsewhere in the pattern, so now we
+          stick in OP_SKIPZERO in front of it so that it is skipped on
+          execution. As we don't have a list of which groups are referenced, we
+          cannot do this selectively.


-        /* Handle a number */
+          If the maximum is 1 or unlimited, we just have to stick in the
+          BRAZERO and do no more at this point. */


-        if (refsign >= 0)
-          {
-          while (IS_DIGIT(*ptr))
+          if (repeat_max <= 1 || repeat_max == REPEAT_UNLIMITED)
             {
-            if (recno > INT_MAX / 10 - 1)  /* Integer overflow */
+            memmove(previous + 1, previous, CU2BYTES(len));
+            code++;
+            if (repeat_max == 0)
               {
-              while (IS_DIGIT(*ptr)) ptr++;
-              *errorcodeptr = ERR61;
-              goto FAILED;
+              *previous++ = OP_SKIPZERO;
+              goto END_REPEAT;
               }
-            recno = recno * 10 + (int)(*ptr - CHAR_0);
-            ptr++;
+            brazeroptr = previous;    /* Save for possessive optimizing */
+            *previous++ = OP_BRAZERO + repeat_type;
             }
-          }


-        /* Otherwise we expect to read a name; anything else is an error. When
-        the referenced name is one of a number of duplicates, a different
-        opcode is used and it needs more memory. Unfortunately we cannot tell
-        whether this is the case in the first pass, so we have to allow for
-        more memory always. In the second pass, the additional to skipunits
-        happens later. */
+          /* If the maximum is greater than 1 and limited, we have to replicate
+          in a nested fashion, sticking OP_BRAZERO before each set of brackets.
+          The first one has to be handled carefully because it's the original
+          copy, which has to be moved up. The remainder can be handled by code
+          that is common with the non-zero minimum case below. We have to
+          adjust the value or repeat_max, since one less copy is required. */


-        else
-          {
-          if (IS_DIGIT(*ptr))
+          else
             {
-            *errorcodeptr = ERR44;  /* Group name must start with non-digit */
-            goto FAILED;
+            int linkoffset;
+            memmove(previous + 2 + LINK_SIZE, previous, CU2BYTES(len));
+            code += 2 + LINK_SIZE;
+            *previous++ = OP_BRAZERO + repeat_type;
+            *previous++ = OP_BRA;
+
+            /* We chain together the bracket link offset fields that have to be
+            filled in later when the ends of the brackets are reached. */
+
+            linkoffset = (bralink == NULL)? 0 : (int)(previous - bralink);
+            bralink = previous;
+            PUTINC(previous, 0, linkoffset);
             }
-          if (!MAX_255(*ptr) || (cb->ctypes[*ptr] & ctype_word) == 0)
-            {
-            *errorcodeptr = ERR28;   /* Assertion expected */
-            goto FAILED;
-            }
-          name = ptr;
-          /* Increment ptr, set namelen, check length */
-          READ_NAME(ctype_word, ERR48, *errorcodeptr);
-          if (lengthptr != NULL) skipunits += IMM2_SIZE;
-          }


-        /* Check the terminator */
-
-        if ((terminator > 0 && *ptr++ != (PCRE2_UCHAR)terminator) ||
-            *ptr++ != CHAR_RIGHT_PARENTHESIS)
-          {
-          ptr--;                  /* Error offset */
-          *errorcodeptr = ERR26;  /* Malformed number or name */
-          goto FAILED;
+          if (repeat_max != REPEAT_UNLIMITED) repeat_max--;
           }


-        /* Do no further checking in the pre-compile phase. */
+        /* If the minimum is greater than zero, replicate the group as many
+        times as necessary, and adjust the maximum to the number of subsequent
+        copies that we need. */


-        if (lengthptr != NULL) break;
-
-        /* In the real compile we do the work of looking for the actual
-        reference. If refsign is not negative, it means we have a number in
-        recno. */
-
-        if (refsign >= 0)
+        else
           {
-          if (recno <= 0)
+          if (repeat_min > 1)
             {
-            *errorcodeptr = ERR35;
-            goto FAILED;
-            }
-          if (refsign != 0) recno = (refsign == CHAR_MINUS)?
-            (cb->bracount + 1) - recno : recno + cb->bracount;
-          if (recno <= 0 || (uint32_t)recno > cb->final_bracount)
-            {
-            *errorcodeptr = ERR15;
-            goto FAILED;
-            }
-          PUT2(code, 2+LINK_SIZE, recno);
-          if ((uint32_t)recno > cb->top_backref) cb->top_backref = recno;
-          break;
-          }
+            /* In the pre-compile phase, we don't actually do the replication.
+            We just adjust the length as if we had. Do some paranoid checks for
+            potential integer overflow. The INT64_OR_DOUBLE type is a 64-bit
+            integer type when available, otherwise double. */


-        /* Otherwise look for the name. */
+            if (lengthptr != NULL)
+              {
+              PCRE2_SIZE delta = (repeat_min - 1)*length_prevgroup;
+              if ((INT64_OR_DOUBLE)(repeat_min - 1)*
+                    (INT64_OR_DOUBLE)length_prevgroup >
+                      (INT64_OR_DOUBLE)INT_MAX ||
+                  OFLOW_MAX - *lengthptr < delta)
+                {
+                *errorcodeptr = ERR20;
+                return FALSE;
+                }
+              *lengthptr += delta;
+              }


-        slot = cb->name_table;
-        for (i = 0; i < cb->names_found; i++)
-          {
-          if (PRIV(strncmp)(name, slot+IMM2_SIZE, namelen) == 0) break;
-          slot += cb->name_entry_size;
-          }
+            /* This is compiling for real. If there is a set first code unit for
+            the group, and we have not yet set a "required code unit", set it. */


-        /* Found the named subpattern. If the name is duplicated, add one to
-        the opcode to change CREF/RREF into DNCREF/DNRREF and insert
-        appropriate data values. Otherwise, just insert the unique subpattern
-        number. */
-
-        if (i < cb->names_found)
-          {
-          int offset = i;            /* Offset of first name found */
-
-          count = 0;
-          for (;;)
-            {
-            recno = GET2(slot, 0);   /* Number for last found */
-            if ((uint32_t)recno > cb->top_backref) cb->top_backref = recno;
-            count++;
-            if (++i >= cb->names_found) break;
-            slot += cb->name_entry_size;
-            if (PRIV(strncmp)(name, slot+IMM2_SIZE, namelen) != 0 ||
-              (slot+IMM2_SIZE)[namelen] != 0) break;
+            else
+              {
+              if (groupsetfirstcu && reqcuflags < 0)
+                {
+                reqcu = firstcu;
+                reqcuflags = firstcuflags;
+                }
+              for (i = 1; (uint32_t)i < repeat_min; i++)
+                {
+                memcpy(code, previous, CU2BYTES(len));
+                code += len;
+                }
+              }
             }


-          if (count > 1)
-            {
-            PUT2(code, 2+LINK_SIZE, offset);
-            PUT2(code, 2+LINK_SIZE+IMM2_SIZE, count);
-            skipunits += IMM2_SIZE;
-            code[1+LINK_SIZE]++;
-            }
-          else  /* Not a duplicated name */
-            {
-            PUT2(code, 2+LINK_SIZE, recno);
-            }
+          if (repeat_max != REPEAT_UNLIMITED) repeat_max -= repeat_min;
           }


-        /* If terminator == CHAR_NULL it means that the name followed directly
-        after the opening parenthesis [e.g. (?(abc)...] and in this case there
-        are some further alternatives to try. For the cases where terminator !=
-        CHAR_NULL [things like (?(<name>... or (?('name')... or (?(R&name)... ]
-        we have now checked all the possibilities, so give an error. */
+        /* This code is common to both the zero and non-zero minimum cases. If
+        the maximum is limited, it replicates the group in a nested fashion,
+        remembering the bracket starts on a stack. In the case of a zero
+        minimum, the first one was set up above. In all cases the repeat_max
+        now specifies the number of additional copies needed. Again, we must
+        remember to replicate entries on the forward reference list. */


-        else if (terminator != CHAR_NULL)
+        if (repeat_max != REPEAT_UNLIMITED)
           {
-          *errorcodeptr = ERR15;
-          goto FAILED;
-          }
+          /* In the pre-compile phase, we don't actually do the replication. We
+          just adjust the length as if we had. For each repetition we must add
+          1 to the length for BRAZERO and for all but the last repetition we
+          must add 2 + 2*LINKSIZE to allow for the nesting that occurs. Do some
+          paranoid checks to avoid integer overflow. The INT64_OR_DOUBLE type
+          is a 64-bit integer type when available, otherwise double. */


-        /* Check for (?(R) for recursion. Allow digits after R to specify a
-        specific group number. */
-
-        else if (*name == CHAR_R)
-          {
-          recno = 0;
-          for (i = 1; i < namelen; i++)
+          if (lengthptr != NULL && repeat_max > 0)
             {
-            if (!IS_DIGIT(name[i]))
+            PCRE2_SIZE delta = repeat_max*(length_prevgroup + 1 + 2 + 2*LINK_SIZE) -
+                        2 - 2*LINK_SIZE;   /* Last one doesn't nest */
+            if ((INT64_OR_DOUBLE)repeat_max *
+                  (INT64_OR_DOUBLE)(length_prevgroup + 1 + 2 + 2*LINK_SIZE)
+                    > (INT64_OR_DOUBLE)INT_MAX ||
+                OFLOW_MAX - *lengthptr < delta)
               {
-              *errorcodeptr = ERR15;        /* Non-existent subpattern */
-              goto FAILED;
+              *errorcodeptr = ERR20;
+              return FALSE;
               }
-            if (recno > INT_MAX / 10 - 1)   /* Integer overflow */
-              {
-              *errorcodeptr = ERR61;
-              goto FAILED;
-              }
-            recno = recno * 10 + name[i] - CHAR_0;
+            *lengthptr += delta;
             }
-          if (recno == 0) recno = RREF_ANY;
-          code[1+LINK_SIZE] = OP_RREF;      /* Change test type */
-          PUT2(code, 2+LINK_SIZE, recno);
-          }


-        /* Similarly, check for the (?(DEFINE) "condition", which is always
-        false. During compilation we set OP_DEFINE to distinguish this from
-        other OP_FALSE conditions so that it can be checked for having only one
-        branch, but after that the opcode is changed to OP_FALSE. */
+          /* This is compiling for real */


-        else if (namelen == 6 && PRIV(strncmp_c8)(name, STRING_DEFINE, 6) == 0)
-          {
-          code[1+LINK_SIZE] = OP_DEFINE;
-          skipunits = 1;
-          }
+          else for (i = repeat_max - 1; i >= 0; i--)
+            {
+            *code++ = OP_BRAZERO + repeat_type;


-        /* Reference to an unidentified subpattern. */
+            /* All but the final copy start a new nesting, maintaining the
+            chain of brackets outstanding. */


-        else
-          {
-          *errorcodeptr = ERR15;
-          goto FAILED;
-          }
-        break;
+            if (i != 0)
+              {
+              int linkoffset;
+              *code++ = OP_BRA;
+              linkoffset = (bralink == NULL)? 0 : (int)(code - bralink);
+              bralink = code;
+              PUTINC(code, 0, linkoffset);
+              }


+            memcpy(code, previous, CU2BYTES(len));
+            code += len;
+            }


-        /* ------------------------------------------------------------ */
-        case CHAR_EQUALS_SIGN:                 /* Positive lookahead */
-        bravalue = OP_ASSERT;
-        cb->assert_depth += 1;
-        ptr++;
-        break;
+          /* Now chain through the pending brackets, and fill in their length
+          fields (which are holding the chain links pro tem). */


-        /* Optimize (?!) to (*FAIL) unless it is quantified - which is a weird
-        thing to do, but Perl allows all assertions to be quantified, and when
-        they contain capturing parentheses there may be a potential use for
-        this feature. Not that that applies to a quantified (?!) but we allow
-        it for uniformity. */
-
-        /* ------------------------------------------------------------ */
-        case CHAR_EXCLAMATION_MARK:            /* Negative lookahead */
-        ptr++;
-        if (*ptr == CHAR_RIGHT_PARENTHESIS && ptr[1] != CHAR_ASTERISK &&
-             ptr[1] != CHAR_PLUS && ptr[1] != CHAR_QUESTION_MARK &&
-            (ptr[1] != CHAR_LEFT_CURLY_BRACKET || !is_counted_repeat(ptr+2)))
-          {
-          *code++ = OP_FAIL;
-          previous = NULL;
-          continue;
+          while (bralink != NULL)
+            {
+            int oldlinkoffset;
+            int linkoffset = (int)(code - bralink + 1);
+            PCRE2_UCHAR *bra = code - linkoffset;
+            oldlinkoffset = GET(bra, 1);
+            bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset;
+            *code++ = OP_KET;
+            PUTINC(code, 0, linkoffset);
+            PUT(bra, 1, linkoffset);
+            }
           }
-        bravalue = OP_ASSERT_NOT;
-        cb->assert_depth += 1;
-        break;


+        /* If the maximum is unlimited, set a repeater in the final copy. For
+        ONCE brackets, that's all we need to do. However, possessively repeated
+        ONCE brackets can be converted into non-capturing brackets, as the
+        behaviour of (?:xx)++ is the same as (?>xx)++ and this saves having to
+        deal with possessive ONCEs specially.


-        /* ------------------------------------------------------------ */
-        case CHAR_LESS_THAN_SIGN:              /* Lookbehind or named define */
-        switch (ptr[1])
-          {
-          case CHAR_EQUALS_SIGN:               /* Positive lookbehind */
-          bravalue = OP_ASSERTBACK;
-          cb->assert_depth += 1;
-          ptr += 2;
-          break;
+        Otherwise, when we are doing the actual compile phase, check to see
+        whether this group is one that could match an empty string. If so,
+        convert the initial operator to the S form (e.g. OP_BRA -> OP_SBRA) so
+        that runtime checking can be done. [This check is also applied to ONCE
+        groups at runtime, but in a different way.]


-          case CHAR_EXCLAMATION_MARK:          /* Negative lookbehind */
-          bravalue = OP_ASSERTBACK_NOT;
-          cb->assert_depth += 1;
-          ptr += 2;
-          break;
+        Then, if the quantifier was possessive and the bracket is not a
+        conditional, we convert the BRA code to the POS form, and the KET code to
+        KETRPOS. (It turns out to be convenient at runtime to detect this kind of
+        subpattern at both the start and at the end.) The use of special opcodes
+        makes it possible to reduce greatly the stack usage in pcre2_match(). If
+        the group is preceded by OP_BRAZERO, convert this to OP_BRAPOSZERO.


-          /* Must be a name definition - as the syntax was checked in the
-          pre-pass, we can assume here that it is valid. Skip over the name
-          and go to handle the numbered group. */
+        Then, if the minimum number of matches is 1 or 0, cancel the possessive
+        flag so that the default action below, of wrapping everything inside
+        atomic brackets, does not happen. When the minimum is greater than 1,
+        there will be earlier copies of the group, and so we still have to wrap
+        the whole thing. */


-          default:
-          while (*(++ptr) != CHAR_GREATER_THAN_SIGN);
-          ptr++;
-          goto NUMBERED_GROUP;
-          }
-        break;
+        else
+          {
+          PCRE2_UCHAR *ketcode = code - 1 - LINK_SIZE;
+          PCRE2_UCHAR *bracode = ketcode - GET(ketcode, 1);


+          /* Convert possessive ONCE brackets to non-capturing */


-        /* ------------------------------------------------------------ */
-        case CHAR_GREATER_THAN_SIGN:           /* One-time brackets */
-        bravalue = OP_ONCE;
-        ptr++;
-        break;
+          if ((*bracode == OP_ONCE || *bracode == OP_ONCE_NC) &&
+              possessive_quantifier) *bracode = OP_BRA;


+          /* For non-possessive ONCE brackets, all we need to do is to
+          set the KET. */


-        /* ------------------------------------------------------------ */
-        case CHAR_C:                 /* Callout */
-        previous_callout = code;     /* Save for later completion */
-        after_manual_callout = 1;    /* Skip one item before completing */
-        ptr++;                       /* Character after (?C */
+          if (*bracode == OP_ONCE || *bracode == OP_ONCE_NC)
+            *ketcode = OP_KETRMAX + repeat_type;


-        /* A callout may have a string argument, delimited by one of a fixed
-        number of characters, or an undelimited numerical argument, or no
-        argument, which is the same as (?C0). Different opcodes are used for
-        the two cases. */
+          /* Handle non-ONCE brackets and possessive ONCEs (which have been
+          converted to non-capturing above). */


-        if (*ptr != CHAR_RIGHT_PARENTHESIS && !IS_DIGIT(*ptr))
-          {
-          uint32_t delimiter = 0;
-
-          for (i = 0; PRIV(callout_start_delims)[i] != 0; i++)
+          else
             {
-            if (*ptr == PRIV(callout_start_delims)[i])
-              {
-              delimiter = PRIV(callout_end_delims)[i];
-              break;
-              }
-            }
+            /* In the compile phase, check whether the group could match an
+            empty string. */


-          if (delimiter == 0)
-            {
-            *errorcodeptr = ERR82;
-            goto FAILED;
-            }
-
-          /* During the pre-compile phase, we parse the string and update the
-          length. There is no need to generate any code. (In fact, the string
-          has already been parsed in the pre-pass that looks for named
-          parentheses, but it does no harm to leave this code in.) */
-
-          if (lengthptr != NULL)     /* Only check the string */
-            {
-            PCRE2_SPTR start = ptr;
-            do
+            if (lengthptr == NULL)
               {
-              if (++ptr >= cb->end_pattern)
+              PCRE2_UCHAR *scode = bracode;
+              do
                 {
-                *errorcodeptr = ERR81;
-                ptr = start;   /* To give a more useful message */
-                goto FAILED;
+                int count = 0;
+                int rc = could_be_empty_branch(scode, ketcode, utf, cb, FALSE,
+                  NULL, &count);
+                if (rc < 0)
+                  {
+                  *errorcodeptr = ERR86;
+                  return FALSE;
+                  }
+                if (rc > 0)
+                  {
+                  *bracode += OP_SBRA - OP_BRA;
+                  break;
+                  }
+                scode += GET(scode, 1);
                 }
-              if (ptr[0] == delimiter && ptr[1] == delimiter) ptr += 2;
-              }
-            while (ptr[0] != delimiter);
+              while (*scode == OP_ALT);


-            /* Start points to the opening delimiter, ptr points to the
-            closing delimiter. We must allow for including the delimiter and
-            for the terminating zero. Any doubled delimiters within the string
-            make this an overestimate, but it is not worth bothering about. */
+              /* A conditional group with only one branch has an implicit empty
+              alternative branch. */


-            (*lengthptr) += (ptr - start) + 2 + (1 + 4*LINK_SIZE);
-            }
+              if (*bracode == OP_COND && bracode[GET(bracode,1)] != OP_ALT)
+                *bracode = OP_SCOND;
+              }


-          /* In the real compile we can copy the string, knowing that it is
-          syntactically OK. The starting delimiter is included so that the
-          client can discover it if they want. We also pass the start offset to
-          help a script language give better error messages. */
+            /* Handle possessive quantifiers. */


-          else
-            {
-            PCRE2_UCHAR *callout_string = code + (1 + 4*LINK_SIZE);
-            *callout_string++ = *ptr++;
-            PUT(code, 1 + 3*LINK_SIZE, (int)(ptr - cb->start_pattern)); /* Start offset */
-            for(;;)
+            if (possessive_quantifier)
               {
-              if (*ptr == delimiter)
+              /* For COND brackets, we wrap the whole thing in a possessively
+              repeated non-capturing bracket, because we have not invented POS
+              versions of the COND opcodes. */
+
+              if (*bracode == OP_COND || *bracode == OP_SCOND)
                 {
-                if (ptr[1] == delimiter) ptr++; else break;
+                int nlen = (int)(code - bracode);
+                memmove(bracode + 1 + LINK_SIZE, bracode, CU2BYTES(nlen));
+                code += 1 + LINK_SIZE;
+                nlen += 1 + LINK_SIZE;
+                *bracode = (*bracode == OP_COND)? OP_BRAPOS : OP_SBRAPOS;
+                *code++ = OP_KETRPOS;
+                PUTINC(code, 0, nlen);
+                PUT(bracode, 1, nlen);
                 }
-              *callout_string++ = *ptr++;
-              }
-            *callout_string++ = CHAR_NULL;
-            code[0] = OP_CALLOUT_STR;
-            PUT(code, 1, (int)(ptr + 2 - cb->start_pattern)); /* Next offset */
-            PUT(code, 1 + LINK_SIZE, 0);      /* Default length */
-            PUT(code, 1 + 2*LINK_SIZE,        /* Compute size */
-                (int)(callout_string - code));
-            code = callout_string;
-            }


-          /* Advance to what should be the closing parenthesis, which is
-          checked below. */
+              /* For non-COND brackets, we modify the BRA code and use KETRPOS. */


-          ptr++;
-          }
+              else
+                {
+                *bracode += 1;              /* Switch to xxxPOS opcodes */
+                *ketcode = OP_KETRPOS;
+                }


-        /* Handle a callout with an optional numerical argument, which must be
-        less than or equal to 255. A missing argument gives 0. */
+              /* If the minimum is zero, mark it as possessive, then unset the
+              possessive flag when the minimum is 0 or 1. */


-        else
-          {
-          int n = 0;
-          code[0] = OP_CALLOUT;     /* Numerical callout */
-          while (IS_DIGIT(*ptr))
-            {
-            n = n * 10 + *ptr++ - CHAR_0;
-            if (n > 255)
-              {
-              *errorcodeptr = ERR38;
-              goto FAILED;
+              if (brazeroptr != NULL) *brazeroptr = OP_BRAPOSZERO;
+              if (repeat_min < 2) possessive_quantifier = FALSE;
               }
-            }
-          PUT(code, 1, (int)(ptr - cb->start_pattern + 1));  /* Next offset */
-          PUT(code, 1 + LINK_SIZE, 0);                    /* Default length */
-          code[1 + 2*LINK_SIZE] = n;                      /* Callout number */
-          code += PRIV(OP_lengths)[OP_CALLOUT];
-          }


-        /* Both formats must have a closing parenthesis */
+            /* Non-possessive quantifier */


-        if (*ptr != CHAR_RIGHT_PARENTHESIS)
-          {
-          *errorcodeptr = ERR39;
-          goto FAILED;
+            else *ketcode = OP_KETRMAX + repeat_type;
+            }
           }
+        }
+      break;


-        /* Callouts cannot be quantified. */
+      /* If previous was a character type match (\d or similar), abolish it and
+      create a suitable repeat item. The code is shared with single-character
+      repeats by setting op_type to add a suitable offset into repeat_type.
+      Note the the Unicode property types will be present only when
+      SUPPORT_UNICODE is defined, but we don't wrap the little bits of code
+      here because it just makes it horribly messy. */


-        previous = NULL;
-        continue;
+      default:
+      if (op_previous >= OP_EODN)   /* Not a character type - internal error */
+        {
+        *errorcodeptr = ERR10;
+        return FALSE;
+        }
+      else
+        {
+        int prop_type, prop_value;
+        PCRE2_UCHAR *oldcode;


+        op_type = OP_TYPESTAR - OP_STAR;      /* Use type opcodes */
+        mclength = 0;                         /* Not a character */


-        /* ------------------------------------------------------------ */
-        case CHAR_P:              /* Python-style named subpattern handling */
-        if (*(++ptr) == CHAR_EQUALS_SIGN ||
-            *ptr == CHAR_GREATER_THAN_SIGN)  /* Reference or recursion */
+        if (op_previous == OP_PROP || op_previous == OP_NOTPROP)
           {
-          is_recurse = *ptr == CHAR_GREATER_THAN_SIGN;
-          terminator = CHAR_RIGHT_PARENTHESIS;
-          goto NAMED_REF_OR_RECURSE;
+          prop_type = previous[1];
+          prop_value = previous[2];
           }
-        else if (*ptr != CHAR_LESS_THAN_SIGN)  /* Test for Python-style defn */
+        else
           {
-          *errorcodeptr = ERR41;
-          goto FAILED;
+          /* Come here from just above with a character in mcbuffer/mclength. */
+          OUTPUT_SINGLE_REPEAT:
+          prop_type = prop_value = -1;
           }
-        /* Fall through to handle (?P< as (?< is handled */


+        /* At this point, if prop_type == prop_value == -1 we either have a
+        character in mcbuffer when mclength is greater than zero, or we have
+        mclength zero, in which case there is a non-property character type in
+        op_previous. If prop_type/value are not negative, we have a property
+        character type in op_previous. */


-        /* ------------------------------------------------------------ */
-        case CHAR_APOSTROPHE:   /* Define a name - note fall through above */
+        oldcode = code;                   /* Save where we were */
+        code = previous;                  /* Usually overwrite previous item */


-        /* The syntax was checked and the list of names was set up in the
-        pre-pass, so there is nothing to be done now except to skip over the
-        name. */
+        /* If the maximum is zero then the minimum must also be zero; Perl allows
+        this case, so we do too - by simply omitting the item altogether. */


-        terminator = (*ptr == CHAR_LESS_THAN_SIGN)?
-                  CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE;
-        while (*(++ptr) != (unsigned int)terminator);
-        ptr++;
-        goto NUMBERED_GROUP;      /* Set up numbered group */
+        if (repeat_max == 0) goto END_REPEAT;


+        /* Combine the op_type with the repeat_type */


-        /* ------------------------------------------------------------ */
-        case CHAR_AMPERSAND:            /* Perl recursion/subroutine syntax */
-        terminator = CHAR_RIGHT_PARENTHESIS;
-        is_recurse = TRUE;
-        /* Fall through */
+        repeat_type += op_type;


-        /* We come here from the Python syntax above that handles both
-        references (?P=name) and recursion (?P>name), as well as falling
-        through from the Perl recursion syntax (?&name). We also come here from
-        the Perl \k<name> or \k'name' back reference syntax and the \k{name}
-        .NET syntax, and the Oniguruma \g<...> and \g'...' subroutine syntax. */
+        /* A minimum of zero is handled either as the special case * or ?, or as
+        an UPTO, with the maximum given. */


-        NAMED_REF_OR_RECURSE:
-        name = ++ptr;
-        if (IS_DIGIT(*ptr))
+        if (repeat_min == 0)
           {
-          *errorcodeptr = ERR44;   /* Group name must start with non-digit */
-          goto FAILED;
+          if (repeat_max == REPEAT_UNLIMITED) *code++ = OP_STAR + repeat_type;
+            else if (repeat_max == 1) *code++ = OP_QUERY + repeat_type;
+          else
+            {
+            *code++ = OP_UPTO + repeat_type;
+            PUT2INC(code, 0, repeat_max);
+            }
           }
-        /* Increment ptr, set namelen, check length */
-        READ_NAME(ctype_word, ERR48, *errorcodeptr);


-        /* In the pre-compile phase, do a syntax check. */
+        /* A repeat minimum of 1 is optimized into some special cases. If the
+        maximum is unlimited, we use OP_PLUS. Otherwise, the original item is
+        left in place and, if the maximum is greater than 1, we use OP_UPTO with
+        one less than the maximum. */


-        if (lengthptr != NULL)
+        else if (repeat_min == 1)
           {
-          if (namelen == 0)
+          if (repeat_max == REPEAT_UNLIMITED)
+            *code++ = OP_PLUS + repeat_type;
+          else
             {
-            *errorcodeptr = ERR62;
-            goto FAILED;
+            code = oldcode;  /* Leave previous item in place */
+            if (repeat_max == 1) goto END_REPEAT;
+            *code++ = OP_UPTO + repeat_type;
+            PUT2INC(code, 0, repeat_max - 1);
             }
-          if (*ptr != (PCRE2_UCHAR)terminator)
-            {
-            *errorcodeptr = ERR42;
-            goto FAILED;
-            }
           }


-        /* Scan the list of names generated in the pre-pass in order to get
-        a number and whether or not this name is duplicated. */
+        /* The case {n,n} is just an EXACT, while the general case {n,m} is
+        handled as an EXACT followed by an UPTO or STAR or QUERY. */


-        recno = 0;
-        is_dupname = FALSE;
-        ng = cb->named_groups;
-
-        for (i = 0; i < cb->names_found; i++, ng++)
+        else
           {
-          if (namelen == ng->length &&
-              PRIV(strncmp)(name, ng->name, namelen) == 0)
-            {
-            open_capitem *oc;
-            is_dupname = ng->isdup;
-            recno = ng->number;
+          *code++ = OP_EXACT + op_type;  /* NB EXACT doesn't have repeat_type */
+          PUT2INC(code, 0, repeat_min);


-            /* For a recursion, that's all that is needed. We can now go to the
-            code that handles numerical recursion. */
+          /* Unless repeat_max equals repeat_min, fill in the data for EXACT,
+          and then generate the second opcode. For a repeated Unicode property
+          match, there are two extra values that define the required property,
+          and mclength is set zero to indicate this. */


-            if (is_recurse) goto HANDLE_RECURSION;
-
-            /* For a back reference, update the back reference map and the
-            maximum back reference. Then for each group we must check to see if
-            it is recursive, that is, it is inside the group that it
-            references. A flag is set so that the group can be made atomic. */
-
-            cb->backref_map |= (recno < 32)? (1u << recno) : 1;
-            if ((uint32_t)recno > cb->top_backref) cb->top_backref = recno;
-
-            for (oc = cb->open_caps; oc != NULL; oc = oc->next)
+          if (repeat_max != repeat_min)
+            {
+            if (mclength > 0)
               {
-              if (oc->number == recno)
+              memcpy(code, mcbuffer, CU2BYTES(mclength));
+              code += mclength;
+              }
+            else
+              {
+              *code++ = op_previous;
+              if (prop_type >= 0)
                 {
-                oc->flag = TRUE;
-                break;
+                *code++ = prop_type;
+                *code++ = prop_value;
                 }
               }
-            }
-          }


-        /* If the name was not found we have a bad reference. */
+            /* Now set up the following opcode */


-        if (recno == 0)
-          {
-          *errorcodeptr = ERR15;
-          goto FAILED;
-          }
-
-        /* If a back reference name is not duplicated, we can handle it as a
-        numerical reference. */
-
-        if (!is_dupname) goto HANDLE_REFERENCE;
-
-        /* If a back reference name is duplicated, we generate a different
-        opcode to a numerical back reference. In the second pass we must search
-        for the index and count in the final name table. */
-
-        count = 0;
-        index = 0;
-
-        if (lengthptr == NULL)
-          {
-          slot = cb->name_table;
-          for (i = 0; i < cb->names_found; i++)
-            {
-            if (PRIV(strncmp)(name, slot+IMM2_SIZE, namelen) == 0 &&
-                slot[IMM2_SIZE+namelen] == 0)
+            if (repeat_max == REPEAT_UNLIMITED)
+              *code++ = OP_STAR + repeat_type;
+            else
               {
-              if (count == 0) index = i;
-              count++;
+              repeat_max -= repeat_min;
+              if (repeat_max == 1)
+                {
+                *code++ = OP_QUERY + repeat_type;
+                }
+              else
+                {
+                *code++ = OP_UPTO + repeat_type;
+                PUT2INC(code, 0, repeat_max);
+                }
               }
-            slot += cb->name_entry_size;
             }
-
-          if (count == 0)
-            {
-            *errorcodeptr = ERR15;
-            goto FAILED;
-            }
           }


-        if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
-        previous = code;
-        *code++ = ((options & PCRE2_CASELESS) != 0)? OP_DNREFI : OP_DNREF;
-        PUT2INC(code, 0, index);
-        PUT2INC(code, 0, count);
-        continue;  /* End of back ref handling */
+        /* Fill in the character or character type for the final opcode. */


-
-        /* ------------------------------------------------------------ */
-        case CHAR_R:              /* Recursion, same as (?0) */
-        recno = 0;
-        if (*(++ptr) != CHAR_RIGHT_PARENTHESIS)
+        if (mclength > 0)
           {
-          *errorcodeptr = ERR29;
-          goto FAILED;
+          memcpy(code, mcbuffer, CU2BYTES(mclength));
+          code += mclength;
           }
-        goto HANDLE_RECURSION;
-
-
-        /* ------------------------------------------------------------ */
-        case CHAR_MINUS: case CHAR_PLUS:  /* Recursion or subroutine */
-        case CHAR_0: case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4:
-        case CHAR_5: case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9:
+        else
           {
-          terminator = CHAR_RIGHT_PARENTHESIS;
-
-          /* Come here from the \g<...> and \g'...' code (Oniguruma
-          compatibility). However, the syntax has been checked to ensure that
-          the ... are a (signed) number, so that neither ERR63 nor ERR29 will
-          be called on this path, nor with the jump to OTHER_CHAR_AFTER_QUERY
-          ever be taken. */
-
-          HANDLE_NUMERICAL_RECURSION:
-
-          if ((refsign = *ptr) == CHAR_PLUS)
+          *code++ = op_previous;
+          if (prop_type >= 0)
             {
-            ptr++;
-            if (!IS_DIGIT(*ptr))
-              {
-              *errorcodeptr = ERR63;
-              goto FAILED;
-              }
+            *code++ = prop_type;
+            *code++ = prop_value;
             }
-          else if (refsign == CHAR_MINUS)
-            {
-            if (!IS_DIGIT(ptr[1]))
-              goto OTHER_CHAR_AFTER_QUERY;
-            ptr++;
-            }
+          }
+        }
+      break;
+      }  /* End of switch on different op_previous values */


-          recno = 0;
-          while (IS_DIGIT(*ptr))
-            {
-            if (recno > INT_MAX / 10 - 1) /* Integer overflow */
-              {
-              while (IS_DIGIT(*ptr)) ptr++;
-              *errorcodeptr = ERR61;
-              goto FAILED;
-              }
-            recno = recno * 10 + *ptr++ - CHAR_0;
-            }


-          if (*ptr != (PCRE2_UCHAR)terminator)
-            {
-            *errorcodeptr = ERR29;
-            goto FAILED;
-            }
+    /* If the character following a repeat is '+', possessive_quantifier is
+    TRUE. For some opcodes, there are special alternative opcodes for this
+    case. For anything else, we wrap the entire repeated item inside OP_ONCE
+    brackets. Logically, the '+' notation is just syntactic sugar, taken from
+    Sun's Java package, but the special opcodes can optimize it.


-          if (refsign == CHAR_MINUS)
-            {
-            if (recno == 0)
-              {
-              *errorcodeptr = ERR58;
-              goto FAILED;
-              }
-            recno = (int)(cb->bracount + 1) - recno;
-            if (recno <= 0)
-              {
-              *errorcodeptr = ERR15;
-              goto FAILED;
-              }
-            }
-          else if (refsign == CHAR_PLUS)
-            {
-            if (recno == 0)
-              {
-              *errorcodeptr = ERR58;
-              goto FAILED;
-              }
-            recno += cb->bracount;
-            }
+    Some (but not all) possessively repeated subpatterns have already been
+    completely handled in the code just above. For them, possessive_quantifier
+    is always FALSE at this stage. Note that the repeated item starts at
+    tempcode, not at previous, which might be the first part of a string whose
+    (former) last char we repeated. */


-          if ((uint32_t)recno > cb->final_bracount)
-            {
-            *errorcodeptr = ERR15;
-            goto FAILED;
-            }
+    if (possessive_quantifier)
+      {
+      int len;


-          /* Come here from code above that handles a named recursion.
-          We insert the number of the called group after OP_RECURSE. At the
-          end of compiling the pattern is scanned and these numbers are
-          replaced by offsets within the pattern. It is done like this to avoid
-          problems with forward references and adjusting offsets when groups
-          are duplicated and moved (as discovered in previous implementations).
-          Note that a recursion does not have a set first character (relevant
-          if it is repeated, because it will then be wrapped with ONCE
-          brackets). */
+      /* Possessifying an EXACT quantifier has no effect, so we can ignore it.
+      However, QUERY, STAR, or UPTO may follow (for quantifiers such as {5,6},
+      {5,}, or {5,10}). We skip over an EXACT item; if the length of what
+      remains is greater than zero, there's a further opcode that can be
+      handled. If not, do nothing, leaving the EXACT alone. */


-          HANDLE_RECURSION:
-          previous = code;
-          *code = OP_RECURSE;
-          PUT(code, 1, recno);
-          code += 1 + LINK_SIZE;
-          groupsetfirstcu = FALSE;
-          cb->had_recurse = TRUE;
-          }
+      switch(*tempcode)
+        {
+        case OP_TYPEEXACT:
+        tempcode += PRIV(OP_lengths)[*tempcode] +
+          ((tempcode[1 + IMM2_SIZE] == OP_PROP
+          || tempcode[1 + IMM2_SIZE] == OP_NOTPROP)? 2 : 0);
+        break;


-        /* Can't determine a first byte now */
+        /* CHAR opcodes are used for exacts whose count is 1. */


-        if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
-        continue;
+        case OP_CHAR:
+        case OP_CHARI:
+        case OP_NOT:
+        case OP_NOTI:
+        case OP_EXACT:
+        case OP_EXACTI:
+        case OP_NOTEXACT:
+        case OP_NOTEXACTI:
+        tempcode += PRIV(OP_lengths)[*tempcode];
+#ifdef SUPPORT_UNICODE
+        if (utf && HAS_EXTRALEN(tempcode[-1]))
+          tempcode += GET_EXTRALEN(tempcode[-1]);
+#endif
+        break;


+        /* For the class opcodes, the repeat operator appears at the end;
+        adjust tempcode to point to it. */


-        /* ------------------------------------------------------------ */
-        default:              /* Other characters: check option setting */
-        OTHER_CHAR_AFTER_QUERY:
-        set = unset = 0;
-        optset = &set;
+        case OP_CLASS:
+        case OP_NCLASS:
+        tempcode += 1 + 32/sizeof(PCRE2_UCHAR);
+        break;


-        while (*ptr != CHAR_RIGHT_PARENTHESIS && *ptr != CHAR_COLON)
-          {
-          switch (*ptr++)
-            {
-            case CHAR_MINUS: optset = &unset; break;
+#ifdef SUPPORT_WIDE_CHARS
+        case OP_XCLASS:
+        tempcode += GET(tempcode, 1);
+        break;
+#endif
+        }


-            case CHAR_J:    /* Record that it changed in the external options */
-            *optset |= PCRE2_DUPNAMES;
-            cb->external_flags |= PCRE2_JCHANGED;
-            break;
+      /* If tempcode is equal to code (which points to the end of the repeated
+      item), it means we have skipped an EXACT item but there is no following
+      QUERY, STAR, or UPTO; the value of len will be 0, and we do nothing. In
+      all other cases, tempcode will be pointing to the repeat opcode, and will
+      be less than code, so the value of len will be greater than 0. */


-            case CHAR_i: *optset |= PCRE2_CASELESS; break;
-            case CHAR_m: *optset |= PCRE2_MULTILINE; break;
-            case CHAR_s: *optset |= PCRE2_DOTALL; break;
-            case CHAR_x: *optset |= PCRE2_EXTENDED; break;
-            case CHAR_U: *optset |= PCRE2_UNGREEDY; break;
+      len = (int)(code - tempcode);
+      if (len > 0)
+        {
+        unsigned int repcode = *tempcode;


-            default:  *errorcodeptr = ERR11;
-                      ptr--;    /* Correct the offset */
-                      goto FAILED;
-            }
-          }
+        /* There is a table for possessifying opcodes, all of which are less
+        than OP_CALLOUT. A zero entry means there is no possessified version.
+        */


-        /* Set up the changed option bits, but don't change anything yet. */
+        if (repcode < OP_CALLOUT && opcode_possessify[repcode] > 0)
+          *tempcode = opcode_possessify[repcode];


-        newoptions = (options | set) & (~unset);
+        /* For opcode without a special possessified version, wrap the item in
+        ONCE brackets. */


-        /* If the options ended with ')' this is not the start of a nested
-        group with option changes, so the options change at this level. They
-        must also be passed back for use in subsequent branches. Reset the
-        greedy defaults and the case value for firstcu and reqcu. */
-
-        if (*ptr == CHAR_RIGHT_PARENTHESIS)
+        else
           {
-          *optionsptr = options = newoptions;
-          greedy_default = ((newoptions & PCRE2_UNGREEDY) != 0);
-          greedy_non_default = greedy_default ^ 1;
-          req_caseopt = ((newoptions & PCRE2_CASELESS) != 0)? REQ_CASELESS:0;
-          previous = NULL;       /* This item can't be repeated */
-          continue;              /* It is complete */
+          memmove(tempcode + 1 + LINK_SIZE, tempcode, CU2BYTES(len));
+          code += 1 + LINK_SIZE;
+          len += 1 + LINK_SIZE;
+          tempcode[0] = OP_ONCE;
+          *code++ = OP_KET;
+          PUTINC(code, 0, len);
+          PUT(tempcode, 1, len);
           }
+        }
+      }


-        /* If the options ended with ':' we are heading into a nested group
-        with possible change of options. Such groups are non-capturing and are
-        not assertions of any kind. All we need to do is skip over the ':';
-        the newoptions value is handled below. */
+    /* We set the "follows varying string" flag for subsequently encountered
+    reqcus if it isn't already set and we have just passed a varying length
+    item. */


-        bravalue = OP_BRA;
-        ptr++;
-        }     /* End of switch for character following (? */
-      }       /* End of (? handling */
+    END_REPEAT:
+    cb->req_varyopt |= reqvary;
+    break;


-    /* Opening parenthesis not followed by '*' or '?'. If PCRE2_NO_AUTO_CAPTURE
-    is set, all unadorned brackets become non-capturing and behave like (?:...)
-    brackets. */


-    else if ((options & PCRE2_NO_AUTO_CAPTURE) != 0)
-      {
-      bravalue = OP_BRA;
-      }
+    /* ===================================================================*/
+    /* Handle a 32-bit data character with a value greater than META_END. */


-    /* Else we have a capturing group. */
+    case META_BIGVALUE:
+    pptr++;
+    goto NORMAL_CHAR;


-    else
-      {
-      NUMBERED_GROUP:
-      cb->bracount += 1;
-      PUT2(code, 1+LINK_SIZE, cb->bracount);
-      skipunits = IMM2_SIZE;
-      }


-    /* Process nested bracketed regex. First check for parentheses nested too
-    deeply. */
+    /* ===============================================================*/
+    /* Handle a back reference by number, which is the meta argument. The
+    pattern offsets for back references to group numbers less than 10 are held
+    in a special vector, to avoid using more than two parsed pattern elements
+    in 64-bit environments. We only need the offset to the first occurrence,
+    because if that doesn't fail, subsequent ones will also be OK. */


-    if ((cb->parens_depth += 1) > (int)(cb->cx->parens_nest_limit))
-      {
-      *errorcodeptr = ERR19;
-      goto FAILED;
-      }
+    case META_BACKREF:
+    if (meta_arg < 10) offset = cb->small_ref_offset[meta_arg];
+      else GETPLUSOFFSET(offset, pptr);


-    /* All assertions used not to be repeatable, but this was changed for Perl
-    compatibility. All kinds can now be repeated except for assertions that are
-    conditions (Perl also forbids these to be repeated). We copy code into a
-    non-register variable (tempcode) in order to be able to pass its address
-    because some compilers complain otherwise. At the start of a conditional
-    group whose condition is an assertion, cb->iscondassert is set. We unset it
-    here so as to allow assertions later in the group to be quantified. */
-
-    if (bravalue >= OP_ASSERT && bravalue <= OP_ASSERTBACK_NOT &&
-        cb->iscondassert)
+    if (meta_arg > cb->bracount)
       {
-      previous = NULL;
-      cb->iscondassert = FALSE;
+      cb->erroroffset = offset;
+      *errorcodeptr = ERR15;  /* Non-existent subpattern */
+      return FALSE;
       }
-    else
-      {
-      previous = code;
-      }


-    *code = bravalue;
-    tempcode = code;
-    tempreqvary = cb->req_varyopt;        /* Save value before bracket */
-    tempbracount = cb->bracount;          /* Save value before bracket */
-    length_prevgroup = 0;                 /* Initialize for pre-compile phase */
+    /* Come here from named backref handling when the reference is to a
+    single group (that is, not to a duplicated name). The back reference
+    data will have already been updated. We must disable firstcu if not
+    set, to cope with cases like (?=(\w+))\1: which would otherwise set ':'
+    later. */


-    if (!compile_regex(
-         newoptions,                      /* The complete new option state */
-         &tempcode,                       /* Where to put code (updated) */
-         &ptr,                            /* Input pointer (updated) */
-         errorcodeptr,                    /* Where to put an error message */
-         (bravalue == OP_ASSERTBACK ||
-          bravalue == OP_ASSERTBACK_NOT), /* TRUE if back assert */
-         reset_bracount,                  /* True if (?| group */
-         skipunits,                       /* Skip over bracket number */
-         cond_depth +
-           ((bravalue == OP_COND)?1:0),   /* Depth of condition subpatterns */
-         &subfirstcu,                     /* For possible first char */
-         &subfirstcuflags,
-         &subreqcu,                       /* For possible last char */
-         &subreqcuflags,
-         bcptr,                           /* Current branch chain */
-         cb,                              /* Compile data block */
-         (lengthptr == NULL)? NULL :      /* Actual compile phase */
-           &length_prevgroup              /* Pre-compile phase */
-         ))
-      goto FAILED;
+    HANDLE_SINGLE_REFERENCE:
+    if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+    *code++ = ((options & PCRE2_CASELESS) != 0)? OP_REFI : OP_REF;
+    PUT2INC(code, 0, meta_arg);


-    cb->parens_depth -= 1;
+    /* Update the map of back references, and keep the highest one. We
+    could do this in parse_regex() for numerical back references, but not
+    for named back references, because we don't know the numbers to which
+    named back references refer. So we do it all in this function. */


-    /* If this was an atomic group and there are no capturing groups within it,
-    generate OP_ONCE_NC instead of OP_ONCE. */
+    cb->backref_map |= (meta_arg < 32)? (1u << meta_arg) : 1;
+    if (meta_arg > cb->top_backref) cb->top_backref = meta_arg;


-    if (bravalue == OP_ONCE && cb->bracount <= tempbracount)
-      *code = OP_ONCE_NC;
+    /* Check to see if this back reference is recursive, that it, it
+    is inside the group that it references. A flag is set so that the
+    group can be made atomic. */


-    if (bravalue >= OP_ASSERT && bravalue <= OP_ASSERTBACK_NOT)
-      cb->assert_depth -= 1;
-
-    /* At the end of compiling, code is still pointing to the start of the
-    group, while tempcode has been updated to point past the end of the group.
-    The pattern pointer (ptr) is on the bracket.
-
-    If this is a conditional bracket, check that there are no more than
-    two branches in the group, or just one if it's a DEFINE group. We do this
-    in the real compile phase, not in the pre-pass, where the whole group may
-    not be available. */
-
-    if (bravalue == OP_COND && lengthptr == NULL)
+    for (oc = cb->open_caps; oc != NULL; oc = oc->next)
       {
-      PCRE2_UCHAR *tc = code;
-      int condcount = 0;
-
-      do {
-         condcount++;
-         tc += GET(tc,1);
-         }
-      while (*tc != OP_KET);
-
-      /* A DEFINE group is never obeyed inline (the "condition" is always
-      false). It must have only one branch. Having checked this, change the
-      opcode to OP_FALSE. */
-
-      if (code[LINK_SIZE+1] == OP_DEFINE)
+      if (oc->number == meta_arg)
         {
-        if (condcount > 1)
-          {
-          *errorcodeptr = ERR54;
-          goto FAILED;
-          }
-        code[LINK_SIZE+1] = OP_FALSE;
-        bravalue = OP_DEFINE;   /* Just a flag to suppress char handling below */
+        oc->flag = TRUE;
+        break;
         }
-
-      /* A "normal" conditional group. If there is just one branch, we must not
-      make use of its firstcu or reqcu, because this is equivalent to an
-      empty second branch. */
-
-      else
-        {
-        if (condcount > 2)
-          {
-          *errorcodeptr = ERR27;
-          goto FAILED;
-          }
-        if (condcount == 1) subfirstcuflags = subreqcuflags = REQ_NONE;
-        }
       }
+    break;


-    /* At the end of a group, it's an error if we hit end of pattern or
-    any non-closing parenthesis. This check also happens in the pre-scan,
-    so should not trigger here, but leave this code as an insurance. */


-    if (*ptr != CHAR_RIGHT_PARENTHESIS)
-      {
-      *errorcodeptr = ERR14;
-      goto FAILED;
-      }
+    /* ===============================================================*/
+    /* Handle recursion by inserting the number of the called group (which is
+    the meta argument) after OP_RECURSE. At the end of compiling the pattern is
+    scanned and these numbers are replaced by offsets within the pattern. It is
+    done like this to avoid problems with forward references and adjusting
+    offsets when groups are duplicated and moved (as discovered in previous
+    implementations). Note that a recursion does not have a set first character
+    (relevant if it is repeated, because it will then be wrapped with ONCE
+    brackets). */


-    /* In the pre-compile phase, update the length by the length of the group,
-    less the brackets at either end. Then reduce the compiled code to just a
-    set of non-capturing brackets so that it doesn't use much memory if it is
-    duplicated by a quantifier.*/
-
-    if (lengthptr != NULL)
+    case META_RECURSE:
+    GETPLUSOFFSET(offset, pptr);
+    if (meta_arg > cb->bracount)
       {
-      if (OFLOW_MAX - *lengthptr < length_prevgroup - 2 - 2*LINK_SIZE)
-        {
-        *errorcodeptr = ERR20;
-        goto FAILED;
-        }
-      *lengthptr += length_prevgroup - 2 - 2*LINK_SIZE;
-      code++;   /* This already contains bravalue */
-      PUTINC(code, 0, 1 + LINK_SIZE);
-      *code++ = OP_KET;
-      PUTINC(code, 0, 1 + LINK_SIZE);
-      break;    /* No need to waste time with special character handling */
+      cb->erroroffset = offset;
+      *errorcodeptr = ERR15;  /* Non-existent subpattern */
+      return FALSE;
       }
+    HANDLE_NUMERICAL_RECURSION:
+    *code = OP_RECURSE;
+    PUT(code, 1, meta_arg);
+    code += 1 + LINK_SIZE;
+    groupsetfirstcu = FALSE;
+    cb->had_recurse = TRUE;
+    if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+    break;


-    /* Otherwise update the main code pointer to the end of the group. */


-    code = tempcode;
+    /* ===============================================================*/
+    /* Handle capturing parentheses; the number is the meta argument. */


-    /* For a DEFINE group, required and first character settings are not
-    relevant. */
+    case META_CAPTURE:
+    bravalue = OP_CBRA;
+    skipunits = IMM2_SIZE;
+    PUT2(code, 1+LINK_SIZE, meta_arg);
+    cb->lastcapture = meta_arg;
+    goto GROUP_PROCESS;


-    if (bravalue == OP_DEFINE) break;


-    /* Handle updating of the required and first characters for other types of
-    group. Update for normal brackets of all kinds, and conditions with two
-    branches (see code above). If the bracket is followed by a quantifier with
-    zero repeat, we have to back off. Hence the definition of zeroreqcu and
-    zerofirstcu outside the main loop so that they can be accessed for the
-    back off. */
+    /* ===============================================================*/
+    /* Handle escape sequence items. For ones like \d, the ESC_values are
+    arranged to be the same as the corresponding OP_values in the default case
+    when PCRE2_UCP is not set (which is the only case in which they will appear
+    here).


-    zeroreqcu = reqcu;
-    zeroreqcuflags = reqcuflags;
-    zerofirstcu = firstcu;
-    zerofirstcuflags = firstcuflags;
-    groupsetfirstcu = FALSE;
+    Note: \Q and \E are never seen here, as they were dealt with in
+    parse_pattern(). Neither are numerical back references or recursions, which
+    were turned into META_BACKREF or META_RECURSE items, respectively. \k and
+    \g, when followed by names, are turned into META_BACKREF_BYNAME or
+    META_RECURSE_BYNAME. */


-    if (bravalue >= OP_ONCE)
-      {
-      /* If we have not yet set a firstcu in this branch, take it from the
-      subpattern, remembering that it was set here so that a repeat of more
-      than one can replicate it as reqcu if necessary. If the subpattern has
-      no firstcu, set "none" for the whole branch. In both cases, a zero
-      repeat forces firstcu to "none". */
+    case META_ESCAPE:


-      if (firstcuflags == REQ_UNSET && subfirstcuflags != REQ_UNSET)
-        {
-        if (subfirstcuflags >= 0)
-          {
-          firstcu = subfirstcu;
-          firstcuflags = subfirstcuflags;
-          groupsetfirstcu = TRUE;
-          }
-        else firstcuflags = REQ_NONE;
-        zerofirstcuflags = REQ_NONE;
-        }
+    /* We can test for escape sequences that consume a character because their
+    values lie between ESC_b and ESC_Z for the latter; this may have to change
+    if any new ones are ever created. For these sequences, we disable the
+    setting of a first character if it hasn't already been set. */


-      /* If firstcu was previously set, convert the subpattern's firstcu
-      into reqcu if there wasn't one, using the vary flag that was in
-      existence beforehand. */
+    if (firstcuflags == REQ_UNSET && meta_arg > ESC_b && meta_arg < ESC_Z)
+      firstcuflags = REQ_NONE;


-      else if (subfirstcuflags >= 0 && subreqcuflags < 0)
-        {
-        subreqcu = subfirstcu;
-        subreqcuflags = subfirstcuflags | tempreqvary;
-        }
+    /* Set values to reset to if this is followed by a zero repeat. */


-      /* If the subpattern set a required byte (or set a first byte that isn't
-      really the first byte - see above), set it. */
+    zerofirstcu = firstcu;
+    zerofirstcuflags = firstcuflags;
+    zeroreqcu = reqcu;
+    zeroreqcuflags = reqcuflags;


-      if (subreqcuflags >= 0)
-        {
-        reqcu = subreqcu;
-        reqcuflags = subreqcuflags;
-        }
-      }
+    /* If Unicode is not supported, \P and \p are not allowed and are
+    faulted at parse time, so will never appear here. */


-    /* For a forward assertion, we take the reqcu, if set. This can be
-    helpful if the pattern that follows the assertion doesn't set a different
-    char. For example, it's useful for /(?=abcde).+/. We can't set firstcu
-    for an assertion, however because it leads to incorrect effect for patterns
-    such as /(?=a)a.+/ when the "real" "a" would then become a reqcu instead
-    of a firstcu. This is overcome by a scan at the end if there's no
-    firstcu, looking for an asserted first char. */
-
-    else if (bravalue == OP_ASSERT && subreqcuflags >= 0)
+#ifdef SUPPORT_UNICODE
+    if (meta_arg == ESC_P || meta_arg == ESC_p)
       {
-      reqcu = subreqcu;
-      reqcuflags = subreqcuflags;
+      uint32_t ptype = *(++pptr) >> 16;
+      uint32_t pdata = *pptr & 0xffff;
+      *code++ = (meta_arg == ESC_p)? OP_PROP : OP_NOTPROP;
+      *code++ = ptype;
+      *code++ = pdata;
+      break;  /* End META_ESCAPE */
       }
-    break;     /* End of processing '(' */
-
-
-    /* ===================================================================*/
-    /* Handle metasequences introduced by \. For ones like \d, the ESC_ values
-    are arranged to be the negation of the corresponding OP_values in the
-    default case when PCRE2_UCP is not set. For the back references, the values
-    are negative the reference number. Only back references and those types
-    that consume a character may be repeated. We can test for values between
-    ESC_b and ESC_Z for the latter; this may have to change if any new ones are
-    ever created.
-
-    Note: \Q and \E are handled at the start of the character-processing loop,
-    not here. */
-
-    case CHAR_BACKSLASH:
-    tempptr = ptr;
-    escape = PRIV(check_escape)(&ptr, cb->end_pattern, &ec, errorcodeptr,
-      options, FALSE, cb);
-    if (*errorcodeptr != 0) goto FAILED;
-
-    if (escape == 0)                  /* The escape coded a single character */
-      c = ec;
-    else
-      {
-      /* For metasequences that actually match a character, we disable the
-      setting of a first character if it hasn't already been set. */
-
-      if (firstcuflags == REQ_UNSET && escape > ESC_b && escape < ESC_Z)
-        firstcuflags = REQ_NONE;
-
-      /* Set values to reset to if this is followed by a zero repeat. */
-
-      zerofirstcu = firstcu;
-      zerofirstcuflags = firstcuflags;
-      zeroreqcu = reqcu;
-      zeroreqcuflags = reqcuflags;
-
-      /* \g<name> or \g'name' is a subroutine call by name and \g<n> or \g'n'
-      is a subroutine call by number (Oniguruma syntax). In fact, the value
-      ESC_g is returned only for these cases. So we don't need to check for <
-      or ' if the value is ESC_g. For the Perl syntax \g{n} the value is
-      -n, and for the Perl syntax \g{name} the result is ESC_k (as
-      that is a synonym for a named back reference). */
-
-      if (escape == ESC_g)
-        {
-        PCRE2_SPTR p;
-        uint32_t cf;
-
-        terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)?
-          CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE;
-
-        /* These two statements stop the compiler for warning about possibly
-        unset variables caused by the jump to HANDLE_NUMERICAL_RECURSION. In
-        fact, because we do the check for a number below, the paths that
-        would actually be in error are never taken. */
-
-        skipunits = 0;
-        reset_bracount = FALSE;
-
-        /* If it's not a signed or unsigned number, treat it as a name. */
-
-        cf = ptr[1];
-        if (cf != CHAR_PLUS && cf != CHAR_MINUS && !IS_DIGIT(cf))
-          {
-          is_recurse = TRUE;
-          goto NAMED_REF_OR_RECURSE;
-          }
-
-        /* Signed or unsigned number (cf = ptr[1]) is known to be plus or minus
-        or a digit. */
-
-        p = ptr + 2;
-        while (IS_DIGIT(*p)) p++;
-        if (*p != (PCRE2_UCHAR)terminator)
-          {
-          *errorcodeptr = ERR57;
-          goto FAILED;
-          }
-        ptr++;
-        goto HANDLE_NUMERICAL_RECURSION;
-        }
-
-      /* \k<name> or \k'name' is a back reference by name (Perl syntax).
-      We also support \k{name} (.NET syntax).  */
-
-      if (escape == ESC_k)
-        {
-        if ((ptr[1] != CHAR_LESS_THAN_SIGN &&
-          ptr[1] != CHAR_APOSTROPHE && ptr[1] != CHAR_LEFT_CURLY_BRACKET))
-          {
-          *errorcodeptr = ERR69;
-          goto FAILED;
-          }
-        is_recurse = FALSE;
-        terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)?
-          CHAR_GREATER_THAN_SIGN : (*ptr == CHAR_APOSTROPHE)?
-          CHAR_APOSTROPHE : CHAR_RIGHT_CURLY_BRACKET;
-        goto NAMED_REF_OR_RECURSE;
-        }
-
-      /* Back references are handled specially; must disable firstcu if
-      not set to cope with cases like (?=(\w+))\1: which would otherwise set
-      ':' later. */
-
-      if (escape < 0)
-        {
-        open_capitem *oc;
-        recno = -escape;
-
-        /* Come here from named backref handling when the reference is to a
-        single group (i.e. not to a duplicated name). */
-
-        HANDLE_REFERENCE:
-        if (recno > (int)cb->final_bracount)
-          {
-          *errorcodeptr = ERR15;
-          goto FAILED;
-          }
-        if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
-        previous = code;
-        *code++ = ((options & PCRE2_CASELESS) != 0)? OP_REFI : OP_REF;
-        PUT2INC(code, 0, recno);
-        cb->backref_map |= (recno < 32)? (1u << recno) : 1;
-        if ((uint32_t)recno > cb->top_backref) cb->top_backref = recno;
-
-        /* Check to see if this back reference is recursive, that it, it
-        is inside the group that it references. A flag is set so that the
-        group can be made atomic. */
-
-        for (oc = cb->open_caps; oc != NULL; oc = oc->next)
-          {
-          if (oc->number == recno)
-            {
-            oc->flag = TRUE;
-            break;
-            }
-          }
-        }
-
-      /* So are Unicode property matches, if supported. */
-
-#ifdef SUPPORT_UNICODE
-      else if (escape == ESC_P || escape == ESC_p)
-        {
-        BOOL negated;
-        unsigned int ptype = 0, pdata = 0;
-        if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr, cb))
-          goto FAILED;
-        previous = code;
-        *code++ = ((escape == ESC_p) != negated)? OP_PROP : OP_NOTPROP;
-        *code++ = ptype;
-        *code++ = pdata;
-        }
-#else
-
-      /* If Unicode properties are not supported, \X, \P, and \p are not
-      allowed. */
-
-      else if (escape == ESC_X || escape == ESC_P || escape == ESC_p)
-        {
-        *errorcodeptr = ERR45;
-        goto FAILED;
-        }
 #endif


-      /* The use of \C can be locked out. */
+    /* For the rest (including \X when Unicode is supported - if not it's
+    faulted at parse time), the OP value is the escape value when PCRE2_UCP is
+    not set; if it is set, these escapes do not show up here because they are
+    converted into Unicode property tests in parse_regex(). Note that \b and \B
+    do a one-character lookbehind, and \A also behaves as if it does. */


-#ifdef NEVER_BACKSLASH_C
-      else if (escape == ESC_C)
-        {
-        *errorcodeptr = ERR85;
-        goto FAILED;
-        }
-#else
-      else if (escape == ESC_C && (options & PCRE2_NEVER_BACKSLASH_C) != 0)
-        {
-        *errorcodeptr = ERR83;
-        goto FAILED;
-        }
-#endif
+    if (meta_arg == ESC_C) cb->external_flags |= PCRE2_HASBKC; /* Record */
+    if ((meta_arg == ESC_b || meta_arg == ESC_B || meta_arg == ESC_A) &&
+         cb->max_lookbehind == 0)
+      cb->max_lookbehind = 1;


-      /* For the rest (including \X when Unicode properties are supported), we
-      can obtain the OP value by negating the escape value in the default
-      situation when PCRE2_UCP is not set. When it *is* set, we substitute
-      Unicode property tests. Note that \b and \B do a one-character
-      lookbehind, and \A also behaves as if it does. */
+    /* In non-UTF mode, and for both 32-bit modes, we turn \C into OP_ALLANY
+    instead of OP_ANYBYTE so that it works in DFA mode and in lookbehinds. */


-      else
-        {
-        if (escape == ESC_C) cb->external_flags |= PCRE2_HASBKC; /* Record */
-        if ((escape == ESC_b || escape == ESC_B || escape == ESC_A) &&
-             cb->max_lookbehind == 0)
-          cb->max_lookbehind = 1;
-#ifdef SUPPORT_UNICODE
-        if (escape >= ESC_DU && escape <= ESC_wu)
-          {
-          cb->nestptr[1] = cb->nestptr[0];         /* Back up if at 2nd level */
-          cb->nestptr[0] = ptr + 1;                /* Where to resume */
-          ptr = substitutes[escape - ESC_DU] - 1;  /* Just before substitute */
-          }
-        else
-#endif
-        /* In non-UTF mode, and for both 32-bit modes, we turn \C into
-        OP_ALLANY instead of OP_ANYBYTE so that it works in DFA mode and in
-        lookbehinds. */
-
-          {
-          previous = (escape > ESC_b && escape < ESC_Z)? code : NULL;
 #if PCRE2_CODE_UNIT_WIDTH == 32
-          *code++ = (escape == ESC_C)? OP_ALLANY : escape;
+    *code++ = (meta_arg == ESC_C)? OP_ALLANY : meta_arg;
 #else
-          *code++ = (!utf && escape == ESC_C)? OP_ALLANY : escape;
+    *code++ = (!utf && meta_arg == ESC_C)? OP_ALLANY : meta_arg;
 #endif
-          }
-        }
-      continue;
-      }
+    break;  /* End META_ESCAPE */


-    /* We have a data character whose value is in c. In UTF-8 mode it may have
-    a value > 127. We set its representation in the length/buffer, and then
-    handle it as a data character. */


-    mclength = PUTCHAR(c, mcbuffer);
-    goto ONE_CHAR;
-
-
     /* ===================================================================*/
-    /* Handle a literal character. It is guaranteed not to be whitespace or #
-    when the extended flag is set. If we are in a UTF mode, it may be a
-    multi-unit literal character. */
+    /* Handle an unrecognized meta value. A parsed pattern value less than
+    META_END is a literal. Otherwise we have a problem. */


     default:
-    NORMAL_CHAR:
-    mclength = 1;
-    mcbuffer[0] = c;
-
-#ifdef SUPPORT_UNICODE
-    if (utf && HAS_EXTRALEN(c))
-      ACROSSCHAR(TRUE, ptr[1], mcbuffer[mclength++] = *(++ptr));
+    if (meta >= META_END)
+      {
+#ifdef DEBUG_SHOW_PARSED
+      fprintf(stderr, "** Unrecognized parsed pattern item 0x%.8x\n", *pptr);
 #endif
+      *errorcodeptr = ERR89;  /* Internal error - unrecognized. */
+      return FALSE;
+      }


-    /* At this point we have the character's bytes in mcbuffer, and the length
-    in mclength. When not in UTF mode, the length is always 1. */
+    /* Handle a literal character. We come here by goto in the case of a
+    32-bit, non-UTF character whose value is greater than META_END. */


-    ONE_CHAR:
-    previous = code;
+    NORMAL_CHAR:
+    meta = *pptr;     /* Get the full 32 bits */
+    NORMAL_CHAR_SET:  /* Character is already in meta */


     /* For caseless UTF mode, check whether this character has more than one
     other case. If so, generate a special OP_PROP item instead of OP_CHARI. */
@@ -7492,23 +7204,36 @@
 #ifdef SUPPORT_UNICODE
     if (utf && (options & PCRE2_CASELESS) != 0)
       {
-      GETCHAR(c, mcbuffer);
-      if ((c = UCD_CASESET(c)) != 0)
+      uint32_t caseset = UCD_CASESET(meta);
+      if (caseset != 0)
         {
         *code++ = OP_PROP;
         *code++ = PT_CLIST;
-        *code++ = c;
+        *code++ = caseset;
         if (firstcuflags == REQ_UNSET)
           firstcuflags = zerofirstcuflags = REQ_NONE;
-        break;
+        break;  /* End handling this meta item */
         }
       }
 #endif


-    /* Caseful matches, or not one of the multicase characters. */
+    /* Caseful matches, or not one of the multicase characters. Get the
+    character's code units into mcbuffer, with the length in mclength. When not
+    in UTF mode, the length is always 1. */


+#ifdef SUPPORT_UNICODE
+    if (utf) mclength = PRIV(ord2utf)(meta, mcbuffer); else
+#endif
+      {
+      mclength = 1;
+      mcbuffer[0] = meta;
+      }
+
+    /* Generate the appropriate code */
+
     *code++ = ((options & PCRE2_CASELESS) != 0)? OP_CHARI : OP_CHAR;
-    for (c = 0; c < mclength; c++) *code++ = mcbuffer[c];
+    memcpy(code, mcbuffer, CU2BYTES(mclength));
+    code += mclength;


     /* Remember if \r or \n were seen */


@@ -7515,10 +7240,10 @@
     if (mcbuffer[0] == CHAR_CR || mcbuffer[0] == CHAR_NL)
       cb->external_flags |= PCRE2_HASCRORLF;


-    /* Set the first and required bytes appropriately. If no previous first
-    byte, set it from this character, but revert to none on a zero repeat.
-    Otherwise, leave the firstcu value alone, and don't change it on a zero
-    repeat. */
+    /* Set the first and required code units appropriately. If no previous
+    first code unit, set it from this character, but revert to none on a zero
+    repeat. Otherwise, leave the firstcu value alone, and don't change it on
+    a zero repeat. */


     if (firstcuflags == REQ_UNSET)
       {
@@ -7526,7 +7251,7 @@
       zeroreqcu = reqcu;
       zeroreqcuflags = reqcuflags;


-      /* If the character is more than one byte long, we can set firstcu
+      /* If the character is more than one code unit long, we can set firstcu
       only if it is not to be matched caselessly. */


       if (mclength == 1 || req_caseopt == 0)
@@ -7534,7 +7259,6 @@
         firstcu = mcbuffer[0] | req_caseopt;
         firstcu = mcbuffer[0];
         firstcuflags = req_caseopt;
-
         if (mclength != 1)
           {
           reqcu = code[-1];
@@ -7559,18 +7283,11 @@
         reqcuflags = req_caseopt | cb->req_varyopt;
         }
       }
+    break;    /* End default meta handling */
+    }         /* End of big switch */
+  }           /* End of big loop */


-    break;            /* End of literal character handling */
-    }
-  }                   /* end of big loop */
-
-/* Control never reaches here by falling through, only by a goto for all the
-error states. Pass back the position in the pattern so that it can be displayed
-to the user for diagnosing the error. */
-
-FAILED:
-*ptrptr = ptr;
-return FALSE;
+/* Control never reaches here. */
 }



@@ -7579,22 +7296,19 @@
 *   Compile regex: a sequence of alternatives    *
 *************************************************/


-/* On entry, ptr is pointing past the bracket character, but on return it
-points to the closing bracket, or vertical bar, or end of string. The code
-variable is pointing at the byte into which the BRA operator has been stored.
-This function is used during the pre-compile phase when we are trying to find
-out the amount of memory needed, as well as during the real compile phase. The
-value of lengthptr distinguishes the two phases.
+/* On entry, pptr is pointing past the bracket meta, but on return it points to
+the closing bracket or META_END. The code variable is pointing at the code unit
+into which the BRA operator has been stored. This function is used during the
+pre-compile phase when we are trying to find out the amount of memory needed,
+as well as during the real compile phase. The value of lengthptr distinguishes
+the two phases.

 Arguments:
   options           option bits, including any changes for this subpattern
   codeptr           -> the address of the current code pointer
-  ptrptr            -> the address of the current pattern pointer
+  pptrptr           -> the address of the current parsed pattern pointer
   errorcodeptr      -> pointer to error code variable
-  lookbehind        TRUE if this is a lookbehind assertion
-  reset_bracount    TRUE to reset the count for each branch
   skipunits         skip this many code units at start (for brackets and OP_COND)
-  cond_depth        depth of nesting for conditional subpatterns
   firstcuptr        place to put the first required code unit
   firstcuflagsptr   place to put the first code unit flags, or a negative number
   reqcuptr          place to put the last required code unit
@@ -7608,26 +7322,24 @@
 */


static BOOL
-compile_regex(uint32_t options, PCRE2_UCHAR **codeptr, PCRE2_SPTR *ptrptr,
- int *errorcodeptr, BOOL lookbehind, BOOL reset_bracount, uint32_t skipunits,
- int cond_depth, uint32_t *firstcuptr, int32_t *firstcuflagsptr,
- uint32_t *reqcuptr, int32_t *reqcuflagsptr, branch_chain *bcptr,
- compile_block *cb, size_t *lengthptr)
+compile_regex(uint32_t options, PCRE2_UCHAR **codeptr, uint32_t **pptrptr,
+ int *errorcodeptr, uint32_t skipunits, uint32_t *firstcuptr,
+ int32_t *firstcuflagsptr, uint32_t *reqcuptr,int32_t *reqcuflagsptr,
+ branch_chain *bcptr, compile_block *cb, PCRE2_SIZE *lengthptr)
{
-PCRE2_SPTR ptr = *ptrptr;
PCRE2_UCHAR *code = *codeptr;
PCRE2_UCHAR *last_branch = code;
PCRE2_UCHAR *start_bracket = code;
-PCRE2_UCHAR *reverse_count = NULL;
+BOOL lookbehind;
open_capitem capitem;
int capnumber = 0;
+uint32_t *pptr = *pptrptr;
uint32_t firstcu, reqcu;
+uint32_t lookbehindlength;
int32_t firstcuflags, reqcuflags;
uint32_t branchfirstcu, branchreqcu;
int32_t branchfirstcuflags, branchreqcuflags;
-size_t length;
-unsigned int orig_bracount;
-unsigned int max_bracount;
+PCRE2_SIZE length;
branch_chain bc;

/* If set, call the external function that checks for stack availability. */
@@ -7656,17 +7368,22 @@

length = 2 + 2*LINK_SIZE + skipunits;

-/* WARNING: If the above line is changed for any reason, you must also change
-the code that abstracts option settings at the start of the pattern and makes
-them global. It tests the value of length for (2 + 2*LINK_SIZE) in the
-pre-compile phase to find out whether or not anything has yet been compiled.
+/* Remember if this is a lookbehind assertion, and if it is, save its length
+and skip over the pattern offset. */

-If this is a capturing subpattern, add to the chain of open capturing items
-so that we can detect them if (*ACCEPT) is encountered. This is also used to
-detect groups that contain recursive back references to themselves. Note that
-only OP_CBRA need be tested here; changing this opcode to one of its variants,
-e.g. OP_SCBRAPOS, happens later, after the group has been compiled. */
+lookbehind = *code == OP_ASSERTBACK || *code == OP_ASSERTBACK_NOT;
+if (lookbehind)
+ {
+ lookbehindlength = META_DATA(pptr[-1]);
+ pptr += SIZEOFFSET;
+ }
+else lookbehindlength = 0;

+/* If this is a capturing subpattern, add to the chain of open capturing items
+so that we can detect them if (*ACCEPT) is encountered. Note that only OP_CBRA
+need be tested here; changing this opcode to one of its variants, e.g.
+OP_SCBRAPOS, happens later, after the group has been compiled. */
+
if (*code == OP_CBRA)
{
capnumber = GET2(code, 1 + LINK_SIZE);
@@ -7683,22 +7400,14 @@

/* Loop for each alternative branch */

-orig_bracount = max_bracount = cb->bracount;
-
for (;;)
{
- /* For a (?| group, reset the capturing bracket count so that each branch
- uses the same numbers. */
+ /* Insert OP_REVERSE if this is as lookbehind assertion. */

-  if (reset_bracount) cb->bracount = orig_bracount;
-
-  /* Set up dummy OP_REVERSE if lookbehind assertion */
-
-  if (lookbehind)
+  if (lookbehind && lookbehindlength > 0)
     {
     *code++ = OP_REVERSE;
-    reverse_count = code;
-    PUTINC(code, 0, 0);
+    PUTINC(code, 0, lookbehindlength);
     length += 1 + LINK_SIZE;
     }


@@ -7705,19 +7414,11 @@
/* Now compile the branch; in the pre-compile phase its length gets added
into the length. */

-  if (!compile_branch(&options, &code, &ptr, errorcodeptr, &branchfirstcu,
+  if (!compile_branch(&options, &code, &pptr, errorcodeptr, &branchfirstcu,
         &branchfirstcuflags, &branchreqcu, &branchreqcuflags, &bc,
-        cond_depth, cb, (lengthptr == NULL)? NULL : &length))
-    {
-    *ptrptr = ptr;
+        cb, (lengthptr == NULL)? NULL : &length))
     return FALSE;
-    }


- /* Keep the highest bracket count in case (?| was used and some branch
- has fewer than the rest. */
-
- if (cb->bracount > max_bracount) max_bracount = cb->bracount;
-
/* In the real compile phase, there is some post-processing to be done. */

   if (lengthptr == NULL)
@@ -7778,56 +7479,24 @@
         reqcuflags |= branchreqcuflags; /* To "or" REQ_VARY */
         }
       }
-
-    /* If lookbehind, check that this branch matches a fixed-length string, and
-    put the length into the OP_REVERSE item. Temporarily mark the end of the
-    branch with OP_END. If the branch contains OP_RECURSE, the result is
-    FFL_LATER (a negative value) because there may be forward references that
-    we can't check here. Set a flag to cause another lookbehind check at the
-    end. Why not do it all at the end? Because common errors can be picked up
-    here and the offset of the problem can be shown. */
-
-    if (lookbehind)
-      {
-      int fixed_length;
-      int count = 0;
-      *code = OP_END;
-      fixed_length = find_fixedlength(last_branch,  (options & PCRE2_UTF) != 0,
-        FALSE, cb, NULL, &count);
-      if (fixed_length == FFL_LATER)
-        {
-        cb->check_lookbehind = TRUE;
-        }
-      else if (fixed_length < 0)
-        {
-        *errorcodeptr = fixed_length_errors[-fixed_length];
-        *ptrptr = ptr;
-        return FALSE;
-        }
-      else
-        {
-        if (fixed_length > cb->max_lookbehind)
-          cb->max_lookbehind = fixed_length;
-        PUT(reverse_count, 0, fixed_length);
-        }
-      }
     }


- /* Reached end of expression, either ')' or end of pattern. In the real
- compile phase, go back through the alternative branches and reverse the chain
- of offsets, with the field in the BRA item now becoming an offset to the
- first alternative. If there are no alternatives, it points to the end of the
- group. The length in the terminating ket is always the length of the whole
- bracketed item. Return leaving the pointer at the terminating char. */
+ /* Handle reaching the end of the expression, either ')' or end of pattern.
+ In the real compile phase, go back through the alternative branches and
+ reverse the chain of offsets, with the field in the BRA item now becoming an
+ offset to the first alternative. If there are no alternatives, it points to
+ the end of the group. The length in the terminating ket is always the length
+ of the whole bracketed item. Return leaving the pointer at the terminating
+ char. */

-  if (*ptr != CHAR_VERTICAL_LINE)
+  if (META_CODE(*pptr) != META_ALT)
     {
     if (lengthptr == NULL)
       {
-      size_t branch_length = code - last_branch;
+      PCRE2_SIZE branch_length = code - last_branch;
       do
         {
-        size_t prev_length = GET(last_branch, 1);
+        PCRE2_SIZE prev_length = GET(last_branch, 1);
         PUT(last_branch, 1, branch_length);
         branch_length = prev_length;
         last_branch -= branch_length;
@@ -7862,14 +7531,10 @@
       cb->open_caps = cb->open_caps->next;
       }


-    /* Retain the highest bracket number, in case resetting was used. */
-
-    cb->bracount = max_bracount;
-
     /* Set values to pass back */


     *codeptr = code;
-    *ptrptr = ptr;
+    *pptrptr = pptr;
     *firstcuptr = firstcu;
     *firstcuflagsptr = firstcuflags;
     *reqcuptr = reqcu;
@@ -7906,11 +7571,12 @@
     PUT(code, 1, (int)(code - last_branch));
     bc.current_branch = last_branch = code;
     code += 1 + LINK_SIZE;
+    lookbehindlength = META_DATA(*pptr);
     }


/* Advance past the vertical bar */

- ptr++;
+ pptr++;
}
/* Control never reaches here */
}
@@ -7959,13 +7625,13 @@
*/

 static BOOL
-is_anchored(register PCRE2_SPTR code, unsigned int bracket_map,
-  compile_block *cb, int atomcount)
+is_anchored(PCRE2_SPTR code, unsigned int bracket_map, compile_block *cb,
+  int atomcount)
 {
 do {
    PCRE2_SPTR scode = first_significant_code(
      code + PRIV(OP_lengths)[*code], FALSE);
-   register int op = *scode;
+   int op = *scode;


    /* Non-capturing brackets */


@@ -8056,7 +7722,7 @@
 do {
    PCRE2_SPTR scode = first_significant_code(
      code + PRIV(OP_lengths)[*code], FALSE);
-   register int op = *scode;
+   int op = *scode;


    /* If we are at the start of a conditional assertion group, *both* the
    conditional assertion *and* what follows the condition must satisfy the test
@@ -8155,6 +7821,153 @@



 /*************************************************
+*   Scan compiled regex for recursion reference  *
+*************************************************/
+
+/* This function scans through a compiled pattern until it finds an instance of
+OP_RECURSE.
+
+Arguments:
+  code        points to start of expression
+  utf         TRUE in UTF mode
+
+Returns:      pointer to the opcode for OP_RECURSE, or NULL if not found
+*/
+
+static PCRE2_SPTR
+find_recurse(PCRE2_SPTR code, BOOL utf)
+{
+for (;;)
+  {
+  PCRE2_UCHAR c = *code;
+  if (c == OP_END) return NULL;
+  if (c == OP_RECURSE) return code;
+
+  /* XCLASS is used for classes that cannot be represented just by a bit map.
+  This includes negated single high-valued characters. CALLOUT_STR is used for
+  callouts with string arguments. In both cases the length in the table is
+  zero; the actual length is stored in the compiled code. */
+
+  if (c == OP_XCLASS) code += GET(code, 1);
+    else if (c == OP_CALLOUT_STR) code += GET(code, 1 + 2*LINK_SIZE);
+
+  /* Otherwise, we can get the item's length from the table, except that for
+  repeated character types, we have to test for \p and \P, which have an extra
+  two code units of parameters, and for MARK/PRUNE/SKIP/THEN with an argument,
+  we must add in its length. */
+
+  else
+    {
+    switch(c)
+      {
+      case OP_TYPESTAR:
+      case OP_TYPEMINSTAR:
+      case OP_TYPEPLUS:
+      case OP_TYPEMINPLUS:
+      case OP_TYPEQUERY:
+      case OP_TYPEMINQUERY:
+      case OP_TYPEPOSSTAR:
+      case OP_TYPEPOSPLUS:
+      case OP_TYPEPOSQUERY:
+      if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2;
+      break;
+
+      case OP_TYPEPOSUPTO:
+      case OP_TYPEUPTO:
+      case OP_TYPEMINUPTO:
+      case OP_TYPEEXACT:
+      if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
+        code += 2;
+      break;
+
+      case OP_MARK:
+      case OP_PRUNE_ARG:
+      case OP_SKIP_ARG:
+      case OP_THEN_ARG:
+      code += code[1];
+      break;
+      }
+
+    /* Add in the fixed length from the table */
+
+    code += PRIV(OP_lengths)[c];
+
+    /* In UTF-8 and UTF-16 modes, opcodes that are followed by a character may
+    be followed by a multi-unit character. The length in the table is a
+    minimum, so we have to arrange to skip the extra units. */
+
+#ifdef MAYBE_UTF_MULTI
+    if (utf) switch(c)
+      {
+      case OP_CHAR:
+      case OP_CHARI:
+      case OP_NOT:
+      case OP_NOTI:
+      case OP_EXACT:
+      case OP_EXACTI:
+      case OP_NOTEXACT:
+      case OP_NOTEXACTI:
+      case OP_UPTO:
+      case OP_UPTOI:
+      case OP_NOTUPTO:
+      case OP_NOTUPTOI:
+      case OP_MINUPTO:
+      case OP_MINUPTOI:
+      case OP_NOTMINUPTO:
+      case OP_NOTMINUPTOI:
+      case OP_POSUPTO:
+      case OP_POSUPTOI:
+      case OP_NOTPOSUPTO:
+      case OP_NOTPOSUPTOI:
+      case OP_STAR:
+      case OP_STARI:
+      case OP_NOTSTAR:
+      case OP_NOTSTARI:
+      case OP_MINSTAR:
+      case OP_MINSTARI:
+      case OP_NOTMINSTAR:
+      case OP_NOTMINSTARI:
+      case OP_POSSTAR:
+      case OP_POSSTARI:
+      case OP_NOTPOSSTAR:
+      case OP_NOTPOSSTARI:
+      case OP_PLUS:
+      case OP_PLUSI:
+      case OP_NOTPLUS:
+      case OP_NOTPLUSI:
+      case OP_MINPLUS:
+      case OP_MINPLUSI:
+      case OP_NOTMINPLUS:
+      case OP_NOTMINPLUSI:
+      case OP_POSPLUS:
+      case OP_POSPLUSI:
+      case OP_NOTPOSPLUS:
+      case OP_NOTPOSPLUSI:
+      case OP_QUERY:
+      case OP_QUERYI:
+      case OP_NOTQUERY:
+      case OP_NOTQUERYI:
+      case OP_MINQUERY:
+      case OP_MINQUERYI:
+      case OP_NOTMINQUERY:
+      case OP_NOTMINQUERYI:
+      case OP_POSQUERY:
+      case OP_POSQUERYI:
+      case OP_NOTPOSQUERY:
+      case OP_NOTPOSQUERYI:
+      if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]);
+      break;
+      }
+#else
+    (void)(utf);  /* Keep compiler happy by referencing function argument */
+#endif  /* MAYBE_UTF_MULTI */
+    }
+  }
+}
+
+
+
+/*************************************************
 *    Check for asserted fixed first code unit    *
 *************************************************/


@@ -8179,7 +7992,7 @@
static uint32_t
find_firstassertedcu(PCRE2_SPTR code, int32_t *flags, BOOL inassert)
{
-register uint32_t c = 0;
+uint32_t c = 0;
int cflags = REQ_NONE;

 *flags = REQ_NONE;
@@ -8189,7 +8002,7 @@
    int xl = (*code == OP_CBRA || *code == OP_SCBRA ||
              *code == OP_CBRAPOS || *code == OP_SCBRAPOS)? IMM2_SIZE:0;
    PCRE2_SPTR scode = first_significant_code(code + 1+LINK_SIZE + xl, TRUE);
-   register PCRE2_UCHAR op = *scode;
+   PCRE2_UCHAR op = *scode;


    switch(op)
      {
@@ -8262,6 +8075,7 @@
   name         the name to add
   length       the length of the name
   groupno      the group number
+  tablecount   the count of names in the table so far


 Returns:       nothing
 */
@@ -8268,12 +8082,12 @@


static void
add_name_to_table(compile_block *cb, PCRE2_SPTR name, int length,
- unsigned int groupno)
+ unsigned int groupno, uint32_t tablecount)
{
-int i;
+uint32_t i;
PCRE2_UCHAR *slot = cb->name_table;

-for (i = 0; i < cb->names_found; i++)
+for (i = 0; i < tablecount; i++)
{
int crc = memcmp(name, slot+IMM2_SIZE, CU2BYTES(length));
if (crc == 0 && slot[IMM2_SIZE+length] != 0)
@@ -8298,7 +8112,6 @@

PUT2(slot, 0, groupno);
memcpy(slot + IMM2_SIZE, name, CU2BYTES(length));
-cb->names_found++;

/* Add a terminating zero and fill the rest of the slot with zeroes so that
the memory is all initialized. Otherwise valgrind moans about uninitialized
@@ -8311,6 +8124,652 @@


 /*************************************************
+*             Skip in parsed pattern             *
+*************************************************/
+
+/* This function is called to skip parts of the parsed pattern when finding the
+length of a lookbehind branch. It is called after (*ACCEPT) and (*FAIL) to find
+the end of the branch, it is called to skip over an internal lookaround, and it
+is also called to skip to the end of a class, during which it will never
+encounter nested groups (but there's no need to have special code for that).
+
+Arguments:
+  pptr       current pointer to skip from
+  skiptype   PSKIP_CLASS when skipping to end of class
+             PSKIP_ALT when META_ALT ends the skip
+             PSKIP_KET when only META_KET ends the skip
+
+Returns:     new value of pptr
+*/
+
+static uint32_t *
+parsed_skip(uint32_t *pptr, uint32_t skiptype)
+{
+uint32_t nestlevel = 0;
+
+for (pptr += 1;; pptr++)
+  {
+  switch(META_CODE(*pptr))
+    {
+    case META_BIGVALUE:
+    pptr += 1;
+    break;
+
+    case META_CLASS_END:
+    if (skiptype == PSKIP_CLASS) return pptr;
+    break;
+
+    case META_ATOMIC:
+    case META_CAPTURE:
+    case META_COND_ASSERT:
+    case META_COND_DEFINE:
+    case META_COND_NAME:
+    case META_COND_NUMBER:
+    case META_COND_RNAME:
+    case META_COND_RNUMBER:
+    case META_COND_VERSION:
+    case META_LOOKAHEAD:
+    case META_LOOKAHEADNOT:
+    case META_LOOKBEHIND:
+    case META_LOOKBEHINDNOT:
+    case META_NOCAPTURE:
+    nestlevel++;
+    break;
+
+    case META_ALT:
+    if (nestlevel == 0 && skiptype == PSKIP_ALT) return pptr;
+    break;
+
+    case META_KET:
+    if (nestlevel == 0) return pptr;
+    nestlevel--;
+    break;
+
+    default:
+    break;
+    }
+  }
+/* Control never reaches here */
+return pptr;
+}
+
+
+
+/*************************************************
+*       Find length of a parsed group            *
+*************************************************/
+
+/* This is called for nested groups within a branch of a lookbehind whose
+length is being computed. If all the branches in the nested group have the same
+length, that is OK. On entry, the pointer must be at the first element after
+the group initializing code. Caching is used to improve processing speed when
+the same capturing group occurs many times.
+
+Arguments:
+  pptrptr     pointer to pointer in the parsed pattern
+  errcodeptr  pointer to the errorcode
+  lcptr       pointer to the loop counter
+  group       number of captured group or -1 for a non-capturing group
+  recurses    chain of recurse_check to catch mutual recursion
+  cb          pointer to the compile data
+
+Returns:      the group length or a negative number
+*/
+
+static int
+get_grouplength(uint32_t **pptrptr, int *errcodeptr, int *lcptr,
+  int group, parsed_recurse_check *recurses, compile_block *cb)
+{
+int branchlength;
+int grouplength = -1;
+
+/* The cache can be used only if there is no possibility of there being two
+groups with the same number. */
+
+if (group > 0)
+  {
+  uint32_t groupinfo = cb->groupinfo[group];
+  if ((cb->external_flags & PCRE2_DUPCAPUSED) == 0)
+    {
+    if ((groupinfo & GI_NOT_FIXED_LENGTH) != 0) return -1;
+    if ((groupinfo & GI_SET_FIXED_LENGTH) != 0)
+      return groupinfo & GI_FIXED_LENGTH_MASK;
+    }
+  }
+
+/* Scan the group */
+
+for(;;)
+  {
+  branchlength = get_branchlength(pptrptr, errcodeptr, lcptr, recurses, cb);
+  if (branchlength < 0) goto ISNOTFIXED;
+  if (grouplength == -1) grouplength = branchlength;
+    else if (grouplength != branchlength) goto ISNOTFIXED;
+  if (**pptrptr == META_KET) break;
+  *pptrptr += 1;   /* Skip META_ALT */
+  }
+
+if (group > 0)
+  cb->groupinfo[group] |= (uint32_t)(GI_SET_FIXED_LENGTH | grouplength);
+return grouplength;
+
+ISNOTFIXED:
+if (group > 0) cb->groupinfo[group] |= GI_NOT_FIXED_LENGTH;
+return -1;
+}
+
+
+
+/*************************************************
+*        Find length of a parsed branch          *
+*************************************************/
+
+/* Return a fixed length for a branch in a lookbehind, giving an error if the
+length is not fixed. If any lookbehinds are encountered on the way, they get
+their length set. On entry, *pptrptr points to the first element inside the
+branch. On exit it is set to point to the ALT or KET.
+
+Arguments:
+  pptrptr     pointer to pointer in the parsed pattern
+  errcodeptr  pointer to error code
+  lcptr       pointer to loop counter
+  recurses    chain of recurse_check to catch mutual recursion
+  cb          pointer to compile block
+
+Returns:      the length, or a negative value on error
+*/
+
+static int
+get_branchlength(uint32_t **pptrptr, int *errcodeptr, int *lcptr,
+  parsed_recurse_check *recurses, compile_block *cb)
+{
+int branchlength = 0;
+int grouplength;
+uint32_t lastitemlength = 0;
+uint32_t *pptr = *pptrptr;
+PCRE2_SIZE offset;
+parsed_recurse_check this_recurse;
+
+/* A large and/or complex regex can take too long to process. This can happen
+more often when (?| groups are present in the pattern because their length
+cannot be cached. */
+
+if ((*lcptr)++ > 2000)
+  {
+  *errcodeptr = ERR35;  /* Lookbehind is too complicated */
+  return -1;
+  }
+
+/* Scan the branch, accumulating the length. */
+
+for (;; pptr++)
+  {
+  parsed_recurse_check *r;
+  uint32_t *gptr, *gptrend;
+  uint32_t escape;
+  uint32_t group = 0;
+  uint32_t itemlength = 0;
+
+  if (*pptr < META_END)
+    {
+    itemlength = 1;
+    }
+
+  else switch (META_CODE(*pptr))
+    {
+    case META_KET:
+    case META_ALT:
+    goto EXIT;
+
+    /* (*ACCEPT) and (*FAIL) terminate the branch, but we must skip to the
+    actual termination. */
+
+    case META_ACCEPT:
+    case META_FAIL:
+    pptr = parsed_skip(pptr, PSKIP_ALT);
+    goto EXIT;
+
+    case META_MARK:
+    case META_PRUNE_ARG:
+    case META_SKIP_ARG:
+    case META_THEN_ARG:
+    pptr += pptr[1] + 1;
+    break;
+
+    case META_CIRCUMFLEX:
+    case META_COMMIT:
+    case META_DOLLAR:
+    case META_PRUNE:
+    case META_SKIP:
+    case META_THEN:
+    break;
+
+    case META_OPTIONS:
+    pptr += 1;
+    break;
+
+    case META_BIGVALUE:
+    itemlength = 1;
+    pptr += 1;
+    break;
+
+    case META_CLASS:
+    case META_CLASS_NOT:
+    itemlength = 1;
+    pptr = parsed_skip(pptr, PSKIP_CLASS);
+    break;
+
+    case META_CLASS_EMPTY_NOT:
+    case META_DOT:
+    itemlength = 1;
+    break;
+
+    case META_CALLOUT_NUMBER:
+    pptr += 3;
+    break;
+
+    case META_CALLOUT_STRING:
+    pptr += 3 + SIZEOFFSET;
+    break;
+
+    /* Only some escapes consume a character. Of those, \R and \X are never
+    allowed because they might match more than character. \C is allowed only in
+    32-bit and non-UTF 8/16-bit modes. */
+
+    case META_ESCAPE:
+    escape = META_DATA(*pptr);
+    if (escape == ESC_R || escape == ESC_X) return -1;
+    if (escape > ESC_b && escape < ESC_Z)
+      {
+#if PCRE2_CODE_UNIT_WIDTH != 32
+      if ((cb->external_options & PCRE2_UTF) != 0 && escape == ESC_C)
+        {
+        *errcodeptr = ERR36;
+        return -1;
+        }
+#endif
+      itemlength = 1;
+      if (escape == ESC_p || escape == ESC_P) pptr++;  /* Skip prop data */
+      }
+    break;
+
+    /* Lookaheads can be ignored. */
+
+    case META_LOOKAHEAD:
+    case META_LOOKAHEADNOT:
+    pptr = parsed_skip(pptr, PSKIP_KET);
+    break;
+
+    /* Lookbehinds can be ignored, but must themselves be checked. */
+
+    case META_LOOKBEHIND:
+    case META_LOOKBEHINDNOT:
+    if (!set_lookbehind_lengths(&pptr, errcodeptr, lcptr, recurses, cb))
+      return -1;
+    break;
+
+    /* Back references and recursions are handled by very similar code. At this
+    stage, the names generated in the parsing pass are available, but the main
+    name table has not yet been created. So for the named varieties, scan the
+    list of names in order to get the number of the first one in the pattern,
+    and whether or not this name is duplicated. */
+
+    case META_BACKREF_BYNAME:
+    if ((cb->external_options & PCRE2_MATCH_UNSET_BACKREF) != 0)
+      goto ISNOTFIXED;
+
+    case META_RECURSE_BYNAME:
+      {
+      int i;
+      PCRE2_SPTR name;
+      BOOL is_dupname = FALSE;
+      named_group *ng = cb->named_groups;
+      uint32_t meta_code = META_CODE(*pptr);
+      uint32_t length = *(++pptr);
+
+      GETPLUSOFFSET(offset, pptr);
+      name = cb->start_pattern + offset;
+      for (i = 0; i < cb->names_found; i++, ng++)
+        {
+        if (length == ng->length && PRIV(strncmp)(name, ng->name, length) == 0)
+          {
+          group = ng->number;
+          is_dupname = ng->isdup;
+          break;
+          }
+        }
+
+      if (group == 0)
+        {
+        *errcodeptr = ERR15;  /* Non-existent subpattern */
+        cb->erroroffset = offset;
+        return -1;
+        }
+
+      /* A numerical back reference can be fixed length if duplicate capturing
+      groups are not being used. A non-duplicate named back reference can also
+      be handled. */
+
+      if (meta_code == META_RECURSE_BYNAME ||
+          (!is_dupname && (cb->external_flags & PCRE2_DUPCAPUSED) == 0))
+        goto RECURSE_OR_BACKREF_LENGTH;  /* Handle as a numbered version. */
+      }
+    goto ISNOTFIXED;                     /* Duplicate name or number */
+
+    /* The offset values for back references < 10 are in a separate vector
+    because otherwise they would use more than two parsed pattern elements on
+    64-bit systems. */
+
+    case META_BACKREF:
+    if ((cb->external_options & PCRE2_MATCH_UNSET_BACKREF) != 0 ||
+        (cb->external_flags & PCRE2_DUPCAPUSED) != 0)
+      goto ISNOTFIXED;
+    group = META_DATA(*pptr);
+    if (group < 10)
+      {
+      offset = cb->small_ref_offset[group];
+      goto RECURSE_OR_BACKREF_LENGTH;
+      }
+
+    /* Fall through for groups >= 10 - picking up group twice does no harm. */
+
+    /* A true recursion implies not fixed length, but a subroutine call may
+    be OK. Back reference "recursions" are also failed. */
+
+    case META_RECURSE:
+    group = META_DATA(*pptr);
+    GETPLUSOFFSET(offset, pptr);
+
+    RECURSE_OR_BACKREF_LENGTH:
+    if (group > cb->bracount)
+      {
+      cb->erroroffset = offset;
+      *errcodeptr = ERR15;  /* Non-existent subpattern */
+      return -1;
+      }
+
+    for (gptr = cb->parsed_pattern; *gptr != META_END; gptr++)
+      {
+      if (META_CODE(*gptr) == META_BIGVALUE) gptr++;
+        else if (*gptr == (META_CAPTURE | group)) break;
+      }
+    gptrend = parsed_skip(gptr, PSKIP_KET);
+    if (pptr > gptr && pptr < gptrend) goto ISNOTFIXED;  /* Local recursion */
+    for (r = recurses; r != NULL; r = r->prev) if (r->groupptr == gptr) break;
+    if (r != NULL) goto ISNOTFIXED;   /* Mutual recursion */
+    this_recurse.prev = recurses;
+    this_recurse.groupptr = gptr;
+    gptr++;
+    grouplength = get_grouplength(&gptr, errcodeptr, lcptr, group,
+      &this_recurse, cb);
+    if (grouplength < 0)
+      {
+      if (*errcodeptr == 0) goto ISNOTFIXED;
+      return -1;  /* Error already set */
+      }
+    itemlength = grouplength;
+    break;
+
+    /* Check nested groups - advance past the initial data for each type and
+    then seek a fixed length with get_grouplength(). */
+
+    case META_COND_NAME:
+    case META_COND_NUMBER:
+    case META_COND_RNAME:
+    case META_COND_RNUMBER:
+    case META_COND_DEFINE:
+    pptr += 2 + SIZEOFFSET;
+    goto CHECK_GROUP;
+
+    case META_COND_ASSERT:
+    pptr += 1 + SIZEOFFSET;
+    goto CHECK_GROUP;
+
+    case META_COND_VERSION:
+    pptr += 4;
+    goto CHECK_GROUP;
+
+    case META_CAPTURE:
+    group = META_DATA(*pptr);
+    /* Fall through */
+
+    case META_ATOMIC:
+    case META_NOCAPTURE:
+    pptr++;
+    CHECK_GROUP:
+    grouplength = get_grouplength(&pptr, errcodeptr, lcptr, group, recurses, cb);
+    if (grouplength < 0) return -1;
+    itemlength = grouplength;
+    break;
+
+    /* Exact repetition is OK; variable repetition is not. A repetition of zero
+    must subtract the length that has already been added. */
+
+    case META_MINMAX:
+    case META_MINMAX_PLUS:
+    case META_MINMAX_QUERY:
+    if (pptr[1] == pptr[2])
+      {
+      if (pptr[1] == 0) branchlength -= lastitemlength;
+        else itemlength = (pptr[1] - 1) * lastitemlength;
+      pptr += 2;
+      break;
+      }
+    /* Fall through */
+
+    /* Any other item means this branch does not have a fixed length. */
+
+    default:
+    ISNOTFIXED:
+    *errcodeptr = ERR25;   /* Not fixed length */
+    return -1;
+    }
+
+  /* Add the item length to the branchlength, and save it for use if the next
+  thing is a quantifier. */
+
+  branchlength += itemlength;
+  lastitemlength = itemlength;
+
+  /* Ensure that the length does not overflow the limit. */
+
+  if (branchlength > LOOKBEHIND_MAX)
+    {
+    *errcodeptr = ERR87;
+    return -1;
+    }
+  }
+
+EXIT:
+*pptrptr = pptr;
+if (branchlength > cb->max_lookbehind) cb->max_lookbehind = branchlength;
+return branchlength;
+}
+
+
+
+/*************************************************
+*        Set lengths in a lookbehind             *
+*************************************************/
+
+/* This function is called for each lookbehind, to set the lengths in its
+branches. An error occurs if any branch does not have a fixed length that is
+less than the maximum (65535). On exit, the pointer must be left on the final
+ket.
+
+Arguments:
+  pptrptr     pointer to pointer in the parsed pattern
+  errcodeptr  pointer to error code
+  lcptr       pointer to loop counter
+  recurses    chain of recurse_check to catch mutual recursion
+  cb          pointer to compile block
+
+Returns:      TRUE if all is well
+              FALSE otherwise, with error code and offset set
+*/
+
+static BOOL
+set_lookbehind_lengths(uint32_t **pptrptr, int *errcodeptr, int *lcptr,
+  parsed_recurse_check *recurses, compile_block *cb)
+{
+PCRE2_SIZE offset;
+int branchlength;
+uint32_t *bptr = *pptrptr;
+
+READPLUSOFFSET(offset, bptr);  /* Offset for error messages */
+*pptrptr += SIZEOFFSET;
+
+do
+  {
+  *pptrptr += 1;
+  branchlength = get_branchlength(pptrptr, errcodeptr, lcptr, recurses, cb);
+  if (branchlength < 0)
+    {
+    /* The errorcode and offset may already be set from a nested lookbehind. */
+    if (*errcodeptr == 0) *errcodeptr = ERR25;
+    if (cb->erroroffset == PCRE2_UNSET) cb->erroroffset = offset;
+    return FALSE;
+    }
+  *bptr |= branchlength;  /* branchlength never more than 65535 */
+  bptr = *pptrptr;
+  }
+while (*bptr == META_ALT);
+
+return TRUE;
+}
+
+
+
+/*************************************************
+*         Check parsed pattern lookbehinds       *
+*************************************************/
+
+/* This function is called at the end of parsing a pattern if any lookbehinds
+were encountered. It scans the parsed pattern for them, calling
+set_lookbehind_lengths() for each one. At the start, the errorcode is zero and
+the error offset is marked unset. The enables the functions above not to
+override settings from deeper nestings.
+
+Arguments cb      points to the compile block
+Returns:          0 on success, or an errorcode (cb->erroroffset will be set)
+*/
+
+static int
+check_lookbehinds(compile_block *cb)
+{
+uint32_t *pptr;
+int errorcode = 0;
+int loopcount = 0;
+
+cb->erroroffset = PCRE2_UNSET;
+
+for (pptr = cb->parsed_pattern; *pptr != META_END; pptr++)
+  {
+  if (*pptr < META_END) continue;  /* Literal */
+
+  switch (META_CODE(*pptr))
+    {
+    default:
+    return ERR70;  /* Unrecognized meta code */
+
+    case META_ESCAPE:
+    if (*pptr - META_ESCAPE == ESC_P || *pptr - META_ESCAPE == ESC_p)
+      pptr += 1;
+    break;
+
+    case META_ACCEPT:
+    case META_ALT:
+    case META_ASTERISK:
+    case META_ASTERISK_PLUS:
+    case META_ASTERISK_QUERY:
+    case META_ATOMIC:
+    case META_BACKREF:
+    case META_CAPTURE:
+    case META_CIRCUMFLEX:
+    case META_CLASS:
+    case META_CLASS_EMPTY:
+    case META_CLASS_EMPTY_NOT:
+    case META_CLASS_END:
+    case META_CLASS_NOT:
+    case META_COMMIT:
+    case META_DOLLAR:
+    case META_DOT:
+    case META_FAIL:
+    case META_KET:
+    case META_LOOKAHEAD:
+    case META_LOOKAHEADNOT:
+    case META_NOCAPTURE:
+    case META_PLUS:
+    case META_PLUS_PLUS:
+    case META_PLUS_QUERY:
+    case META_PRUNE:
+    case META_QUERY:
+    case META_QUERY_PLUS:
+    case META_QUERY_QUERY:
+    case META_RANGE_ESCAPED:
+    case META_RANGE_LITERAL:
+    case META_SKIP:
+    case META_THEN:
+    break;
+
+    case META_COND_ASSERT:
+    case META_RECURSE:
+    pptr += SIZEOFFSET;
+    break;
+
+    case META_BACKREF_BYNAME:
+    case META_COND_DEFINE:
+    case META_COND_NAME:
+    case META_COND_NUMBER:
+    case META_COND_RNAME:
+    case META_COND_RNUMBER:
+    case META_RECURSE_BYNAME:
+    pptr += 1 + SIZEOFFSET;
+    break;
+
+    case META_CALLOUT_STRING:
+    pptr += 3 + SIZEOFFSET;
+    break;
+
+    case META_BIGVALUE:
+    case META_OPTIONS:
+    case META_POSIX:
+    case META_POSIX_NEG:
+    pptr += 1;
+    break;
+
+    case META_MINMAX:
+    case META_MINMAX_QUERY:
+    case META_MINMAX_PLUS:
+    pptr += 2;
+    break;
+
+    case META_CALLOUT_NUMBER:
+    case META_COND_VERSION:
+    pptr += 3;
+    break;
+
+    case META_MARK:
+    case META_PRUNE_ARG:
+    case META_SKIP_ARG:
+    case META_THEN_ARG:
+    pptr += 1 + pptr[1];
+    break;
+
+    case META_LOOKBEHIND:
+    case META_LOOKBEHINDNOT:
+    if (!set_lookbehind_lengths(&pptr, &errorcode, &loopcount, NULL, cb))
+      return errorcode;
+    break;
+    }
+  }
+
+return 0;
+}
+
+
+
+/*************************************************
 *     External function to compile a pattern     *
 *************************************************/


@@ -8334,6 +8793,7 @@
    int *errorptr, PCRE2_SIZE *erroroffset, pcre2_compile_context *ccontext)
 {
 BOOL utf;                               /* Set TRUE for UTF mode */
+BOOL has_lookbehind;                    /* Set TRUE if a lookbehind is found */
 pcre2_real_code *re = NULL;             /* What we will return */
 compile_block cb;                       /* "Static" compile-time data */
 const uint8_t *tables;                  /* Char tables base pointer */
@@ -8341,10 +8801,13 @@
 PCRE2_UCHAR *code;                      /* Current pointer in compiled code */
 PCRE2_SPTR codestart;                   /* Start of compiled code */
 PCRE2_SPTR ptr;                         /* Current pointer in pattern */
+uint32_t *pptr;                         /* Current pointer in parsed pattern */


-size_t length = 1;                      /* Allow or final END opcode */
-size_t usedlength;                      /* Actual length used */
-size_t re_blocksize;                    /* Size of memory block */
+PCRE2_SIZE length = 1;                  /* Allow for final END opcode */
+PCRE2_SIZE usedlength;                  /* Actual length used */
+PCRE2_SIZE re_blocksize;                /* Size of memory block */
+PCRE2_SIZE big32count = 0;              /* 32-bit literals >= 0x80000000 */
+PCRE2_SIZE parsed_size_needed;          /* Needed for parsed pattern */


 int32_t firstcuflags, reqcuflags;       /* Type of first/req code unit */
 uint32_t firstcu, reqcu;                /* Value of first/req code unit */
@@ -8358,18 +8821,19 @@
 int bsr = 0;                            /* Unset; can be set by the pattern */
 int errorcode = 0;                      /* Initialize to avoid compiler warn */


+uint32_t i;                             /* Local loop counter */
+
 /* Comments at the head of this file explain about these variables. */


-PCRE2_UCHAR *copied_pattern = NULL;
-PCRE2_UCHAR stack_copied_pattern[COPIED_PATTERN_SIZE];
+uint32_t stack_groupinfo[GROUPINFO_DEFAULT_SIZE];
+uint32_t stack_parsed_pattern[PARSED_PATTERN_DEFAULT_SIZE];
named_group named_groups[NAMED_GROUP_LIST_SIZE];

/* The workspace is used in different ways in the different compiling phases.
-It needs to be 16-bit aligned for the preliminary group scan, and 32-bit
-aligned for the group information cache. */
+It needs to be 16-bit aligned for the preliminary parsing scan. */

-uint32_t c32workspace[C32_WORK_SIZE];
-PCRE2_UCHAR *cworkspace = (PCRE2_UCHAR *)c32workspace;
+uint32_t c16workspace[C16_WORK_SIZE];
+PCRE2_UCHAR *cworkspace = (PCRE2_UCHAR *)c16workspace;


/* -------------- Check arguments and set up the pattern ----------------- */
@@ -8402,42 +8866,14 @@
ccontext = (pcre2_compile_context *)(&PRIV(default_compile_context));

/* A zero-terminated pattern is indicated by the special length value
-PCRE2_ZERO_TERMINATED. Otherwise, we make a copy of the pattern and add a zero,
-to ensure that it is always possible to look one code unit beyond the end of
-the pattern's characters. In both cases, check that the pattern is overlong. */
+PCRE2_ZERO_TERMINATED. Check for an overlong pattern. */

-if (patlen == PCRE2_ZERO_TERMINATED)
+if (patlen == PCRE2_ZERO_TERMINATED) patlen = PRIV(strlen)(pattern);
+if (patlen > ccontext->max_pattern_length)
   {
-  patlen = PRIV(strlen)(pattern);
-  if (patlen > ccontext->max_pattern_length)
-    {
-    *errorptr = ERR88;
-    return NULL;
-    }
+  *errorptr = ERR88;
+  return NULL;
   }
-else
-  {
-  if (patlen > ccontext->max_pattern_length)
-    {
-    *errorptr = ERR88;
-    return NULL;
-    }
-  if (patlen < COPIED_PATTERN_SIZE)
-    copied_pattern = stack_copied_pattern;
-  else
-    {
-    copied_pattern = ccontext->memctl.malloc(CU2BYTES(patlen + 1),
-      ccontext->memctl.memory_data);
-    if (copied_pattern == NULL)
-      {
-      *errorptr = ERR21;
-      return NULL;
-      }
-    }
-  memcpy(copied_pattern, pattern, CU2BYTES(patlen));
-  copied_pattern[patlen] = 0;
-  pattern = copied_pattern;
-  }


/* ------------ Initialize the "static" compile data -------------- */

@@ -8449,16 +8885,16 @@
cb.ctypes = tables + ctypes_offset;

cb.assert_depth = 0;
-cb.bracount = cb.final_bracount = 0;
+cb.bracount = 0;
cb.cx = ccontext;
cb.dupnames = FALSE;
cb.end_pattern = pattern + patlen;
-cb.nestptr[0] = cb.nestptr[1] = NULL;
+cb.erroroffset = 0;
cb.external_flags = 0;
cb.external_options = options;
-cb.groupinfo = c32workspace;
+cb.groupinfo = stack_groupinfo;
cb.had_recurse = FALSE;
-cb.iscondassert = FALSE;
+cb.lastcapture = 0;
cb.max_lookbehind = 0;
cb.name_entry_size = 0;
cb.name_table = NULL;
@@ -8467,6 +8903,7 @@
cb.names_found = 0;
cb.open_caps = NULL;
cb.parens_depth = 0;
+cb.parsed_pattern = stack_parsed_pattern;
cb.req_varyopt = 0;
cb.start_code = cworkspace;
cb.start_pattern = pattern;
@@ -8480,6 +8917,19 @@
cb.top_backref = 0;
cb.backref_map = 0;

+/* Escape sequences \1 to \9 are always back references, but as they are only
+two characters long, only two elements can be used in the parsed_pattern
+vector. The first contains the reference, and we'd like to use the second to
+record the offset in the pattern, so that forward references to non-existent
+groups can be diagnosed later with an offset. However, on 64-bit systems,
+PCRE2_SIZE won't fit. Instead, we have a vector of offsets for the first
+occurrence of \1 to \9, indexed by the second parsed_pattern value. All other
+references have enough space for the offset to be put into the parsed pattern.
+*/
+
+for (i = 0; i < 10; i++) cb.small_ref_offset[i] = PCRE2_UNSET;
+
+
/* --------------- Start looking at the pattern --------------- */

/* Check for global one-time option settings at the start of the pattern, and
@@ -8488,15 +8938,16 @@
ptr = pattern;
skipatstart = 0;

-while (ptr[skipatstart] == CHAR_LEFT_PARENTHESIS &&
+while (patlen - skipatstart >= 2 &&
+       ptr[skipatstart] == CHAR_LEFT_PARENTHESIS &&
        ptr[skipatstart+1] == CHAR_ASTERISK)
   {
-  unsigned int i;
   for (i = 0; i < sizeof(pso_list)/sizeof(pso); i++)
     {
     pso *p = pso_list + i;


-    if (PRIV(strncmp_c8)(ptr+skipatstart+2, (char *)(p->name), p->length) == 0)
+    if (patlen - skipatstart - 2 >= p->length &&
+        PRIV(strncmp_c8)(ptr+skipatstart+2, (char *)(p->name), p->length) == 0)
       {
       uint32_t c, pp;


@@ -8529,7 +8980,7 @@
           {
           errorcode = ERR60;
           ptr += pp;
-          goto HAD_ERROR;
+          goto HAD_EARLY_ERROR;
           }
         while (IS_DIGIT(ptr[pp]))
           {
@@ -8540,7 +8991,7 @@
           {
           errorcode = ERR60;
           ptr += pp;
-          goto HAD_ERROR;
+          goto HAD_EARLY_ERROR;
           }
         if (p->type == PSO_LIMM) limit_match = c;
           else limit_recursion = c;
@@ -8563,7 +9014,7 @@
 if ((cb.external_options & (PCRE2_UTF|PCRE2_UCP)) != 0)
   {
   errorcode = ERR32;
-  goto HAD_ERROR;
+  goto HAD_EARLY_ERROR;
   }
 #endif


@@ -8576,11 +9027,11 @@
   if ((options & PCRE2_NEVER_UTF) != 0)
     {
     errorcode = ERR74;
-    goto HAD_ERROR;
+    goto HAD_EARLY_ERROR;
     }
   if ((options & PCRE2_NO_UTF_CHECK) == 0 &&
        (errorcode = PRIV(valid_utf)(pattern, patlen, erroroffset)) != 0)
-    goto HAD_UTF_ERROR;
+    goto HAD_ERROR;  /* Offset was set by valid_utf() */
   }


 /* Check UCP lockout. */
@@ -8589,7 +9040,7 @@
     (PCRE2_UCP|PCRE2_NEVER_UCP))
   {
   errorcode = ERR75;
-  goto HAD_ERROR;
+  goto HAD_EARLY_ERROR;
   }


/* Process the BSR setting. */
@@ -8628,23 +9079,101 @@

default:
errorcode = ERR56;
- goto HAD_ERROR;
+ goto HAD_EARLY_ERROR;
}

-/* Before we do anything else, do a pre-scan of the pattern in order to
-discover the named groups and their numerical equivalents, so that this
-information is always available for the remaining processing. */
+/* Pre-scan the pattern to do two things: (1) Discover the named groups and
+their numerical equivalents, so that this information is always available for
+the remaining processing. (2) At the same time, parse the pattern and put a
+processed version into the parsed_pattern vector. This has escapes interpreted
+and comments removed (amongst other things).

-errorcode = scan_for_captures(&ptr, cb.external_options, &cb);
-if (errorcode != 0) goto HAD_ERROR;
+In all but one case, when PCRE2_AUTO_CALLOUT is not set, the number of unsigned
+32-bit ints in the parsed pattern is bounded by the length of the pattern plus
+one (for the terminator). The exceptional case is when running in 32-bit,
+non-UTF mode, when literal characters greater than META_END (0x80000000) have
+to be coded as two units. In this case, therefore, we scan the pattern to check
+for such values. */

-/* For obscure debugging this code can be enabled. */
+#if PCRE2_CODE_UNIT_WIDTH == 32
+if (!utf)
+ {
+ PCRE2_SPTR p;
+ for (p = ptr; p < cb.end_pattern; p++) if (*p >= META_END) big32count++;
+ }
+#endif

-#if 0
+/* Ensure that the parsed pattern buffer is big enough. When PCRE2_AUTO_CALLOUT
+is set we have to assume a numerical callout (4 elements) for each character
+plus one at the end. This is overkill, but memory is plentiful these days. For
+many smaller patterns the vector on the stack (which was set up above) can be
+used. */
+
+parsed_size_needed = patlen - skipatstart + big32count;
+if ((options & PCRE2_AUTO_CALLOUT) != 0)
+  parsed_size_needed = (parsed_size_needed + 1) * 4;
+
+if (parsed_size_needed >= PARSED_PATTERN_DEFAULT_SIZE)
   {
-  int i;
+  cb.parsed_pattern = ccontext->memctl.malloc(
+    (parsed_size_needed + 1) * sizeof(uint32_t),
+      ccontext->memctl.memory_data);
+  if (cb.parsed_pattern == NULL)
+    {
+    *errorptr = ERR21;
+    return NULL;
+    }
+  }
+
+/* Do the parsing scan. */
+
+errorcode = parse_regex(ptr, cb.external_options, &has_lookbehind, &cb);
+if (errorcode != 0) goto HAD_CB_ERROR;
+
+/* Workspace is needed to remember information about numbered groups: whether a
+group can match an empty string and what its fixed length is. This is done to
+avoid the possibility of recursive references causing very long compile times
+when checking these features. Unnumbered groups do not have this exposure since
+they cannot be referenced. We use an indexed vector for this purpose. If there
+are sufficiently few groups, the default vector on the stack, as set up above,
+can be used. Otherwise we have to get/free a special vector. The vector must be
+initialized to zero. */
+
+if (cb.bracount >= GROUPINFO_DEFAULT_SIZE)
+  {
+  cb.groupinfo = ccontext->memctl.malloc(
+    (cb.bracount + 1)*sizeof(uint32_t), ccontext->memctl.memory_data);
+  if (cb.groupinfo == NULL)
+    {
+    errorcode = ERR21;
+    cb.erroroffset = 0;
+    goto HAD_CB_ERROR;
+    }
+  }
+memset(cb.groupinfo, 0, (cb.bracount + 1) * sizeof(uint32_t));
+
+/* If there were any lookbehinds, scan the parsed pattern to figure out their
+lengths. */
+
+if (has_lookbehind)
+  {
+  errorcode = check_lookbehinds(&cb);
+  if (errorcode != 0) goto HAD_CB_ERROR;
+  }
+
+/* For debugging, there is a function that shows the parsed data vector. */
+
+#ifdef DEBUG_SHOW_PARSED
+fprintf(stderr, "+++ Pre-scan complete:\n");
+show_parsed(&cb);
+#endif
+
+/* For debugging capturing information this code can be enabled. */
+
+#ifdef DEBUG_SHOW_CAPTURES
+  {
   named_group *ng = cb.named_groups;
-  fprintf(stderr, "+++Captures: %d\n", cb.final_bracount);
+  fprintf(stderr, "+++Captures: %d\n", cb.bracount);
   for (i = 0; i < cb.names_found; i++, ng++)
     {
     fprintf(stderr, "+++%3d %.*s\n", ng->number, ng->length, ng->name);
@@ -8652,12 +9181,6 @@
   }
 #endif


-/* Reset current bracket count to zero and current pointer to the start of the
-pattern. */
-
-cb.bracount = 0;
-ptr = pattern + skipatstart;
-
/* Pretend to compile the pattern while actually just accumulating the amount
of memory required in the 'length' variable. This behaviour is triggered by
passing a non-NULL final argument to compile_regex(). We pass a block of
@@ -8666,24 +9189,24 @@
workspace will never overflow, though there is a test for its doing so.

On error, errorcode will be set non-zero, so we don't need to look at the
-result of the function. The initial options have been put into the cb block so
-that they can be changed if an option setting is found within the regex right
-at the beginning. Bringing initial option settings outside can help speed up
-starting point checks. We still have to pass a separate options variable (the
-first argument) because that may change as the pattern is processed. */
+result of the function. The initial options have been put into the cb block,
+but we still have to pass a separate options variable (the first argument)
+because the options may change as the pattern is processed. */

+cb.erroroffset = patlen; /* For any subsequent errors that do not set it */
+pptr = cb.parsed_pattern;
code = cworkspace;
*code = OP_BRA;

-(void)compile_regex(cb.external_options, &code, &ptr, &errorcode, FALSE,
- FALSE, 0, 0, &firstcu, &firstcuflags, &reqcu, &reqcuflags, NULL,
- &cb, &length);
+(void)compile_regex(cb.external_options, &code, &pptr, &errorcode, 0, &firstcu,
+ &firstcuflags, &reqcu, &reqcuflags, NULL, &cb, &length);

-if (errorcode != 0) goto HAD_ERROR;
+if (errorcode != 0) goto HAD_CB_ERROR; /* Offset is in cb.erroroffset */
+
if (length > MAX_PATTERN_SIZE)
{
errorcode = ERR20;
- goto HAD_ERROR;
+ goto HAD_CB_ERROR;
}

/* Compute the size of, and then get and initialize, the data block for storing
@@ -8698,7 +9221,7 @@
if (re == NULL)
{
errorcode = ERR21;
- goto HAD_ERROR;
+ goto HAD_CB_ERROR;
}

re->memctl = ccontext->memctl;
@@ -8729,44 +9252,19 @@
codestart = (PCRE2_SPTR)((uint8_t *)re + sizeof(pcre2_real_code)) +
re->name_entry_size * re->name_count;

-/* Workspace is needed to remember information about numbered groups: whether a
-group can match an empty string and what its fixed length is. This is done to
-avoid the possibility of recursive references causing very long compile times
-when checking these features. Unnumbered groups do not have this exposure since
-they cannot be referenced. We use an indexed vector for this purpose. If there
-are sufficiently few groups, it can be the c32workspace vector, as set up
-above. Otherwise we have to get/free a special vector. The vector must be
-initialized to zero. */
-
-if (cb.final_bracount >= C32_WORK_SIZE)
-  {
-  cb.groupinfo = ccontext->memctl.malloc(
-    (cb.final_bracount + 1)*sizeof(uint32_t), ccontext->memctl.memory_data);
-  if (cb.groupinfo == NULL)
-    {
-    errorcode = ERR21;
-    goto HAD_ERROR;
-    }
-  }
-memset(cb.groupinfo, 0, (cb.final_bracount + 1) * sizeof(uint32_t));
-
 /* Update the compile data block for the actual compile. The starting points of
 the name/number translation table and of the code are passed around in the
 compile data block. The start/end pattern and initial options are already set
-from the pre-compile phase, as is the name_entry_size field. Reset the bracket
-count and the names_found field. */
+from the pre-compile phase, as is the name_entry_size field. */


cb.parens_depth = 0;
cb.assert_depth = 0;
-cb.bracount = 0;
-cb.max_lookbehind = 0;
+cb.lastcapture = 0;
cb.name_table = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code));
cb.start_code = codestart;
-cb.iscondassert = FALSE;
cb.req_varyopt = 0;
cb.had_accept = FALSE;
cb.had_pruneorskip = FALSE;
-cb.check_lookbehind = FALSE;
cb.open_caps = NULL;

/* If any named groups were found, create the name/number table from the list
@@ -8774,11 +9272,9 @@

 if (cb.names_found > 0)
   {
-  int i = cb.names_found;
   named_group *ng = cb.named_groups;
-  cb.names_found = 0;
-  for (; i > 0; i--, ng++)
-    add_name_to_table(&cb, ng->name, ng->length, ng->number);
+  for (i = 0; i < cb.names_found; i++, ng++)
+    add_name_to_table(&cb, ng->name, ng->length, ng->number, i);
   }


/* Set up a starting, non-extracting bracket, then compile the expression. On
@@ -8785,11 +9281,11 @@
error, errorcode will be set non-zero, so we don't need to look at the result
of the function here. */

-ptr = pattern + skipatstart;
+pptr = cb.parsed_pattern;
code = (PCRE2_UCHAR *)codestart;
*code = OP_BRA;
-(void)compile_regex(re->overall_options, &code, &ptr, &errorcode, FALSE, FALSE,
- 0, 0, &firstcu, &firstcuflags, &reqcu, &reqcuflags, NULL, &cb, NULL);
+(void)compile_regex(re->overall_options, &code, &pptr, &errorcode, 0, &firstcu,
+ &firstcuflags, &reqcu, &reqcuflags, NULL, &cb, NULL);

re->top_bracket = cb.bracount;
re->top_backref = cb.top_backref;
@@ -8826,7 +9322,7 @@
{
PCRE2_UCHAR *rcode;
PCRE2_SPTR rgroup;
- int ccount = 0;
+ unsigned int ccount = 0;
int start = RSCAN_CACHE_SIZE;
recurse_cache rc[RSCAN_CACHE_SIZE];

@@ -8834,16 +9330,16 @@
        rcode != NULL;
        rcode = (PCRE2_UCHAR *)find_recurse(rcode + 1 + LINK_SIZE, utf))
     {
-    int i, p, recno;
+    int p, groupnumber;


-    recno = (int)GET(rcode, 1);
-    if (recno == 0) rgroup = codestart; else
+    groupnumber = (int)GET(rcode, 1);
+    if (groupnumber == 0) rgroup = codestart; else
       {
       PCRE2_SPTR search_from = codestart;
       rgroup = NULL;
       for (i = 0, p = start; i < ccount; i++, p = (p + 1) & 7)
         {
-        if (recno == rc[p].recno)
+        if (groupnumber == rc[p].groupnumber)
           {
           rgroup = rc[p].group;
           break;
@@ -8853,12 +9349,12 @@
         search time below when the new group number is greater than any of the
         previously found groups. */


-        if (recno > rc[p].recno) search_from = rc[p].group;
+        if (groupnumber > rc[p].groupnumber) search_from = rc[p].group;
         }


       if (rgroup == NULL)
         {
-        rgroup = PRIV(find_bracket)(search_from, utf, recno);
+        rgroup = PRIV(find_bracket)(search_from, utf, groupnumber);
         if (rgroup == NULL)
           {
           errorcode = ERR53;
@@ -8865,7 +9361,7 @@
           break;
           }
         if (--start < 0) start = RSCAN_CACHE_SIZE - 1;
-        rc[start].recno = recno;
+        rc[start].groupnumber = groupnumber;
         rc[start].group = rgroup;
         if (ccount < RSCAN_CACHE_SIZE) ccount++;
         }
@@ -8878,94 +9374,28 @@
 /* In rare debugging situations we sometimes need to look at the compiled code
 at this stage. */


-#ifdef CALL_PRINTINT
+#ifdef DEBUG_CALL_PRINTINT
pcre2_printint(re, stderr, TRUE);
fprintf(stderr, "Length=%lu Used=%lu\n", length, usedlength);
#endif

-/* After a successful compile, give an error if there's back reference to a
-non-existent capturing subpattern. Then, unless disabled, check whether any
-single character iterators can be auto-possessified. The function overwrites
-the appropriate opcode values, so the type of the pointer must be cast. NOTE:
-the intermediate variable "temp" is used in this code because at least one
-compiler gives a warning about loss of "const" attribute if the cast
-(PCRE2_UCHAR *)codestart is used directly in the function call. */
+/* Unless disabled, check whether any single character iterators can be
+auto-possessified. The function overwrites the appropriate opcode values, so
+the type of the pointer must be cast. NOTE: the intermediate variable "temp" is
+used in this code because at least one compiler gives a warning about loss of
+"const" attribute if the cast (PCRE2_UCHAR *)codestart is used directly in the
+function call. */

-if (errorcode == 0)
+if (errorcode == 0 && (re->overall_options & PCRE2_NO_AUTO_POSSESS) == 0)
   {
-  if (re->top_backref > re->top_bracket) errorcode = ERR15;
-  else if ((re->overall_options & PCRE2_NO_AUTO_POSSESS) == 0)
-    {
-    PCRE2_UCHAR *temp = (PCRE2_UCHAR *)codestart;
-    if (PRIV(auto_possessify)(temp, utf, &cb) != 0) errorcode = ERR80;
-    }
+  PCRE2_UCHAR *temp = (PCRE2_UCHAR *)codestart;
+  if (PRIV(auto_possessify)(temp, utf, &cb) != 0) errorcode = ERR80;
   }


-/* If there were any lookbehind assertions that contained OP_RECURSE
-(recursions or subroutine calls), a flag is set for them to be checked here,
-because they may contain forward references. Actual recursions cannot be fixed
-length, but subroutine calls can. It is done like this so that those without
-OP_RECURSE that are not fixed length get a diagnosic with a useful offset. The
-exceptional ones forgo this. We scan the pattern to check that they are fixed
-length, and set their lengths. */
+/* Failed to compile, or error while post-processing. */

-if (errorcode == 0 && cb.check_lookbehind)
- {
- PCRE2_UCHAR *cc = (PCRE2_UCHAR *)codestart;
+if (errorcode != 0) goto HAD_CB_ERROR;

-  /* Loop, searching for OP_REVERSE items, and process those that do not have
-  their length set. (Actually, it will also re-process any that have a length
-  of zero, but that is a pathological case, and it does no harm.) When we find
-  one, we temporarily terminate the branch it is in while we scan it. Note that
-  calling find_bracket() with a negative group number returns a pointer to the
-  OP_REVERSE item, not the actual lookbehind. */
-
-  for (cc = (PCRE2_UCHAR *)PRIV(find_bracket)(codestart, utf, -1);
-       cc != NULL;
-       cc = (PCRE2_UCHAR *)PRIV(find_bracket)(cc, utf, -1))
-    {
-    if (GET(cc, 1) == 0)
-      {
-      int fixed_length;
-      int count = 0;
-      PCRE2_UCHAR *be = cc - 1 - LINK_SIZE + GET(cc, -LINK_SIZE);
-      int end_op = *be;
-      *be = OP_END;
-      fixed_length = find_fixedlength(cc, utf, TRUE, &cb, NULL, &count);
-      *be = end_op;
-      if (fixed_length < 0)
-        {
-        errorcode = fixed_length_errors[-fixed_length];
-        break;
-        }
-      if (fixed_length > cb.max_lookbehind) cb.max_lookbehind = fixed_length;
-      PUT(cc, 1, fixed_length);
-      }
-    cc += 1 + LINK_SIZE;
-    }
-
-  /* The previous value of the maximum lookbehind was transferred to the
-  compiled regex block above. We could have updated this value in the loop
-  above, but keep the two values in step, just in case some later code below
-  uses the cb value. */
-
-  re->max_lookbehind = cb.max_lookbehind;
-  }
-
-/* Failed to compile, or error while post-processing. Earlier errors get here
-via the dreaded goto. */
-
-if (errorcode != 0)
-  {
-  HAD_ERROR:
-  *erroroffset = (int)(ptr - pattern);
-  HAD_UTF_ERROR:
-  *errorptr = errorcode;
-  pcre2_code_free(re);
-  re = NULL;
-  goto EXIT;
-  }
-
 /* Successful compile. If the anchored option was not passed, set it if
 we can determine that the pattern is anchored by virtue of ^ characters or \A
 or anything else, such as starting with non-atomic .* when DOTALL is set and
@@ -9061,7 +9491,7 @@
   if (rc < 0)
     {
     errorcode = ERR86;
-    goto HAD_ERROR;
+    goto HAD_CB_ERROR;
     }
   if (rc > 0)
     {
@@ -9080,23 +9510,40 @@
     PRIV(study)(re) != 0)
   {
   errorcode = ERR31;
-  goto HAD_ERROR;
+  goto HAD_CB_ERROR;
   }


-/* Control ends up here in all cases. If memory was obtained for a
-zero-terminated copy of the pattern, remember to free it before returning. Also
-free the list of named groups if a larger one had to be obtained, and likewise
-the group information vector. */
+/* Control ends up here in all cases. If memory was obtained for the parsed
+version of the pattern, free it before returning. Also free the list of named
+groups if a larger one had to be obtained, and likewise the group information
+vector. */

 EXIT:
-if (copied_pattern != stack_copied_pattern)
-  ccontext->memctl.free(copied_pattern, ccontext->memctl.memory_data);
+if (cb.parsed_pattern != stack_parsed_pattern)
+  ccontext->memctl.free(cb.parsed_pattern, ccontext->memctl.memory_data);
 if (cb.named_group_list_size > NAMED_GROUP_LIST_SIZE)
   ccontext->memctl.free((void *)cb.named_groups, ccontext->memctl.memory_data);
-if (cb.groupinfo != c32workspace)
+if (cb.groupinfo != stack_groupinfo)
   ccontext->memctl.free((void *)cb.groupinfo, ccontext->memctl.memory_data);
+return re;    /* Will be NULL after an error */


-return re;    /* Will be NULL after an error */
+/* Errors discovered in parse_regex() set the offset value in the compile
+block. Errors discovered before it is called must compute it from the ptr
+value. After parse_regex() is called, the offset in the compile block is set to
+the end of the pattern, but certain errors in compile_regex() may reset it if
+an offset is available in the parsed pattern. */
+
+HAD_CB_ERROR:
+ptr = pattern + cb.erroroffset;
+
+HAD_EARLY_ERROR:
+*erroroffset = ptr - pattern;
+
+HAD_ERROR:
+*errorptr = errorcode;
+pcre2_code_free(re);
+re = NULL;
+goto EXIT;
 }


/* End of pcre2_compile.c */

Modified: code/trunk/src/pcre2_error.c
===================================================================
--- code/trunk/src/pcre2_error.c    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/src/pcre2_error.c    2016-10-02 16:01:01 UTC (rev 555)
@@ -91,13 +91,13 @@
   "failed to allocate heap memory\0"
   "unmatched closing parenthesis\0"
   "internal error: code overflow\0"
-  "letter or underscore expected after (?< or (?'\0"
+  "missing closing parenthesis for condition\0"
   /* 25 */
   "lookbehind assertion is not fixed length\0"
-  "malformed number or name after (?(\0"
+  "a relative value of zero is not allowed\0"
   "conditional group contains more than two branches\0"
   "assertion expected after (?( or (?(?C)\0"
-  "(?R or (?[+-]digits must be followed by )\0"
+  "digit expected after (?+ or (?-\0"
   /* 30 */
   "unknown POSIX class name\0"
   "internal error in pcre2_study(): should not occur\0"
@@ -105,7 +105,7 @@
   "parentheses are too deeply nested (stack check)\0"
   "character code point value in \\x{} or \\o{} is too large\0"
   /* 35 */
-  "invalid condition (?(0)\0"
+  "lookbehind is too complicated\0"
   "\\C is not allowed in a lookbehind assertion in UTF-" XSTRING(PCRE2_CODE_UNIT_WIDTH) " mode\0"
   "PCRE does not support \\L, \\l, \\N{name}, \\U, or \\u\0"
   "number after (?C is greater than 255\0"
@@ -132,13 +132,13 @@
   "missing opening brace after \\o\0"
   "internal error: unknown newline setting\0"
   "\\g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number\0"
-  "a numbered reference must not be zero\0"
+  "(?R (recursive pattern call) must be followed by a closing parenthesis\0"
   "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)\0"
   /* 60 */
   "(*VERB) not recognized or malformed\0"
-  "number is too big\0"
+  "group number is too big\0"
   "subpattern name expected\0"
-  "digit expected after (?+\0"
+  "SPARE ERROR\0"
   "non-octal character in \\o{} (closing brace missing?)\0"
   /* 65 */
   "different names for subpatterns of the same number are not allowed\0"
@@ -151,9 +151,9 @@
 #endif
   "\\k is not followed by a braced, angle-bracketed, or quoted name\0"
   /* 70 */
-  "internal error: unknown opcode in find_fixedlength()\0"
+  "internal error: unknown meta code in check_lookbehinds()\0"
   "\\N is not supported in a class\0"
-  "SPARE ERROR\0"
+  "callout string is too long\0"
   "disallowed Unicode code point (>= 0xd800 && <= 0xdfff)\0"
   "using UTF is disabled by the application\0"
   /* 75 */
@@ -161,7 +161,7 @@
   "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)\0"
   "character code point value in \\u.... sequence is too large\0"
   "digits missing in \\x{} or \\o{}\0"
-  "syntax error in (?(VERSION condition\0"
+  "syntax error or number too big in (?(VERSION condition\0"
   /* 80 */
   "internal error: unknown opcode in auto_possessify()\0"
   "missing terminating delimiter for callout with string argument\0"
@@ -173,6 +173,8 @@
   "regular expression is too complicated\0"
   "lookbehind assertion is too long\0"
   "pattern string is longer than the limit set by the application\0"
+  "internal error: unknown code in parsed pattern\0" 
+  /* 90 */
   ;


/* Match-time and UTF error texts are in the same format. */

Modified: code/trunk/src/pcre2_internal.h
===================================================================
--- code/trunk/src/pcre2_internal.h    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/src/pcre2_internal.h    2016-10-02 16:01:01 UTC (rev 555)
@@ -1298,23 +1298,16 @@
 compatibility mode, and for \C in non-utf mode. In non-DOTALL mode, "." behaves
 like \N.


-The special values ESC_DU, ESC_du, etc. are used instead of ESC_D, ESC_d, etc.
-when PCRE2_UCP is set and replacement of \d etc by \p sequences is required.
-They must be contiguous, and remain in order so that the replacements can be
-looked up from a table.
-
Negative numbers are used to encode a backreference (\1, \2, \3, etc.) in
-check_escape(). There are two tests in the code for an escape
-greater than ESC_b and less than ESC_Z to detect the types that may be
-repeated. These are the types that consume characters. If any new escapes are
-put in between that don't consume a character, that code will have to change.
-*/
+check_escape(). There are tests in the code for an escape greater than ESC_b
+and less than ESC_Z to detect the types that may be repeated. These are the
+types that consume characters. If any new escapes are put in between that don't
+consume a character, that code will have to change. */

 enum { ESC_A = 1, ESC_G, ESC_K, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s,
        ESC_W, ESC_w, ESC_N, ESC_dum, ESC_C, ESC_P, ESC_p, ESC_R, ESC_H,
        ESC_h, ESC_V, ESC_v, ESC_X, ESC_Z, ESC_z,
-       ESC_E, ESC_Q, ESC_g, ESC_k,
-       ESC_DU, ESC_du, ESC_SU, ESC_su, ESC_WU, ESC_wu };
+       ESC_E, ESC_Q, ESC_g, ESC_k };



 /********************** Opcode definitions ******************/
@@ -1380,7 +1373,8 @@
   OP_CIRC,           /* 27 Start of line - not multiline */
   OP_CIRCM,          /* 28 Start of line - multiline */


- /* Single characters; caseful must precede the caseless ones */
+ /* Single characters; caseful must precede the caseless ones, and these
+ must remain in this order, and adjacent. */

   OP_CHAR,           /* 29 Match one character, casefully */
   OP_CHARI,          /* 30 Match one character, caselessly */


Modified: code/trunk/src/pcre2_intmodedep.h
===================================================================
--- code/trunk/src/pcre2_intmodedep.h    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/src/pcre2_intmodedep.h    2016-10-02 16:01:01 UTC (rev 555)
@@ -648,7 +648,8 @@


#ifndef PCRE2_PCRE2TEST

-/* Structure for checking for mutual recursion when scanning compiled code. */
+/* Structures for checking for mutual recursion when scanning compiled or
+parsed code. */

typedef struct recurse_check {
struct recurse_check *prev;
@@ -655,11 +656,16 @@
PCRE2_SPTR group;
} recurse_check;

+typedef struct parsed_recurse_check {
+ struct parsed_recurse_check *prev;
+ uint32_t *groupptr;
+} parsed_recurse_check;
+
/* Structure for building a cache when filling in recursion offsets. */

typedef struct recurse_cache {
PCRE2_SPTR group;
- int recno;
+ int groupnumber;
} recurse_cache;

 /* Structure for maintaining a chain of pointers to the currently incomplete
@@ -693,9 +699,10 @@
   PCRE2_SPTR start_code;           /* The start of the compiled code */
   PCRE2_SPTR start_pattern;        /* The start of the pattern */
   PCRE2_SPTR end_pattern;          /* The end of the pattern */
-  PCRE2_SPTR nestptr[2];           /* Pointer(s) saved for string substitution */
   PCRE2_UCHAR *name_table;         /* The name/number table */
-  size_t workspace_size;           /* Size of workspace */
+  PCRE2_SIZE workspace_size;       /* Size of workspace */
+  PCRE2_SIZE small_ref_offset[10]; /* Offsets for \1 to \9 */
+  PCRE2_SIZE erroroffset;          /* Offset of error in pattern */ 
   uint16_t names_found;            /* Number of entries so far */
   uint16_t name_entry_size;        /* Size of each entry */
   open_capitem *open_caps;         /* Chain of open capture items */
@@ -703,8 +710,9 @@
   uint32_t named_group_list_size;  /* Number of entries in the list */
   uint32_t external_options;       /* External (initial) options */
   uint32_t external_flags;         /* External flag bits to be set */
-  uint32_t bracount;               /* Count of capturing parens as we compile */
-  uint32_t final_bracount;         /* Saved value after first pass */
+  uint32_t bracount;               /* Count of capturing parentheses */
+  uint32_t lastcapture;            /* Last capture encountered */ 
+  uint32_t *parsed_pattern;        /* Parsed pattern buffer */ 
   uint32_t *groupinfo;             /* Group info vector */
   uint32_t top_backref;            /* Maximum back reference */
   uint32_t backref_map;            /* Bitmap of low back refs */
@@ -718,9 +726,7 @@
   BOOL had_accept;                 /* (*ACCEPT) encountered */
   BOOL had_pruneorskip;            /* (*PRUNE) or (*SKIP) encountered */
   BOOL had_recurse;                /* Had a recursion or subroutine call */
-  BOOL check_lookbehind;           /* Lookbehinds need later checking */
   BOOL dupnames;                   /* Duplicate names exist */
-  BOOL iscondassert;               /* Next assert is a condition */
 } compile_block;


/* Structure for keeping the properties of the in-memory stack used

Modified: code/trunk/src/pcre2_substitute.c
===================================================================
--- code/trunk/src/pcre2_substitute.c    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/src/pcre2_substitute.c    2016-10-02 16:01:01 UTC (rev 555)
@@ -114,7 +114,7 @@
   else if (*ptr == CHAR_BACKSLASH)
     {
     int erc;
-    int errorcode = 0;
+    int errorcode;
     uint32_t ch;


     if (ptr < ptrend - 1) switch (ptr[1])
@@ -127,8 +127,10 @@
       continue;
       }


+    ptr += 1;  /* Must point after \ */
     erc = PRIV(check_escape)(&ptr, ptrend, &ch, &errorcode,
       code->overall_options, FALSE, NULL);
+    ptr -= 1;  /* Back to last code unit of escape */ 
     if (errorcode != 0)
       {
       rc = errorcode;
@@ -698,7 +700,7 @@
     else if ((suboptions & PCRE2_SUBSTITUTE_EXTENDED) != 0 &&
               *ptr == CHAR_BACKSLASH)
       {
-      int errorcode = 0;
+      int errorcode;


       if (ptr < repend - 1) switch (ptr[1])
         {
@@ -728,10 +730,10 @@
         break;
         }


+      ptr++;  /* Point after \ */
       rc = PRIV(check_escape)(&ptr, repend, &ch, &errorcode,
         code->overall_options, FALSE, NULL);
       if (errorcode != 0) goto BADESCAPE;
-      ptr++;


       switch(rc)
         {


Modified: code/trunk/src/pcre2test.c
===================================================================
--- code/trunk/src/pcre2test.c    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/src/pcre2test.c    2016-10-02 16:01:01 UTC (rev 555)
@@ -2808,7 +2808,7 @@


/* In UTF mode the input is always interpreted as a string of UTF-8 bytes using
the original UTF-8 definition of RFC 2279, which allows for up to 6 bytes, and
-code values from 0 to 0x7fffffff. However, values greater than the later UTF
+code values from 0 to 0x7fffffff. However, values greater than the later UTF
limit of 0x10ffff cause an error.

In non-UTF mode the input is interpreted as UTF-8 if the utf8_input modifier
@@ -2867,7 +2867,7 @@

 else while (len > 0)
   {
-  int chlen; 
+  int chlen;
   uint32_t c;
   uint32_t topbit = 0;
   if (!utf && *p == 0xff && len > 1)
@@ -2875,7 +2875,7 @@
     topbit = 0x80000000u;
     p++;
     len--;
-    }     
+    }
   chlen = utf82ord(p, &c);
   if (chlen <= 0) return -1;
   if (utf && c > 0x10ffff) return -2;
@@ -4494,6 +4494,7 @@
 int errorcode;
 void *use_pat_context;
 PCRE2_SIZE patlen;
+PCRE2_SIZE valgrind_access_length;
 PCRE2_SIZE erroroffset;


/* Initialize the context and pattern/data controls for this test from the
@@ -4537,7 +4538,7 @@
if (!decode_modifiers(p, CTX_PAT, &pat_patctl, NULL)) return PR_SKIP;
utf = (pat_patctl.options & PCRE2_UTF) != 0;

-/* The utf8_input modifier is not allowed in 8-bit mode, and is mutually
+/* The utf8_input modifier is not allowed in 8-bit mode, and is mutually
exclusive with the utf modifier. */

 if ((pat_patctl.control & CTL_UTF8_INPUT) != 0)
@@ -4550,8 +4551,8 @@
   if (utf)
     {
     fprintf(outfile, "** The utf and utf8_input modifiers are mutually exclusive\n");
-    return PR_SKIP; 
-    }   
+    return PR_SKIP;
+    }
   }


/* Check for mutually exclusive modifiers. At present, these are all in the
@@ -4949,12 +4950,44 @@
break;
}

-/* The pattern is now in pbuffer[8|16|32], with the length in patlen. By
-default, however, we pass a zero-terminated pattern. The length is passed only
-if we had a hex pattern. */
+/* The pattern is now in pbuffer[8|16|32], with the length in code units in
+patlen. By default, however, we pass a zero-terminated pattern. The length is
+passed only if we had a hex pattern. When valgrind is supported, arrange for
+the unused part of the buffer to be marked as no access. */

-if ((pat_patctl.control & CTL_HEXPAT) == 0) patlen = PCRE2_ZERO_TERMINATED;
+valgrind_access_length = patlen;
+if ((pat_patctl.control & CTL_HEXPAT) == 0)
+ {
+ patlen = PCRE2_ZERO_TERMINATED;
+ valgrind_access_length += 1; /* For the terminating zero */
+ }

+#ifdef SUPPORT_VALGRIND
+#ifdef SUPPORT_PCRE2_8
+if (test_mode == PCRE8_MODE && pbuffer8 != NULL)
+  {
+  VALGRIND_MAKE_MEM_NOACCESS(pbuffer8 + valgrind_access_length,
+    pbuffer8_size - valgrind_access_length);
+  }
+#endif
+#ifdef SUPPORT_PCRE2_16
+if (test_mode == PCRE16_MODE && pbuffer16 != NULL)
+  {
+  VALGRIND_MAKE_MEM_NOACCESS(pbuffer16 + valgrind_access_length,
+    pbuffer16_size - valgrind_access_length*sizeof(uint16_t));
+  }
+#endif
+#ifdef SUPPORT_PCRE2_32
+if (test_mode == PCRE32_MODE && pbuffer32 != NULL)
+  {
+  VALGRIND_MAKE_MEM_NOACCESS(pbuffer32 + valgrind_access_length,
+    pbuffer32_size - valgrind_access_length*sizeof(uint32_t));
+  }
+#endif
+#else  /* Valgrind not supported */
+(void)valgrind_access_length;  /* Avoid compiler warning */
+#endif
+
 /* If #newline_default has been used and the library was not compiled with an
 appropriate default newline setting, local_newline_default will be non-zero. We
 use this if there is no explicit newline modifier. */
@@ -4996,6 +5029,65 @@
 PCRE2_COMPILE(compiled_code, pbuffer, patlen, pat_patctl.options|forbid_utf,
   &errorcode, &erroroffset, use_pat_context);


+/* Call the JIT compiler if requested. When timing, we must free and recompile
+the pattern each time because that is the only way to free the JIT compiled
+code. We know that compilation will always succeed. */
+
+if (TEST(compiled_code, !=, NULL) && pat_patctl.jit != 0)
+  {
+  if (timeit > 0)
+    {
+    register int i;
+    clock_t time_taken = 0;
+    for (i = 0; i < timeit; i++)
+      {
+      clock_t start_time;
+      SUB1(pcre2_code_free, compiled_code);
+      PCRE2_COMPILE(compiled_code, pbuffer, patlen,
+        pat_patctl.options|forbid_utf, &errorcode, &erroroffset,
+        use_pat_context);
+      start_time = clock();
+      PCRE2_JIT_COMPILE(jitrc,compiled_code, pat_patctl.jit);
+      time_taken += clock() - start_time;
+      }
+    total_jit_compile_time += time_taken;
+    fprintf(outfile, "JIT compile  %.4f milliseconds\n",
+      (((double)time_taken * 1000.0) / (double)timeit) /
+        (double)CLOCKS_PER_SEC);
+    }
+  else
+    {
+    PCRE2_JIT_COMPILE(jitrc, compiled_code, pat_patctl.jit);
+    }
+  }
+
+/* If valgrind is supported, mark the pbuffer as accessible again. The 16-bit
+and 32-bit buffers can be marked completely undefined, but we must leave the
+pattern in the 8-bit buffer defined because it may be read from a callout
+during matching. */
+
+#ifdef SUPPORT_VALGRIND
+#ifdef SUPPORT_PCRE2_8
+if (test_mode == PCRE8_MODE)
+  {
+  VALGRIND_MAKE_MEM_UNDEFINED(pbuffer8 + valgrind_access_length, 
+    pbuffer8_size - valgrind_access_length);
+  }
+#endif
+#ifdef SUPPORT_PCRE2_16
+if (test_mode == PCRE16_MODE)
+  {
+  VALGRIND_MAKE_MEM_UNDEFINED(pbuffer16, pbuffer16_size);
+  }
+#endif
+#ifdef SUPPORT_PCRE2_32
+if (test_mode == PCRE32_MODE)
+  {
+  VALGRIND_MAKE_MEM_UNDEFINED(pbuffer32, pbuffer32_size);
+  }
+#endif
+#endif
+
 /* Compilation failed; go back for another re, skipping to blank line
 if non-interactive. */


@@ -5029,38 +5121,6 @@
if (pattern_info(PCRE2_INFO_MAXLOOKBEHIND, &maxlookbehind, FALSE) != 0)
return PR_ABEND;

-/* Call the JIT compiler if requested. When timing, we must free and recompile
-the pattern each time because that is the only way to free the JIT compiled
-code. We know that compilation will always succeed. */
-
-if (pat_patctl.jit != 0)
-  {
-  if (timeit > 0)
-    {
-    register int i;
-    clock_t time_taken = 0;
-    for (i = 0; i < timeit; i++)
-      {
-      clock_t start_time;
-      SUB1(pcre2_code_free, compiled_code);
-      PCRE2_COMPILE(compiled_code, pbuffer, patlen,
-        pat_patctl.options|forbid_utf, &errorcode, &erroroffset,
-        use_pat_context);
-      start_time = clock();
-      PCRE2_JIT_COMPILE(jitrc,compiled_code, pat_patctl.jit);
-      time_taken += clock() - start_time;
-      }
-    total_jit_compile_time += time_taken;
-    fprintf(outfile, "JIT compile  %.4f milliseconds\n",
-      (((double)time_taken * 1000.0) / (double)timeit) /
-        (double)CLOCKS_PER_SEC);
-    }
-  else
-    {
-    PCRE2_JIT_COMPILE(jitrc, compiled_code, pat_patctl.jit);
-    }
-  }
-
 /* If an explicit newline modifier was given, set the information flag in the
 pattern so that it is preserved over push/pop. */


@@ -5300,10 +5360,10 @@
for (i = 0; i < subject_length - pre_start - post_start + 4; i++)
fprintf(outfile, " ");

-fprintf(outfile, "%.*s",
-  (int)((cb->next_item_length == 0)? 1 : cb->next_item_length),
-  pbuffer8 + cb->pattern_position);
-
+if (cb->next_item_length != 0)  
+  fprintf(outfile, "%.*s", (int)(cb->next_item_length),
+    pbuffer8 + cb->pattern_position);
+    
 fprintf(outfile, "\n");
 first_callout = FALSE;


@@ -5740,18 +5800,18 @@
     continue;
     }


- /* Handle a non-escaped character. In non-UTF 32-bit mode with utf8_input
+ /* Handle a non-escaped character. In non-UTF 32-bit mode with utf8_input
set, do the fudge for setting the top bit. */

   if (c != '\\')
     {
     uint32_t topbit = 0;
-    if (test_mode == PCRE32_MODE && c == 0xff && *p != 0) 
+    if (test_mode == PCRE32_MODE && c == 0xff && *p != 0)
       {
       topbit = 0x80000000;
       c = *p++;
-      }  
-    if ((utf || (pat_patctl.control & CTL_UTF8_INPUT) != 0) && 
+      }
+    if ((utf || (pat_patctl.control & CTL_UTF8_INPUT) != 0) &&
       HASUTF8EXTRALEN(c)) { GETUTF8INC(c, p); }
     c |= topbit;
     }
@@ -6405,7 +6465,7 @@
     }


/* Otherwise just run a single match, setting up a callout if required (the
- default). */
+ default). There is a copy of the pattern in pbuffer8 for use by callouts. */

   else
     {
@@ -7583,6 +7643,10 @@
     }
   }


+#if defined(SUPPORT_LIBREADLINE) || defined(SUPPORT_LIBEDIT)
+if (INTERACTIVE(infile)) using_history();
+#endif
+
if (argc > 2)
{
outfile = fopen(argv[op+1], OUTPUT_MODE);
@@ -7621,8 +7685,7 @@
p = buffer;

/* If we have a pattern set up for testing, or we are skipping after a
- compile failure, a blank line terminates this test; otherwise process the
- line as a data line. */
+ compile failure, a blank line terminates this test. */

   if (expectdata || skipping)
     {
@@ -7645,14 +7708,21 @@
       skipping = FALSE;
       setlocale(LC_CTYPE, "C");
       }
+      
+    /* Otherwise, if we are not skipping, and the line is not a data comment 
+    line starting with "\=", process a data line. */
+     
     else if (!skipping && !(p[0] == '\\' && p[1] == '=' && isspace(p[2])))
+      { 
       rc = process_data();
+      } 
     }


/* We do not have a pattern set up for testing. Lines starting with # are
either comments or special commands. Blank lines are ignored. Otherwise, the
line must start with a valid delimiter. It is then processed as a pattern
- line. */
+ line. A copy of the pattern is left in pbuffer8 for use by callouts. Under
+ valgrind, make the unused part of the buffer undefined, to catch overruns. */

   else if (*p == '#')
     {
@@ -7713,6 +7783,10 @@


EXIT:

+#if defined(SUPPORT_LIBREADLINE) || defined(SUPPORT_LIBEDIT)
+if (infile != NULL && INTERACTIVE(infile)) clear_history();
+#endif
+
if (infile != NULL && infile != stdin) fclose(infile);
if (outfile != NULL && outfile != stdout) fclose(outfile);


Modified: code/trunk/testdata/testinput1
===================================================================
--- code/trunk/testdata/testinput1    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testinput1    2016-10-02 16:01:01 UTC (rev 555)
@@ -5792,4 +5792,18 @@
     aaaccccaaa
     bccccb 


+# /x does not apply to MARK labels 
+
+/x (*MARK:ab cd # comment
+ef) x/x,mark
+    axxz
+
+/(?<=a(B){0}c)X/
+    acX
+
+/(?<DEFINE>b)(?(DEFINE)(a+))(?&DEFINE)/          
+    bbbb 
+\= Expect no match     
+    baaab
+
 # End of testinput1 


Modified: code/trunk/testdata/testinput15
===================================================================
--- code/trunk/testdata/testinput15    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testinput15    2016-10-02 16:01:01 UTC (rev 555)
@@ -79,7 +79,7 @@
 /((?2))((?1))/
     abc


-/((?(R2)a+|(?1)b))/
+/((?(R2)a+|(?1)b))()/
     aaaabcde


/(?(R)a*(?1)|((?R))b)/

Modified: code/trunk/testdata/testinput17
===================================================================
--- code/trunk/testdata/testinput17    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testinput17    2016-10-02 16:01:01 UTC (rev 555)
@@ -177,7 +177,7 @@
 /((?2))((?1))/
     abc


-/((?(R2)a+|(?1)b))/
+/((?(R2)a+|(?1)b))()/
     aaaabcde


/(?(R)a*(?1)|((?R))b)/

Modified: code/trunk/testdata/testinput2
===================================================================
--- code/trunk/testdata/testinput2    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testinput2    2016-10-02 16:01:01 UTC (rev 555)
@@ -189,9 +189,9 @@
     the barfoo
     and cattlefoo


-/(?<=a+)b/
+/abc(?<=a+)b/

-/(?<=aaa|b{0,3})b/
+/12345(?<=aaa|b{0,3})b/

/(?<!(foo)a\1)bar/

@@ -4518,6 +4518,18 @@
      \ B)x/x,alt_verbnames,mark
     x  


+/(*: A \ and #comment
+     \ B)x/alt_verbnames,mark
+    x  
+    
+/(*: A \ and #comment
+     \ B)x/x,mark
+    x  
+    
+/(*: A \ and #comment
+     \ B)x/mark
+    x  
+    
 /(*:A
 B)x/alt_verbnames,mark 
     x
@@ -4819,4 +4831,61 @@


/\[AB]{6000000000000000000000}/expand

+# Hex uses pattern length, not zero-terminated. This tests for overrunning
+# the given length of a pattern.
+
+/'(*U'/hex
+
+/'(*'/hex
+
+/'('/hex
+
+//hex
+
+# These tests are here because Perl never allows a back reference in a
+# lookbehind. PCRE2 supports some limited cases.
+
+/([ab])...(?<=\1)z/
+    a11az
+    b11bz 
+\= Expect no match
+    b11az 
+    
+/(?|([ab]))...(?<=\1)z/
+
+/([ab])(\1)...(?<=\2)z/
+    aa11az
+    
+/(a\2)(b\1)(?<=\2)/ 
+ 
+/(?<A>[ab])...(?<=\k'A')z/
+    a11az
+    b11bz 
+\= Expect no match
+    b11az 
+
+/(?<A>[ab])...(?<=\k'A')(?<A>)z/dupnames
+
+# Perl does not support \g+n
+
+/((\g+1X)?([ab]))+/
+    aaXbbXa
+
+/ab(?C1)c/auto_callout
+    abc
+
+/'ab(?C1)c'/hex,auto_callout
+    abc
+    
+# Perl accepts these, but gives a warning. We can't warn, so give an error. 
+
+/[a-[:digit:]]+/
+    a-a9-a
+
+/[A-[:digit:]]+/
+    A-A9-A
+
+/[a-\d]+/
+    a-a9-a
+
 # End of testinput2 


Modified: code/trunk/testdata/testinput5
===================================================================
--- code/trunk/testdata/testinput5    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testinput5    2016-10-02 16:01:01 UTC (rev 555)
@@ -1725,5 +1725,14 @@
     \x{1d7cf}
 \= Expect no match
     \x{10000}
+    
+# Hex uses pattern length, not zero-terminated. This tests for overrunning
+# the given length of a pattern.


+/'(*UTF)'/hex
+
+/a(?<=A\XB)/utf
+
+/ab(?<=A\RB)/utf
+
# End of testinput5

Modified: code/trunk/testdata/testinput6
===================================================================
--- code/trunk/testdata/testinput6    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testinput6    2016-10-02 16:01:01 UTC (rev 555)
@@ -4635,7 +4635,7 @@
 /((?(R)a+|(?1)b))/
     aaaabcde


-/((?(R2)a+|(?1)b))/
+/((?(R2)a+|(?1)b))()/
     aaaabcde


/(?(R)a*(?1)|((?R))b)/

Modified: code/trunk/testdata/testinput8
===================================================================
--- code/trunk/testdata/testinput8    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testinput8    2016-10-02 16:01:01 UTC (rev 555)
@@ -161,19 +161,15 @@


# Use "expand" to create some very long patterns with nested parentheses, in
# order to test workspace overflow. Again, this varies with code unit width,
-# and even with it fails in two modes, the error offset differs. It also varies
+# and even when it fails in two modes, the error offset differs. It also varies
# with link size - hence multiple tests with different values.

-/(?'ABC'\[[bar](]{105}*THEN:\[A]{255}\[)]{106}/expand,-fullbincode
+/(?'ABC'\[[bar](]{792}*THEN:\[A]{255}\[)]{793}/expand,-fullbincode,parens_nest_limit=1000

-/(?'ABC'\[[bar](]{106}*THEN:\[A]{255}\[)]{107}/expand,-fullbincode
+/(?'ABC'\[[bar](]{793}*THEN:\[A]{255}\[)]{794}/expand,-fullbincode,parens_nest_limit=1000

-/(?'ABC'\[[bar](]{159}*THEN:\[A]{255}\[)]{160}/expand,-fullbincode
+/(?'ABC'\[[bar](]{1793}*THEN:\[A]{255}\[)]{1794}/expand,-fullbincode,parens_nest_limit=2000

-/(?'ABC'\[[bar](]{199}*THEN:\[A]{255}\[)]{200}/expand,-fullbincode
-
-/(?'ABC'\[[bar](]{299}*THEN:\[A]{255}\[)]{300}/expand,-fullbincode
-
 /(?(1)(?1)){8,}+()/debug
     abcd



Modified: code/trunk/testdata/testoutput1
===================================================================
--- code/trunk/testdata/testoutput1    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testoutput1    2016-10-02 16:01:01 UTC (rev 555)
@@ -9257,4 +9257,24 @@
  1: b
  2: cccc


+# /x does not apply to MARK labels 
+
+/x (*MARK:ab cd # comment
+ef) x/x,mark
+    axxz
+ 0: xx
+MK: ab cd # comment\x0aef
+
+/(?<=a(B){0}c)X/
+    acX
+ 0: X
+
+/(?<DEFINE>b)(?(DEFINE)(a+))(?&DEFINE)/          
+    bbbb 
+ 0: bb
+ 1: b
+\= Expect no match     
+    baaab
+No match
+
 # End of testinput1 


Modified: code/trunk/testdata/testoutput12-16
===================================================================
--- code/trunk/testdata/testoutput12-16    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testoutput12-16    2016-10-02 16:01:01 UTC (rev 555)
@@ -557,7 +557,7 @@
  0: \x{11234}


/(*UTF-32)\x{11234}/
-Failed: error 134 at offset 17: character code point value in \x{} or \o{} is too large
+Failed: error 160 at offset 5: (*VERB) not recognized or malformed
abcd\x{11234}pqr

/(*UTF-32)\x{112}/

Modified: code/trunk/testdata/testoutput15
===================================================================
--- code/trunk/testdata/testoutput15    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testoutput15    2016-10-02 16:01:01 UTC (rev 555)
@@ -188,7 +188,7 @@
     abc
 Failed: error -52: nested recursion at the same subject position


-/((?(R2)a+|(?1)b))/
+/((?(R2)a+|(?1)b))()/
     aaaabcde
 Failed: error -52: nested recursion at the same subject position



Modified: code/trunk/testdata/testoutput17
===================================================================
--- code/trunk/testdata/testoutput17    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testoutput17    2016-10-02 16:01:01 UTC (rev 555)
@@ -335,7 +335,7 @@
     abc
 Failed: error -46: JIT stack limit reached


-/((?(R2)a+|(?1)b))/
+/((?(R2)a+|(?1)b))()/
     aaaabcde
 Failed: error -46: JIT stack limit reached



Modified: code/trunk/testdata/testoutput18
===================================================================
--- code/trunk/testdata/testoutput18    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testoutput18    2016-10-02 16:01:01 UTC (rev 555)
@@ -139,7 +139,7 @@
  0+ issippi


 /abc/\
-Failed: POSIX code 9: bad escape sequence at offset 3     
+Failed: POSIX code 9: bad escape sequence at offset 4     


 "(?(?C)"
 Failed: POSIX code 11: unbalanced () at offset 6     


Modified: code/trunk/testdata/testoutput2
===================================================================
--- code/trunk/testdata/testoutput2    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testoutput2    2016-10-02 16:01:01 UTC (rev 555)
@@ -472,14 +472,13 @@
     and cattlefoo
 No match


-/(?<=a+)b/
-Failed: error 125 at offset 6: lookbehind assertion is not fixed length
+/abc(?<=a+)b/
+Failed: error 125 at offset 3: lookbehind assertion is not fixed length

-/(?<=aaa|b{0,3})b/
-Failed: error 125 at offset 14: lookbehind assertion is not fixed length
+/12345(?<=aaa|b{0,3})b/
+Failed: error 125 at offset 5: lookbehind assertion is not fixed length

/(?<!(foo)a\1)bar/
-Failed: error 125 at offset 12: lookbehind assertion is not fixed length

/(?i)abc/I
Capturing subpattern count = 0
@@ -539,25 +538,25 @@
Subject length lower bound = 1

/(a)(?(1)a|b|c)/
-Failed: error 127 at offset 13: conditional group contains more than two branches
+Failed: error 127 at offset 3: conditional group contains more than two branches

/(?(?=a)a|b|c)/
-Failed: error 127 at offset 12: conditional group contains more than two branches
+Failed: error 127 at offset 0: conditional group contains more than two branches

/(?(1a)/
-Failed: error 114 at offset 6: missing closing parenthesis
+Failed: error 124 at offset 4: missing closing parenthesis for condition

/(?(1a))/
-Failed: error 126 at offset 4: malformed number or name after (?(
+Failed: error 124 at offset 4: missing closing parenthesis for condition

/(?(?i))/
-Failed: error 128 at offset 3: assertion expected after (?( or (?(?C)
+Failed: error 128 at offset 2: assertion expected after (?( or (?(?C)

/(?(abc))/
-Failed: error 115 at offset 7: reference to non-existent subpattern
+Failed: error 115 at offset 3: reference to non-existent subpattern

/(?(?<ab))/
-Failed: error 128 at offset 3: assertion expected after (?( or (?(?C)
+Failed: error 142 at offset 7: syntax error in subpattern name (missing terminator)

/((?s)blah)\s+\1/I
Capturing subpattern count = 1
@@ -715,13 +714,13 @@
No match

/(?<=ab(c+)d)ef/
-Failed: error 125 at offset 11: lookbehind assertion is not fixed length
+Failed: error 125 at offset 0: lookbehind assertion is not fixed length

/(?<=ab(?<=c+)d)ef/
-Failed: error 125 at offset 12: lookbehind assertion is not fixed length
+Failed: error 125 at offset 6: lookbehind assertion is not fixed length

/(?<=ab(c|de)f)g/
-Failed: error 125 at offset 13: lookbehind assertion is not fixed length
+Failed: error 125 at offset 0: lookbehind assertion is not fixed length

/The next three are in testinput2 because they have variable length branches/

@@ -905,7 +904,7 @@
Failed: error 114 at offset 4: missing closing parenthesis

/(?<%)b/
-Failed: error 124 at offset 3: letter or underscore expected after (?< or (?'
+Failed: error 162 at offset 3: subpattern name expected

/a(?{)b/
Failed: error 111 at offset 3: unrecognized character after (? or (?-
@@ -923,22 +922,22 @@
Failed: error 111 at offset 3: unrecognized character after (? or (?-

/(?(1?)a|b)/
-Failed: error 126 at offset 4: malformed number or name after (?(
+Failed: error 124 at offset 4: missing closing parenthesis for condition

/[a[:xyz:/
Failed: error 106 at offset 8: missing terminating ] for character class

/(?<=x+)y/
-Failed: error 125 at offset 6: lookbehind assertion is not fixed length
+Failed: error 125 at offset 0: lookbehind assertion is not fixed length

/a{37,17}/
Failed: error 104 at offset 7: numbers out of order in {} quantifier

/abc/\
-Failed: error 101 at offset 3: \ at end of pattern
+Failed: error 101 at offset 4: \ at end of pattern

/abc/\i
-Failed: error 101 at offset 3: \ at end of pattern
+Failed: error 101 at offset 4: \ at end of pattern

/(a)bc(d)/I
Capturing subpattern count = 2
@@ -2115,7 +2114,7 @@
Failed: error 108 at offset 9: range out of order in character class

/^(?(0)f|b)oo/I
-Failed: error 135 at offset 6: invalid condition (?(0)
+Failed: error 115 at offset 5: reference to non-existent subpattern

# This one's here because of the large output vector needed

@@ -3099,19 +3098,19 @@
Failed: error 112 at offset 0: POSIX named classes are supported only within a class

/\l/I
-Failed: error 137 at offset 1: PCRE does not support \L, \l, \N{name}, \U, or \u
+Failed: error 137 at offset 2: PCRE does not support \L, \l, \N{name}, \U, or \u

/\L/I
-Failed: error 137 at offset 1: PCRE does not support \L, \l, \N{name}, \U, or \u
+Failed: error 137 at offset 2: PCRE does not support \L, \l, \N{name}, \U, or \u

/\N{name}/I
-Failed: error 137 at offset 1: PCRE does not support \L, \l, \N{name}, \U, or \u
+Failed: error 137 at offset 2: PCRE does not support \L, \l, \N{name}, \U, or \u

/\u/I
-Failed: error 137 at offset 1: PCRE does not support \L, \l, \N{name}, \U, or \u
+Failed: error 137 at offset 2: PCRE does not support \L, \l, \N{name}, \U, or \u

/\U/I
-Failed: error 137 at offset 1: PCRE does not support \L, \l, \N{name}, \U, or \u
+Failed: error 137 at offset 2: PCRE does not support \L, \l, \N{name}, \U, or \u

 /a{1,3}b/ungreedy
     ab
@@ -3545,25 +3544,25 @@
 Subject length lower bound = 0
     abcabcabc
 --->abcabcabc
-  0 ^             (abc(?C1))*
-  1 ^  ^          )
-  1 ^     ^       )
-  1 ^        ^    )
+  0 ^             (
+  1 ^  ^          )*
+  1 ^     ^       )*
+  1 ^        ^    )*
  0: abcabcabc
  1: abc
     abcabc\=callout_fail=1:3
 --->abcabc
-  0 ^          (abc(?C1))*
-  1 ^  ^       )
-  1 ^     ^    )
+  0 ^          (
+  1 ^  ^       )*
+  1 ^     ^    )*
  0: abcabc
  1: abc
     abcabcabc\=callout_fail=1:3
 --->abcabcabc
-  0 ^             (abc(?C1))*
-  1 ^  ^          )
-  1 ^     ^       )
-  1 ^        ^    )
+  0 ^             (
+  1 ^  ^          )*
+  1 ^     ^       )*
+  1 ^        ^    )*
  0: abcabc
  1: abc


@@ -3575,7 +3574,7 @@
 Callout 0: last capture = 0
  0: <unset>
 --->123
-    ^  ^    )
+    ^  ^    )*
  0: 123
  1: 123
     123456\=callout_capture
@@ -3582,12 +3581,12 @@
 Callout 0: last capture = 0
  0: <unset>
 --->123456
-    ^  ^       )
+    ^  ^       )*
 Callout 0: last capture = 1
  0: <unset>
  1: 123
 --->123456
-    ^     ^    )
+    ^     ^    )*
  0: 123456
  1: 456
     123456789\=callout_capture
@@ -3594,17 +3593,17 @@
 Callout 0: last capture = 0
  0: <unset>
 --->123456789
-    ^  ^          )
+    ^  ^          )*
 Callout 0: last capture = 1
  0: <unset>
  1: 123
 --->123456789
-    ^     ^       )
+    ^     ^       )*
 Callout 0: last capture = 1
  0: <unset>
  1: 456
 --->123456789
-    ^        ^    )
+    ^        ^    )*
  0: 123456789
  1: 789


@@ -4355,10 +4354,10 @@
C aa (2) A (group 2)

/(?P<x>eks)(?P<x>eccs)/I
-Failed: error 143 at offset 15: two named subpatterns have the same name (PCRE2_DUPNAMES not set)
+Failed: error 143 at offset 16: two named subpatterns have the same name (PCRE2_DUPNAMES not set)

/(?P<abc>abc(?P<def>def)(?P<abc>xyz))/I
-Failed: error 143 at offset 30: two named subpatterns have the same name (PCRE2_DUPNAMES not set)
+Failed: error 143 at offset 31: two named subpatterns have the same name (PCRE2_DUPNAMES not set)

 "\[((?P<elem>\d+)(,(?P>elem))*)\]"I
 Capturing subpattern count = 3
@@ -4723,7 +4722,7 @@
 /(abc|def)x/IB,auto_callout
 ------------------------------------------------------------------
         Bra
-        Callout 255 0 9
+        Callout 255 0 1
         CBra 1
         Callout 255 1 1
         a
@@ -4731,7 +4730,7 @@
         b
         Callout 255 3 1
         c
-        Callout 255 4 0
+        Callout 255 4 1
         Alt
         Callout 255 5 1
         d
@@ -4739,7 +4738,7 @@
         e
         Callout 255 7 1
         f
-        Callout 255 8 0
+        Callout 255 8 1
         Ket
         Callout 255 9 1
         x
@@ -4754,7 +4753,7 @@
 Subject length lower bound = 4
   abcx
 --->abcx
- +0 ^        (abc|def)
+ +0 ^        (
  +1 ^        a
  +2 ^^       b
  +3 ^ ^      c
@@ -4765,7 +4764,7 @@
  1: abc
   defx
 --->defx
- +0 ^        (abc|def)
+ +0 ^        (
  +1 ^        a
  +5 ^        d
  +6 ^^       e
@@ -4778,7 +4777,7 @@
 \= Expect no match 
   abcdefzx
 --->abcdefzx
- +0 ^            (abc|def)
+ +0 ^            (
  +1 ^            a
  +2 ^^           b
  +3 ^ ^          c
@@ -4785,7 +4784,7 @@
  +4 ^  ^         |
  +9 ^  ^         x
  +5 ^            d
- +0    ^         (abc|def)
+ +0    ^         (
  +1    ^         a
  +5    ^         d
  +6    ^^        e
@@ -4797,7 +4796,7 @@
 /(abc|def)x/IB,auto_callout
 ------------------------------------------------------------------
         Bra
-        Callout 255 0 9
+        Callout 255 0 1
         CBra 1
         Callout 255 1 1
         a
@@ -4805,7 +4804,7 @@
         b
         Callout 255 3 1
         c
-        Callout 255 4 0
+        Callout 255 4 1
         Alt
         Callout 255 5 1
         d
@@ -4813,7 +4812,7 @@
         e
         Callout 255 7 1
         f
-        Callout 255 8 0
+        Callout 255 8 1
         Ket
         Callout 255 9 1
         x
@@ -4828,7 +4827,7 @@
 Subject length lower bound = 4
   abcx
 --->abcx
- +0 ^        (abc|def)
+ +0 ^        (
  +1 ^        a
  +2 ^^       b
  +3 ^ ^      c
@@ -4839,7 +4838,7 @@
  1: abc
   defx
 --->defx
- +0 ^        (abc|def)
+ +0 ^        (
  +1 ^        a
  +5 ^        d
  +6 ^^       e
@@ -4852,7 +4851,7 @@
 \= Expect no match 
   abcdefzx
 --->abcdefzx
- +0 ^            (abc|def)
+ +0 ^            (
  +1 ^            a
  +2 ^^           b
  +3 ^ ^          c
@@ -4859,7 +4858,7 @@
  +4 ^  ^         |
  +9 ^  ^         x
  +5 ^            d
- +0    ^         (abc|def)
+ +0    ^         (
  +1    ^         a
  +5    ^         d
  +6    ^^        e
@@ -4875,7 +4874,7 @@
 Subject length lower bound = 6
   ababab
 --->ababab
- +0 ^          (ab|cd){3,4}
+ +0 ^          (
  +1 ^          a
  +2 ^^         b
  +3 ^ ^        |
@@ -4892,7 +4891,7 @@
  1: ab
   abcdabcd
 --->abcdabcd
- +0 ^            (ab|cd){3,4}
+ +0 ^            (
  +1 ^            a
  +2 ^^           b
  +3 ^ ^          |
@@ -4899,7 +4898,7 @@
  +1 ^ ^          a
  +4 ^ ^          c
  +5 ^  ^         d
- +6 ^   ^        )
+ +6 ^   ^        ){3,4}
  +1 ^   ^        a
  +2 ^    ^       b
  +3 ^     ^      |
@@ -4906,13 +4905,13 @@
  +1 ^     ^      a
  +4 ^     ^      c
  +5 ^      ^     d
- +6 ^       ^    )
+ +6 ^       ^    ){3,4}
 +12 ^       ^    
  0: abcdabcd
  1: cd
   abcdcdcdcdcd
 --->abcdcdcdcdcd
- +0 ^                (ab|cd){3,4}
+ +0 ^                (
  +1 ^                a
  +2 ^^               b
  +3 ^ ^              |
@@ -4919,15 +4918,15 @@
  +1 ^ ^              a
  +4 ^ ^              c
  +5 ^  ^             d
- +6 ^   ^            )
+ +6 ^   ^            ){3,4}
  +1 ^   ^            a
  +4 ^   ^            c
  +5 ^    ^           d
- +6 ^     ^          )
+ +6 ^     ^          ){3,4}
  +1 ^     ^          a
  +4 ^     ^          c
  +5 ^      ^         d
- +6 ^       ^        )
+ +6 ^       ^        ){3,4}
 +12 ^       ^        
  0: abcdcdcd
  1: cd
@@ -4935,7 +4934,7 @@
 /([ab]{,4}c|xy)/IB,auto_callout
 ------------------------------------------------------------------
         Bra
-        Callout 255 0 14
+        Callout 255 0 1
         CBra 1
         Callout 255 1 4
         [ab]
@@ -4949,13 +4948,13 @@
         }
         Callout 255 9 1
         c
-        Callout 255 10 0
+        Callout 255 10 1
         Alt
         Callout 255 11 1
         x
         Callout 255 12 1
         y
-        Callout 255 13 0
+        Callout 255 13 1
         Ket
         Callout 255 14 0
         Ket
@@ -4968,15 +4967,15 @@
 \= Expect no match 
     Note: that { does NOT introduce a quantifier
 --->Note: that { does NOT introduce a quantifier
- +0         ^                                        ([ab]{,4}c|xy)
+ +0         ^                                        (
  +1         ^                                        [ab]
  +5         ^^                                       {
 +11         ^                                        x
- +0                                 ^                ([ab]{,4}c|xy)
+ +0                                 ^                (
  +1                                 ^                [ab]
  +5                                 ^^               {
 +11                                 ^                x
- +0                                     ^            ([ab]{,4}c|xy)
+ +0                                     ^            (
  +1                                     ^            [ab]
  +5                                     ^^           {
 +11                                     ^            x
@@ -4985,7 +4984,7 @@
 /([ab]{,4}c|xy)/IB,auto_callout
 ------------------------------------------------------------------
         Bra
-        Callout 255 0 14
+        Callout 255 0 1
         CBra 1
         Callout 255 1 4
         [ab]
@@ -4999,13 +4998,13 @@
         }
         Callout 255 9 1
         c
-        Callout 255 10 0
+        Callout 255 10 1
         Alt
         Callout 255 11 1
         x
         Callout 255 12 1
         y
-        Callout 255 13 0
+        Callout 255 13 1
         Ket
         Callout 255 14 0
         Ket
@@ -5018,15 +5017,15 @@
 \= Expect no match 
     Note: that { does NOT introduce a quantifier
 --->Note: that { does NOT introduce a quantifier
- +0         ^                                        ([ab]{,4}c|xy)
+ +0         ^                                        (
  +1         ^                                        [ab]
  +5         ^^                                       {
 +11         ^                                        x
- +0                                 ^                ([ab]{,4}c|xy)
+ +0                                 ^                (
  +1                                 ^                [ab]
  +5                                 ^^               {
 +11                                 ^                x
- +0                                     ^            ([ab]{,4}c|xy)
+ +0                                     ^            (
  +1                                     ^            [ab]
  +5                                     ^^           {
 +11                                     ^            x
@@ -5035,19 +5034,19 @@
 /([ab]{1,4}c|xy){4,5}?123/IB,auto_callout
 ------------------------------------------------------------------
         Bra
-        Callout 255 0 21
+        Callout 255 0 1
         CBra 1
         Callout 255 1 9
         [ab]{1,4}+
         Callout 255 10 1
         c
-        Callout 255 11 0
+        Callout 255 11 1
         Alt
         Callout 255 12 1
         x
         Callout 255 13 1
         y
-        Callout 255 14 0
+        Callout 255 14 7
         Ket
         CBra 1
         Callout 255 1 9
@@ -5054,13 +5053,13 @@
         [ab]{1,4}+
         Callout 255 10 1
         c
-        Callout 255 11 0
+        Callout 255 11 1
         Alt
         Callout 255 12 1
         x
         Callout 255 13 1
         y
-        Callout 255 14 0
+        Callout 255 14 7
         Ket
         CBra 1
         Callout 255 1 9
@@ -5067,13 +5066,13 @@
         [ab]{1,4}+
         Callout 255 10 1
         c
-        Callout 255 11 0
+        Callout 255 11 1
         Alt
         Callout 255 12 1
         x
         Callout 255 13 1
         y
-        Callout 255 14 0
+        Callout 255 14 7
         Ket
         CBra 1
         Callout 255 1 9
@@ -5080,13 +5079,13 @@
         [ab]{1,4}+
         Callout 255 10 1
         c
-        Callout 255 11 0
+        Callout 255 11 1
         Alt
         Callout 255 12 1
         x
         Callout 255 13 1
         y
-        Callout 255 14 0
+        Callout 255 14 7
         Ket
         Braminzero
         CBra 1
@@ -5094,13 +5093,13 @@
         [ab]{1,4}+
         Callout 255 10 1
         c
-        Callout 255 11 0
+        Callout 255 11 1
         Alt
         Callout 255 12 1
         x
         Callout 255 13 1
         y
-        Callout 255 14 0
+        Callout 255 14 7
         Ket
         Callout 255 21 1
         1
@@ -5119,7 +5118,7 @@
 Subject length lower bound = 11
     aacaacaacaacaac123
 --->aacaacaacaacaac123
- +0 ^                      ([ab]{1,4}c|xy){4,5}?
+ +0 ^                      (
  +1 ^                      [ab]{1,4}
 +10 ^ ^                    c
 +11 ^  ^                   |
@@ -5651,7 +5650,7 @@
 Subject length lower bound = 1


/^((?P<A>a1)|(?P<A>a2)b)/I
-Failed: error 143 at offset 17: two named subpatterns have the same name (PCRE2_DUPNAMES not set)
+Failed: error 143 at offset 18: two named subpatterns have the same name (PCRE2_DUPNAMES not set)

/^((?P<A>a1)|(?P<A>a2)b)/I,dupnames
Capturing subpattern count = 3
@@ -5833,7 +5832,7 @@
C a2 (2) A (non-unique)

/^(?P<A>a) (?J:(?P<B>b)(?P<B>c)) (?P<A>d)/I
-Failed: error 143 at offset 37: two named subpatterns have the same name (PCRE2_DUPNAMES not set)
+Failed: error 143 at offset 38: two named subpatterns have the same name (PCRE2_DUPNAMES not set)

# In this next test, J is not set at the outer level; consequently it isn't set
# in the pattern's options; consequently pcre2_substring_get_byname() produces
@@ -5889,10 +5888,10 @@
1: X

/(?:(?(2y)a|b)(X))+/I
-Failed: error 126 at offset 7: malformed number or name after (?(
+Failed: error 124 at offset 7: missing closing parenthesis for condition

/(?:(?(ZA)a|b)(?P<ZZ>X))+/I
-Failed: error 115 at offset 9: reference to non-existent subpattern
+Failed: error 115 at offset 6: reference to non-existent subpattern

/(?:(?(ZZ)a|b)(?(ZZ)a|b)(?P<ZZ>X))+/I
Capturing subpattern count = 1
@@ -7023,7 +7022,7 @@
No match

/^(?P>abc)(?<abcd>xxx)/
-Failed: error 115 at offset 8: reference to non-existent subpattern
+Failed: error 115 at offset 5: reference to non-existent subpattern

 /^(?P>abc)(?<abc>x|y)/
     xx
@@ -7283,13 +7282,13 @@
 No match


/(?(<bc))/
-Failed: error 126 at offset 6: malformed number or name after (?(
+Failed: error 142 at offset 6: syntax error in subpattern name (missing terminator)

/(?(''))/
-Failed: error 128 at offset 4: assertion expected after (?( or (?(?C)
+Failed: error 162 at offset 4: subpattern name expected

/(?('R')stuff)/
-Failed: error 115 at offset 7: reference to non-existent subpattern
+Failed: error 115 at offset 4: reference to non-existent subpattern

 /((abc (?(R) (?(R1)1) (?(R2)2) X  |  (?1)  (?2)   (?R) ))) /x
     abcabc1Xabc2XabcXabcabc
@@ -7304,10 +7303,10 @@
  2: abcabc1Xabc2XabcX


/(?<A> (?'B' abc (?(R) (?(R&C)1) (?(R&B)2) X | (?1) (?2) (?R) ))) /x
-Failed: error 115 at offset 29: reference to non-existent subpattern
+Failed: error 115 at offset 27: reference to non-existent subpattern

/^(?(DEFINE) abc | xyz ) /x
-Failed: error 154 at offset 22: DEFINE group contains more than one branch
+Failed: error 154 at offset 4: DEFINE group contains more than one branch

/(?(DEFINE) abc) xyz/Ix
Capturing subpattern count = 0
@@ -7513,19 +7512,19 @@
No match

/^(a)\g-2/
-Failed: error 115 at offset 7: reference to non-existent subpattern
+Failed: error 115 at offset 8: reference to non-existent subpattern

/^(a)\g/
-Failed: error 158 at offset 5: a numbered reference must not be zero
+Failed: error 157 at offset 6: \g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number

/^(a)\g{0}/
-Failed: error 158 at offset 8: a numbered reference must not be zero
+Failed: error 115 at offset 9: reference to non-existent subpattern

/^(a)\g{3/
-Failed: error 157 at offset 8: \g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number
+Failed: error 157 at offset 6: \g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number

/^(a)\g{aa}/
-Failed: error 115 at offset 9: reference to non-existent subpattern
+Failed: error 115 at offset 7: reference to non-existent subpattern

 /^a.b/newline=lf
     a\rb
@@ -7648,13 +7647,13 @@
 No match


/x(?-0)y/
-Failed: error 158 at offset 5: a numbered reference must not be zero
+Failed: error 126 at offset 5: a relative value of zero is not allowed

/x(?-1)y/
Failed: error 115 at offset 5: reference to non-existent subpattern

/x(?+0)y/
-Failed: error 158 at offset 5: a numbered reference must not be zero
+Failed: error 126 at offset 5: a relative value of zero is not allowed

/x(?+1)y/
Failed: error 115 at offset 5: reference to non-existent subpattern
@@ -7716,7 +7715,7 @@
No match

/(?(-1)a)/B
-Failed: error 115 at offset 6: reference to non-existent subpattern
+Failed: error 115 at offset 5: reference to non-existent subpattern

/((?(-1)a))/B
------------------------------------------------------------------
@@ -7732,7 +7731,7 @@
------------------------------------------------------------------

/((?(-2)a))/B
-Failed: error 115 at offset 7: reference to non-existent subpattern
+Failed: error 115 at offset 6: reference to non-existent subpattern

/^(?(+1)X|Y)(.)/B
------------------------------------------------------------------
@@ -8223,10 +8222,10 @@
Failed: error 166 at offset 7: (*MARK) must have an argument

/(?i:A{1,}\6666666666)/
-Failed: error 161 at offset 19: number is too big
+Failed: error 161 at offset 19: group number is too big

/\g6666666666/
-Failed: error 161 at offset 11: number is too big
+Failed: error 161 at offset 7: group number is too big

/[\g6666666666]/B
------------------------------------------------------------------
@@ -8493,25 +8492,25 @@
Failed: error 162 at offset 9: subpattern name expected

/(?<abc>)(?&a)/
-Failed: error 115 at offset 12: reference to non-existent subpattern
+Failed: error 115 at offset 11: reference to non-existent subpattern

/(?<a>)(?&aaaaaaaaaaaaaaaaaaaaaaa)/
-Failed: error 115 at offset 32: reference to non-existent subpattern
+Failed: error 115 at offset 9: reference to non-existent subpattern

/(?+-a)/
-Failed: error 163 at offset 3: digit expected after (?+
+Failed: error 129 at offset 2: digit expected after (?+ or (?-

/(?-+a)/
Failed: error 111 at offset 3: unrecognized character after (? or (?-

/(?(-1))/
-Failed: error 115 at offset 6: reference to non-existent subpattern
+Failed: error 115 at offset 5: reference to non-existent subpattern

/(?(+10))/
-Failed: error 115 at offset 7: reference to non-existent subpattern
+Failed: error 115 at offset 4: reference to non-existent subpattern

/(?(10))/
-Failed: error 115 at offset 6: reference to non-existent subpattern
+Failed: error 115 at offset 3: reference to non-existent subpattern

/(?(+2))()()/

@@ -8527,10 +8526,10 @@
Failed: error 162 at offset 3: subpattern name expected

/\k/
-Failed: error 169 at offset 1: \k is not followed by a braced, angle-bracketed, or quoted name
+Failed: error 169 at offset 2: \k is not followed by a braced, angle-bracketed, or quoted name

/\kabc/
-Failed: error 169 at offset 1: \k is not followed by a braced, angle-bracketed, or quoted name
+Failed: error 169 at offset 2: \k is not followed by a braced, angle-bracketed, or quoted name

/(?P=)/
Failed: error 162 at offset 4: subpattern name expected
@@ -8628,11 +8627,11 @@
2: xyz

 /(?&N)[]a(?<N>)](?<M>abc)/
-Failed: error 115 at offset 4: reference to non-existent subpattern
+Failed: error 115 at offset 3: reference to non-existent subpattern
    abc<abc


 /(?&N)[]a(?<N>)](abc)/
-Failed: error 115 at offset 4: reference to non-existent subpattern
+Failed: error 115 at offset 3: reference to non-existent subpattern
    abc<abc


 /a[]b/
@@ -8712,8 +8711,8 @@
 Subject length lower bound = 0
    adc
 --->adc
- +0 ^       (?(?=.*b)b|^)
- +2 ^       (?=.*b)
+ +0 ^       (?
+ +2 ^       (?=
  +5 ^       .*
  +7 ^  ^    b
  +7 ^ ^     b
@@ -8725,8 +8724,8 @@
  0: 
    abc 
 --->abc
- +0 ^       (?(?=.*b)b|^)
- +2 ^       (?=.*b)
+ +0 ^       (?
+ +2 ^       (?=
  +5 ^       .*
  +7 ^  ^    b
  +7 ^ ^     b
@@ -8733,8 +8732,8 @@
  +7 ^^      b
  +8 ^ ^     )
  +9 ^       b
- +0  ^      (?(?=.*b)b|^)
- +2  ^      (?=.*b)
+ +0  ^      (?
+ +2  ^      (?=
  +5  ^      .*
  +7  ^ ^    b
  +7  ^^     b
@@ -8847,23 +8846,23 @@
 --->"ab"
  +0 ^        ^
  +1 ^        "
- +2 ^^       ((?(?=[a])[^"])|b)*
- +3 ^^       (?(?=[a])[^"])
- +5 ^^       (?=[a])
+ +2 ^^       (
+ +3 ^^       (?
+ +5 ^^       (?=
  +8 ^^       [a]
 +11 ^ ^      )
 +12 ^^       [^"]
 +16 ^ ^      )
 +17 ^ ^      |
- +3 ^ ^      (?(?=[a])[^"])
- +5 ^ ^      (?=[a])
+ +3 ^ ^      (?
+ +5 ^ ^      (?=
  +8 ^ ^      [a]
 +17 ^ ^      |
 +21 ^ ^      "
 +18 ^ ^      b
-+19 ^  ^     )
- +3 ^  ^     (?(?=[a])[^"])
- +5 ^  ^     (?=[a])
++19 ^  ^     )*
+ +3 ^  ^     (?
+ +5 ^  ^     (?=
  +8 ^  ^     [a]
 +17 ^  ^     |
 +21 ^  ^     "
@@ -9472,22 +9471,21 @@
  1: a


/(a)(?<=b\1)/
-Failed: error 125 at offset 10: lookbehind assertion is not fixed length

/(a)(?<=b+(?1))/
-Failed: error 125 at offset 13: lookbehind assertion is not fixed length
+Failed: error 125 at offset 3: lookbehind assertion is not fixed length

/(a+)(?<=b(?1))/
-Failed: error 125 at offset 14: lookbehind assertion is not fixed length
+Failed: error 125 at offset 4: lookbehind assertion is not fixed length

/(a(?<=b(?1)))/
-Failed: error 125 at offset 13: lookbehind assertion is not fixed length
+Failed: error 125 at offset 2: lookbehind assertion is not fixed length

/(?<=b(?1))xyz/
Failed: error 115 at offset 8: reference to non-existent subpattern

/(?<=b(?1))xyz(b+)pqrstuvew/
-Failed: error 125 at offset 26: lookbehind assertion is not fixed length
+Failed: error 125 at offset 0: lookbehind assertion is not fixed length

/(a|bc)\1/I
Capturing subpattern count = 1
@@ -9611,7 +9609,7 @@
C B (1) a (group 1)

/(?|(?<a>A)|(?<b>B))/
-Failed: error 165 at offset 15: different names for subpatterns of the same number are not allowed
+Failed: error 165 at offset 16: different names for subpatterns of the same number are not allowed

 /(?:a(?<quote> (?<apostrophe>')|(?<realquote>")) |
     b(?<quote> (?<apostrophe>')|(?<realquote>")) ) 
@@ -9989,7 +9987,7 @@
 Failed: error 166 at offset 6: (*MARK) must have an argument


/abc(*FAIL:123)xyz/
-Failed: error 159 at offset 13: an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)
+Failed: error 159 at offset 10: an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)

# This should, and does, fail. In Perl, it does not, which I think is a
# bug because replacing the B in the pattern by (B|D) does make it fail.
@@ -10335,7 +10333,7 @@
Failed: error 142 at offset 29: syntax error in subpattern name (missing terminator)

/(?P<abn>(?P=axn)xxx)/B
-Failed: error 115 at offset 15: reference to non-existent subpattern
+Failed: error 115 at offset 12: reference to non-existent subpattern

/(?P<abn>(?P=axn)xxx)(?<axn>yy)/B
------------------------------------------------------------------
@@ -10456,7 +10454,7 @@
Subject length lower bound = 5

/(?<=(abc)+)X/
-Failed: error 125 at offset 10: lookbehind assertion is not fixed length
+Failed: error 125 at offset 0: lookbehind assertion is not fixed length

 /(^ab)/I
 Capturing subpattern count = 1
@@ -10966,10 +10964,10 @@
     adz
 --->adz
  +0 ^       ^
- +1 ^       (a(*:A)(d|e(*:B))z|aeq)
+ +1 ^       (
  +2 ^       a
  +3 ^^      (*:A)
- +8 ^^      (d|e(*:B))
+ +8 ^^      (
 Latest Mark: A
  +9 ^^      d
 +10 ^ ^     |
@@ -10982,10 +10980,10 @@
     aez
 --->aez
  +0 ^       ^
- +1 ^       (a(*:A)(d|e(*:B))z|aeq)
+ +1 ^       (
  +2 ^       a
  +3 ^^      (*:A)
- +8 ^^      (d|e(*:B))
+ +8 ^^      (
 Latest Mark: A
  +9 ^^      d
 +11 ^^      e
@@ -11001,10 +10999,10 @@
     aeqwerty
 --->aeqwerty
  +0 ^            ^
- +1 ^            (a(*:A)(d|e(*:B))z|aeq)
+ +1 ^            (
  +2 ^            a
  +3 ^^           (*:A)
- +8 ^^           (d|e(*:B))
+ +8 ^^           (
 Latest Mark: A
  +9 ^^           d
 +11 ^^           e
@@ -11223,14 +11221,14 @@
 ------------------------------------------------------------------


 /a[\NB]c/
-Failed: error 171 at offset 3: \N is not supported in a class
+Failed: error 171 at offset 4: \N is not supported in a class
     aNc


/a[B-\Nc]/
-Failed: error 150 at offset 5: invalid range in character class
+Failed: error 150 at offset 6: invalid range in character class

/a[B\Nc]/
-Failed: error 171 at offset 4: \N is not supported in a class
+Failed: error 171 at offset 5: \N is not supported in a class

/(a)(?2){0,1999}?(b)/

@@ -11735,11 +11733,11 @@
  1: <unset>
  2: a
 --->aab
-    ^^      )
+    ^^      ){0}
 Callout 1: last capture = 0
  0: <unset>
 --->aab
-    ^^      ((a)(?C2)){0}
+    ^^      (
  0: a


 /(?:(a)+(?C1)bb|aa(?C2)b)++/
@@ -11798,8 +11796,8 @@
     bb
 --->bb
  +0 ^      ^
- +1 ^      (?(?=a)aa|bb)
- +3 ^      (?=a)
+ +1 ^      (?
+ +3 ^      (?=
  +6 ^      a
 +11 ^      b
 +12 ^^     b
@@ -11811,8 +11809,8 @@
     bb
 --->bb
   1 ^      ^
-  2 ^      (?(?C99)(?=(?C3)a(?C4))(?C5)a(?C6)a(?C7)|(?C8)b(?C9)b(?C10))
- 99 ^      (?=(?C3)a(?C4))
+  2 ^      (?
+ 99 ^      (?=
   3 ^      a
   8 ^      b
   9 ^^     b
@@ -13023,7 +13021,7 @@
     A\123B


/^A\oB/
-Failed: error 155 at offset 3: missing opening brace after \o
+Failed: error 155 at offset 4: missing opening brace after \o

/^A\x{zz}B/
Failed: error 167 at offset 5: non-hex character in \x{} (closing brace missing?)
@@ -13032,7 +13030,7 @@
Failed: error 167 at offset 7: non-hex character in \x{} (closing brace missing?)

/^A\x{/
-Failed: error 167 at offset 5: non-hex character in \x{} (closing brace missing?)
+Failed: error 178 at offset 5: digits missing in \x{} or \o{}

/[ab]++/B,no_auto_possess
------------------------------------------------------------------
@@ -13067,16 +13065,16 @@
------------------------------------------------------------------

/[a-[:digit:]]+/
-Failed: error 150 at offset 3: invalid range in character class
+Failed: error 150 at offset 4: invalid range in character class

/[A-[:digit:]]+/
-Failed: error 150 at offset 3: invalid range in character class
+Failed: error 150 at offset 4: invalid range in character class

/[a-[.xxx.]]+/
-Failed: error 150 at offset 3: invalid range in character class
+Failed: error 150 at offset 4: invalid range in character class

/[a-[=xxx=]]+/
-Failed: error 150 at offset 3: invalid range in character class
+Failed: error 150 at offset 4: invalid range in character class

/[a-[!xxx!]]+/
Failed: error 108 at offset 3: range out of order in character class
@@ -13086,13 +13084,13 @@
0: A]]]

/[a-\d]+/
-Failed: error 150 at offset 4: invalid range in character class
+Failed: error 150 at offset 5: invalid range in character class

/(?<0abc>xx)/
Failed: error 144 at offset 3: group name must start with a non-digit

/(?&1abc)xx(?<1abc>y)/
-Failed: error 144 at offset 13: group name must start with a non-digit
+Failed: error 144 at offset 3: group name must start with a non-digit

/(?<ab-cd>xx)/
Failed: error 142 at offset 5: syntax error in subpattern name (missing terminator)
@@ -13116,13 +13114,13 @@
Failed: error 144 at offset 4: group name must start with a non-digit

/\g{4df}/
-Failed: error 144 at offset 3: group name must start with a non-digit
+Failed: error 157 at offset 2: \g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number

/(?&1abc)xx(?<1abc>y)/
-Failed: error 144 at offset 13: group name must start with a non-digit
+Failed: error 144 at offset 3: group name must start with a non-digit

/(?P>1abc)xx(?<1abc>y)/
-Failed: error 144 at offset 14: group name must start with a non-digit
+Failed: error 144 at offset 4: group name must start with a non-digit

/\g'3gh'/
Failed: error 157 at offset 2: \g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number
@@ -13137,7 +13135,7 @@
Failed: error 144 at offset 4: group name must start with a non-digit

/(?(4gh)abc)/
-Failed: error 126 at offset 4: malformed number or name after (?(
+Failed: error 124 at offset 4: missing closing parenthesis for condition

/(?(R&6yh)abc)/
Failed: error 144 at offset 5: group name must start with a non-digit
@@ -13215,10 +13213,10 @@
# Test stack guard external calls.

/(((a)))/stackguard=1
-Failed: error 133 at offset 2: parentheses are too deeply nested (stack check)
+Failed: error 133 at offset 7: parentheses are too deeply nested (stack check)

/(((a)))/stackguard=2
-Failed: error 133 at offset 3: parentheses are too deeply nested (stack check)
+Failed: error 133 at offset 7: parentheses are too deeply nested (stack check)

/(((a)))/stackguard=3

@@ -13243,10 +13241,10 @@
------------------------------------------------------------------

/\othing/
-Failed: error 155 at offset 1: missing opening brace after \o
+Failed: error 155 at offset 2: missing opening brace after \o

/\o{}/
-Failed: error 178 at offset 1: digits missing in \x{} or \o{}
+Failed: error 178 at offset 3: digits missing in \x{} or \o{}

/\o{whatever}/
Failed: error 164 at offset 3: non-octal character in \o{} (closing brace missing?)
@@ -13372,16 +13370,16 @@
No match

/(?(VERSION<10)yes|no)/
-Failed: error 179 at offset 10: syntax error in (?(VERSION condition
+Failed: error 179 at offset 10: syntax error or number too big in (?(VERSION condition

/(?(VERSION>10)yes|no)/
-Failed: error 179 at offset 11: syntax error in (?(VERSION condition
+Failed: error 179 at offset 11: syntax error or number too big in (?(VERSION condition

/(?(VERSION>=10.0.0)yes|no)/
-Failed: error 179 at offset 16: syntax error in (?(VERSION condition
+Failed: error 179 at offset 16: syntax error or number too big in (?(VERSION condition

/(?(VERSION=10.101)yes|no)/
-Failed: error 179 at offset 17: syntax error in (?(VERSION condition
+Failed: error 179 at offset 17: syntax error or number too big in (?(VERSION condition

 /abcd/I
 Capturing subpattern count = 0
@@ -13955,15 +13953,15 @@
         Bra
         Bra
         a
-        CalloutStr `code` 8 14 0
+        CalloutStr `code` 8 14 4
         Ket
         Bra
         a
-        CalloutStr `code` 8 14 0
+        CalloutStr `code` 8 14 4
         Ket
         Bra
         a
-        CalloutStr `code` 8 14 0
+        CalloutStr `code` 8 14 4
         Ket
         Ket
         End
@@ -13974,7 +13972,7 @@
         Bra
         ^
         Cond
-        Callout 25 9 7
+        Callout 25 9 3
         Assert
         abc
         Ket
@@ -13985,14 +13983,14 @@
         Ket
         End
 ------------------------------------------------------------------
-Callout 25  (?=abc)
+Callout 25  (?=
     abcdefg
 --->abcdefg
- 25 ^           (?=abc)
+ 25 ^           (?=
  0: abcd
     xyz123 
 --->xyz123
- 25 ^          (?=abc)
+ 25 ^          (?=
  0: xyz


 /^(?(?C$abc$)(?=abc)abcd|xyz)/B
@@ -14000,7 +13998,7 @@
         Bra
         ^
         Cond
-        CalloutStr $abc$ 7 12 7
+        CalloutStr $abc$ 7 12 3
         Assert
         abc
         Ket
@@ -14014,12 +14012,12 @@
     abcdefg
 Callout (7): $abc$
 --->abcdefg
-    ^           (?=abc)
+    ^           (?=
  0: abcd
     xyz123 
 Callout (7): $abc$
 --->xyz123
-    ^          (?=abc)
+    ^          (?=
  0: xyz


 /^ab(?C'first')cd(?C"second")ef/
@@ -14036,13 +14034,13 @@
     aaaXY
 Callout (8): `code`
 --->aaaXY
-    ^^        )
+    ^^        ){3}
 Callout (8): `code`
 --->aaaXY
-    ^ ^       )
+    ^ ^       ){3}
 Callout (8): `code`
 --->aaaXY
-    ^  ^      )
+    ^  ^      ){3}
  0: aaaX


# Binary zero in callout string
@@ -14073,7 +14071,7 @@
# Perl fails to diagnose the absence of an assertion

"(?(?<E>.*!.*)?)"
-Failed: error 128 at offset 3: assertion expected after (?( or (?(?C)
+Failed: error 128 at offset 2: assertion expected after (?( or (?(?C)

"X((?2)()*+){2}+"B
------------------------------------------------------------------
@@ -14124,7 +14122,7 @@
Failed: error 115 at offset 15: reference to non-existent subpattern

";(?<=()((?3))((?2)))"
-Failed: error 125 at offset 20: lookbehind assertion is not fixed length
+Failed: error 125 at offset 1: lookbehind assertion is not fixed length

# Perl loops on this (PCRE2 used to!)

@@ -14306,7 +14304,7 @@
"(?J)(?'d'(?'d'\g{d}))"

"(?=!((?2)(?))({8(?<=(?1){29}8bbbb\x16\xd\xc6^($(\xa9H4){4}h}?1)B))\x15')"
-Failed: error 125 at offset 72: lookbehind assertion is not fixed length
+Failed: error 125 at offset 16: lookbehind assertion is not fixed length

/A(?'')Z/
Failed: error 162 at offset 4: subpattern name expected
@@ -14314,7 +14312,7 @@
"(?J:(?|(?'R')(\k'R')|((?'R'))))"

/(?<=|(\,\$(?73591620449005828816)\xa8.{7}){6}\x09)/
-Failed: error 161 at offset 32: number is too big
+Failed: error 161 at offset 17: group number is too big

/^(?:(?(1)x|)+)+$()/B
------------------------------------------------------------------
@@ -14335,16 +14333,16 @@
------------------------------------------------------------------

/[[:>:]](?<)/
-Failed: error 124 at offset 10: letter or underscore expected after (?< or (?'
+Failed: error 162 at offset 10: subpattern name expected

/((?x)(*:0))#(?'/
-Failed: error 124 at offset 15: letter or underscore expected after (?< or (?'
+Failed: error 162 at offset 15: subpattern name expected

/(?C$[$)(?<]/
-Failed: error 124 at offset 10: letter or underscore expected after (?< or (?'
+Failed: error 162 at offset 10: subpattern name expected

/(?C$)$)(?<]/
-Failed: error 124 at offset 10: letter or underscore expected after (?< or (?'
+Failed: error 162 at offset 10: subpattern name expected

/(?(R))*+/B
------------------------------------------------------------------
@@ -14362,7 +14360,7 @@
0:

/((?x)(?#))#(?'/
-Failed: error 124 at offset 14: letter or underscore expected after (?< or (?'
+Failed: error 162 at offset 14: subpattern name expected

/((?x)(?#))#(?'abc')/I
Capturing subpattern count = 2
@@ -14372,7 +14370,7 @@
Subject length lower bound = 1

/[[:\\](?<[::]/
-Failed: error 124 at offset 9: letter or underscore expected after (?< or (?'
+Failed: error 162 at offset 9: subpattern name expected

/[[:\\](?'abc')[a:]/I
Capturing subpattern count = 1
@@ -14401,13 +14399,13 @@
------------------------------------------------------------------

/(?R-:(?</
-Failed: error 114 at offset 8: missing closing parenthesis
+Failed: error 158 at offset 3: (?R (recursive pattern call) must be followed by a closing parenthesis

/(?R-:(?<)/
-Failed: error 129 at offset 3: (?R or (?[+-]digits must be followed by )
+Failed: error 158 at offset 3: (?R (recursive pattern call) must be followed by a closing parenthesis

/(?(?C{\Q})(?!(?'/
-Failed: error 124 at offset 16: letter or underscore expected after (?< or (?'
+Failed: error 162 at offset 16: subpattern name expected

/(?(?C{\Q})(?!(?'abc')))/I
Capturing subpattern count = 1
@@ -14505,10 +14503,10 @@
0: ab

/(?(8000000000/
-Failed: error 114 at offset 13: missing closing parenthesis
+Failed: error 161 at offset 8: group number is too big

/((?(R8000000000)))/
-Failed: error 161 at offset 16: number is too big
+Failed: error 161 at offset 9: group number is too big

/0(?0)|(1)(*THEN)(*SKIP:0)(*FAIL)/
\= Expect no match
@@ -14516,7 +14514,7 @@
No match

/(?(1)()\983040\2)/
-Failed: error 115 at offset 13: reference to non-existent subpattern
+Failed: error 161 at offset 14: group number is too big

/(*LIMIT_MATCH=)abc/
Failed: error 160 at offset 14: (*VERB) not recognized or malformed
@@ -14539,7 +14537,7 @@
No match

/(*MARK:a\zb)z/alt_verbnames
-Failed: error 140 at offset 9: invalid escape sequence in (*VERB) name
+Failed: error 140 at offset 10: invalid escape sequence in (*VERB) name

/(*:ab\t(d\)c)xxx/
Failed: error 122 at offset 12: unmatched closing parenthesis
@@ -14565,6 +14563,24 @@
0: x
MK: A and B

+/(*: A \ and #comment
+     \ B)x/alt_verbnames,mark
+    x  
+ 0: x
+MK:  A  and #comment\x0a      B
+    
+/(*: A \ and #comment
+     \ B)x/x,mark
+    x  
+ 0: x
+MK:  A \ and #comment\x0a     \ B
+    
+/(*: A \ and #comment
+     \ B)x/mark
+    x  
+ 0: x
+MK:  A \ and #comment\x0a     \ B
+    
 /(*:A
 B)x/alt_verbnames,mark 
     x
@@ -14715,7 +14731,7 @@
 Failed: error -49 at offset 3 in replacement: unknown substring


/(?<!a{65535}a{5})x/I
-Failed: error 187 at offset 16: lookbehind assertion is too long
+Failed: error 187 at offset 0: lookbehind assertion is too long

/(?<!a{65535})x/I
Capturing subpattern count = 0
@@ -14781,7 +14797,7 @@
((?-2)(?-2))((?-2)(?-2))((?-2)(?-2))((?-2)(?-2))
((?-2)(?-2))((?-2)(?-2))((?-2)(?-2))
a)"xI
-Failed: error 186 at offset 154: regular expression is too complicated
+Failed: error 135 at offset 9: lookbehind is too complicated

 # Test the use of malloc for caching group information when there are more
 # groups than fit into the on-stack workspace.
@@ -14950,11 +14966,11 @@
 /(A*)\E+/B,auto_callout
 ------------------------------------------------------------------
         Bra
-        Callout 255 0 7
+        Callout 255 0 1
         SCBra 1
         Callout 255 1 2
         A*
-        Callout 255 3 0
+        Callout 255 3 4
         KetRmax
         Callout 255 7 0
         Ket
@@ -14964,10 +14980,10 @@
 /()\Q\E*]/B,auto_callout
 ------------------------------------------------------------------
         Bra
-        Callout 255 0 7
+        Callout 255 0 1
         Brazero
         SCBra 1
-        Callout 255 1 0
+        Callout 255 1 6
         KetRmax
         Callout 255 7 1
         ]
@@ -14977,8 +14993,8 @@
 ------------------------------------------------------------------
     a[bc]d
 --->a[bc]d
- +0     ^      ()\Q\E*
- +1     ^      )
+ +0     ^      (
+ +1     ^      )\Q\E*
  +7     ^      ]
  +8     ^^     
  0: ]
@@ -15077,7 +15093,7 @@
 (?-x):?/extended


/(8(*:6^\x09x\xa6l\)6!|\xd0:[^:|)\x09d\Z\d{85*m(?'(?<1!)*\W[*\xff]!!h\w]*\xbe;/alt_bsux,alt_verbnames,allow_empty_class,dollar_endonly,extended,multiline,never_utf,no_dotstar_anchor,no_start_optimize
-Failed: error 124 at offset 49: letter or underscore expected after (?< or (?'
+Failed: error 162 at offset 49: subpattern name expected

 /a|(b)c/replace=>$1<,substitute_unset_empty
     cat
@@ -15195,6 +15211,101 @@
 /\[AB]{6000000000000000000000}/expand
 ** Pattern repeat count too large


+# Hex uses pattern length, not zero-terminated. This tests for overrunning
+# the given length of a pattern.
+
+/'(*U'/hex
+Failed: error 160 at offset 3: (*VERB) not recognized or malformed
+
+/'(*'/hex
+Failed: error 109 at offset 1: quantifier does not follow a repeatable item
+
+/'('/hex
+Failed: error 114 at offset 1: missing closing parenthesis
+
+//hex
+
+# These tests are here because Perl never allows a back reference in a
+# lookbehind. PCRE2 supports some limited cases.
+
+/([ab])...(?<=\1)z/
+    a11az
+ 0: a11az
+ 1: a
+    b11bz 
+ 0: b11bz
+ 1: b
+\= Expect no match
+    b11az 
+No match
+    
+/(?|([ab]))...(?<=\1)z/
+Failed: error 125 at offset 13: lookbehind assertion is not fixed length
+
+/([ab])(\1)...(?<=\2)z/
+    aa11az
+ 0: aa11az
+ 1: a
+ 2: a
+    
+/(a\2)(b\1)(?<=\2)/ 
+Failed: error 125 at offset 10: lookbehind assertion is not fixed length
+ 
+/(?<A>[ab])...(?<=\k'A')z/
+    a11az
+ 0: a11az
+ 1: a
+    b11bz 
+ 0: b11bz
+ 1: b
+\= Expect no match
+    b11az 
+No match
+
+/(?<A>[ab])...(?<=\k'A')(?<A>)z/dupnames
+Failed: error 125 at offset 13: lookbehind assertion is not fixed length
+
+# Perl does not support \g+n
+
+/((\g+1X)?([ab]))+/
+    aaXbbXa
+ 0: aaXbbXa
+ 1: bXa
+ 2: bX
+ 3: a
+
+/ab(?C1)c/auto_callout
+    abc
+--->abc
+ +0 ^       a
+ +1 ^^      b
+  1 ^ ^     c
+ +8 ^  ^    
+ 0: abc
+
+/'ab(?C1)c'/hex,auto_callout
+    abc
+--->abc
+ +0 ^       a
+ +1 ^^      b
+  1 ^ ^     c
+ +8 ^  ^    
+ 0: abc
+    
+# Perl accepts these, but gives a warning. We can't warn, so give an error. 
+
+/[a-[:digit:]]+/
+Failed: error 150 at offset 4: invalid range in character class
+    a-a9-a
+
+/[A-[:digit:]]+/
+Failed: error 150 at offset 4: invalid range in character class
+    A-A9-A
+
+/[a-\d]+/
+Failed: error 150 at offset 5: invalid range in character class
+    a-a9-a
+
 # End of testinput2 
 Error -63: PCRE2_ERROR_BADDATA (unknown error number)
 Error -62: bad serialized data
@@ -15203,4 +15314,5 @@
 Error 0: PCRE2_ERROR_BADDATA (unknown error number)
 Error 100: no error
 Error 188: pattern string is longer than the limit set by the application
-Error 189: PCRE2_ERROR_BADDATA (unknown error number)
+Error 189: internal error: unknown code in parsed pattern
+Error 190: PCRE2_ERROR_BADDATA (unknown error number)


Modified: code/trunk/testdata/testoutput21
===================================================================
--- code/trunk/testdata/testoutput21    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testoutput21    2016-10-02 16:01:01 UTC (rev 555)
@@ -76,7 +76,7 @@
 ------------------------------------------------------------------


/ab\Cde/never_backslash_c
-Failed: error 183 at offset 3: using \C is disabled by the application
+Failed: error 183 at offset 4: using \C is disabled by the application

/ab\Cde/info
Capturing subpattern count = 0

Modified: code/trunk/testdata/testoutput22-16
===================================================================
--- code/trunk/testdata/testoutput22-16    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testoutput22-16    2016-10-02 16:01:01 UTC (rev 555)
@@ -17,7 +17,7 @@
 # 16-bit modes, but not in 32-bit mode.


 /(?<=ab\Cde)X/utf
-Failed: error 136 at offset 10: \C is not allowed in a lookbehind assertion in UTF-16 mode
+Failed: error 136 at offset 0: \C is not allowed in a lookbehind assertion in UTF-16 mode
     ab!deXYZ


# Autopossessification tests

Modified: code/trunk/testdata/testoutput22-8
===================================================================
--- code/trunk/testdata/testoutput22-8    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testoutput22-8    2016-10-02 16:01:01 UTC (rev 555)
@@ -17,7 +17,7 @@
 # 16-bit modes, but not in 32-bit mode.


 /(?<=ab\Cde)X/utf
-Failed: error 136 at offset 10: \C is not allowed in a lookbehind assertion in UTF-8 mode
+Failed: error 136 at offset 0: \C is not allowed in a lookbehind assertion in UTF-8 mode
     ab!deXYZ


# Autopossessification tests

Modified: code/trunk/testdata/testoutput23
===================================================================
--- code/trunk/testdata/testoutput23    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testoutput23    2016-10-02 16:01:01 UTC (rev 555)
@@ -3,6 +3,6 @@
 # correct error message.


/a\Cb/
-Failed: error 185 at offset 2: using \C is disabled in this PCRE2 library
+Failed: error 185 at offset 3: using \C is disabled in this PCRE2 library

# End of testinput23

Modified: code/trunk/testdata/testoutput5
===================================================================
--- code/trunk/testdata/testoutput5    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testoutput5    2016-10-02 16:01:01 UTC (rev 555)
@@ -1748,7 +1748,7 @@
 ------------------------------------------------------------------


/\ud800/utf,alt_bsux,allow_empty_class,match_unset_backref
-Failed: error 173 at offset 5: disallowed Unicode code point (>= 0xd800 && <= 0xdfff)
+Failed: error 173 at offset 6: disallowed Unicode code point (>= 0xd800 && <= 0xdfff)

/^a+[a\x{200}]/B,utf
------------------------------------------------------------------
@@ -3999,7 +3999,7 @@
/$(&.+[\p{Me}].\s\xdcC*?(?(<y>))(?<!^)$C((;*?(R))+(?(R)){0,6}?|){12\x8a\X*?\x8a\x0b\xd1^9\3*+(\xc1,\k'P'\xb4)\xcc(z\z(?JJ)(?'X'8};(\x0b\xd1^9\?'3*+(\xc1.]k+\x0b'Pm'\xb4\xcc4'\xd1'(?'X'))?-%--\x95$9*\4'|\xd1(''%\x95*$9)#(?'R')3\x07?('P\xed')\\x16:;()\x1e\x10*:(?<y>)\xd1+!~:(?)''(d'E:yD!\s(?'R'\x1e;\x10:U))|')g!\xb0*){29+))#(?'P'})*?/

"(*UTF)(*UCP)(.UTF).+X(\V+;\^(\D|)!999}(?(?C{7(?C')\H*\S*/^\x5\xa\\xd3\x85n?(;\D*(?m).[^mH+((*UCP)(*U:F)})(?!^)(?'"
-Failed: error 124 at offset 113: letter or underscore expected after (?< or (?'
+Failed: error 162 at offset 113: subpattern name expected

 /[\pS#moq]/
     =
@@ -4161,5 +4161,16 @@
 \= Expect no match
     \x{10000}
 No match
+    
+# Hex uses pattern length, not zero-terminated. This tests for overrunning
+# the given length of a pattern.


+/'(*UTF)'/hex
+
+/a(?<=A\XB)/utf
+Failed: error 125 at offset 1: lookbehind assertion is not fixed length
+
+/ab(?<=A\RB)/utf
+Failed: error 125 at offset 2: lookbehind assertion is not fixed length
+
# End of testinput5

Modified: code/trunk/testdata/testoutput6
===================================================================
--- code/trunk/testdata/testoutput6    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testoutput6    2016-10-02 16:01:01 UTC (rev 555)
@@ -713,7 +713,7 @@
 /(ab|cd){3,4}/auto_callout
   ababab
 --->ababab
- +0 ^          (ab|cd){3,4}
+ +0 ^          (
  +1 ^          a
  +4 ^          c
  +2 ^^         b
@@ -732,7 +732,7 @@
  0: ababab
   abcdabcd
 --->abcdabcd
- +0 ^            (ab|cd){3,4}
+ +0 ^            (
  +1 ^            a
  +4 ^            c
  +2 ^^           b
@@ -740,7 +740,7 @@
  +1 ^ ^          a
  +4 ^ ^          c
  +5 ^  ^         d
- +6 ^   ^        )
+ +6 ^   ^        ){3,4}
  +1 ^   ^        a
  +4 ^   ^        c
  +2 ^    ^       b
@@ -749,13 +749,13 @@
  +1 ^     ^      a
  +4 ^     ^      c
  +5 ^      ^     d
- +6 ^       ^    )
+ +6 ^       ^    ){3,4}
 +12 ^       ^    
  0: abcdabcd
  1: abcdab
   abcdcdcdcdcd  
 --->abcdcdcdcdcd
- +0 ^                (ab|cd){3,4}
+ +0 ^                (
  +1 ^                a
  +4 ^                c
  +2 ^^               b
@@ -763,16 +763,16 @@
  +1 ^ ^              a
  +4 ^ ^              c
  +5 ^  ^             d
- +6 ^   ^            )
+ +6 ^   ^            ){3,4}
  +1 ^   ^            a
  +4 ^   ^            c
  +5 ^    ^           d
- +6 ^     ^          )
+ +6 ^     ^          ){3,4}
 +12 ^     ^          
  +1 ^     ^          a
  +4 ^     ^          c
  +5 ^      ^         d
- +6 ^       ^        )
+ +6 ^       ^        ){3,4}
 +12 ^       ^        
  0: abcdcdcd
  1: abcdcd
@@ -6712,11 +6712,11 @@
 --->"ab"
  +0 ^        ^
  +1 ^        "
- +2 ^^       ((?(?=[a])[^"])|b)*
+ +2 ^^       (
 +21 ^^       "
- +3 ^^       (?(?=[a])[^"])
+ +3 ^^       (?
 +18 ^^       b
- +5 ^^       (?=[a])
+ +5 ^^       (?=
  +8  ^       [a]
 +11  ^^      )
 +12 ^^       [^"]
@@ -6723,15 +6723,15 @@
 +16 ^ ^      )
 +17 ^ ^      |
 +21 ^ ^      "
- +3 ^ ^      (?(?=[a])[^"])
+ +3 ^ ^      (?
 +18 ^ ^      b
- +5 ^ ^      (?=[a])
+ +5 ^ ^      (?=
  +8   ^      [a]
-+19 ^  ^     )
++19 ^  ^     )*
 +21 ^  ^     "
- +3 ^  ^     (?(?=[a])[^"])
+ +3 ^  ^     (?
 +18 ^  ^     b
- +5 ^  ^     (?=[a])
+ +5 ^  ^     (?=
  +8    ^     [a]
 +17 ^  ^     |
 +22 ^   ^    $
@@ -7154,7 +7154,7 @@
     aaaabcde
  0: aaaab


-/((?(R2)a+|(?1)b))/
+/((?(R2)a+|(?1)b))()/
     aaaabcde
 Failed: error -40: backreference condition or recursion test is not supported for DFA matching


@@ -7548,7 +7548,7 @@
         Bra
         ^
         Cond
-        Callout 25 9 7
+        Callout 25 9 3
         Assert
         abc
         Ket
@@ -7561,11 +7561,11 @@
 ------------------------------------------------------------------
     abcdefg
 --->abcdefg
- 25 ^           (?=abc)
+ 25 ^           (?=
  0: abcd
     xyz123 
 --->xyz123
- 25 ^          (?=abc)
+ 25 ^          (?=
  0: xyz


 /^(?(?C$abc$)(?=abc)abcd|xyz)/B
@@ -7573,7 +7573,7 @@
         Bra
         ^
         Cond
-        CalloutStr $abc$ 7 12 7
+        CalloutStr $abc$ 7 12 3
         Assert
         abc
         Ket
@@ -7587,12 +7587,12 @@
     abcdefg
 Callout (7): $abc$
 --->abcdefg
-    ^           (?=abc)
+    ^           (?=
  0: abcd
     xyz123 
 Callout (7): $abc$
 --->xyz123
-    ^          (?=abc)
+    ^          (?=
  0: xyz


 /^ab(?C'first')cd(?C"second")ef/
@@ -7609,13 +7609,13 @@
     aaaXY
 Callout (8): `code`
 --->aaaXY
-    ^^        )
+    ^^        ){3}
 Callout (8): `code`
 --->aaaXY
-    ^ ^       )
+    ^ ^       ){3}
 Callout (8): `code`
 --->aaaXY
-    ^  ^      )
+    ^  ^      ){3}
  0: aaaX


# Binary zero in callout string

Modified: code/trunk/testdata/testoutput8-16-2
===================================================================
--- code/trunk/testdata/testoutput8-16-2    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testoutput8-16-2    2016-10-02 16:01:01 UTC (rev 555)
@@ -854,24 +854,18 @@


# Use "expand" to create some very long patterns with nested parentheses, in
# order to test workspace overflow. Again, this varies with code unit width,
-# and even with it fails in two modes, the error offset differs. It also varies
+# and even when it fails in two modes, the error offset differs. It also varies
# with link size - hence multiple tests with different values.

-/(?'ABC'\[[bar](]{105}*THEN:\[A]{255}\[)]{106}/expand,-fullbincode
-Failed: error 186 at offset 594: regular expression is too complicated
+/(?'ABC'\[[bar](]{792}*THEN:\[A]{255}\[)]{793}/expand,-fullbincode,parens_nest_limit=1000
+Failed: error 186 at offset 5813: regular expression is too complicated

-/(?'ABC'\[[bar](]{106}*THEN:\[A]{255}\[)]{107}/expand,-fullbincode
-Failed: error 186 at offset 594: regular expression is too complicated
+/(?'ABC'\[[bar](]{793}*THEN:\[A]{255}\[)]{794}/expand,-fullbincode,parens_nest_limit=1000
+Failed: error 186 at offset 5820: regular expression is too complicated

-/(?'ABC'\[[bar](]{159}*THEN:\[A]{255}\[)]{160}/expand,-fullbincode
-Failed: error 186 at offset 594: regular expression is too complicated
+/(?'ABC'\[[bar](]{1793}*THEN:\[A]{255}\[)]{1794}/expand,-fullbincode,parens_nest_limit=2000
+Failed: error 186 at offset 12820: regular expression is too complicated

-/(?'ABC'\[[bar](]{199}*THEN:\[A]{255}\[)]{200}/expand,-fullbincode
-Failed: error 186 at offset 594: regular expression is too complicated
-
-/(?'ABC'\[[bar](]{299}*THEN:\[A]{255}\[)]{300}/expand,-fullbincode
-Failed: error 186 at offset 594: regular expression is too complicated
-
/(?(1)(?1)){8,}+()/debug
------------------------------------------------------------------
0 79 Bra
@@ -1031,6 +1025,5 @@
Failed: error 114 at offset 509: missing closing parenthesis

/([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00]([00](*ACCEPT)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))/-fullbincode
-Failed: error 186 at offset 490: regular expression is too complicated

# End of testinput8

Modified: code/trunk/testdata/testoutput8-16-3
===================================================================
--- code/trunk/testdata/testoutput8-16-3    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testoutput8-16-3    2016-10-02 16:01:01 UTC (rev 555)
@@ -853,21 +853,16 @@


# Use "expand" to create some very long patterns with nested parentheses, in
# order to test workspace overflow. Again, this varies with code unit width,
-# and even with it fails in two modes, the error offset differs. It also varies
+# and even when it fails in two modes, the error offset differs. It also varies
# with link size - hence multiple tests with different values.

-/(?'ABC'\[[bar](]{105}*THEN:\[A]{255}\[)]{106}/expand,-fullbincode
+/(?'ABC'\[[bar](]{792}*THEN:\[A]{255}\[)]{793}/expand,-fullbincode,parens_nest_limit=1000

-/(?'ABC'\[[bar](]{106}*THEN:\[A]{255}\[)]{107}/expand,-fullbincode
+/(?'ABC'\[[bar](]{793}*THEN:\[A]{255}\[)]{794}/expand,-fullbincode,parens_nest_limit=1000

-/(?'ABC'\[[bar](]{159}*THEN:\[A]{255}\[)]{160}/expand,-fullbincode
+/(?'ABC'\[[bar](]{1793}*THEN:\[A]{255}\[)]{1794}/expand,-fullbincode,parens_nest_limit=2000
+Failed: error 186 at offset 12820: regular expression is too complicated

-/(?'ABC'\[[bar](]{199}*THEN:\[A]{255}\[)]{200}/expand,-fullbincode
-Failed: error 186 at offset 1147: regular expression is too complicated
-
-/(?'ABC'\[[bar](]{299}*THEN:\[A]{255}\[)]{300}/expand,-fullbincode
-Failed: error 186 at offset 1147: regular expression is too complicated
-
/(?(1)(?1)){8,}+()/debug
------------------------------------------------------------------
0 110 Bra

Modified: code/trunk/testdata/testoutput8-16-4
===================================================================
--- code/trunk/testdata/testoutput8-16-4    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testoutput8-16-4    2016-10-02 16:01:01 UTC (rev 555)
@@ -853,21 +853,16 @@


# Use "expand" to create some very long patterns with nested parentheses, in
# order to test workspace overflow. Again, this varies with code unit width,
-# and even with it fails in two modes, the error offset differs. It also varies
+# and even when it fails in two modes, the error offset differs. It also varies
# with link size - hence multiple tests with different values.

-/(?'ABC'\[[bar](]{105}*THEN:\[A]{255}\[)]{106}/expand,-fullbincode
+/(?'ABC'\[[bar](]{792}*THEN:\[A]{255}\[)]{793}/expand,-fullbincode,parens_nest_limit=1000

-/(?'ABC'\[[bar](]{106}*THEN:\[A]{255}\[)]{107}/expand,-fullbincode
+/(?'ABC'\[[bar](]{793}*THEN:\[A]{255}\[)]{794}/expand,-fullbincode,parens_nest_limit=1000

-/(?'ABC'\[[bar](]{159}*THEN:\[A]{255}\[)]{160}/expand,-fullbincode
+/(?'ABC'\[[bar](]{1793}*THEN:\[A]{255}\[)]{1794}/expand,-fullbincode,parens_nest_limit=2000
+Failed: error 186 at offset 12820: regular expression is too complicated

-/(?'ABC'\[[bar](]{199}*THEN:\[A]{255}\[)]{200}/expand,-fullbincode
-Failed: error 186 at offset 1147: regular expression is too complicated
-
-/(?'ABC'\[[bar](]{299}*THEN:\[A]{255}\[)]{300}/expand,-fullbincode
-Failed: error 186 at offset 1147: regular expression is too complicated
-
/(?(1)(?1)){8,}+()/debug
------------------------------------------------------------------
0 110 Bra

Modified: code/trunk/testdata/testoutput8-32-2
===================================================================
--- code/trunk/testdata/testoutput8-32-2    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testoutput8-32-2    2016-10-02 16:01:01 UTC (rev 555)
@@ -853,21 +853,18 @@


# Use "expand" to create some very long patterns with nested parentheses, in
# order to test workspace overflow. Again, this varies with code unit width,
-# and even with it fails in two modes, the error offset differs. It also varies
+# and even when it fails in two modes, the error offset differs. It also varies
# with link size - hence multiple tests with different values.

-/(?'ABC'\[[bar](]{105}*THEN:\[A]{255}\[)]{106}/expand,-fullbincode
+/(?'ABC'\[[bar](]{792}*THEN:\[A]{255}\[)]{793}/expand,-fullbincode,parens_nest_limit=1000
+Failed: error 186 at offset 5813: regular expression is too complicated

-/(?'ABC'\[[bar](]{106}*THEN:\[A]{255}\[)]{107}/expand,-fullbincode
+/(?'ABC'\[[bar](]{793}*THEN:\[A]{255}\[)]{794}/expand,-fullbincode,parens_nest_limit=1000
+Failed: error 186 at offset 5820: regular expression is too complicated

-/(?'ABC'\[[bar](]{159}*THEN:\[A]{255}\[)]{160}/expand,-fullbincode
+/(?'ABC'\[[bar](]{1793}*THEN:\[A]{255}\[)]{1794}/expand,-fullbincode,parens_nest_limit=2000
+Failed: error 186 at offset 12820: regular expression is too complicated

-/(?'ABC'\[[bar](]{199}*THEN:\[A]{255}\[)]{200}/expand,-fullbincode
-Failed: error 186 at offset 979: regular expression is too complicated
-
-/(?'ABC'\[[bar](]{299}*THEN:\[A]{255}\[)]{300}/expand,-fullbincode
-Failed: error 186 at offset 979: regular expression is too complicated
-
/(?(1)(?1)){8,}+()/debug
------------------------------------------------------------------
0 79 Bra

Modified: code/trunk/testdata/testoutput8-32-3
===================================================================
--- code/trunk/testdata/testoutput8-32-3    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testoutput8-32-3    2016-10-02 16:01:01 UTC (rev 555)
@@ -853,21 +853,18 @@


# Use "expand" to create some very long patterns with nested parentheses, in
# order to test workspace overflow. Again, this varies with code unit width,
-# and even with it fails in two modes, the error offset differs. It also varies
+# and even when it fails in two modes, the error offset differs. It also varies
# with link size - hence multiple tests with different values.

-/(?'ABC'\[[bar](]{105}*THEN:\[A]{255}\[)]{106}/expand,-fullbincode
+/(?'ABC'\[[bar](]{792}*THEN:\[A]{255}\[)]{793}/expand,-fullbincode,parens_nest_limit=1000
+Failed: error 186 at offset 5813: regular expression is too complicated

-/(?'ABC'\[[bar](]{106}*THEN:\[A]{255}\[)]{107}/expand,-fullbincode
+/(?'ABC'\[[bar](]{793}*THEN:\[A]{255}\[)]{794}/expand,-fullbincode,parens_nest_limit=1000
+Failed: error 186 at offset 5820: regular expression is too complicated

-/(?'ABC'\[[bar](]{159}*THEN:\[A]{255}\[)]{160}/expand,-fullbincode
+/(?'ABC'\[[bar](]{1793}*THEN:\[A]{255}\[)]{1794}/expand,-fullbincode,parens_nest_limit=2000
+Failed: error 186 at offset 12820: regular expression is too complicated

-/(?'ABC'\[[bar](]{199}*THEN:\[A]{255}\[)]{200}/expand,-fullbincode
-Failed: error 186 at offset 979: regular expression is too complicated
-
-/(?'ABC'\[[bar](]{299}*THEN:\[A]{255}\[)]{300}/expand,-fullbincode
-Failed: error 186 at offset 979: regular expression is too complicated
-
/(?(1)(?1)){8,}+()/debug
------------------------------------------------------------------
0 79 Bra

Modified: code/trunk/testdata/testoutput8-32-4
===================================================================
--- code/trunk/testdata/testoutput8-32-4    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testoutput8-32-4    2016-10-02 16:01:01 UTC (rev 555)
@@ -853,21 +853,18 @@


# Use "expand" to create some very long patterns with nested parentheses, in
# order to test workspace overflow. Again, this varies with code unit width,
-# and even with it fails in two modes, the error offset differs. It also varies
+# and even when it fails in two modes, the error offset differs. It also varies
# with link size - hence multiple tests with different values.

-/(?'ABC'\[[bar](]{105}*THEN:\[A]{255}\[)]{106}/expand,-fullbincode
+/(?'ABC'\[[bar](]{792}*THEN:\[A]{255}\[)]{793}/expand,-fullbincode,parens_nest_limit=1000
+Failed: error 186 at offset 5813: regular expression is too complicated

-/(?'ABC'\[[bar](]{106}*THEN:\[A]{255}\[)]{107}/expand,-fullbincode
+/(?'ABC'\[[bar](]{793}*THEN:\[A]{255}\[)]{794}/expand,-fullbincode,parens_nest_limit=1000
+Failed: error 186 at offset 5820: regular expression is too complicated

-/(?'ABC'\[[bar](]{159}*THEN:\[A]{255}\[)]{160}/expand,-fullbincode
+/(?'ABC'\[[bar](]{1793}*THEN:\[A]{255}\[)]{1794}/expand,-fullbincode,parens_nest_limit=2000
+Failed: error 186 at offset 12820: regular expression is too complicated

-/(?'ABC'\[[bar](]{199}*THEN:\[A]{255}\[)]{200}/expand,-fullbincode
-Failed: error 186 at offset 979: regular expression is too complicated
-
-/(?'ABC'\[[bar](]{299}*THEN:\[A]{255}\[)]{300}/expand,-fullbincode
-Failed: error 186 at offset 979: regular expression is too complicated
-
/(?(1)(?1)){8,}+()/debug
------------------------------------------------------------------
0 79 Bra

Modified: code/trunk/testdata/testoutput8-8-2
===================================================================
--- code/trunk/testdata/testoutput8-8-2    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testoutput8-8-2    2016-10-02 16:01:01 UTC (rev 555)
@@ -854,23 +854,17 @@


# Use "expand" to create some very long patterns with nested parentheses, in
# order to test workspace overflow. Again, this varies with code unit width,
-# and even with it fails in two modes, the error offset differs. It also varies
+# and even when it fails in two modes, the error offset differs. It also varies
# with link size - hence multiple tests with different values.

-/(?'ABC'\[[bar](]{105}*THEN:\[A]{255}\[)]{106}/expand,-fullbincode
+/(?'ABC'\[[bar](]{792}*THEN:\[A]{255}\[)]{793}/expand,-fullbincode,parens_nest_limit=1000

-/(?'ABC'\[[bar](]{106}*THEN:\[A]{255}\[)]{107}/expand,-fullbincode
-Failed: error 186 at offset 637: regular expression is too complicated
+/(?'ABC'\[[bar](]{793}*THEN:\[A]{255}\[)]{794}/expand,-fullbincode,parens_nest_limit=1000
+Failed: error 186 at offset 5820: regular expression is too complicated

-/(?'ABC'\[[bar](]{159}*THEN:\[A]{255}\[)]{160}/expand,-fullbincode
-Failed: error 186 at offset 637: regular expression is too complicated
+/(?'ABC'\[[bar](]{1793}*THEN:\[A]{255}\[)]{1794}/expand,-fullbincode,parens_nest_limit=2000
+Failed: error 186 at offset 12820: regular expression is too complicated

-/(?'ABC'\[[bar](]{199}*THEN:\[A]{255}\[)]{200}/expand,-fullbincode
-Failed: error 186 at offset 637: regular expression is too complicated
-
-/(?'ABC'\[[bar](]{299}*THEN:\[A]{255}\[)]{300}/expand,-fullbincode
-Failed: error 186 at offset 637: regular expression is too complicated
-
/(?(1)(?1)){8,}+()/debug
------------------------------------------------------------------
0 119 Bra

Modified: code/trunk/testdata/testoutput8-8-3
===================================================================
--- code/trunk/testdata/testoutput8-8-3    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testoutput8-8-3    2016-10-02 16:01:01 UTC (rev 555)
@@ -853,22 +853,16 @@


# Use "expand" to create some very long patterns with nested parentheses, in
# order to test workspace overflow. Again, this varies with code unit width,
-# and even with it fails in two modes, the error offset differs. It also varies
+# and even when it fails in two modes, the error offset differs. It also varies
# with link size - hence multiple tests with different values.

-/(?'ABC'\[[bar](]{105}*THEN:\[A]{255}\[)]{106}/expand,-fullbincode
+/(?'ABC'\[[bar](]{792}*THEN:\[A]{255}\[)]{793}/expand,-fullbincode,parens_nest_limit=1000

-/(?'ABC'\[[bar](]{106}*THEN:\[A]{255}\[)]{107}/expand,-fullbincode
+/(?'ABC'\[[bar](]{793}*THEN:\[A]{255}\[)]{794}/expand,-fullbincode,parens_nest_limit=1000

-/(?'ABC'\[[bar](]{159}*THEN:\[A]{255}\[)]{160}/expand,-fullbincode
-Failed: error 186 at offset 936: regular expression is too complicated
+/(?'ABC'\[[bar](]{1793}*THEN:\[A]{255}\[)]{1794}/expand,-fullbincode,parens_nest_limit=2000
+Failed: error 186 at offset 12820: regular expression is too complicated

-/(?'ABC'\[[bar](]{199}*THEN:\[A]{255}\[)]{200}/expand,-fullbincode
-Failed: error 186 at offset 936: regular expression is too complicated
-
-/(?'ABC'\[[bar](]{299}*THEN:\[A]{255}\[)]{300}/expand,-fullbincode
-Failed: error 186 at offset 936: regular expression is too complicated
-
/(?(1)(?1)){8,}+()/debug
------------------------------------------------------------------
0 150 Bra

Modified: code/trunk/testdata/testoutput8-8-4
===================================================================
--- code/trunk/testdata/testoutput8-8-4    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testoutput8-8-4    2016-10-02 16:01:01 UTC (rev 555)
@@ -853,20 +853,16 @@


# Use "expand" to create some very long patterns with nested parentheses, in
# order to test workspace overflow. Again, this varies with code unit width,
-# and even with it fails in two modes, the error offset differs. It also varies
+# and even when it fails in two modes, the error offset differs. It also varies
# with link size - hence multiple tests with different values.

-/(?'ABC'\[[bar](]{105}*THEN:\[A]{255}\[)]{106}/expand,-fullbincode
+/(?'ABC'\[[bar](]{792}*THEN:\[A]{255}\[)]{793}/expand,-fullbincode,parens_nest_limit=1000

-/(?'ABC'\[[bar](]{106}*THEN:\[A]{255}\[)]{107}/expand,-fullbincode
+/(?'ABC'\[[bar](]{793}*THEN:\[A]{255}\[)]{794}/expand,-fullbincode,parens_nest_limit=1000

-/(?'ABC'\[[bar](]{159}*THEN:\[A]{255}\[)]{160}/expand,-fullbincode
+/(?'ABC'\[[bar](]{1793}*THEN:\[A]{255}\[)]{1794}/expand,-fullbincode,parens_nest_limit=2000
+Failed: error 186 at offset 12820: regular expression is too complicated

-/(?'ABC'\[[bar](]{199}*THEN:\[A]{255}\[)]{200}/expand,-fullbincode
-
-/(?'ABC'\[[bar](]{299}*THEN:\[A]{255}\[)]{300}/expand,-fullbincode
-Failed: error 186 at offset 1224: regular expression is too complicated
-
/(?(1)(?1)){8,}+()/debug
------------------------------------------------------------------
0 181 Bra

Modified: code/trunk/testdata/testoutput9
===================================================================
--- code/trunk/testdata/testoutput9    2016-08-03 17:22:59 UTC (rev 554)
+++ code/trunk/testdata/testoutput9    2016-10-02 16:01:01 UTC (rev 555)
@@ -307,7 +307,7 @@
 ------------------------------------------------------------------


/\777/I
-Failed: error 151 at offset 3: octal value is greater than \377 in 8-bit non-UTF-8 mode
+Failed: error 151 at offset 4: octal value is greater than \377 in 8-bit non-UTF-8 mode

 /(*:0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF)XX/mark
 Failed: error 176 at offset 259: name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)
@@ -314,7 +314,7 @@
     XX


 /(*:0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF)XX/mark,alt_verbnames
-Failed: error 176 at offset 258: name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)
+Failed: error 176 at offset 259: name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)
     XX


/(*:0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE)XX/mark
@@ -328,10 +328,10 @@
MK: 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE

/\u0100/alt_bsux,allow_empty_class,match_unset_backref,dupnames
-Failed: error 177 at offset 5: character code point value in \u.... sequence is too large
+Failed: error 177 at offset 6: character code point value in \u.... sequence is too large

/[\u0100-\u0200]/alt_bsux,allow_empty_class,match_unset_backref,dupnames
-Failed: error 177 at offset 6: character code point value in \u.... sequence is too large
+Failed: error 177 at offset 7: character code point value in \u.... sequence is too large

/[^\x00-a]{12,}[^b-\xff]*/B
------------------------------------------------------------------