#include <new>
+#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
+#ifdef BOOST_MSVC
+# pragma warning(push)
+# pragma warning(disable: 4800)
+#endif
namespace boost{
namespace re_detail{
struct saved_state
{
union{
- unsigned int id;
+ unsigned int state_id;
// this padding ensures correct alignment on 64-bit platforms:
std::size_t padding1;
std::ptrdiff_t padding2;
void* padding3;
};
- saved_state(unsigned i) : id(i) {}
+ saved_state(unsigned i) : state_id(i) {}
};
template <class BidiIterator>
: saved_state(arg_id), count(c), rep(r), last_position(lp){}
};
+template <class Results>
+struct saved_recursion : public saved_state
+{
+ saved_recursion(int idx, const re_syntax_base* p, Results* pr)
+ : saved_state(14), recursion_id(idx), preturn_address(p), results(*pr)
+ {}
+ int recursion_id;
+ const re_syntax_base* preturn_address;
+ Results results;
+};
+
template <class BidiIterator, class Allocator, class traits>
bool perl_matcher<BidiIterator, Allocator, traits>::match_all_states()
{
- static matcher_proc_type const s_match_vtable[29] =
+ static matcher_proc_type const s_match_vtable[30] =
{
(&perl_matcher<BidiIterator, Allocator, traits>::match_startmark),
&perl_matcher<BidiIterator, Allocator, traits>::match_endmark,
&perl_matcher<BidiIterator, Allocator, traits>::match_combining,
&perl_matcher<BidiIterator, Allocator, traits>::match_soft_buffer_end,
&perl_matcher<BidiIterator, Allocator, traits>::match_restart_continue,
- (::boost::is_random_access_iterator<BidiIterator>::value ? &perl_matcher<BidiIterator, Allocator, traits>::match_dot_repeat_fast : &perl_matcher<BidiIterator, Allocator, traits>::match_dot_repeat_slow),
+ // Although this next line *should* be evaluated at compile time, in practice
+ // some compilers (VC++) emit run-time initialisation which breaks thread
+ // safety, so use a dispatch function instead:
+ //(::boost::is_random_access_iterator<BidiIterator>::value ? &perl_matcher<BidiIterator, Allocator, traits>::match_dot_repeat_fast : &perl_matcher<BidiIterator, Allocator, traits>::match_dot_repeat_slow),
+ &perl_matcher<BidiIterator, Allocator, traits>::match_dot_repeat_dispatch,
&perl_matcher<BidiIterator, Allocator, traits>::match_char_repeat,
&perl_matcher<BidiIterator, Allocator, traits>::match_set_repeat,
&perl_matcher<BidiIterator, Allocator, traits>::match_long_set_repeat,
&perl_matcher<BidiIterator, Allocator, traits>::match_backstep,
&perl_matcher<BidiIterator, Allocator, traits>::match_assert_backref,
&perl_matcher<BidiIterator, Allocator, traits>::match_toggle_case,
+ &perl_matcher<BidiIterator, Allocator, traits>::match_recursion,
};
push_recursion_stopper();
if(!(this->*proc)())
{
if(state_count > max_state_count)
- raise_error(traits_inst, regex_constants::error_space);
+ raise_error(traits_inst, regex_constants::error_complexity);
if((m_match_flags & match_partial) && (position == last) && (position != search_base))
m_has_partial_match = true;
bool successful_unwind = unwind(false);
m_backup_state = block;
}
else
- raise_error(traits_inst, regex_constants::error_size);
+ raise_error(traits_inst, regex_constants::error_stack);
}
template <class BidiIterator, class Allocator, class traits>
inline void perl_matcher<BidiIterator, Allocator, traits>::push_matched_paren(int index, const sub_match<BidiIterator>& sub)
{
- BOOST_ASSERT(index);
+ //BOOST_ASSERT(index);
saved_matched_paren<BidiIterator>* pmp = static_cast<saved_matched_paren<BidiIterator>*>(m_backup_state);
--pmp;
if(pmp < m_stack_base)
}
template <class BidiIterator, class Allocator, class traits>
-inline void perl_matcher<BidiIterator, Allocator, traits>::push_single_repeat(std::size_t c, const re_repeat* r, BidiIterator last_position, int id)
+inline void perl_matcher<BidiIterator, Allocator, traits>::push_single_repeat(std::size_t c, const re_repeat* r, BidiIterator last_position, int state_id)
{
saved_single_repeat<BidiIterator>* pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
--pmp;
pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
--pmp;
}
- (void) new (pmp)saved_single_repeat<BidiIterator>(c, r, last_position, id);
+ (void) new (pmp)saved_single_repeat<BidiIterator>(c, r, last_position, state_id);
+ m_backup_state = pmp;
+}
+
+template <class BidiIterator, class Allocator, class traits>
+inline void perl_matcher<BidiIterator, Allocator, traits>::push_recursion(int idx, const re_syntax_base* p, results_type* presults)
+{
+ saved_recursion<results_type>* pmp = static_cast<saved_recursion<results_type>*>(m_backup_state);
+ --pmp;
+ if(pmp < m_stack_base)
+ {
+ extend_stack();
+ pmp = static_cast<saved_recursion<results_type>*>(m_backup_state);
+ --pmp;
+ }
+ (void) new (pmp)saved_recursion<results_type>(idx, p, presults);
m_backup_state = pmp;
}
bool perl_matcher<BidiIterator, Allocator, traits>::match_startmark()
{
int index = static_cast<const re_brace*>(pstate)->index;
+ icase = static_cast<const re_brace*>(pstate)->icase;
switch(index)
{
case 0:
break;
}
}
+ case -5:
+ {
+ push_matched_paren(0, (*m_presult)[0]);
+ m_presult->set_first(position, 0, true);
+ pstate = pstate->next.p;
+ break;
+ }
default:
{
BOOST_ASSERT(index > 0);
take_second = can_start(*position, rep->_map, (unsigned char)mask_skip);
}
- if(take_first || (next_count->get_id() != rep->id))
+ if((m_backup_state->state_id != saved_state_repeater_count)
+ || (static_cast<saved_repeater<BidiIterator>*>(m_backup_state)->count.get_id() != rep->state_id)
+ || (next_count->get_id() != rep->state_id))
{
// we're moving to a different repeat from the last
// one, so set up a counter object:
- push_repeater_count(rep->id, &next_count);
+ push_repeater_count(rep->state_id, &next_count);
}
//
// If we've had at least one repeat already, and the last one
#endif
}
+template <class BidiIterator, class Allocator, class traits>
+bool perl_matcher<BidiIterator, Allocator, traits>::match_recursion()
+{
+ BOOST_ASSERT(pstate->type == syntax_element_recurse);
+ //
+ // Backup call stack:
+ //
+ push_recursion_pop();
+ //
+ // Set new call stack:
+ //
+ if(recursion_stack.capacity() == 0)
+ {
+ recursion_stack.reserve(50);
+ }
+ recursion_stack.push_back(recursion_info<results_type>());
+ recursion_stack.back().preturn_address = pstate->next.p;
+ recursion_stack.back().results = *m_presult;
+ if(static_cast<const re_recurse*>(pstate)->state_id > 0)
+ {
+ push_repeater_count(static_cast<const re_recurse*>(pstate)->state_id, &next_count);
+ }
+ pstate = static_cast<const re_jump*>(pstate)->alt.p;
+ recursion_stack.back().idx = static_cast<const re_brace*>(pstate)->index;
+
+ return true;
+}
+
+template <class BidiIterator, class Allocator, class traits>
+bool perl_matcher<BidiIterator, Allocator, traits>::match_endmark()
+{
+ int index = static_cast<const re_brace*>(pstate)->index;
+ icase = static_cast<const re_brace*>(pstate)->icase;
+ if(index > 0)
+ {
+ if((m_match_flags & match_nosubs) == 0)
+ {
+ m_presult->set_second(position, index);
+ }
+ if(!recursion_stack.empty())
+ {
+ if(index == recursion_stack.back().idx)
+ {
+ pstate = recursion_stack.back().preturn_address;
+ *m_presult = recursion_stack.back().results;
+ push_recursion(recursion_stack.back().idx, recursion_stack.back().preturn_address, &recursion_stack.back().results);
+ recursion_stack.pop_back();
+ }
+ }
+ }
+ else if((index < 0) && (index != -4))
+ {
+ // matched forward lookahead:
+ pstate = 0;
+ return true;
+ }
+ pstate = pstate->next.p;
+ return true;
+}
+
+template <class BidiIterator, class Allocator, class traits>
+bool perl_matcher<BidiIterator, Allocator, traits>::match_match()
+{
+ if(!recursion_stack.empty())
+ {
+ BOOST_ASSERT(0 == recursion_stack.back().idx);
+ pstate = recursion_stack.back().preturn_address;
+ *m_presult = recursion_stack.back().results;
+ push_recursion(recursion_stack.back().idx, recursion_stack.back().preturn_address, &recursion_stack.back().results);
+ recursion_stack.pop_back();
+ return true;
+ }
+ if((m_match_flags & match_not_null) && (position == (*m_presult)[0].first))
+ return false;
+ if((m_match_flags & match_all) && (position != last))
+ return false;
+ if((m_match_flags & regex_constants::match_not_initial_null) && (position == search_base))
+ return false;
+ m_presult->set_second(position);
+ pstate = 0;
+ m_has_found_match = true;
+ if((m_match_flags & match_posix) == match_posix)
+ {
+ m_result.maybe_assign(*m_presult);
+ if((m_match_flags & match_any) == 0)
+ return false;
+ }
+#ifdef BOOST_REGEX_MATCH_EXTRA
+ if(match_extra & m_match_flags)
+ {
+ for(unsigned i = 0; i < m_presult->size(); ++i)
+ if((*m_presult)[i].matched)
+ ((*m_presult)[i]).get_captures().push_back((*m_presult)[i]);
+ }
+#endif
+ return true;
+}
+
/****************************************************************************
Unwind and associated proceedures follow, these perform what normal stack
template <class BidiIterator, class Allocator, class traits>
bool perl_matcher<BidiIterator, Allocator, traits>::unwind(bool have_match)
{
- static unwind_proc_type const s_unwind_table[14] =
+ static unwind_proc_type const s_unwind_table[18] =
{
&perl_matcher<BidiIterator, Allocator, traits>::unwind_end,
&perl_matcher<BidiIterator, Allocator, traits>::unwind_paren,
&perl_matcher<BidiIterator, Allocator, traits>::unwind_short_set_repeat,
&perl_matcher<BidiIterator, Allocator, traits>::unwind_long_set_repeat,
&perl_matcher<BidiIterator, Allocator, traits>::unwind_non_greedy_repeat,
+ &perl_matcher<BidiIterator, Allocator, traits>::unwind_recursion,
+ &perl_matcher<BidiIterator, Allocator, traits>::unwind_recursion_pop,
};
m_recursive_result = have_match;
//
do
{
- unwinder = s_unwind_table[m_backup_state->id];
+ unwinder = s_unwind_table[m_backup_state->state_id];
cont = (this->*unwinder)(m_recursive_result);
}while(cont);
//
// restore previous values if no match was found:
if(have_match == false)
{
- m_presult->set_first(pmp->sub.first, pmp->index);
- m_presult->set_second(pmp->sub.second, pmp->index, pmp->sub.matched);
+ m_presult->set_first(pmp->sub.first, pmp->index, pmp->index == 0);
+ m_presult->set_second(pmp->sub.second, pmp->index, pmp->sub.matched, pmp->index == 0);
}
#ifdef BOOST_REGEX_MATCH_EXTRA
//
{
// can't repeat any more, remove the pushed state:
destroy_single_repeat();
+ if((m_match_flags & match_partial) && (position == last) && (position != search_base))
+ m_has_partial_match = true;
if(0 == (rep->can_be_null & mask_skip))
return true;
}
{
// can't repeat any more, remove the pushed state:
destroy_single_repeat();
+ if((m_match_flags & match_partial) && (position == last) && (position != search_base))
+ m_has_partial_match = true;
if(0 == (rep->can_be_null & mask_skip))
return true;
}
pstate = rep->next.p;
}while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip));
}
+ // remember where we got to if this is a leading repeat:
+ if((rep->leading) && (count < rep->max))
+ restart = position;
if(position == last)
{
// can't repeat any more, remove the pushed state:
destroy_single_repeat();
+ if((m_match_flags & match_partial) && (position == last) && (position != search_base))
+ m_has_partial_match = true;
if(0 == (rep->can_be_null & mask_skip))
return true;
}
pstate = rep->next.p;
}while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip));
}
+ // remember where we got to if this is a leading repeat:
+ if((rep->leading) && (count < rep->max))
+ restart = position;
if(position == last)
{
// can't repeat any more, remove the pushed state:
destroy_single_repeat();
+ if((m_match_flags & match_partial) && (position == last) && (position != search_base))
+ m_has_partial_match = true;
if(0 == (rep->can_be_null & mask_skip))
return true;
}
pstate = rep->next.p;
}while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip));
}
+ // remember where we got to if this is a leading repeat:
+ if((rep->leading) && (count < rep->max))
+ restart = position;
if(position == last)
{
// can't repeat any more, remove the pushed state:
destroy_single_repeat();
+ if((m_match_flags & match_partial) && (position == last) && (position != search_base))
+ m_has_partial_match = true;
if(0 == (rep->can_be_null & mask_skip))
return true;
}
return r;
}
+template <class BidiIterator, class Allocator, class traits>
+bool perl_matcher<BidiIterator, Allocator, traits>::unwind_recursion(bool r)
+{
+ saved_recursion<results_type>* pmp = static_cast<saved_recursion<results_type>*>(m_backup_state);
+ if(!r)
+ {
+ recursion_stack.push_back(recursion_info<results_type>());
+ recursion_stack.back().idx = pmp->recursion_id;
+ recursion_stack.back().preturn_address = pmp->preturn_address;
+ recursion_stack.back().results = pmp->results;
+ }
+ boost::re_detail::inplace_destroy(pmp++);
+ m_backup_state = pmp;
+ return true;
+}
+
+template <class BidiIterator, class Allocator, class traits>
+bool perl_matcher<BidiIterator, Allocator, traits>::unwind_recursion_pop(bool r)
+{
+ saved_state* pmp = static_cast<saved_state*>(m_backup_state);
+ if(!r)
+ {
+ recursion_stack.pop_back();
+ }
+ boost::re_detail::inplace_destroy(pmp++);
+ m_backup_state = pmp;
+ return true;
+}
+
+template <class BidiIterator, class Allocator, class traits>
+void perl_matcher<BidiIterator, Allocator, traits>::push_recursion_pop()
+{
+ saved_state* pmp = static_cast<saved_state*>(m_backup_state);
+ --pmp;
+ if(pmp < m_stack_base)
+ {
+ extend_stack();
+ pmp = static_cast<saved_state*>(m_backup_state);
+ --pmp;
+ }
+ (void) new (pmp)saved_state(15);
+ m_backup_state = pmp;
+}
+/*
+template <class BidiIterator, class Allocator, class traits>
+bool perl_matcher<BidiIterator, Allocator, traits>::unwind_parenthesis_pop(bool r)
+{
+ saved_state* pmp = static_cast<saved_state*>(m_backup_state);
+ if(!r)
+ {
+ --parenthesis_stack_position;
+ }
+ boost::re_detail::inplace_destroy(pmp++);
+ m_backup_state = pmp;
+ return true;
+}
+
+template <class BidiIterator, class Allocator, class traits>
+void perl_matcher<BidiIterator, Allocator, traits>::push_parenthesis_pop()
+{
+ saved_state* pmp = static_cast<saved_state*>(m_backup_state);
+ --pmp;
+ if(pmp < m_stack_base)
+ {
+ extend_stack();
+ pmp = static_cast<saved_state*>(m_backup_state);
+ --pmp;
+ }
+ (void) new (pmp)saved_state(16);
+ m_backup_state = pmp;
+}
+
+template <class BidiIterator, class Allocator, class traits>
+bool perl_matcher<BidiIterator, Allocator, traits>::unwind_parenthesis_push(bool r)
+{
+ saved_position<BidiIterator>* pmp = static_cast<saved_position<BidiIterator>*>(m_backup_state);
+ if(!r)
+ {
+ parenthesis_stack[parenthesis_stack_position++] = pmp->position;
+ }
+ boost::re_detail::inplace_destroy(pmp++);
+ m_backup_state = pmp;
+ return true;
+}
+
+template <class BidiIterator, class Allocator, class traits>
+inline void perl_matcher<BidiIterator, Allocator, traits>::push_parenthesis_push(BidiIterator p)
+{
+ saved_position<BidiIterator>* pmp = static_cast<saved_position<BidiIterator>*>(m_backup_state);
+ --pmp;
+ if(pmp < m_stack_base)
+ {
+ extend_stack();
+ pmp = static_cast<saved_position<BidiIterator>*>(m_backup_state);
+ --pmp;
+ }
+ (void) new (pmp)saved_position<BidiIterator>(0, p, 17);
+ m_backup_state = pmp;
+}
+*/
} // namespace re_detail
} // namespace boost
+#ifdef BOOST_MSVC
+# pragma warning(pop)
+#endif
+
+#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