6 * Use, modification and distribution are subject to the
7 * Boost Software License, Version 1.0. (See accompanying file
8 * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
13 * LOCATION: see http://www.boost.org for most recent version.
14 * FILE perl_matcher_common.cpp
15 * VERSION see <boost/version.hpp>
16 * DESCRIPTION: Definitions of perl_matcher member functions that are
17 * specific to the non-recursive implementation.
20 #ifndef BOOST_REGEX_V5_PERL_MATCHER_NON_RECURSIVE_HPP
21 #define BOOST_REGEX_V5_PERL_MATCHER_NON_RECURSIVE_HPP
23 #include <boost/regex/v5/mem_block_cache.hpp>
25 #ifdef BOOST_REGEX_MSVC
26 # pragma warning(push)
27 # pragma warning(disable: 4706 4459)
28 #if BOOST_REGEX_MSVC < 1910
29 #pragma warning(disable:4800)
34 namespace BOOST_REGEX_DETAIL_NS{
37 inline void inplace_destroy(T* p)
39 (void)p; // warning suppression
46 unsigned int state_id;
47 // this padding ensures correct alignment on 64-bit platforms:
49 std::ptrdiff_t padding2;
52 saved_state(unsigned i) : state_id(i) {}
55 template <class BidiIterator>
56 struct saved_matched_paren : public saved_state
59 sub_match<BidiIterator> sub;
60 saved_matched_paren(int i, const sub_match<BidiIterator>& s) : saved_state(1), index(i), sub(s){}
63 template <class BidiIterator>
64 struct saved_position : public saved_state
66 const re_syntax_base* pstate;
67 BidiIterator position;
68 saved_position(const re_syntax_base* ps, BidiIterator pos, int i) : saved_state(i), pstate(ps), position(pos){}
71 template <class BidiIterator>
72 struct saved_assertion : public saved_position<BidiIterator>
75 saved_assertion(bool p, const re_syntax_base* ps, BidiIterator pos)
76 : saved_position<BidiIterator>(ps, pos, saved_type_assertion), positive(p){}
79 template <class BidiIterator>
80 struct saved_repeater : public saved_state
82 repeater_count<BidiIterator> count;
83 saved_repeater(int i, repeater_count<BidiIterator>** s, BidiIterator start, int current_recursion_id)
84 : saved_state(saved_state_repeater_count), count(i, s, start, current_recursion_id){}
87 struct saved_extra_block : public saved_state
89 saved_state *base, *end;
90 saved_extra_block(saved_state* b, saved_state* e)
91 : saved_state(saved_state_extra_block), base(b), end(e) {}
94 struct save_state_init
97 save_state_init(saved_state** base, saved_state** end)
100 *base = static_cast<saved_state*>(get_mem_block());
101 *end = reinterpret_cast<saved_state*>(reinterpret_cast<char*>(*base)+BOOST_REGEX_BLOCKSIZE);
103 (void) new (*end)saved_state(0);
104 BOOST_REGEX_ASSERT(*end > *base);
108 put_mem_block(*stack);
113 template <class BidiIterator>
114 struct saved_single_repeat : public saved_state
117 const re_repeat* rep;
118 BidiIterator last_position;
119 saved_single_repeat(std::size_t c, const re_repeat* r, BidiIterator lp, int arg_id)
120 : saved_state(arg_id), count(c), rep(r), last_position(lp){}
123 template <class Results>
124 struct saved_recursion : public saved_state
126 saved_recursion(int idx, const re_syntax_base* p, Results* pr, Results* pr2)
127 : saved_state(14), recursion_id(idx), preturn_address(p), internal_results(*pr), prior_results(*pr2) {}
129 const re_syntax_base* preturn_address;
130 Results internal_results, prior_results;
133 struct saved_change_case : public saved_state
136 saved_change_case(bool c) : saved_state(18), icase(c) {}
141 incrementer(unsigned* pu) : m_pu(pu) { ++*m_pu; }
142 ~incrementer() { --*m_pu; }
143 bool operator > (unsigned i) { return *m_pu > i; }
148 template <class BidiIterator, class Allocator, class traits>
149 bool perl_matcher<BidiIterator, Allocator, traits>::match_all_states()
151 static matcher_proc_type const s_match_vtable[34] =
153 (&perl_matcher<BidiIterator, Allocator, traits>::match_startmark),
154 &perl_matcher<BidiIterator, Allocator, traits>::match_endmark,
155 &perl_matcher<BidiIterator, Allocator, traits>::match_literal,
156 &perl_matcher<BidiIterator, Allocator, traits>::match_start_line,
157 &perl_matcher<BidiIterator, Allocator, traits>::match_end_line,
158 &perl_matcher<BidiIterator, Allocator, traits>::match_wild,
159 &perl_matcher<BidiIterator, Allocator, traits>::match_match,
160 &perl_matcher<BidiIterator, Allocator, traits>::match_word_boundary,
161 &perl_matcher<BidiIterator, Allocator, traits>::match_within_word,
162 &perl_matcher<BidiIterator, Allocator, traits>::match_word_start,
163 &perl_matcher<BidiIterator, Allocator, traits>::match_word_end,
164 &perl_matcher<BidiIterator, Allocator, traits>::match_buffer_start,
165 &perl_matcher<BidiIterator, Allocator, traits>::match_buffer_end,
166 &perl_matcher<BidiIterator, Allocator, traits>::match_backref,
167 &perl_matcher<BidiIterator, Allocator, traits>::match_long_set,
168 &perl_matcher<BidiIterator, Allocator, traits>::match_set,
169 &perl_matcher<BidiIterator, Allocator, traits>::match_jump,
170 &perl_matcher<BidiIterator, Allocator, traits>::match_alt,
171 &perl_matcher<BidiIterator, Allocator, traits>::match_rep,
172 &perl_matcher<BidiIterator, Allocator, traits>::match_combining,
173 &perl_matcher<BidiIterator, Allocator, traits>::match_soft_buffer_end,
174 &perl_matcher<BidiIterator, Allocator, traits>::match_restart_continue,
175 // Although this next line *should* be evaluated at compile time, in practice
176 // some compilers (VC++) emit run-time initialisation which breaks thread
177 // safety, so use a dispatch function instead:
178 //(::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),
179 &perl_matcher<BidiIterator, Allocator, traits>::match_dot_repeat_dispatch,
180 &perl_matcher<BidiIterator, Allocator, traits>::match_char_repeat,
181 &perl_matcher<BidiIterator, Allocator, traits>::match_set_repeat,
182 &perl_matcher<BidiIterator, Allocator, traits>::match_long_set_repeat,
183 &perl_matcher<BidiIterator, Allocator, traits>::match_backstep,
184 &perl_matcher<BidiIterator, Allocator, traits>::match_assert_backref,
185 &perl_matcher<BidiIterator, Allocator, traits>::match_toggle_case,
186 &perl_matcher<BidiIterator, Allocator, traits>::match_recursion,
187 &perl_matcher<BidiIterator, Allocator, traits>::match_fail,
188 &perl_matcher<BidiIterator, Allocator, traits>::match_accept,
189 &perl_matcher<BidiIterator, Allocator, traits>::match_commit,
190 &perl_matcher<BidiIterator, Allocator, traits>::match_then,
192 incrementer inc(&m_recursions);
194 raise_error(traits_inst, regex_constants::error_complexity);
195 push_recursion_stopper();
199 matcher_proc_type proc = s_match_vtable[pstate->type];
203 if(state_count > max_state_count)
204 raise_error(traits_inst, regex_constants::error_complexity);
205 if((m_match_flags & match_partial) && (position == last) && (position != search_base))
206 m_has_partial_match = true;
207 bool successful_unwind = unwind(false);
208 if((m_match_flags & match_partial) && (position == last) && (position != search_base))
209 m_has_partial_match = true;
210 if(!successful_unwind)
211 return m_recursive_result;
214 }while(unwind(true));
215 return m_recursive_result;
218 template <class BidiIterator, class Allocator, class traits>
219 void perl_matcher<BidiIterator, Allocator, traits>::extend_stack()
224 saved_state* stack_base;
225 saved_state* backup_state;
226 stack_base = static_cast<saved_state*>(get_mem_block());
227 backup_state = reinterpret_cast<saved_state*>(reinterpret_cast<char*>(stack_base)+BOOST_REGEX_BLOCKSIZE);
228 saved_extra_block* block = static_cast<saved_extra_block*>(backup_state);
230 (void) new (block) saved_extra_block(m_stack_base, m_backup_state);
231 m_stack_base = stack_base;
232 m_backup_state = block;
235 raise_error(traits_inst, regex_constants::error_stack);
238 template <class BidiIterator, class Allocator, class traits>
239 inline void perl_matcher<BidiIterator, Allocator, traits>::push_matched_paren(int index, const sub_match<BidiIterator>& sub)
241 //BOOST_REGEX_ASSERT(index);
242 saved_matched_paren<BidiIterator>* pmp = static_cast<saved_matched_paren<BidiIterator>*>(m_backup_state);
244 if(pmp < m_stack_base)
247 pmp = static_cast<saved_matched_paren<BidiIterator>*>(m_backup_state);
250 (void) new (pmp)saved_matched_paren<BidiIterator>(index, sub);
251 m_backup_state = pmp;
254 template <class BidiIterator, class Allocator, class traits>
255 inline void perl_matcher<BidiIterator, Allocator, traits>::push_case_change(bool c)
257 //BOOST_REGEX_ASSERT(index);
258 saved_change_case* pmp = static_cast<saved_change_case*>(m_backup_state);
260 if(pmp < m_stack_base)
263 pmp = static_cast<saved_change_case*>(m_backup_state);
266 (void) new (pmp)saved_change_case(c);
267 m_backup_state = pmp;
270 template <class BidiIterator, class Allocator, class traits>
271 inline void perl_matcher<BidiIterator, Allocator, traits>::push_recursion_stopper()
273 saved_state* pmp = m_backup_state;
275 if(pmp < m_stack_base)
278 pmp = m_backup_state;
281 (void) new (pmp)saved_state(saved_type_recurse);
282 m_backup_state = pmp;
285 template <class BidiIterator, class Allocator, class traits>
286 inline void perl_matcher<BidiIterator, Allocator, traits>::push_assertion(const re_syntax_base* ps, bool positive)
288 saved_assertion<BidiIterator>* pmp = static_cast<saved_assertion<BidiIterator>*>(m_backup_state);
290 if(pmp < m_stack_base)
293 pmp = static_cast<saved_assertion<BidiIterator>*>(m_backup_state);
296 (void) new (pmp)saved_assertion<BidiIterator>(positive, ps, position);
297 m_backup_state = pmp;
300 template <class BidiIterator, class Allocator, class traits>
301 inline void perl_matcher<BidiIterator, Allocator, traits>::push_alt(const re_syntax_base* ps)
303 saved_position<BidiIterator>* pmp = static_cast<saved_position<BidiIterator>*>(m_backup_state);
305 if(pmp < m_stack_base)
308 pmp = static_cast<saved_position<BidiIterator>*>(m_backup_state);
311 (void) new (pmp)saved_position<BidiIterator>(ps, position, saved_state_alt);
312 m_backup_state = pmp;
315 template <class BidiIterator, class Allocator, class traits>
316 inline void perl_matcher<BidiIterator, Allocator, traits>::push_non_greedy_repeat(const re_syntax_base* ps)
318 saved_position<BidiIterator>* pmp = static_cast<saved_position<BidiIterator>*>(m_backup_state);
320 if(pmp < m_stack_base)
323 pmp = static_cast<saved_position<BidiIterator>*>(m_backup_state);
326 (void) new (pmp)saved_position<BidiIterator>(ps, position, saved_state_non_greedy_long_repeat);
327 m_backup_state = pmp;
330 template <class BidiIterator, class Allocator, class traits>
331 inline void perl_matcher<BidiIterator, Allocator, traits>::push_repeater_count(int i, repeater_count<BidiIterator>** s)
333 saved_repeater<BidiIterator>* pmp = static_cast<saved_repeater<BidiIterator>*>(m_backup_state);
335 if(pmp < m_stack_base)
338 pmp = static_cast<saved_repeater<BidiIterator>*>(m_backup_state);
341 (void) new (pmp)saved_repeater<BidiIterator>(i, s, position, this->recursion_stack.empty() ? (INT_MIN + 3) : this->recursion_stack.back().idx);
342 m_backup_state = pmp;
345 template <class BidiIterator, class Allocator, class traits>
346 inline void perl_matcher<BidiIterator, Allocator, traits>::push_single_repeat(std::size_t c, const re_repeat* r, BidiIterator last_position, int state_id)
348 saved_single_repeat<BidiIterator>* pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
350 if(pmp < m_stack_base)
353 pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
356 (void) new (pmp)saved_single_repeat<BidiIterator>(c, r, last_position, state_id);
357 m_backup_state = pmp;
360 template <class BidiIterator, class Allocator, class traits>
361 inline void perl_matcher<BidiIterator, Allocator, traits>::push_recursion(int idx, const re_syntax_base* p, results_type* presults, results_type* presults2)
363 saved_recursion<results_type>* pmp = static_cast<saved_recursion<results_type>*>(m_backup_state);
365 if(pmp < m_stack_base)
368 pmp = static_cast<saved_recursion<results_type>*>(m_backup_state);
371 (void) new (pmp)saved_recursion<results_type>(idx, p, presults, presults2);
372 m_backup_state = pmp;
375 template <class BidiIterator, class Allocator, class traits>
376 bool perl_matcher<BidiIterator, Allocator, traits>::match_toggle_case()
378 // change our case sensitivity:
379 push_case_change(this->icase);
380 this->icase = static_cast<const re_case*>(pstate)->icase;
381 pstate = pstate->next.p;
385 template <class BidiIterator, class Allocator, class traits>
386 bool perl_matcher<BidiIterator, Allocator, traits>::match_startmark()
388 int index = static_cast<const re_brace*>(pstate)->index;
389 icase = static_cast<const re_brace*>(pstate)->icase;
393 pstate = pstate->next.p;
398 // forward lookahead assert:
399 const re_syntax_base* next_pstate = static_cast<const re_jump*>(pstate->next.p)->alt.p->next.p;
400 pstate = pstate->next.p->next.p;
401 push_assertion(next_pstate, index == -1);
406 // independent sub-expression, currently this is always recursive:
407 bool old_independent = m_independent;
408 m_independent = true;
409 const re_syntax_base* next_pstate = static_cast<const re_jump*>(pstate->next.p)->alt.p->next.p;
410 pstate = pstate->next.p->next.p;
412 #if !defined(BOOST_NO_EXCEPTIONS)
415 r = match_all_states();
416 if(!r && !m_independent)
418 // Must be unwinding from a COMMIT/SKIP/PRUNE and the independent
419 // sub failed, need to unwind everything else:
420 while (m_backup_state->state_id)
424 #if !defined(BOOST_NO_EXCEPTIONS)
428 pstate = next_pstate;
429 // unwind all pushed states, apart from anything else this
430 // ensures that all the states are correctly destructed
431 // not just the memory freed.
432 while(unwind(true)) {}
436 pstate = next_pstate;
437 m_independent = old_independent;
438 #ifdef BOOST_REGEX_MATCH_EXTRA
439 if(r && (m_match_flags & match_extra))
442 // our captures have been stored in *m_presult
443 // we need to unpack them, and insert them
444 // back in the right order when we unwind the stack:
446 match_results<BidiIterator, Allocator> temp_match(*m_presult);
448 for(i = 0; i < temp_match.size(); ++i)
449 (*m_presult)[i].get_captures().clear();
450 // match everything else:
451 #if !defined(BOOST_NO_EXCEPTIONS)
454 r = match_all_states();
455 #if !defined(BOOST_NO_EXCEPTIONS)
459 pstate = next_pstate;
460 // unwind all pushed states, apart from anything else this
461 // ensures that all the states are correctly destructed
462 // not just the memory freed.
463 while(unwind(true)) {}
467 // now place the stored captures back:
468 for(i = 0; i < temp_match.size(); ++i)
470 typedef typename sub_match<BidiIterator>::capture_sequence_type seq;
471 seq& s1 = (*m_presult)[i].get_captures();
472 const seq& s2 = temp_match[i].captures();
484 // conditional expression:
485 const re_alt* alt = static_cast<const re_alt*>(pstate->next.p);
486 BOOST_REGEX_ASSERT(alt->type == syntax_element_alt);
487 pstate = alt->next.p;
488 if(pstate->type == syntax_element_assert_backref)
490 if(!match_assert_backref())
496 // zero width assertion, have to match this recursively:
497 BOOST_REGEX_ASSERT(pstate->type == syntax_element_startmark);
498 bool negated = static_cast<const re_brace*>(pstate)->index == -2;
499 BidiIterator saved_position = position;
500 const re_syntax_base* next_pstate = static_cast<const re_jump*>(pstate->next.p)->alt.p->next.p;
501 pstate = pstate->next.p->next.p;
502 #if !defined(BOOST_NO_EXCEPTIONS)
505 bool r = match_all_states();
506 position = saved_position;
510 pstate = next_pstate;
513 #if !defined(BOOST_NO_EXCEPTIONS)
517 pstate = next_pstate;
518 // unwind all pushed states, apart from anything else this
519 // ensures that all the states are correctly destructed
520 // not just the memory freed.
521 while(unwind(true)){}
530 push_matched_paren(0, (*m_presult)[0]);
531 m_presult->set_first(position, 0, true);
532 pstate = pstate->next.p;
537 BOOST_REGEX_ASSERT(index > 0);
538 if((m_match_flags & match_nosubs) == 0)
540 push_matched_paren(index, (*m_presult)[index]);
541 m_presult->set_first(position, index);
543 pstate = pstate->next.p;
550 template <class BidiIterator, class Allocator, class traits>
551 bool perl_matcher<BidiIterator, Allocator, traits>::match_alt()
553 bool take_first, take_second;
554 const re_alt* jmp = static_cast<const re_alt*>(pstate);
556 // find out which of these two alternatives we need to take:
559 take_first = jmp->can_be_null & mask_take;
560 take_second = jmp->can_be_null & mask_skip;
564 take_first = can_start(*position, jmp->_map, (unsigned char)mask_take);
565 take_second = can_start(*position, jmp->_map, (unsigned char)mask_skip);
570 // we can take the first alternative,
571 // see if we need to push next alternative:
574 push_alt(jmp->alt.p);
576 pstate = pstate->next.p;
584 return false; // neither option is possible
587 template <class BidiIterator, class Allocator, class traits>
588 bool perl_matcher<BidiIterator, Allocator, traits>::match_rep()
590 #ifdef BOOST_REGEX_MSVC
591 #pragma warning(push)
592 #pragma warning(disable:4127 4244)
594 #ifdef BOOST_BORLANDC
595 #pragma option push -w-8008 -w-8066 -w-8004
597 const re_repeat* rep = static_cast<const re_repeat*>(pstate);
599 // find out which of these two alternatives we need to take:
600 bool take_first, take_second;
603 take_first = rep->can_be_null & mask_take;
604 take_second = rep->can_be_null & mask_skip;
608 take_first = can_start(*position, rep->_map, (unsigned char)mask_take);
609 take_second = can_start(*position, rep->_map, (unsigned char)mask_skip);
612 if((m_backup_state->state_id != saved_state_repeater_count)
613 || (static_cast<saved_repeater<BidiIterator>*>(m_backup_state)->count.get_id() != rep->state_id)
614 || (next_count->get_id() != rep->state_id))
616 // we're moving to a different repeat from the last
617 // one, so set up a counter object:
618 push_repeater_count(rep->state_id, &next_count);
621 // If we've had at least one repeat already, and the last one
622 // matched the NULL string then set the repeat count to
625 next_count->check_null_repeat(position, rep->max);
627 if(next_count->get_count() < rep->min)
629 // we must take the repeat:
632 // increase the counter:
634 pstate = rep->next.p;
640 bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent);
643 // try and take the repeat if we can:
644 if((next_count->get_count() < rep->max) && take_first)
648 // store position in case we fail:
649 push_alt(rep->alt.p);
651 // increase the counter:
653 pstate = rep->next.p;
661 return false; // can't take anything, fail...
665 // try and skip the repeat if we can:
668 if((next_count->get_count() < rep->max) && take_first)
670 // store position in case we fail:
671 push_non_greedy_repeat(rep->next.p);
676 if((next_count->get_count() < rep->max) && take_first)
678 // increase the counter:
680 pstate = rep->next.p;
685 #ifdef BOOST_BORLANDC
688 #ifdef BOOST_REGEX_MSVC
693 template <class BidiIterator, class Allocator, class traits>
694 bool perl_matcher<BidiIterator, Allocator, traits>::match_dot_repeat_slow()
696 std::size_t count = 0;
697 const re_repeat* rep = static_cast<const re_repeat*>(pstate);
698 re_syntax_base* psingle = rep->next.p;
699 // match compulsory repeats first:
700 while(count < rep->min)
707 bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent);
710 // repeat for as long as we can:
711 while(count < rep->max)
718 // remember where we got to if this is a leading repeat:
719 if((rep->leading) && (count < rep->max))
721 // push backtrack info if available:
723 push_single_repeat(count, rep, position, saved_state_greedy_single_repeat);
724 // jump to next state:
730 // non-greedy, push state and return true if we can skip:
732 push_single_repeat(count, rep, position, saved_state_rep_slow_dot);
734 return (position == last) ? (rep->can_be_null & mask_skip) : can_start(*position, rep->_map, mask_skip);
738 template <class BidiIterator, class Allocator, class traits>
739 bool perl_matcher<BidiIterator, Allocator, traits>::match_dot_repeat_fast()
741 if(m_match_flags & match_not_dot_null)
742 return match_dot_repeat_slow();
743 if((static_cast<const re_dot*>(pstate->next.p)->mask & match_any_mask) == 0)
744 return match_dot_repeat_slow();
746 const re_repeat* rep = static_cast<const re_repeat*>(pstate);
747 bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent);
748 std::size_t count = static_cast<std::size_t>((std::min)(static_cast<std::size_t>(std::distance(position, last)), greedy ? rep->max : rep->min));
752 return false; // not enough text left to match
754 std::advance(position, count);
758 if((rep->leading) && (count < rep->max))
760 // push backtrack info if available:
762 push_single_repeat(count, rep, position, saved_state_greedy_single_repeat);
763 // jump to next state:
769 // non-greedy, push state and return true if we can skip:
771 push_single_repeat(count, rep, position, saved_state_rep_fast_dot);
773 return (position == last) ? (rep->can_be_null & mask_skip) : can_start(*position, rep->_map, mask_skip);
777 template <class BidiIterator, class Allocator, class traits>
778 bool perl_matcher<BidiIterator, Allocator, traits>::match_char_repeat()
780 #ifdef BOOST_REGEX_MSVC
781 #pragma warning(push)
782 #pragma warning(disable:4127)
784 #ifdef BOOST_BORLANDC
785 #pragma option push -w-8008 -w-8066 -w-8004
787 const re_repeat* rep = static_cast<const re_repeat*>(pstate);
788 BOOST_REGEX_ASSERT(1 == static_cast<const re_literal*>(rep->next.p)->length);
789 const char_type what = *reinterpret_cast<const char_type*>(static_cast<const re_literal*>(rep->next.p) + 1);
790 std::size_t count = 0;
792 // start by working out how much we can skip:
794 bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent);
795 std::size_t desired = greedy ? rep->max : rep->min;
796 if(::boost::is_random_access_iterator<BidiIterator>::value)
798 BidiIterator end = position;
799 // Move end forward by "desired", preferably without using distance or advance if we can
800 // as these can be slow for some iterator types.
801 std::size_t len = (desired == (std::numeric_limits<std::size_t>::max)()) ? 0u : std::distance(position, last);
805 std::advance(end, desired);
806 BidiIterator origin(position);
807 while((position != end) && (traits_inst.translate(*position, icase) == what))
811 count = (unsigned)std::distance(origin, position);
815 while((count < desired) && (position != last) && (traits_inst.translate(*position, icase) == what))
827 if((rep->leading) && (count < rep->max))
829 // push backtrack info if available:
831 push_single_repeat(count, rep, position, saved_state_greedy_single_repeat);
832 // jump to next state:
838 // non-greedy, push state and return true if we can skip:
840 push_single_repeat(count, rep, position, saved_state_rep_char);
842 return (position == last) ? (rep->can_be_null & mask_skip) : can_start(*position, rep->_map, mask_skip);
844 #ifdef BOOST_BORLANDC
847 #ifdef BOOST_REGEX_MSVC
852 template <class BidiIterator, class Allocator, class traits>
853 bool perl_matcher<BidiIterator, Allocator, traits>::match_set_repeat()
855 #ifdef BOOST_REGEX_MSVC
856 #pragma warning(push)
857 #pragma warning(disable:4127)
859 #ifdef BOOST_BORLANDC
860 #pragma option push -w-8008 -w-8066 -w-8004
862 const re_repeat* rep = static_cast<const re_repeat*>(pstate);
863 const unsigned char* map = static_cast<const re_set*>(rep->next.p)->_map;
864 std::size_t count = 0;
866 // start by working out how much we can skip:
868 bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent);
869 std::size_t desired = greedy ? rep->max : rep->min;
870 if(::boost::is_random_access_iterator<BidiIterator>::value)
872 BidiIterator end = position;
873 // Move end forward by "desired", preferably without using distance or advance if we can
874 // as these can be slow for some iterator types.
875 std::size_t len = (desired == (std::numeric_limits<std::size_t>::max)()) ? 0u : std::distance(position, last);
879 std::advance(end, desired);
880 BidiIterator origin(position);
881 while((position != end) && map[static_cast<unsigned char>(traits_inst.translate(*position, icase))])
885 count = (unsigned)std::distance(origin, position);
889 while((count < desired) && (position != last) && map[static_cast<unsigned char>(traits_inst.translate(*position, icase))])
901 if((rep->leading) && (count < rep->max))
903 // push backtrack info if available:
905 push_single_repeat(count, rep, position, saved_state_greedy_single_repeat);
906 // jump to next state:
912 // non-greedy, push state and return true if we can skip:
914 push_single_repeat(count, rep, position, saved_state_rep_short_set);
916 return (position == last) ? (rep->can_be_null & mask_skip) : can_start(*position, rep->_map, mask_skip);
918 #ifdef BOOST_BORLANDC
921 #ifdef BOOST_REGEX_MSVC
926 template <class BidiIterator, class Allocator, class traits>
927 bool perl_matcher<BidiIterator, Allocator, traits>::match_long_set_repeat()
929 #ifdef BOOST_REGEX_MSVC
930 #pragma warning(push)
931 #pragma warning(disable:4127)
933 #ifdef BOOST_BORLANDC
934 #pragma option push -w-8008 -w-8066 -w-8004
936 typedef typename traits::char_class_type m_type;
937 const re_repeat* rep = static_cast<const re_repeat*>(pstate);
938 const re_set_long<m_type>* set = static_cast<const re_set_long<m_type>*>(pstate->next.p);
939 std::size_t count = 0;
941 // start by working out how much we can skip:
943 bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent);
944 std::size_t desired = greedy ? rep->max : rep->min;
945 if(::boost::is_random_access_iterator<BidiIterator>::value)
947 BidiIterator end = position;
948 // Move end forward by "desired", preferably without using distance or advance if we can
949 // as these can be slow for some iterator types.
950 std::size_t len = (desired == (std::numeric_limits<std::size_t>::max)()) ? 0u : std::distance(position, last);
954 std::advance(end, desired);
955 BidiIterator origin(position);
956 while((position != end) && (position != re_is_set_member(position, last, set, re.get_data(), icase)))
960 count = (unsigned)std::distance(origin, position);
964 while((count < desired) && (position != last) && (position != re_is_set_member(position, last, set, re.get_data(), icase)))
976 if((rep->leading) && (count < rep->max))
978 // push backtrack info if available:
980 push_single_repeat(count, rep, position, saved_state_greedy_single_repeat);
981 // jump to next state:
987 // non-greedy, push state and return true if we can skip:
989 push_single_repeat(count, rep, position, saved_state_rep_long_set);
991 return (position == last) ? (rep->can_be_null & mask_skip) : can_start(*position, rep->_map, mask_skip);
993 #ifdef BOOST_BORLANDC
996 #ifdef BOOST_REGEX_MSVC
1001 template <class BidiIterator, class Allocator, class traits>
1002 bool perl_matcher<BidiIterator, Allocator, traits>::match_recursion()
1004 BOOST_REGEX_ASSERT(pstate->type == syntax_element_recurse);
1006 // See if we've seen this recursion before at this location, if we have then
1007 // we need to prevent infinite recursion:
1009 for(typename std::vector<recursion_info<results_type> >::reverse_iterator i = recursion_stack.rbegin(); i != recursion_stack.rend(); ++i)
1011 if(i->idx == static_cast<const re_brace*>(static_cast<const re_jump*>(pstate)->alt.p)->index)
1013 if(i->location_of_start == position)
1019 // Backup call stack:
1021 push_recursion_pop();
1023 // Set new call stack:
1025 if(recursion_stack.capacity() == 0)
1027 recursion_stack.reserve(50);
1029 recursion_stack.push_back(recursion_info<results_type>());
1030 recursion_stack.back().preturn_address = pstate->next.p;
1031 recursion_stack.back().results = *m_presult;
1032 pstate = static_cast<const re_jump*>(pstate)->alt.p;
1033 recursion_stack.back().idx = static_cast<const re_brace*>(pstate)->index;
1034 recursion_stack.back().location_of_start = position;
1035 //if(static_cast<const re_recurse*>(pstate)->state_id > 0)
1037 push_repeater_count(-(2 + static_cast<const re_brace*>(pstate)->index), &next_count);
1043 template <class BidiIterator, class Allocator, class traits>
1044 bool perl_matcher<BidiIterator, Allocator, traits>::match_endmark()
1046 int index = static_cast<const re_brace*>(pstate)->index;
1047 icase = static_cast<const re_brace*>(pstate)->icase;
1050 if((m_match_flags & match_nosubs) == 0)
1052 m_presult->set_second(position, index);
1054 if(!recursion_stack.empty())
1056 if(index == recursion_stack.back().idx)
1058 pstate = recursion_stack.back().preturn_address;
1059 *m_presult = recursion_stack.back().results;
1060 push_recursion(recursion_stack.back().idx, recursion_stack.back().preturn_address, m_presult, &recursion_stack.back().results);
1061 recursion_stack.pop_back();
1062 push_repeater_count(-(2 + index), &next_count);
1066 else if((index < 0) && (index != -4))
1068 // matched forward lookahead:
1072 pstate = pstate->next.p;
1076 template <class BidiIterator, class Allocator, class traits>
1077 bool perl_matcher<BidiIterator, Allocator, traits>::match_match()
1079 if(!recursion_stack.empty())
1081 BOOST_REGEX_ASSERT(0 == recursion_stack.back().idx);
1082 pstate = recursion_stack.back().preturn_address;
1083 push_recursion(recursion_stack.back().idx, recursion_stack.back().preturn_address, m_presult, &recursion_stack.back().results);
1084 *m_presult = recursion_stack.back().results;
1085 recursion_stack.pop_back();
1088 if((m_match_flags & match_not_null) && (position == (*m_presult)[0].first))
1090 if((m_match_flags & match_all) && (position != last))
1092 if((m_match_flags & regex_constants::match_not_initial_null) && (position == search_base))
1094 m_presult->set_second(position);
1096 m_has_found_match = true;
1097 if((m_match_flags & match_posix) == match_posix)
1099 m_result.maybe_assign(*m_presult);
1100 if((m_match_flags & match_any) == 0)
1103 #ifdef BOOST_REGEX_MATCH_EXTRA
1104 if(match_extra & m_match_flags)
1106 for(unsigned i = 0; i < m_presult->size(); ++i)
1107 if((*m_presult)[i].matched)
1108 ((*m_presult)[i]).get_captures().push_back((*m_presult)[i]);
1114 template <class BidiIterator, class Allocator, class traits>
1115 bool perl_matcher<BidiIterator, Allocator, traits>::match_commit()
1117 // Ideally we would just junk all the states that are on the stack,
1118 // however we might not unwind correctly in that case, so for now,
1119 // just mark that we don't backtrack into whatever is left (or rather
1120 // we'll unwind it unconditionally without pausing to try other matches).
1122 switch(static_cast<const re_commit*>(pstate)->action)
1128 if(base != position)
1131 // Have to decrement restart since it will get incremented again later:
1139 saved_state* pmp = m_backup_state;
1141 if(pmp < m_stack_base)
1144 pmp = m_backup_state;
1147 (void) new (pmp)saved_state(16);
1148 m_backup_state = pmp;
1149 pstate = pstate->next.p;
1153 template <class BidiIterator, class Allocator, class traits>
1154 bool perl_matcher<BidiIterator, Allocator, traits>::match_then()
1156 // Just leave a mark that we need to skip to next alternative:
1157 saved_state* pmp = m_backup_state;
1159 if(pmp < m_stack_base)
1162 pmp = m_backup_state;
1165 (void) new (pmp)saved_state(17);
1166 m_backup_state = pmp;
1167 pstate = pstate->next.p;
1171 template <class BidiIterator, class Allocator, class traits>
1172 bool perl_matcher<BidiIterator, Allocator, traits>::skip_until_paren(int index, bool have_match)
1176 if(pstate->type == syntax_element_endmark)
1178 if(static_cast<const re_brace*>(pstate)->index == index)
1181 return this->match_endmark();
1182 pstate = pstate->next.p;
1187 // Unenclosed closing ), occurs when (*ACCEPT) is inside some other
1188 // parenthesis which may or may not have other side effects associated with it.
1189 const re_syntax_base* sp = pstate;
1194 // unwind may leave pstate NULL if we've unwound a forward lookahead, in which
1195 // case just move to the next state and keep looking...
1197 pstate = sp->next.p;
1202 else if(pstate->type == syntax_element_match)
1204 else if(pstate->type == syntax_element_startmark)
1206 int idx = static_cast<const re_brace*>(pstate)->index;
1207 pstate = pstate->next.p;
1208 skip_until_paren(idx, false);
1211 pstate = pstate->next.p;
1216 /****************************************************************************
1218 Unwind and associated procedures follow, these perform what normal stack
1219 unwinding does in the recursive implementation.
1221 ****************************************************************************/
1223 template <class BidiIterator, class Allocator, class traits>
1224 bool perl_matcher<BidiIterator, Allocator, traits>::unwind(bool have_match)
1226 static unwind_proc_type const s_unwind_table[19] =
1228 &perl_matcher<BidiIterator, Allocator, traits>::unwind_end,
1229 &perl_matcher<BidiIterator, Allocator, traits>::unwind_paren,
1230 &perl_matcher<BidiIterator, Allocator, traits>::unwind_recursion_stopper,
1231 &perl_matcher<BidiIterator, Allocator, traits>::unwind_assertion,
1232 &perl_matcher<BidiIterator, Allocator, traits>::unwind_alt,
1233 &perl_matcher<BidiIterator, Allocator, traits>::unwind_repeater_counter,
1234 &perl_matcher<BidiIterator, Allocator, traits>::unwind_extra_block,
1235 &perl_matcher<BidiIterator, Allocator, traits>::unwind_greedy_single_repeat,
1236 &perl_matcher<BidiIterator, Allocator, traits>::unwind_slow_dot_repeat,
1237 &perl_matcher<BidiIterator, Allocator, traits>::unwind_fast_dot_repeat,
1238 &perl_matcher<BidiIterator, Allocator, traits>::unwind_char_repeat,
1239 &perl_matcher<BidiIterator, Allocator, traits>::unwind_short_set_repeat,
1240 &perl_matcher<BidiIterator, Allocator, traits>::unwind_long_set_repeat,
1241 &perl_matcher<BidiIterator, Allocator, traits>::unwind_non_greedy_repeat,
1242 &perl_matcher<BidiIterator, Allocator, traits>::unwind_recursion,
1243 &perl_matcher<BidiIterator, Allocator, traits>::unwind_recursion_pop,
1244 &perl_matcher<BidiIterator, Allocator, traits>::unwind_commit,
1245 &perl_matcher<BidiIterator, Allocator, traits>::unwind_then,
1246 &perl_matcher<BidiIterator, Allocator, traits>::unwind_case,
1249 m_recursive_result = have_match;
1250 m_unwound_lookahead = false;
1251 m_unwound_alt = false;
1252 unwind_proc_type unwinder;
1255 // keep unwinding our stack until we have something to do:
1259 unwinder = s_unwind_table[m_backup_state->state_id];
1260 cont = (this->*unwinder)(m_recursive_result);
1263 // return true if we have more states to try:
1265 return pstate ? true : false;
1268 template <class BidiIterator, class Allocator, class traits>
1269 bool perl_matcher<BidiIterator, Allocator, traits>::unwind_end(bool)
1271 pstate = 0; // nothing left to search
1272 return false; // end of stack nothing more to search
1275 template <class BidiIterator, class Allocator, class traits>
1276 bool perl_matcher<BidiIterator, Allocator, traits>::unwind_case(bool)
1278 saved_change_case* pmp = static_cast<saved_change_case*>(m_backup_state);
1280 boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++);
1281 m_backup_state = pmp;
1285 template <class BidiIterator, class Allocator, class traits>
1286 bool perl_matcher<BidiIterator, Allocator, traits>::unwind_paren(bool have_match)
1288 saved_matched_paren<BidiIterator>* pmp = static_cast<saved_matched_paren<BidiIterator>*>(m_backup_state);
1289 // restore previous values if no match was found:
1292 m_presult->set_first(pmp->sub.first, pmp->index, pmp->index == 0);
1293 m_presult->set_second(pmp->sub.second, pmp->index, pmp->sub.matched, pmp->index == 0);
1295 #ifdef BOOST_REGEX_MATCH_EXTRA
1297 // we have a match, push the capture information onto the stack:
1299 else if(pmp->sub.matched && (match_extra & m_match_flags))
1300 ((*m_presult)[pmp->index]).get_captures().push_back(pmp->sub);
1303 m_backup_state = pmp+1;
1304 boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp);
1305 return true; // keep looking
1308 template <class BidiIterator, class Allocator, class traits>
1309 bool perl_matcher<BidiIterator, Allocator, traits>::unwind_recursion_stopper(bool)
1311 boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(m_backup_state++);
1312 pstate = 0; // nothing left to search
1313 return false; // end of stack nothing more to search
1316 template <class BidiIterator, class Allocator, class traits>
1317 bool perl_matcher<BidiIterator, Allocator, traits>::unwind_assertion(bool r)
1319 saved_assertion<BidiIterator>* pmp = static_cast<saved_assertion<BidiIterator>*>(m_backup_state);
1320 pstate = pmp->pstate;
1321 position = pmp->position;
1322 bool result = (r == pmp->positive);
1323 m_recursive_result = pmp->positive ? r : !r;
1324 boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++);
1325 m_backup_state = pmp;
1326 m_unwound_lookahead = true;
1327 return !result; // return false if the assertion was matched to stop search.
1330 template <class BidiIterator, class Allocator, class traits>
1331 bool perl_matcher<BidiIterator, Allocator, traits>::unwind_alt(bool r)
1333 saved_position<BidiIterator>* pmp = static_cast<saved_position<BidiIterator>*>(m_backup_state);
1336 pstate = pmp->pstate;
1337 position = pmp->position;
1339 boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++);
1340 m_backup_state = pmp;
1345 template <class BidiIterator, class Allocator, class traits>
1346 bool perl_matcher<BidiIterator, Allocator, traits>::unwind_repeater_counter(bool)
1348 saved_repeater<BidiIterator>* pmp = static_cast<saved_repeater<BidiIterator>*>(m_backup_state);
1349 boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++);
1350 m_backup_state = pmp;
1351 return true; // keep looking
1354 template <class BidiIterator, class Allocator, class traits>
1355 bool perl_matcher<BidiIterator, Allocator, traits>::unwind_extra_block(bool)
1358 saved_extra_block* pmp = static_cast<saved_extra_block*>(m_backup_state);
1359 void* condemmed = m_stack_base;
1360 m_stack_base = pmp->base;
1361 m_backup_state = pmp->end;
1362 boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp);
1363 put_mem_block(condemmed);
1364 return true; // keep looking
1367 template <class BidiIterator, class Allocator, class traits>
1368 inline void perl_matcher<BidiIterator, Allocator, traits>::destroy_single_repeat()
1370 saved_single_repeat<BidiIterator>* p = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
1371 boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(p++);
1375 template <class BidiIterator, class Allocator, class traits>
1376 bool perl_matcher<BidiIterator, Allocator, traits>::unwind_greedy_single_repeat(bool r)
1378 saved_single_repeat<BidiIterator>* pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
1380 // if we have a match, just discard this state:
1383 destroy_single_repeat();
1387 const re_repeat* rep = pmp->rep;
1388 std::size_t count = pmp->count;
1389 BOOST_REGEX_ASSERT(rep->next.p != 0);
1390 BOOST_REGEX_ASSERT(rep->alt.p != 0);
1394 if((m_match_flags & match_partial) && (position == last))
1395 m_has_partial_match = true;
1397 BOOST_REGEX_ASSERT(count);
1398 position = pmp->last_position;
1400 // backtrack till we can skip out:
1406 }while(count && !can_start(*position, rep->_map, mask_skip));
1408 // if we've hit base, destroy this state:
1411 destroy_single_repeat();
1412 if(!can_start(*position, rep->_map, mask_skip))
1417 pmp->count = count + rep->min;
1418 pmp->last_position = position;
1420 pstate = rep->alt.p;
1424 template <class BidiIterator, class Allocator, class traits>
1425 bool perl_matcher<BidiIterator, Allocator, traits>::unwind_slow_dot_repeat(bool r)
1427 saved_single_repeat<BidiIterator>* pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
1429 // if we have a match, just discard this state:
1432 destroy_single_repeat();
1436 const re_repeat* rep = pmp->rep;
1437 std::size_t count = pmp->count;
1438 BOOST_REGEX_ASSERT(rep->type == syntax_element_dot_rep);
1439 BOOST_REGEX_ASSERT(rep->next.p != 0);
1440 BOOST_REGEX_ASSERT(rep->alt.p != 0);
1441 BOOST_REGEX_ASSERT(rep->next.p->type == syntax_element_wild);
1443 BOOST_REGEX_ASSERT(count < rep->max);
1444 pstate = rep->next.p;
1445 position = pmp->last_position;
1447 if(position != last)
1449 // wind forward until we can skip out of the repeat:
1454 // failed repeat match, discard this state and look for another:
1455 destroy_single_repeat();
1460 pstate = rep->next.p;
1461 }while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip));
1463 if(position == last)
1465 // can't repeat any more, remove the pushed state:
1466 destroy_single_repeat();
1467 if((m_match_flags & match_partial) && (position == last) && (position != search_base))
1468 m_has_partial_match = true;
1469 if(0 == (rep->can_be_null & mask_skip))
1472 else if(count == rep->max)
1474 // can't repeat any more, remove the pushed state:
1475 destroy_single_repeat();
1476 if(!can_start(*position, rep->_map, mask_skip))
1482 pmp->last_position = position;
1484 pstate = rep->alt.p;
1488 template <class BidiIterator, class Allocator, class traits>
1489 bool perl_matcher<BidiIterator, Allocator, traits>::unwind_fast_dot_repeat(bool r)
1491 saved_single_repeat<BidiIterator>* pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
1493 // if we have a match, just discard this state:
1496 destroy_single_repeat();
1500 const re_repeat* rep = pmp->rep;
1501 std::size_t count = pmp->count;
1503 BOOST_REGEX_ASSERT(count < rep->max);
1504 position = pmp->last_position;
1505 if(position != last)
1508 // wind forward until we can skip out of the repeat:
1514 }while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip));
1517 // remember where we got to if this is a leading repeat:
1518 if((rep->leading) && (count < rep->max))
1520 if(position == last)
1522 // can't repeat any more, remove the pushed state:
1523 destroy_single_repeat();
1524 if((m_match_flags & match_partial) && (position == last) && (position != search_base))
1525 m_has_partial_match = true;
1526 if(0 == (rep->can_be_null & mask_skip))
1529 else if(count == rep->max)
1531 // can't repeat any more, remove the pushed state:
1532 destroy_single_repeat();
1533 if(!can_start(*position, rep->_map, mask_skip))
1539 pmp->last_position = position;
1541 pstate = rep->alt.p;
1545 template <class BidiIterator, class Allocator, class traits>
1546 bool perl_matcher<BidiIterator, Allocator, traits>::unwind_char_repeat(bool r)
1548 saved_single_repeat<BidiIterator>* pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
1550 // if we have a match, just discard this state:
1553 destroy_single_repeat();
1557 const re_repeat* rep = pmp->rep;
1558 std::size_t count = pmp->count;
1559 pstate = rep->next.p;
1560 const char_type what = *reinterpret_cast<const char_type*>(static_cast<const re_literal*>(pstate) + 1);
1561 position = pmp->last_position;
1563 BOOST_REGEX_ASSERT(rep->type == syntax_element_char_rep);
1564 BOOST_REGEX_ASSERT(rep->next.p != 0);
1565 BOOST_REGEX_ASSERT(rep->alt.p != 0);
1566 BOOST_REGEX_ASSERT(rep->next.p->type == syntax_element_literal);
1567 BOOST_REGEX_ASSERT(count < rep->max);
1569 if(position != last)
1571 // wind forward until we can skip out of the repeat:
1574 if(traits_inst.translate(*position, icase) != what)
1576 // failed repeat match, discard this state and look for another:
1577 destroy_single_repeat();
1583 pstate = rep->next.p;
1584 }while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip));
1586 // remember where we got to if this is a leading repeat:
1587 if((rep->leading) && (count < rep->max))
1589 if(position == last)
1591 // can't repeat any more, remove the pushed state:
1592 destroy_single_repeat();
1593 if((m_match_flags & match_partial) && (position == last) && (position != search_base))
1594 m_has_partial_match = true;
1595 if(0 == (rep->can_be_null & mask_skip))
1598 else if(count == rep->max)
1600 // can't repeat any more, remove the pushed state:
1601 destroy_single_repeat();
1602 if(!can_start(*position, rep->_map, mask_skip))
1608 pmp->last_position = position;
1610 pstate = rep->alt.p;
1614 template <class BidiIterator, class Allocator, class traits>
1615 bool perl_matcher<BidiIterator, Allocator, traits>::unwind_short_set_repeat(bool r)
1617 saved_single_repeat<BidiIterator>* pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
1619 // if we have a match, just discard this state:
1622 destroy_single_repeat();
1626 const re_repeat* rep = pmp->rep;
1627 std::size_t count = pmp->count;
1628 pstate = rep->next.p;
1629 const unsigned char* map = static_cast<const re_set*>(rep->next.p)->_map;
1630 position = pmp->last_position;
1632 BOOST_REGEX_ASSERT(rep->type == syntax_element_short_set_rep);
1633 BOOST_REGEX_ASSERT(rep->next.p != 0);
1634 BOOST_REGEX_ASSERT(rep->alt.p != 0);
1635 BOOST_REGEX_ASSERT(rep->next.p->type == syntax_element_set);
1636 BOOST_REGEX_ASSERT(count < rep->max);
1638 if(position != last)
1640 // wind forward until we can skip out of the repeat:
1643 if(!map[static_cast<unsigned char>(traits_inst.translate(*position, icase))])
1645 // failed repeat match, discard this state and look for another:
1646 destroy_single_repeat();
1652 pstate = rep->next.p;
1653 }while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip));
1655 // remember where we got to if this is a leading repeat:
1656 if((rep->leading) && (count < rep->max))
1658 if(position == last)
1660 // can't repeat any more, remove the pushed state:
1661 destroy_single_repeat();
1662 if((m_match_flags & match_partial) && (position == last) && (position != search_base))
1663 m_has_partial_match = true;
1664 if(0 == (rep->can_be_null & mask_skip))
1667 else if(count == rep->max)
1669 // can't repeat any more, remove the pushed state:
1670 destroy_single_repeat();
1671 if(!can_start(*position, rep->_map, mask_skip))
1677 pmp->last_position = position;
1679 pstate = rep->alt.p;
1683 template <class BidiIterator, class Allocator, class traits>
1684 bool perl_matcher<BidiIterator, Allocator, traits>::unwind_long_set_repeat(bool r)
1686 typedef typename traits::char_class_type m_type;
1687 saved_single_repeat<BidiIterator>* pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
1689 // if we have a match, just discard this state:
1692 destroy_single_repeat();
1696 const re_repeat* rep = pmp->rep;
1697 std::size_t count = pmp->count;
1698 pstate = rep->next.p;
1699 const re_set_long<m_type>* set = static_cast<const re_set_long<m_type>*>(pstate);
1700 position = pmp->last_position;
1702 BOOST_REGEX_ASSERT(rep->type == syntax_element_long_set_rep);
1703 BOOST_REGEX_ASSERT(rep->next.p != 0);
1704 BOOST_REGEX_ASSERT(rep->alt.p != 0);
1705 BOOST_REGEX_ASSERT(rep->next.p->type == syntax_element_long_set);
1706 BOOST_REGEX_ASSERT(count < rep->max);
1708 if(position != last)
1710 // wind forward until we can skip out of the repeat:
1713 if(position == re_is_set_member(position, last, set, re.get_data(), icase))
1715 // failed repeat match, discard this state and look for another:
1716 destroy_single_repeat();
1722 pstate = rep->next.p;
1723 }while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip));
1725 // remember where we got to if this is a leading repeat:
1726 if((rep->leading) && (count < rep->max))
1728 if(position == last)
1730 // can't repeat any more, remove the pushed state:
1731 destroy_single_repeat();
1732 if((m_match_flags & match_partial) && (position == last) && (position != search_base))
1733 m_has_partial_match = true;
1734 if(0 == (rep->can_be_null & mask_skip))
1737 else if(count == rep->max)
1739 // can't repeat any more, remove the pushed state:
1740 destroy_single_repeat();
1741 if(!can_start(*position, rep->_map, mask_skip))
1747 pmp->last_position = position;
1749 pstate = rep->alt.p;
1753 template <class BidiIterator, class Allocator, class traits>
1754 bool perl_matcher<BidiIterator, Allocator, traits>::unwind_non_greedy_repeat(bool r)
1756 saved_position<BidiIterator>* pmp = static_cast<saved_position<BidiIterator>*>(m_backup_state);
1759 position = pmp->position;
1760 pstate = pmp->pstate;
1763 boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++);
1764 m_backup_state = pmp;
1768 template <class BidiIterator, class Allocator, class traits>
1769 bool perl_matcher<BidiIterator, Allocator, traits>::unwind_recursion(bool r)
1771 // We are backtracking back inside a recursion, need to push the info
1772 // back onto the recursion stack, and do so unconditionally, otherwise
1773 // we can get mismatched pushes and pops...
1774 saved_recursion<results_type>* pmp = static_cast<saved_recursion<results_type>*>(m_backup_state);
1777 recursion_stack.push_back(recursion_info<results_type>());
1778 recursion_stack.back().idx = pmp->recursion_id;
1779 recursion_stack.back().preturn_address = pmp->preturn_address;
1780 recursion_stack.back().results = pmp->prior_results;
1781 recursion_stack.back().location_of_start = position;
1782 *m_presult = pmp->internal_results;
1784 boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++);
1785 m_backup_state = pmp;
1789 template <class BidiIterator, class Allocator, class traits>
1790 bool perl_matcher<BidiIterator, Allocator, traits>::unwind_recursion_pop(bool r)
1792 // Backtracking out of a recursion, we must pop state off the recursion
1793 // stack unconditionally to ensure matched pushes and pops:
1794 saved_state* pmp = static_cast<saved_state*>(m_backup_state);
1795 if (!r && !recursion_stack.empty())
1797 *m_presult = recursion_stack.back().results;
1798 position = recursion_stack.back().location_of_start;
1799 recursion_stack.pop_back();
1801 boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++);
1802 m_backup_state = pmp;
1806 template <class BidiIterator, class Allocator, class traits>
1807 void perl_matcher<BidiIterator, Allocator, traits>::push_recursion_pop()
1809 saved_state* pmp = static_cast<saved_state*>(m_backup_state);
1811 if(pmp < m_stack_base)
1814 pmp = static_cast<saved_state*>(m_backup_state);
1817 (void) new (pmp)saved_state(15);
1818 m_backup_state = pmp;
1821 template <class BidiIterator, class Allocator, class traits>
1822 bool perl_matcher<BidiIterator, Allocator, traits>::unwind_commit(bool b)
1824 boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(m_backup_state++);
1825 while(unwind(b) && !m_unwound_lookahead){}
1826 if(m_unwound_lookahead && pstate)
1829 // If we stop because we just unwound an assertion, put the
1830 // commit state back on the stack again:
1832 m_unwound_lookahead = false;
1833 saved_state* pmp = m_backup_state;
1835 if(pmp < m_stack_base)
1838 pmp = m_backup_state;
1841 (void) new (pmp)saved_state(16);
1842 m_backup_state = pmp;
1844 // This prevents us from stopping when we exit from an independent sub-expression:
1845 m_independent = false;
1849 template <class BidiIterator, class Allocator, class traits>
1850 bool perl_matcher<BidiIterator, Allocator, traits>::unwind_then(bool b)
1852 // Unwind everything till we hit an alternative:
1853 boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(m_backup_state++);
1854 bool result = false;
1856 while(result && !m_unwound_alt)
1860 // We're now pointing at the next alternative, need one more backtrack
1861 // since *all* the other alternatives must fail once we've reached a THEN clause:
1862 if(result && m_unwound_alt)
1867 } // namespace BOOST_REGEX_DETAIL_NS
1868 } // namespace boost
1870 #ifdef BOOST_REGEX_MSVC
1871 # pragma warning(pop)