113 typedef typename Encoding::Ch Ch;
114 template <
typename,
typename>
friend class GenericRegexSearch;
116 GenericRegex(
const Ch* source,
Allocator* allocator = 0) :
117 ownAllocator_(allocator ? 0 :
RAPIDJSON_NEW(
Allocator)()), allocator_(allocator ? allocator : ownAllocator_),
118 states_(allocator_, 256), ranges_(allocator_, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
119 anchorBegin_(), anchorEnd_()
131 bool IsValid()
const {
132 return root_ != kRegexInvalidState;
145 static const unsigned kAnyCharacterClass = 0xFFFFFFFF;
146 static const unsigned kRangeCharacterClass = 0xFFFFFFFE;
147 static const unsigned kRangeNegationFlag = 0x80000000;
171 return states_.template Bottom<State>()[index];
174 const State& GetState(
SizeType index)
const {
176 return states_.template Bottom<State>()[index];
181 return ranges_.template Bottom<Range>()[index];
184 const Range& GetRange(
SizeType index)
const {
186 return ranges_.template Bottom<Range>()[index];
189 template <
typename InputStream>
195 *atomCountStack.template Push<unsigned>() = 0;
198 while (ds.Peek() != 0) {
199 switch (codepoint = ds.Take()) {
209 while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() < kAlternation)
210 if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
212 *operatorStack.template Push<Operator>() = kAlternation;
213 *atomCountStack.template Top<unsigned>() = 0;
217 *operatorStack.template Push<Operator>() = kLeftParenthesis;
218 *atomCountStack.template Push<unsigned>() = 0;
222 while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis)
223 if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
225 if (operatorStack.Empty())
227 operatorStack.template Pop<Operator>(1);
228 atomCountStack.template Pop<unsigned>(1);
229 ImplicitConcatenation(atomCountStack, operatorStack);
233 if (!Eval(operandStack, kZeroOrOne))
238 if (!Eval(operandStack, kZeroOrMore))
243 if (!Eval(operandStack, kOneOrMore))
250 if (!ParseUnsigned(ds, &n))
253 if (ds.Peek() ==
',') {
255 if (ds.Peek() ==
'}')
256 m = kInfinityQuantifier;
257 else if (!ParseUnsigned(ds, &m) || m < n)
263 if (!EvalQuantifier(operandStack, n, m) || ds.Peek() !=
'}')
270 PushOperand(operandStack, kAnyCharacterClass);
271 ImplicitConcatenation(atomCountStack, operatorStack);
277 if (!ParseRange(ds, &range))
279 SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass);
280 GetState(s).rangeStart = range;
281 *operandStack.template Push<Frag>() = Frag(s, s, s);
283 ImplicitConcatenation(atomCountStack, operatorStack);
287 if (!CharacterEscape(ds, &codepoint))
290 RAPIDJSON_DELIBERATE_FALLTHROUGH;
293 PushOperand(operandStack, codepoint);
294 ImplicitConcatenation(atomCountStack, operatorStack);
298 while (!operatorStack.Empty())
299 if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
303 if (operandStack.GetSize() ==
sizeof(Frag)) {
304 Frag* e = operandStack.template Pop<Frag>(1);
305 Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0));
308#if RAPIDJSON_REGEX_VERBOSE
309 printf(
"root: %d\n", root_);
310 for (
SizeType i = 0; i < stateCount_ ; i++) {
311 State& s = GetState(i);
312 printf(
"[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (
char)s.codepoint);
320 State* s = states_.template Push<State>();
323 s->codepoint = codepoint;
324 s->rangeStart = kRegexInvalidRange;
325 return stateCount_++;
329 SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);
330 *operandStack.template Push<Frag>() = Frag(s, s, s);
334 if (*atomCountStack.template Top<unsigned>())
335 *operatorStack.template Push<Operator>() = kConcatenation;
336 (*atomCountStack.template Top<unsigned>())++;
341 while (GetState(l1).out != kRegexInvalidState)
342 l1 = GetState(l1).out;
343 GetState(l1).out = l2;
348 for (
SizeType next; l != kRegexInvalidState; l = next) {
349 next = GetState(l).out;
359 Frag e2 = *operandStack.template Pop<Frag>(1);
360 Frag e1 = *operandStack.template Pop<Frag>(1);
361 Patch(e1.out, e2.start);
362 *operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex));
367 if (operandStack.GetSize() >=
sizeof(Frag) * 2) {
368 Frag e2 = *operandStack.template Pop<Frag>(1);
369 Frag e1 = *operandStack.template Pop<Frag>(1);
370 SizeType s = NewState(e1.start, e2.start, 0);
371 *operandStack.template Push<Frag>() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex));
377 if (operandStack.GetSize() >=
sizeof(Frag)) {
378 Frag e = *operandStack.template Pop<Frag>(1);
379 SizeType s = NewState(kRegexInvalidState, e.start, 0);
380 *operandStack.template Push<Frag>() = Frag(s, Append(e.out, s), e.minIndex);
386 if (operandStack.GetSize() >=
sizeof(Frag)) {
387 Frag e = *operandStack.template Pop<Frag>(1);
388 SizeType s = NewState(kRegexInvalidState, e.start, 0);
390 *operandStack.template Push<Frag>() = Frag(s, s, e.minIndex);
396 if (operandStack.GetSize() >=
sizeof(Frag)) {
397 Frag e = *operandStack.template Pop<Frag>(1);
398 SizeType s = NewState(kRegexInvalidState, e.start, 0);
400 *operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex);
411 bool EvalQuantifier(
Stack<Allocator>& operandStack,
unsigned n,
unsigned m) {
418 else if (m == kInfinityQuantifier)
419 Eval(operandStack, kZeroOrMore);
421 Eval(operandStack, kZeroOrOne);
422 for (
unsigned i = 0; i < m - 1; i++)
423 CloneTopOperand(operandStack);
424 for (
unsigned i = 0; i < m - 1; i++)
425 Eval(operandStack, kConcatenation);
430 for (
unsigned i = 0; i < n - 1; i++)
431 CloneTopOperand(operandStack);
433 if (m == kInfinityQuantifier)
434 Eval(operandStack, kOneOrMore);
436 CloneTopOperand(operandStack);
437 Eval(operandStack, kZeroOrOne);
438 for (
unsigned i = n; i < m - 1; i++)
439 CloneTopOperand(operandStack);
440 for (
unsigned i = n; i < m; i++)
441 Eval(operandStack, kConcatenation);
444 for (
unsigned i = 0; i < n - 1; i++)
445 Eval(operandStack, kConcatenation);
453 const Frag src = *operandStack.template Top<Frag>();
454 SizeType count = stateCount_ - src.minIndex;
455 State* s = states_.template Push<State>(count);
456 memcpy(s, &GetState(src.minIndex), count *
sizeof(State));
457 for (
SizeType j = 0; j < count; j++) {
458 if (s[j].out != kRegexInvalidState)
460 if (s[j].out1 != kRegexInvalidState)
463 *operandStack.template Push<Frag>() = Frag(src.start + count, src.out + count, src.minIndex + count);
464 stateCount_ += count;
467 template <
typename InputStream>
470 if (ds.Peek() <
'0' || ds.Peek() >
'9')
472 while (ds.Peek() >=
'0' && ds.Peek() <=
'9') {
473 if (r >= 429496729 && ds.Peek() >
'5')
475 r = r * 10 + (ds.Take() -
'0');
481 template <
typename InputStream>
486 SizeType start = kRegexInvalidRange;
487 SizeType current = kRegexInvalidRange;
489 while ((codepoint = ds.Take()) != 0) {
492 if (codepoint ==
'^') {
500 if (start == kRegexInvalidRange)
505 GetRange(current).next = r;
508 GetRange(start).start |= kRangeNegationFlag;
513 if (ds.Peek() ==
'b') {
517 else if (!CharacterEscape(ds, &codepoint))
520 RAPIDJSON_DELIBERATE_FALLTHROUGH;
525 if (codepoint ==
'-') {
530 RAPIDJSON_DELIBERATE_FALLTHROUGH;
535 if (current != kRegexInvalidRange)
536 GetRange(current).next = r;
537 if (start == kRegexInvalidRange)
546 GetRange(current).end = codepoint;
554 SizeType NewRange(
unsigned codepoint) {
555 Range* r = ranges_.template Push<Range>();
556 r->start = r->end = codepoint;
557 r->next = kRegexInvalidRange;
558 return rangeCount_++;
561 template <
typename InputStream>
564 switch (codepoint = ds.Take()) {
579 *escapedCodepoint = codepoint;
return true;
580 case 'f': *escapedCodepoint = 0x000C;
return true;
581 case 'n': *escapedCodepoint = 0x000A;
return true;
582 case 'r': *escapedCodepoint = 0x000D;
return true;
583 case 't': *escapedCodepoint = 0x0009;
return true;
584 case 'v': *escapedCodepoint = 0x000B;
return true;
598 static const unsigned kInfinityQuantifier = ~0u;
606class GenericRegexSearch {
608 typedef typename BESRegexType::EncodingType Encoding;
609 typedef typename Encoding::Ch Ch;
611 GenericRegexSearch(
const BESRegexType& regex,
Allocator* allocator = 0) :
612 regex_(regex), allocator_(allocator), ownAllocator_(0),
613 state0_(allocator, 0), state1_(allocator, 0), stateSet_()
618 stateSet_ =
static_cast<unsigned*
>(allocator_->Malloc(GetStateSetSize()));
619 state0_.template Reserve<SizeType>(regex_.stateCount_);
620 state1_.template Reserve<SizeType>(regex_.stateCount_);
623 ~GenericRegexSearch() {
624 Allocator::Free(stateSet_);
628 template <
typename InputStream>
629 bool Match(InputStream& is) {
630 return SearchWithAnchoring(is,
true,
true);
633 bool Match(
const Ch* s) {
638 template <
typename InputStream>
639 bool Search(InputStream& is) {
640 return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_);
643 bool Search(
const Ch* s) {
649 typedef typename BESRegexType::State State;
650 typedef typename BESRegexType::Range Range;
652 template <
typename InputStream>
653 bool SearchWithAnchoring(InputStream& is,
bool anchorBegin,
bool anchorEnd) {
658 const size_t stateSetSize = GetStateSetSize();
659 std::memset(stateSet_, 0, stateSetSize);
661 bool matched = AddState(*current, regex_.root_);
663 while (!current->Empty() && (codepoint = ds.Take()) != 0) {
664 std::memset(stateSet_, 0, stateSetSize);
667 for (
const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {
668 const State& sr = regex_.GetState(*s);
669 if (sr.codepoint == codepoint ||
670 sr.codepoint == BESRegexType::kAnyCharacterClass ||
671 (sr.codepoint == BESRegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
673 matched = AddState(*next, sr.out) || matched;
674 if (!anchorEnd && matched)
678 AddState(*next, regex_.root_);
680 internal::Swap(current, next);
686 size_t GetStateSetSize()
const {
687 return (regex_.stateCount_ + 31) / 32 * 4;
694 const State& s = regex_.GetState(index);
695 if (s.out1 != kRegexInvalidState) {
696 bool matched = AddState(l, s.out);
697 return AddState(l, s.out1) || matched;
699 else if (!(stateSet_[index >> 5] & (1u << (index & 31)))) {
700 stateSet_[index >> 5] |= (1u << (index & 31));
701 *l.template PushUnsafe<SizeType>() = index;
703 return s.out == kRegexInvalidState;
706 bool MatchRange(
SizeType rangeIndex,
unsigned codepoint)
const {
707 bool yes = (regex_.GetRange(rangeIndex).start & BESRegexType::kRangeNegationFlag) == 0;
708 while (rangeIndex != kRegexInvalidRange) {
709 const Range& r = regex_.GetRange(rangeIndex);
710 if (codepoint >= (r.start & ~BESRegexType::kRangeNegationFlag) && codepoint <= r.end)
717 const BESRegexType& regex_;