#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>
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();
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
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)
{
}
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;
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:
// 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:
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))
{
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;
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;
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;
++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();
//
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;
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 ')' :
//
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)
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:
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)
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;
// 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)
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}
++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++);
}
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;
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:
)
)
{
- // 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)
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;
// 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:
//
// 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:
}
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;
++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:
// 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)
++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;
}
}
++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;
}
//
//
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);
// 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:
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;
++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;
}
}
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.]
//
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))
// 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)
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;
}
//
// 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)
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);
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))
++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}
++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;
}
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);
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);
++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;
}
++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;
}
}
}
// 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;
}
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;
}
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:
{
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 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;
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:
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;
// 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);
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)));
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;
}
}
// 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;
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;
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;
}
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;
}
// 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;
}
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;
}
}
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)));
}
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;
}
}
//
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:
// 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;
}
//
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;
}
}
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;
}
}
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;
}
// 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;
}
//
} // 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