regex_compiler.h 16.7 KB
Newer Older
1 2
// class template regex -*- C++ -*-

3
// Copyright (C) 2010-2017 Free Software Foundation, Inc.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.

/**
26 27 28
 *  @file bits/regex_compiler.h
 *  This is an internal header file, included by other library headers.
 *  Do not attempt to use it directly. @headername{regex}
29 30
 */

31 32
namespace std _GLIBCXX_VISIBILITY(default)
{
33 34 35 36 37 38 39 40 41
_GLIBCXX_BEGIN_NAMESPACE_VERSION
_GLIBCXX_BEGIN_NAMESPACE_CXX11

  template<typename>
    class regex_traits;

_GLIBCXX_END_NAMESPACE_CXX11
_GLIBCXX_END_NAMESPACE_VERSION

42
namespace __detail
43
{
44 45
_GLIBCXX_BEGIN_NAMESPACE_VERSION

46 47 48 49 50
  /**
   * @addtogroup regex-detail
   * @{
   */

51
  template<typename, bool, bool>
52
    struct _BracketMatcher;
53

Tim Shen committed
54
  /**
55
   * @brief Builds an NFA from an input iterator range.
Tim Shen committed
56 57 58
   *
   * The %_TraitsT type should fulfill requirements [28.3].
   */
59
  template<typename _TraitsT>
60 61 62
    class _Compiler
    {
    public:
63 64
      typedef typename _TraitsT::char_type        _CharT;
      typedef const _CharT*                       _IterT;
65
      typedef _NFA<_TraitsT>              	  _RegexT;
66
      typedef regex_constants::syntax_option_type _FlagT;
67

68
      _Compiler(_IterT __b, _IterT __e,
69
		const typename _TraitsT::locale_type& __traits, _FlagT __flags);
70

71
      shared_ptr<const _RegexT>
72
      _M_get_nfa()
73
      { return std::move(_M_nfa); }
74 75

    private:
76 77 78 79 80 81
      typedef _Scanner<_CharT>               _ScannerT;
      typedef typename _TraitsT::string_type _StringT;
      typedef typename _ScannerT::_TokenT    _TokenT;
      typedef _StateSeq<_TraitsT>            _StateSeqT;
      typedef std::stack<_StateSeqT>         _StackT;
      typedef std::ctype<_CharT>             _CtypeT;
82 83 84

      // accepts a specific token or returns false.
      bool
85
      _M_match_token(_TokenT __token);
86 87 88 89

      void
      _M_disjunction();

Tim Shen committed
90
      void
91 92 93 94 95 96 97 98
      _M_alternative();

      bool
      _M_term();

      bool
      _M_assertion();

99
      bool
100 101 102 103 104 105 106 107
      _M_quantifier();

      bool
      _M_atom();

      bool
      _M_bracket_expression();

108 109 110
      template<bool __icase, bool __collate>
	void
	_M_insert_any_matcher_ecma();
111

112 113 114
      template<bool __icase, bool __collate>
	void
	_M_insert_any_matcher_posix();
115

116 117 118
      template<bool __icase, bool __collate>
	void
	_M_insert_char_matcher();
119

120 121 122
      template<bool __icase, bool __collate>
	void
	_M_insert_character_class_matcher();
123

124 125 126 127
      template<bool __icase, bool __collate>
	void
	_M_insert_bracket_matcher(bool __neg);

128 129
      // Returns true if successfully matched one term and should continue.
      // Returns false if the compiler should move on.
130
      template<bool __icase, bool __collate>
131
	bool
132 133
	_M_expression_term(pair<bool, _CharT>& __last_char,
			   _BracketMatcher<_TraitsT, __icase, __collate>&
134
			   __matcher);
135 136 137 138

      int
      _M_cur_int_value(int __radix);

139 140 141
      bool
      _M_try_char();

142 143 144 145 146 147 148
      _StateSeqT
      _M_pop()
      {
	auto ret = _M_stack.top();
	_M_stack.pop();
	return ret;
      }
149

150 151 152 153 154 155 156
      _FlagT              _M_flags;
      _ScannerT           _M_scanner;
      shared_ptr<_RegexT> _M_nfa;
      _StringT            _M_value;
      _StackT             _M_stack;
      const _TraitsT&     _M_traits;
      const _CtypeT&      _M_ctype;
157 158
    };

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
  template<typename _Tp>
    struct __has_contiguous_iter : std::false_type { };

  template<typename _Ch, typename _Tr, typename _Alloc>
    struct __has_contiguous_iter<std::basic_string<_Ch, _Tr, _Alloc>>
    : std::true_type
    { };

  template<typename _Tp, typename _Alloc>
    struct __has_contiguous_iter<std::vector<_Tp, _Alloc>>
    : std::true_type
    { };

  template<typename _Tp>
    struct __is_contiguous_normal_iter : std::false_type { };

  template<typename _CharT>
    struct __is_contiguous_normal_iter<_CharT*> : std::true_type { };

  template<typename _Tp, typename _Cont>
    struct
    __is_contiguous_normal_iter<__gnu_cxx::__normal_iterator<_Tp, _Cont>>
    : __has_contiguous_iter<_Cont>::type
    { };

  template<typename _Iter, typename _TraitsT>
    using __enable_if_contiguous_normal_iter
      = typename enable_if< __is_contiguous_normal_iter<_Iter>::value,
                           std::shared_ptr<const _NFA<_TraitsT>> >::type;

  template<typename _Iter, typename _TraitsT>
    using __disable_if_contiguous_normal_iter
      = typename enable_if< !__is_contiguous_normal_iter<_Iter>::value,
                           std::shared_ptr<const _NFA<_TraitsT>> >::type;

  template<typename _FwdIter, typename _TraitsT>
    inline __enable_if_contiguous_normal_iter<_FwdIter, _TraitsT>
    __compile_nfa(_FwdIter __first, _FwdIter __last,
197
		  const typename _TraitsT::locale_type& __loc,
198 199
		  regex_constants::syntax_option_type __flags)
    {
200 201
      size_t __len = __last - __first;
      const auto* __cfirst = __len ? std::__addressof(*__first) : nullptr;
202
      using _Cmplr = _Compiler<_TraitsT>;
203 204 205 206 207 208 209 210 211 212 213 214
      return _Cmplr(__cfirst, __cfirst + __len, __loc, __flags)._M_get_nfa();
    }

  template<typename _FwdIter, typename _TraitsT>
    inline __disable_if_contiguous_normal_iter<_FwdIter, _TraitsT>
    __compile_nfa(_FwdIter __first, _FwdIter __last,
		  const typename _TraitsT::locale_type& __loc,
		  regex_constants::syntax_option_type __flags)
    {
      basic_string<typename _TraitsT::char_type> __str(__first, __last);
      return __compile_nfa(__str.data(), __str.data() + __str.size(), __loc,
          __flags);
215 216
    }

217 218
  // [28.13.14]
  template<typename _TraitsT, bool __icase, bool __collate>
219
    class _RegexTranslatorBase
220
    {
221 222 223
    public:
      typedef typename _TraitsT::char_type	      _CharT;
      typedef typename _TraitsT::string_type	      _StringT;
224
      typedef _StringT _StrTransT;
225 226

      explicit
227
      _RegexTranslatorBase(const _TraitsT& __traits)
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
      : _M_traits(__traits)
      { }

      _CharT
      _M_translate(_CharT __ch) const
      {
	if (__icase)
	  return _M_traits.translate_nocase(__ch);
	else if (__collate)
	  return _M_traits.translate(__ch);
	else
	  return __ch;
      }

      _StrTransT
      _M_transform(_CharT __ch) const
      {
245 246
	_StrTransT __str(1, __ch);
	return _M_traits.transform(__str.begin(), __str.end());
247 248
      }

249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
      // See LWG 523. It's not efficiently implementable when _TraitsT is not
      // std::regex_traits<>, and __collate is true. See specializations for
      // implementations of other cases.
      bool
      _M_match_range(const _StrTransT& __first, const _StrTransT& __last,
		     const _StrTransT& __s) const
      { return __first <= __s && __s <= __last; }

    protected:
      bool _M_in_range_icase(_CharT __first, _CharT __last, _CharT __ch) const
      {
	typedef std::ctype<_CharT> __ctype_type;
	const auto& __fctyp = use_facet<__ctype_type>(this->_M_traits.getloc());
	auto __lower = __fctyp.tolower(__ch);
	auto __upper = __fctyp.toupper(__ch);
	return (__first <= __lower && __lower <= __last)
	  || (__first <= __upper && __upper <= __last);
      }

      const _TraitsT& _M_traits;
    };

  template<typename _TraitsT, bool __icase, bool __collate>
    class _RegexTranslator
    : public _RegexTranslatorBase<_TraitsT, __icase, __collate>
    {
    public:
      typedef _RegexTranslatorBase<_TraitsT, __icase, __collate> _Base;
      using _Base::_Base;
    };

  template<typename _TraitsT, bool __icase>
    class _RegexTranslator<_TraitsT, __icase, false>
    : public _RegexTranslatorBase<_TraitsT, __icase, false>
    {
    public:
      typedef _RegexTranslatorBase<_TraitsT, __icase, false> _Base;
      typedef typename _Base::_CharT _CharT;
      typedef _CharT _StrTransT;

      using _Base::_Base;

291
      _StrTransT
292
      _M_transform(_CharT __ch) const
293 294
      { return __ch; }

295 296
      bool
      _M_match_range(_CharT __first, _CharT __last, _CharT __ch) const
297
      {
298 299 300
	if (!__icase)
	  return __first <= __ch && __ch <= __last;
	return this->_M_in_range_icase(__first, __last, __ch);
301
      }
302
    };
303

304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
  template<typename _CharType>
    class _RegexTranslator<std::regex_traits<_CharType>, true, true>
    : public _RegexTranslatorBase<std::regex_traits<_CharType>, true, true>
    {
    public:
      typedef _RegexTranslatorBase<std::regex_traits<_CharType>, true, true>
	_Base;
      typedef typename _Base::_CharT _CharT;
      typedef typename _Base::_StrTransT _StrTransT;

      using _Base::_Base;

      bool
      _M_match_range(const _StrTransT& __first, const _StrTransT& __last,
		     const _StrTransT& __str) const
      {
	__glibcxx_assert(__first.size() == 1);
	__glibcxx_assert(__last.size() == 1);
	__glibcxx_assert(__str.size() == 1);
	return this->_M_in_range_icase(__first[0], __last[0], __str[0]);
      }
325 326 327 328
    };

  template<typename _TraitsT>
    class _RegexTranslator<_TraitsT, false, false>
329
    {
330 331 332 333 334
    public:
      typedef typename _TraitsT::char_type _CharT;
      typedef _CharT                       _StrTransT;

      explicit
335
      _RegexTranslator(const _TraitsT&)
336 337 338 339 340 341 342 343 344
      { }

      _CharT
      _M_translate(_CharT __ch) const
      { return __ch; }

      _StrTransT
      _M_transform(_CharT __ch) const
      { return __ch; }
345 346 347 348

      bool
      _M_match_range(_CharT __first, _CharT __last, _CharT __ch) const
      { return __first <= __ch && __ch <= __last; }
349 350 351 352 353 354 355 356 357 358
    };

  template<typename _TraitsT, bool __is_ecma, bool __icase, bool __collate>
    struct _AnyMatcher;

  template<typename _TraitsT, bool __icase, bool __collate>
    struct _AnyMatcher<_TraitsT, false, __icase, __collate>
    {
      typedef _RegexTranslator<_TraitsT, __icase, __collate> _TransT;
      typedef typename _TransT::_CharT                       _CharT;
359

360 361
      explicit
      _AnyMatcher(const _TraitsT& __traits)
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
      : _M_translator(__traits)
      { }

      bool
      operator()(_CharT __ch) const
      {
	static auto __nul = _M_translator._M_translate('\0');
	return _M_translator._M_translate(__ch) != __nul;
      }

      _TransT _M_translator;
    };

  template<typename _TraitsT, bool __icase, bool __collate>
    struct _AnyMatcher<_TraitsT, true, __icase, __collate>
    {
      typedef _RegexTranslator<_TraitsT, __icase, __collate> _TransT;
      typedef typename _TransT::_CharT                       _CharT;

      explicit
      _AnyMatcher(const _TraitsT& __traits)
      : _M_translator(__traits)
384 385 386 387
      { }

      bool
      operator()(_CharT __ch) const
388 389 390 391
      { return _M_apply(__ch, typename is_same<_CharT, char>::type()); }

      bool
      _M_apply(_CharT __ch, true_type) const
392
      {
393 394 395 396
	auto __c = _M_translator._M_translate(__ch);
	auto __n = _M_translator._M_translate('\n');
	auto __r = _M_translator._M_translate('\r');
	return __c != __n && __c != __r;
397 398 399 400 401
      }

      bool
      _M_apply(_CharT __ch, false_type) const
      {
402 403 404 405 406 407
	auto __c = _M_translator._M_translate(__ch);
	auto __n = _M_translator._M_translate('\n');
	auto __r = _M_translator._M_translate('\r');
	auto __u2028 = _M_translator._M_translate(u'\u2028');
	auto __u2029 = _M_translator._M_translate(u'\u2029');
	return __c != __n && __c != __r && __c != __u2028 && __c != __u2029;
408 409
      }

410
      _TransT _M_translator;
411 412
    };

413
  template<typename _TraitsT, bool __icase, bool __collate>
414 415
    struct _CharMatcher
    {
416 417
      typedef _RegexTranslator<_TraitsT, __icase, __collate> _TransT;
      typedef typename _TransT::_CharT                       _CharT;
418

419
      _CharMatcher(_CharT __ch, const _TraitsT& __traits)
420
      : _M_translator(__traits), _M_ch(_M_translator._M_translate(__ch))
421 422 423 424
      { }

      bool
      operator()(_CharT __ch) const
425
      { return _M_ch == _M_translator._M_translate(__ch); }
426

427 428
      _TransT _M_translator;
      _CharT  _M_ch;
429 430
    };

431
  /// Matches a character range (bracket expression)
432
  template<typename _TraitsT, bool __icase, bool __collate>
433 434
    struct _BracketMatcher
    {
435
    public:
436 437 438 439 440
      typedef _RegexTranslator<_TraitsT, __icase, __collate> _TransT;
      typedef typename _TransT::_CharT                       _CharT;
      typedef typename _TransT::_StrTransT                   _StrTransT;
      typedef typename _TraitsT::string_type                 _StringT;
      typedef typename _TraitsT::char_class_type             _CharClassT;
441

442
    public:
443
      _BracketMatcher(bool __is_non_matching,
444 445 446
		      const _TraitsT& __traits)
      : _M_class_set(0), _M_translator(__traits), _M_traits(__traits),
      _M_is_non_matching(__is_non_matching)
447 448 449
      { }

      bool
450 451 452
      operator()(_CharT __ch) const
      {
	_GLIBCXX_DEBUG_ASSERT(_M_is_ready);
453
	return _M_apply(__ch, _UseCache());
454
      }
455 456 457

      void
      _M_add_char(_CharT __c)
458
      {
459
	_M_char_set.push_back(_M_translator._M_translate(__c));
460
	_GLIBCXX_DEBUG_ONLY(_M_is_ready = false);
461
      }
462

463 464
      _StringT
      _M_add_collate_element(const _StringT& __s)
465 466 467 468
      {
	auto __st = _M_traits.lookup_collatename(__s.data(),
						 __s.data() + __s.size());
	if (__st.empty())
469 470
	  __throw_regex_error(regex_constants::error_collate,
			      "Invalid collate element.");
471
	_M_char_set.push_back(_M_translator._M_translate(__st[0]));
472
	_GLIBCXX_DEBUG_ONLY(_M_is_ready = false);
473
	return __st;
474 475 476 477 478
      }

      void
      _M_add_equivalence_class(const _StringT& __s)
      {
479 480 481
	auto __st = _M_traits.lookup_collatename(__s.data(),
						 __s.data() + __s.size());
	if (__st.empty())
482 483
	  __throw_regex_error(regex_constants::error_collate,
			      "Invalid equivalence class.");
484 485
	__st = _M_traits.transform_primary(__st.data(),
					   __st.data() + __st.size());
486
	_M_equiv_set.push_back(__st);
487
	_GLIBCXX_DEBUG_ONLY(_M_is_ready = false);
488 489
      }

490
      // __neg should be true for \D, \S and \W only.
491
      void
492
      _M_add_character_class(const _StringT& __s, bool __neg)
493
      {
494 495
	auto __mask = _M_traits.lookup_classname(__s.data(),
						 __s.data() + __s.size(),
496
						 __icase);
497
	if (__mask == 0)
498 499
	  __throw_regex_error(regex_constants::error_collate,
			      "Invalid character class.");
500 501 502 503
	if (!__neg)
	  _M_class_set |= __mask;
	else
	  _M_neg_class_set.push_back(__mask);
504
	_GLIBCXX_DEBUG_ONLY(_M_is_ready = false);
505 506 507 508 509
      }

      void
      _M_make_range(_CharT __l, _CharT __r)
      {
510
	if (__l > __r)
511 512
	  __throw_regex_error(regex_constants::error_range,
			      "Invalid range in bracket expression.");
513
	_M_range_set.push_back(make_pair(_M_translator._M_transform(__l),
514
					 _M_translator._M_transform(__r)));
515
	_GLIBCXX_DEBUG_ONLY(_M_is_ready = false);
516 517
      }

518 519 520
      void
      _M_ready()
      {
521 522 523 524
	std::sort(_M_char_set.begin(), _M_char_set.end());
	auto __end = std::unique(_M_char_set.begin(), _M_char_set.end());
	_M_char_set.erase(__end, _M_char_set.end());
	_M_make_cache(_UseCache());
525
	_GLIBCXX_DEBUG_ONLY(_M_is_ready = true);
526 527 528
      }

    private:
529 530 531 532
      // Currently we only use the cache for char
      typedef typename std::is_same<_CharT, char>::type _UseCache;

      static constexpr size_t
533 534 535 536
      _S_cache_size()
      {
	return 1ul << (sizeof(_CharT) * __CHAR_BIT__ * int(_UseCache::value));
      }
537

538
      struct _Dummy { };
539 540 541 542
      typedef typename std::conditional<_UseCache::value,
					std::bitset<_S_cache_size()>,
					_Dummy>::type _CacheT;
      typedef typename std::make_unsigned<_CharT>::type _UnsignedCharT;
543 544 545 546 547 548 549 550 551 552 553

      bool
      _M_apply(_CharT __ch, false_type) const;

      bool
      _M_apply(_CharT __ch, true_type) const
      { return _M_cache[static_cast<_UnsignedCharT>(__ch)]; }

      void
      _M_make_cache(true_type)
      {
554 555
	for (unsigned __i = 0; __i < _M_cache.size(); __i++)
	  _M_cache[__i] = _M_apply(static_cast<_CharT>(__i), false_type());
556 557 558 559 560 561 562
      }

      void
      _M_make_cache(false_type)
      { }

    private:
563 564 565
      std::vector<_CharT>                       _M_char_set;
      std::vector<_StringT>                     _M_equiv_set;
      std::vector<pair<_StrTransT, _StrTransT>> _M_range_set;
566
      std::vector<_CharClassT>                  _M_neg_class_set;
567 568 569 570
      _CharClassT                               _M_class_set;
      _TransT                                   _M_translator;
      const _TraitsT&                           _M_traits;
      bool                                      _M_is_non_matching;
571
      _CacheT					_M_cache;
572
#ifdef _GLIBCXX_DEBUG
573
      bool                                      _M_is_ready = false;
574
#endif
575 576
    };

577
 //@} regex-detail
578
_GLIBCXX_END_NAMESPACE_VERSION
579
} // namespace __detail
580
} // namespace std
581 582

#include <bits/regex_compiler.tcc>