This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
tweak to use SIZE_ONLY
[perl5.git] / regcomp.c
index 9c9fc14..c0425b7 100644 (file)
--- a/regcomp.c
+++ b/regcomp.c
@@ -41,6 +41,8 @@
 #  define Perl_regnext my_regnext
 #  define Perl_save_re_context my_save_re_context
 #  define Perl_reginitcolors my_reginitcolors 
+
+#  define PERL_NO_GET_CONTEXT
 #endif 
 
 /*SUPPRESS 112*/
@@ -67,7 +69,7 @@
  *
  ****    Alterations to Henry's code are...
  ****
- ****    Copyright (c) 1991-1999, Larry Wall
+ ****    Copyright (c) 1991-2000, Larry Wall
  ****
  ****    You may distribute under the terms of either the GNU General Public
  ****    License or the Artistic License, as specified in the README file.
 #define PERL_IN_REGCOMP_C
 #include "perl.h"
 
-#ifndef PERL_IN_XSUB_RE
+#ifdef PERL_IN_XSUB_RE
+#  if defined(PERL_CAPI) || defined(PERL_OBJECT)
+#    include "XSUB.h"
+#  endif
+#else
 #  include "INTERN.h"
 #endif
 
 #define        SPSTART         0x4     /* Starts with * or +. */
 #define TRYAGAIN       0x8     /* Weeded out a declaration. */
 
+/* Length of a variant. */
+
+typedef struct scan_data_t {
+    I32 len_min;
+    I32 len_delta;
+    I32 pos_min;
+    I32 pos_delta;
+    SV *last_found;
+    I32 last_end;                      /* min value, <0 unless valid. */
+    I32 last_start_min;
+    I32 last_start_max;
+    SV **longest;                      /* Either &l_fixed, or &l_float. */
+    SV *longest_fixed;
+    I32 offset_fixed;
+    SV *longest_float;
+    I32 offset_float_min;
+    I32 offset_float_max;
+    I32 flags;
+    I32 whilem_c;
+    struct regnode_charclass_class *start_class;
+} scan_data_t;
+
 /*
  * Forward declarations for pregcomp()'s friends.
  */
 
 static scan_data_t zero_scan_data = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-                                     0, 0, 0 };
+                                     0, 0, 0, 0, 0 };
 
 #define SF_BEFORE_EOL          (SF_BEFORE_SEOL|SF_BEFORE_MEOL)
 #define SF_BEFORE_SEOL         0x1
@@ -157,6 +185,9 @@ static scan_data_t zero_scan_data = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 #define SF_IN_PAR              0x100
 #define SF_HAS_EVAL            0x200
 #define SCF_DO_SUBSTR          0x400
+#define SCF_DO_STCLASS_AND     0x0800
+#define SCF_DO_STCLASS_OR      0x1000
+#define SCF_DO_STCLASS         (SCF_DO_STCLASS_AND|SCF_DO_STCLASS_OR)
 
 #define RF_utf8                8
 #define UTF (PL_reg_flags & RF_utf8)
@@ -165,15 +196,19 @@ static scan_data_t zero_scan_data = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
 #define OOB_CHAR8              1234
 #define OOB_UTF8               123456
+#define OOB_NAMEDCLASS         -1
 
 #define CHR_SVLEN(sv) (UTF ? sv_len_utf8(sv) : SvCUR(sv))
 #define CHR_DIST(a,b) (UTF ? utf8_distance(a,b) : a - b)
 
-STATIC void
-S_clear_re(pTHX_ void *r)
-{
-    ReREFCNT_dec((regexp *)r);
-}
+/* Allow for side effects in s */
+#define REGC(c,s) STMT_START { if (!SIZE_ONLY) *(s) = (c); else (s);} STMT_END
+
+static void clear_re(pTHXo_ void *r);
+
+/* Mark that we cannot extend a found fixed substring at this point.
+   Updata the longest found anchored substring and the longest found
+   floating substrings if needed. */
 
 STATIC void
 S_scan_commit(pTHX_ scan_data_t *data)
@@ -209,6 +244,131 @@ S_scan_commit(pTHX_ scan_data_t *data)
     data->flags &= ~SF_BEFORE_EOL;
 }
 
+/* Can match anything (initialization) */
+STATIC void
+S_cl_anything(pTHX_ struct regnode_charclass_class *cl)
+{
+    int value;
+
+    ANYOF_CLASS_ZERO(cl);
+    for (value = 0; value < 256; ++value)
+       ANYOF_BITMAP_SET(cl, value);
+    cl->flags = ANYOF_EOS;
+    if (LOC)
+       cl->flags |= ANYOF_LOCALE;
+}
+
+/* Can match anything (initialization) */
+STATIC int
+S_cl_is_anything(pTHX_ struct regnode_charclass_class *cl)
+{
+    int value;
+
+    for (value = 0; value < ANYOF_MAX; value += 2)
+       if (ANYOF_CLASS_TEST(cl, value) && ANYOF_CLASS_TEST(cl, value + 1))
+           return 1;
+    for (value = 0; value < 256; ++value)
+       if (!ANYOF_BITMAP_TEST(cl, value))
+           return 0;
+    return 1;
+}
+
+/* Can match anything (initialization) */
+STATIC void
+S_cl_init(pTHX_ struct regnode_charclass_class *cl)
+{
+    Zero(cl, 1, struct regnode_charclass_class);
+    cl->type = ANYOF;
+    cl_anything(cl);
+}
+
+STATIC void
+S_cl_init_zero(pTHX_ struct regnode_charclass_class *cl)
+{
+    Zero(cl, 1, struct regnode_charclass_class);
+    cl->type = ANYOF;
+    cl_anything(cl);
+    if (LOC)
+       cl->flags |= ANYOF_LOCALE;
+}
+
+/* 'And' a given class with another one.  Can create false positives */
+/* We assume that cl is not inverted */
+STATIC void
+S_cl_and(pTHX_ struct regnode_charclass_class *cl,
+        struct regnode_charclass_class *and_with)
+{
+    if (!(and_with->flags & ANYOF_CLASS)
+       && !(cl->flags & ANYOF_CLASS)
+       && (and_with->flags & ANYOF_LOCALE) == (cl->flags & ANYOF_LOCALE)
+       && !(and_with->flags & ANYOF_FOLD)
+       && !(cl->flags & ANYOF_FOLD)) {
+       int i;
+
+       if (and_with->flags & ANYOF_INVERT)
+           for (i = 0; i < ANYOF_BITMAP_SIZE; i++)
+               cl->bitmap[i] &= ~and_with->bitmap[i];
+       else
+           for (i = 0; i < ANYOF_BITMAP_SIZE; i++)
+               cl->bitmap[i] &= and_with->bitmap[i];
+    } /* XXXX: logic is complicated otherwise, leave it along for a moment. */
+    if (!(and_with->flags & ANYOF_EOS))
+       cl->flags &= ~ANYOF_EOS;
+}
+
+/* 'OR' a given class with another one.  Can create false positives */
+/* We assume that cl is not inverted */
+STATIC void
+S_cl_or(pTHX_ struct regnode_charclass_class *cl, struct regnode_charclass_class *or_with)
+{
+    if (or_with->flags & ANYOF_INVERT) {
+       /* We do not use
+        * (B1 | CL1) | (!B2 & !CL2) = (B1 | !B2 & !CL2) | (CL1 | (!B2 & !CL2))
+        *   <= (B1 | !B2) | (CL1 | !CL2)
+        * which is wasteful if CL2 is small, but we ignore CL2:
+        *   (B1 | CL1) | (!B2 & !CL2) <= (B1 | CL1) | !B2 = (B1 | !B2) | CL1
+        * XXXX Can we handle case-fold?  Unclear:
+        *   (OK1(i) | OK1(i')) | !(OK1(i) | OK1(i')) =
+        *   (OK1(i) | OK1(i')) | (!OK1(i) & !OK1(i'))
+        */
+       if ( (or_with->flags & ANYOF_LOCALE) == (cl->flags & ANYOF_LOCALE)
+            && !(or_with->flags & ANYOF_FOLD)
+            && !(cl->flags & ANYOF_FOLD) ) {
+           int i;
+
+           for (i = 0; i < ANYOF_BITMAP_SIZE; i++)
+               cl->bitmap[i] |= ~or_with->bitmap[i];
+       } /* XXXX: logic is complicated otherwise */
+       else {
+           cl_anything(cl);
+       }
+    } else {
+       /* (B1 | CL1) | (B2 | CL2) = (B1 | B2) | (CL1 | CL2)) */
+       if ( (or_with->flags & ANYOF_LOCALE) == (cl->flags & ANYOF_LOCALE)
+            && (!(or_with->flags & ANYOF_FOLD) 
+                || (cl->flags & ANYOF_FOLD)) ) {
+           int i;
+
+           /* OR char bitmap and class bitmap separately */
+           for (i = 0; i < ANYOF_BITMAP_SIZE; i++)
+               cl->bitmap[i] |= or_with->bitmap[i];
+           if (or_with->flags & ANYOF_CLASS) {
+               for (i = 0; i < ANYOF_CLASSBITMAP_SIZE; i++)
+                   cl->classflags[i] |= or_with->classflags[i];
+               cl->flags |= ANYOF_CLASS;
+           }
+       }
+       else { /* XXXX: logic is complicated, leave it along for a moment. */
+           cl_anything(cl);
+       }
+    }
+    if (or_with->flags & ANYOF_EOS)
+       cl->flags |= ANYOF_EOS;
+}
+
+/* REx optimizer.  Converts nodes into quickier variants "in place".
+   Finds fixed substrings.  */
+
 /* Stops at toplevel WHILEM as well as at `last'. At end *scanp is set
    to the position after last scanned or to NULL. */
 
@@ -226,18 +386,20 @@ S_study_chunk(pTHX_ regnode **scanp, I32 *deltap, regnode *last, scan_data_t *da
     int is_inf_internal = 0;           /* The studied chunk is infinite */
     I32 is_par = OP(scan) == OPEN ? ARG(scan) : 0;
     scan_data_t data_fake;
+    struct regnode_charclass_class and_with; /* Valid if flags & SCF_DO_STCLASS_OR */
     
     while (scan && OP(scan) != END && scan < last) {
        /* Peephole optimizer: */
 
        if (PL_regkind[(U8)OP(scan)] == EXACT) {
+           /* Merge several consecutive EXACTish nodes into one. */
            regnode *n = regnext(scan);
            U32 stringok = 1;
 #ifdef DEBUGGING
            regnode *stop = scan;
 #endif 
 
-           next = scan + (*OPERAND(scan) + 2 - 1)/sizeof(regnode) + 2;
+           next = scan + NODE_SZ_STR(scan);
            /* Skip NOTHING, merge EXACT*. */
            while (n &&
                   ( PL_regkind[(U8)OP(n)] == NOTHING || 
@@ -256,17 +418,17 @@ S_study_chunk(pTHX_ regnode **scanp, I32 *deltap, regnode *last, scan_data_t *da
                    n = regnext(n);
                }
                else {
-                   int oldl = *OPERAND(scan);
+                   int oldl = STR_LEN(scan);
                    regnode *nnext = regnext(n);
                    
-                   if (oldl + *OPERAND(n) > U8_MAX) 
+                   if (oldl + STR_LEN(n) > U8_MAX) 
                        break;
                    NEXT_OFF(scan) += NEXT_OFF(n);
-                   *OPERAND(scan) += *OPERAND(n);
-                   next = n + (*OPERAND(n) + 2 - 1)/sizeof(regnode) + 2;
+                   STR_LEN(scan) += STR_LEN(n);
+                   next = n + NODE_SZ_STR(n);
                    /* Now we can overwrite *n : */
-                   Move(OPERAND(n) + 1, OPERAND(scan) + oldl + 1,
-                        *OPERAND(n) + 1, char);
+                   Move(STRING(n), STRING(scan) + oldl,
+                        STR_LEN(n), char);
 #ifdef DEBUGGING
                    if (stringok)
                        stop = next - 1;
@@ -276,21 +438,18 @@ S_study_chunk(pTHX_ regnode **scanp, I32 *deltap, regnode *last, scan_data_t *da
            }
 #ifdef DEBUGGING
            /* Allow dumping */
-           n = scan + (*OPERAND(scan) + 2 - 1)/sizeof(regnode) + 2;
+           n = scan + NODE_SZ_STR(scan);
            while (n <= stop) {
-               /* Purify reports a benign UMR here sometimes, because we
-                * don't initialize the OP() slot of a node when that node
-                * is occupied by just the trailing null of the string in
-                * an EXACT node */
                if (PL_regkind[(U8)OP(n)] != NOTHING || OP(n) == NOTHING) {
                    OP(n) = OPTIMIZED;
                    NEXT_OFF(n) = 0;
                }
                n++;
            }
-#endif 
-
+#endif
        }
+       /* Follow the next-chain of the current node and optimize
+          away all the NOTHINGs from it.  */
        if (OP(scan) != CURLYX) {
            int max = (reg_off_by_arg[OP(scan)]
                       ? I32_MAX
@@ -311,6 +470,8 @@ S_study_chunk(pTHX_ regnode **scanp, I32 *deltap, regnode *last, scan_data_t *da
            else 
                NEXT_OFF(scan) = off;
        }
+       /* The principal pseudo-switch.  Cannot be a switch, since we
+          look into several different things.  */
        if (OP(scan) == BRANCH || OP(scan) == BRANCHJ 
                   || OP(scan) == IFTHEN || OP(scan) == SUSPEND) {
            next = regnext(scan);
@@ -318,21 +479,32 @@ S_study_chunk(pTHX_ regnode **scanp, I32 *deltap, regnode *last, scan_data_t *da
            
            if (OP(next) == code || code == IFTHEN || code == SUSPEND) { 
                I32 max1 = 0, min1 = I32_MAX, num = 0;
+               struct regnode_charclass_class accum;
                
-               if (flags & SCF_DO_SUBSTR)
-                   scan_commit(data);
+               if (flags & SCF_DO_SUBSTR) /* XXXX Add !SUSPEND? */
+                   scan_commit(data);  /* Cannot merge strings after this. */
+               if (flags & SCF_DO_STCLASS)
+                   cl_init_zero(&accum);
                while (OP(scan) == code) {
-                   I32 deltanext, minnext;
+                   I32 deltanext, minnext, f = 0;
+                   struct regnode_charclass_class this_class;
 
                    num++;
                    data_fake.flags = 0;
+                   if (data)
+                       data_fake.whilem_c = data->whilem_c;
                    next = regnext(scan);
                    scan = NEXTOPER(scan);
                    if (code != BRANCH)
                        scan = NEXTOPER(scan);
-                   /* We suppose the run is continuous, last=next...*/
+                   if (flags & SCF_DO_STCLASS) {
+                       cl_init(&this_class);
+                       data_fake.start_class = &this_class;
+                       f = SCF_DO_STCLASS_AND;
+                   }               
+                   /* we suppose the run is continuous, last=next...*/
                    minnext = study_chunk(&scan, &deltanext, next,
-                                         &data_fake, 0);
+                                         &data_fake, f);
                    if (min1 > minnext) 
                        min1 = minnext;
                    if (max1 < minnext + deltanext)
@@ -344,6 +516,10 @@ S_study_chunk(pTHX_ regnode **scanp, I32 *deltap, regnode *last, scan_data_t *da
                        pars++;
                    if (data && (data_fake.flags & SF_HAS_EVAL))
                        data->flags |= SF_HAS_EVAL;
+                   if (data)
+                       data->whilem_c = data_fake.whilem_c;
+                   if (flags & SCF_DO_STCLASS)
+                       cl_or(&accum, &this_class);
                    if (code == SUSPEND) 
                        break;
                }
@@ -357,6 +533,30 @@ S_study_chunk(pTHX_ regnode **scanp, I32 *deltap, regnode *last, scan_data_t *da
                }
                min += min1;
                delta += max1 - min1;
+               if (flags & SCF_DO_STCLASS_OR) {
+                   cl_or(data->start_class, &accum);
+                   if (min1) {
+                       cl_and(data->start_class, &and_with);
+                       flags &= ~SCF_DO_STCLASS;
+                   }
+               }
+               else if (flags & SCF_DO_STCLASS_AND) {
+                   if (min1) {
+                       cl_and(data->start_class, &accum);
+                       flags &= ~SCF_DO_STCLASS;
+                   }
+                   else {
+                       /* Switch to OR mode: cache the old value of 
+                        * data->start_class */
+                       StructCopy(data->start_class, &and_with,
+                                  struct regnode_charclass_class);
+                       flags &= ~SCF_DO_STCLASS_AND;
+                       StructCopy(&accum, data->start_class,
+                                  struct regnode_charclass_class);
+                       flags |= SCF_DO_STCLASS_OR;
+                       data->start_class->flags |= ANYOF_EOS;
+                   }
+               }
            }
            else if (code == BRANCHJ)   /* single branch is optimized. */
                scan = NEXTOPER(NEXTOPER(scan));
@@ -365,9 +565,9 @@ S_study_chunk(pTHX_ regnode **scanp, I32 *deltap, regnode *last, scan_data_t *da
            continue;
        }
        else if (OP(scan) == EXACT) {
-           I32 l = *OPERAND(scan);
+           I32 l = STR_LEN(scan);
            if (UTF) {
-               unsigned char *s = (unsigned char *)(OPERAND(scan)+1);
+               unsigned char *s = (unsigned char *)STRING(scan);
                unsigned char *e = s + l;
                I32 newl = 0;
                while (s < e) {
@@ -385,18 +585,43 @@ S_study_chunk(pTHX_ regnode **scanp, I32 *deltap, regnode *last, scan_data_t *da
                    data->last_start_max = is_inf
                        ? I32_MAX : data->pos_min + data->pos_delta; 
                }
-               sv_catpvn(data->last_found, (char *)(OPERAND(scan)+1), *OPERAND(scan));
+               sv_catpvn(data->last_found, STRING(scan), STR_LEN(scan));
                data->last_end = data->pos_min + l;
                data->pos_min += l; /* As in the first entry. */
                data->flags &= ~SF_BEFORE_EOL;
            }
+           if (flags & SCF_DO_STCLASS_AND) {
+               /* Check whether it is compatible with what we know already! */
+               int compat = 1;
+
+               if (!(data->start_class->flags & (ANYOF_CLASS | ANYOF_LOCALE)) 
+                   && !ANYOF_BITMAP_TEST(data->start_class, *STRING(scan))
+                   && (!(data->start_class->flags & ANYOF_FOLD)
+                       || !ANYOF_BITMAP_TEST(data->start_class,
+                                             PL_fold[*(U8*)STRING(scan)])))
+                   compat = 0;
+               ANYOF_CLASS_ZERO(data->start_class);
+               ANYOF_BITMAP_ZERO(data->start_class);
+               if (compat)
+                   ANYOF_BITMAP_SET(data->start_class, *STRING(scan));
+               data->start_class->flags &= ~ANYOF_EOS;
+           }
+           else if (flags & SCF_DO_STCLASS_OR) {
+               /* false positive possible if the class is case-folded */
+               ANYOF_BITMAP_SET(data->start_class, *STRING(scan));     
+               data->start_class->flags &= ~ANYOF_EOS;
+               cl_and(data->start_class, &and_with);
+           }
+           flags &= ~SCF_DO_STCLASS;
        }
-       else if (PL_regkind[(U8)OP(scan)] == EXACT) {
-           I32 l = *OPERAND(scan);
+       else if (PL_regkind[(U8)OP(scan)] == EXACT) { /* But OP != EXACT! */
+           I32 l = STR_LEN(scan);
+
+           /* Search for fixed substrings supports EXACT only. */
            if (flags & SCF_DO_SUBSTR) 
                scan_commit(data);
            if (UTF) {
-               unsigned char *s = (unsigned char *)(OPERAND(scan)+1);
+               unsigned char *s = (unsigned char *)STRING(scan);
                unsigned char *e = s + l;
                I32 newl = 0;
                while (s < e) {
@@ -408,19 +633,51 @@ S_study_chunk(pTHX_ regnode **scanp, I32 *deltap, regnode *last, scan_data_t *da
            min += l;
            if (data && (flags & SCF_DO_SUBSTR))
                data->pos_min += l;
+           if (flags & SCF_DO_STCLASS_AND) {
+               /* Check whether it is compatible with what we know already! */
+               int compat = 1;
+
+               if (!(data->start_class->flags & (ANYOF_CLASS | ANYOF_LOCALE)) 
+                   && !ANYOF_BITMAP_TEST(data->start_class, *STRING(scan))
+                   && !ANYOF_BITMAP_TEST(data->start_class, 
+                                         PL_fold[*(U8*)STRING(scan)]))
+                   compat = 0;
+               ANYOF_CLASS_ZERO(data->start_class);
+               ANYOF_BITMAP_ZERO(data->start_class);
+               if (compat) {
+                   ANYOF_BITMAP_SET(data->start_class, *STRING(scan));
+                   data->start_class->flags &= ~ANYOF_EOS;
+                   data->start_class->flags |= ANYOF_FOLD;
+                   if (OP(scan) == EXACTFL)
+                       data->start_class->flags |= ANYOF_LOCALE;
+               }
+           }
+           else if (flags & SCF_DO_STCLASS_OR) {
+               if (data->start_class->flags & ANYOF_FOLD) {
+                   /* false positive possible if the class is case-folded.
+                      Assume that the locale settings are the same... */
+                   ANYOF_BITMAP_SET(data->start_class, *STRING(scan)); 
+                   data->start_class->flags &= ~ANYOF_EOS;
+               }
+               cl_and(data->start_class, &and_with);
+           }
+           flags &= ~SCF_DO_STCLASS;
        }
        else if (strchr((char*)PL_varies,OP(scan))) {
            I32 mincount, maxcount, minnext, deltanext, pos_before, fl;
+           I32 f = flags;
            regnode *oscan = scan;
-           
+           struct regnode_charclass_class this_class;
+           struct regnode_charclass_class *oclass = NULL;
+
            switch (PL_regkind[(U8)OP(scan)]) {
-           case WHILEM:
+           case WHILEM:                /* End of (?:...)* . */
                scan = NEXTOPER(scan);
                goto finish;
            case PLUS:
-               if (flags & SCF_DO_SUBSTR) {
+               if (flags & (SCF_DO_SUBSTR | SCF_DO_STCLASS)) {
                    next = NEXTOPER(scan);
-                   if (OP(next) == EXACT) {
+                   if (OP(next) == EXACT || (flags & SCF_DO_STCLASS)) {
                        mincount = 1; 
                        maxcount = REG_INFTY; 
                        next = regnext(scan);
@@ -433,10 +690,17 @@ S_study_chunk(pTHX_ regnode **scanp, I32 *deltap, regnode *last, scan_data_t *da
                min++;
                /* Fall through. */
            case STAR:
+               if (flags & SCF_DO_STCLASS) {
+                   mincount = 0;
+                   maxcount = REG_INFTY; 
+                   next = regnext(scan);
+                   scan = NEXTOPER(scan);
+                   goto do_curly;
+               }
                is_inf = is_inf_internal = 1; 
                scan = regnext(scan);
                if (flags & SCF_DO_SUBSTR) {
-                   scan_commit(data);
+                   scan_commit(data);  /* Cannot extend fixed substrings */
                    data->longest = &(data->longest_float);
                }
                goto optimize_curly_tail;
@@ -447,7 +711,7 @@ S_study_chunk(pTHX_ regnode **scanp, I32 *deltap, regnode *last, scan_data_t *da
                scan = NEXTOPER(scan) + EXTRA_STEP_2ARGS;
              do_curly:
                if (flags & SCF_DO_SUBSTR) {
-                   if (mincount == 0) scan_commit(data);
+                   if (mincount == 0) scan_commit(data); /* Cannot extend fixed substrings */
                    pos_before = data->pos_min;
                }
                if (data) {
@@ -456,20 +720,56 @@ S_study_chunk(pTHX_ regnode **scanp, I32 *deltap, regnode *last, scan_data_t *da
                    if (is_inf)
                        data->flags |= SF_IS_INF;
                }
+               if (flags & SCF_DO_STCLASS) {
+                   cl_init(&this_class);
+                   oclass = data->start_class;
+                   data->start_class = &this_class;
+                   f |= SCF_DO_STCLASS_AND;
+                   f &= ~SCF_DO_STCLASS_OR;
+               }
+
                /* This will finish on WHILEM, setting scan, or on NULL: */
                minnext = study_chunk(&scan, &deltanext, last, data, 
                                      mincount == 0 
-                                       ? (flags & ~SCF_DO_SUBSTR) : flags);
+                                       ? (f & ~SCF_DO_SUBSTR) : f);
+
+               if (flags & SCF_DO_STCLASS)
+                   data->start_class = oclass;
+               if (mincount == 0 || minnext == 0) {
+                   if (flags & SCF_DO_STCLASS_OR) {
+                       cl_or(data->start_class, &this_class);
+                   }
+                   else if (flags & SCF_DO_STCLASS_AND) {
+                       /* Switch to OR mode: cache the old value of 
+                        * data->start_class */
+                       StructCopy(data->start_class, &and_with,
+                                  struct regnode_charclass_class);
+                       flags &= ~SCF_DO_STCLASS_AND;
+                       StructCopy(&this_class, data->start_class,
+                                  struct regnode_charclass_class);
+                       flags |= SCF_DO_STCLASS_OR;
+                       data->start_class->flags |= ANYOF_EOS;
+                   }
+               } else {                /* Non-zero len */
+                   if (flags & SCF_DO_STCLASS_OR) {
+                       cl_or(data->start_class, &this_class);
+                       cl_and(data->start_class, &and_with);
+                   }
+                   else if (flags & SCF_DO_STCLASS_AND)
+                       cl_and(data->start_class, &this_class);
+                   flags &= ~SCF_DO_STCLASS;
+               }
                if (!scan)              /* It was not CURLYX, but CURLY. */
                    scan = next;
-               if (ckWARN(WARN_UNSAFE) && (minnext + deltanext == 0) 
+               if (ckWARN(WARN_REGEXP) && (minnext + deltanext == 0) 
                    && !(data->flags & (SF_HAS_PAR|SF_IN_PAR))
                    && maxcount <= REG_INFTY/3) /* Complement check for big count */
-                   Perl_warner(aTHX_ WARN_UNSAFE, "Strange *+?{} on zero-length expression");
+                   Perl_warner(aTHX_ WARN_REGEXP,
+                               "Strange *+?{} on zero-length expression");
                min += minnext * mincount;
-               is_inf_internal |= (maxcount == REG_INFTY 
-                                   && (minnext + deltanext) > 0
-                                  || deltanext == I32_MAX);
+               is_inf_internal |= ((maxcount == REG_INFTY 
+                                    && (minnext + deltanext) > 0)
+                                   || deltanext == I32_MAX);
                is_inf |= is_inf_internal;
                delta += (minnext + deltanext) * maxcount - minnext * mincount;
 
@@ -486,7 +786,7 @@ S_study_chunk(pTHX_ regnode **scanp, I32 *deltap, regnode *last, scan_data_t *da
                    nxt = regnext(nxt);
                    if (!strchr((char*)PL_simple,OP(nxt))
                        && !(PL_regkind[(U8)OP(nxt)] == EXACT
-                            && *OPERAND(nxt) == 1)) 
+                            && STR_LEN(nxt) == 1)) 
                        goto nogo;
                    nxt2 = nxt;
                    nxt = regnext(nxt);
@@ -559,6 +859,16 @@ S_study_chunk(pTHX_ regnode **scanp, I32 *deltap, regnode *last, scan_data_t *da
                    else
                        oscan->flags = 0;
                }
+               else if (OP(oscan) == CURLYX && data && ++data->whilem_c < 16) {
+                   /* This stays as CURLYX, and can put the count/of pair. */
+                   /* Find WHILEM (as in regexec.c) */
+                   regnode *nxt = oscan + NEXT_OFF(oscan);
+
+                   if (OP(PREVOPER(nxt)) == NOTHING) /* LONGJMP */
+                       nxt += ARG(nxt);
+                   PREVOPER(nxt)->flags = data->whilem_c
+                       | (PL_reg_whilem_seen << 4); /* On WHILEM */
+               }
                if (data && fl & (SF_HAS_PAR|SF_IN_PAR)) 
                    pars++;
                if (flags & SCF_DO_SUBSTR) {
@@ -598,6 +908,8 @@ S_study_chunk(pTHX_ regnode **scanp, I32 *deltap, regnode *last, scan_data_t *da
                    data->pos_delta += - counted * deltanext +
                        (minnext + deltanext) * maxcount - minnext * mincount;
                    if (mincount != maxcount) {
+                        /* Cannot extend fixed substrings found inside
+                           the group.  */
                        scan_commit(data);
                        if (mincount && last_str) {
                            sv_setsv(data->last_found, last_str);
@@ -622,43 +934,264 @@ S_study_chunk(pTHX_ regnode **scanp, I32 *deltap, regnode *last, scan_data_t *da
                        NEXT_OFF(oscan) += NEXT_OFF(next);
                }
                continue;
-           default:                    /* REF only? */
+           default:                    /* REF and CLUMP only? */
                if (flags & SCF_DO_SUBSTR) {
-                   scan_commit(data);
+                   scan_commit(data);  /* Cannot expect anything... */
                    data->longest = &(data->longest_float);
                }
                is_inf = is_inf_internal = 1;
+               if (flags & SCF_DO_STCLASS_OR)
+                   cl_anything(data->start_class);
+               flags &= ~SCF_DO_STCLASS;
                break;
            }
        }
        else if (strchr((char*)PL_simple,OP(scan)) || PL_regkind[(U8)OP(scan)] == ANYUTF8) {
+           int value;
+
            if (flags & SCF_DO_SUBSTR) {
                scan_commit(data);
                data->pos_min++;
            }
            min++;
+           if (flags & SCF_DO_STCLASS) {
+               data->start_class->flags &= ~ANYOF_EOS; /* No match on empty */
+
+               /* Some of the logic below assumes that switching
+                  locale on will only add false positives. */
+               switch (PL_regkind[(U8)OP(scan)]) {
+               case ANYUTF8:
+               case SANY:
+               case SANYUTF8:
+               case ALNUMUTF8:
+               case ANYOFUTF8:
+               case ALNUMLUTF8:
+               case NALNUMUTF8:
+               case NALNUMLUTF8:
+               case SPACEUTF8:
+               case NSPACEUTF8:
+               case SPACELUTF8:
+               case NSPACELUTF8:
+               case DIGITUTF8:
+               case NDIGITUTF8:
+               default:
+                 do_default:
+                   /* Perl_croak(aTHX_ "panic: unexpected simple REx opcode %d", OP(scan)); */
+                   if (flags & SCF_DO_STCLASS_OR) /* Allow everything */
+                       cl_anything(data->start_class);
+                   break;
+               case REG_ANY:
+                   if (OP(scan) == SANY)
+                       goto do_default;
+                   if (flags & SCF_DO_STCLASS_OR) { /* Everything but \n */
+                       value = (ANYOF_BITMAP_TEST(data->start_class,'\n')
+                                || (data->start_class->flags & ANYOF_CLASS));
+                       cl_anything(data->start_class);
+                   }
+                   if (flags & SCF_DO_STCLASS_AND || !value)
+                       ANYOF_BITMAP_CLEAR(data->start_class,'\n');
+                   break;
+               case ANYOF:
+                   if (flags & SCF_DO_STCLASS_AND)
+                       cl_and(data->start_class,
+                              (struct regnode_charclass_class*)scan);
+                   else
+                       cl_or(data->start_class,
+                             (struct regnode_charclass_class*)scan);
+                   break;
+               case ALNUM:
+                   if (flags & SCF_DO_STCLASS_AND) {
+                       if (!(data->start_class->flags & ANYOF_LOCALE)) {
+                           ANYOF_CLASS_CLEAR(data->start_class,ANYOF_NALNUM);
+                           for (value = 0; value < 256; value++)
+                               if (!isALNUM(value))
+                                   ANYOF_BITMAP_CLEAR(data->start_class, value);
+                       }
+                   }
+                   else {
+                       if (data->start_class->flags & ANYOF_LOCALE)
+                           ANYOF_CLASS_SET(data->start_class,ANYOF_ALNUM);
+                       else {
+                           for (value = 0; value < 256; value++)
+                               if (isALNUM(value))
+                                   ANYOF_BITMAP_SET(data->start_class, value);                     
+                       }
+                   }
+                   break;
+               case ALNUML:
+                   if (flags & SCF_DO_STCLASS_AND) {
+                       if (data->start_class->flags & ANYOF_LOCALE)
+                           ANYOF_CLASS_CLEAR(data->start_class,ANYOF_NALNUM);
+                   }
+                   else {
+                       ANYOF_CLASS_SET(data->start_class,ANYOF_ALNUM);
+                       data->start_class->flags |= ANYOF_LOCALE;
+                   }
+                   break;
+               case NALNUM:
+                   if (flags & SCF_DO_STCLASS_AND) {
+                       if (!(data->start_class->flags & ANYOF_LOCALE)) {
+                           ANYOF_CLASS_CLEAR(data->start_class,ANYOF_ALNUM);
+                           for (value = 0; value < 256; value++)
+                               if (isALNUM(value))
+                                   ANYOF_BITMAP_CLEAR(data->start_class, value);
+                       }
+                   }
+                   else {
+                       if (data->start_class->flags & ANYOF_LOCALE)
+                           ANYOF_CLASS_SET(data->start_class,ANYOF_NALNUM);
+                       else {
+                           for (value = 0; value < 256; value++)
+                               if (!isALNUM(value))
+                                   ANYOF_BITMAP_SET(data->start_class, value);                     
+                       }
+                   }
+                   break;
+               case NALNUML:
+                   if (flags & SCF_DO_STCLASS_AND) {
+                       if (data->start_class->flags & ANYOF_LOCALE)
+                           ANYOF_CLASS_CLEAR(data->start_class,ANYOF_ALNUM);
+                   }
+                   else {
+                       data->start_class->flags |= ANYOF_LOCALE;
+                       ANYOF_CLASS_SET(data->start_class,ANYOF_NALNUM);
+                   }
+                   break;
+               case SPACE:
+                   if (flags & SCF_DO_STCLASS_AND) {
+                       if (!(data->start_class->flags & ANYOF_LOCALE)) {
+                           ANYOF_CLASS_CLEAR(data->start_class,ANYOF_NSPACE);
+                           for (value = 0; value < 256; value++)
+                               if (!isSPACE(value))
+                                   ANYOF_BITMAP_CLEAR(data->start_class, value);
+                       }
+                   }
+                   else {
+                       if (data->start_class->flags & ANYOF_LOCALE)
+                           ANYOF_CLASS_SET(data->start_class,ANYOF_SPACE);
+                       else {
+                           for (value = 0; value < 256; value++)
+                               if (isSPACE(value))
+                                   ANYOF_BITMAP_SET(data->start_class, value);                     
+                       }
+                   }
+                   break;
+               case SPACEL:
+                   if (flags & SCF_DO_STCLASS_AND) {
+                       if (data->start_class->flags & ANYOF_LOCALE)
+                           ANYOF_CLASS_CLEAR(data->start_class,ANYOF_NSPACE);
+                   }
+                   else {
+                       data->start_class->flags |= ANYOF_LOCALE;
+                       ANYOF_CLASS_SET(data->start_class,ANYOF_SPACE);
+                   }
+                   break;
+               case NSPACE:
+                   if (flags & SCF_DO_STCLASS_AND) {
+                       if (!(data->start_class->flags & ANYOF_LOCALE)) {
+                           ANYOF_CLASS_CLEAR(data->start_class,ANYOF_SPACE);
+                           for (value = 0; value < 256; value++)
+                               if (isSPACE(value))
+                                   ANYOF_BITMAP_CLEAR(data->start_class, value);
+                       }
+                   }
+                   else {
+                       if (data->start_class->flags & ANYOF_LOCALE)
+                           ANYOF_CLASS_SET(data->start_class,ANYOF_NSPACE);
+                       else {
+                           for (value = 0; value < 256; value++)
+                               if (!isSPACE(value))
+                                   ANYOF_BITMAP_SET(data->start_class, value);                     
+                       }
+                   }
+                   break;
+               case NSPACEL:
+                   if (flags & SCF_DO_STCLASS_AND) {
+                       if (data->start_class->flags & ANYOF_LOCALE) {
+                           ANYOF_CLASS_CLEAR(data->start_class,ANYOF_SPACE);
+                           for (value = 0; value < 256; value++)
+                               if (!isSPACE(value))
+                                   ANYOF_BITMAP_CLEAR(data->start_class, value);
+                       }
+                   }
+                   else {
+                       data->start_class->flags |= ANYOF_LOCALE;
+                       ANYOF_CLASS_SET(data->start_class,ANYOF_NSPACE);
+                   }
+                   break;
+               case DIGIT:
+                   if (flags & SCF_DO_STCLASS_AND) {
+                       ANYOF_CLASS_CLEAR(data->start_class,ANYOF_NDIGIT);
+                       for (value = 0; value < 256; value++)
+                           if (!isDIGIT(value))
+                               ANYOF_BITMAP_CLEAR(data->start_class, value);
+                   }
+                   else {
+                       if (data->start_class->flags & ANYOF_LOCALE)
+                           ANYOF_CLASS_SET(data->start_class,ANYOF_DIGIT);
+                       else {
+                           for (value = 0; value < 256; value++)
+                               if (isDIGIT(value))
+                                   ANYOF_BITMAP_SET(data->start_class, value);                     
+                       }
+                   }
+                   break;
+               case NDIGIT:
+                   if (flags & SCF_DO_STCLASS_AND) {
+                       ANYOF_CLASS_CLEAR(data->start_class,ANYOF_DIGIT);
+                       for (value = 0; value < 256; value++)
+                           if (isDIGIT(value))
+                               ANYOF_BITMAP_CLEAR(data->start_class, value);
+                   }
+                   else {
+                       if (data->start_class->flags & ANYOF_LOCALE)
+                           ANYOF_CLASS_SET(data->start_class,ANYOF_NDIGIT);
+                       else {
+                           for (value = 0; value < 256; value++)
+                               if (!isDIGIT(value))
+                                   ANYOF_BITMAP_SET(data->start_class, value);                     
+                       }
+                   }
+                   break;
+               }
+               if (flags & SCF_DO_STCLASS_OR)
+                   cl_and(data->start_class, &and_with);
+               flags &= ~SCF_DO_STCLASS;
+           }
        }
        else if (PL_regkind[(U8)OP(scan)] == EOL && flags & SCF_DO_SUBSTR) {
            data->flags |= (OP(scan) == MEOL
                            ? SF_BEFORE_MEOL
                            : SF_BEFORE_SEOL);
        }
-       else if (PL_regkind[(U8)OP(scan)] == BRANCHJ
-                  && (scan->flags || data)
+       else if (  PL_regkind[(U8)OP(scan)] == BRANCHJ
+                /* Lookbehind, or need to calculate parens/evals/stclass: */
+                  && (scan->flags || data || (flags & SCF_DO_STCLASS))
                   && (OP(scan) == IFMATCH || OP(scan) == UNLESSM)) {
+           /* Lookahead/lookbehind */
            I32 deltanext, minnext;
            regnode *nscan;
+           struct regnode_charclass_class intrnl;
+           int f = 0;
 
            data_fake.flags = 0;
+           if (data)
+               data_fake.whilem_c = data->whilem_c;
+           if ( flags & SCF_DO_STCLASS && !scan->flags
+                && OP(scan) == IFMATCH ) { /* Lookahead */
+               cl_init(&intrnl);
+               data_fake.start_class = &intrnl;
+               f = SCF_DO_STCLASS_AND;
+           }
            next = regnext(scan);
            nscan = NEXTOPER(NEXTOPER(scan));
-           minnext = study_chunk(&nscan, &deltanext, last, &data_fake, 0);
+           minnext = study_chunk(&nscan, &deltanext, last, &data_fake, f);
            if (scan->flags) {
                if (deltanext) {
                    FAIL("variable length lookbehind not implemented");
                }
                else if (minnext > U8_MAX) {
-                   FAIL2("lookbehind longer than %d not implemented", U8_MAX);
+                   FAIL2("lookbehind longer than %"UVuf" not implemented", (UV)U8_MAX);
                }
                scan->flags = minnext;
            }
@@ -666,6 +1199,15 @@ S_study_chunk(pTHX_ regnode **scanp, I32 *deltap, regnode *last, scan_data_t *da
                pars++;
            if (data && (data_fake.flags & SF_HAS_EVAL))
                data->flags |= SF_HAS_EVAL;
+           if (data)
+               data->whilem_c = data_fake.whilem_c;
+           if (f) {
+               int was = (data->start_class->flags & ANYOF_EOS);
+
+               cl_and(data->start_class, &intrnl);
+               if (was)
+                   data->start_class->flags |= ANYOF_EOS;
+           }
        }
        else if (OP(scan) == OPEN) {
            pars++;
@@ -680,12 +1222,15 @@ S_study_chunk(pTHX_ regnode **scanp, I32 *deltap, regnode *last, scan_data_t *da
                if (data)
                    data->flags |= SF_HAS_EVAL;
        }
-       else if (OP(scan) == LOGICAL && scan->flags == 2) { /* Embedded */
+       else if (OP(scan) == LOGICAL && scan->flags == 2) { /* Embedded follows */
                if (flags & SCF_DO_SUBSTR) {
                    scan_commit(data);
                    data->longest = &(data->longest_float);
                }
                is_inf = is_inf_internal = 1;
+               if (flags & SCF_DO_STCLASS_OR) /* Allow everything */
+                   cl_anything(data->start_class);
+               flags &= ~SCF_DO_STCLASS;
        }
        /* Else: zero-length, ignore. */
        scan = regnext(scan);
@@ -706,6 +1251,8 @@ S_study_chunk(pTHX_ regnode **scanp, I32 *deltap, regnode *last, scan_data_t *da
        data->flags |= SF_HAS_PAR;
        data->flags &= ~SF_IN_PAR;
     }
+    if (flags & SCF_DO_STCLASS_OR)
+       cl_and(data->start_class, &and_with);
     return min;
 }
 
@@ -776,28 +1323,27 @@ Perl_pregcomp(pTHX_ char *exp, char *xend, PMOP *pm)
     dTHR;
     register regexp *r;
     regnode *scan;
-    SV **longest;
-    SV *longest_fixed;
-    SV *longest_float;
     regnode *first;
     I32 flags;
     I32 minlen = 0;
     I32 sawplus = 0;
     I32 sawopen = 0;
+    scan_data_t data;
 
     if (exp == NULL)
        FAIL("NULL regexp argument");
 
-    if (PL_curcop == &PL_compiling ? (PL_hints & HINT_UTF8) : IN_UTF8)
+    if (pm->op_pmdynflags & PMdf_UTF8) {
        PL_reg_flags |= RF_utf8;
+    }
     else
        PL_reg_flags = 0;
 
     PL_regprecomp = savepvn(exp, xend - exp);
     DEBUG_r(if (!PL_colorset) reginitcolors());
-    DEBUG_r(PerlIO_printf(Perl_debug_log, "%sCompiling%s RE `%s%*s%s'\n",
+    DEBUG_r(PerlIO_printf(Perl_debug_log, "%sCompiling REx%s `%s%*s%s'\n",
                      PL_colors[4],PL_colors[5],PL_colors[0],
-                     xend - exp, PL_regprecomp, PL_colors[1]));
+                     (int)(xend - exp), PL_regprecomp, PL_colors[1]));
     PL_regflags = pm->op_pmflags;
     PL_regsawback = 0;
 
@@ -813,13 +1359,17 @@ Perl_pregcomp(pTHX_ char *exp, char *xend, PMOP *pm)
     PL_regnpar = 1;
     PL_regsize = 0L;
     PL_regcode = &PL_regdummy;
-    regc((U8)REG_MAGIC, (char*)PL_regcode);
+    PL_reg_whilem_seen = 0;
+#if 0 /* REGC() is (currently) a NOP at the first pass.
+       * Clever compilers notice this and complain. --jhi */
+    REGC((U8)REG_MAGIC, (char*)PL_regcode);
+#endif
     if (reg(0, &flags) == NULL) {
        Safefree(PL_regprecomp);
        PL_regprecomp = Nullch;
        return(NULL);
     }
-    DEBUG_r(PerlIO_printf(Perl_debug_log, "size %d ", PL_regsize));
+    DEBUG_r(PerlIO_printf(Perl_debug_log, "size %"IVdf" ", (IV)PL_regsize));
 
     /* Small enough for pointer-storage convention?
        If extralen==0, this means that we will not need long jumps. */
@@ -827,12 +1377,18 @@ Perl_pregcomp(pTHX_ char *exp, char *xend, PMOP *pm)
         PL_regsize += PL_extralen;
     else
        PL_extralen = 0;
+    if (PL_reg_whilem_seen > 15)
+       PL_reg_whilem_seen = 15;
 
     /* Allocate space and initialize. */
     Newc(1001, r, sizeof(regexp) + (unsigned)PL_regsize * sizeof(regnode),
         char, regexp);
     if (r == NULL)
        FAIL("regexp out of space");
+#ifdef DEBUGGING
+    /* avoid reading uninitialized memory in DEBUGGING code in study_chunk() */
+    Zero(r, sizeof(regexp) + (unsigned)PL_regsize * sizeof(regnode), char);
+#endif
     r->refcnt = 1;
     r->prelen = xend - exp;
     r->precomp = PL_regprecomp;
@@ -854,7 +1410,7 @@ Perl_pregcomp(pTHX_ char *exp, char *xend, PMOP *pm)
     PL_regcode = r->program;
     /* Store the count of eval-groups for security checks: */
     PL_regcode->next_off = ((PL_seen_evals > U16_MAX) ? U16_MAX : PL_seen_evals);
-    regc((U8)REG_MAGIC, (char*) PL_regcode++);
+    REGC((U8)REG_MAGIC, (char*) PL_regcode++);
     r->data = 0;
     if (reg(0, &flags) == NULL)
        return(NULL);
@@ -873,18 +1429,22 @@ Perl_pregcomp(pTHX_ char *exp, char *xend, PMOP *pm)
        3-units-long substrs field. */
     Newz(1004, r->substrs, 1, struct reg_substr_data);
 
+    StructCopy(&zero_scan_data, &data, scan_data_t);
+    /* XXXX Should not we check for something else?  Usually it is OPEN1... */
     if (OP(scan) != BRANCH) {  /* Only one top-level choice. */
-       scan_data_t data;
        I32 fake;
        STRLEN longest_float_length, longest_fixed_length;
+       struct regnode_charclass_class ch_class;
+       int stclass_flag;
 
-       StructCopy(&zero_scan_data, &data, scan_data_t);
        first = scan;
        /* Skip introductions and multiplicators >= 1. */
        while ((OP(first) == OPEN && (sawopen = 1)) ||
+              /* An OR of *one* alternative - should not happen now. */
            (OP(first) == BRANCH && OP(regnext(first)) != BRANCH) ||
            (OP(first) == PLUS) ||
            (OP(first) == MINMOD) ||
+              /* An {n,m} with n>0 */
            (PL_regkind[(U8)OP(first)] == CURLY && ARG1(first) > 0) ) {
                if (OP(first) == PLUS)
                    sawplus = 1;
@@ -895,8 +1455,13 @@ Perl_pregcomp(pTHX_ char *exp, char *xend, PMOP *pm)
 
        /* Starting-point info. */
       again:
-       if (OP(first) == EXACT);        /* Empty, get anchored substr later. */
-       else if (strchr((char*)PL_simple+4,OP(first)))
+       if (PL_regkind[(U8)OP(first)] == EXACT) {
+           if (OP(first) == EXACT);    /* Empty, get anchored substr later. */
+           else if ((OP(first) == EXACTF || OP(first) == EXACTFL)
+                    && !UTF)
+               r->regstclass = first;
+       }
+       else if (strchr((char*)PL_simple,OP(first)))
            r->regstclass = first;
        else if (PL_regkind[(U8)OP(first)] == BOUND ||
                 PL_regkind[(U8)OP(first)] == NBOUND)
@@ -937,8 +1502,8 @@ Perl_pregcomp(pTHX_ char *exp, char *xend, PMOP *pm)
            r->reganch |= ROPT_SKIP;
 
        /* Scan is after the zeroth branch, first is atomic matcher. */
-       DEBUG_r(PerlIO_printf(Perl_debug_log, "first at %d\n", 
-                             first - scan + 1));
+       DEBUG_r(PerlIO_printf(Perl_debug_log, "first at %"IVdf"\n", 
+                             (IV)(first - scan + 1)));
        /*
        * If there's something expensive in the r.e., find the
        * longest literal string that must appear and make it the
@@ -957,9 +1522,15 @@ Perl_pregcomp(pTHX_ char *exp, char *xend, PMOP *pm)
        data.last_found = newSVpvn("",0);
        data.longest = &(data.longest_fixed);
        first = scan;
-       
+       if (!r->regstclass) {
+           cl_init(&ch_class);
+           data.start_class = &ch_class;
+           stclass_flag = SCF_DO_STCLASS_AND;
+       } else                          /* XXXX Check for BOUND? */
+           stclass_flag = 0;
+
        minlen = study_chunk(&first, &fake, scan + PL_regsize, /* Up to end */
-                            &data, SCF_DO_SUBSTR);
+                            &data, SCF_DO_SUBSTR | stclass_flag);
        if ( PL_regnpar == 1 && data.longest == &(data.longest_fixed)
             && data.last_start_min == 0 && data.last_end > 0 
             && !PL_seen_zerolen
@@ -1014,6 +1585,28 @@ Perl_pregcomp(pTHX_ char *exp, char *xend, PMOP *pm)
            SvREFCNT_dec(data.longest_fixed);
            longest_fixed_length = 0;
        }
+       if (r->regstclass 
+           && (OP(r->regstclass) == REG_ANY || OP(r->regstclass) == ANYUTF8
+               || OP(r->regstclass) == SANYUTF8 || OP(r->regstclass) == SANY))
+           r->regstclass = NULL;
+       if ((!r->anchored_substr || r->anchored_offset) && stclass_flag
+           && !(data.start_class->flags & ANYOF_EOS)
+           && !cl_is_anything(data.start_class)) {
+           SV *sv;
+           I32 n = add_data(1, "f");
+
+           New(1006, PL_regcomp_rx->data->data[n], 1, 
+               struct regnode_charclass_class);
+           StructCopy(data.start_class,
+                      (struct regnode_charclass_class*)PL_regcomp_rx->data->data[n],
+                      struct regnode_charclass_class);
+           r->regstclass = (regnode*)PL_regcomp_rx->data->data[n];
+           r->reganch &= ~ROPT_SKIP;   /* Used in find_byclass(). */
+           DEBUG_r((sv = sv_newmortal(),
+                    regprop(sv, (regnode*)data.start_class),
+                    PerlIO_printf(Perl_debug_log, "synthetic stclass `%s'.\n",
+                                  SvPVX(sv))));
+       }
 
        /* A temporary algorithm prefers floated substr to fixed one to dig more info. */
        if (longest_fixed_length > longest_float_length) {
@@ -1027,7 +1620,9 @@ Perl_pregcomp(pTHX_ char *exp, char *xend, PMOP *pm)
            r->check_offset_min = data.offset_float_min;
            r->check_offset_max = data.offset_float_max;
        }
-       if (r->check_substr) {
+       /* XXXX Currently intuiting is not compatible with ANCH_GPOS.
+          This should be changed ASAP!  */
+       if (r->check_substr && !(r->reganch & ROPT_ANCH_GPOS)) {
            r->reganch |= RE_USE_INTUIT;
            if (SvTAIL(r->check_substr))
                r->reganch |= RE_INTUIT_TAIL;
@@ -1036,11 +1631,31 @@ Perl_pregcomp(pTHX_ char *exp, char *xend, PMOP *pm)
     else {
        /* Several toplevels. Best we can is to set minlen. */
        I32 fake;
+       struct regnode_charclass_class ch_class;
        
        DEBUG_r(PerlIO_printf(Perl_debug_log, "\n"));
        scan = r->program + 1;
-       minlen = study_chunk(&scan, &fake, scan + PL_regsize, NULL, 0);
+       cl_init(&ch_class);
+       data.start_class = &ch_class;
+       minlen = study_chunk(&scan, &fake, scan + PL_regsize, &data, SCF_DO_STCLASS_AND);
        r->check_substr = r->anchored_substr = r->float_substr = Nullsv;
+       if (!(data.start_class->flags & ANYOF_EOS)
+           && !cl_is_anything(data.start_class)) {
+           SV *sv;
+           I32 n = add_data(1, "f");
+
+           New(1006, PL_regcomp_rx->data->data[n], 1, 
+               struct regnode_charclass_class);
+           StructCopy(data.start_class,
+                      (struct regnode_charclass_class*)PL_regcomp_rx->data->data[n],
+                      struct regnode_charclass_class);
+           r->regstclass = (regnode*)PL_regcomp_rx->data->data[n];
+           r->reganch &= ~ROPT_SKIP;   /* Used in find_byclass(). */
+           DEBUG_r((sv = sv_newmortal(),
+                    regprop(sv, (regnode*)data.start_class),
+                    PerlIO_printf(Perl_debug_log, "synthetic stclass `%s'.\n",
+                                  SvPVX(sv))));
+       }
     }
 
     r->minlen = minlen;
@@ -1117,6 +1732,11 @@ S_reg(pTHX_ I32 paren, I32 *flagp)
                *flagp = TRYAGAIN;
                return NULL;
            case 'p':
+               if (SIZE_ONLY)
+                   Perl_warner(aTHX_ WARN_REGEXP,
+                               "(?p{}) is deprecated - use (??{})");
+               /* FALL THROUGH*/
+           case '?':
                logical = 1;
                paren = *PL_regcomp_parse++;
                /* FALL THROUGH */
@@ -1517,8 +2137,10 @@ S_regpiece(pTHX_ I32 *flagp)
                reginsert(CURLY, ret);
            }
            else {
-               PL_regnaughty += 4 + PL_regnaughty;     /* compound interest */
-               regtail(ret, reg_node(WHILEM));
+               regnode *w = reg_node(WHILEM);
+
+               w->flags = 0;
+               regtail(ret, w);
                if (!SIZE_ONLY && PL_extralen) {
                    reginsert(LONGJMP,ret);
                    reginsert(NOTHING,ret);
@@ -1529,7 +2151,8 @@ S_regpiece(pTHX_ I32 *flagp)
                    NEXT_OFF(ret) = 3;  /* Go over NOTHING to LONGJMP. */
                regtail(ret, reg_node(NOTHING));
                if (SIZE_ONLY)
-                   PL_extralen += 3;
+                   PL_reg_whilem_seen++, PL_extralen += 3;
+               PL_regnaughty += 4 + PL_regnaughty;     /* compound interest */
            }
            ret->flags = 0;
 
@@ -1585,8 +2208,8 @@ S_regpiece(pTHX_ I32 *flagp)
        goto do_curly;
     }
   nest_check:
-    if (ckWARN(WARN_UNSAFE) && !SIZE_ONLY && !(flags&HASWIDTH) && max > REG_INFTY/3) {
-       Perl_warner(aTHX_ WARN_UNSAFE, "%.*s matches null string many times",
+    if (ckWARN(WARN_REGEXP) && !SIZE_ONLY && !(flags&HASWIDTH) && max > REG_INFTY/3) {
+       Perl_warner(aTHX_ WARN_REGEXP, "%.*s matches null string many times",
            PL_regcomp_parse - origparse, origparse);
     }
 
@@ -1901,8 +2524,7 @@ tryagain:
            ret = reg_node(FOLD
                          ? (LOC ? EXACTFL : EXACTF)
                          : EXACT);
-           s = (char *) OPERAND(ret);
-           regc(0, s++);               /* save spot for len */
+           s = STRING(ret);
            for (len = 0, p = PL_regcomp_parse - 1;
              len < 127 && p < PL_regxend;
              len++)
@@ -1955,11 +2577,19 @@ tryagain:
                        p++;
                        break;
                    case 'e':
-                       ender = '\033';
+#ifdef ASCIIish
+                         ender = '\033';
+#else
+                         ender = '\047';
+#endif
                        p++;
                        break;
                    case 'a':
-                       ender = '\007';
+#ifdef ASCIIish
+                         ender = '\007';
+#else
+                         ender = '\057';
+#endif
                        p++;
                        break;
                    case 'x':
@@ -1969,7 +2599,7 @@ tryagain:
                            if (!e)
                                FAIL("Missing right brace on \\x{}");
                            else if (UTF) {
-                               ender = scan_hex(p + 1, e - p, &numlen);
+                               ender = (UV)scan_hex(p + 1, e - p, &numlen);
                                if (numlen + len >= 127) {      /* numlen is generous */
                                    p--;
                                    goto loopdone;
@@ -1980,7 +2610,7 @@ tryagain:
                                FAIL("Can't use \\x{} without 'use utf8' declaration");
                        }
                        else {
-                           ender = scan_hex(p, 2, &numlen);
+                           ender = (UV)scan_hex(p, 2, &numlen);
                            p += numlen;
                        }
                        break;
@@ -1993,7 +2623,7 @@ tryagain:
                    case '5': case '6': case '7': case '8':case '9':
                        if (*p == '0' ||
                          (isDIGIT(p[1]) && atoi(p) >= PL_regnpar) ) {
-                           ender = scan_oct(p, 3, &numlen);
+                           ender = (UV)scan_oct(p, 3, &numlen);
                            p += numlen;
                        }
                        else {
@@ -2006,11 +2636,11 @@ tryagain:
                            FAIL("trailing \\ in regexp");
                        /* FALL THROUGH */
                    default:
-                       if (!SIZE_ONLY && ckWARN(WARN_UNSAFE) && isALPHA(*p))
-                           Perl_warner(aTHX_ WARN_UNSAFE
-                                  "/%.127s/: Unrecognized escape \\%c passed through",
-                                  PL_regprecomp,
-                                  *p);
+                       if (!SIZE_ONLY && ckWARN(WARN_REGEXP) && isALPHA(*p))
+                           Perl_warner(aTHX_ WARN_REGEXP
+                                       "/%.127s/: Unrecognized escape \\%c passed through",
+                                       PL_regprecomp,
+                                       *p);
                        goto normal_default;
                    }
                    break;
@@ -2042,7 +2672,7 @@ tryagain:
                    }
                    else {
                        len++;
-                       regc(ender, s++);
+                       REGC(ender, s++);
                    }
                    break;
                }
@@ -2052,7 +2682,7 @@ tryagain:
                    len += numlen - 1;
                }
                else
-                   regc(ender, s++);
+                   REGC(ender, s++);
            }
        loopdone:
            PL_regcomp_parse = p - 1;
@@ -2064,14 +2694,11 @@ tryagain:
            if (len == 1)
                *flagp |= SIMPLE;
            if (!SIZE_ONLY)
-               *OPERAND(ret) = len;
-           regc('\0', s++);
-           if (SIZE_ONLY) {
-               PL_regsize += (len + 2 + sizeof(regnode) - 1) / sizeof(regnode);
-           }
-           else {
-               PL_regcode += (len + 2 + sizeof(regnode) - 1) / sizeof(regnode);
-           }
+               STR_LEN(ret) = len;
+           if (SIZE_ONLY)
+               PL_regsize += STR_SZ(len);
+           else
+               PL_regcode += STR_SZ(len);
        }
        break;
     }
@@ -2106,7 +2733,7 @@ S_regpposixcc(pTHX_ I32 value)
 {
     dTHR;
     char *posixcc = 0;
-    I32 namedclass = -1;
+    I32 namedclass = OOB_NAMEDCLASS;
 
     if (value == '[' && PL_regcomp_parse + 1 < PL_regxend &&
        /* I smell either [: or [= or [. -- POSIX has been here, right? */
@@ -2195,15 +2822,15 @@ S_regpposixcc(pTHX_ I32 value)
                        }
                        break;
                    }
-                   if ((namedclass == -1 ||
-                        !(posixcc + skip + 2 < PL_regxend &&
-                          (posixcc[skip] == ':' &&
-                           posixcc[skip + 1] == ']'))))
-                       Perl_croak(aTHX_ "Character class [:%.*s:] unknown",
-                                  t - s - 1, s + 1); 
-               } else if (ckWARN(WARN_UNSAFE) && !SIZE_ONLY)
+                   if (namedclass == OOB_NAMEDCLASS ||
+                       posixcc[skip] != ':' ||
+                       posixcc[skip+1] != ']')
+                       Perl_croak(aTHX_
+                                  "Character class [:%.*s:] unknown",
+                                  t - s - 1, s + 1);
+               } else if (ckWARN(WARN_REGEXP) && !SIZE_ONLY)
                    /* [[=foo=]] and [[.foo.]] are still future. */
-                   Perl_warner(aTHX_ WARN_UNSAFE,
+                   Perl_warner(aTHX_ WARN_REGEXP,
                                "Character class syntax [%c %c] is reserved for future extensions", c, c);
            } else {
                /* Maternal grandfather:
@@ -2219,20 +2846,20 @@ S_regpposixcc(pTHX_ I32 value)
 STATIC void
 S_checkposixcc(pTHX)
 {
-    if (ckWARN(WARN_UNSAFE) && !SIZE_ONLY &&
+    if (!SIZE_ONLY && ckWARN(WARN_REGEXP) &&
        (*PL_regcomp_parse == ':' ||
         *PL_regcomp_parse == '=' ||
         *PL_regcomp_parse == '.')) {
        char *s = PL_regcomp_parse;
-       char  c = *s++;
+       char  c = *s++;
 
        while(*s && isALNUM(*s))
            s++;
        if (*s && c == *s && s[1] == ']') {
-           Perl_warner(aTHX_ WARN_UNSAFE,
+           Perl_warner(aTHX_ WARN_REGEXP,
                        "Character class syntax [%c %c] belongs inside character classes", c, c);
            if (c == '=' || c == '.')
-               Perl_warner(aTHX_ WARN_UNSAFE,
+               Perl_warner(aTHX_ WARN_REGEXP,
                            "Character class syntax [%c %c] is reserved for future extensions", c, c);
        }
     }
@@ -2242,48 +2869,51 @@ STATIC regnode *
 S_regclass(pTHX)
 {
     dTHR;
-    register char *opnd, *s;
-    register I32 value;
+    register U32 value;
     register I32 lastvalue = OOB_CHAR8;
     register I32 range = 0;
     register regnode *ret;
-    register I32 def;
     I32 numlen;
     I32 namedclass;
+    char *rangebegin;
+    bool need_class = 0;
 
-    s = opnd = (char *) OPERAND(PL_regcode);
     ret = reg_node(ANYOF);
-    for (value = 0; value < ANYOF_SIZE; value++)
-       regc(0, s++);
+    if (SIZE_ONLY)
+       PL_regsize += ANYOF_SKIP;
+    else {
+       ret->flags = 0;
+       ANYOF_BITMAP_ZERO(ret);
+       PL_regcode += ANYOF_SKIP;
+       if (FOLD)
+           ANYOF_FLAGS(ret) |= ANYOF_FOLD;
+       if (LOC)
+           ANYOF_FLAGS(ret) |= ANYOF_LOCALE;
+    }
     if (*PL_regcomp_parse == '^') {    /* Complement of range. */
        PL_regnaughty++;
        PL_regcomp_parse++;
        if (!SIZE_ONLY)
-           ANYOF_FLAGS(opnd) |= ANYOF_INVERT;
-    }
-    if (!SIZE_ONLY) {
-       PL_regcode += ANY_SKIP;
-       if (FOLD)
-           ANYOF_FLAGS(opnd) |= ANYOF_FOLD;
-       if (LOC)
-           ANYOF_FLAGS(opnd) |= ANYOF_LOCALE;
-    }
-    else {
-       PL_regsize += ANY_SKIP;
+           ANYOF_FLAGS(ret) |= ANYOF_INVERT;
     }
 
-    checkposixcc();
+    if (!SIZE_ONLY && ckWARN(WARN_REGEXP))
+       checkposixcc();
 
     if (*PL_regcomp_parse == ']' || *PL_regcomp_parse == '-')
        goto skipcond;          /* allow 1st char to be ] or - */
     while (PL_regcomp_parse < PL_regxend && *PL_regcomp_parse != ']') {
        skipcond:
-       namedclass = -1;
+       namedclass = OOB_NAMEDCLASS;
+       if (!range)
+           rangebegin = PL_regcomp_parse;
        value = UCHARAT(PL_regcomp_parse++);
        if (value == '[')
            namedclass = regpposixcc(value);
        else if (value == '\\') {
            value = UCHARAT(PL_regcomp_parse++);
+           /* Some compilers cannot handle switching on 64-bit integer
+            * values, therefore value cannot be an UV. --jhi */
            switch (value) {
            case 'w':   namedclass = ANYOF_ALNUM;       break;
            case 'W':   namedclass = ANYOF_NALNUM;      break;
@@ -2296,10 +2926,15 @@ S_regclass(pTHX)
            case 't':   value = '\t';                   break;
            case 'f':   value = '\f';                   break;
            case 'b':   value = '\b';                   break;
+#ifdef ASCIIish
            case 'e':   value = '\033';                 break;
            case 'a':   value = '\007';                 break;
+#else
+           case 'e':   value = '\047';                 break;
+           case 'a':   value = '\057';                 break;
+#endif
            case 'x':
-               value = scan_hex(PL_regcomp_parse, 2, &numlen);
+               value = (UV)scan_hex(PL_regcomp_parse, 2, &numlen);
                PL_regcomp_parse += numlen;
                break;
            case 'c':
@@ -2308,271 +2943,326 @@ S_regclass(pTHX)
                break;
            case '0': case '1': case '2': case '3': case '4':
            case '5': case '6': case '7': case '8': case '9':
-               value = scan_oct(--PL_regcomp_parse, 3, &numlen);
+               value = (UV)scan_oct(--PL_regcomp_parse, 3, &numlen);
                PL_regcomp_parse += numlen;
                break;
+           default:
+               if (!SIZE_ONLY && ckWARN(WARN_REGEXP) && isALPHA(value))
+                   Perl_warner(aTHX_ WARN_REGEXP, 
+                               "/%.127s/: Unrecognized escape \\%c in character class passed through",
+                               PL_regprecomp,
+                               (int)value);
+               break;
            }
        }
-       if (!SIZE_ONLY && namedclass > -1) {
-           switch (namedclass) {
-           case ANYOF_ALNUM:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_ALNUM);
-               else {
-                   for (value = 0; value < 256; value++)
-                       if (isALNUM(value))
-                           ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           case ANYOF_NALNUM:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_NALNUM);
-               else {
-                   for (value = 0; value < 256; value++)
-                       if (!isALNUM(value))
-                           ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           case ANYOF_SPACE:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_SPACE);
-               else {
-                   for (value = 0; value < 256; value++)
-                       if (isSPACE(value))
-                           ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           case ANYOF_NSPACE:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_NSPACE);
-               else {
-                   for (value = 0; value < 256; value++)
-                       if (!isSPACE(value))
-                           ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           case ANYOF_DIGIT:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_DIGIT);
-               else {
-                   for (value = '0'; value <= '9'; value++)
-                       ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           case ANYOF_NDIGIT:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_NDIGIT);
-               else {
-                   for (value = 0; value < '0'; value++)
-                       ANYOF_BITMAP_SET(opnd, value);
-                   for (value = '9' + 1; value < 256; value++)
-                       ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           case ANYOF_NALNUMC:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_NALNUMC);
-               else {
-                   for (value = 0; value < 256; value++)
-                       if (!isALNUMC(value))
-                           ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           case ANYOF_ALNUMC:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_ALNUMC);
-               else {
-                   for (value = 0; value < 256; value++)
-                       if (isALNUMC(value))
-                           ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           case ANYOF_ALPHA:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_ALPHA);
-               else {
-                   for (value = 0; value < 256; value++)
-                       if (isALPHA(value))
-                           ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           case ANYOF_NALPHA:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_NALPHA);
-               else {
-                   for (value = 0; value < 256; value++)
-                       if (!isALPHA(value))
-                           ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           case ANYOF_ASCII:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_ASCII);
-               else {
-                   for (value = 0; value < 128; value++)
-                       ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           case ANYOF_NASCII:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_NASCII);
-               else {
-                   for (value = 128; value < 256; value++)
-                       ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           case ANYOF_CNTRL:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_CNTRL);
-               else {
-                   for (value = 0; value < 256; value++)
-                       if (isCNTRL(value))
-                           ANYOF_BITMAP_SET(opnd, value);
-               }
-               lastvalue = OOB_CHAR8;
-               break;
-           case ANYOF_NCNTRL:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_NCNTRL);
-               else {
-                   for (value = 0; value < 256; value++)
-                       if (!isCNTRL(value))
-                           ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           case ANYOF_GRAPH:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_GRAPH);
-               else {
-                   for (value = 0; value < 256; value++)
-                       if (isGRAPH(value))
-                           ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           case ANYOF_NGRAPH:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_NGRAPH);
-               else {
-                   for (value = 0; value < 256; value++)
-                       if (!isGRAPH(value))
-                           ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           case ANYOF_LOWER:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_LOWER);
-               else {
-                   for (value = 0; value < 256; value++)
-                       if (isLOWER(value))
-                           ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           case ANYOF_NLOWER:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_NLOWER);
-               else {
-                   for (value = 0; value < 256; value++)
-                       if (!isLOWER(value))
-                           ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           case ANYOF_PRINT:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_PRINT);
-               else {
-                   for (value = 0; value < 256; value++)
-                       if (isPRINT(value))
-                           ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           case ANYOF_NPRINT:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_NPRINT);
-               else {
-                   for (value = 0; value < 256; value++)
-                       if (!isPRINT(value))
-                           ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           case ANYOF_PUNCT:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_PUNCT);
-               else {
-                   for (value = 0; value < 256; value++)
-                       if (isPUNCT(value))
-                           ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           case ANYOF_NPUNCT:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_NPUNCT);
-               else {
-                   for (value = 0; value < 256; value++)
-                       if (!isPUNCT(value))
-                           ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           case ANYOF_UPPER:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_UPPER);
-               else {
-                   for (value = 0; value < 256; value++)
-                       if (isUPPER(value))
-                           ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           case ANYOF_NUPPER:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_NUPPER);
-               else {
-                   for (value = 0; value < 256; value++)
-                       if (!isUPPER(value))
-                           ANYOF_BITMAP_SET(opnd, value);
+       if (namedclass > OOB_NAMEDCLASS) {
+           if (!need_class && !SIZE_ONLY)
+               ANYOF_CLASS_ZERO(ret);
+           need_class = 1;
+           if (range) { /* a-\d, a-[:digit:] */
+               if (!SIZE_ONLY) {
+                   if (ckWARN(WARN_REGEXP))
+                       Perl_warner(aTHX_ WARN_REGEXP,
+                                   "/%.127s/: false [] range \"%*.*s\" in regexp",
+                                   PL_regprecomp,
+                                   PL_regcomp_parse - rangebegin,
+                                   PL_regcomp_parse - rangebegin,
+                                   rangebegin);
+                   ANYOF_BITMAP_SET(ret, lastvalue);
+                   ANYOF_BITMAP_SET(ret, '-');
                }
-               break;
-           case ANYOF_XDIGIT:
-               if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_XDIGIT);
-               else {
-                   for (value = 0; value < 256; value++)
-                       if (isXDIGIT(value))
-                           ANYOF_BITMAP_SET(opnd, value);
+               range = 0; /* this is not a true range */
+           }
+           if (!SIZE_ONLY) {
+               switch (namedclass) {
+               case ANYOF_ALNUM:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_ALNUM);
+                   else {
+                       for (value = 0; value < 256; value++)
+                           if (isALNUM(value))
+                               ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               case ANYOF_NALNUM:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_NALNUM);
+                   else {
+                       for (value = 0; value < 256; value++)
+                           if (!isALNUM(value))
+                               ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               case ANYOF_SPACE:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_SPACE);
+                   else {
+                       for (value = 0; value < 256; value++)
+                           if (isSPACE(value))
+                               ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               case ANYOF_NSPACE:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_NSPACE);
+                   else {
+                       for (value = 0; value < 256; value++)
+                           if (!isSPACE(value))
+                               ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               case ANYOF_DIGIT:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_DIGIT);
+                   else {
+                       for (value = '0'; value <= '9'; value++)
+                           ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               case ANYOF_NDIGIT:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_NDIGIT);
+                   else {
+                       for (value = 0; value < '0'; value++)
+                           ANYOF_BITMAP_SET(ret, value);
+                       for (value = '9' + 1; value < 256; value++)
+                           ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               case ANYOF_NALNUMC:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_NALNUMC);
+                   else {
+                       for (value = 0; value < 256; value++)
+                           if (!isALNUMC(value))
+                               ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               case ANYOF_ALNUMC:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_ALNUMC);
+                   else {
+                       for (value = 0; value < 256; value++)
+                           if (isALNUMC(value))
+                               ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               case ANYOF_ALPHA:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_ALPHA);
+                   else {
+                       for (value = 0; value < 256; value++)
+                           if (isALPHA(value))
+                               ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               case ANYOF_NALPHA:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_NALPHA);
+                   else {
+                       for (value = 0; value < 256; value++)
+                           if (!isALPHA(value))
+                               ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               case ANYOF_ASCII:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_ASCII);
+                   else {
+#ifdef ASCIIish
+                       for (value = 0; value < 128; value++)
+                           ANYOF_BITMAP_SET(ret, value);
+#else  /* EBCDIC */
+                       for (value = 0; value < 256; value++)
+                           if (isASCII(value))
+                               ANYOF_BITMAP_SET(ret, value);
+#endif /* EBCDIC */
+                   }
+                   break;
+               case ANYOF_NASCII:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_NASCII);
+                   else {
+#ifdef ASCIIish
+                       for (value = 128; value < 256; value++)
+                           ANYOF_BITMAP_SET(ret, value);
+#else  /* EBCDIC */
+                       for (value = 0; value < 256; value++)
+                           if (!isASCII(value))
+                               ANYOF_BITMAP_SET(ret, value);
+#endif /* EBCDIC */
+                   }
+                   break;
+               case ANYOF_CNTRL:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_CNTRL);
+                   else {
+                       for (value = 0; value < 256; value++)
+                           if (isCNTRL(value))
+                               ANYOF_BITMAP_SET(ret, value);
+                   }
+                   lastvalue = OOB_CHAR8;
+                   break;
+               case ANYOF_NCNTRL:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_NCNTRL);
+                   else {
+                       for (value = 0; value < 256; value++)
+                           if (!isCNTRL(value))
+                               ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               case ANYOF_GRAPH:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_GRAPH);
+                   else {
+                       for (value = 0; value < 256; value++)
+                           if (isGRAPH(value))
+                               ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               case ANYOF_NGRAPH:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_NGRAPH);
+                   else {
+                       for (value = 0; value < 256; value++)
+                           if (!isGRAPH(value))
+                               ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               case ANYOF_LOWER:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_LOWER);
+                   else {
+                       for (value = 0; value < 256; value++)
+                           if (isLOWER(value))
+                               ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               case ANYOF_NLOWER:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_NLOWER);
+                   else {
+                       for (value = 0; value < 256; value++)
+                           if (!isLOWER(value))
+                               ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               case ANYOF_PRINT:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_PRINT);
+                   else {
+                       for (value = 0; value < 256; value++)
+                           if (isPRINT(value))
+                               ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               case ANYOF_NPRINT:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_NPRINT);
+                   else {
+                       for (value = 0; value < 256; value++)
+                           if (!isPRINT(value))
+                               ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               case ANYOF_PUNCT:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_PUNCT);
+                   else {
+                       for (value = 0; value < 256; value++)
+                           if (isPUNCT(value))
+                               ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               case ANYOF_NPUNCT:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_NPUNCT);
+                   else {
+                       for (value = 0; value < 256; value++)
+                           if (!isPUNCT(value))
+                               ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               case ANYOF_UPPER:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_UPPER);
+                   else {
+                       for (value = 0; value < 256; value++)
+                           if (isUPPER(value))
+                               ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               case ANYOF_NUPPER:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_NUPPER);
+                   else {
+                       for (value = 0; value < 256; value++)
+                           if (!isUPPER(value))
+                               ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               case ANYOF_XDIGIT:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_XDIGIT);
+                   else {
+                       for (value = 0; value < 256; value++)
+                           if (isXDIGIT(value))
+                               ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               case ANYOF_NXDIGIT:
+                   if (LOC)
+                       ANYOF_CLASS_SET(ret, ANYOF_NXDIGIT);
+                   else {
+                       for (value = 0; value < 256; value++)
+                           if (!isXDIGIT(value))
+                               ANYOF_BITMAP_SET(ret, value);
+                   }
+                   break;
+               default:
+                   FAIL("invalid [::] class in regexp");
+                   break;
                }
-               break;
-           case ANYOF_NXDIGIT:
                if (LOC)
-                   ANYOF_CLASS_SET(opnd, ANYOF_NXDIGIT);
-               else {
-                   for (value = 0; value < 256; value++)
-                       if (!isXDIGIT(value))
-                           ANYOF_BITMAP_SET(opnd, value);
-               }
-               break;
-           default:
-               FAIL("invalid [::] class in regexp");
-               break;
+                   ANYOF_FLAGS(ret) |= ANYOF_CLASS;
+               continue;
            }
-           if (LOC)
-               ANYOF_FLAGS(opnd) |= ANYOF_CLASS;
-           lastvalue = OOB_CHAR8;
        }
-        else
        if (range) {
-           if (lastvalue > value)
-               FAIL("invalid [] range in regexp");
+           if (lastvalue > value) /* b-a */ {
+               Perl_croak(aTHX_
+                          "/%.127s/: invalid [] range \"%*.*s\" in regexp",
+                          PL_regprecomp,
+                          PL_regcomp_parse - rangebegin,
+                          PL_regcomp_parse - rangebegin,
+                          rangebegin);
+           }
            range = 0;
        }
        else {
            lastvalue = value;
            if (*PL_regcomp_parse == '-' && PL_regcomp_parse+1 < PL_regxend &&
-             PL_regcomp_parse[1] != ']') {
+               PL_regcomp_parse[1] != ']') {
                PL_regcomp_parse++;
-               range = 1;
+               if (namedclass > OOB_NAMEDCLASS) { /* \w-, [:word:]- */
+                   if (ckWARN(WARN_REGEXP))
+                       Perl_warner(aTHX_ WARN_REGEXP,
+                                   "/%.127s/: false [] range \"%*.*s\" in regexp",
+                                   PL_regprecomp,
+                                   PL_regcomp_parse - rangebegin,
+                                   PL_regcomp_parse - rangebegin,
+                                   rangebegin);
+                   if (!SIZE_ONLY)
+                       ANYOF_BITMAP_SET(ret, '-');
+               } else
+                   range = 1;
                continue;       /* do it next time */
            }
        }
+       /* now is the next time */
        if (!SIZE_ONLY) {
-#ifndef ASCIIish
+#ifndef ASCIIish /* EBCDIC, for example. */
            if ((isLOWER(lastvalue) && isLOWER(value)) ||
                (isUPPER(lastvalue) && isUPPER(value)))
            {
@@ -2580,36 +3270,42 @@ S_regclass(pTHX)
                if (isLOWER(lastvalue)) {
                    for (i = lastvalue; i <= value; i++)
                        if (isLOWER(i))
-                           ANYOF_BITMAP_SET(opnd, i);
+                           ANYOF_BITMAP_SET(ret, i);
                } else {
                    for (i = lastvalue; i <= value; i++)
                        if (isUPPER(i))
-                           ANYOF_BITMAP_SET(opnd, i);
+                           ANYOF_BITMAP_SET(ret, i);
                }
            }
            else
 #endif
                for ( ; lastvalue <= value; lastvalue++)
-                   ANYOF_BITMAP_SET(opnd, lastvalue);
+                   ANYOF_BITMAP_SET(ret, lastvalue);
         }
-       lastvalue = value;
+       range = 0;
+    }
+    if (need_class) {
+       if (SIZE_ONLY)
+           PL_regsize += ANYOF_CLASS_ADD_SKIP;
+       else
+           PL_regcode += ANYOF_CLASS_ADD_SKIP;
     }
     /* optimize case-insensitive simple patterns (e.g. /[a-z]/i) */
     if (!SIZE_ONLY &&
-       (ANYOF_FLAGS(opnd) & (ANYOF_FLAGS_ALL ^ ANYOF_INVERT)) == ANYOF_FOLD) {
+       (ANYOF_FLAGS(ret) & (ANYOF_FLAGS_ALL ^ ANYOF_INVERT)) == ANYOF_FOLD) {
        for (value = 0; value < 256; ++value) {
-           if (ANYOF_BITMAP_TEST(opnd, value)) {
+           if (ANYOF_BITMAP_TEST(ret, value)) {
                I32 cf = PL_fold[value];
-               ANYOF_BITMAP_SET(opnd, cf);
+               ANYOF_BITMAP_SET(ret, cf);
            }
        }
-       ANYOF_FLAGS(opnd) &= ~ANYOF_FOLD;
+       ANYOF_FLAGS(ret) &= ~ANYOF_FOLD;
     }
     /* optimize inverted simple patterns (e.g. [^a-z]) */
-    if (!SIZE_ONLY && (ANYOF_FLAGS(opnd) & ANYOF_FLAGS_ALL) == ANYOF_INVERT) {
+    if (!SIZE_ONLY && (ANYOF_FLAGS(ret) & ANYOF_FLAGS_ALL) == ANYOF_INVERT) {
        for (value = 0; value < ANYOF_BITMAP_SIZE; ++value)
-           opnd[ANYOF_BITMAP_OFFSET + value] ^= ANYOF_FLAGS_ALL;
-       ANYOF_FLAGS(opnd) = 0;
+           ANYOF_BITMAP(ret)[value] ^= ANYOF_FLAGS_ALL;
+       ANYOF_FLAGS(ret) = 0;
     }
     return ret;
 }
@@ -2618,7 +3314,7 @@ STATIC regnode *
 S_regclassutf8(pTHX)
 {
     dTHR;
-    register char *opnd, *e;
+    register char *e;
     register U32 value;
     register U32 lastvalue = OOB_UTF8;
     register I32 range = 0;
@@ -2628,6 +3324,7 @@ S_regclassutf8(pTHX)
     SV *listsv;
     U8 flags = 0;
     I32 namedclass;
+    char *rangebegin;
 
     if (*PL_regcomp_parse == '^') {    /* Complement of range. */
        PL_regnaughty++;
@@ -2643,22 +3340,27 @@ S_regclassutf8(pTHX)
        listsv = newSVpvn("# comment\n",10);
     }
 
-    checkposixcc();
+    if (!SIZE_ONLY && ckWARN(WARN_REGEXP))
+       checkposixcc();
 
     if (*PL_regcomp_parse == ']' || *PL_regcomp_parse == '-')
        goto skipcond;          /* allow 1st char to be ] or - */
 
     while (PL_regcomp_parse < PL_regxend && *PL_regcomp_parse != ']') {
        skipcond:
-       namedclass = -1;
+       namedclass = OOB_NAMEDCLASS;
+       if (!range)
+           rangebegin = PL_regcomp_parse;
        value = utf8_to_uv((U8*)PL_regcomp_parse, &numlen);
        PL_regcomp_parse += numlen;
-
        if (value == '[')
            namedclass = regpposixcc(value);
        else if (value == '\\') {
-           value = utf8_to_uv((U8*)PL_regcomp_parse, &numlen);
+           value = (U32)utf8_to_uv((U8*)PL_regcomp_parse, &numlen);
            PL_regcomp_parse += numlen;
+           /* Some compilers cannot handle switching on 64-bit integer
+            * values, therefore value cannot be an UV.  Yes, this will
+            * be a problem later if we want switch on Unicode.  --jhi */
            switch (value) {
            case 'w':           namedclass = ANYOF_ALNUM;               break;
            case 'W':           namedclass = ANYOF_NALNUM;              break;
@@ -2681,10 +3383,10 @@ S_regclassutf8(pTHX)
                if (!SIZE_ONLY) {
                    if (value == 'p')
                        Perl_sv_catpvf(aTHX_ listsv,
-                                      "+utf8::%.*s\n", n, PL_regcomp_parse);
+                                      "+utf8::%.*s\n", (int)n, PL_regcomp_parse);
                    else
                        Perl_sv_catpvf(aTHX_ listsv,
-                                      "!utf8::%.*s\n", n, PL_regcomp_parse);
+                                      "!utf8::%.*s\n", (int)n, PL_regcomp_parse);
                }
                PL_regcomp_parse = e + 1;
                lastvalue = OOB_UTF8;
@@ -2694,20 +3396,25 @@ S_regclassutf8(pTHX)
            case 't':           value = '\t';           break;
            case 'f':           value = '\f';           break;
            case 'b':           value = '\b';           break;
+#ifdef ASCIIish
            case 'e':           value = '\033';         break;
            case 'a':           value = '\007';         break;
+#else
+           case 'e':           value = '\047';         break;
+           case 'a':           value = '\057';         break;
+#endif
            case 'x':
                if (*PL_regcomp_parse == '{') {
                    e = strchr(PL_regcomp_parse++, '}');
                     if (!e)
                         FAIL("Missing right brace on \\x{}");
-                   value = scan_hex(PL_regcomp_parse,
+                   value = (UV)scan_hex(PL_regcomp_parse,
                                     e - PL_regcomp_parse,
                                     &numlen);
                    PL_regcomp_parse = e + 1;
                }
                else {
-                   value = scan_hex(PL_regcomp_parse, 2, &numlen);
+                   value = (UV)scan_hex(PL_regcomp_parse, 2, &numlen);
                    PL_regcomp_parse += numlen;
                }
                break;
@@ -2717,87 +3424,130 @@ S_regclassutf8(pTHX)
                break;
            case '0': case '1': case '2': case '3': case '4':
            case '5': case '6': case '7': case '8': case '9':
-               value = scan_oct(--PL_regcomp_parse, 3, &numlen);
+               value = (UV)scan_oct(--PL_regcomp_parse, 3, &numlen);
                PL_regcomp_parse += numlen;
                break;
+           default:
+               if (!SIZE_ONLY && ckWARN(WARN_REGEXP) && isALPHA(value))
+                   Perl_warner(aTHX_ WARN_REGEXP, 
+                               "/%.127s/: Unrecognized escape \\%c in character class passed through",
+                               PL_regprecomp,
+                               (int)value);
+               break;
            }
        }
-       if (!SIZE_ONLY && namedclass > -1) {
-           switch (namedclass) {
-           case ANYOF_ALNUM:
-               Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsWord\n");        break;
-           case ANYOF_NALNUM:
-               Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsWord\n");        break;
-           case ANYOF_ALNUMC:
-               Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsAlnum\n");       break;
-           case ANYOF_NALNUMC:
-               Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsAlnum\n");       break;
-           case ANYOF_ALPHA:
-               Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsAlpha\n");       break;
-           case ANYOF_NALPHA:
-               Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsAlpha\n");       break;
-           case ANYOF_ASCII:
-               Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsASCII\n");       break;
-           case ANYOF_NASCII:
-               Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsASCII\n");       break;
-           case ANYOF_CNTRL:
-               Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsCntrl\n");       break;
-           case ANYOF_NCNTRL:
-               Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsCntrl\n");       break;
-           case ANYOF_GRAPH:
-               Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsGraph\n");       break;
-           case ANYOF_NGRAPH:
-               Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsGraph\n");       break;
-           case ANYOF_DIGIT:
-               Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsDigit\n");       break;
-           case ANYOF_NDIGIT:
-               Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsDigit\n");       break;
-           case ANYOF_LOWER:
-               Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsLower\n");       break;
-           case ANYOF_NLOWER:
-               Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsLower\n");       break;
-           case ANYOF_PRINT:
-               Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsPrint\n");       break;
-           case ANYOF_NPRINT:
-               Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsPrint\n");       break;
-           case ANYOF_PUNCT:
-               Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsPunct\n");       break;
-           case ANYOF_NPUNCT:
-               Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsPunct\n");       break;
-           case ANYOF_SPACE:
-               Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsSpace\n");       break;
-           case ANYOF_NSPACE:
-               Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsSpace\n");       break;
-           case ANYOF_UPPER:
-               Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsUpper\n");       break;
-           case ANYOF_NUPPER:
-               Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsUpper\n");       break;
-           case ANYOF_XDIGIT:
-               Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsXDigit\n");      break;
-           case ANYOF_NXDIGIT:
-               Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsXDigit\n");      break;
+       if (namedclass > OOB_NAMEDCLASS) {
+           if (range) { /* a-\d, a-[:digit:] */
+               if (!SIZE_ONLY) {
+                   if (ckWARN(WARN_REGEXP))
+                       Perl_warner(aTHX_ WARN_REGEXP,
+                                   "/%.127s/: false [] range \"%*.*s\" in regexp",
+                                   PL_regprecomp,
+                                   PL_regcomp_parse - rangebegin,
+                                   PL_regcomp_parse - rangebegin,
+                                   rangebegin);
+                   Perl_sv_catpvf(aTHX_ listsv,
+                                  /* 0x002D is Unicode for '-' */
+                                  "%04"UVxf"\n002D\n", (UV)lastvalue);
+               }
+               range = 0;
+           }
+           if (!SIZE_ONLY) {
+               switch (namedclass) {
+               case ANYOF_ALNUM:
+                   Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsWord\n");    break;
+               case ANYOF_NALNUM:
+                   Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsWord\n");    break;
+               case ANYOF_ALNUMC:
+                   Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsAlnum\n");   break;
+               case ANYOF_NALNUMC:
+                   Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsAlnum\n");   break;
+               case ANYOF_ALPHA:
+                   Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsAlpha\n");   break;
+               case ANYOF_NALPHA:
+                   Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsAlpha\n");   break;
+               case ANYOF_ASCII:
+                   Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsASCII\n");   break;
+               case ANYOF_NASCII:
+                   Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsASCII\n");   break;
+               case ANYOF_CNTRL:
+                   Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsCntrl\n");   break;
+               case ANYOF_NCNTRL:
+                   Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsCntrl\n");   break;
+               case ANYOF_GRAPH:
+                   Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsGraph\n");   break;
+               case ANYOF_NGRAPH:
+                   Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsGraph\n");   break;
+               case ANYOF_DIGIT:
+                   Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsDigit\n");   break;
+               case ANYOF_NDIGIT:
+                   Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsDigit\n");   break;
+               case ANYOF_LOWER:
+                   Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsLower\n");   break;
+               case ANYOF_NLOWER:
+                   Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsLower\n");   break;
+               case ANYOF_PRINT:
+                   Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsPrint\n");   break;
+               case ANYOF_NPRINT:
+                   Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsPrint\n");   break;
+               case ANYOF_PUNCT:
+                   Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsPunct\n");   break;
+               case ANYOF_NPUNCT:
+                   Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsPunct\n");   break;
+               case ANYOF_SPACE:
+                   Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsSpace\n");   break;
+               case ANYOF_NSPACE:
+                   Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsSpace\n");   break;
+               case ANYOF_UPPER:
+                   Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsUpper\n");   break;
+               case ANYOF_NUPPER:
+                   Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsUpper\n");   break;
+               case ANYOF_XDIGIT:
+                   Perl_sv_catpvf(aTHX_ listsv, "+utf8::IsXDigit\n");  break;
+               case ANYOF_NXDIGIT:
+                   Perl_sv_catpvf(aTHX_ listsv, "!utf8::IsXDigit\n");  break;
+               }
+               continue;
            }
        }
-        else
         if (range) {
-           if (lastvalue > value)
-               FAIL("invalid [] range in regexp");
-           if (!SIZE_ONLY)
-               Perl_sv_catpvf(aTHX_ listsv, "%04x\t%04x\n", lastvalue, value);
-           lastvalue = value;
+           if (lastvalue > value) { /* b-a */
+               Perl_croak(aTHX_
+                          "/%.127s/: invalid [] range \"%*.*s\" in regexp",
+                          PL_regprecomp,
+                          PL_regcomp_parse - rangebegin,
+                          PL_regcomp_parse - rangebegin,
+                          rangebegin);
+           }
            range = 0;
        }
        else {
            lastvalue = value;
            if (*PL_regcomp_parse == '-' && PL_regcomp_parse+1 < PL_regxend &&
-             PL_regcomp_parse[1] != ']') {
+               PL_regcomp_parse[1] != ']') {
                PL_regcomp_parse++;
-               range = 1;
+               if (namedclass > OOB_NAMEDCLASS) { /* \w-, [:word:]- */
+                   if (ckWARN(WARN_REGEXP))
+                       Perl_warner(aTHX_ WARN_REGEXP,
+                                   "/%.127s/: false [] range \"%*.*s\" in regexp",
+                                   PL_regprecomp,
+                                   PL_regcomp_parse - rangebegin,
+                                   PL_regcomp_parse - rangebegin,
+                                   rangebegin);
+                   if (!SIZE_ONLY)
+                       Perl_sv_catpvf(aTHX_ listsv,
+                                      /* 0x002D is Unicode for '-' */
+                                      "002D\n");
+               } else
+                   range = 1;
                continue;       /* do it next time */
            }
-           if (!SIZE_ONLY)
-               Perl_sv_catpvf(aTHX_ listsv, "%04x\n", value);
        }
+       /* now is the next time */
+       if (!SIZE_ONLY)
+           Perl_sv_catpvf(aTHX_ listsv, "%04"UVxf"\t%04"UVxf"\n",
+                          (UV)lastvalue, (UV)value);
+       range = 0;
     }
 
     ret = reganode(ANYOFUTF8, 0);
@@ -2895,14 +3645,14 @@ S_reganode(pTHX_ U8 op, U32 arg)
 }
 
 /*
-- regc - emit (if appropriate) a Unicode character
+- reguni - emit (if appropriate) a Unicode character
 */
 STATIC void
 S_reguni(pTHX_ UV uv, char* s, I32* lenp)
 {
     dTHR;
     if (SIZE_ONLY) {
-       U8 tmpbuf[10];
+       U8 tmpbuf[UTF8_MAXLEN];
        *lenp = uv_to_utf8(tmpbuf, uv) - tmpbuf;
     }
     else
@@ -2911,17 +3661,6 @@ S_reguni(pTHX_ UV uv, char* s, I32* lenp)
 }
 
 /*
-- regc - emit (if appropriate) a byte of code
-*/
-STATIC void
-S_regc(pTHX_ U8 b, char* s)
-{
-    dTHR;
-    if (!SIZE_ONLY)
-       *s = b;
-}
-
-/*
 - reginsert - insert an operator in front of already-emitted operand
 *
 * Means relocating the operand.
@@ -2963,7 +3702,6 @@ S_regtail(pTHX_ regnode *p, regnode *val)
     dTHR;
     register regnode *scan;
     register regnode *temp;
-    register I32 offset;
 
     if (SIZE_ONLY)
        return;
@@ -3032,7 +3770,7 @@ S_dumpuntil(pTHX_ regnode *start, regnode *node, regnode *last, SV* sv, I32 l)
 {
 #ifdef DEBUGGING
     register U8 op = EXACT;    /* Arbitrary non-END op. */
-    register regnode *next, *onode;
+    register regnode *next;
 
     while (op != END && (!last || node < last)) {
        /* While that wasn't END last time... */
@@ -3046,12 +3784,12 @@ S_dumpuntil(pTHX_ regnode *start, regnode *node, regnode *last, SV* sv, I32 l)
        if (OP(node) == OPTIMIZED)
            goto after_print;
        regprop(sv, node);
-       PerlIO_printf(Perl_debug_log, "%4d:%*s%s", node - start, 
-                     2*l + 1, "", SvPVX(sv));
+       PerlIO_printf(Perl_debug_log, "%4"IVdf":%*s%s", (IV)(node - start),
+                     (int)(2*l + 1), "", SvPVX(sv));
        if (next == NULL)               /* Next ptr. */
            PerlIO_printf(Perl_debug_log, "(0)");
        else 
-           PerlIO_printf(Perl_debug_log, "(%d)", next - start);
+           PerlIO_printf(Perl_debug_log, "(%"IVdf")", (IV)(next - start));
        (void)PerlIO_putc(Perl_debug_log, '\n');
       after_print:
        if (PL_regkind[(U8)op] == BRANCHJ) {
@@ -3078,11 +3816,11 @@ S_dumpuntil(pTHX_ regnode *start, regnode *node, regnode *last, SV* sv, I32 l)
        }
        else if (op == ANYOF) {
            node = NEXTOPER(node);
-           node += ANY_SKIP;
+           node += ANYOF_SKIP;
        }
        else if (PL_regkind[(U8)op] == EXACT) {
             /* Literal string, where present. */
-           node += ((*OPERAND(node)) + 2 + sizeof(regnode) - 1) / sizeof(regnode);
+           node += NODE_SZ_STR(node) - 1;
            node = NEXTOPER(node);
        }
        else {
@@ -3112,19 +3850,23 @@ Perl_regdump(pTHX_ regexp *r)
 
     /* Header fields of interest. */
     if (r->anchored_substr)
-       PerlIO_printf(Perl_debug_log, "anchored `%s%s%s'%s at %d ", 
+       PerlIO_printf(Perl_debug_log,
+                     "anchored `%s%.*s%s'%s at %"IVdf" ", 
                      PL_colors[0],
+                     (int)(SvCUR(r->anchored_substr) - (SvTAIL(r->anchored_substr)!=0)),
                      SvPVX(r->anchored_substr), 
                      PL_colors[1],
                      SvTAIL(r->anchored_substr) ? "$" : "",
-                     r->anchored_offset);
+                     (IV)r->anchored_offset);
     if (r->float_substr)
-       PerlIO_printf(Perl_debug_log, "floating `%s%s%s'%s at %d..%u ", 
+       PerlIO_printf(Perl_debug_log,
+                     "floating `%s%.*s%s'%s at %"IVdf"..%"UVuf" ", 
                      PL_colors[0],
-                     SvPVX(r->float_substr), 
+                     (int)(SvCUR(r->float_substr) - (SvTAIL(r->float_substr)!=0)), 
+                     SvPVX(r->float_substr),
                      PL_colors[1],
                      SvTAIL(r->float_substr) ? "$" : "",
-                     r->float_min_offset, r->float_max_offset);
+                     (IV)r->float_min_offset, (UV)r->float_max_offset);
     if (r->check_substr)
        PerlIO_printf(Perl_debug_log, 
                      r->check_substr == r->float_substr 
@@ -3165,6 +3907,17 @@ Perl_regdump(pTHX_ regexp *r)
 #endif /* DEBUGGING */
 }
 
+STATIC void
+S_put_byte(pTHX_ SV *sv, int c)
+{
+    if (c <= ' ' || c == 127 || c == 255)
+       Perl_sv_catpvf(aTHX_ sv, "\\%o", c);
+    else if (c == '-' || c == ']' || c == '\\' || c == '^')
+       Perl_sv_catpvf(aTHX_ sv, "\\%c", c);
+    else
+       Perl_sv_catpvf(aTHX_ sv, "%c", c);
+}
+
 /*
 - regprop - printable representation of opcode
 */
@@ -3183,16 +3936,80 @@ Perl_regprop(pTHX_ SV *sv, regnode *o)
     k = PL_regkind[(U8)OP(o)];
 
     if (k == EXACT)
-       Perl_sv_catpvf(aTHX_ sv, " <%s%s%s>", PL_colors[0], OPERAND(o) + 1, PL_colors[1]);
+       Perl_sv_catpvf(aTHX_ sv, " <%s%.*s%s>", PL_colors[0],
+                      STR_LEN(o), STRING(o), PL_colors[1]);
     else if (k == CURLY) {
        if (OP(o) == CURLYM || OP(o) == CURLYN)
            Perl_sv_catpvf(aTHX_ sv, "[%d]", o->flags); /* Parenth number */
        Perl_sv_catpvf(aTHX_ sv, " {%d,%d}", ARG1(o), ARG2(o));
     }
+    else if (k == WHILEM && o->flags)                  /* Ordinal/of */
+       Perl_sv_catpvf(aTHX_ sv, "[%d/%d]", o->flags & 0xf, o->flags>>4);
     else if (k == REF || k == OPEN || k == CLOSE || k == GROUPP )
-       Perl_sv_catpvf(aTHX_ sv, "%d", ARG(o)); /* Parenth number */
+       Perl_sv_catpvf(aTHX_ sv, "%d", (int)ARG(o));    /* Parenth number */
     else if (k == LOGICAL)
-       Perl_sv_catpvf(aTHX_ sv, "[%d]", ARG(o));       /* 2: embedded, otherwise 1 */
+       Perl_sv_catpvf(aTHX_ sv, "[%d]", o->flags);     /* 2: embedded, otherwise 1 */
+    else if (k == ANYOF) {
+       int i, rangestart = -1;
+       const char * const out[] = {    /* Should be syncronized with
+                                          a table in regcomp.h */
+           "\\w",
+           "\\W",
+           "\\s",
+           "\\S",
+           "\\d",
+           "\\D",
+           "[:alnum:]",
+           "[:^alnum:]",
+           "[:alpha:]",
+           "[:^alpha:]",
+           "[:ascii:]",
+           "[:^ascii:]",
+           "[:ctrl:]",
+           "[:^ctrl:]",
+           "[:graph:]",
+           "[:^graph:]",
+           "[:lower:]",
+           "[:^lower:]",
+           "[:print:]",
+           "[:^print:]",
+           "[:punct:]",
+           "[:^punct:]",
+           "[:upper:]",
+           "[:!upper:]",
+           "[:xdigit:]",
+           "[:^xdigit:]"
+       };
+
+       if (o->flags & ANYOF_LOCALE)
+           sv_catpv(sv, "{loc}");
+       if (o->flags & ANYOF_FOLD)
+           sv_catpv(sv, "{i}");
+       Perl_sv_catpvf(aTHX_ sv, "[%s", PL_colors[0]);
+       if (o->flags & ANYOF_INVERT)
+           sv_catpv(sv, "^");
+       for (i = 0; i <= 256; i++) {
+           if (i < 256 && ANYOF_BITMAP_TEST(o,i)) {
+               if (rangestart == -1)
+                   rangestart = i;
+           } else if (rangestart != -1) {
+               if (i <= rangestart + 3)
+                   for (; rangestart < i; rangestart++)
+                       put_byte(sv, rangestart);
+               else {
+                   put_byte(sv, rangestart);
+                   sv_catpv(sv, "-");
+                   put_byte(sv, i - 1);
+               }
+               rangestart = -1;
+           }
+       }
+       if (o->flags & ANYOF_CLASS)
+           for (i = 0; i < sizeof(out)/sizeof(char*); i++)
+               if (ANYOF_CLASS_TEST(o,i))
+                   sv_catpv(sv, out[i]);
+       Perl_sv_catpvf(aTHX_ sv, "%s]", PL_colors[1]);
+    }
     else if (k == BRANCHJ && (OP(o) == UNLESSM || OP(o) == IFMATCH))
        Perl_sv_catpvf(aTHX_ sv, "[-%d]", o->flags);
 #endif /* DEBUGGING */
@@ -3221,6 +4038,10 @@ void
 Perl_pregfree(pTHX_ struct regexp *r)
 {
     dTHR;
+    DEBUG_r(if (!PL_colorset) reginitcolors());
+
+    if (!r || (--r->refcnt > 0))
+       return;
     DEBUG_r(PerlIO_printf(Perl_debug_log,
                      "%sFreeing REx:%s `%s%.60s%s%s'\n",
                      PL_colors[4],PL_colors[5],PL_colors[0],
@@ -3228,9 +4049,6 @@ Perl_pregfree(pTHX_ struct regexp *r)
                      PL_colors[1],
                      (strlen(r->precomp) > 60 ? "..." : "")));
 
-
-    if (!r || (--r->refcnt > 0))
-       return;
     if (r->precomp)
        Safefree(r->precomp);
     if (RX_MATCH_COPIED(r))
@@ -3253,6 +4071,9 @@ Perl_pregfree(pTHX_ struct regexp *r)
            case 's':
                SvREFCNT_dec((SV*)r->data->data[n]);
                break;
+           case 'f':
+               Safefree(r->data->data[n]);
+               break;
            case 'p':
                new_comppad = (AV*)r->data->data[n];
                break;
@@ -3329,7 +4150,7 @@ S_re_croak2(pTHX_ const char* pat1,const char* pat2,...)
 #else
     va_start(args);
 #endif
-    msv = mess(buf, &args);
+    msv = vmess(buf, &args);
     va_end(args);
     message = SvPV(msv,l1);
     if (l1 > 512)
@@ -3353,40 +4174,53 @@ Perl_save_re_context(pTHX)
     SAVEPPTR(PL_reginput);             /* String-input pointer. */
     SAVEPPTR(PL_regbol);               /* Beginning of input, for ^ check. */
     SAVEPPTR(PL_regeol);               /* End of input, for $ check. */
-    SAVESPTR(PL_regstartp);            /* Pointer to startp array. */
-    SAVESPTR(PL_regendp);              /* Ditto for endp. */
-    SAVESPTR(PL_reglastparen);         /* Similarly for lastparen. */
+    SAVEVPTR(PL_regstartp);            /* Pointer to startp array. */
+    SAVEVPTR(PL_regendp);              /* Ditto for endp. */
+    SAVEVPTR(PL_reglastparen);         /* Similarly for lastparen. */
     SAVEPPTR(PL_regtill);              /* How far we are required to go. */
-    SAVEI32(PL_regprev);               /* char before regbol, \n if none */
-    SAVESPTR(PL_reg_start_tmp);                /* from regexec.c */
+    SAVEI8(PL_regprev);                        /* char before regbol, \n if none */
+    SAVEVPTR(PL_reg_start_tmp);                /* from regexec.c */
     PL_reg_start_tmp = 0;
     SAVEFREEPV(PL_reg_start_tmp);
     SAVEI32(PL_reg_start_tmpl);                /* from regexec.c */
     PL_reg_start_tmpl = 0;
-    SAVESPTR(PL_regdata);
+    SAVEVPTR(PL_regdata);
     SAVEI32(PL_reg_flags);             /* from regexec.c */
     SAVEI32(PL_reg_eval_set);          /* from regexec.c */
     SAVEI32(PL_regnarrate);            /* from regexec.c */
-    SAVESPTR(PL_regprogram);           /* from regexec.c */
+    SAVEVPTR(PL_regprogram);           /* from regexec.c */
     SAVEINT(PL_regindent);             /* from regexec.c */
-    SAVESPTR(PL_regcc);                        /* from regexec.c */
-    SAVESPTR(PL_curcop);
-    SAVESPTR(PL_regcomp_rx);           /* from regcomp.c */
+    SAVEVPTR(PL_regcc);                        /* from regexec.c */
+    SAVEVPTR(PL_curcop);
+    SAVEVPTR(PL_regcomp_rx);           /* from regcomp.c */
     SAVEI32(PL_regseen);               /* from regcomp.c */
     SAVEI32(PL_regsawback);            /* Did we see \1, ...? */
     SAVEI32(PL_regnaughty);            /* How bad is this pattern? */
-    SAVESPTR(PL_regcode);              /* Code-emit pointer; &regdummy = don't */
+    SAVEVPTR(PL_regcode);              /* Code-emit pointer; &regdummy = don't */
     SAVEPPTR(PL_regxend);              /* End of input for compile */
     SAVEPPTR(PL_regcomp_parse);                /* Input-scan pointer. */
-    SAVESPTR(PL_reg_call_cc);          /* from regexec.c */
-    SAVESPTR(PL_reg_re);               /* from regexec.c */
+    SAVEVPTR(PL_reg_call_cc);          /* from regexec.c */
+    SAVEVPTR(PL_reg_re);               /* from regexec.c */
     SAVEPPTR(PL_reg_ganch);            /* from regexec.c */
     SAVESPTR(PL_reg_sv);               /* from regexec.c */
-    SAVESPTR(PL_reg_magic);            /* from regexec.c */
+    SAVEVPTR(PL_reg_magic);            /* from regexec.c */
     SAVEI32(PL_reg_oldpos);                    /* from regexec.c */
-    SAVESPTR(PL_reg_oldcurpm);         /* from regexec.c */
-    SAVESPTR(PL_reg_curpm);            /* from regexec.c */
+    SAVEVPTR(PL_reg_oldcurpm);         /* from regexec.c */
+    SAVEVPTR(PL_reg_curpm);            /* from regexec.c */
 #ifdef DEBUGGING
     SAVEPPTR(PL_reg_starttry);         /* from regexec.c */    
 #endif
 }
+
+#ifdef PERL_OBJECT
+#include "XSUB.h"
+#undef this
+#define this pPerl
+#endif
+
+static void
+clear_re(pTHXo_ void *r)
+{
+    ReREFCNT_dec((regexp *)r);
+}
+