source: NonGTP/Boost/boost/regex/v4/perl_matcher_non_recursive.hpp @ 857

Revision 857, 43.4 KB checked in by igarcia, 18 years ago (diff)
Line 
1/*
2 *
3 * Copyright (c) 2002
4 * John Maddock
5 *
6 * Use, modification and distribution are subject to the
7 * Boost Software License, Version 1.0. (See accompanying file
8 * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 *
10 */
11
12 /*
13  *   LOCATION:    see http://www.boost.org for most recent version.
14  *   FILE         perl_matcher_common.cpp
15  *   VERSION      see <boost/version.hpp>
16  *   DESCRIPTION: Definitions of perl_matcher member functions that are
17  *                specific to the non-recursive implementation.
18  */
19
20#ifndef BOOST_REGEX_V4_PERL_MATCHER_NON_RECURSIVE_HPP
21#define BOOST_REGEX_V4_PERL_MATCHER_NON_RECURSIVE_HPP
22
23#include <new>
24
25#ifdef BOOST_HAS_ABI_HEADERS
26#  include BOOST_ABI_PREFIX
27#endif
28
29namespace boost{
30namespace re_detail{
31
32template <class T>
33inline void inplace_destroy(T* p)
34{
35   (void)p;  // warning suppression
36   p->~T();
37}
38
39struct saved_state
40{
41   union{
42      unsigned int id;
43      // this padding ensures correct alignment on 64-bit platforms:
44      std::size_t padding1;
45      std::ptrdiff_t padding2;
46      void* padding3;
47   };
48   saved_state(unsigned i) : id(i) {}
49};
50
51template <class BidiIterator>
52struct saved_matched_paren : public saved_state
53{
54   int index;
55   sub_match<BidiIterator> sub;
56   saved_matched_paren(int i, const sub_match<BidiIterator>& s) : saved_state(1), index(i), sub(s){};
57};
58
59template <class BidiIterator>
60struct saved_position : public saved_state
61{
62   const re_syntax_base* pstate;
63   BidiIterator position;
64   saved_position(const re_syntax_base* ps, BidiIterator pos, int i) : saved_state(i), pstate(ps), position(pos){};
65};
66
67template <class BidiIterator>
68struct saved_assertion : public saved_position<BidiIterator>
69{
70   bool positive;
71   saved_assertion(bool p, const re_syntax_base* ps, BidiIterator pos)
72      : saved_position<BidiIterator>(ps, pos, saved_type_assertion), positive(p){};
73};
74
75template <class BidiIterator>
76struct saved_repeater : public saved_state
77{
78   repeater_count<BidiIterator> count;
79   saved_repeater(int i, repeater_count<BidiIterator>** s, BidiIterator start)
80      : saved_state(saved_state_repeater_count), count(i,s,start){}
81};
82
83struct saved_extra_block : public saved_state
84{
85   saved_state *base, *end;
86   saved_extra_block(saved_state* b, saved_state* e)
87      : saved_state(saved_state_extra_block), base(b), end(e) {}
88};
89
90struct save_state_init
91{
92   saved_state** stack;
93   save_state_init(saved_state** base, saved_state** end)
94      : stack(base)
95   {
96      *base = static_cast<saved_state*>(get_mem_block());
97      *end = reinterpret_cast<saved_state*>(reinterpret_cast<char*>(*base)+BOOST_REGEX_BLOCKSIZE);
98      --(*end);
99      (void) new (*end)saved_state(0);
100      BOOST_ASSERT(*end > *base);
101   }
102   ~save_state_init()
103   {
104      put_mem_block(*stack);
105      *stack = 0;
106   }
107};
108
109template <class BidiIterator>
110struct saved_single_repeat : public saved_state
111{
112   std::size_t count;
113   const re_repeat* rep;
114   BidiIterator last_position;
115   saved_single_repeat(std::size_t c, const re_repeat* r, BidiIterator lp, int arg_id)
116      : saved_state(arg_id), count(c), rep(r), last_position(lp){}
117};
118
119template <class BidiIterator, class Allocator, class traits>
120bool perl_matcher<BidiIterator, Allocator, traits>::match_all_states()
121{
122   static matcher_proc_type const s_match_vtable[29] =
123   {
124      (&perl_matcher<BidiIterator, Allocator, traits>::match_startmark),
125      &perl_matcher<BidiIterator, Allocator, traits>::match_endmark,
126      &perl_matcher<BidiIterator, Allocator, traits>::match_literal,
127      &perl_matcher<BidiIterator, Allocator, traits>::match_start_line,
128      &perl_matcher<BidiIterator, Allocator, traits>::match_end_line,
129      &perl_matcher<BidiIterator, Allocator, traits>::match_wild,
130      &perl_matcher<BidiIterator, Allocator, traits>::match_match,
131      &perl_matcher<BidiIterator, Allocator, traits>::match_word_boundary,
132      &perl_matcher<BidiIterator, Allocator, traits>::match_within_word,
133      &perl_matcher<BidiIterator, Allocator, traits>::match_word_start,
134      &perl_matcher<BidiIterator, Allocator, traits>::match_word_end,
135      &perl_matcher<BidiIterator, Allocator, traits>::match_buffer_start,
136      &perl_matcher<BidiIterator, Allocator, traits>::match_buffer_end,
137      &perl_matcher<BidiIterator, Allocator, traits>::match_backref,
138      &perl_matcher<BidiIterator, Allocator, traits>::match_long_set,
139      &perl_matcher<BidiIterator, Allocator, traits>::match_set,
140      &perl_matcher<BidiIterator, Allocator, traits>::match_jump,
141      &perl_matcher<BidiIterator, Allocator, traits>::match_alt,
142      &perl_matcher<BidiIterator, Allocator, traits>::match_rep,
143      &perl_matcher<BidiIterator, Allocator, traits>::match_combining,
144      &perl_matcher<BidiIterator, Allocator, traits>::match_soft_buffer_end,
145      &perl_matcher<BidiIterator, Allocator, traits>::match_restart_continue,
146      (::boost::is_random_access_iterator<BidiIterator>::value ? &perl_matcher<BidiIterator, Allocator, traits>::match_dot_repeat_fast : &perl_matcher<BidiIterator, Allocator, traits>::match_dot_repeat_slow),
147      &perl_matcher<BidiIterator, Allocator, traits>::match_char_repeat,
148      &perl_matcher<BidiIterator, Allocator, traits>::match_set_repeat,
149      &perl_matcher<BidiIterator, Allocator, traits>::match_long_set_repeat,
150      &perl_matcher<BidiIterator, Allocator, traits>::match_backstep,
151      &perl_matcher<BidiIterator, Allocator, traits>::match_assert_backref,
152      &perl_matcher<BidiIterator, Allocator, traits>::match_toggle_case,
153   };
154
155   push_recursion_stopper();
156   do{
157      while(pstate)
158      {
159         matcher_proc_type proc = s_match_vtable[pstate->type];
160         ++state_count;
161         if(!(this->*proc)())
162         {
163            if(state_count > max_state_count)
164               raise_error(traits_inst, regex_constants::error_space);
165            if((m_match_flags & match_partial) && (position == last) && (position != search_base))
166               m_has_partial_match = true;
167            bool successful_unwind = unwind(false);
168            if((m_match_flags & match_partial) && (position == last) && (position != search_base))
169               m_has_partial_match = true;
170            if(false == successful_unwind)
171               return m_recursive_result;
172         }
173      }
174   }while(unwind(true));
175   return m_recursive_result;
176}
177
178template <class BidiIterator, class Allocator, class traits>
179void perl_matcher<BidiIterator, Allocator, traits>::extend_stack()
180{
181   if(used_block_count)
182   {
183      --used_block_count;
184      saved_state* stack_base;
185      saved_state* backup_state;
186      stack_base = static_cast<saved_state*>(get_mem_block());
187      backup_state = reinterpret_cast<saved_state*>(reinterpret_cast<char*>(stack_base)+BOOST_REGEX_BLOCKSIZE);
188      saved_extra_block* block = static_cast<saved_extra_block*>(backup_state);
189      --block;
190      (void) new (block) saved_extra_block(m_stack_base, m_backup_state);
191      m_stack_base = stack_base;
192      m_backup_state = block;
193   }
194   else
195      raise_error(traits_inst, regex_constants::error_size);
196}
197
198template <class BidiIterator, class Allocator, class traits>
199inline void perl_matcher<BidiIterator, Allocator, traits>::push_matched_paren(int index, const sub_match<BidiIterator>& sub)
200{
201   BOOST_ASSERT(index);
202   saved_matched_paren<BidiIterator>* pmp = static_cast<saved_matched_paren<BidiIterator>*>(m_backup_state);
203   --pmp;
204   if(pmp < m_stack_base)
205   {
206      extend_stack();
207      pmp = static_cast<saved_matched_paren<BidiIterator>*>(m_backup_state);
208      --pmp;
209   }
210   (void) new (pmp)saved_matched_paren<BidiIterator>(index, sub);
211   m_backup_state = pmp;
212}
213
214template <class BidiIterator, class Allocator, class traits>
215inline void perl_matcher<BidiIterator, Allocator, traits>::push_recursion_stopper()
216{
217   saved_state* pmp = m_backup_state;
218   --pmp;
219   if(pmp < m_stack_base)
220   {
221      extend_stack();
222      pmp = m_backup_state;
223      --pmp;
224   }
225   (void) new (pmp)saved_state(saved_type_recurse);
226   m_backup_state = pmp;
227}
228
229template <class BidiIterator, class Allocator, class traits>
230inline void perl_matcher<BidiIterator, Allocator, traits>::push_assertion(const re_syntax_base* ps, bool positive)
231{
232   saved_assertion<BidiIterator>* pmp = static_cast<saved_assertion<BidiIterator>*>(m_backup_state);
233   --pmp;
234   if(pmp < m_stack_base)
235   {
236      extend_stack();
237      pmp = static_cast<saved_assertion<BidiIterator>*>(m_backup_state);
238      --pmp;
239   }
240   (void) new (pmp)saved_assertion<BidiIterator>(positive, ps, position);
241   m_backup_state = pmp;
242}
243
244template <class BidiIterator, class Allocator, class traits>
245inline void perl_matcher<BidiIterator, Allocator, traits>::push_alt(const re_syntax_base* ps)
246{
247   saved_position<BidiIterator>* pmp = static_cast<saved_position<BidiIterator>*>(m_backup_state);
248   --pmp;
249   if(pmp < m_stack_base)
250   {
251      extend_stack();
252      pmp = static_cast<saved_position<BidiIterator>*>(m_backup_state);
253      --pmp;
254   }
255   (void) new (pmp)saved_position<BidiIterator>(ps, position, saved_state_alt);
256   m_backup_state = pmp;
257}
258
259template <class BidiIterator, class Allocator, class traits>
260inline void perl_matcher<BidiIterator, Allocator, traits>::push_non_greedy_repeat(const re_syntax_base* ps)
261{
262   saved_position<BidiIterator>* pmp = static_cast<saved_position<BidiIterator>*>(m_backup_state);
263   --pmp;
264   if(pmp < m_stack_base)
265   {
266      extend_stack();
267      pmp = static_cast<saved_position<BidiIterator>*>(m_backup_state);
268      --pmp;
269   }
270   (void) new (pmp)saved_position<BidiIterator>(ps, position, saved_state_non_greedy_long_repeat);
271   m_backup_state = pmp;
272}
273
274template <class BidiIterator, class Allocator, class traits>
275inline void perl_matcher<BidiIterator, Allocator, traits>::push_repeater_count(int i, repeater_count<BidiIterator>** s)
276{
277   saved_repeater<BidiIterator>* pmp = static_cast<saved_repeater<BidiIterator>*>(m_backup_state);
278   --pmp;
279   if(pmp < m_stack_base)
280   {
281      extend_stack();
282      pmp = static_cast<saved_repeater<BidiIterator>*>(m_backup_state);
283      --pmp;
284   }
285   (void) new (pmp)saved_repeater<BidiIterator>(i, s, position);
286   m_backup_state = pmp;
287}
288
289template <class BidiIterator, class Allocator, class traits>
290inline void perl_matcher<BidiIterator, Allocator, traits>::push_single_repeat(std::size_t c, const re_repeat* r, BidiIterator last_position, int id)
291{
292   saved_single_repeat<BidiIterator>* pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
293   --pmp;
294   if(pmp < m_stack_base)
295   {
296      extend_stack();
297      pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
298      --pmp;
299   }
300   (void) new (pmp)saved_single_repeat<BidiIterator>(c, r, last_position, id);
301   m_backup_state = pmp;
302}
303
304template <class BidiIterator, class Allocator, class traits>
305bool perl_matcher<BidiIterator, Allocator, traits>::match_startmark()
306{
307   int index = static_cast<const re_brace*>(pstate)->index;
308   switch(index)
309   {
310   case 0:
311      pstate = pstate->next.p;
312      break;
313   case -1:
314   case -2:
315      {
316         // forward lookahead assert:
317         const re_syntax_base* next_pstate = static_cast<const re_jump*>(pstate->next.p)->alt.p->next.p;
318         pstate = pstate->next.p->next.p;
319         push_assertion(next_pstate, index == -1);
320         break;
321      }
322   case -3:
323      {
324         // independent sub-expression, currently this is always recursive:
325         bool old_independent = m_independent;
326         m_independent = true;
327         const re_syntax_base* next_pstate = static_cast<const re_jump*>(pstate->next.p)->alt.p->next.p;
328         pstate = pstate->next.p->next.p;
329         bool r = match_all_states();
330         pstate = next_pstate;
331         m_independent = old_independent;
332#ifdef BOOST_REGEX_MATCH_EXTRA
333         if(r && (m_match_flags & match_extra))
334         {
335            //
336            // our captures have been stored in *m_presult
337            // we need to unpack them, and insert them
338            // back in the right order when we unwind the stack:
339            //
340            match_results<BidiIterator, Allocator> temp_match(*m_presult);
341            unsigned i;
342            for(i = 0; i < temp_match.size(); ++i)
343               (*m_presult)[i].get_captures().clear();
344            // match everything else:
345            r = match_all_states();
346            // now place the stored captures back:
347            for(i = 0; i < temp_match.size(); ++i)
348            {
349               typedef typename sub_match<BidiIterator>::capture_sequence_type seq;
350               seq& s1 = (*m_presult)[i].get_captures();
351               const seq& s2 = temp_match[i].captures();
352               s1.insert(
353                  s1.end(),
354                  s2.begin(),
355                  s2.end());
356            }
357         }
358#endif
359         return r;
360      }
361   case -4:
362      {
363      // conditional expression:
364      const re_alt* alt = static_cast<const re_alt*>(pstate->next.p);
365      BOOST_ASSERT(alt->type == syntax_element_alt);
366      pstate = alt->next.p;
367      if(pstate->type == syntax_element_assert_backref)
368      {
369         if(!match_assert_backref())
370            pstate = alt->alt.p;
371         break;
372      }
373      else
374      {
375         // zero width assertion, have to match this recursively:
376         BOOST_ASSERT(pstate->type == syntax_element_startmark);
377         bool negated = static_cast<const re_brace*>(pstate)->index == -2;
378         BidiIterator saved_position = position;
379         const re_syntax_base* next_pstate = static_cast<const re_jump*>(pstate->next.p)->alt.p->next.p;
380         pstate = pstate->next.p->next.p;
381         bool r = match_all_states();
382         position = saved_position;
383         if(negated)
384            r = !r;
385         if(r)
386            pstate = next_pstate;
387         else
388            pstate = alt->alt.p;
389         break;
390      }
391      }
392   default:
393   {
394      BOOST_ASSERT(index > 0);
395      if((m_match_flags & match_nosubs) == 0)
396      {
397         push_matched_paren(index, (*m_presult)[index]);
398         m_presult->set_first(position, index);
399      }
400      pstate = pstate->next.p;
401      break;
402   }
403   }
404   return true;
405}
406
407template <class BidiIterator, class Allocator, class traits>
408bool perl_matcher<BidiIterator, Allocator, traits>::match_alt()
409{
410   bool take_first, take_second;
411   const re_alt* jmp = static_cast<const re_alt*>(pstate);
412
413   // find out which of these two alternatives we need to take:
414   if(position == last)
415   {
416      take_first = jmp->can_be_null & mask_take;
417      take_second = jmp->can_be_null & mask_skip;
418   }
419   else
420   {
421      take_first = can_start(*position, jmp->_map, (unsigned char)mask_take);
422      take_second = can_start(*position, jmp->_map, (unsigned char)mask_skip);
423  }
424
425   if(take_first)
426   {
427      // we can take the first alternative,
428      // see if we need to push next alternative:
429      if(take_second)
430      {
431         push_alt(jmp->alt.p);
432      }
433      pstate = pstate->next.p;
434      return true;
435   }
436   if(take_second)
437   {
438      pstate = jmp->alt.p;
439      return true;
440   }
441   return false;  // neither option is possible
442}
443
444template <class BidiIterator, class Allocator, class traits>
445bool perl_matcher<BidiIterator, Allocator, traits>::match_rep()
446{
447#ifdef BOOST_MSVC
448#pragma warning(push)
449#pragma warning(disable:4127 4244)
450#endif
451#ifdef __BORLANDC__
452#pragma option push -w-8008 -w-8066 -w-8004
453#endif
454   const re_repeat* rep = static_cast<const re_repeat*>(pstate);
455
456   // find out which of these two alternatives we need to take:
457   bool take_first, take_second;
458   if(position == last)
459   {
460      take_first = rep->can_be_null & mask_take;
461      take_second = rep->can_be_null & mask_skip;
462   }
463   else
464   {
465      take_first = can_start(*position, rep->_map, (unsigned char)mask_take);
466      take_second = can_start(*position, rep->_map, (unsigned char)mask_skip);
467   }
468
469   if(take_first || (next_count->get_id() != rep->id))
470   {
471      // we're moving to a different repeat from the last
472      // one, so set up a counter object:
473      push_repeater_count(rep->id, &next_count);
474   }
475   //
476   // If we've had at least one repeat already, and the last one
477   // matched the NULL string then set the repeat count to
478   // maximum:
479   //
480   next_count->check_null_repeat(position, rep->max);
481
482   if(next_count->get_count() < rep->min)
483   {
484      // we must take the repeat:
485      if(take_first)
486      {
487         // increase the counter:
488         ++(*next_count);
489         pstate = rep->next.p;
490         return true;
491      }
492      return false;
493   }
494
495   bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent);   
496   if(greedy)
497   {
498      // try and take the repeat if we can:
499      if((next_count->get_count() < rep->max) && take_first)
500      {
501         if(take_second)
502         {
503            // store position in case we fail:
504            push_alt(rep->alt.p);
505         }
506         // increase the counter:
507         ++(*next_count);
508         pstate = rep->next.p;
509         return true;
510      }
511      else if(take_second)
512      {
513         pstate = rep->alt.p;
514         return true;
515      }
516      return false; // can't take anything, fail...
517   }
518   else // non-greedy
519   {
520      // try and skip the repeat if we can:
521      if(take_second)
522      {
523         if((next_count->get_count() < rep->max) && take_first)
524         {
525            // store position in case we fail:
526            push_non_greedy_repeat(rep->next.p);
527         }
528         pstate = rep->alt.p;
529         return true;
530      }
531      if((next_count->get_count() < rep->max) && take_first)
532      {
533         // increase the counter:
534         ++(*next_count);
535         pstate = rep->next.p;
536         return true;
537      }
538   }
539   return false;
540#ifdef __BORLANDC__
541#pragma option pop
542#endif
543#ifdef BOOST_MSVC
544#pragma warning(pop)
545#endif
546}
547
548template <class BidiIterator, class Allocator, class traits>
549bool perl_matcher<BidiIterator, Allocator, traits>::match_dot_repeat_slow()
550{
551   unsigned count = 0;
552   const re_repeat* rep = static_cast<const re_repeat*>(pstate);
553   re_syntax_base* psingle = rep->next.p;
554   // match compulsary repeats first:
555   while(count < rep->min)
556   {
557      pstate = psingle;
558      if(!match_wild())
559         return false;
560      ++count;
561   }
562   bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent);   
563   if(greedy)
564   {
565      // repeat for as long as we can:
566      while(count < rep->max)
567      {
568         pstate = psingle;
569         if(!match_wild())
570            break;
571         ++count;
572      }
573      // remember where we got to if this is a leading repeat:
574      if((rep->leading) && (count < rep->max))
575         restart = position;
576      // push backtrack info if available:
577      if(count - rep->min)
578         push_single_repeat(count, rep, position, saved_state_greedy_single_repeat);
579      // jump to next state:
580      pstate = rep->alt.p;
581      return true;
582   }
583   else
584   {
585      // non-greedy, push state and return true if we can skip:
586      if(count < rep->max)
587         push_single_repeat(count, rep, position, saved_state_rep_slow_dot);
588      pstate = rep->alt.p;
589      return (position == last) ? (rep->can_be_null & mask_skip) : can_start(*position, rep->_map, mask_skip);
590   }
591}
592
593template <class BidiIterator, class Allocator, class traits>
594bool perl_matcher<BidiIterator, Allocator, traits>::match_dot_repeat_fast()
595{
596   if(m_match_flags & match_not_dot_null)
597      return match_dot_repeat_slow();
598   if((static_cast<const re_dot*>(pstate->next.p)->mask & match_any_mask) == 0)
599      return match_dot_repeat_slow();
600
601   const re_repeat* rep = static_cast<const re_repeat*>(pstate);
602   bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent);   
603   unsigned count = static_cast<unsigned>((std::min)(static_cast<unsigned>(::boost::re_detail::distance(position, last)), static_cast<unsigned>(greedy ? rep->max : rep->min)));
604   if(rep->min > count)
605   {
606      position = last;
607      return false;  // not enough text left to match
608   }
609   std::advance(position, count);
610
611   if(greedy)
612   {
613      if((rep->leading) && (count < rep->max))
614         restart = position;
615      // push backtrack info if available:
616      if(count - rep->min)
617         push_single_repeat(count, rep, position, saved_state_greedy_single_repeat);
618      // jump to next state:
619      pstate = rep->alt.p;
620      return true;
621   }
622   else
623   {
624      // non-greedy, push state and return true if we can skip:
625      if(count < rep->max)
626         push_single_repeat(count, rep, position, saved_state_rep_fast_dot);
627      pstate = rep->alt.p;
628      return (position == last) ? (rep->can_be_null & mask_skip) : can_start(*position, rep->_map, mask_skip);
629   }
630}
631
632template <class BidiIterator, class Allocator, class traits>
633bool perl_matcher<BidiIterator, Allocator, traits>::match_char_repeat()
634{
635#ifdef BOOST_MSVC
636#pragma warning(push)
637#pragma warning(disable:4127)
638#endif
639#ifdef __BORLANDC__
640#pragma option push -w-8008 -w-8066 -w-8004
641#endif
642   const re_repeat* rep = static_cast<const re_repeat*>(pstate);
643   BOOST_ASSERT(1 == static_cast<const re_literal*>(rep->next.p)->length);
644   const char_type what = *reinterpret_cast<const char_type*>(static_cast<const re_literal*>(rep->next.p) + 1);
645   std::size_t count = 0;
646   //
647   // start by working out how much we can skip:
648   //
649   bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent);   
650   std::size_t desired = greedy ? rep->max : rep->min;
651   if(::boost::is_random_access_iterator<BidiIterator>::value)
652   {
653      BidiIterator end = position;
654      std::advance(end, (std::min)((std::size_t)::boost::re_detail::distance(position, last), desired));
655      BidiIterator origin(position);
656      while((position != end) && (traits_inst.translate(*position, icase) == what))
657      {
658         ++position;
659      }
660      count = (unsigned)::boost::re_detail::distance(origin, position);
661   }
662   else
663   {
664      while((count < desired) && (position != last) && (traits_inst.translate(*position, icase) == what))
665      {
666         ++position;
667         ++count;
668      }
669   }
670
671   if(count < rep->min)
672      return false;
673
674   if(greedy)
675   {
676      if((rep->leading) && (count < rep->max))
677         restart = position;
678      // push backtrack info if available:
679      if(count - rep->min)
680         push_single_repeat(count, rep, position, saved_state_greedy_single_repeat);
681      // jump to next state:
682      pstate = rep->alt.p;
683      return true;
684   }
685   else
686   {
687      // non-greedy, push state and return true if we can skip:
688      if(count < rep->max)
689         push_single_repeat(count, rep, position, saved_state_rep_char);
690      pstate = rep->alt.p;
691      return (position == last) ? (rep->can_be_null & mask_skip) : can_start(*position, rep->_map, mask_skip);
692   }
693#ifdef __BORLANDC__
694#pragma option pop
695#endif
696#ifdef BOOST_MSVC
697#pragma warning(pop)
698#endif
699}
700
701template <class BidiIterator, class Allocator, class traits>
702bool perl_matcher<BidiIterator, Allocator, traits>::match_set_repeat()
703{
704#ifdef BOOST_MSVC
705#pragma warning(push)
706#pragma warning(disable:4127)
707#endif
708#ifdef __BORLANDC__
709#pragma option push -w-8008 -w-8066 -w-8004
710#endif
711   const re_repeat* rep = static_cast<const re_repeat*>(pstate);
712   const unsigned char* map = static_cast<const re_set*>(rep->next.p)->_map;
713   std::size_t count = 0;
714   //
715   // start by working out how much we can skip:
716   //
717   bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent);   
718   std::size_t desired = greedy ? rep->max : rep->min;
719   if(::boost::is_random_access_iterator<BidiIterator>::value)
720   {
721      BidiIterator end = position;
722      std::advance(end, (std::min)((std::size_t)::boost::re_detail::distance(position, last), desired));
723      BidiIterator origin(position);
724      while((position != end) && map[static_cast<unsigned char>(traits_inst.translate(*position, icase))])
725      {
726         ++position;
727      }
728      count = (unsigned)::boost::re_detail::distance(origin, position);
729   }
730   else
731   {
732      while((count < desired) && (position != last) && map[static_cast<unsigned char>(traits_inst.translate(*position, icase))])
733      {
734         ++position;
735         ++count;
736      }
737   }
738
739   if(count < rep->min)
740      return false;
741
742   if(greedy)
743   {
744      if((rep->leading) && (count < rep->max))
745         restart = position;
746      // push backtrack info if available:
747      if(count - rep->min)
748         push_single_repeat(count, rep, position, saved_state_greedy_single_repeat);
749      // jump to next state:
750      pstate = rep->alt.p;
751      return true;
752   }
753   else
754   {
755      // non-greedy, push state and return true if we can skip:
756      if(count < rep->max)
757         push_single_repeat(count, rep, position, saved_state_rep_short_set);
758      pstate = rep->alt.p;
759      return (position == last) ? (rep->can_be_null & mask_skip) : can_start(*position, rep->_map, mask_skip);
760   }
761#ifdef __BORLANDC__
762#pragma option pop
763#endif
764#ifdef BOOST_MSVC
765#pragma warning(pop)
766#endif
767}
768
769template <class BidiIterator, class Allocator, class traits>
770bool perl_matcher<BidiIterator, Allocator, traits>::match_long_set_repeat()
771{
772#ifdef BOOST_MSVC
773#pragma warning(push)
774#pragma warning(disable:4127)
775#endif
776#ifdef __BORLANDC__
777#pragma option push -w-8008 -w-8066 -w-8004
778#endif
779   typedef typename traits::char_class_type mask_type;
780   const re_repeat* rep = static_cast<const re_repeat*>(pstate);
781   const re_set_long<mask_type>* set = static_cast<const re_set_long<mask_type>*>(pstate->next.p);
782   std::size_t count = 0;
783   //
784   // start by working out how much we can skip:
785   //
786   bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent);   
787   std::size_t desired = greedy ? rep->max : rep->min;
788   if(::boost::is_random_access_iterator<BidiIterator>::value)
789   {
790      BidiIterator end = position;
791      std::advance(end, (std::min)((std::size_t)::boost::re_detail::distance(position, last), desired));
792      BidiIterator origin(position);
793      while((position != end) && (position != re_is_set_member(position, last, set, re.get_data(), icase)))
794      {
795         ++position;
796      }
797      count = (unsigned)::boost::re_detail::distance(origin, position);
798   }
799   else
800   {
801      while((count < desired) && (position != last) && (position != re_is_set_member(position, last, set, re.get_data(), icase)))
802      {
803         ++position;
804         ++count;
805      }
806   }
807
808   if(count < rep->min)
809      return false;
810
811   if(greedy)
812   {
813      if((rep->leading) && (count < rep->max))
814         restart = position;
815      // push backtrack info if available:
816      if(count - rep->min)
817         push_single_repeat(count, rep, position, saved_state_greedy_single_repeat);
818      // jump to next state:
819      pstate = rep->alt.p;
820      return true;
821   }
822   else
823   {
824      // non-greedy, push state and return true if we can skip:
825      if(count < rep->max)
826         push_single_repeat(count, rep, position, saved_state_rep_long_set);
827      pstate = rep->alt.p;
828      return (position == last) ? (rep->can_be_null & mask_skip) : can_start(*position, rep->_map, mask_skip);
829   }
830#ifdef __BORLANDC__
831#pragma option pop
832#endif
833#ifdef BOOST_MSVC
834#pragma warning(pop)
835#endif
836}
837
838/****************************************************************************
839
840Unwind and associated proceedures follow, these perform what normal stack
841unwinding does in the recursive implementation.
842
843****************************************************************************/
844
845template <class BidiIterator, class Allocator, class traits>
846bool perl_matcher<BidiIterator, Allocator, traits>::unwind(bool have_match)
847{
848   static unwind_proc_type const s_unwind_table[14] =
849   {
850      &perl_matcher<BidiIterator, Allocator, traits>::unwind_end,
851      &perl_matcher<BidiIterator, Allocator, traits>::unwind_paren,
852      &perl_matcher<BidiIterator, Allocator, traits>::unwind_recursion_stopper,
853      &perl_matcher<BidiIterator, Allocator, traits>::unwind_assertion,
854      &perl_matcher<BidiIterator, Allocator, traits>::unwind_alt,
855      &perl_matcher<BidiIterator, Allocator, traits>::unwind_repeater_counter,
856      &perl_matcher<BidiIterator, Allocator, traits>::unwind_extra_block,
857      &perl_matcher<BidiIterator, Allocator, traits>::unwind_greedy_single_repeat,
858      &perl_matcher<BidiIterator, Allocator, traits>::unwind_slow_dot_repeat,
859      &perl_matcher<BidiIterator, Allocator, traits>::unwind_fast_dot_repeat,
860      &perl_matcher<BidiIterator, Allocator, traits>::unwind_char_repeat,
861      &perl_matcher<BidiIterator, Allocator, traits>::unwind_short_set_repeat,
862      &perl_matcher<BidiIterator, Allocator, traits>::unwind_long_set_repeat,
863      &perl_matcher<BidiIterator, Allocator, traits>::unwind_non_greedy_repeat,
864   };
865
866   m_recursive_result = have_match;
867   unwind_proc_type unwinder;
868   bool cont;
869   //
870   // keep unwinding our stack until we have something to do:
871   //
872   do
873   {
874      unwinder = s_unwind_table[m_backup_state->id];
875      cont = (this->*unwinder)(m_recursive_result);
876   }while(cont);
877   //
878   // return true if we have more states to try:
879   //
880   return pstate ? true : false;
881}
882
883template <class BidiIterator, class Allocator, class traits>
884bool perl_matcher<BidiIterator, Allocator, traits>::unwind_end(bool)
885{
886   pstate = 0;   // nothing left to search
887   return false; // end of stack nothing more to search
888}
889
890template <class BidiIterator, class Allocator, class traits>
891bool perl_matcher<BidiIterator, Allocator, traits>::unwind_paren(bool have_match)
892{
893   saved_matched_paren<BidiIterator>* pmp = static_cast<saved_matched_paren<BidiIterator>*>(m_backup_state);
894   // restore previous values if no match was found:
895   if(have_match == false)
896   {
897      m_presult->set_first(pmp->sub.first, pmp->index);
898      m_presult->set_second(pmp->sub.second, pmp->index, pmp->sub.matched);
899   }
900#ifdef BOOST_REGEX_MATCH_EXTRA
901   //
902   // we have a match, push the capture information onto the stack:
903   //
904   else if(pmp->sub.matched && (match_extra & m_match_flags))
905      ((*m_presult)[pmp->index]).get_captures().push_back(pmp->sub);
906#endif
907   // unwind stack:
908   m_backup_state = pmp+1;
909   boost::re_detail::inplace_destroy(pmp);
910   return true; // keep looking
911}
912
913template <class BidiIterator, class Allocator, class traits>
914bool perl_matcher<BidiIterator, Allocator, traits>::unwind_recursion_stopper(bool)
915{
916   boost::re_detail::inplace_destroy(m_backup_state++);
917   pstate = 0;   // nothing left to search
918   return false; // end of stack nothing more to search
919}
920
921template <class BidiIterator, class Allocator, class traits>
922bool perl_matcher<BidiIterator, Allocator, traits>::unwind_assertion(bool r)
923{
924   saved_assertion<BidiIterator>* pmp = static_cast<saved_assertion<BidiIterator>*>(m_backup_state);
925   pstate = pmp->pstate;
926   position = pmp->position;
927   bool result = (r == pmp->positive);
928   m_recursive_result = pmp->positive ? r : !r;
929   boost::re_detail::inplace_destroy(pmp++);
930   m_backup_state = pmp;
931   return !result; // return false if the assertion was matched to stop search.
932}
933
934template <class BidiIterator, class Allocator, class traits>
935bool perl_matcher<BidiIterator, Allocator, traits>::unwind_alt(bool r)
936{
937   saved_position<BidiIterator>* pmp = static_cast<saved_position<BidiIterator>*>(m_backup_state);
938   if(!r)
939   {
940      pstate = pmp->pstate;
941      position = pmp->position;
942   }
943   boost::re_detail::inplace_destroy(pmp++);
944   m_backup_state = pmp;
945   return r;
946}
947
948template <class BidiIterator, class Allocator, class traits>
949bool perl_matcher<BidiIterator, Allocator, traits>::unwind_repeater_counter(bool)
950{
951   saved_repeater<BidiIterator>* pmp = static_cast<saved_repeater<BidiIterator>*>(m_backup_state);
952   boost::re_detail::inplace_destroy(pmp++);
953   m_backup_state = pmp;
954   return true; // keep looking
955}
956
957template <class BidiIterator, class Allocator, class traits>
958bool perl_matcher<BidiIterator, Allocator, traits>::unwind_extra_block(bool)
959{
960   saved_extra_block* pmp = static_cast<saved_extra_block*>(m_backup_state);
961   void* condemmed = m_stack_base;
962   m_stack_base = pmp->base;
963   m_backup_state = pmp->end;
964   boost::re_detail::inplace_destroy(pmp);
965   put_mem_block(condemmed);
966   return true; // keep looking
967}
968
969template <class BidiIterator, class Allocator, class traits>
970inline void perl_matcher<BidiIterator, Allocator, traits>::destroy_single_repeat()
971{
972   saved_single_repeat<BidiIterator>* p = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
973   boost::re_detail::inplace_destroy(p++);
974   m_backup_state = p;
975}
976
977template <class BidiIterator, class Allocator, class traits>
978bool perl_matcher<BidiIterator, Allocator, traits>::unwind_greedy_single_repeat(bool r)
979{
980   saved_single_repeat<BidiIterator>* pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
981
982   // if we have a match, just discard this state:
983   if(r)
984   {
985      destroy_single_repeat();
986      return true;
987   }
988
989   const re_repeat* rep = pmp->rep;
990   std::size_t count = pmp->count;
991   BOOST_ASSERT(rep->next.p != 0);
992   BOOST_ASSERT(rep->alt.p != 0);
993
994   count -= rep->min;
995   
996   if((m_match_flags & match_partial) && (position == last))
997      m_has_partial_match = true;
998
999   BOOST_ASSERT(count);
1000   position = pmp->last_position;
1001
1002   // backtrack till we can skip out:
1003   do
1004   {
1005      --position;
1006      --count;
1007      ++state_count;
1008   }while(count && !can_start(*position, rep->_map, mask_skip));
1009
1010   // if we've hit base, destroy this state:
1011   if(count == 0)
1012   {
1013         destroy_single_repeat();
1014         if(!can_start(*position, rep->_map, mask_skip))
1015            return true;
1016   }
1017   else
1018   {
1019      pmp->count = count + rep->min;
1020      pmp->last_position = position;
1021   }
1022   pstate = rep->alt.p;
1023   return false;
1024}
1025
1026template <class BidiIterator, class Allocator, class traits>
1027bool perl_matcher<BidiIterator, Allocator, traits>::unwind_slow_dot_repeat(bool r)
1028{
1029   saved_single_repeat<BidiIterator>* pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
1030
1031   // if we have a match, just discard this state:
1032   if(r)
1033   {
1034      destroy_single_repeat();
1035      return true;
1036   }
1037
1038   const re_repeat* rep = pmp->rep;
1039   std::size_t count = pmp->count;
1040   BOOST_ASSERT(rep->type == syntax_element_dot_rep);
1041   BOOST_ASSERT(rep->next.p != 0);
1042   BOOST_ASSERT(rep->alt.p != 0);
1043   BOOST_ASSERT(rep->next.p->type == syntax_element_wild);
1044
1045   BOOST_ASSERT(count < rep->max);
1046   pstate = rep->next.p;
1047   position = pmp->last_position;
1048
1049   if(position != last)
1050   {
1051      // wind forward until we can skip out of the repeat:
1052      do
1053      {
1054         if(!match_wild())
1055         {
1056            // failed repeat match, discard this state and look for another:
1057            destroy_single_repeat();
1058            return true;
1059         }
1060         ++count;
1061         ++state_count;
1062         pstate = rep->next.p;
1063      }while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip));
1064   }   
1065   if(position == last)
1066   {
1067      // can't repeat any more, remove the pushed state:
1068      destroy_single_repeat();
1069      if(0 == (rep->can_be_null & mask_skip))
1070         return true;
1071   }
1072   else if(count == rep->max)
1073   {
1074      // can't repeat any more, remove the pushed state:
1075      destroy_single_repeat();
1076      if(!can_start(*position, rep->_map, mask_skip))
1077         return true;
1078   }
1079   else
1080   {
1081      pmp->count = count;
1082      pmp->last_position = position;
1083   }
1084   pstate = rep->alt.p;
1085   return false;
1086}
1087
1088template <class BidiIterator, class Allocator, class traits>
1089bool perl_matcher<BidiIterator, Allocator, traits>::unwind_fast_dot_repeat(bool r)
1090{
1091   saved_single_repeat<BidiIterator>* pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
1092
1093   // if we have a match, just discard this state:
1094   if(r)
1095   {
1096      destroy_single_repeat();
1097      return true;
1098   }
1099
1100   const re_repeat* rep = pmp->rep;
1101   std::size_t count = pmp->count;
1102
1103   BOOST_ASSERT(count < rep->max);
1104   position = pmp->last_position;
1105   if(position != last)
1106   {
1107
1108      // wind forward until we can skip out of the repeat:
1109      do
1110      {
1111         ++position;
1112         ++count;
1113         ++state_count;
1114      }while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip));
1115   }
1116
1117   if(position == last)
1118   {
1119      // can't repeat any more, remove the pushed state:
1120      destroy_single_repeat();
1121      if(0 == (rep->can_be_null & mask_skip))
1122         return true;
1123   }
1124   else if(count == rep->max)
1125   {
1126      // can't repeat any more, remove the pushed state:
1127      destroy_single_repeat();
1128      if(!can_start(*position, rep->_map, mask_skip))
1129         return true;
1130   }
1131   else
1132   {
1133      pmp->count = count;
1134      pmp->last_position = position;
1135   }
1136   pstate = rep->alt.p;
1137   return false;
1138}
1139
1140template <class BidiIterator, class Allocator, class traits>
1141bool perl_matcher<BidiIterator, Allocator, traits>::unwind_char_repeat(bool r)
1142{
1143   saved_single_repeat<BidiIterator>* pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
1144
1145   // if we have a match, just discard this state:
1146   if(r)
1147   {
1148      destroy_single_repeat();
1149      return true;
1150   }
1151
1152   const re_repeat* rep = pmp->rep;
1153   std::size_t count = pmp->count;
1154   pstate = rep->next.p;
1155   const char_type what = *reinterpret_cast<const char_type*>(static_cast<const re_literal*>(pstate) + 1);
1156   position = pmp->last_position;
1157
1158   BOOST_ASSERT(rep->type == syntax_element_char_rep);
1159   BOOST_ASSERT(rep->next.p != 0);
1160   BOOST_ASSERT(rep->alt.p != 0);
1161   BOOST_ASSERT(rep->next.p->type == syntax_element_literal);
1162   BOOST_ASSERT(count < rep->max);
1163
1164   if(position != last)
1165   {
1166      // wind forward until we can skip out of the repeat:
1167      do
1168      {
1169         if(traits_inst.translate(*position, icase) != what)
1170         {
1171            // failed repeat match, discard this state and look for another:
1172            destroy_single_repeat();
1173            return true;
1174         }
1175         ++count;
1176         ++ position;
1177         ++state_count;
1178         pstate = rep->next.p;
1179      }while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip));
1180   }   
1181   if(position == last)
1182   {
1183      // can't repeat any more, remove the pushed state:
1184      destroy_single_repeat();
1185      if(0 == (rep->can_be_null & mask_skip))
1186         return true;
1187   }
1188   else if(count == rep->max)
1189   {
1190      // can't repeat any more, remove the pushed state:
1191      destroy_single_repeat();
1192      if(!can_start(*position, rep->_map, mask_skip))
1193         return true;
1194   }
1195   else
1196   {
1197      pmp->count = count;
1198      pmp->last_position = position;
1199   }
1200   pstate = rep->alt.p;
1201   return false;
1202}
1203
1204template <class BidiIterator, class Allocator, class traits>
1205bool perl_matcher<BidiIterator, Allocator, traits>::unwind_short_set_repeat(bool r)
1206{
1207   saved_single_repeat<BidiIterator>* pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
1208
1209   // if we have a match, just discard this state:
1210   if(r)
1211   {
1212      destroy_single_repeat();
1213      return true;
1214   }
1215
1216   const re_repeat* rep = pmp->rep;
1217   std::size_t count = pmp->count;
1218   pstate = rep->next.p;
1219   const unsigned char* map = static_cast<const re_set*>(rep->next.p)->_map;
1220   position = pmp->last_position;
1221
1222   BOOST_ASSERT(rep->type == syntax_element_short_set_rep);
1223   BOOST_ASSERT(rep->next.p != 0);
1224   BOOST_ASSERT(rep->alt.p != 0);
1225   BOOST_ASSERT(rep->next.p->type == syntax_element_set);
1226   BOOST_ASSERT(count < rep->max);
1227   
1228   if(position != last)
1229   {
1230      // wind forward until we can skip out of the repeat:
1231      do
1232      {
1233         if(!map[static_cast<unsigned char>(traits_inst.translate(*position, icase))])
1234         {
1235            // failed repeat match, discard this state and look for another:
1236            destroy_single_repeat();
1237            return true;
1238         }
1239         ++count;
1240         ++ position;
1241         ++state_count;
1242         pstate = rep->next.p;
1243      }while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip));
1244   }   
1245   if(position == last)
1246   {
1247      // can't repeat any more, remove the pushed state:
1248      destroy_single_repeat();
1249      if(0 == (rep->can_be_null & mask_skip))
1250         return true;
1251   }
1252   else if(count == rep->max)
1253   {
1254      // can't repeat any more, remove the pushed state:
1255      destroy_single_repeat();
1256      if(!can_start(*position, rep->_map, mask_skip))
1257         return true;
1258   }
1259   else
1260   {
1261      pmp->count = count;
1262      pmp->last_position = position;
1263   }
1264   pstate = rep->alt.p;
1265   return false;
1266}
1267
1268template <class BidiIterator, class Allocator, class traits>
1269bool perl_matcher<BidiIterator, Allocator, traits>::unwind_long_set_repeat(bool r)
1270{
1271   typedef typename traits::char_class_type mask_type;
1272   saved_single_repeat<BidiIterator>* pmp = static_cast<saved_single_repeat<BidiIterator>*>(m_backup_state);
1273
1274   // if we have a match, just discard this state:
1275   if(r)
1276   {
1277      destroy_single_repeat();
1278      return true;
1279   }
1280
1281   const re_repeat* rep = pmp->rep;
1282   std::size_t count = pmp->count;
1283   pstate = rep->next.p;
1284   const re_set_long<mask_type>* set = static_cast<const re_set_long<mask_type>*>(pstate);
1285   position = pmp->last_position;
1286
1287   BOOST_ASSERT(rep->type == syntax_element_long_set_rep);
1288   BOOST_ASSERT(rep->next.p != 0);
1289   BOOST_ASSERT(rep->alt.p != 0);
1290   BOOST_ASSERT(rep->next.p->type == syntax_element_long_set);
1291   BOOST_ASSERT(count < rep->max);
1292
1293   if(position != last)
1294   {
1295      // wind forward until we can skip out of the repeat:
1296      do
1297      {
1298         if(position == re_is_set_member(position, last, set, re.get_data(), icase))
1299         {
1300            // failed repeat match, discard this state and look for another:
1301            destroy_single_repeat();
1302            return true;
1303         }
1304         ++position;
1305         ++count;
1306         ++state_count;
1307         pstate = rep->next.p;
1308      }while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip));
1309   }   
1310   if(position == last)
1311   {
1312      // can't repeat any more, remove the pushed state:
1313      destroy_single_repeat();
1314      if(0 == (rep->can_be_null & mask_skip))
1315         return true;
1316   }
1317   else if(count == rep->max)
1318   {
1319      // can't repeat any more, remove the pushed state:
1320      destroy_single_repeat();
1321      if(!can_start(*position, rep->_map, mask_skip))
1322         return true;
1323   }
1324   else
1325   {
1326      pmp->count = count;
1327      pmp->last_position = position;
1328   }
1329   pstate = rep->alt.p;
1330   return false;
1331}
1332
1333template <class BidiIterator, class Allocator, class traits>
1334bool perl_matcher<BidiIterator, Allocator, traits>::unwind_non_greedy_repeat(bool r)
1335{
1336   saved_position<BidiIterator>* pmp = static_cast<saved_position<BidiIterator>*>(m_backup_state);
1337   if(!r)
1338   {
1339      position = pmp->position;
1340      pstate = pmp->pstate;
1341      ++(*next_count);
1342   }
1343   boost::re_detail::inplace_destroy(pmp++);
1344   m_backup_state = pmp;
1345   return r;
1346}
1347
1348} // namespace re_detail
1349} // namespace boost
1350
1351#ifdef BOOST_HAS_ABI_HEADERS
1352#  include BOOST_ABI_SUFFIX
1353#endif
1354
1355#endif
1356
1357
Note: See TracBrowser for help on using the repository browser.