Line data Source code
1 : // class template regex -*- C++ -*-
2 :
3 : // Copyright (C) 2010-2021 Free Software Foundation, Inc.
4 : //
5 : // This file is part of the GNU ISO C++ Library. This library is free
6 : // software; you can redistribute it and/or modify it under the
7 : // terms of the GNU General Public License as published by the
8 : // Free Software Foundation; either version 3, or (at your option)
9 : // any later version.
10 :
11 : // This library is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 :
16 : // Under Section 7 of GPL version 3, you are granted additional
17 : // permissions described in the GCC Runtime Library Exception, version
18 : // 3.1, as published by the Free Software Foundation.
19 :
20 : // You should have received a copy of the GNU General Public License and
21 : // a copy of the GCC Runtime Library Exception along with this program;
22 : // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 : // <http://www.gnu.org/licenses/>.
24 :
25 : /**
26 : * @file bits/regex_compiler.h
27 : * This is an internal header file, included by other library headers.
28 : * Do not attempt to use it directly. @headername{regex}
29 : */
30 :
31 : namespace std _GLIBCXX_VISIBILITY(default)
32 : {
33 : _GLIBCXX_BEGIN_NAMESPACE_VERSION
34 : _GLIBCXX_BEGIN_NAMESPACE_CXX11
35 :
36 : template<typename>
37 : class regex_traits;
38 :
39 : _GLIBCXX_END_NAMESPACE_CXX11
40 :
41 : namespace __detail
42 : {
43 : /**
44 : * @addtogroup regex-detail
45 : * @{
46 : */
47 :
48 : template<typename, bool, bool>
49 : struct _BracketMatcher;
50 :
51 : /**
52 : * @brief Builds an NFA from an input iterator range.
53 : *
54 : * The %_TraitsT type should fulfill requirements [28.3].
55 : */
56 : template<typename _TraitsT>
57 : class _Compiler
58 : {
59 : public:
60 : typedef typename _TraitsT::char_type _CharT;
61 : typedef _NFA<_TraitsT> _RegexT;
62 : typedef regex_constants::syntax_option_type _FlagT;
63 :
64 : _Compiler(const _CharT* __b, const _CharT* __e,
65 : const typename _TraitsT::locale_type& __traits, _FlagT __flags);
66 :
67 : shared_ptr<const _RegexT>
68 368 : _M_get_nfa() noexcept
69 368 : { return std::move(_M_nfa); }
70 :
71 : private:
72 : typedef _Scanner<_CharT> _ScannerT;
73 : typedef typename _TraitsT::string_type _StringT;
74 : typedef typename _ScannerT::_TokenT _TokenT;
75 : typedef _StateSeq<_TraitsT> _StateSeqT;
76 : typedef std::stack<_StateSeqT> _StackT;
77 : typedef std::ctype<_CharT> _CtypeT;
78 :
79 : // accepts a specific token or returns false.
80 : bool
81 : _M_match_token(_TokenT __token);
82 :
83 : void
84 : _M_disjunction();
85 :
86 : void
87 : _M_alternative();
88 :
89 : bool
90 : _M_term();
91 :
92 : bool
93 : _M_assertion();
94 :
95 : bool
96 : _M_quantifier();
97 :
98 : bool
99 : _M_atom();
100 :
101 : bool
102 : _M_bracket_expression();
103 :
104 : template<bool __icase, bool __collate>
105 : void
106 : _M_insert_any_matcher_ecma();
107 :
108 : template<bool __icase, bool __collate>
109 : void
110 : _M_insert_any_matcher_posix();
111 :
112 : template<bool __icase, bool __collate>
113 : void
114 : _M_insert_char_matcher();
115 :
116 : template<bool __icase, bool __collate>
117 : void
118 : _M_insert_character_class_matcher();
119 :
120 : template<bool __icase, bool __collate>
121 : void
122 : _M_insert_bracket_matcher(bool __neg);
123 :
124 : // Cache of the last atom seen in a bracketed range expression.
125 : struct _BracketState
126 : {
127 : enum class _Type : char { _None, _Char, _Class } _M_type = _Type::_None;
128 : _CharT _M_char;
129 :
130 : void
131 1371 : set(_CharT __c) noexcept { _M_type = _Type::_Char; _M_char = __c; }
132 :
133 : _GLIBCXX_NODISCARD _CharT
134 1371 : get() const noexcept { return _M_char; }
135 :
136 : void
137 545 : reset(_Type __t = _Type::_None) noexcept { _M_type = __t; }
138 :
139 : explicit operator bool() const noexcept
140 : { return _M_type != _Type::_None; }
141 :
142 : // Previous token was a single character.
143 : _GLIBCXX_NODISCARD bool
144 2081 : _M_is_char() const noexcept { return _M_type == _Type::_Char; }
145 :
146 : // Previous token was a character class, equivalent class,
147 : // collating symbol etc.
148 : _GLIBCXX_NODISCARD bool
149 379 : _M_is_class() const noexcept { return _M_type == _Type::_Class; }
150 : };
151 :
152 : template<bool __icase, bool __collate>
153 : using _BracketMatcher
154 : = std::__detail::_BracketMatcher<_TraitsT, __icase, __collate>;
155 :
156 : // Returns true if successfully parsed one term and should continue
157 : // compiling a bracket expression.
158 : // Returns false if the compiler should move on.
159 : template<bool __icase, bool __collate>
160 : bool
161 : _M_expression_term(_BracketState& __last_char,
162 : _BracketMatcher<__icase, __collate>& __matcher);
163 :
164 : int
165 : _M_cur_int_value(int __radix);
166 :
167 : bool
168 : _M_try_char();
169 :
170 : _StateSeqT
171 14719 : _M_pop()
172 : {
173 14719 : auto ret = _M_stack.top();
174 14719 : _M_stack.pop();
175 14719 : return ret;
176 : }
177 :
178 : static _FlagT
179 368 : _S_validate(_FlagT __f)
180 : {
181 : using namespace regex_constants;
182 368 : switch (__f & (ECMAScript|basic|extended|awk|grep|egrep))
183 : {
184 368 : case ECMAScript:
185 : case basic:
186 : case extended:
187 : case awk:
188 : case grep:
189 : case egrep:
190 368 : return __f;
191 0 : case _FlagT(0):
192 0 : return __f | ECMAScript;
193 0 : default:
194 0 : std::__throw_regex_error(_S_grammar, "conflicting grammar options");
195 : }
196 0 : }
197 :
198 : _FlagT _M_flags;
199 : _ScannerT _M_scanner;
200 : shared_ptr<_RegexT> _M_nfa;
201 : _StringT _M_value;
202 : _StackT _M_stack;
203 : const _TraitsT& _M_traits;
204 : const _CtypeT& _M_ctype;
205 : };
206 :
207 : // [28.13.14]
208 : template<typename _TraitsT, bool __icase, bool __collate>
209 : class _RegexTranslatorBase
210 : {
211 : public:
212 : typedef typename _TraitsT::char_type _CharT;
213 : typedef typename _TraitsT::string_type _StringT;
214 : typedef _StringT _StrTransT;
215 :
216 : explicit
217 24 : _RegexTranslatorBase(const _TraitsT& __traits)
218 24 : : _M_traits(__traits)
219 24 : { }
220 :
221 : _CharT
222 1227 : _M_translate(_CharT __ch) const
223 : {
224 : if (__icase)
225 1227 : return _M_traits.translate_nocase(__ch);
226 : else if (__collate)
227 0 : return _M_traits.translate(__ch);
228 : else
229 : return __ch;
230 : }
231 :
232 : _StrTransT
233 0 : _M_transform(_CharT __ch) const
234 : {
235 0 : _StrTransT __str(1, __ch);
236 0 : return _M_traits.transform(__str.begin(), __str.end());
237 0 : }
238 :
239 : // See LWG 523. It's not efficiently implementable when _TraitsT is not
240 : // std::regex_traits<>, and __collate is true. See specializations for
241 : // implementations of other cases.
242 : bool
243 0 : _M_match_range(const _StrTransT& __first, const _StrTransT& __last,
244 : const _StrTransT& __s) const
245 0 : { return __first <= __s && __s <= __last; }
246 :
247 : protected:
248 0 : bool _M_in_range_icase(_CharT __first, _CharT __last, _CharT __ch) const
249 : {
250 : typedef std::ctype<_CharT> __ctype_type;
251 0 : const auto& __fctyp = use_facet<__ctype_type>(this->_M_traits.getloc());
252 0 : auto __lower = __fctyp.tolower(__ch);
253 0 : auto __upper = __fctyp.toupper(__ch);
254 0 : return (__first <= __lower && __lower <= __last)
255 0 : || (__first <= __upper && __upper <= __last);
256 : }
257 :
258 : const _TraitsT& _M_traits;
259 : };
260 :
261 : template<typename _TraitsT, bool __icase, bool __collate>
262 : class _RegexTranslator
263 : : public _RegexTranslatorBase<_TraitsT, __icase, __collate>
264 : {
265 : public:
266 : typedef _RegexTranslatorBase<_TraitsT, __icase, __collate> _Base;
267 : using _Base::_Base;
268 : };
269 :
270 : template<typename _TraitsT, bool __icase>
271 : class _RegexTranslator<_TraitsT, __icase, false>
272 : : public _RegexTranslatorBase<_TraitsT, __icase, false>
273 : {
274 : public:
275 : typedef _RegexTranslatorBase<_TraitsT, __icase, false> _Base;
276 : typedef typename _Base::_CharT _CharT;
277 : typedef _CharT _StrTransT;
278 :
279 : using _Base::_Base;
280 :
281 : _StrTransT
282 765 : _M_transform(_CharT __ch) const
283 765 : { return __ch; }
284 :
285 : bool
286 0 : _M_match_range(_CharT __first, _CharT __last, _CharT __ch) const
287 : {
288 : if (!__icase)
289 : return __first <= __ch && __ch <= __last;
290 0 : return this->_M_in_range_icase(__first, __last, __ch);
291 : }
292 : };
293 :
294 : template<typename _CharType>
295 : class _RegexTranslator<std::regex_traits<_CharType>, true, true>
296 : : public _RegexTranslatorBase<std::regex_traits<_CharType>, true, true>
297 : {
298 : public:
299 : typedef _RegexTranslatorBase<std::regex_traits<_CharType>, true, true>
300 : _Base;
301 : typedef typename _Base::_CharT _CharT;
302 : typedef typename _Base::_StrTransT _StrTransT;
303 :
304 : using _Base::_Base;
305 :
306 : bool
307 0 : _M_match_range(const _StrTransT& __first, const _StrTransT& __last,
308 : const _StrTransT& __str) const
309 : {
310 0 : __glibcxx_assert(__first.size() == 1);
311 0 : __glibcxx_assert(__last.size() == 1);
312 0 : __glibcxx_assert(__str.size() == 1);
313 0 : return this->_M_in_range_icase(__first[0], __last[0], __str[0]);
314 : }
315 : };
316 :
317 : template<typename _TraitsT>
318 : class _RegexTranslator<_TraitsT, false, false>
319 : {
320 : public:
321 : typedef typename _TraitsT::char_type _CharT;
322 : typedef _CharT _StrTransT;
323 :
324 : explicit
325 4859 : _RegexTranslator(const _TraitsT&)
326 4859 : { }
327 :
328 : _CharT
329 1868728 : _M_translate(_CharT __ch) const
330 1868728 : { return __ch; }
331 :
332 : _StrTransT
333 124185 : _M_transform(_CharT __ch) const
334 124185 : { return __ch; }
335 :
336 : bool
337 90021 : _M_match_range(_CharT __first, _CharT __last, _CharT __ch) const
338 90021 : { return __first <= __ch && __ch <= __last; }
339 : };
340 :
341 : template<typename _TraitsT, bool __is_ecma, bool __icase, bool __collate>
342 : struct _AnyMatcher;
343 :
344 : template<typename _TraitsT, bool __icase, bool __collate>
345 : struct _AnyMatcher<_TraitsT, false, __icase, __collate>
346 : {
347 : typedef _RegexTranslator<_TraitsT, __icase, __collate> _TransT;
348 : typedef typename _TransT::_CharT _CharT;
349 :
350 : explicit
351 0 : _AnyMatcher(const _TraitsT& __traits)
352 0 : : _M_translator(__traits)
353 0 : { }
354 :
355 : bool
356 0 : operator()(_CharT __ch) const
357 : {
358 0 : static auto __nul = _M_translator._M_translate('\0');
359 0 : return _M_translator._M_translate(__ch) != __nul;
360 : }
361 :
362 : _TransT _M_translator;
363 : };
364 :
365 : template<typename _TraitsT, bool __icase, bool __collate>
366 : struct _AnyMatcher<_TraitsT, true, __icase, __collate>
367 : {
368 : typedef _RegexTranslator<_TraitsT, __icase, __collate> _TransT;
369 : typedef typename _TransT::_CharT _CharT;
370 :
371 : explicit
372 347 : _AnyMatcher(const _TraitsT& __traits)
373 347 : : _M_translator(__traits)
374 347 : { }
375 :
376 : bool
377 251747 : operator()(_CharT __ch) const
378 251747 : { return _M_apply(__ch, typename is_same<_CharT, char>::type()); }
379 :
380 : bool
381 251747 : _M_apply(_CharT __ch, true_type) const
382 : {
383 251747 : auto __c = _M_translator._M_translate(__ch);
384 251747 : auto __n = _M_translator._M_translate('\n');
385 251747 : auto __r = _M_translator._M_translate('\r');
386 251747 : return __c != __n && __c != __r;
387 : }
388 :
389 : bool
390 : _M_apply(_CharT __ch, false_type) const
391 : {
392 : auto __c = _M_translator._M_translate(__ch);
393 : auto __n = _M_translator._M_translate('\n');
394 : auto __r = _M_translator._M_translate('\r');
395 : auto __u2028 = _M_translator._M_translate(u'\u2028');
396 : auto __u2029 = _M_translator._M_translate(u'\u2029');
397 : return __c != __n && __c != __r && __c != __u2028 && __c != __u2029;
398 : }
399 :
400 : _TransT _M_translator;
401 : };
402 :
403 : template<typename _TraitsT, bool __icase, bool __collate>
404 : struct _CharMatcher
405 : {
406 : typedef _RegexTranslator<_TraitsT, __icase, __collate> _TransT;
407 : typedef typename _TransT::_CharT _CharT;
408 :
409 4047 : _CharMatcher(_CharT __ch, const _TraitsT& __traits)
410 4047 : : _M_translator(__traits), _M_ch(_M_translator._M_translate(__ch))
411 4047 : { }
412 :
413 : bool
414 984491 : operator()(_CharT __ch) const
415 984491 : { return _M_ch == _M_translator._M_translate(__ch); }
416 :
417 : _TransT _M_translator;
418 : _CharT _M_ch;
419 : };
420 :
421 : /// Matches a character range (bracket expression)
422 : template<typename _TraitsT, bool __icase, bool __collate>
423 : struct _BracketMatcher
424 : {
425 : public:
426 : typedef _RegexTranslator<_TraitsT, __icase, __collate> _TransT;
427 : typedef typename _TransT::_CharT _CharT;
428 : typedef typename _TransT::_StrTransT _StrTransT;
429 : typedef typename _TraitsT::string_type _StringT;
430 : typedef typename _TraitsT::char_class_type _CharClassT;
431 :
432 : public:
433 489 : _BracketMatcher(bool __is_non_matching,
434 : const _TraitsT& __traits)
435 489 : : _M_class_set(0), _M_translator(__traits), _M_traits(__traits),
436 978 : _M_is_non_matching(__is_non_matching)
437 489 : { }
438 :
439 : bool
440 114522 : operator()(_CharT __ch) const
441 : {
442 : _GLIBCXX_DEBUG_ASSERT(_M_is_ready);
443 114522 : return _M_apply(__ch, _UseCache());
444 : }
445 :
446 : void
447 992 : _M_add_char(_CharT __c)
448 : {
449 992 : _M_char_set.push_back(_M_translator._M_translate(__c));
450 : _GLIBCXX_DEBUG_ONLY(_M_is_ready = false);
451 992 : }
452 :
453 : _StringT
454 0 : _M_add_collate_element(const _StringT& __s)
455 : {
456 0 : auto __st = _M_traits.lookup_collatename(__s.data(),
457 0 : __s.data() + __s.size());
458 0 : if (__st.empty())
459 0 : __throw_regex_error(regex_constants::error_collate,
460 : "Invalid collate element.");
461 0 : _M_char_set.push_back(_M_translator._M_translate(__st[0]));
462 : _GLIBCXX_DEBUG_ONLY(_M_is_ready = false);
463 0 : return __st;
464 0 : }
465 :
466 : void
467 0 : _M_add_equivalence_class(const _StringT& __s)
468 : {
469 0 : auto __st = _M_traits.lookup_collatename(__s.data(),
470 0 : __s.data() + __s.size());
471 0 : if (__st.empty())
472 0 : __throw_regex_error(regex_constants::error_collate,
473 : "Invalid equivalence class.");
474 0 : __st = _M_traits.transform_primary(__st.data(),
475 0 : __st.data() + __st.size());
476 0 : _M_equiv_set.push_back(__st);
477 : _GLIBCXX_DEBUG_ONLY(_M_is_ready = false);
478 0 : }
479 :
480 : // __neg should be true for \D, \S and \W only.
481 : void
482 255 : _M_add_character_class(const _StringT& __s, bool __neg)
483 : {
484 255 : auto __mask = _M_traits.lookup_classname(__s.data(),
485 255 : __s.data() + __s.size(),
486 : __icase);
487 255 : if (__mask == 0)
488 0 : __throw_regex_error(regex_constants::error_collate,
489 : "Invalid character class.");
490 255 : if (!__neg)
491 255 : _M_class_set |= __mask;
492 : else
493 0 : _M_neg_class_set.push_back(__mask);
494 : _GLIBCXX_DEBUG_ONLY(_M_is_ready = false);
495 255 : }
496 :
497 : void
498 379 : _M_make_range(_CharT __l, _CharT __r)
499 : {
500 379 : if (__l > __r)
501 0 : __throw_regex_error(regex_constants::error_range,
502 : "Invalid range in bracket expression.");
503 379 : _M_range_set.push_back(make_pair(_M_translator._M_transform(__l),
504 379 : _M_translator._M_transform(__r)));
505 : _GLIBCXX_DEBUG_ONLY(_M_is_ready = false);
506 379 : }
507 :
508 : void
509 489 : _M_ready()
510 : {
511 489 : std::sort(_M_char_set.begin(), _M_char_set.end());
512 489 : auto __end = std::unique(_M_char_set.begin(), _M_char_set.end());
513 489 : _M_char_set.erase(__end, _M_char_set.end());
514 489 : _M_make_cache(_UseCache());
515 : _GLIBCXX_DEBUG_ONLY(_M_is_ready = true);
516 489 : }
517 :
518 : private:
519 : // Currently we only use the cache for char
520 : typedef typename std::is_same<_CharT, char>::type _UseCache;
521 :
522 : static constexpr size_t
523 : _S_cache_size =
524 : 1ul << (sizeof(_CharT) * __CHAR_BIT__ * int(_UseCache::value));
525 :
526 : struct _Dummy { };
527 : typedef typename std::conditional<_UseCache::value,
528 : std::bitset<_S_cache_size>,
529 : _Dummy>::type _CacheT;
530 : typedef typename std::make_unsigned<_CharT>::type _UnsignedCharT;
531 :
532 : bool
533 : _M_apply(_CharT __ch, false_type) const;
534 :
535 : bool
536 114522 : _M_apply(_CharT __ch, true_type) const
537 114522 : { return _M_cache[static_cast<_UnsignedCharT>(__ch)]; }
538 :
539 : void
540 489 : _M_make_cache(true_type)
541 : {
542 125673 : for (unsigned __i = 0; __i < _M_cache.size(); __i++)
543 125184 : _M_cache[__i] = _M_apply(static_cast<_CharT>(__i), false_type());
544 489 : }
545 :
546 : void
547 : _M_make_cache(false_type)
548 : { }
549 :
550 : private:
551 : std::vector<_CharT> _M_char_set;
552 : std::vector<_StringT> _M_equiv_set;
553 : std::vector<pair<_StrTransT, _StrTransT>> _M_range_set;
554 : std::vector<_CharClassT> _M_neg_class_set;
555 : _CharClassT _M_class_set;
556 : _TransT _M_translator;
557 : const _TraitsT& _M_traits;
558 : bool _M_is_non_matching;
559 : _CacheT _M_cache;
560 : #ifdef _GLIBCXX_DEBUG
561 : bool _M_is_ready = false;
562 : #endif
563 : };
564 :
565 : ///@} regex-detail
566 : } // namespace __detail
567 : _GLIBCXX_END_NAMESPACE_VERSION
568 : } // namespace std
569 :
570 : #include <bits/regex_compiler.tcc>
|