regex.h
Go to the documentation of this file.
1 // Tencent is pleased to support the open source community by making RapidJSON available.
2 //
3 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 //
5 // Licensed under the MIT License (the "License"); you may not use this file except
6 // in compliance with the License. You may obtain a copy of the License at
7 //
8 // http://opensource.org/licenses/MIT
9 //
10 // Unless required by applicable law or agreed to in writing, software distributed
11 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 // specific language governing permissions and limitations under the License.
14 
15 #ifndef RAPIDJSON_INTERNAL_REGEX_H_
16 #define RAPIDJSON_INTERNAL_REGEX_H_
17 
18 #include "../allocators.h"
19 #include "../stream.h"
20 #include "stack.h"
21 
22 #ifdef __clang__
23 RAPIDJSON_DIAG_PUSH
24 RAPIDJSON_DIAG_OFF(padded)
25 RAPIDJSON_DIAG_OFF(switch-enum)
26 RAPIDJSON_DIAG_OFF(implicit-fallthrough)
27 #elif defined(_MSC_VER)
28 RAPIDJSON_DIAG_PUSH
29 RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
30 #endif
31 
32 #ifdef __GNUC__
33 RAPIDJSON_DIAG_PUSH
34 RAPIDJSON_DIAG_OFF(effc++)
35 #if __GNUC__ >= 7
36 RAPIDJSON_DIAG_OFF(implicit-fallthrough)
37 #endif
38 #endif
39 
40 #ifndef RAPIDJSON_REGEX_VERBOSE
41 #define RAPIDJSON_REGEX_VERBOSE 0
42 #endif
43 
45 namespace internal {
46 
47 ///////////////////////////////////////////////////////////////////////////////
48 // DecodedStream
49 
50 template <typename SourceStream, typename Encoding>
52 public:
53  DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
54  unsigned Peek() { return codepoint_; }
55  unsigned Take() {
56  unsigned c = codepoint_;
57  if (c) // No further decoding when '\0'
58  Decode();
59  return c;
60  }
61 
62 private:
63  void Decode() {
64  if (!Encoding::Decode(ss_, &codepoint_))
65  codepoint_ = 0;
66  }
67 
68  SourceStream& ss_;
69  unsigned codepoint_;
70 };
71 
72 ///////////////////////////////////////////////////////////////////////////////
73 // GenericRegex
74 
75 static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1
77 
78 template <typename Encoding, typename Allocator>
80 
81 //! Regular expression engine with subset of ECMAscript grammar.
82 /*!
83  Supported regular expression syntax:
84  - \c ab Concatenation
85  - \c a|b Alternation
86  - \c a? Zero or one
87  - \c a* Zero or more
88  - \c a+ One or more
89  - \c a{3} Exactly 3 times
90  - \c a{3,} At least 3 times
91  - \c a{3,5} 3 to 5 times
92  - \c (ab) Grouping
93  - \c ^a At the beginning
94  - \c a$ At the end
95  - \c . Any character
96  - \c [abc] Character classes
97  - \c [a-c] Character class range
98  - \c [a-z0-9_] Character class combination
99  - \c [^abc] Negated character classes
100  - \c [^a-c] Negated character class range
101  - \c [\b] Backspace (U+0008)
102  - \c \\| \\\\ ... Escape characters
103  - \c \\f Form feed (U+000C)
104  - \c \\n Line feed (U+000A)
105  - \c \\r Carriage return (U+000D)
106  - \c \\t Tab (U+0009)
107  - \c \\v Vertical tab (U+000B)
108 
109  \note This is a Thompson NFA engine, implemented with reference to
110  Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).",
111  https://swtch.com/~rsc/regexp/regexp1.html
112 */
113 template <typename Encoding, typename Allocator = CrtAllocator>
115 public:
116  typedef Encoding EncodingType;
117  typedef typename Encoding::Ch Ch;
118  template <typename, typename> friend class GenericRegexSearch;
119 
120  GenericRegex(const Ch* source, Allocator* allocator = 0) :
121  states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
122  anchorBegin_(), anchorEnd_()
123  {
126  Parse(ds);
127  }
128 
130 
131  bool IsValid() const {
132  return root_ != kRegexInvalidState;
133  }
134 
135 private:
136  enum Operator {
142  kLeftParenthesis
143  };
144 
145  static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.'
146  static const unsigned kRangeCharacterClass = 0xFFFFFFFE;
147  static const unsigned kRangeNegationFlag = 0x80000000;
148 
149  struct Range {
150  unsigned start; //
151  unsigned end;
153  };
154 
155  struct State {
156  SizeType out; //!< Equals to kInvalid for matching state
157  SizeType out1; //!< Equals to non-kInvalid for split
159  unsigned codepoint;
160  };
161 
162  struct Frag {
163  Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {}
165  SizeType out; //!< link-list of all output states
167  };
168 
170  RAPIDJSON_ASSERT(index < stateCount_);
171  return states_.template Bottom<State>()[index];
172  }
173 
174  const State& GetState(SizeType index) const {
175  RAPIDJSON_ASSERT(index < stateCount_);
176  return states_.template Bottom<State>()[index];
177  }
178 
180  RAPIDJSON_ASSERT(index < rangeCount_);
181  return ranges_.template Bottom<Range>()[index];
182  }
183 
184  const Range& GetRange(SizeType index) const {
185  RAPIDJSON_ASSERT(index < rangeCount_);
186  return ranges_.template Bottom<Range>()[index];
187  }
188 
189  template <typename InputStream>
191  Allocator allocator;
192  Stack<Allocator> operandStack(&allocator, 256); // Frag
193  Stack<Allocator> operatorStack(&allocator, 256); // Operator
194  Stack<Allocator> atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis)
195 
196  *atomCountStack.template Push<unsigned>() = 0;
197 
198  unsigned codepoint;
199  while (ds.Peek() != 0) {
200  switch (codepoint = ds.Take()) {
201  case '^':
202  anchorBegin_ = true;
203  break;
204 
205  case '$':
206  anchorEnd_ = true;
207  break;
208 
209  case '|':
210  while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() < kAlternation)
211  if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
212  return;
213  *operatorStack.template Push<Operator>() = kAlternation;
214  *atomCountStack.template Top<unsigned>() = 0;
215  break;
216 
217  case '(':
218  *operatorStack.template Push<Operator>() = kLeftParenthesis;
219  *atomCountStack.template Push<unsigned>() = 0;
220  break;
221 
222  case ')':
223  while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis)
224  if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
225  return;
226  if (operatorStack.Empty())
227  return;
228  operatorStack.template Pop<Operator>(1);
229  atomCountStack.template Pop<unsigned>(1);
230  ImplicitConcatenation(atomCountStack, operatorStack);
231  break;
232 
233  case '?':
234  if (!Eval(operandStack, kZeroOrOne))
235  return;
236  break;
237 
238  case '*':
239  if (!Eval(operandStack, kZeroOrMore))
240  return;
241  break;
242 
243  case '+':
244  if (!Eval(operandStack, kOneOrMore))
245  return;
246  break;
247 
248  case '{':
249  {
250  unsigned n, m;
251  if (!ParseUnsigned(ds, &n))
252  return;
253 
254  if (ds.Peek() == ',') {
255  ds.Take();
256  if (ds.Peek() == '}')
257  m = kInfinityQuantifier;
258  else if (!ParseUnsigned(ds, &m) || m < n)
259  return;
260  }
261  else
262  m = n;
263 
264  if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}')
265  return;
266  ds.Take();
267  }
268  break;
269 
270  case '.':
271  PushOperand(operandStack, kAnyCharacterClass);
272  ImplicitConcatenation(atomCountStack, operatorStack);
273  break;
274 
275  case '[':
276  {
277  SizeType range;
278  if (!ParseRange(ds, &range))
279  return;
280  SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass);
281  GetState(s).rangeStart = range;
282  *operandStack.template Push<Frag>() = Frag(s, s, s);
283  }
284  ImplicitConcatenation(atomCountStack, operatorStack);
285  break;
286 
287  case '\\': // Escape character
288  if (!CharacterEscape(ds, &codepoint))
289  return; // Unsupported escape character
290  // fall through to default
291 
292  default: // Pattern character
293  PushOperand(operandStack, codepoint);
294  ImplicitConcatenation(atomCountStack, operatorStack);
295  }
296  }
297 
298  while (!operatorStack.Empty())
299  if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
300  return;
301 
302  // Link the operand to matching state.
303  if (operandStack.GetSize() == sizeof(Frag)) {
304  Frag* e = operandStack.template Pop<Frag>(1);
305  Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0));
306  root_ = e->start;
307 
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);
313  }
314  printf("\n");
315 #endif
316  }
317  }
318 
319  SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {
320  State* s = states_.template Push<State>();
321  s->out = out;
322  s->out1 = out1;
323  s->codepoint = codepoint;
325  return stateCount_++;
326  }
327 
328  void PushOperand(Stack<Allocator>& operandStack, unsigned codepoint) {
329  SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);
330  *operandStack.template Push<Frag>() = Frag(s, s, s);
331  }
332 
333  void ImplicitConcatenation(Stack<Allocator>& atomCountStack, Stack<Allocator>& operatorStack) {
334  if (*atomCountStack.template Top<unsigned>())
335  *operatorStack.template Push<Operator>() = kConcatenation;
336  (*atomCountStack.template Top<unsigned>())++;
337  }
338 
340  SizeType old = l1;
341  while (GetState(l1).out != kRegexInvalidState)
342  l1 = GetState(l1).out;
343  GetState(l1).out = l2;
344  return old;
345  }
346 
348  for (SizeType next; l != kRegexInvalidState; l = next) {
349  next = GetState(l).out;
350  GetState(l).out = s;
351  }
352  }
353 
354  bool Eval(Stack<Allocator>& operandStack, Operator op) {
355  switch (op) {
356  case kConcatenation:
357  RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2);
358  {
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));
363  }
364  return true;
365 
366  case kAlternation:
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));
372  return true;
373  }
374  return false;
375 
376  case kZeroOrOne:
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);
381  return true;
382  }
383  return false;
384 
385  case kZeroOrMore:
386  if (operandStack.GetSize() >= sizeof(Frag)) {
387  Frag e = *operandStack.template Pop<Frag>(1);
388  SizeType s = NewState(kRegexInvalidState, e.start, 0);
389  Patch(e.out, s);
390  *operandStack.template Push<Frag>() = Frag(s, s, e.minIndex);
391  return true;
392  }
393  return false;
394 
395  default:
396  RAPIDJSON_ASSERT(op == kOneOrMore);
397  if (operandStack.GetSize() >= sizeof(Frag)) {
398  Frag e = *operandStack.template Pop<Frag>(1);
399  SizeType s = NewState(kRegexInvalidState, e.start, 0);
400  Patch(e.out, s);
401  *operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex);
402  return true;
403  }
404  return false;
405  }
406  }
407 
408  bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) {
409  RAPIDJSON_ASSERT(n <= m);
410  RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag));
411 
412  if (n == 0) {
413  if (m == 0) // a{0} not support
414  return false;
415  else if (m == kInfinityQuantifier)
416  Eval(operandStack, kZeroOrMore); // a{0,} -> a*
417  else {
418  Eval(operandStack, kZeroOrOne); // a{0,5} -> a?
419  for (unsigned i = 0; i < m - 1; i++)
420  CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a?
421  for (unsigned i = 0; i < m - 1; i++)
422  Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a?
423  }
424  return true;
425  }
426 
427  for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a
428  CloneTopOperand(operandStack);
429 
430  if (m == kInfinityQuantifier)
431  Eval(operandStack, kOneOrMore); // a{3,} -> a a a+
432  else if (m > n) {
433  CloneTopOperand(operandStack); // a{3,5} -> a a a a
434  Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a?
435  for (unsigned i = n; i < m - 1; i++)
436  CloneTopOperand(operandStack); // a{3,5} -> a a a a? a?
437  for (unsigned i = n; i < m; i++)
438  Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a?
439  }
440 
441  for (unsigned i = 0; i < n - 1; i++)
442  Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a?
443 
444  return true;
445  }
446 
447  static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; }
448 
449  void CloneTopOperand(Stack<Allocator>& operandStack) {
450  const Frag src = *operandStack.template Top<Frag>(); // Copy constructor to prevent invalidation
451  SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_)
452  State* s = states_.template Push<State>(count);
453  memcpy(s, &GetState(src.minIndex), count * sizeof(State));
454  for (SizeType j = 0; j < count; j++) {
455  if (s[j].out != kRegexInvalidState)
456  s[j].out += count;
457  if (s[j].out1 != kRegexInvalidState)
458  s[j].out1 += count;
459  }
460  *operandStack.template Push<Frag>() = Frag(src.start + count, src.out + count, src.minIndex + count);
461  stateCount_ += count;
462  }
463 
464  template <typename InputStream>
466  unsigned r = 0;
467  if (ds.Peek() < '0' || ds.Peek() > '9')
468  return false;
469  while (ds.Peek() >= '0' && ds.Peek() <= '9') {
470  if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295
471  return false; // overflow
472  r = r * 10 + (ds.Take() - '0');
473  }
474  *u = r;
475  return true;
476  }
477 
478  template <typename InputStream>
480  bool isBegin = true;
481  bool negate = false;
482  int step = 0;
485  unsigned codepoint;
486  while ((codepoint = ds.Take()) != 0) {
487  if (isBegin) {
488  isBegin = false;
489  if (codepoint == '^') {
490  negate = true;
491  continue;
492  }
493  }
494 
495  switch (codepoint) {
496  case ']':
497  if (start == kRegexInvalidRange)
498  return false; // Error: nothing inside []
499  if (step == 2) { // Add trailing '-'
500  SizeType r = NewRange('-');
501  RAPIDJSON_ASSERT(current != kRegexInvalidRange);
502  GetRange(current).next = r;
503  }
504  if (negate)
505  GetRange(start).start |= kRangeNegationFlag;
506  *range = start;
507  return true;
508 
509  case '\\':
510  if (ds.Peek() == 'b') {
511  ds.Take();
512  codepoint = 0x0008; // Escape backspace character
513  }
514  else if (!CharacterEscape(ds, &codepoint))
515  return false;
516  // fall through to default
517 
518  default:
519  switch (step) {
520  case 1:
521  if (codepoint == '-') {
522  step++;
523  break;
524  }
525  // fall through to step 0 for other characters
526 
527  case 0:
528  {
529  SizeType r = NewRange(codepoint);
530  if (current != kRegexInvalidRange)
531  GetRange(current).next = r;
532  if (start == kRegexInvalidRange)
533  start = r;
534  current = r;
535  }
536  step = 1;
537  break;
538 
539  default:
540  RAPIDJSON_ASSERT(step == 2);
541  GetRange(current).end = codepoint;
542  step = 0;
543  }
544  }
545  }
546  return false;
547  }
548 
549  SizeType NewRange(unsigned codepoint) {
550  Range* r = ranges_.template Push<Range>();
551  r->start = r->end = codepoint;
553  return rangeCount_++;
554  }
555 
556  template <typename InputStream>
557  bool CharacterEscape(DecodedStream<InputStream, Encoding>& ds, unsigned* escapedCodepoint) {
558  unsigned codepoint;
559  switch (codepoint = ds.Take()) {
560  case '^':
561  case '$':
562  case '|':
563  case '(':
564  case ')':
565  case '?':
566  case '*':
567  case '+':
568  case '.':
569  case '[':
570  case ']':
571  case '{':
572  case '}':
573  case '\\':
574  *escapedCodepoint = codepoint; return true;
575  case 'f': *escapedCodepoint = 0x000C; return true;
576  case 'n': *escapedCodepoint = 0x000A; return true;
577  case 'r': *escapedCodepoint = 0x000D; return true;
578  case 't': *escapedCodepoint = 0x0009; return true;
579  case 'v': *escapedCodepoint = 0x000B; return true;
580  default:
581  return false; // Unsupported escape character
582  }
583  }
584 
590 
591  static const unsigned kInfinityQuantifier = ~0u;
592 
593  // For SearchWithAnchoring()
596 };
597 
598 template <typename RegexType, typename Allocator = CrtAllocator>
599 class GenericRegexSearch {
600 public:
601  typedef typename RegexType::EncodingType Encoding;
602  typedef typename Encoding::Ch Ch;
603 
604  GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) :
605  regex_(regex), allocator_(allocator), ownAllocator_(0),
606  state0_(allocator, 0), state1_(allocator, 0), stateSet_()
607  {
608  RAPIDJSON_ASSERT(regex_.IsValid());
609  if (!allocator_)
610  ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
611  stateSet_ = static_cast<unsigned*>(allocator_->Malloc(GetStateSetSize()));
612  state0_.template Reserve<SizeType>(regex_.stateCount_);
613  state1_.template Reserve<SizeType>(regex_.stateCount_);
614  }
615 
617  Allocator::Free(stateSet_);
618  RAPIDJSON_DELETE(ownAllocator_);
619  }
620 
621  template <typename InputStream>
622  bool Match(InputStream& is) {
623  return SearchWithAnchoring(is, true, true);
624  }
625 
626  bool Match(const Ch* s) {
628  return Match(is);
629  }
630 
631  template <typename InputStream>
632  bool Search(InputStream& is) {
633  return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_);
634  }
635 
636  bool Search(const Ch* s) {
638  return Search(is);
639  }
640 
641 private:
642  typedef typename RegexType::State State;
643  typedef typename RegexType::Range Range;
644 
645  template <typename InputStream>
646  bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) {
648 
649  state0_.Clear();
650  Stack<Allocator> *current = &state0_, *next = &state1_;
651  const size_t stateSetSize = GetStateSetSize();
652  std::memset(stateSet_, 0, stateSetSize);
653 
654  bool matched = AddState(*current, regex_.root_);
655  unsigned codepoint;
656  while (!current->Empty() && (codepoint = ds.Take()) != 0) {
657  std::memset(stateSet_, 0, stateSetSize);
658  next->Clear();
659  matched = false;
660  for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {
661  const State& sr = regex_.GetState(*s);
662  if (sr.codepoint == codepoint ||
663  sr.codepoint == RegexType::kAnyCharacterClass ||
664  (sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
665  {
666  matched = AddState(*next, sr.out) || matched;
667  if (!anchorEnd && matched)
668  return true;
669  }
670  if (!anchorBegin)
671  AddState(*next, regex_.root_);
672  }
673  internal::Swap(current, next);
674  }
675 
676  return matched;
677  }
678 
679  size_t GetStateSetSize() const {
680  return (regex_.stateCount_ + 31) / 32 * 4;
681  }
682 
683  // Return whether the added states is a match state
685  RAPIDJSON_ASSERT(index != kRegexInvalidState);
686 
687  const State& s = regex_.GetState(index);
688  if (s.out1 != kRegexInvalidState) { // Split
689  bool matched = AddState(l, s.out);
690  return AddState(l, s.out1) || matched;
691  }
692  else if (!(stateSet_[index >> 5] & (1u << (index & 31)))) {
693  stateSet_[index >> 5] |= (1u << (index & 31));
694  *l.template PushUnsafe<SizeType>() = index;
695  }
696  return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation.
697  }
698 
699  bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {
700  bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0;
701  while (rangeIndex != kRegexInvalidRange) {
702  const Range& r = regex_.GetRange(rangeIndex);
703  if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end)
704  return yes;
705  rangeIndex = r.next;
706  }
707  return !yes;
708  }
709 
710  const RegexType& regex_;
711  Allocator* allocator_;
712  Allocator* ownAllocator_;
716 };
717 
720 
721 } // namespace internal
723 
724 #ifdef __GNUC__
725 RAPIDJSON_DIAG_POP
726 #endif
727 
728 #if defined(__clang__) || defined(_MSC_VER)
729 RAPIDJSON_DIAG_POP
730 #endif
731 
732 #endif // RAPIDJSON_INTERNAL_REGEX_H_
SizeType stateCount_
Definition: regex.h:588
unsigned Take()
Definition: regex.h:55
Allocator * ownAllocator_
Definition: regex.h:712
bool Eval(Stack< Allocator > &operandStack, Operator op)
Definition: regex.h:354
SizeType NewRange(unsigned codepoint)
Definition: regex.h:549
const Range & GetRange(SizeType index) const
Definition: regex.h:184
const CharType(& source)[N]
Definition: pointer.h:1147
const State & GetState(SizeType index) const
Definition: regex.h:174
RAPIDJSON_NAMESPACE_BEGIN typedef unsigned SizeType
Size type (for string lengths, array sizes, etc.)
Definition: rapidjson.h:384
SizeType out
link-list of all output states
Definition: regex.h:165
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition: rapidjson.h:406
unsigned codepoint_
Definition: regex.h:69
Class representing operators that can appear in template expressions.
Definition: template.cpp:428
Read-only string stream.
Definition: fwd.h:47
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
Definition: rapidjson.h:124
GenericRegexSearch< Regex > RegexSearch
Definition: regex.h:719
Stack< Allocator > state0_
Definition: regex.h:713
Stack< Allocator > ranges_
Definition: regex.h:586
SizeType out1
Equals to non-kInvalid for split.
Definition: regex.h:157
A type-unsafe stack for storing different types of data.
Definition: stack.h:36
bool IsValid() const
Definition: regex.h:131
const RegexType & regex_
Definition: regex.h:710
bool Empty() const
Definition: stack.h:176
Regular expression engine with subset of ECMAscript grammar.
Definition: regex.h:114
bool AddState(Stack< Allocator > &l, SizeType index)
Definition: regex.h:684
GenericRegex< UTF8<> > Regex
Definition: regex.h:718
static QStrList * l
Definition: config.cpp:1044
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
Definition: rapidjson.h:121
Allocator * allocator_
Definition: regex.h:711
#define Search
Definition: pyscanner.cpp:1849
void CloneTopOperand(Stack< Allocator > &operandStack)
Definition: regex.h:449
SizeType out
Equals to kInvalid for matching state.
Definition: regex.h:156
#define RAPIDJSON_NEW(TypeName)
! customization point for global new
Definition: rapidjson.h:601
RegexType::State State
Definition: regex.h:642
const double e
SourceStream & ss_
Definition: regex.h:68
SizeType NewState(SizeType out, SizeType out1, unsigned codepoint)
Definition: regex.h:319
void PushOperand(Stack< Allocator > &operandStack, unsigned codepoint)
Definition: regex.h:328
unsigned int uint32_t
Definition: stdint.h:126
SizeType rangeCount_
Definition: regex.h:589
bool SearchWithAnchoring(InputStream &is, bool anchorBegin, bool anchorEnd)
Definition: regex.h:646
int start
Definition: doxysearch.cpp:178
std::void_t< T > n
DecodedStream(SourceStream &ss)
Definition: regex.h:53
GenericRegexSearch(const RegexType &regex, Allocator *allocator=0)
Definition: regex.h:604
static Entry * current
Encoding EncodingType
Definition: regex.h:116
size_t GetStateSetSize() const
Definition: regex.h:679
static const SizeType kRegexInvalidState
Represents an invalid index in GenericRegex::State::out, out1.
Definition: regex.h:75
Stack< Allocator > state1_
Definition: regex.h:714
size_t GetSize() const
Definition: stack.h:177
void Swap(T &a, T &b) RAPIDJSON_NOEXCEPT
Custom swap() to avoid dependency on C++ <algorithm> header.
Definition: swap.h:33
#define RAPIDJSON_DELETE(x)
! customization point for global delete
Definition: rapidjson.h:605
void Parse(DecodedStream< InputStream, Encoding > &ds)
Definition: regex.h:190
void GetRange(const PFPStruct &pfp, unsigned short sfIndex, unsigned short &fromPt, unsigned short &npts)
Definition: PFPUtils.cxx:1389
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition: pointer.h:1124
switch(yytype)
Definition: ce_parse.cpp:1127
bool ParseRange(DecodedStream< InputStream, Encoding > &ds, SizeType *range)
Definition: regex.h:479
bool Search(InputStream &is)
Definition: regex.h:632
static SizeType Min(SizeType a, SizeType b)
Definition: regex.h:447
State & GetState(SizeType index)
Definition: regex.h:169
Frag(SizeType s, SizeType o, SizeType m)
Definition: regex.h:163
bool MatchRange(SizeType rangeIndex, unsigned codepoint) const
Definition: regex.h:699
bool EvalQuantifier(Stack< Allocator > &operandStack, unsigned n, unsigned m)
Definition: regex.h:408
bool Match(InputStream &is)
Definition: regex.h:622
bool Search(const Ch *s)
Definition: regex.h:636
Encoding::Ch Ch
Definition: regex.h:117
static bool * b
Definition: config.cpp:1043
RegexType::Range Range
Definition: regex.h:643
void Patch(SizeType l, SizeType s)
Definition: regex.h:347
bool ParseUnsigned(DecodedStream< InputStream, Encoding > &ds, unsigned *u)
Definition: regex.h:465
RegexType::EncodingType Encoding
Definition: regex.h:601
SizeType Append(SizeType l1, SizeType l2)
Definition: regex.h:339
int end
Definition: doxysearch.cpp:179
bool Match(const Ch *s)
Definition: regex.h:626
Range & GetRange(SizeType index)
Definition: regex.h:179
bool CharacterEscape(DecodedStream< InputStream, Encoding > &ds, unsigned *escapedCodepoint)
Definition: regex.h:557
static const double sr
Definition: Units.h:166
void ImplicitConcatenation(Stack< Allocator > &atomCountStack, Stack< Allocator > &operatorStack)
Definition: regex.h:333
static QCString * s
Definition: config.cpp:1042
static const SizeType kRegexInvalidRange
Definition: regex.h:76
unsigned Peek()
Definition: regex.h:54
Stack< Allocator > states_
Definition: regex.h:585
GenericRegex(const Ch *source, Allocator *allocator=0)
Definition: regex.h:120