15 #ifndef RAPIDJSON_INTERNAL_REGEX_H_ 16 #define RAPIDJSON_INTERNAL_REGEX_H_ 18 #include "../allocators.h" 19 #include "../stream.h" 24 RAPIDJSON_DIAG_OFF(padded)
25 RAPIDJSON_DIAG_OFF(
switch-
enum)
26 RAPIDJSON_DIAG_OFF(implicit-fallthrough)
27 #elif defined(_MSC_VER) 29 RAPIDJSON_DIAG_OFF(4512)
34 RAPIDJSON_DIAG_OFF(effc++)
36 RAPIDJSON_DIAG_OFF(implicit-fallthrough)
40 #ifndef RAPIDJSON_REGEX_VERBOSE 41 #define RAPIDJSON_REGEX_VERBOSE 0 50 template <
typename SourceStream,
typename Encoding>
78 template <
typename Encoding,
typename Allocator>
113 template <
typename Encoding,
typename Allocator = CrtAllocator>
117 typedef typename Encoding::Ch
Ch;
121 ownAllocator_(allocator ? 0 :
RAPIDJSON_NEW(Allocator)()), allocator_(allocator ? allocator : ownAllocator_),
122 states_(allocator_, 256), ranges_(allocator_, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
123 anchorBegin_(), anchorEnd_()
149 static const unsigned kAnyCharacterClass = 0xFFFFFFFF;
150 static const unsigned kRangeCharacterClass = 0xFFFFFFFE;
151 static const unsigned kRangeNegationFlag = 0x80000000;
175 return states_.template Bottom<State>()[index];
180 return states_.template Bottom<State>()[index];
185 return ranges_.template Bottom<Range>()[index];
190 return ranges_.template Bottom<Range>()[index];
193 template <
typename InputStream>
199 *atomCountStack.template Push<unsigned>() = 0;
202 while (ds.
Peek() != 0) {
203 switch (codepoint = ds.
Take()) {
213 while (!operatorStack.
Empty() && *operatorStack.template Top<Operator>() < kAlternation)
214 if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
216 *operatorStack.template Push<Operator>() = kAlternation;
217 *atomCountStack.template Top<unsigned>() = 0;
221 *operatorStack.template Push<Operator>() = kLeftParenthesis;
222 *atomCountStack.template Push<unsigned>() = 0;
226 while (!operatorStack.
Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis)
227 if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
229 if (operatorStack.
Empty())
231 operatorStack.template Pop<Operator>(1);
232 atomCountStack.template Pop<unsigned>(1);
233 ImplicitConcatenation(atomCountStack, operatorStack);
237 if (!Eval(operandStack, kZeroOrOne))
242 if (!Eval(operandStack, kZeroOrMore))
247 if (!Eval(operandStack, kOneOrMore))
254 if (!ParseUnsigned(ds, &n))
257 if (ds.
Peek() ==
',') {
259 if (ds.
Peek() ==
'}')
260 m = kInfinityQuantifier;
261 else if (!ParseUnsigned(ds, &m) || m < n)
267 if (!EvalQuantifier(operandStack, n, m) || ds.
Peek() !=
'}')
274 PushOperand(operandStack, kAnyCharacterClass);
275 ImplicitConcatenation(atomCountStack, operatorStack);
281 if (!ParseRange(ds, &range))
283 SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass);
284 GetState(s).rangeStart = range;
285 *operandStack.template Push<Frag>() =
Frag(s, s, s);
287 ImplicitConcatenation(atomCountStack, operatorStack);
291 if (!CharacterEscape(ds, &codepoint))
296 PushOperand(operandStack, codepoint);
297 ImplicitConcatenation(atomCountStack, operatorStack);
301 while (!operatorStack.
Empty())
302 if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
307 Frag* e = operandStack.template Pop<Frag>(1);
308 Patch(e->
out, NewState(kRegexInvalidState, kRegexInvalidState, 0));
311 #if RAPIDJSON_REGEX_VERBOSE 312 printf(
"root: %d\n", root_);
313 for (
SizeType i = 0; i < stateCount_ ; i++) {
314 State& s = GetState(i);
315 printf(
"[%2d] out: %2d out1: %2d c: '%c'\n", i, s.
out, s.
out1, (
char)s.
codepoint);
323 State* s = states_.template Push<State>();
328 return stateCount_++;
332 SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);
333 *operandStack.template Push<Frag>() =
Frag(s, s, s);
337 if (*atomCountStack.template Top<unsigned>())
338 *operatorStack.template Push<Operator>() = kConcatenation;
339 (*atomCountStack.template Top<unsigned>())++;
344 while (GetState(l1).out != kRegexInvalidState)
345 l1 = GetState(l1).out;
346 GetState(l1).out = l2;
352 next = GetState(l).out;
362 Frag e2 = *operandStack.template Pop<Frag>(1);
363 Frag e1 = *operandStack.template Pop<Frag>(1);
364 Patch(e1.out, e2.
start);
365 *operandStack.template Push<Frag>() =
Frag(e1.start, e2.
out, Min(e1.minIndex, e2.
minIndex));
371 Frag e2 = *operandStack.template Pop<Frag>(1);
372 Frag e1 = *operandStack.template Pop<Frag>(1);
374 *operandStack.template Push<Frag>() =
Frag(s, Append(e1.out, e2.
out), Min(e1.minIndex, e2.
minIndex));
381 Frag e = *operandStack.template Pop<Frag>(1);
383 *operandStack.template Push<Frag>() =
Frag(s, Append(e.
out, s), e.
minIndex);
390 Frag e = *operandStack.template Pop<Frag>(1);
393 *operandStack.template Push<Frag>() =
Frag(s, s, e.
minIndex);
400 Frag e = *operandStack.template Pop<Frag>(1);
421 else if (m == kInfinityQuantifier)
422 Eval(operandStack, kZeroOrMore);
424 Eval(operandStack, kZeroOrOne);
425 for (
unsigned i = 0; i < m - 1; i++)
426 CloneTopOperand(operandStack);
427 for (
unsigned i = 0; i < m - 1; i++)
428 Eval(operandStack, kConcatenation);
433 for (
unsigned i = 0; i < n - 1; i++)
434 CloneTopOperand(operandStack);
436 if (m == kInfinityQuantifier)
437 Eval(operandStack, kOneOrMore);
439 CloneTopOperand(operandStack);
440 Eval(operandStack, kZeroOrOne);
441 for (
unsigned i = n; i < m - 1; i++)
442 CloneTopOperand(operandStack);
443 for (
unsigned i = n; i < m; i++)
444 Eval(operandStack, kConcatenation);
447 for (
unsigned i = 0; i < n - 1; i++)
448 Eval(operandStack, kConcatenation);
456 const Frag src = *operandStack.template Top<Frag>();
458 State* s = states_.template Push<State>(count);
460 for (
SizeType j = 0; j < count; j++) {
461 if (s[j].out != kRegexInvalidState)
463 if (s[j].out1 != kRegexInvalidState)
466 *operandStack.template Push<Frag>() =
Frag(src.
start + count, src.
out + count, src.
minIndex + count);
467 stateCount_ += count;
470 template <
typename InputStream>
473 if (ds.
Peek() <
'0' || ds.
Peek() >
'9')
475 while (ds.
Peek() >=
'0' && ds.
Peek() <=
'9') {
476 if (r >= 429496729 && ds.
Peek() >
'5')
478 r = r * 10 + (ds.
Take() -
'0');
484 template <
typename InputStream>
492 while ((codepoint = ds.
Take()) != 0) {
495 if (codepoint ==
'^') {
503 if (start == kRegexInvalidRange)
508 GetRange(current).next = r;
511 GetRange(start).start |= kRangeNegationFlag;
516 if (ds.
Peek() ==
'b') {
520 else if (!CharacterEscape(ds, &codepoint))
527 if (codepoint ==
'-') {
536 if (current != kRegexInvalidRange)
537 GetRange(current).next = r;
538 if (start == kRegexInvalidRange)
547 GetRange(current).end = codepoint;
556 Range* r = ranges_.template Push<Range>();
559 return rangeCount_++;
562 template <
typename InputStream>
565 switch (codepoint = ds.
Take()) {
580 *escapedCodepoint = codepoint;
return true;
581 case 'f': *escapedCodepoint = 0x000C;
return true;
582 case 'n': *escapedCodepoint = 0x000A;
return true;
583 case 'r': *escapedCodepoint = 0x000D;
return true;
584 case 't': *escapedCodepoint = 0x0009;
return true;
585 case 'v': *escapedCodepoint = 0x000B;
return true;
599 static const unsigned kInfinityQuantifier = ~0u;
606 template <
typename RegexType,
typename Allocator = CrtAllocator>
610 typedef typename Encoding::Ch
Ch;
613 regex_(regex), allocator_(allocator), ownAllocator_(0),
614 state0_(allocator, 0), state1_(allocator, 0), stateSet_()
619 stateSet_ =
static_cast<unsigned*
>(allocator_->Malloc(GetStateSetSize()));
620 state0_.template Reserve<SizeType>(regex_.stateCount_);
621 state1_.template Reserve<SizeType>(regex_.stateCount_);
625 Allocator::Free(stateSet_);
629 template <
typename InputStream>
631 return SearchWithAnchoring(is,
true,
true);
639 template <
typename InputStream>
641 return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_);
650 typedef typename RegexType::State
State;
651 typedef typename RegexType::Range
Range;
653 template <
typename InputStream>
659 const size_t stateSetSize = GetStateSetSize();
660 std::memset(stateSet_, 0, stateSetSize);
662 bool matched = AddState(*current, regex_.root_);
664 while (!current->
Empty() && (codepoint = ds.
Take()) != 0) {
665 std::memset(stateSet_, 0, stateSetSize);
668 for (
const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {
669 const State& sr = regex_.GetState(*s);
670 if (sr.codepoint == codepoint ||
671 sr.codepoint == RegexType::kAnyCharacterClass ||
672 (sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
674 matched = AddState(*next, sr.out) || matched;
675 if (!anchorEnd && matched)
679 AddState(*next, regex_.root_);
688 return (regex_.stateCount_ + 31) / 32 * 4;
695 const State& s = regex_.GetState(index);
696 if (s.out1 != kRegexInvalidState) {
697 bool matched = AddState(l, s.out);
698 return AddState(l, s.out1) || matched;
700 else if (!(stateSet_[index >> 5] & (1u << (index & 31)))) {
701 stateSet_[index >> 5] |= (1u << (index & 31));
702 *l.template PushUnsafe<SizeType>() = index;
708 bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0;
709 while (rangeIndex != kRegexInvalidRange) {
710 const Range& r = regex_.GetRange(rangeIndex);
711 if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end)
736 #if defined(__clang__) || defined(_MSC_VER) 740 #endif // RAPIDJSON_INTERNAL_REGEX_H_
bool MatchRange(SizeType rangeIndex, unsigned codepoint) const
Stack< Allocator > states_
const CharType(& source)[N]
RAPIDJSON_NAMESPACE_BEGIN typedef unsigned SizeType
Size type (for string lengths, array sizes, etc.)
void Parse(DecodedStream< InputStream, Encoding > &ds)
GenericRegex(const Ch *source, Allocator *allocator=0)
GenericRegexSearch(const RegexType ®ex, Allocator *allocator=0)
Allocator * ownAllocator_
SizeType NewRange(unsigned codepoint)
bool ParseRange(DecodedStream< InputStream, Encoding > &ds, SizeType *range)
GenericRegex< UTF8<> > Regex
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
Stack< Allocator > state0_
GenericRegexSearch< Regex > RegexSearch
bool CharacterEscape(DecodedStream< InputStream, Encoding > &ds, unsigned *escapedCodepoint)
SizeType out
Equals to kInvalid for matching state.
SizeType out1
Equals to non-kInvalid for split.
const Range & GetRange(SizeType index) const
#define RAPIDJSON_NEW(TypeName)
! customization point for global new
bool EvalQuantifier(Stack< Allocator > &operandStack, unsigned n, unsigned m)
bool Match(InputStream &is)
static SizeType Min(SizeType a, SizeType b)
Range & GetRange(SizeType index)
Frag(SizeType s, SizeType o, SizeType m)
SizeType Append(SizeType l1, SizeType l2)
static const SizeType kRegexInvalidRange
SizeType NewState(SizeType out, SizeType out1, unsigned codepoint)
DecodedStream(SourceStream &ss)
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
void Swap(T &a, T &b) RAPIDJSON_NOEXCEPT
Custom swap() to avoid dependency on C++ <algorithm> header.
#define RAPIDJSON_DELETE(x)
! customization point for global delete
SizeType out
link-list of all output states
Stack< Allocator > state1_
void Patch(SizeType l, SizeType s)
A type-unsafe stack for storing different types of data.
bool Eval(Stack< Allocator > &operandStack, Operator op)
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
static const SizeType kRegexInvalidState
Represents an invalid index in GenericRegex::State::out, out1.
RegexType::EncodingType Encoding
bool ParseUnsigned(DecodedStream< InputStream, Encoding > &ds, unsigned *u)
Stack< Allocator > ranges_
State & GetState(SizeType index)
Regular expression engine with subset of ECMAscript grammar.
size_t GetStateSetSize() const
bool SearchWithAnchoring(InputStream &is, bool anchorBegin, bool anchorEnd)
Allocator * ownAllocator_
void ImplicitConcatenation(Stack< Allocator > &atomCountStack, Stack< Allocator > &operatorStack)
void PushOperand(Stack< Allocator > &operandStack, unsigned codepoint)
bool Search(InputStream &is)
#define RAPIDJSON_ASSERT(x)
Assertion.
const State & GetState(SizeType index) const
bool AddState(Stack< Allocator > &l, SizeType index)
void CloneTopOperand(Stack< Allocator > &operandStack)