mirror of
https://github.com/boostorg/regex.git
synced 2025-07-17 22:32:09 +02:00
Fix for bug in recursive expressions, see http://lists.boost.org/Archives/boost/2015/03/221018.php
This commit is contained in:
@ -253,23 +253,40 @@ class repeater_count
|
|||||||
int state_id;
|
int state_id;
|
||||||
std::size_t count; // the number of iterations so far
|
std::size_t count; // the number of iterations so far
|
||||||
BidiIterator start_pos; // where the last repeat started
|
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:
|
public:
|
||||||
repeater_count(repeater_count** s) : stack(s), next(0), state_id(-1), count(0), start_pos() {}
|
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)
|
: start_pos(start)
|
||||||
{
|
{
|
||||||
state_id = i;
|
state_id = i;
|
||||||
stack = s;
|
stack = s;
|
||||||
next = *stack;
|
next = *stack;
|
||||||
*stack = this;
|
*stack = this;
|
||||||
if(state_id > next->state_id)
|
if((state_id > next->state_id) && (next->state_id >= 0))
|
||||||
count = 0;
|
count = 0;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
repeater_count* p = next;
|
repeater_count* p = next;
|
||||||
while(p && (p->state_id != state_id))
|
p = unwind_until(state_id, p, current_recursion_id);
|
||||||
p = p->next;
|
|
||||||
if(p)
|
if(p)
|
||||||
{
|
{
|
||||||
count = p->count;
|
count = p->count;
|
||||||
|
@ -87,8 +87,8 @@ template <class BidiIterator>
|
|||||||
struct saved_repeater : public saved_state
|
struct saved_repeater : public saved_state
|
||||||
{
|
{
|
||||||
repeater_count<BidiIterator> count;
|
repeater_count<BidiIterator> count;
|
||||||
saved_repeater(int i, repeater_count<BidiIterator>** s, BidiIterator start)
|
saved_repeater(int i, repeater_count<BidiIterator>** s, BidiIterator start, int current_recursion_id)
|
||||||
: saved_state(saved_state_repeater_count), count(i,s,start){}
|
: saved_state(saved_state_repeater_count), count(i, s, start, current_recursion_id){}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct saved_extra_block : public saved_state
|
struct saved_extra_block : public saved_state
|
||||||
@ -309,7 +309,7 @@ inline void perl_matcher<BidiIterator, Allocator, traits>::push_repeater_count(i
|
|||||||
pmp = static_cast<saved_repeater<BidiIterator>*>(m_backup_state);
|
pmp = static_cast<saved_repeater<BidiIterator>*>(m_backup_state);
|
||||||
--pmp;
|
--pmp;
|
||||||
}
|
}
|
||||||
(void) new (pmp)saved_repeater<BidiIterator>(i, s, position);
|
(void) new (pmp)saved_repeater<BidiIterator>(i, s, position, this->recursion_stack.size() ? this->recursion_stack.back().idx : (INT_MIN + 3));
|
||||||
m_backup_state = pmp;
|
m_backup_state = pmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -923,12 +923,12 @@ bool perl_matcher<BidiIterator, Allocator, traits>::match_recursion()
|
|||||||
recursion_stack.push_back(recursion_info<results_type>());
|
recursion_stack.push_back(recursion_info<results_type>());
|
||||||
recursion_stack.back().preturn_address = pstate->next.p;
|
recursion_stack.back().preturn_address = pstate->next.p;
|
||||||
recursion_stack.back().results = *m_presult;
|
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;
|
pstate = static_cast<const re_jump*>(pstate)->alt.p;
|
||||||
recursion_stack.back().idx = static_cast<const re_brace*>(pstate)->index;
|
recursion_stack.back().idx = static_cast<const re_brace*>(pstate)->index;
|
||||||
|
//if(static_cast<const re_recurse*>(pstate)->state_id > 0)
|
||||||
|
{
|
||||||
|
push_repeater_count(-(2 + static_cast<const re_brace*>(pstate)->index), &next_count);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -952,6 +952,7 @@ bool perl_matcher<BidiIterator, Allocator, traits>::match_endmark()
|
|||||||
*m_presult = recursion_stack.back().results;
|
*m_presult = recursion_stack.back().results;
|
||||||
push_recursion(recursion_stack.back().idx, recursion_stack.back().preturn_address, &recursion_stack.back().results);
|
push_recursion(recursion_stack.back().idx, recursion_stack.back().preturn_address, &recursion_stack.back().results);
|
||||||
recursion_stack.pop_back();
|
recursion_stack.pop_back();
|
||||||
|
push_repeater_count(-(2 + index), &next_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -308,7 +308,7 @@ bool perl_matcher<BidiIterator, Allocator, traits>::match_rep()
|
|||||||
// Always copy the repeat count, so that the state is restored
|
// Always copy the repeat count, so that the state is restored
|
||||||
// when we exit this scope:
|
// when we exit this scope:
|
||||||
//
|
//
|
||||||
repeater_count<BidiIterator> r(rep->state_id, &next_count, position);
|
repeater_count<BidiIterator> 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
|
// If we've had at least one repeat already, and the last one
|
||||||
// matched the NULL string then set the repeat count to
|
// matched the NULL string then set the repeat count to
|
||||||
|
@ -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, 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_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_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:
|
// Recursion to a named sub with a name that is used multiple times:
|
||||||
TEST_REGEX_SEARCH("(?:(?<A>a+)|(?<A>b+))\\.(?&A)", perl, "aaaa.aa", match_default, make_array(0, 7, 0, 4, -1, -1, -2, -2));
|
TEST_REGEX_SEARCH("(?:(?<A>a+)|(?<A>b+))\\.(?&A)", perl, "aaaa.aa", match_default, make_array(0, 7, 0, 4, -1, -1, -2, -2));
|
||||||
|
Reference in New Issue
Block a user