diff --git a/include/boost/regex/v4/perl_matcher.hpp b/include/boost/regex/v4/perl_matcher.hpp index b7b3b58e..e21f093d 100644 --- a/include/boost/regex/v4/perl_matcher.hpp +++ b/include/boost/regex/v4/perl_matcher.hpp @@ -253,23 +253,40 @@ class repeater_count int state_id; std::size_t count; // the number of iterations so far BidiIterator start_pos; // where the last repeat started + + repeater_count* unwind_until(int n, repeater_count* p, int current_recursion_id) + { + while(p && (p->state_id != n)) + { + if(-2 - current_recursion_id == p->state_id) + return 0; + p = p->next; + if(p && (p->state_id < 0)) + { + p = unwind_until(p->state_id, p, current_recursion_id); + if(!p) + return p; + p = p->next; + } + } + return p; + } public: repeater_count(repeater_count** s) : stack(s), next(0), state_id(-1), count(0), start_pos() {} - - repeater_count(int i, repeater_count** s, BidiIterator start) + + repeater_count(int i, repeater_count** s, BidiIterator start, int current_recursion_id) : start_pos(start) { state_id = i; stack = s; next = *stack; *stack = this; - if(state_id > next->state_id) + if((state_id > next->state_id) && (next->state_id >= 0)) count = 0; else { repeater_count* p = next; - while(p && (p->state_id != state_id)) - p = p->next; + p = unwind_until(state_id, p, current_recursion_id); if(p) { count = p->count; diff --git a/include/boost/regex/v4/perl_matcher_non_recursive.hpp b/include/boost/regex/v4/perl_matcher_non_recursive.hpp index 5c1f7a98..07e93411 100644 --- a/include/boost/regex/v4/perl_matcher_non_recursive.hpp +++ b/include/boost/regex/v4/perl_matcher_non_recursive.hpp @@ -87,8 +87,8 @@ template struct saved_repeater : public saved_state { repeater_count count; - saved_repeater(int i, repeater_count** s, BidiIterator start) - : saved_state(saved_state_repeater_count), count(i,s,start){} + saved_repeater(int i, repeater_count** s, BidiIterator start, int current_recursion_id) + : saved_state(saved_state_repeater_count), count(i, s, start, current_recursion_id){} }; struct saved_extra_block : public saved_state @@ -309,7 +309,7 @@ inline void perl_matcher::push_repeater_count(i pmp = static_cast*>(m_backup_state); --pmp; } - (void) new (pmp)saved_repeater(i, s, position); + (void) new (pmp)saved_repeater(i, s, position, this->recursion_stack.size() ? this->recursion_stack.back().idx : (INT_MIN + 3)); m_backup_state = pmp; } @@ -923,12 +923,12 @@ bool perl_matcher::match_recursion() recursion_stack.push_back(recursion_info()); recursion_stack.back().preturn_address = pstate->next.p; recursion_stack.back().results = *m_presult; - if(static_cast(pstate)->state_id > 0) - { - push_repeater_count(static_cast(pstate)->state_id, &next_count); - } pstate = static_cast(pstate)->alt.p; recursion_stack.back().idx = static_cast(pstate)->index; + //if(static_cast(pstate)->state_id > 0) + { + push_repeater_count(-(2 + static_cast(pstate)->index), &next_count); + } return true; } @@ -952,6 +952,7 @@ bool perl_matcher::match_endmark() *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(); + push_repeater_count(-(2 + index), &next_count); } } } diff --git a/include/boost/regex/v4/perl_matcher_recursive.hpp b/include/boost/regex/v4/perl_matcher_recursive.hpp index 8e0e182b..9ed5af18 100644 --- a/include/boost/regex/v4/perl_matcher_recursive.hpp +++ b/include/boost/regex/v4/perl_matcher_recursive.hpp @@ -308,7 +308,7 @@ bool perl_matcher::match_rep() // Always copy the repeat count, so that the state is restored // when we exit this scope: // - repeater_count r(rep->state_id, &next_count, position); + repeater_count r(rep->state_id, &next_count, position, this->recursion_stack.size() ? this->recursion_stack.back().idx : INT_MIN + 3); // // If we've had at least one repeat already, and the last one // matched the NULL string then set the repeat count to diff --git a/test/regress/test_perl_ex.cpp b/test/regress/test_perl_ex.cpp index 2699e642..5ff48e1d 100644 --- a/test/regress/test_perl_ex.cpp +++ b/test/regress/test_perl_ex.cpp @@ -918,6 +918,7 @@ void test_recursion() TEST_REGEX_SEARCH("namespace\\s+(\\w+)\\s+(\\{(?:[^{}]*(?:(?2)[^{}]*)*)?\\})", perl, "namespace one { namespace two { int foo(); } }", match_default, make_array(0, 46, 10, 13, 14, 46, -2, -2)); TEST_REGEX_SEARCH("namespace\\s+(\\w+)\\s+(\\{(?:[^{}]*(?:(?2)[^{}]*)*)?\\})", perl, "namespace one { namespace two { int foo(){} } { {{{ } } } } {}}", match_default, make_array(0, 64, 10, 13, 14, 64, -2, -2)); TEST_INVALID_REGEX("((?1)|a)", perl); + TEST_REGEX_SEARCH("a(?0)?", perl, "aaaaa", match_default, make_array(0, 5, -2, -2)); // Recursion to a named sub with a name that is used multiple times: TEST_REGEX_SEARCH("(?:(?a+)|(?b+))\\.(?&A)", perl, "aaaa.aa", match_default, make_array(0, 7, 0, 4, -1, -1, -2, -2));