]> git.lyx.org Git - lyx.git/blobdiff - boost/boost/regex/v4/basic_regex_parser.hpp
Also display the info about BibTeX databases in the TeX info panel.
[lyx.git] / boost / boost / regex / v4 / basic_regex_parser.hpp
index 08e705ad00d384efc4f59cf5ccef04c1ae6d4ac5..87ff6e204227a1e50d1ac4b38fa7ada3ed60599b 100644 (file)
 #ifndef BOOST_REGEX_V4_BASIC_REGEX_PARSER_HPP
 #define BOOST_REGEX_V4_BASIC_REGEX_PARSER_HPP
 
+#ifdef BOOST_MSVC
+#pragma warning(push)
+#pragma warning(disable: 4103)
+#endif
 #ifdef BOOST_HAS_ABI_HEADERS
 #  include BOOST_ABI_PREFIX
 #endif
+#ifdef BOOST_MSVC
+#pragma warning(pop)
+#endif
 
 namespace boost{
 namespace re_detail{
 
 #ifdef BOOST_MSVC
 #pragma warning(push)
-#pragma warning(disable:4244)
+#pragma warning(disable:4244 4800)
 #endif
 
 template <class charT, class traits>
@@ -38,6 +45,11 @@ public:
    basic_regex_parser(regex_data<charT, traits>* data);
    void parse(const charT* p1, const charT* p2, unsigned flags);
    void fail(regex_constants::error_type error_code, std::ptrdiff_t position);
+   void fail(regex_constants::error_type error_code, std::ptrdiff_t position, std::string message, std::ptrdiff_t start_pos);
+   void fail(regex_constants::error_type error_code, std::ptrdiff_t position, const std::string& message)
+   {
+      fail(error_code, position, message, position);
+   }
 
    bool parse_all();
    bool parse_basic();
@@ -71,6 +83,8 @@ private:
    const charT*               m_end;            // the end of the string being parsed
    const charT*               m_position;       // our current parser position
    unsigned                   m_mark_count;     // how many sub-expressions we have
+   int                        m_mark_reset;     // used to indicate that we're inside a (?|...) block.
+   unsigned                   m_max_mark;       // largest mark count seen inside a (?|...) block.
    std::ptrdiff_t             m_paren_start;    // where the last seen ')' began (where repeats are inserted).
    std::ptrdiff_t             m_alt_insert_point; // where to insert the next alternative
    bool                       m_has_case_change; // true if somewhere in the current block the case has changed
@@ -89,7 +103,7 @@ private:
 
 template <class charT, class traits>
 basic_regex_parser<charT, traits>::basic_regex_parser(regex_data<charT, traits>* data)
-   : basic_regex_creator<charT, traits>(data), m_mark_count(0), m_paren_start(0), m_alt_insert_point(0), m_has_case_change(false)
+   : basic_regex_creator<charT, traits>(data), m_mark_count(0), m_mark_reset(-1), m_max_mark(0), m_paren_start(0), m_alt_insert_point(0), m_has_case_change(false)
 {
 }
 
@@ -102,7 +116,12 @@ void basic_regex_parser<charT, traits>::parse(const charT* p1, const charT* p2,
    m_position = m_base = p1;
    m_end = p2;
    // empty strings are errors:
-   if(p1 == p2)
+   if((p1 == p2) && 
+      (
+         ((l_flags & regbase::main_option_type) != regbase::perl_syntax_group)
+         || (l_flags & regbase::no_empty_expressions)
+      )
+     )
    {
       fail(regex_constants::error_empty, 0);
       return;
@@ -111,14 +130,27 @@ void basic_regex_parser<charT, traits>::parse(const charT* p1, const charT* p2,
    switch(l_flags & regbase::main_option_type)
    {
    case regbase::perl_syntax_group:
-      m_parser_proc = &basic_regex_parser<charT, traits>::parse_extended;
-      break;
+      {
+         m_parser_proc = &basic_regex_parser<charT, traits>::parse_extended;
+         //
+         // Add a leading paren with index zero to give recursions a target:
+         //
+         re_brace* br = static_cast<re_brace*>(this->append_state(syntax_element_startmark, sizeof(re_brace)));
+         br->index = 0;
+         br->icase = this->flags() & regbase::icase;
+         break;
+      }
    case regbase::basic_syntax_group:
       m_parser_proc = &basic_regex_parser<charT, traits>::parse_basic;
       break;
    case regbase::literal:
       m_parser_proc = &basic_regex_parser<charT, traits>::parse_literal;
       break;
+   default:
+      // Ooops, someone has managed to set more than one of the main option flags, 
+      // so this must be an error:
+      fail(regex_constants::error_unknown, 0, "An invalid combination of regular expression syntax flags was used.");
+      return;
    }
 
    // parse all our characters:
@@ -133,7 +165,7 @@ void basic_regex_parser<charT, traits>::parse(const charT* p1, const charT* p2,
    // have had an unexpected ')' :
    if(!result)
    {
-      fail(regex_constants::error_paren, ::boost::re_detail::distance(m_base, m_position));
+      fail(regex_constants::error_paren, ::boost::re_detail::distance(m_base, m_position), "Found a closing ) with no corresponding openening parenthesis.");
       return;
    }
    // if an error has been set then give up now:
@@ -146,13 +178,40 @@ void basic_regex_parser<charT, traits>::parse(const charT* p1, const charT* p2,
 
 template <class charT, class traits>
 void basic_regex_parser<charT, traits>::fail(regex_constants::error_type error_code, std::ptrdiff_t position)
+{
+   // get the error message:
+   std::string message = this->m_pdata->m_ptraits->error_string(error_code);
+   fail(error_code, position, message);
+}
+
+template <class charT, class traits>
+void basic_regex_parser<charT, traits>::fail(regex_constants::error_type error_code, std::ptrdiff_t position, std::string message, std::ptrdiff_t start_pos)
 {
    if(0 == this->m_pdata->m_status) // update the error code if not already set
       this->m_pdata->m_status = error_code;
    m_position = m_end; // don't bother parsing anything else
-   // get the error message:
-   std::string message = this->m_pdata->m_ptraits->error_string(error_code);
-   // and raise the exception, this will do nothing if exceptions are disabled:
+
+   //
+   // Augment error message with the regular expression text:
+   //
+   if(start_pos == position)
+      start_pos = (std::max)(static_cast<std::ptrdiff_t>(0), position - static_cast<std::ptrdiff_t>(10));
+   std::ptrdiff_t end_pos = (std::min)(position + static_cast<std::ptrdiff_t>(10), static_cast<std::ptrdiff_t>(m_end - m_base));
+   if(error_code != regex_constants::error_empty)
+   {
+      if((start_pos != 0) || (end_pos != (m_end - m_base)))
+         message += "  The error occured while parsing the regular expression fragment: '";
+      else
+         message += "  The error occured while parsing the regular expression: '";
+      if(start_pos != end_pos)
+      {
+         message += std::string(m_base + start_pos, m_base + position);
+         message += ">>>HERE>>>";
+         message += std::string(m_base + position, m_base + end_pos);
+      }
+      message += "'.";
+   }
+
 #ifndef BOOST_NO_EXCEPTIONS
    if(0 == (this->flags() & regex_constants::no_except))
    {
@@ -260,7 +319,7 @@ bool basic_regex_parser<charT, traits>::parse_extended()
    case regex_constants::syntax_star:
       if(m_position == this->m_base)
       {
-         fail(regex_constants::error_badrepeat, 0);
+         fail(regex_constants::error_badrepeat, 0, "The repeat operator \"*\" cannot start a regular expression.");
          return false;
       }
       ++m_position;
@@ -268,7 +327,7 @@ bool basic_regex_parser<charT, traits>::parse_extended()
    case regex_constants::syntax_question:
       if(m_position == this->m_base)
       {
-         fail(regex_constants::error_badrepeat, 0);
+         fail(regex_constants::error_badrepeat, 0, "The repeat operator \"?\" cannot start a regular expression.");
          return false;
       }
       ++m_position;
@@ -276,7 +335,7 @@ bool basic_regex_parser<charT, traits>::parse_extended()
    case regex_constants::syntax_plus:
       if(m_position == this->m_base)
       {
-         fail(regex_constants::error_badrepeat, 0);
+         fail(regex_constants::error_badrepeat, 0, "The repeat operator \"+\" cannot start a regular expression.");
          return false;
       }
       ++m_position;
@@ -285,7 +344,7 @@ bool basic_regex_parser<charT, traits>::parse_extended()
       ++m_position;
       return parse_repeat_range(false);
    case regex_constants::syntax_close_brace:
-      fail(regex_constants::error_brace, this->m_position - this->m_end);
+      fail(regex_constants::error_brace, this->m_position - this->m_base, "Found a closing repetition operator } with no corresponding {.");
       return false;
    case regex_constants::syntax_or:
       return parse_alt();
@@ -361,9 +420,19 @@ bool basic_regex_parser<charT, traits>::parse_open_paren()
    //
    unsigned markid = 0;
    if(0 == (this->flags() & regbase::nosubs))
+   {
       markid = ++m_mark_count;
+#ifndef BOOST_NO_STD_DISTANCE
+      if(this->flags() & regbase::save_subexpression_location)
+         this->m_pdata->m_subs.push_back(std::pair<std::size_t, std::size_t>(std::distance(m_base, m_position) - 1, 0));
+#else
+      if(this->flags() & regbase::save_subexpression_location)
+         this->m_pdata->m_subs.push_back(std::pair<std::size_t, std::size_t>((m_position - m_base) - 1, 0));
+#endif
+   }
    re_brace* pb = static_cast<re_brace*>(this->append_state(syntax_element_startmark, sizeof(re_brace)));
    pb->index = markid;
+   pb->icase = this->flags() & regbase::icase;
    std::ptrdiff_t last_paren_start = this->getoffset(pb);
    // back up insertion point for alternations, and set new point:
    std::ptrdiff_t last_alt_point = m_alt_insert_point;
@@ -376,6 +445,11 @@ bool basic_regex_parser<charT, traits>::parse_open_paren()
    bool old_case_change = m_has_case_change;
    m_has_case_change = false; // no changes to this scope as yet...
    //
+   // Back up branch reset data in case we have a nested (?|...)
+   //
+   int mark_reset = m_mark_reset;
+   m_mark_reset = -1;
+   //
    // now recursively add more states, this will terminate when we get to a
    // matching ')' :
    //
@@ -400,6 +474,10 @@ bool basic_regex_parser<charT, traits>::parse_open_paren()
    this->flags(opts);
    m_has_case_change = old_case_change;
    //
+   // restore branch reset:
+   //
+   m_mark_reset = mark_reset;
+   //
    // we either have a ')' or we have run out of characters prematurely:
    //
    if(m_position == m_end)
@@ -408,12 +486,20 @@ bool basic_regex_parser<charT, traits>::parse_open_paren()
       return false;
    }
    BOOST_ASSERT(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_close_mark);
+#ifndef BOOST_NO_STD_DISTANCE
+   if(markid && (this->flags() & regbase::save_subexpression_location))
+      this->m_pdata->m_subs.at(markid - 1).second = std::distance(m_base, m_position);
+#else
+   if(markid && (this->flags() & regbase::save_subexpression_location))
+      this->m_pdata->m_subs.at(markid - 1).second = (m_position - m_base);
+#endif
    ++m_position;
    //
    // append closing parenthesis state:
    //
    pb = static_cast<re_brace*>(this->append_state(syntax_element_endmark, sizeof(re_brace)));
    pb->index = markid;
+   pb->icase = this->flags() & regbase::icase;
    this->m_paren_start = last_paren_start;
    //
    // restore the alternate insertion point:
@@ -463,7 +549,7 @@ bool basic_regex_parser<charT, traits>::parse_basic_escape()
    case regex_constants::syntax_close_brace:
       if(this->flags() & regbase::no_intervals)
          return parse_literal();
-      fail(regex_constants::error_brace, this->m_position - this->m_base);
+      fail(regex_constants::error_brace, this->m_position - this->m_base, "Found a closing repetition operator } with no corresponding {.");
       return false;
    case regex_constants::syntax_or:
       if(this->flags() & regbase::bk_vbar)
@@ -558,7 +644,7 @@ bool basic_regex_parser<charT, traits>::parse_basic_escape()
          case 'c':
          case 'C':
             // not supported yet:
-            fail(regex_constants::error_escape, m_position - m_base);
+            fail(regex_constants::error_escape, m_position - m_base, "The \\c and \\C escape sequences are not supported by POSIX basic regular expressions: try the Perl syntax instead.");
             return false;
          default:
             break;
@@ -582,6 +668,7 @@ bool basic_regex_parser<charT, traits>::parse_extended_escape()
       // fall through:
    case regex_constants::escape_type_class:
       {
+escape_type_class_jump:
          typedef typename traits::char_class_type mask_type;
          mask_type m = this->m_traits.lookup_classname(m_position, m_position+1);
          if(m != 0)
@@ -655,7 +742,7 @@ bool basic_regex_parser<charT, traits>::parse_extended_escape()
          char_class_type m;
          if(m_position == m_end)
          {
-            fail(regex_constants::error_escape, m_position - m_base);
+            fail(regex_constants::error_escape, m_position - m_base, "Incomplete property escape found.");
             return false;
          }
          // maybe have \p{ddd}
@@ -667,7 +754,7 @@ bool basic_regex_parser<charT, traits>::parse_extended_escape()
                ++m_position;
             if(m_position == m_end)
             {
-               fail(regex_constants::error_escape, m_position - m_base);
+               fail(regex_constants::error_escape, m_position - m_base, "Closing } missing from property escape sequence.");
                return false;
             }
             m = this->m_traits.lookup_classname(++base, m_position++);
@@ -690,8 +777,124 @@ bool basic_regex_parser<charT, traits>::parse_extended_escape()
             }
             return true;
          }
-         fail(regex_constants::error_ctype, m_position - m_base);
+         fail(regex_constants::error_ctype, m_position - m_base, "Escape sequence was neither a valid property nor a valid character class name.");
+         return false;
+      }
+   case regex_constants::escape_type_reset_start_mark:
+      if(0 == (this->flags() & (regbase::main_option_type | regbase::no_perl_ex)))
+      {
+         re_brace* pb = static_cast<re_brace*>(this->append_state(syntax_element_startmark, sizeof(re_brace)));
+         pb->index = -5;
+         pb->icase = this->flags() & regbase::icase;
+         this->m_pdata->m_data.align();
+         ++m_position;
+         return true;
       }
+      goto escape_type_class_jump;
+   case regex_constants::escape_type_line_ending:
+      if(0 == (this->flags() & (regbase::main_option_type | regbase::no_perl_ex)))
+      {
+         const charT* e = get_escape_R_string<charT>();
+         const charT* old_position = m_position;
+         const charT* old_end = m_end;
+         const charT* old_base = m_base;
+         m_position = e;
+         m_base = e;
+         m_end = e + traits::length(e);
+         bool r = parse_all();
+         m_position = ++old_position;
+         m_end = old_end;
+         m_base = old_base;
+         return r;
+      }
+      goto escape_type_class_jump;
+   case regex_constants::escape_type_extended_backref:
+      if(0 == (this->flags() & (regbase::main_option_type | regbase::no_perl_ex)))
+      {
+         bool have_brace = false;
+         bool negative = false;
+         static const char* incomplete_message = "Incomplete \\g escape found.";
+         if(++m_position == m_end)
+         {
+            fail(regex_constants::error_escape, m_position - m_base, incomplete_message);
+            return false;
+         }
+         // maybe have \g{ddd}
+         regex_constants::syntax_type syn = this->m_traits.syntax_type(*m_position);
+         regex_constants::syntax_type syn_end = 0;
+         if((syn == regex_constants::syntax_open_brace) 
+            || (syn == regex_constants::escape_type_left_word)
+            || (syn == regex_constants::escape_type_end_buffer))
+         {
+            if(++m_position == m_end)
+            {
+               fail(regex_constants::error_escape, m_position - m_base, incomplete_message);
+               return false;
+            }
+            have_brace = true;
+            switch(syn)
+            {
+            case regex_constants::syntax_open_brace:
+               syn_end = regex_constants::syntax_close_brace;
+               break;
+            case regex_constants::escape_type_left_word:
+               syn_end = regex_constants::escape_type_right_word;
+               break;
+            default:
+               syn_end = regex_constants::escape_type_end_buffer;
+               break;
+            }
+         }
+         negative = (*m_position == static_cast<charT>('-'));
+         if((negative) && (++m_position == m_end))
+         {
+            fail(regex_constants::error_escape, m_position - m_base, incomplete_message);
+            return false;
+         }
+         const charT* pc = m_position;
+         int i = this->m_traits.toi(pc, m_end, 10);
+         if((i < 0) && syn_end)
+         {
+            // Check for a named capture, get the leftmost one if there is more than one:
+            const charT* base = m_position;
+            while((m_position != m_end) && (this->m_traits.syntax_type(*m_position) != syn_end))
+            {
+               ++m_position;
+            }
+            i = hash_value_from_capture_name(base, m_position);
+            pc = m_position;
+         }
+         if(negative)
+            i = 1 + m_mark_count - i;
+         if(((i > 0) && (this->m_backrefs & (1u << (i-1)))) || ((i > 10000) && (this->m_pdata->get_id(i) > 0) && (this->m_backrefs & (1u << (this->m_pdata->get_id(i)-1)))))
+         {
+            m_position = pc;
+            re_brace* pb = static_cast<re_brace*>(this->append_state(syntax_element_backref, sizeof(re_brace)));
+            pb->index = i;
+            pb->icase = this->flags() & regbase::icase;
+         }
+         else
+         {
+            fail(regex_constants::error_backref, m_position - m_base);
+            return false;
+         }
+         m_position = pc;
+         if(have_brace)
+         {
+            if((m_position == m_end) || (this->m_traits.syntax_type(*m_position) != syn_end))
+            {
+               fail(regex_constants::error_escape, m_position - m_base, incomplete_message);
+               return false;
+            }
+            ++m_position;
+         }
+         return true;
+      }
+      goto escape_type_class_jump;
+   case regex_constants::escape_type_control_v:
+      if(0 == (this->flags() & (regbase::main_option_type | regbase::no_perl_ex)))
+         goto escape_type_class_jump;
+      // fallthrough:
    default:
       this->append_literal(unescape_character());
       break;
@@ -719,6 +922,7 @@ template <class charT, class traits>
 bool basic_regex_parser<charT, traits>::parse_repeat(std::size_t low, std::size_t high)
 {
    bool greedy = true;
+   bool pocessive = false;
    std::size_t insert_point;
    // 
    // when we get to here we may have a non-greedy ? mark still to come:
@@ -730,16 +934,24 @@ bool basic_regex_parser<charT, traits>::parse_repeat(std::size_t low, std::size_
          )
       )
    {
-      // OK we have a perl regex, check for a '?':
+      // OK we have a perl or emacs regex, check for a '?':
       if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_question)
       {
          greedy = false;
          ++m_position;
       }
+      // for perl regexes only check for pocessive ++ repeats.
+      if((m_position != m_end)
+         && (0 == (this->flags() & regbase::main_option_type)) 
+         && (this->m_traits.syntax_type(*m_position) == regex_constants::syntax_plus))
+      {
+         pocessive = true;
+         ++m_position;
+      }
    }
    if(0 == this->m_last_state)
    {
-      fail(regex_constants::error_badrepeat, ::boost::re_detail::distance(m_base, m_position));
+      fail(regex_constants::error_badrepeat, ::boost::re_detail::distance(m_base, m_position), "Nothing to repeat.");
       return false;
    }
    if(this->m_last_state->type == syntax_element_endmark)
@@ -777,6 +989,7 @@ bool basic_regex_parser<charT, traits>::parse_repeat(std::size_t low, std::size_
       case syntax_element_restart_continue:
       case syntax_element_jump:
       case syntax_element_startmark:
+      case syntax_element_backstep:
          // can't legally repeat any of the above:
          fail(regex_constants::error_badrepeat, m_position - m_base);
          return false;
@@ -803,12 +1016,45 @@ bool basic_regex_parser<charT, traits>::parse_repeat(std::size_t low, std::size_
    // now fill in the alt jump for the repeat:
    rep = static_cast<re_repeat*>(this->getaddress(rep_off));
    rep->alt.i = this->m_pdata->m_data.size() - rep_off;
+   //
+   // If the repeat is pocessive then bracket the repeat with a (?>...)
+   // independent sub-expression construct:
+   //
+   if(pocessive)
+   {
+      if(m_position != m_end)
+      {
+         //
+         // Check for illegal following quantifier, we have to do this here, because
+         // the extra states we insert below circumvents our usual error checking :-(
+         //
+         switch(this->m_traits.syntax_type(*m_position))
+         {
+         case regex_constants::syntax_star:
+         case regex_constants::syntax_plus:
+         case regex_constants::syntax_question:
+         case regex_constants::syntax_open_brace:
+            fail(regex_constants::error_badrepeat, m_position - m_base);
+            return false;
+         }
+      }
+      re_brace* pb = static_cast<re_brace*>(this->insert_state(insert_point, syntax_element_startmark, sizeof(re_brace)));
+      pb->index = -3;
+      pb->icase = this->flags() & regbase::icase;
+      jmp = static_cast<re_jump*>(this->insert_state(insert_point + sizeof(re_brace), syntax_element_jump, sizeof(re_jump)));
+      this->m_pdata->m_data.align();
+      jmp->alt.i = this->m_pdata->m_data.size() - this->getoffset(jmp);
+      pb = static_cast<re_brace*>(this->append_state(syntax_element_endmark, sizeof(re_brace)));
+      pb->index = -3;
+      pb->icase = this->flags() & regbase::icase;
+   }
    return true;
 }
 
 template <class charT, class traits>
 bool basic_regex_parser<charT, traits>::parse_repeat_range(bool isbasic)
 {
+   static const char* incomplete_message = "Missing } in quantified repetition.";
    //
    // parse a repeat-range:
    //
@@ -820,7 +1066,7 @@ bool basic_regex_parser<charT, traits>::parse_repeat_range(bool isbasic)
    // fail if at end:
    if(this->m_position == this->m_end)
    {
-      fail(regex_constants::error_brace, this->m_position - this->m_base);
+      fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message);
       return false;
    }
    // get min:
@@ -835,7 +1081,7 @@ bool basic_regex_parser<charT, traits>::parse_repeat_range(bool isbasic)
    }
    else if(this->m_position == this->m_end)
    {
-      fail(regex_constants::error_brace, this->m_position - this->m_base);
+      fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message);
       return false;
    }
    min = v;
@@ -849,7 +1095,7 @@ bool basic_regex_parser<charT, traits>::parse_repeat_range(bool isbasic)
          ++m_position;
       if(this->m_position == this->m_end)
       {
-         fail(regex_constants::error_brace, this->m_position - this->m_base);
+         fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message);
          return false;
       }
       // get the value if any:
@@ -867,7 +1113,7 @@ bool basic_regex_parser<charT, traits>::parse_repeat_range(bool isbasic)
    // OK now check trailing }:
    if(this->m_position == this->m_end)
    {
-      fail(regex_constants::error_brace, this->m_position - this->m_base);
+      fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message);
       return false;
    }
    if(isbasic)
@@ -877,13 +1123,13 @@ bool basic_regex_parser<charT, traits>::parse_repeat_range(bool isbasic)
          ++m_position;
          if(this->m_position == this->m_end)
          {
-            fail(regex_constants::error_brace, this->m_position - this->m_base);
+            fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message);
             return false;
          }
       }
       else
       {
-         fail(regex_constants::error_badbrace, this->m_position - this->m_base);
+         fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message);
          return false;
       }
    }
@@ -891,7 +1137,7 @@ bool basic_regex_parser<charT, traits>::parse_repeat_range(bool isbasic)
       ++m_position;
    else
    {
-      fail(regex_constants::error_badbrace, this->m_position - this->m_base);
+      fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message);
       return false;
    }
    //
@@ -899,7 +1145,11 @@ bool basic_regex_parser<charT, traits>::parse_repeat_range(bool isbasic)
    //
    if(min > max)
    {
-      fail(regex_constants::error_badbrace, this->m_position - this->m_base);
+      // Backtrack to error location:
+      m_position -= 2;
+      while(this->m_traits.isctype(*m_position, this->m_word_mask)) --m_position;
+         ++m_position;
+      fail(regex_constants::error_badbrace, m_position - m_base);
       return false;
    }
    return parse_repeat(min, max);
@@ -912,11 +1162,27 @@ bool basic_regex_parser<charT, traits>::parse_alt()
    // error check: if there have been no previous states,
    // or if the last state was a '(' then error:
    //
-   if((this->m_last_state == 0) || (this->m_last_state->type == syntax_element_startmark))
+   if(
+      ((this->m_last_state == 0) || (this->m_last_state->type == syntax_element_startmark))
+      &&
+      !(
+         ((this->flags() & regbase::main_option_type) == regbase::perl_syntax_group)
+           &&
+         ((this->flags() & regbase::no_empty_expressions) == 0)
+        )
+      )
    {
-      fail(regex_constants::error_empty, this->m_position - this->m_base);
+      fail(regex_constants::error_empty, this->m_position - this->m_base, "A regular expression can start with the alternation operator |.");
       return false;
    }
+   //
+   // Reset mark count if required:
+   //
+   if(m_max_mark < m_mark_count)
+      m_max_mark = m_mark_count;
+   if(m_mark_reset >= 0)
+      m_mark_count = m_mark_reset;
+
    ++m_position;
    //
    // we need to append a trailing jump: 
@@ -958,10 +1224,11 @@ bool basic_regex_parser<charT, traits>::parse_alt()
 template <class charT, class traits>
 bool basic_regex_parser<charT, traits>::parse_set()
 {
+   static const char* incomplete_message = "Character set declaration starting with [ terminated prematurely - either no ] was found or the set had no content.";
    ++m_position;
    if(m_position == m_end)
    {
-      fail(regex_constants::error_brack, m_position - m_base);
+      fail(regex_constants::error_brack, m_position - m_base, incomplete_message);
       return false;
    }
    basic_char_set<charT, traits> char_set;
@@ -994,7 +1261,7 @@ bool basic_regex_parser<charT, traits>::parse_set()
             ++m_position;
             if(0 == this->append_set(char_set))
             {
-               fail(regex_constants::error_range, m_position - m_base);
+               fail(regex_constants::error_ctype, m_position - m_base);
                return false;
             }
          }
@@ -1049,6 +1316,7 @@ bool basic_regex_parser<charT, traits>::parse_set()
 template <class charT, class traits>
 bool basic_regex_parser<charT, traits>::parse_inner_set(basic_char_set<charT, traits>& char_set)
 {
+   static const char* incomplete_message = "Character class declaration starting with [ terminated prematurely - either no ] was found or the set had no content.";
    //
    // we have either a character class [:name:]
    // a collating element [.name.]
@@ -1056,7 +1324,7 @@ bool basic_regex_parser<charT, traits>::parse_inner_set(basic_char_set<charT, tr
    //
    if(m_end == ++m_position)
    {
-      fail(regex_constants::error_brack, m_position - m_base);
+      fail(regex_constants::error_brack, m_position - m_base, incomplete_message);
       return false;
    }
    switch(this->m_traits.syntax_type(*m_position))
@@ -1081,14 +1349,14 @@ bool basic_regex_parser<charT, traits>::parse_inner_set(basic_char_set<charT, tr
       // skip the ':'
       if(m_end == ++m_position)
       {
-         fail(regex_constants::error_brack, m_position - m_base);
+         fail(regex_constants::error_brack, m_position - m_base, incomplete_message);
          return false;
       }
       const charT* name_first = m_position;
       // skip at least one character, then find the matching ':]'
       if(m_end == ++m_position)
       {
-         fail(regex_constants::error_brack, m_position - m_base);
+         fail(regex_constants::error_brack, m_position - m_base, incomplete_message);
          return false;
       }
       while((m_position != m_end) 
@@ -1097,13 +1365,13 @@ bool basic_regex_parser<charT, traits>::parse_inner_set(basic_char_set<charT, tr
       const charT* name_last = m_position;
       if(m_end == m_position)
       {
-         fail(regex_constants::error_brack, m_position - m_base);
+         fail(regex_constants::error_brack, m_position - m_base, incomplete_message);
          return false;
       }
       if((m_end == ++m_position) 
          || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_set))
       {
-         fail(regex_constants::error_brack, m_position - m_base);
+         fail(regex_constants::error_brack, m_position - m_base, incomplete_message);
          return false;
       }
       //
@@ -1158,14 +1426,14 @@ bool basic_regex_parser<charT, traits>::parse_inner_set(basic_char_set<charT, tr
       // skip the '='
       if(m_end == ++m_position)
       {
-         fail(regex_constants::error_brack, m_position - m_base);
+         fail(regex_constants::error_brack, m_position - m_base, incomplete_message);
          return false;
       }
       const charT* name_first = m_position;
       // skip at least one character, then find the matching '=]'
       if(m_end == ++m_position)
       {
-         fail(regex_constants::error_brack, m_position - m_base);
+         fail(regex_constants::error_brack, m_position - m_base, incomplete_message);
          return false;
       }
       while((m_position != m_end) 
@@ -1174,13 +1442,13 @@ bool basic_regex_parser<charT, traits>::parse_inner_set(basic_char_set<charT, tr
       const charT* name_last = m_position;
       if(m_end == m_position)
       {
-         fail(regex_constants::error_brack, m_position - m_base);
+         fail(regex_constants::error_brack, m_position - m_base, incomplete_message);
          return false;
       }
       if((m_end == ++m_position) 
          || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_set))
       {
-         fail(regex_constants::error_brack, m_position - m_base);
+         fail(regex_constants::error_brack, m_position - m_base, incomplete_message);
          return false;
       }
       string_type m = this->m_traits.lookup_collatename(name_first, name_last);
@@ -1370,7 +1638,7 @@ charT basic_regex_parser<charT, traits>::unescape_character()
    charT result(0);
    if(m_position == m_end)
    {
-      fail(regex_constants::error_escape, m_position - m_base);
+      fail(regex_constants::error_escape, m_position - m_base, "Escape sequence terminated prematurely.");
       return false;
    }
    switch(this->m_traits.escape_syntax_type(*m_position))
@@ -1403,24 +1671,22 @@ charT basic_regex_parser<charT, traits>::unescape_character()
       ++m_position;
       if(m_position == m_end)
       {
-         fail(regex_constants::error_escape, m_position - m_base);
-         return result;
-      }
-      /*
-      if((*m_position < charT('@'))
-            || (*m_position > charT(125)) )
-      {
-         fail(regex_constants::error_escape, m_position - m_base);
+         // Rewind to start of escape:
+         --m_position;
+         while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position;
+         fail(regex_constants::error_escape, m_position - m_base, "ASCII escape sequence terminated prematurely.");
          return result;
       }
-      */
       result = static_cast<charT>(*m_position % 32);
       break;
    case regex_constants::escape_type_hex:
       ++m_position;
       if(m_position == m_end)
       {
-         fail(regex_constants::error_escape, m_position - m_base);
+         // Rewind to start of escape:
+         --m_position;
+         while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position;
+         fail(regex_constants::error_escape, m_position - m_base, "Hexadecimal escape sequence terminated prematurely.");
          return result;
       }
       // maybe have \x{ddd}
@@ -1429,16 +1695,22 @@ charT basic_regex_parser<charT, traits>::unescape_character()
          ++m_position;
          if(m_position == m_end)
          {
-            fail(regex_constants::error_escape, m_position - m_base);
+            // Rewind to start of escape:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position;
+            fail(regex_constants::error_escape, m_position - m_base, "Missing } in hexadecimal escape sequence.");
             return result;
          }
          int i = this->m_traits.toi(m_position, m_end, 16);
          if((m_position == m_end)
             || (i < 0)
-            || ((std::numeric_limits<charT>::is_specialized) && (charT(i) > (std::numeric_limits<charT>::max)()))
+            || ((std::numeric_limits<charT>::is_specialized) && (i > (int)(std::numeric_limits<charT>::max)()))
             || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_brace))
          {
-            fail(regex_constants::error_badbrace, m_position - m_base);
+            // Rewind to start of escape:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position;
+            fail(regex_constants::error_badbrace, m_position - m_base, "Hexadecimal escape sequence was invalid.");
             return result;
          }
          ++m_position;
@@ -1446,12 +1718,15 @@ charT basic_regex_parser<charT, traits>::unescape_character()
       }
       else
       {
-         std::ptrdiff_t len = (std::min)(static_cast<std::ptrdiff_t>(2), m_end - m_position);
+         std::ptrdiff_t len = (std::min)(static_cast<std::ptrdiff_t>(2), static_cast<std::ptrdiff_t>(m_end - m_position));
          int i = this->m_traits.toi(m_position, m_position + len, 16);
          if((i < 0)
             || !valid_value(charT(0), i))
          {
-            fail(regex_constants::error_escape, m_position - m_base);
+            // Rewind to start of escape:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position;
+            fail(regex_constants::error_escape, m_position - m_base, "Escape sequence did not encode a valid character.");
             return result;
          }
          result = charT(i);
@@ -1466,14 +1741,20 @@ charT basic_regex_parser<charT, traits>::unescape_character()
       int val = this->m_traits.toi(bp, bp + 1, 8);
       if(val != 0)
       {
+         // Rewind to start of escape:
+         --m_position;
+         while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position;
          // Oops not an octal escape after all:
-         fail(regex_constants::error_escape, m_position - m_base);
+         fail(regex_constants::error_escape, m_position - m_base, "Invalid octal escape sequence.");
          return result;
       }
       val = this->m_traits.toi(m_position, m_position + len, 8);
       if(val < 0) 
       {
-         fail(regex_constants::error_escape, m_position - m_base);
+         // Rewind to start of escape:
+         --m_position;
+         while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position;
+         fail(regex_constants::error_escape, m_position - m_base, "Octal escape sequence is invalid.");
          return result;
       }
       return static_cast<charT>(val);
@@ -1483,6 +1764,9 @@ charT basic_regex_parser<charT, traits>::unescape_character()
          ++m_position;
          if(m_position == m_end)
          {
+            // Rewind to start of escape:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position;
             fail(regex_constants::error_escape, m_position - m_base);
             return false;
          }
@@ -1495,12 +1779,18 @@ charT basic_regex_parser<charT, traits>::unescape_character()
                ++m_position;
             if(m_position == m_end)
             {
+               // Rewind to start of escape:
+               --m_position;
+               while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position;
                fail(regex_constants::error_escape, m_position - m_base);
                return false;
             }
             string_type s = this->m_traits.lookup_collatename(++base, m_position++);
             if(s.empty())
             {
+               // Rewind to start of escape:
+               --m_position;
+               while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position;
                fail(regex_constants::error_collate, m_position - m_base);
                return false;
             }
@@ -1510,6 +1800,9 @@ charT basic_regex_parser<charT, traits>::unescape_character()
             }
          }
          // fall through is a failure:
+         // Rewind to start of escape:
+         --m_position;
+         while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position;
          fail(regex_constants::error_escape, m_position - m_base);
          return false;
       }
@@ -1541,10 +1834,14 @@ bool basic_regex_parser<charT, traits>::parse_backref()
       m_position = pc;
       re_brace* pb = static_cast<re_brace*>(this->append_state(syntax_element_backref, sizeof(re_brace)));
       pb->index = i;
+      pb->icase = this->flags() & regbase::icase;
    }
    else
    {
-      fail(regex_constants::error_backref, m_position - m_end);
+      // Rewind to start of escape:
+      --m_position;
+      while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position;
+      fail(regex_constants::error_backref, m_position - m_base);
       return false;
    }
    return true;
@@ -1576,7 +1873,7 @@ bool basic_regex_parser<charT, traits>::parse_QE()
       }
       if(++m_position == m_end) // skip the escape
       {
-         fail(regex_constants::error_escape, m_position - m_base);
+         fail(regex_constants::error_escape, m_position - m_base, "Unterminated \\Q...\\E sequence.");
          return false;
       }
       // check to see if it's a \E:
@@ -1607,7 +1904,10 @@ bool basic_regex_parser<charT, traits>::parse_perl_extension()
 {
    if(++m_position == m_end)
    {
-      fail(regex_constants::error_badrepeat, m_position - m_base);
+      // Rewind to start of (? sequence:
+      --m_position;
+      while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+      fail(regex_constants::error_perl_extension, m_position - m_base);
       return false;
    }
    //
@@ -1628,6 +1928,7 @@ bool basic_regex_parser<charT, traits>::parse_perl_extension()
    int markid = 0;
    std::ptrdiff_t jump_offset = 0;
    re_brace* pb = static_cast<re_brace*>(this->append_state(syntax_element_startmark, sizeof(re_brace)));
+   pb->icase = this->flags() & regbase::icase;
    std::ptrdiff_t last_paren_start = this->getoffset(pb);
    // back up insertion point for alternations, and set new point:
    std::ptrdiff_t last_alt_point = m_alt_insert_point;
@@ -1638,11 +1939,20 @@ bool basic_regex_parser<charT, traits>::parse_perl_extension()
    regex_constants::syntax_option_type old_flags = this->flags();
    bool old_case_change = m_has_case_change;
    m_has_case_change = false;
+   charT name_delim;
+   int mark_reset = m_mark_reset;
+   int max_mark = m_max_mark;
+   m_mark_reset = -1;
+   m_max_mark = m_mark_count;
+   int v;
    //
    // select the actual extension used:
    //
    switch(this->m_traits.syntax_type(*m_position))
    {
+   case regex_constants::syntax_or:
+      m_mark_reset = m_mark_count;
+      // fall through:
    case regex_constants::syntax_colon:
       //
       // a non-capturing mark:
@@ -1650,6 +1960,68 @@ bool basic_regex_parser<charT, traits>::parse_perl_extension()
       pb->index = markid = 0;
       ++m_position;
       break;
+   case regex_constants::syntax_digit:
+      {
+      //
+      // a recursive subexpression:
+      //
+      v = this->m_traits.toi(m_position, m_end, 10);
+      if((v < 0) || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark))
+      {
+         // Rewind to start of (? sequence:
+         --m_position;
+         while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+         fail(regex_constants::error_perl_extension, m_position - m_base, "The recursive sub-expression refers to an invalid marking group, or is unterminated.");
+         return false;
+      }
+insert_recursion:
+      pb->index = markid = 0;
+      re_recurse* pr = static_cast<re_recurse*>(this->append_state(syntax_element_recurse, sizeof(re_recurse)));
+      pr->alt.i = v;
+      pr->state_id = 0;
+      static_cast<re_case*>(
+            this->append_state(syntax_element_toggle_case, sizeof(re_case))
+            )->icase = this->flags() & regbase::icase;
+      break;
+      }
+   case regex_constants::syntax_plus:
+      //
+      // A forward-relative recursive subexpression:
+      //
+      ++m_position;
+      v = this->m_traits.toi(m_position, m_end, 10);
+      if((v <= 0) || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark))
+      {
+         // Rewind to start of (? sequence:
+         --m_position;
+         while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+         fail(regex_constants::error_perl_extension, m_position - m_base, "An invalid or unterminated recursive sub-expression.");
+         return false;
+      }
+      v += m_mark_count;
+      goto insert_recursion;
+   case regex_constants::syntax_dash:
+      //
+      // Possibly a backward-relative recursive subexpression:
+      //
+      ++m_position;
+      v = this->m_traits.toi(m_position, m_end, 10);
+      if(v <= 0)
+      {
+         --m_position;
+         // Oops not a relative recursion at all, but a (?-imsx) group:
+         goto option_group_jump;
+      }
+      v = m_mark_count + 1 - v;
+      if(v <= 0)
+      {
+         // Rewind to start of (? sequence:
+         --m_position;
+         while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+         fail(regex_constants::error_perl_extension, m_position - m_base, "An invalid or unterminated recursive sub-expression.");
+         return false;
+      }
+      goto insert_recursion;
    case regex_constants::syntax_equal:
       pb->index = markid = -1;
       ++m_position;
@@ -1669,7 +2041,10 @@ bool basic_regex_parser<charT, traits>::parse_perl_extension()
          // a lookbehind assertion:
          if(++m_position == m_end)
          {
-            fail(regex_constants::error_badrepeat, m_position - m_base);
+            // Rewind to start of (? sequence:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+            fail(regex_constants::error_perl_extension, m_position - m_base);
             return false;
          }
          regex_constants::syntax_type t = this->m_traits.syntax_type(*m_position);
@@ -1679,8 +2054,10 @@ bool basic_regex_parser<charT, traits>::parse_perl_extension()
             pb->index = markid = -1;
          else
          {
-            fail(regex_constants::error_badrepeat, m_position - m_base);
-            return false;
+            // Probably a named capture which also starts (?< :
+            name_delim = '>';
+            --m_position;
+            goto named_capture_jump;
          }
          ++m_position;
          jump_offset = this->getoffset(this->append_state(syntax_element_jump, sizeof(re_jump)));
@@ -1705,22 +2082,152 @@ bool basic_regex_parser<charT, traits>::parse_perl_extension()
       pb->index = markid = -4;
       if(++m_position == m_end)
       {
-         fail(regex_constants::error_badrepeat, m_position - m_base);
+         // Rewind to start of (? sequence:
+         --m_position;
+         while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+         fail(regex_constants::error_perl_extension, m_position - m_base);
          return false;
       }
-      int v = this->m_traits.toi(m_position, m_end, 10);
-      if(v > 0)
+      v = this->m_traits.toi(m_position, m_end, 10);
+      if(*m_position == charT('R'))
+      {
+         if(++m_position == m_end)
+         {
+            // Rewind to start of (? sequence:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+            fail(regex_constants::error_perl_extension, m_position - m_base);
+            return false;
+         }
+         if(*m_position == charT('&'))
+         {
+            const charT* base = ++m_position;
+            while((m_position != m_end) && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark))
+               ++m_position;
+            if(m_position == m_end)
+            {
+               // Rewind to start of (? sequence:
+               --m_position;
+               while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+               fail(regex_constants::error_perl_extension, m_position - m_base);
+               return false;
+            }
+            v = -static_cast<int>(hash_value_from_capture_name(base, m_position));
+         }
+         else
+         {
+            v = -this->m_traits.toi(m_position, m_end, 10);
+         }
+         re_brace* br = static_cast<re_brace*>(this->append_state(syntax_element_assert_backref, sizeof(re_brace)));
+         br->index = v < 0 ? (v - 1) : 0;
+         if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)
+         {
+            // Rewind to start of (? sequence:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+            fail(regex_constants::error_perl_extension, m_position - m_base);
+            return false;
+         }
+         if(++m_position == m_end)
+         {
+            // Rewind to start of (? sequence:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+            fail(regex_constants::error_perl_extension, m_position - m_base);
+            return false;
+         }
+      }
+      else if((*m_position == charT('\'')) || (*m_position == charT('<')))
+      {
+         const charT* base = ++m_position;
+         while((m_position != m_end) && (*m_position != charT('>')) && (*m_position != charT('\'')))
+            ++m_position;
+         if(m_position == m_end)
+         {
+            // Rewind to start of (? sequence:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+            fail(regex_constants::error_perl_extension, m_position - m_base);
+            return false;
+         }
+         v = static_cast<int>(hash_value_from_capture_name(base, m_position));
+         re_brace* br = static_cast<re_brace*>(this->append_state(syntax_element_assert_backref, sizeof(re_brace)));
+         br->index = v;
+         if(((*m_position != charT('>')) && (*m_position != charT('\''))) || (++m_position == m_end))
+         {
+            // Rewind to start of (? sequence:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+            fail(regex_constants::error_perl_extension, m_position - m_base, "Unterminated named capture.");
+            return false;
+         }
+         if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)
+         {
+            // Rewind to start of (? sequence:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+            fail(regex_constants::error_perl_extension, m_position - m_base);
+            return false;
+         }
+         if(++m_position == m_end)
+         {
+            // Rewind to start of (? sequence:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+            fail(regex_constants::error_perl_extension, m_position - m_base);
+            return false;
+         }
+      }
+      else if(*m_position == charT('D'))
+      {
+         const char* def = "DEFINE";
+         while(*def && (m_position != m_end) && (*m_position == charT(*def)))
+            ++m_position, ++def;
+         if((m_position == m_end) || *def)
+         {
+            // Rewind to start of (? sequence:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+            fail(regex_constants::error_perl_extension, m_position - m_base);
+            return false;
+         }
+         re_brace* br = static_cast<re_brace*>(this->append_state(syntax_element_assert_backref, sizeof(re_brace)));
+         br->index = 9999; // special magic value!
+         if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)
+         {
+            // Rewind to start of (? sequence:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+            fail(regex_constants::error_perl_extension, m_position - m_base);
+            return false;
+         }
+         if(++m_position == m_end)
+         {
+            // Rewind to start of (? sequence:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+            fail(regex_constants::error_perl_extension, m_position - m_base);
+            return false;
+         }
+      }
+      else if(v > 0)
       {
          re_brace* br = static_cast<re_brace*>(this->append_state(syntax_element_assert_backref, sizeof(re_brace)));
          br->index = v;
          if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)
          {
-            fail(regex_constants::error_badrepeat, m_position - m_base);
+            // Rewind to start of (? sequence:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+            fail(regex_constants::error_perl_extension, m_position - m_base);
             return false;
          }
          if(++m_position == m_end)
          {
-            fail(regex_constants::error_badrepeat, m_position - m_base);
+            // Rewind to start of (? sequence:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+            fail(regex_constants::error_perl_extension, m_position - m_base);
             return false;
          }
       }
@@ -1729,25 +2236,37 @@ bool basic_regex_parser<charT, traits>::parse_perl_extension()
          // verify that we have a lookahead or lookbehind assert:
          if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_question)
          {
-            fail(regex_constants::error_badrepeat, m_position - m_base);
+            // Rewind to start of (? sequence:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+            fail(regex_constants::error_perl_extension, m_position - m_base);
             return false;
          }
          if(++m_position == m_end)
          {
-            fail(regex_constants::error_badrepeat, m_position - m_base);
+            // Rewind to start of (? sequence:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+            fail(regex_constants::error_perl_extension, m_position - m_base);
             return false;
          }
          if(this->m_traits.syntax_type(*m_position) == regex_constants::escape_type_left_word)
          {
             if(++m_position == m_end)
             {
-               fail(regex_constants::error_badrepeat, m_position - m_base);
+               // Rewind to start of (? sequence:
+               --m_position;
+               while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+               fail(regex_constants::error_perl_extension, m_position - m_base);
                return false;
             }
             if((this->m_traits.syntax_type(*m_position) != regex_constants::syntax_equal)
                && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_not))
             {
-               fail(regex_constants::error_badrepeat, m_position - m_base);
+               // Rewind to start of (? sequence:
+               --m_position;
+               while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+               fail(regex_constants::error_perl_extension, m_position - m_base);
                return false;
             }
             m_position -= 3;
@@ -1757,7 +2276,10 @@ bool basic_regex_parser<charT, traits>::parse_perl_extension()
             if((this->m_traits.syntax_type(*m_position) != regex_constants::syntax_equal)
                && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_not))
             {
-               fail(regex_constants::error_badrepeat, m_position - m_base);
+               // Rewind to start of (? sequence:
+               --m_position;
+               while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+               fail(regex_constants::error_perl_extension, m_position - m_base);
                return false;
             }
             m_position -= 2;
@@ -1766,15 +2288,125 @@ bool basic_regex_parser<charT, traits>::parse_perl_extension()
       break;
       }
    case regex_constants::syntax_close_mark:
-      fail(regex_constants::error_badrepeat, m_position - m_base);
+      // Rewind to start of (? sequence:
+      --m_position;
+      while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+      fail(regex_constants::error_perl_extension, m_position - m_base);
       return false;
+   case regex_constants::escape_type_end_buffer:
+      {
+      name_delim = *m_position;
+named_capture_jump:
+      markid = 0;
+      if(0 == (this->flags() & regbase::nosubs))
+      {
+         markid = ++m_mark_count;
+   #ifndef BOOST_NO_STD_DISTANCE
+         if(this->flags() & regbase::save_subexpression_location)
+            this->m_pdata->m_subs.push_back(std::pair<std::size_t, std::size_t>(std::distance(m_base, m_position) - 2, 0));
+   #else
+         if(this->flags() & regbase::save_subexpression_location)
+            this->m_pdata->m_subs.push_back(std::pair<std::size_t, std::size_t>((m_position - m_base) - 2, 0));
+   #endif
+      }
+      pb->index = markid;
+      const charT* base = ++m_position;
+      if(m_position == m_end)
+      {
+         // Rewind to start of (? sequence:
+         --m_position;
+         while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+         fail(regex_constants::error_perl_extension, m_position - m_base);
+         return false;
+      }
+      while((m_position != m_end) && (*m_position != name_delim))
+         ++m_position;
+      if(m_position == m_end)
+      {
+         // Rewind to start of (? sequence:
+         --m_position;
+         while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+         fail(regex_constants::error_perl_extension, m_position - m_base);
+         return false;
+      }
+      this->m_pdata->set_name(base, m_position, markid);
+      ++m_position;
+      break;
+      }
    default:
+      if(*m_position == charT('R'))
+      {
+         ++m_position;
+         v = 0;
+         if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)
+         {
+            // Rewind to start of (? sequence:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+            fail(regex_constants::error_perl_extension, m_position - m_base);
+            return false;
+         }
+         goto insert_recursion;
+      }
+      if(*m_position == charT('&'))
+      {
+         ++m_position;
+         const charT* base = m_position;
+         while((m_position != m_end) && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark))
+            ++m_position;
+         if(m_position == m_end)
+         {
+            // Rewind to start of (? sequence:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+            fail(regex_constants::error_perl_extension, m_position - m_base);
+            return false;
+         }
+         v = static_cast<int>(hash_value_from_capture_name(base, m_position));
+         goto insert_recursion;
+      }
+      if(*m_position == charT('P'))
+      {
+         ++m_position;
+         if(m_position == m_end)
+         {
+            // Rewind to start of (? sequence:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+            fail(regex_constants::error_perl_extension, m_position - m_base);
+            return false;
+         }
+         if(*m_position == charT('>'))
+         {
+            ++m_position;
+            const charT* base = m_position;
+            while((m_position != m_end) && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark))
+               ++m_position;
+            if(m_position == m_end)
+            {
+               // Rewind to start of (? sequence:
+               --m_position;
+               while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+               fail(regex_constants::error_perl_extension, m_position - m_base);
+               return false;
+            }
+            v = static_cast<int>(hash_value_from_capture_name(base, m_position));
+            goto insert_recursion;
+         }
+      }
       //
       // lets assume that we have a (?imsx) group and try and parse it:
       //
+option_group_jump:
       regex_constants::syntax_option_type opts = parse_options();
       if(m_position == m_end)
+      {
+         // Rewind to start of (? sequence:
+         --m_position;
+         while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+         fail(regex_constants::error_perl_extension, m_position - m_base);
          return false;
+      }
       // make a note of whether we have a case change:
       m_has_case_change = ((opts & regbase::icase) != (this->flags() & regbase::icase));
       pb->index = markid = 0;
@@ -1793,7 +2425,10 @@ bool basic_regex_parser<charT, traits>::parse_perl_extension()
       }
       else
       {
-         fail(regex_constants::error_badrepeat, m_position - m_base);
+         // Rewind to start of (? sequence:
+         --m_position;
+         while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+         fail(regex_constants::error_perl_extension, m_position - m_base);
          return false;
       }
 
@@ -1815,12 +2450,21 @@ bool basic_regex_parser<charT, traits>::parse_perl_extension()
    // Unwind alternatives:
    //
    if(0 == unwind_alts(last_paren_start))
+   {
+      // Rewind to start of (? sequence:
+      --m_position;
+      while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+      fail(regex_constants::error_perl_extension, m_position - m_base, "Invalid alternation operators within (?...) block.");
       return false;
+   }
    //
    // we either have a ')' or we have run out of characters prematurely:
    //
    if(m_position == m_end)
    {
+      // Rewind to start of (? sequence:
+      --m_position;
+      while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
       this->fail(regex_constants::error_paren, ::boost::re_detail::distance(m_base, m_end));
       return false;
    }
@@ -1851,7 +2495,10 @@ bool basic_regex_parser<charT, traits>::parse_perl_extension()
       if(this->m_last_state == jmp)
       {
          // Oops... we didn't have anything inside the assertion:
-         fail(regex_constants::error_empty, m_position - m_base);
+         // Rewind to start of (? sequence:
+         --m_position;
+         while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+         fail(regex_constants::error_perl_extension, m_position - m_base, "Invalid or empty zero width assertion.");
          return false;
       }
    }
@@ -1862,6 +2509,7 @@ bool basic_regex_parser<charT, traits>::parse_perl_extension()
    if(markid == -4)
    {
       re_syntax_base* b = this->getaddress(expected_alt_point);
+      // Make sure we have exactly one alternative following this state:
       if(b->type != syntax_element_alt)
       {
          re_alt* alt = static_cast<re_alt*>(this->insert_state(expected_alt_point, syntax_element_alt, sizeof(re_alt)));
@@ -1869,7 +2517,36 @@ bool basic_regex_parser<charT, traits>::parse_perl_extension()
       }
       else if(this->getaddress(static_cast<re_alt*>(b)->alt.i, b)->type == syntax_element_alt)
       {
-         fail(regex_constants::error_bad_pattern, m_position - m_base);
+         // Can't have seen more than one alternative:
+         // Rewind to start of (? sequence:
+         --m_position;
+         while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+         fail(regex_constants::error_bad_pattern, m_position - m_base, "More than one alternation operator | was encountered inside a conditional expression.");
+         return false;
+      }
+      else
+      {
+         // We must *not* have seen an alternative inside a (DEFINE) block:
+         b = this->getaddress(b->next.i, b);
+         if((b->type == syntax_element_assert_backref) && (static_cast<re_brace*>(b)->index == 9999))
+         {
+            // Rewind to start of (? sequence:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+            fail(regex_constants::error_bad_pattern, m_position - m_base, "Alternation operators are not allowed inside a DEFINE block.");
+            return false;
+         }
+      }
+      // check for invalid repetition of next state:
+      b = this->getaddress(expected_alt_point);
+      b = this->getaddress(static_cast<re_alt*>(b)->next.i, b);
+      if((b->type != syntax_element_assert_backref)
+         && (b->type != syntax_element_startmark))
+      {
+         // Rewind to start of (? sequence:
+         --m_position;
+         while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
+         fail(regex_constants::error_badrepeat, m_position - m_base, "A repetition operator cannot be applied to a zero-width assertion.");
          return false;
       }
    }
@@ -1878,6 +2555,7 @@ bool basic_regex_parser<charT, traits>::parse_perl_extension()
    //
    pb = static_cast<re_brace*>(this->append_state(syntax_element_endmark, sizeof(re_brace)));
    pb->index = markid;
+   pb->icase = this->flags() & regbase::icase;
    this->m_paren_start = last_paren_start;
    //
    // restore the alternate insertion point:
@@ -1887,6 +2565,32 @@ bool basic_regex_parser<charT, traits>::parse_perl_extension()
    // and the case change data:
    //
    m_has_case_change = old_case_change;
+   //
+   // And the mark_reset data:
+   //
+   if(m_max_mark > m_mark_count)
+   {
+      m_mark_count = m_max_mark;
+   }
+   m_mark_reset = mark_reset;
+   m_max_mark = max_mark;
+
+
+   if(markid > 0)
+   {
+#ifndef BOOST_NO_STD_DISTANCE
+      if(this->flags() & regbase::save_subexpression_location)
+         this->m_pdata->m_subs.at(markid - 1).second = std::distance(m_base, m_position) - 1;
+#else
+      if(this->flags() & regbase::save_subexpression_location)
+         this->m_pdata->m_subs.at(markid - 1).second = (m_position - m_base) - 1;
+#endif
+      //
+      // allow backrefs to this mark:
+      //
+      if((markid > 0) && (markid < (int)(sizeof(unsigned) * CHAR_BIT)))
+         this->m_backrefs |= 1u << (markid - 1);
+   }
    return true;
 }
 
@@ -1898,6 +2602,9 @@ bool basic_regex_parser<charT, traits>::add_emacs_code(bool negate)
    //
    if(++m_position == m_end)
    {
+      // Rewind to start of sequence:
+      --m_position;
+      while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position;
       fail(regex_constants::error_escape, m_position - m_base);
       return false;
    }
@@ -1998,16 +2705,24 @@ regex_constants::syntax_option_type basic_regex_parser<charT, traits>::parse_opt
       }
       if(++m_position == m_end)
       {
+         // Rewind to start of (? sequence:
+         --m_position;
+         while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
          fail(regex_constants::error_paren, m_position - m_base);
          return false;
       }
    }
    while(!breakout);
+   
+   breakout = false;
 
    if(*m_position == static_cast<charT>('-'))
    {
       if(++m_position == m_end)
       {
+         // Rewind to start of (? sequence:
+         --m_position;
+         while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
          fail(regex_constants::error_paren, m_position - m_base);
          return false;
       }
@@ -2034,6 +2749,9 @@ regex_constants::syntax_option_type basic_regex_parser<charT, traits>::parse_opt
          }
          if(++m_position == m_end)
          {
+            // Rewind to start of (? sequence:
+            --m_position;
+            while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position;
             fail(regex_constants::error_paren, m_position - m_base);
             return false;
          }
@@ -2051,9 +2769,16 @@ bool basic_regex_parser<charT, traits>::unwind_alts(std::ptrdiff_t last_paren_st
    // alternative then that's an error:
    //
    if((this->m_alt_insert_point == static_cast<std::ptrdiff_t>(this->m_pdata->m_data.size()))
-      && m_alt_jumps.size() && (m_alt_jumps.back() > last_paren_start))
+      && m_alt_jumps.size() && (m_alt_jumps.back() > last_paren_start)
+      &&
+      !(
+         ((this->flags() & regbase::main_option_type) == regbase::perl_syntax_group)
+           &&
+         ((this->flags() & regbase::no_empty_expressions) == 0)
+        )
+      )
    {
-      fail(regex_constants::error_empty, this->m_position - this->m_base);
+      fail(regex_constants::error_empty, this->m_position - this->m_base, "Can't terminate a sub-expression with an alternation operator |.");
       return false;
    }
    // 
@@ -2082,8 +2807,15 @@ bool basic_regex_parser<charT, traits>::unwind_alts(std::ptrdiff_t last_paren_st
 } // namespace re_detail
 } // namespace boost
 
+#ifdef BOOST_MSVC
+#pragma warning(push)
+#pragma warning(disable: 4103)
+#endif
 #ifdef BOOST_HAS_ABI_HEADERS
 #  include BOOST_ABI_SUFFIX
 #endif
+#ifdef BOOST_MSVC
+#pragma warning(pop)
+#endif
 
 #endif