From 6130bce7397918cd5563e4b404c4f86c9dfd94a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20M=C3=BCller?= Date: Sun, 18 May 2025 13:16:18 +0200 Subject: [PATCH 01/21] rename _Parser to _Parser2 --- stl/inc/regex | 71 ++++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index 46dab2b06d0..1a319380297 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1574,7 +1574,7 @@ enum class _Rx_char_class_kind : int { // must be aligned with corresponding _No }; template -class _Builder { // provides operations used by _Parser to build the nfa +class _Builder { // provides operations used by _Parser2 to build the nfa public: _Builder(const _RxTraits& _Tr, regex_constants::syntax_option_type); void _Setlong(); @@ -1785,11 +1785,11 @@ enum _Prs_ret { // indicate class element type }; template -class _Parser { // parse a regular expression +class _Parser2 { // parse a regular expression public: using char_class_type = typename _RxTraits::char_class_type; - _Parser(const _RxTraits& _Tr, _FwdIt _Pfirst, _FwdIt _Plast, regex_constants::syntax_option_type _Fx); + _Parser2(const _RxTraits& _Tr, _FwdIt _Pfirst, _FwdIt _Plast, regex_constants::syntax_option_type _Fx); _Root_node* _Compile(); unsigned int _Mark_count() const noexcept { @@ -2121,7 +2121,7 @@ private: _Visualization.assign(_First, _Last); #endif // _ENHANCED_REGEX_VISUALIZER - _Parser<_InIt, _Elem, _RxTraits> _Prs(_Traits, _First, _Last, _Flags); + _Parser2<_InIt, _Elem, _RxTraits> _Prs(_Traits, _First, _Last, _Flags); _Root_node* _Rx = _Prs._Compile(); _Reset(_Rx); } else { @@ -4160,19 +4160,19 @@ _BidIt _Matcher2<_BidIt, _Elem, _RxTraits, _It, _Alloc>::_Skip(_BidIt _First_arg } template -[[noreturn]] void _Parser<_FwdIt, _Elem, _RxTraits>::_Error(regex_constants::error_type _Code) { // handle error +[[noreturn]] void _Parser2<_FwdIt, _Elem, _RxTraits>::_Error(regex_constants::error_type _Code) { // handle error _Xregex_error(_Code); } template -bool _Parser<_FwdIt, _Elem, _RxTraits>::_Is_esc(_FwdIt _Ch0) const { // assumes _Ch0 != _End +bool _Parser2<_FwdIt, _Elem, _RxTraits>::_Is_esc(_FwdIt _Ch0) const { // assumes _Ch0 != _End return ++_Ch0 != _End && ((!(_L_flags & _L_nex_grp) && (*_Ch0 == _Meta_lpar || *_Ch0 == _Meta_rpar)) || (!(_L_flags & _L_nex_rep) && (*_Ch0 == _Meta_lbr || *_Ch0 == _Meta_rbr))); } template -void _Parser<_FwdIt, _Elem, _RxTraits>::_Trans() { // map character to meta-character +void _Parser2<_FwdIt, _Elem, _RxTraits>::_Trans() { // map character to meta-character static constexpr char _Meta_map[] = {_Meta_lpar, _Meta_rpar, _Meta_dlr, _Meta_caret, _Meta_dot, _Meta_star, _Meta_plus, _Meta_query, _Meta_lsq, _Meta_rsq, _Meta_bar, _Meta_esc, _Meta_dash, _Meta_lbr, _Meta_rbr, _Meta_comma, _Meta_colon, _Meta_equal, _Meta_exc, _Meta_nl, _Meta_cr, _Meta_bsp, 0}; // array of meta chars @@ -4278,7 +4278,7 @@ void _Parser<_FwdIt, _Elem, _RxTraits>::_Trans() { // map character to meta-char } template -void _Parser<_FwdIt, _Elem, _RxTraits>::_Next() { // advance to next input character +void _Parser2<_FwdIt, _Elem, _RxTraits>::_Next() { // advance to next input character if (_Pat != _End) { // advance if (*_Pat == _Meta_esc && _Is_esc(_Pat)) { ++_Pat; @@ -4290,7 +4290,7 @@ void _Parser<_FwdIt, _Elem, _RxTraits>::_Next() { // advance to next input chara } template -void _Parser<_FwdIt, _Elem, _RxTraits>::_Expect(_Meta_type _St, regex_constants::error_type _Code) { +void _Parser2<_FwdIt, _Elem, _RxTraits>::_Expect(_Meta_type _St, regex_constants::error_type _Code) { // check whether current meta-character is _St if (_Mchar != _St) { _Error(_Code); @@ -4300,7 +4300,7 @@ void _Parser<_FwdIt, _Elem, _RxTraits>::_Expect(_Meta_type _St, regex_constants: } template -int _Parser<_FwdIt, _Elem, _RxTraits>::_Do_digits( +int _Parser2<_FwdIt, _Elem, _RxTraits>::_Do_digits( int _Base, int _Initial, int _Count, regex_constants::error_type _Error_type) { // translate digits to numeric value int _Chv; _Val = _Initial; @@ -4317,25 +4317,25 @@ int _Parser<_FwdIt, _Elem, _RxTraits>::_Do_digits( } template -bool _Parser<_FwdIt, _Elem, _RxTraits>::_DecimalDigits3( +bool _Parser2<_FwdIt, _Elem, _RxTraits>::_DecimalDigits3( const regex_constants::error_type _Error_type, const int _Initial /* = 0 */) { // check for decimal value return _Do_digits(10, _Initial, INT_MAX, _Error_type) != INT_MAX; } template -void _Parser<_FwdIt, _Elem, _RxTraits>::_HexDigits(int _Count) { // check for _Count hex digits +void _Parser2<_FwdIt, _Elem, _RxTraits>::_HexDigits(int _Count) { // check for _Count hex digits if (_Do_digits(16, 0, _Count, regex_constants::error_escape) != 0) { _Error(regex_constants::error_escape); } } template -bool _Parser<_FwdIt, _Elem, _RxTraits>::_OctalDigits() { // check for up to 3 octal digits +bool _Parser2<_FwdIt, _Elem, _RxTraits>::_OctalDigits() { // check for up to 3 octal digits return _Do_digits(8, 0, 3, regex_constants::error_escape) != 3; } template -_Prs_ret _Parser<_FwdIt, _Elem, _RxTraits>::_Do_ex_class2( +_Prs_ret _Parser2<_FwdIt, _Elem, _RxTraits>::_Do_ex_class2( _Meta_type _End_arg) { // handle delimited expressions within bracket expression const regex_constants::error_type _Errtype = _End_arg == _Meta_colon ? regex_constants::error_ctype : regex_constants::error_collate; @@ -4404,7 +4404,7 @@ _Prs_ret _Parser<_FwdIt, _Elem, _RxTraits>::_Do_ex_class2( } template -bool _Parser<_FwdIt, _Elem, _RxTraits>::_CharacterClassEscape(bool _Addit) { // check for character class escape +bool _Parser2<_FwdIt, _Elem, _RxTraits>::_CharacterClassEscape(bool _Addit) { // check for character class escape typename _RxTraits::char_class_type _Cls; _FwdIt _Ch0 = _Pat; if (_Ch0 == _End || (_Cls = _Traits.lookup_classname(_Pat, ++_Ch0, (_Flags & regex_constants::icase) != 0)) == 0) { @@ -4433,7 +4433,7 @@ bool _Parser<_FwdIt, _Elem, _RxTraits>::_CharacterClassEscape(bool _Addit) { // } template -_Prs_ret _Parser<_FwdIt, _Elem, _RxTraits>::_ClassEscape3() { // check for class escape +_Prs_ret _Parser2<_FwdIt, _Elem, _RxTraits>::_ClassEscape3() { // check for class escape if ((_L_flags & _L_esc_bsp) && _Char == _Esc_ctrl_b) { // handle backspace escape _Next(); _Val = _Meta_bsp; @@ -4456,7 +4456,7 @@ _Prs_ret _Parser<_FwdIt, _Elem, _RxTraits>::_ClassEscape3() { // check for class } template -_Prs_ret _Parser<_FwdIt, _Elem, _RxTraits>::_ClassAtom(const bool _Initial) { // check for class atom +_Prs_ret _Parser2<_FwdIt, _Elem, _RxTraits>::_ClassAtom(const bool _Initial) { // check for class atom if (_Mchar == _Meta_esc && (_L_flags & (_L_grp_esc | _L_ident_awk))) { // check for valid escape sequence _Next(); return _ClassEscape3(); @@ -4483,7 +4483,7 @@ _Prs_ret _Parser<_FwdIt, _Elem, _RxTraits>::_ClassAtom(const bool _Initial) { // } template -void _Parser<_FwdIt, _Elem, _RxTraits>::_ClassRanges() { // check for valid class ranges +void _Parser2<_FwdIt, _Elem, _RxTraits>::_ClassRanges() { // check for valid class ranges _Prs_ret _Ret; bool _Initial = true; @@ -4532,7 +4532,7 @@ void _Parser<_FwdIt, _Elem, _RxTraits>::_ClassRanges() { // check for valid clas } template -void _Parser<_FwdIt, _Elem, _RxTraits>::_CharacterClass() { // add bracket expression +void _Parser2<_FwdIt, _Elem, _RxTraits>::_CharacterClass() { // add bracket expression _Nfa._Add_class(); if (_Mchar == _Meta_caret) { // negate bracket expression _Nfa._Negate(); @@ -4543,7 +4543,7 @@ void _Parser<_FwdIt, _Elem, _RxTraits>::_CharacterClass() { // add bracket expre } template -void _Parser<_FwdIt, _Elem, _RxTraits>::_Do_capture_group() { // add capture group +void _Parser2<_FwdIt, _Elem, _RxTraits>::_Do_capture_group() { // add capture group ++_Grp_idx; if (_Grp_idx >= 1000) { // hardcoded limit @@ -4558,21 +4558,21 @@ void _Parser<_FwdIt, _Elem, _RxTraits>::_Do_capture_group() { // add capture gro } template -void _Parser<_FwdIt, _Elem, _RxTraits>::_Do_noncapture_group() { // add non-capture group +void _Parser2<_FwdIt, _Elem, _RxTraits>::_Do_noncapture_group() { // add non-capture group _Node_base* _Pos1 = _Nfa._Begin_group(); _Disjunction(); _Nfa._End_group(_Pos1); } template -void _Parser<_FwdIt, _Elem, _RxTraits>::_Do_assert_group(bool _Neg) { // add assert group +void _Parser2<_FwdIt, _Elem, _RxTraits>::_Do_assert_group(bool _Neg) { // add assert group _Node_base* _Pos1 = _Nfa._Begin_assert_group(_Neg); _Disjunction(); _Nfa._End_assert_group(_Pos1); } template -bool _Parser<_FwdIt, _Elem, _RxTraits>::_Wrapped_disjunction() { // add disjunction inside group +bool _Parser2<_FwdIt, _Elem, _RxTraits>::_Wrapped_disjunction() { // add disjunction inside group ++_Disj_count; if (!(_L_flags & _L_empty_grp) && _Mchar == _Meta_rpar) { _Error(regex_constants::error_paren); @@ -4604,7 +4604,7 @@ bool _Parser<_FwdIt, _Elem, _RxTraits>::_Wrapped_disjunction() { // add disjunct } template -bool _Parser<_FwdIt, _Elem, _RxTraits>::_IsIdentityEscape(bool _In_character_class) const { +bool _Parser2<_FwdIt, _Elem, _RxTraits>::_IsIdentityEscape(bool _In_character_class) const { // check for valid identity escape if (_L_flags & _L_ident_ECMA) { @@ -4654,7 +4654,7 @@ bool _Parser<_FwdIt, _Elem, _RxTraits>::_IsIdentityEscape(bool _In_character_cla } template -bool _Parser<_FwdIt, _Elem, _RxTraits>::_IdentityEscape(bool _In_character_class) { +bool _Parser2<_FwdIt, _Elem, _RxTraits>::_IdentityEscape(bool _In_character_class) { // check whether an escape is valid, and process it if so if (_IsIdentityEscape(_In_character_class)) { _Val = _Char; @@ -4666,7 +4666,7 @@ bool _Parser<_FwdIt, _Elem, _RxTraits>::_IdentityEscape(bool _In_character_class } template -bool _Parser<_FwdIt, _Elem, _RxTraits>::_Do_ffn(_Elem _Ch) { // check for limited file format escape characters +bool _Parser2<_FwdIt, _Elem, _RxTraits>::_Do_ffn(_Elem _Ch) { // check for limited file format escape characters if (_Ch == _Esc_ctrl_f) { _Val = '\f'; } else if (_Ch == _Esc_ctrl_n) { @@ -4685,7 +4685,7 @@ bool _Parser<_FwdIt, _Elem, _RxTraits>::_Do_ffn(_Elem _Ch) { // check for limite } template -bool _Parser<_FwdIt, _Elem, _RxTraits>::_Do_ffnx(_Elem _Ch) { // check for the remaining file format escape characters +bool _Parser2<_FwdIt, _Elem, _RxTraits>::_Do_ffnx(_Elem _Ch) { // check for the remaining file format escape characters if (_Ch == _Esc_ctrl_a) { _Val = '\a'; } else if (_Ch == _Esc_ctrl_b) { @@ -4698,7 +4698,8 @@ bool _Parser<_FwdIt, _Elem, _RxTraits>::_Do_ffnx(_Elem _Ch) { // check for the r } template -bool _Parser<_FwdIt, _Elem, _RxTraits>::_CharacterEscape(bool _In_character_class) { // check for valid character escape +bool _Parser2<_FwdIt, _Elem, _RxTraits>::_CharacterEscape(bool _In_character_class) { + // check for valid character escape if (_Mchar == _Meta_eos) { _Error(regex_constants::error_escape); } @@ -4736,7 +4737,7 @@ bool _Parser<_FwdIt, _Elem, _RxTraits>::_CharacterEscape(bool _In_character_clas } template -void _Parser<_FwdIt, _Elem, _RxTraits>::_AtomEscape() { // check for valid atom escape +void _Parser2<_FwdIt, _Elem, _RxTraits>::_AtomEscape() { // check for valid atom escape if ((_L_flags & (_L_bzr_chr | _L_bckr)) && (_Val = _Traits.value(_Char, 10)) != -1) { // escaped decimal sequence _Next(); if ((_L_flags & _L_bzr_chr) && _Val == 0) { // handle \0 @@ -4766,7 +4767,7 @@ void _Parser<_FwdIt, _Elem, _RxTraits>::_AtomEscape() { // check for valid atom } template -void _Parser<_FwdIt, _Elem, _RxTraits>::_Quantifier() { // check for quantifier following atom +void _Parser2<_FwdIt, _Elem, _RxTraits>::_Quantifier() { // check for quantifier following atom int _Min = 0; int _Max = -1; if (_Mchar != _Meta_star) { @@ -4812,7 +4813,7 @@ void _Parser<_FwdIt, _Elem, _RxTraits>::_Quantifier() { // check for quantifier } template -bool _Parser<_FwdIt, _Elem, _RxTraits>::_Alternative() { // check for valid alternative +bool _Parser2<_FwdIt, _Elem, _RxTraits>::_Alternative() { // check for valid alternative bool _Found = false; for (;;) { // concatenate valid elements bool _Quant = true; @@ -4879,7 +4880,7 @@ bool _Parser<_FwdIt, _Elem, _RxTraits>::_Alternative() { // check for valid alte } template -void _Parser<_FwdIt, _Elem, _RxTraits>::_Disjunction() { // check for valid disjunction +void _Parser2<_FwdIt, _Elem, _RxTraits>::_Disjunction() { // check for valid disjunction _Node_base* _Pos1 = _Nfa._Getmark(); if (!_Alternative()) { if (_Mchar != _Meta_bar) { @@ -4904,7 +4905,7 @@ void _Parser<_FwdIt, _Elem, _RxTraits>::_Disjunction() { // check for valid disj } template -void _Parser<_FwdIt, _Elem, _RxTraits>::_Calculate_loop_simplicity( +void _Parser2<_FwdIt, _Elem, _RxTraits>::_Calculate_loop_simplicity( _Node_base* _Nx, _Node_base* _Ne, _Node_rep* _Outer_rep) { // walks regex NFA, calculates values of _Node_rep::_Simple_loop for (; _Nx != _Ne && _Nx; _Nx = _Nx->_Next) { @@ -4990,7 +4991,7 @@ void _Parser<_FwdIt, _Elem, _RxTraits>::_Calculate_loop_simplicity( } template -_Root_node* _Parser<_FwdIt, _Elem, _RxTraits>::_Compile() { // compile regular expression +_Root_node* _Parser2<_FwdIt, _Elem, _RxTraits>::_Compile() { // compile regular expression _Root_node* _Res = nullptr; _Tidy_guard _Guard{_STD addressof(_Nfa)}; _Node_base* _Pos1 = _Nfa._Begin_capture_group(0); @@ -5009,7 +5010,7 @@ _Root_node* _Parser<_FwdIt, _Elem, _RxTraits>::_Compile() { // compile regular e } template -_Parser<_FwdIt, _Elem, _RxTraits>::_Parser( +_Parser2<_FwdIt, _Elem, _RxTraits>::_Parser2( const _RxTraits& _Tr, _FwdIt _Pfirst, _FwdIt _Plast, regex_constants::syntax_option_type _Fx) : _Pat(_Pfirst), _Begin(_Pfirst), _End(_Plast), _Nfa(_Tr, _Fx), _Traits(_Tr), _Flags(_Fx) { From bcdf7875ccd2c1e6f1eddb03eb2c27c45b11eea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20M=C3=BCller?= Date: Sun, 18 May 2025 13:18:54 +0200 Subject: [PATCH 02/21] remove unnecessary version numbers from _Parser2's member functions --- stl/inc/regex | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index 1a319380297..8eabdcef15e 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1807,12 +1807,12 @@ private: // parsing int _Do_digits(int _Base, int _Initial, int _Count, regex_constants::error_type _Error_type); - bool _DecimalDigits3(regex_constants::error_type _Error_type, int _Initial = 0); + bool _DecimalDigits(regex_constants::error_type _Error_type, int _Initial = 0); void _HexDigits(int); bool _OctalDigits(); - _Prs_ret _Do_ex_class2(_Meta_type); + _Prs_ret _Do_ex_class(_Meta_type); bool _CharacterClassEscape(bool); - _Prs_ret _ClassEscape3(); + _Prs_ret _ClassEscape(); _Prs_ret _ClassAtom(bool); void _ClassRanges(); void _CharacterClass(); @@ -4317,7 +4317,7 @@ int _Parser2<_FwdIt, _Elem, _RxTraits>::_Do_digits( } template -bool _Parser2<_FwdIt, _Elem, _RxTraits>::_DecimalDigits3( +bool _Parser2<_FwdIt, _Elem, _RxTraits>::_DecimalDigits( const regex_constants::error_type _Error_type, const int _Initial /* = 0 */) { // check for decimal value return _Do_digits(10, _Initial, INT_MAX, _Error_type) != INT_MAX; } @@ -4335,7 +4335,7 @@ bool _Parser2<_FwdIt, _Elem, _RxTraits>::_OctalDigits() { // check for up to 3 o } template -_Prs_ret _Parser2<_FwdIt, _Elem, _RxTraits>::_Do_ex_class2( +_Prs_ret _Parser2<_FwdIt, _Elem, _RxTraits>::_Do_ex_class( _Meta_type _End_arg) { // handle delimited expressions within bracket expression const regex_constants::error_type _Errtype = _End_arg == _Meta_colon ? regex_constants::error_ctype : regex_constants::error_collate; @@ -4433,7 +4433,7 @@ bool _Parser2<_FwdIt, _Elem, _RxTraits>::_CharacterClassEscape(bool _Addit) { // } template -_Prs_ret _Parser2<_FwdIt, _Elem, _RxTraits>::_ClassEscape3() { // check for class escape +_Prs_ret _Parser2<_FwdIt, _Elem, _RxTraits>::_ClassEscape() { // check for class escape if ((_L_flags & _L_esc_bsp) && _Char == _Esc_ctrl_b) { // handle backspace escape _Next(); _Val = _Meta_bsp; @@ -4459,13 +4459,13 @@ template _Prs_ret _Parser2<_FwdIt, _Elem, _RxTraits>::_ClassAtom(const bool _Initial) { // check for class atom if (_Mchar == _Meta_esc && (_L_flags & (_L_grp_esc | _L_ident_awk))) { // check for valid escape sequence _Next(); - return _ClassEscape3(); + return _ClassEscape(); } else if (_Mchar == _Meta_lsq) { // check for valid delimited expression _Next(); if (_Mchar == _Meta_colon || _Mchar == _Meta_equal || _Mchar == _Meta_dot) { // handle delimited expression _Meta_type _St = _Mchar; _Next(); - return _Do_ex_class2(_St); + return _Do_ex_class(_St); } else { // handle ordinary [ _Val = _Meta_lsq; return _Prs_chr; @@ -4747,7 +4747,7 @@ void _Parser2<_FwdIt, _Elem, _RxTraits>::_AtomEscape() { // check for valid atom _Nfa._Add_char2(_Elem{}); } else if (_L_flags & _L_bckr) { // check for valid backreference if (!(_L_flags & _L_lim_bckr)) { - (void) _DecimalDigits3(regex_constants::error_backref, _Val); + (void) _DecimalDigits(regex_constants::error_backref, _Val); } if (_Val == 0) { @@ -4777,7 +4777,7 @@ void _Parser2<_FwdIt, _Elem, _RxTraits>::_Quantifier() { // check for quantifier _Max = 1; } else if (_Mchar == _Meta_lbr) { // check for valid bracketed value _Next(); - if (!_DecimalDigits3(regex_constants::error_badbrace)) { + if (!_DecimalDigits(regex_constants::error_badbrace)) { _Error(regex_constants::error_badbrace); } @@ -4787,7 +4787,7 @@ void _Parser2<_FwdIt, _Elem, _RxTraits>::_Quantifier() { // check for quantifier } else { // check for decimal constant following comma _Next(); if (_Mchar != _Meta_rbr) { - if (!_DecimalDigits3(regex_constants::error_badbrace)) { + if (!_DecimalDigits(regex_constants::error_badbrace)) { _Error(regex_constants::error_badbrace); } From d93567b5451f393fccbf331a0eda6de83e9f8b94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20M=C3=BCller?= Date: Sun, 18 May 2025 13:19:39 +0200 Subject: [PATCH 03/21] clean up parse flags, extend range of possible parse flags, add new parse flag for forbidden dash at range start --- stl/inc/regex | 94 ++++++++++++++++++++++++++------------------------- 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index 8eabdcef15e..d04a9275fe5 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1843,42 +1843,43 @@ private: int _Val; _Elem _Char; _Meta_type _Mchar; - unsigned int _L_flags; + unsigned long long _L_flags; }; -enum _Lang_flags { // describe language properties - _L_ext_rep = 0x00000001, // + and ? repetitions - _L_alt_pipe = 0x00000002, // uses '|' for alternation - _L_alt_nl = 0x00000004, // uses '\n' for alternation (grep, egrep) - _L_nex_grp = 0x00000008, // has non-escaped capture groups - _L_nex_rep = 0x00000010, // has non-escaped repeats - _L_nc_grp = 0x00000020, // has non-capture groups (?:xxx) - _L_asrt_gen = 0x00000040, // has generalized assertions (?=xxx), (?!xxx) - _L_asrt_wrd = 0x00000080, // has word boundary assertions (\b, \B) - _L_bckr = 0x00000100, // has backreferences (ERE doesn't) - _L_lim_bckr = 0x00000200, // has limited backreferences (BRE \1-\9) - _L_ngr_rep = 0x00000400, // has non-greedy repeats - _L_esc_uni = 0x00000800, // has Unicode escape sequences - _L_esc_hex = 0x00001000, // has hexadecimal escape sequences - _L_esc_oct = 0x00002000, // has octal escape sequences - _L_esc_bsp = 0x00004000, // has backspace escape in character classes - _L_esc_ffnx = 0x00008000, // has extra file escapes (\a and \b) - _L_esc_ffn = 0x00010000, // has limited file escapes (\[fnrtv]) - _L_esc_wsd = 0x00020000, // has w, s, and d character set escapes - _L_esc_ctrl = 0x00040000, // has control escape - _L_no_nl = 0x00080000, // no newline in pattern or matching text - _L_bzr_chr = 0x00100000, // \0 is a valid character constant - _L_grp_esc = 0x00200000, // \ is special character in group - _L_ident_ECMA = 0x00400000, // ECMA identity escape (not identifierpart) - _L_ident_ERE = 0x00800000, // ERE identity escape (.[\*^$, plus {+?}() - _L_ident_awk = 0x01000000, // awk identity escape ( ERE plus "/) - _L_anch_rstr = 0x02000000, // anchor restricted to beginning/end - _L_star_beg = 0x04000000, // star okay at beginning of RE/expr (BRE) - _L_empty_grp = 0x08000000, // empty group allowed (ERE prohibits "()") - _L_paren_bal = 0x10000000, // ')'/'}' special only after '('/'{' - _L_brk_bal = 0x20000000, // ']' special only after '[' (ERE, BRE); TRANSITION, ABI: same value as _L_brk_rstr - _L_brk_rstr = 0x20000000, // ']' not special when first character in set - _L_mtch_long = 0x40000000, // find longest match (ERE, BRE) +enum _Lang_flags2 : unsigned long long { // describe language properties + _L_ext_rep = 0x000000001ULL, // + and ? repetitions + _L_alt_pipe = 0x000000002ULL, // uses '|' for alternation + _L_alt_nl = 0x000000004ULL, // uses '\n' for alternation (grep, egrep) + _L_nex_grp = 0x000000008ULL, // has non-escaped capture groups + _L_nex_rep = 0x000000010ULL, // has non-escaped repeats + _L_nc_grp = 0x000000020ULL, // has non-capture groups (?:xxx) + _L_asrt_gen = 0x000000040ULL, // has generalized assertions (?=xxx), (?!xxx) + _L_asrt_wrd = 0x000000080ULL, // has word boundary assertions (\b, \B) + _L_bckr = 0x000000100ULL, // has backreferences (ERE doesn't) + _L_lim_bckr = 0x000000200ULL, // has limited backreferences (BRE \1-\9) + _L_ngr_rep = 0x000000400ULL, // has non-greedy repeats + _L_esc_uni = 0x000000800ULL, // has Unicode escape sequences + _L_esc_hex = 0x000001000ULL, // has hexadecimal escape sequences + _L_esc_oct = 0x000002000ULL, // has octal escape sequences + _L_esc_bsp = 0x000004000ULL, // has backspace escape in character classes + _L_esc_ffnx = 0x000008000ULL, // has extra file escapes (\a and \b) + _L_esc_ffn = 0x000010000ULL, // has limited file escapes (\[fnrtv]) + _L_esc_wsd = 0x000020000ULL, // has w, s, and d character set escapes + _L_esc_ctrl = 0x000040000ULL, // has control escape + _L_no_nl = 0x000080000ULL, // no newline in pattern or matching text + _L_bzr_chr = 0x000100000ULL, // \0 is a valid character constant + _L_grp_esc = 0x000200000ULL, // \ is special character in group + _L_ident_ECMA = 0x000400000ULL, // ECMA identity escape (not identifierpart) + _L_ident_ERE = 0x000800000ULL, // ERE identity escape (.[\*^$, plus {+?}() + _L_ident_awk = 0x001000000ULL, // awk identity escape ( ERE plus "/) + _L_anch_rstr = 0x002000000ULL, // anchor restricted to beginning/end + _L_star_beg = 0x004000000ULL, // star okay at beginning of RE/expr (BRE) + _L_empty_grp = 0x008000000ULL, // empty group allowed (ERE prohibits "()") + _L_paren_bal = 0x010000000ULL, // ')'/'}' special only after '('/'{' + _L_brk_bal = 0x020000000ULL, // ']' special only after '[' (ERE, BRE) + _L_brk_rstr = 0x040000000ULL, // ']' not special when first character in set + _L_dsh_rstr = 0x080000000ULL, // '-' forbidden at range start in set except when first character (ERE, BRE) + _L_mtch_long = 0x100000000ULL, // find longest match (ERE, BRE) }; class _Regex_base : public _Container_base { // base class for basic_regex to construct and destroy proxy @@ -4457,7 +4458,7 @@ _Prs_ret _Parser2<_FwdIt, _Elem, _RxTraits>::_ClassEscape() { // check for class template _Prs_ret _Parser2<_FwdIt, _Elem, _RxTraits>::_ClassAtom(const bool _Initial) { // check for class atom - if (_Mchar == _Meta_esc && (_L_flags & (_L_grp_esc | _L_ident_awk))) { // check for valid escape sequence + if (_Mchar == _Meta_esc && (_L_flags & _L_grp_esc)) { // check for valid escape sequence _Next(); return _ClassEscape(); } else if (_Mchar == _Meta_lsq) { // check for valid delimited expression @@ -5014,22 +5015,23 @@ _Parser2<_FwdIt, _Elem, _RxTraits>::_Parser2( const _RxTraits& _Tr, _FwdIt _Pfirst, _FwdIt _Plast, regex_constants::syntax_option_type _Fx) : _Pat(_Pfirst), _Begin(_Pfirst), _End(_Plast), _Nfa(_Tr, _Fx), _Traits(_Tr), _Flags(_Fx) { - constexpr unsigned int _ECMA_flags = _L_ext_rep | _L_alt_pipe | _L_nex_grp | _L_nex_rep | _L_nc_grp | _L_asrt_gen - | _L_asrt_wrd | _L_bckr | _L_ngr_rep | _L_esc_uni | _L_esc_hex | _L_esc_bsp - | _L_esc_ffn | _L_esc_wsd | _L_esc_ctrl | _L_bzr_chr | _L_grp_esc | _L_ident_ECMA - | _L_empty_grp; + constexpr unsigned long long _ECMA_flags = _L_ext_rep | _L_alt_pipe | _L_nex_grp | _L_nex_rep | _L_nc_grp + | _L_asrt_gen | _L_asrt_wrd | _L_bckr | _L_ngr_rep | _L_esc_uni + | _L_esc_hex | _L_esc_bsp | _L_esc_ffn | _L_esc_wsd | _L_esc_ctrl + | _L_bzr_chr | _L_grp_esc | _L_ident_ECMA | _L_empty_grp; - constexpr unsigned int _Basic_flags = - _L_bckr | _L_lim_bckr | _L_anch_rstr | _L_star_beg | _L_empty_grp | _L_brk_bal | _L_brk_rstr | _L_mtch_long; + constexpr unsigned long long _Basic_flags = _L_bckr | _L_lim_bckr | _L_anch_rstr | _L_star_beg | _L_empty_grp + | _L_brk_bal | _L_brk_rstr | _L_dsh_rstr | _L_mtch_long; - constexpr unsigned int _Grep_flags = _Basic_flags | _L_alt_nl | _L_no_nl; + constexpr unsigned long long _Grep_flags = _Basic_flags | _L_alt_nl | _L_no_nl; - constexpr unsigned int _Extended_flags = _L_ext_rep | _L_alt_pipe | _L_nex_grp | _L_nex_rep | _L_ident_ERE - | _L_paren_bal | _L_brk_bal | _L_brk_rstr | _L_mtch_long; + constexpr unsigned long long _Extended_flags = _L_ext_rep | _L_alt_pipe | _L_nex_grp | _L_nex_rep | _L_ident_ERE + | _L_paren_bal | _L_brk_bal | _L_brk_rstr | _L_dsh_rstr | _L_mtch_long; - constexpr unsigned int _Awk_flags = _Extended_flags | _L_esc_oct | _L_esc_ffn | _L_esc_ffnx | _L_ident_awk; + constexpr unsigned long long _Awk_flags = + _Extended_flags | _L_esc_oct | _L_esc_ffn | _L_esc_ffnx | _L_grp_esc | _L_ident_awk; - constexpr unsigned int _Egrep_flags = _Extended_flags | _L_alt_nl | _L_no_nl; + constexpr unsigned long long _Egrep_flags = _Extended_flags | _L_alt_nl | _L_no_nl; const regex_constants::syntax_option_type _Masked = _Flags & regex_constants::_Gmask; From a687fb0e8c202ae7ec94599f239789cea0a38dc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20M=C3=BCller?= Date: Sun, 18 May 2025 13:22:17 +0200 Subject: [PATCH 04/21] remove unused member `_Begin` from `_Parser2` --- stl/inc/regex | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index d04a9275fe5..ad240917085 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1832,7 +1832,6 @@ private: void _Calculate_loop_simplicity(_Node_base* _Nx, _Node_base* _Ne, _Node_rep* _Outer_rep); _FwdIt _Pat; - _FwdIt _Begin; _FwdIt _End; unsigned int _Grp_idx = 0; int _Disj_count = 0; @@ -5013,7 +5012,7 @@ _Root_node* _Parser2<_FwdIt, _Elem, _RxTraits>::_Compile() { // compile regular template _Parser2<_FwdIt, _Elem, _RxTraits>::_Parser2( const _RxTraits& _Tr, _FwdIt _Pfirst, _FwdIt _Plast, regex_constants::syntax_option_type _Fx) - : _Pat(_Pfirst), _Begin(_Pfirst), _End(_Plast), _Nfa(_Tr, _Fx), _Traits(_Tr), _Flags(_Fx) { + : _Pat(_Pfirst), _End(_Plast), _Nfa(_Tr, _Fx), _Traits(_Tr), _Flags(_Fx) { constexpr unsigned long long _ECMA_flags = _L_ext_rep | _L_alt_pipe | _L_nex_grp | _L_nex_rep | _L_nc_grp | _L_asrt_gen | _L_asrt_wrd | _L_bckr | _L_ngr_rep | _L_esc_uni From 8adea0f73d609095773cb01df7ba46dd1cc73307 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20M=C3=BCller?= Date: Sun, 18 May 2025 13:22:48 +0200 Subject: [PATCH 05/21] reorder _Parser2 members to reduce padding --- stl/inc/regex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index ad240917085..89a5e587e73 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1838,11 +1838,11 @@ private: vector _Finished_grps; _Builder<_FwdIt, _Elem, _RxTraits> _Nfa; const _RxTraits& _Traits; + unsigned long long _L_flags; regex_constants::syntax_option_type _Flags; int _Val; - _Elem _Char; _Meta_type _Mchar; - unsigned long long _L_flags; + _Elem _Char; }; enum _Lang_flags2 : unsigned long long { // describe language properties From 3cefca79294d83c95ecdceb61c5b9b38646e5061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20M=C3=BCller?= Date: Sun, 18 May 2025 13:25:52 +0200 Subject: [PATCH 06/21] rename `_Builder` to `_Builder2` --- stl/inc/regex | 78 +++++++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index 89a5e587e73..24a60616f6f 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1574,9 +1574,9 @@ enum class _Rx_char_class_kind : int { // must be aligned with corresponding _No }; template -class _Builder { // provides operations used by _Parser2 to build the nfa +class _Builder2 { // provides operations used by _Parser2 to build the nfa public: - _Builder(const _RxTraits& _Tr, regex_constants::syntax_option_type); + _Builder2(const _RxTraits& _Tr, regex_constants::syntax_option_type); void _Setlong(); // _Discard_pattern is an ABI zombie name void _Tidy() noexcept; @@ -1624,7 +1624,7 @@ private: const int _Tmax; // TRANSITION, ABI: preserved for binary compatibility public: - _Builder& operator=(const _Builder&) = delete; + _Builder2& operator=(const _Builder2&) = delete; }; template @@ -1836,7 +1836,7 @@ private: unsigned int _Grp_idx = 0; int _Disj_count = 0; vector _Finished_grps; - _Builder<_FwdIt, _Elem, _RxTraits> _Nfa; + _Builder2<_FwdIt, _Elem, _RxTraits> _Nfa; const _RxTraits& _Traits; unsigned long long _L_flags; regex_constants::syntax_option_type _Flags; @@ -2837,28 +2837,28 @@ _EXPORT_STD using sregex_token_iterator = regex_token_iterator; template -_Builder<_FwdIt, _Elem, _RxTraits>::_Builder(const _RxTraits& _Tr, regex_constants::syntax_option_type _Fx) +_Builder2<_FwdIt, _Elem, _RxTraits>::_Builder2(const _RxTraits& _Tr, regex_constants::syntax_option_type _Fx) : _Root(new _Root_node), _Current(_Root), _Flags(_Fx), _Traits(_Tr), _Bmax(static_cast(_Fx & regex_constants::collate ? 0U : _Bmp_max)), _Tmax(static_cast(_Fx & regex_constants::collate ? 0U : _ARRAY_THRESHOLD)) {} template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Setlong() { // set flag +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Setlong() { // set flag _Root->_Flags |= _Fl_longest; } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Negate() { // set flag +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Negate() { // set flag _Current->_Flags ^= _Fl_negate; } template -_Node_base* _Builder<_FwdIt, _Elem, _RxTraits>::_Getmark() const { +_Node_base* _Builder2<_FwdIt, _Elem, _RxTraits>::_Getmark() const { return _Current; } template -_Node_base* _Builder<_FwdIt, _Elem, _RxTraits>::_Link_node(_Node_base* _Nx) { // insert _Nx at current location +_Node_base* _Builder2<_FwdIt, _Elem, _RxTraits>::_Link_node(_Node_base* _Nx) { // insert _Nx at current location _Nx->_Prev = _Current; if (_Current->_Next) { // set back pointer _Nx->_Next = _Current->_Next; @@ -2870,7 +2870,7 @@ _Node_base* _Builder<_FwdIt, _Elem, _RxTraits>::_Link_node(_Node_base* _Nx) { // } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Insert_node(_Node_base* _Insert_before, _Node_base* _To_insert) { +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Insert_node(_Node_base* _Insert_before, _Node_base* _To_insert) { // insert _To_insert into the graph before the node _Insert_before _Insert_before->_Prev->_Next = _To_insert; _To_insert->_Prev = _Insert_before->_Prev; @@ -2879,42 +2879,42 @@ void _Builder<_FwdIt, _Elem, _RxTraits>::_Insert_node(_Node_base* _Insert_before } template -_Node_base* _Builder<_FwdIt, _Elem, _RxTraits>::_New_node(_Node_type _Kind) { // allocate and link simple node +_Node_base* _Builder2<_FwdIt, _Elem, _RxTraits>::_New_node(_Node_type _Kind) { // allocate and link simple node return _Link_node(new _Node_base(_Kind)); } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_nop() { // add nop node +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_nop() { // add nop node _New_node(_N_nop); } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_bol() { // add bol node +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_bol() { // add bol node _New_node(_N_bol); } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_eol() { // add eol node +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_eol() { // add eol node _New_node(_N_eol); } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_wbound() { // add wbound node +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_wbound() { // add wbound node _New_node(_N_wbound); } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_dot() { // add dot node +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_dot() { // add dot node _New_node(_N_dot); } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_str_node() { // add string node +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_str_node() { // add string node _Link_node(new _Node_str<_Elem>); } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_char2(_Elem _Ch) { // append character +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_char2(_Elem _Ch) { // append character if (_Current->_Kind != _N_str) { _Add_str_node(); } @@ -2930,12 +2930,12 @@ void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_char2(_Elem _Ch) { // append chara } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_class() { // add bracket expression node +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_class() { // add bracket expression node _Link_node(new _Node_class<_Elem, _RxTraits>); } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_char_to_bitmap(_Elem _Ch) { // add character to accelerator table +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_char_to_bitmap(_Elem _Ch) { // add character to accelerator table if (_Flags & regex_constants::icase) { _Ch = _Traits.translate_nocase(_Ch); } @@ -2950,7 +2950,7 @@ void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_char_to_bitmap(_Elem _Ch) { // add } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_char_to_array(_Elem _Ch) { // append character to character array +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_char_to_array(_Elem _Ch) { // append character to character array if (_Flags & regex_constants::icase) { _Ch = _Traits.translate_nocase(_Ch); } @@ -2964,7 +2964,7 @@ void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_char_to_array(_Elem _Ch) { // appe } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_char_to_class(_Elem _Ch) { // add character to bracket expression +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_char_to_class(_Elem _Ch) { // add character to bracket expression if (static_cast(_Ch) < _Bmp_max) { _Add_char_to_bitmap(_Ch); } else { @@ -2973,7 +2973,7 @@ void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_char_to_class(_Elem _Ch) { // add } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_range3(const _Elem _Arg0, const _Elem _Arg1) { +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_range3(const _Elem _Arg0, const _Elem _Arg1) { // add character range to set using string_type = typename _RxTraits::string_type; unsigned int _Ex0 = static_cast(_Arg0); @@ -3032,7 +3032,7 @@ void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_range3(const _Elem _Arg0, const _E } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_elts( +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_elts( _Node_class<_Elem, _RxTraits>* _Node, typename _RxTraits::char_class_type _Cl, bool _Negate) { // add characters in named class to set for (unsigned int _Ch = 0; _Ch < _Bmp_max; ++_Ch) { // add elements or their inverse @@ -3048,7 +3048,7 @@ void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_elts( } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_named_class( +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_named_class( typename _RxTraits::char_class_type _Cl, const _Rx_char_class_kind _Kind) { // add contents of named class to bracket expression using _Char_class_type = typename _RxTraits::char_class_type; @@ -3073,7 +3073,7 @@ void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_named_class( } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Char_to_elts2(const _Elem* const _First, const _Elem* const _Last, +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Char_to_elts2(const _Elem* const _First, const _Elem* const _Last, _Sequence<_Elem>** _Cur) { // add collation element to element sequence auto _Diff = static_cast(_Last - _First); while (*_Cur && _Diff < (*_Cur)->_Sz) { @@ -3090,7 +3090,7 @@ void _Builder<_FwdIt, _Elem, _RxTraits>::_Char_to_elts2(const _Elem* const _Firs } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_equiv2(const _Elem* const _First, const _Elem* const _Last) { +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_equiv2(const _Elem* const _First, const _Elem* const _Last) { // add elements of equivalence class to bracket expression _Node_class<_Elem, _RxTraits>* _Node = static_cast<_Node_class<_Elem, _RxTraits>*>(_Current); typename _RxTraits::string_type _Str = _Traits.transform_primary(_First, _Last); @@ -3117,7 +3117,7 @@ void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_equiv2(const _Elem* const _First, } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_coll2(const _Elem* const _First, const _Elem* const _Last) { +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_coll2(const _Elem* const _First, const _Elem* const _Last) { // add collation element to bracket expression _Node_class<_Elem, _RxTraits>* _Node = static_cast<_Node_class<_Elem, _RxTraits>*>(_Current); _Sequence<_Elem>** _Cur = _STD addressof(_Node->_Coll); @@ -3125,12 +3125,12 @@ void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_coll2(const _Elem* const _First, c } template -_Node_base* _Builder<_FwdIt, _Elem, _RxTraits>::_Begin_group() { // add group node +_Node_base* _Builder2<_FwdIt, _Elem, _RxTraits>::_Begin_group() { // add group node return _New_node(_N_group); } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_End_group(_Node_base* _Back) { // add end of group node +void _Builder2<_FwdIt, _Elem, _RxTraits>::_End_group(_Node_base* _Back) { // add end of group node _Node_type _Elt; if (_Back->_Kind == _N_group) { _Elt = _N_end_group; @@ -3144,7 +3144,7 @@ void _Builder<_FwdIt, _Elem, _RxTraits>::_End_group(_Node_base* _Back) { // add } template -_Node_base* _Builder<_FwdIt, _Elem, _RxTraits>::_Begin_assert_group(const bool _Neg) { // add assert node +_Node_base* _Builder2<_FwdIt, _Elem, _RxTraits>::_Begin_assert_group(const bool _Neg) { // add assert node auto _Node1_unique = _STD make_unique<_Node_assert>(_Neg ? _N_neg_assert : _N_assert); _Node_base* _Node2 = new _Node_base(_N_nop); _Node_assert* _Node1 = _Node1_unique.release(); @@ -3156,23 +3156,23 @@ _Node_base* _Builder<_FwdIt, _Elem, _RxTraits>::_Begin_assert_group(const bool _ } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_End_assert_group(_Node_base* _Nx) { // add end of assert node +void _Builder2<_FwdIt, _Elem, _RxTraits>::_End_assert_group(_Node_base* _Nx) { // add end of assert node _End_group(_Nx); _Current = _Nx; } template -_Node_base* _Builder<_FwdIt, _Elem, _RxTraits>::_Begin_capture_group(unsigned int _Idx) { // add capture group node +_Node_base* _Builder2<_FwdIt, _Elem, _RxTraits>::_Begin_capture_group(unsigned int _Idx) { // add capture group node return _Link_node(new _Node_capture(_Idx)); } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_backreference(unsigned int _Idx) { // add back reference node +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_backreference(unsigned int _Idx) { // add back reference node _Link_node(new _Node_back(_Idx)); } template -_Node_base* _Builder<_FwdIt, _Elem, _RxTraits>::_Begin_if(_Node_base* _Start) { // add if node +_Node_base* _Builder2<_FwdIt, _Elem, _RxTraits>::_Begin_if(_Node_base* _Start) { // add if node // append endif node _Node_base* _Res = new _Node_endif; _Link_node(_Res); @@ -3185,7 +3185,7 @@ _Node_base* _Builder<_FwdIt, _Elem, _RxTraits>::_Begin_if(_Node_base* _Start) { } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Else_if(_Node_base* _Start, _Node_base* _End) { // add else node +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Else_if(_Node_base* _Start, _Node_base* _End) { // add else node _Node_if* _Parent = static_cast<_Node_if*>(_Start->_Next); _Node_base* _First = _End->_Next; _End->_Next = nullptr; @@ -3203,7 +3203,7 @@ void _Builder<_FwdIt, _Elem, _RxTraits>::_Else_if(_Node_base* _Start, _Node_base } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_rep2(int _Min, int _Max, bool _Greedy) { // add repeat node +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_rep2(int _Min, int _Max, bool _Greedy) { // add repeat node if (_Current->_Kind == _N_str && static_cast<_Node_str<_Elem>*>(_Current)->_Data._Size() != 1) { // move final character to new string node _Node_str<_Elem>* _Node = static_cast<_Node_str<_Elem>*>(_Current); @@ -3256,13 +3256,13 @@ void _Builder<_FwdIt, _Elem, _RxTraits>::_Add_rep2(int _Min, int _Max, bool _Gre } template -_Root_node* _Builder<_FwdIt, _Elem, _RxTraits>::_End_pattern() { // wrap up +_Root_node* _Builder2<_FwdIt, _Elem, _RxTraits>::_End_pattern() { // wrap up _New_node(_N_end); return _Root; } template -void _Builder<_FwdIt, _Elem, _RxTraits>::_Tidy() noexcept { // free memory +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Tidy() noexcept { // free memory _Destroy_node(_Root); _Root = nullptr; } From 1c0c01df65bfd16a6bac4ad302932e4d8d7d1b97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20M=C3=BCller?= Date: Sun, 18 May 2025 13:26:05 +0200 Subject: [PATCH 07/21] remove version numbers from member functions of `_Builder2` --- stl/inc/regex | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index 24a60616f6f..7ce568a59a6 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1590,10 +1590,10 @@ public: void _Add_char2(_Elem _Ch); void _Add_class(); void _Add_char_to_class(_Elem _Ch); - void _Add_range3(_Elem, _Elem); + void _Add_range(_Elem, _Elem); void _Add_named_class(typename _RxTraits::char_class_type, _Rx_char_class_kind); - void _Add_equiv2(const _Elem*, const _Elem*); - void _Add_coll2(const _Elem*, const _Elem*); + void _Add_equiv(const _Elem*, const _Elem*); + void _Add_coll(const _Elem*, const _Elem*); _Node_base* _Begin_group(); void _End_group(_Node_base* _Back); _Node_base* _Begin_assert_group(bool); @@ -1602,7 +1602,7 @@ public: void _Add_backreference(unsigned int _Idx); _Node_base* _Begin_if(_Node_base* _Start); void _Else_if(_Node_base*, _Node_base*); - void _Add_rep2(int _Min, int _Max, bool _Greedy); + void _Add_rep(int _Min, int _Max, bool _Greedy); void _Negate(); _Root_node* _End_pattern(); @@ -1614,7 +1614,7 @@ private: void _Add_char_to_bitmap(_Elem _Ch); void _Add_char_to_array(_Elem _Ch); void _Add_elts(_Node_class<_Elem, _RxTraits>*, typename _RxTraits::char_class_type, bool); - void _Char_to_elts2(const _Elem*, const _Elem*, _Sequence<_Elem>**); + void _Char_to_elts(const _Elem*, const _Elem*, _Sequence<_Elem>**); _Root_node* _Root; _Node_base* _Current; @@ -2973,7 +2973,7 @@ void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_char_to_class(_Elem _Ch) { // add } template -void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_range3(const _Elem _Arg0, const _Elem _Arg1) { +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_range(const _Elem _Arg0, const _Elem _Arg1) { // add character range to set using string_type = typename _RxTraits::string_type; unsigned int _Ex0 = static_cast(_Arg0); @@ -3073,7 +3073,7 @@ void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_named_class( } template -void _Builder2<_FwdIt, _Elem, _RxTraits>::_Char_to_elts2(const _Elem* const _First, const _Elem* const _Last, +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Char_to_elts(const _Elem* const _First, const _Elem* const _Last, _Sequence<_Elem>** _Cur) { // add collation element to element sequence auto _Diff = static_cast(_Last - _First); while (*_Cur && _Diff < (*_Cur)->_Sz) { @@ -3090,7 +3090,7 @@ void _Builder2<_FwdIt, _Elem, _RxTraits>::_Char_to_elts2(const _Elem* const _Fir } template -void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_equiv2(const _Elem* const _First, const _Elem* const _Last) { +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_equiv(const _Elem* const _First, const _Elem* const _Last) { // add elements of equivalence class to bracket expression _Node_class<_Elem, _RxTraits>* _Node = static_cast<_Node_class<_Elem, _RxTraits>*>(_Current); typename _RxTraits::string_type _Str = _Traits.transform_primary(_First, _Last); @@ -3112,16 +3112,16 @@ void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_equiv2(const _Elem* const _First, } if (_Bmp_max < static_cast(_STD _Max_limit<_Elem>())) { // map range _Sequence<_Elem>** _Cur = _STD addressof(_Node->_Equiv); - _Char_to_elts2(_First, _Last, _Cur); + _Char_to_elts(_First, _Last, _Cur); } } template -void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_coll2(const _Elem* const _First, const _Elem* const _Last) { +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_coll(const _Elem* const _First, const _Elem* const _Last) { // add collation element to bracket expression _Node_class<_Elem, _RxTraits>* _Node = static_cast<_Node_class<_Elem, _RxTraits>*>(_Current); _Sequence<_Elem>** _Cur = _STD addressof(_Node->_Coll); - _Char_to_elts2(_First, _Last, _Cur); + _Char_to_elts(_First, _Last, _Cur); } template @@ -3203,7 +3203,7 @@ void _Builder2<_FwdIt, _Elem, _RxTraits>::_Else_if(_Node_base* _Start, _Node_bas } template -void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_rep2(int _Min, int _Max, bool _Greedy) { // add repeat node +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_rep(int _Min, int _Max, bool _Greedy) { // add repeat node if (_Current->_Kind == _N_str && static_cast<_Node_str<_Elem>*>(_Current)->_Data._Size() != 1) { // move final character to new string node _Node_str<_Elem>* _Node = static_cast<_Node_str<_Elem>*>(_Current); @@ -4391,13 +4391,13 @@ _Prs_ret _Parser2<_FwdIt, _Elem, _RxTraits>::_Do_ex_class( } if (_End_arg == _Meta_equal) { // process equivalence - _Nfa._Add_equiv2(_Coll_elem_first, _Coll_elem_last); + _Nfa._Add_equiv(_Coll_elem_first, _Coll_elem_last); return _Prs_set; } else { // process collating element // Character ranges with multi-character bounds cannot be represented in NFA nodes yet (see GH-5391). // Provisionally treat multi-character collating elements as character sets. - _Nfa._Add_coll2(_Coll_elem_first, _Coll_elem_last); + _Nfa._Add_coll(_Coll_elem_first, _Coll_elem_last); return _Prs_set; } } @@ -4524,7 +4524,7 @@ void _Parser2<_FwdIt, _Elem, _RxTraits>::_ClassRanges() { // check for valid cla _Chr2 = _Traits.translate(_Chr2); } - _Nfa._Add_range3(_Chr1, _Chr2); + _Nfa._Add_range(_Chr1, _Chr2); } else if (_Ret == _Prs_chr) { _Nfa._Add_char_to_class(static_cast<_Elem>(_Val)); } @@ -4809,7 +4809,7 @@ void _Parser2<_FwdIt, _Elem, _RxTraits>::_Quantifier() { // check for quantifier _Next(); } - _Nfa._Add_rep2(_Min, _Max, _Greedy); + _Nfa._Add_rep(_Min, _Max, _Greedy); } template From 7d9748a1b17ac2752f0fb6f9b655cc9cd9f6433d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20M=C3=BCller?= Date: Sun, 18 May 2025 13:31:23 +0200 Subject: [PATCH 08/21] remove obsolete member variables from `_Builder2` --- stl/inc/regex | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index 7ce568a59a6..5e5fa084c2a 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1620,8 +1620,6 @@ private: _Node_base* _Current; regex_constants::syntax_option_type _Flags; const _RxTraits& _Traits; - const int _Bmax; // TRANSITION, ABI: preserved for binary compatibility - const int _Tmax; // TRANSITION, ABI: preserved for binary compatibility public: _Builder2& operator=(const _Builder2&) = delete; @@ -2838,9 +2836,7 @@ _EXPORT_STD using wsregex_token_iterator = regex_token_iterator _Builder2<_FwdIt, _Elem, _RxTraits>::_Builder2(const _RxTraits& _Tr, regex_constants::syntax_option_type _Fx) - : _Root(new _Root_node), _Current(_Root), _Flags(_Fx), _Traits(_Tr), - _Bmax(static_cast(_Fx & regex_constants::collate ? 0U : _Bmp_max)), - _Tmax(static_cast(_Fx & regex_constants::collate ? 0U : _ARRAY_THRESHOLD)) {} + : _Root(new _Root_node), _Current(_Root), _Flags(_Fx), _Traits(_Tr) {} template void _Builder2<_FwdIt, _Elem, _RxTraits>::_Setlong() { // set flag From 5fbd5b1f59ba4372126438e2c9b3f62692d66329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20M=C3=BCller?= Date: Sun, 18 May 2025 13:32:57 +0200 Subject: [PATCH 09/21] do not escape parentheses and braces in bracket expressions in basic or grep mode --- stl/inc/regex | 9 +++-- .../GH_005244_regex_escape_sequences/test.cpp | 35 +++++++++++++------ 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index 5e5fa084c2a..d2e842cd309 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1782,6 +1782,8 @@ enum _Prs_ret { // indicate class element type _Prs_set }; +enum class _Lex_mode : unsigned char { _Default, _Character_class }; + template class _Parser2 { // parse a regular expression public: @@ -1840,6 +1842,7 @@ private: regex_constants::syntax_option_type _Flags; int _Val; _Meta_type _Mchar; + _Lex_mode _Mode; _Elem _Char; }; @@ -4162,7 +4165,7 @@ template template bool _Parser2<_FwdIt, _Elem, _RxTraits>::_Is_esc(_FwdIt _Ch0) const { // assumes _Ch0 != _End - return ++_Ch0 != _End + return _Mode == _Lex_mode::_Default && ++_Ch0 != _End && ((!(_L_flags & _L_nex_grp) && (*_Ch0 == _Meta_lpar || *_Ch0 == _Meta_rpar)) || (!(_L_flags & _L_nex_rep) && (*_Ch0 == _Meta_lbr || *_Ch0 == _Meta_rbr))); } @@ -4835,8 +4838,10 @@ bool _Parser2<_FwdIt, _Elem, _RxTraits>::_Alternative() { // check for valid alt _AtomEscape(); } } else if (_Mchar == _Meta_lsq) { // add bracket expression + _Mode = _Lex_mode::_Character_class; _Next(); _CharacterClass(); + _Mode = _Lex_mode::_Default; _Expect(_Meta_rsq, regex_constants::error_brack); } else if (_Mchar == _Meta_lpar) { // check for valid group _Next(); @@ -5008,7 +5013,7 @@ _Root_node* _Parser2<_FwdIt, _Elem, _RxTraits>::_Compile() { // compile regular template _Parser2<_FwdIt, _Elem, _RxTraits>::_Parser2( const _RxTraits& _Tr, _FwdIt _Pfirst, _FwdIt _Plast, regex_constants::syntax_option_type _Fx) - : _Pat(_Pfirst), _End(_Plast), _Nfa(_Tr, _Fx), _Traits(_Tr), _Flags(_Fx) { + : _Pat(_Pfirst), _End(_Plast), _Nfa(_Tr, _Fx), _Traits(_Tr), _Flags(_Fx), _Mode(_Lex_mode::_Default) { constexpr unsigned long long _ECMA_flags = _L_ext_rep | _L_alt_pipe | _L_nex_grp | _L_nex_rep | _L_nc_grp | _L_asrt_gen | _L_asrt_wrd | _L_bckr | _L_ngr_rep | _L_esc_uni diff --git a/tests/std/tests/GH_005244_regex_escape_sequences/test.cpp b/tests/std/tests/GH_005244_regex_escape_sequences/test.cpp index 7747befd700..cb5752a3073 100644 --- a/tests/std/tests/GH_005244_regex_escape_sequences/test.cpp +++ b/tests/std/tests/GH_005244_regex_escape_sequences/test.cpp @@ -632,22 +632,15 @@ void test_gh_5244_classescape_posix_not_awk(syntax_option_type option) { check_classescape_noescape("?", option); check_classescape_noescape("|", option); - // TRANSITION, GH-5379 - if (option & (extended | egrep)) { - check_classescape_noescape("(", option); - check_classescape_noescape(")", option); - check_classescape_noescape("{", option); - } + check_classescape_noescape("(", option); + check_classescape_noescape(")", option); + check_classescape_noescape("{", option); // closing characters that are not considered special g_regexTester.should_match("\\]", R"([\]])", option); g_regexTester.should_not_match("]", R"([\]])", option); g_regexTester.should_not_match("\\", R"([\]])", option); - - // TRANSITION, GH-5379 - if (option & (extended | egrep)) { - check_classescape_noescape("}", option); - } + check_classescape_noescape("}", option); // awk escape sequences check_classescape_noescape("a", option); @@ -882,8 +875,28 @@ void test_gh_5244() { test_gh_5244_classescape_awk(); } +void test_gh_5379() { + // GH-5379: Backslashes in character classes are sometimes not matched in basic regular expressions + + // Correct handling of these backslashes at the beginning of a character class is already covered by GH-5244 tests. + // The following tests check that backslashes are handled correctly immediately after a bracketed character class. + for (syntax_option_type syntax : {basic, grep}) { + g_regexTester.should_throw(R"([a]\b)", error_escape, syntax); + g_regexTester.should_match("a[b]", R"([a]\[b])", syntax); + g_regexTester.should_match("a", R"(\([a]\))", syntax); + g_regexTester.should_match("ab", R"([a]\(b\))", syntax); + g_regexTester.should_match("a", R"([a]\{1\})", syntax); + g_regexTester.should_throw(R"([a]\})", error_brace, syntax); + + // also check handling of identity escape "\]", + // which is supported as an extension following more recent POSIX standards + g_regexTester.should_match("a]", R"([a]\])", syntax); + } +} + int main() { test_gh_5244(); + test_gh_5379(); return g_regexTester.result(); } From ccc071b80d1ee29eba255151971cc018b00527e0 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 22 May 2025 02:33:39 -0700 Subject: [PATCH 10/21] Rename `_Builder2::_Add_char2` back to `_Add_char`. --- stl/inc/regex | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index d2e842cd309..dd4d6795819 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1587,7 +1587,7 @@ public: void _Add_eol(); void _Add_wbound(); void _Add_dot(); - void _Add_char2(_Elem _Ch); + void _Add_char(_Elem _Ch); void _Add_class(); void _Add_char_to_class(_Elem _Ch); void _Add_range(_Elem, _Elem); @@ -2913,7 +2913,7 @@ void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_str_node() { // add string node } template -void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_char2(_Elem _Ch) { // append character +void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_char(_Elem _Ch) { // append character if (_Current->_Kind != _N_str) { _Add_str_node(); } @@ -3207,7 +3207,7 @@ void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_rep(int _Min, int _Max, bool _Gre && static_cast<_Node_str<_Elem>*>(_Current)->_Data._Size() != 1) { // move final character to new string node _Node_str<_Elem>* _Node = static_cast<_Node_str<_Elem>*>(_Current); _Add_str_node(); - _Add_char2(_Node->_Data._Del()); + _Add_char(_Node->_Data._Del()); } _Node_base* _Pos = _Current; @@ -4743,7 +4743,7 @@ void _Parser2<_FwdIt, _Elem, _RxTraits>::_AtomEscape() { // check for valid atom if (_Traits.value(_Char, 10) != -1) { _Error(regex_constants::error_escape); } - _Nfa._Add_char2(_Elem{}); + _Nfa._Add_char(_Elem{}); } else if (_L_flags & _L_bckr) { // check for valid backreference if (!(_L_flags & _L_lim_bckr)) { (void) _DecimalDigits(regex_constants::error_backref, _Val); @@ -4759,7 +4759,7 @@ void _Parser2<_FwdIt, _Elem, _RxTraits>::_AtomEscape() { // check for valid atom } } } else if (_CharacterEscape(false)) { - _Nfa._Add_char2(static_cast<_Elem>(_Val)); + _Nfa._Add_char(static_cast<_Elem>(_Val)); } else if (!(_L_flags & _L_esc_wsd) || !_CharacterClassEscape(true)) { _Error(regex_constants::error_escape); } @@ -4851,7 +4851,7 @@ bool _Parser2<_FwdIt, _Elem, _RxTraits>::_Alternative() { // check for valid alt _Nfa._Add_bol(); _Next(); if ((_L_flags & _L_star_beg) && _Mchar == _Meta_star && !_Found) { - _Nfa._Add_char2(_Char); + _Nfa._Add_char(_Char); _Next(); } else { _Quant = false; @@ -4868,7 +4868,7 @@ bool _Parser2<_FwdIt, _Elem, _RxTraits>::_Alternative() { // check for valid alt } else if (_Mchar == _Meta_rsq && !(_L_flags & _L_brk_bal)) { _Error(regex_constants::error_brack); } else { // add character - _Nfa._Add_char2(_Char); + _Nfa._Add_char(_Char); _Next(); } From 8a92b64f8cced769f3d7626b7935f1467a795b18 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 22 May 2025 02:35:16 -0700 Subject: [PATCH 11/21] Drop "ABI zombie name" comment. --- stl/inc/regex | 1 - 1 file changed, 1 deletion(-) diff --git a/stl/inc/regex b/stl/inc/regex index dd4d6795819..9d464df5f92 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1578,7 +1578,6 @@ class _Builder2 { // provides operations used by _Parser2 to build the nfa public: _Builder2(const _RxTraits& _Tr, regex_constants::syntax_option_type); void _Setlong(); - // _Discard_pattern is an ABI zombie name void _Tidy() noexcept; _Node_base* _Getmark() const; From b6651d8c2dae153ea74b6046a8e1334d925ab6b0 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 22 May 2025 02:42:12 -0700 Subject: [PATCH 12/21] Delete copy ctors for `_Builder2` and `_Matcher2`. --- stl/inc/regex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stl/inc/regex b/stl/inc/regex index 9d464df5f92..1fd2309c5f4 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1621,6 +1621,7 @@ private: const _RxTraits& _Traits; public: + _Builder2(const _Builder2&) = delete; _Builder2& operator=(const _Builder2&) = delete; }; @@ -1772,6 +1773,7 @@ private: typename _RxTraits::char_class_type _Char_class_d{}; public: + _Matcher2(const _Matcher2&) = delete; _Matcher2& operator=(const _Matcher2&) = delete; }; From e32b28b91f87fa11d7dd36944632420db60e3101 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 22 May 2025 03:06:40 -0700 Subject: [PATCH 13/21] `_Builder2::_Add_nop` was unused. --- stl/inc/regex | 6 ------ 1 file changed, 6 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index 1fd2309c5f4..e8299da406b 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1581,7 +1581,6 @@ public: void _Tidy() noexcept; _Node_base* _Getmark() const; - void _Add_nop(); void _Add_bol(); void _Add_eol(); void _Add_wbound(); @@ -2883,11 +2882,6 @@ _Node_base* _Builder2<_FwdIt, _Elem, _RxTraits>::_New_node(_Node_type _Kind) { / return _Link_node(new _Node_base(_Kind)); } -template -void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_nop() { // add nop node - _New_node(_N_nop); -} - template void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_bol() { // add bol node _New_node(_N_bol); From 260cbce022e2696fbe9ff2dc6aa919465e1fe919 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 22 May 2025 03:07:03 -0700 Subject: [PATCH 14/21] Avoid shadowing in `_Builder2`: `_Negate` => `_Negative` --- stl/inc/regex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index e8299da406b..b3e32a62934 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -3027,11 +3027,11 @@ void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_range(const _Elem _Arg0, const _E template void _Builder2<_FwdIt, _Elem, _RxTraits>::_Add_elts( - _Node_class<_Elem, _RxTraits>* _Node, typename _RxTraits::char_class_type _Cl, bool _Negate) { + _Node_class<_Elem, _RxTraits>* _Node, typename _RxTraits::char_class_type _Cl, bool _Negative) { // add characters in named class to set for (unsigned int _Ch = 0; _Ch < _Bmp_max; ++_Ch) { // add elements or their inverse bool _Matches = _Traits.isctype(static_cast<_Elem>(_Ch), _Cl); - if (_Matches != _Negate) { // add contents of named class to accelerator table + if (_Matches != _Negative) { // add contents of named class to accelerator table if (!_Node->_Small) { _Node->_Small = new _Bitmap; } From 43c3235becc7c965f9a509b7d61b767a2545bc86 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 22 May 2025 03:13:36 -0700 Subject: [PATCH 15/21] `_Parser2::char_class_type` was unused. --- stl/inc/regex | 2 -- 1 file changed, 2 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index b3e32a62934..c572fe31b4f 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1787,8 +1787,6 @@ enum class _Lex_mode : unsigned char { _Default, _Character_class }; template class _Parser2 { // parse a regular expression public: - using char_class_type = typename _RxTraits::char_class_type; - _Parser2(const _RxTraits& _Tr, _FwdIt _Pfirst, _FwdIt _Plast, regex_constants::syntax_option_type _Fx); _Root_node* _Compile(); From 50204cb1071d2b336ed34f2239bf6040dac92fef Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 22 May 2025 03:17:02 -0700 Subject: [PATCH 16/21] `_Parser2::_Mark_count` can be private. --- stl/inc/regex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/regex b/stl/inc/regex index c572fe31b4f..fc11ef61b50 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1790,11 +1790,11 @@ public: _Parser2(const _RxTraits& _Tr, _FwdIt _Pfirst, _FwdIt _Plast, regex_constants::syntax_option_type _Fx); _Root_node* _Compile(); +private: unsigned int _Mark_count() const noexcept { return _Grp_idx + 1; } -private: // lexing [[noreturn]] void _Error(regex_constants::error_type); From 4fba27c14a8a06ca6e817e0bed4dc779311ebaa6 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 22 May 2025 05:06:46 -0700 Subject: [PATCH 17/21] Use a data member initializer for `_Lex_mode _Mode`. --- stl/inc/regex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index fc11ef61b50..e73454755a5 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1840,7 +1840,7 @@ private: regex_constants::syntax_option_type _Flags; int _Val; _Meta_type _Mchar; - _Lex_mode _Mode; + _Lex_mode _Mode = _Lex_mode::_Default; _Elem _Char; }; @@ -5006,7 +5006,7 @@ _Root_node* _Parser2<_FwdIt, _Elem, _RxTraits>::_Compile() { // compile regular template _Parser2<_FwdIt, _Elem, _RxTraits>::_Parser2( const _RxTraits& _Tr, _FwdIt _Pfirst, _FwdIt _Plast, regex_constants::syntax_option_type _Fx) - : _Pat(_Pfirst), _End(_Plast), _Nfa(_Tr, _Fx), _Traits(_Tr), _Flags(_Fx), _Mode(_Lex_mode::_Default) { + : _Pat(_Pfirst), _End(_Plast), _Nfa(_Tr, _Fx), _Traits(_Tr), _Flags(_Fx) { constexpr unsigned long long _ECMA_flags = _L_ext_rep | _L_alt_pipe | _L_nex_grp | _L_nex_rep | _L_nc_grp | _L_asrt_gen | _L_asrt_wrd | _L_bckr | _L_ngr_rep | _L_esc_uni From 5e0151dfbe85ed97187bb245ee2cc31928df9e6a Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 22 May 2025 05:32:57 -0700 Subject: [PATCH 18/21] Meld `_L_nc_grp` and `_L_asrt_gen` into `_L_nc_asrt`, improve comments. --- stl/inc/regex | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index e73454755a5..e83ee402c4e 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1850,8 +1850,7 @@ enum _Lang_flags2 : unsigned long long { // describe language properties _L_alt_nl = 0x000000004ULL, // uses '\n' for alternation (grep, egrep) _L_nex_grp = 0x000000008ULL, // has non-escaped capture groups _L_nex_rep = 0x000000010ULL, // has non-escaped repeats - _L_nc_grp = 0x000000020ULL, // has non-capture groups (?:xxx) - _L_asrt_gen = 0x000000040ULL, // has generalized assertions (?=xxx), (?!xxx) + _L_nc_asrt = 0x000000020ULL, // has non-capture groups (?:xxx) and generalized assertions (?=xxx), (?!xxx) _L_asrt_wrd = 0x000000080ULL, // has word boundary assertions (\b, \B) _L_bckr = 0x000000100ULL, // has backreferences (ERE doesn't) _L_lim_bckr = 0x000000200ULL, // has limited backreferences (BRE \1-\9) @@ -4568,17 +4567,17 @@ bool _Parser2<_FwdIt, _Elem, _RxTraits>::_Wrapped_disjunction() { // add disjunc ++_Disj_count; if (!(_L_flags & _L_empty_grp) && _Mchar == _Meta_rpar) { _Error(regex_constants::error_paren); - } else if ((_L_flags & _L_nc_grp) && _Mchar == _Meta_query) { // check for valid ECMAScript (?x ... ) group + } else if ((_L_flags & _L_nc_asrt) && _Mchar == _Meta_query) { // check for valid ECMAScript (?x ... ) group _Next(); _Meta_type _Ch = _Mchar; _Next(); - if (_Ch == _Meta_colon) { + if (_Ch == _Meta_colon) { // process non-capture group (?:meow) _Do_noncapture_group(); - } else if (_Ch == _Meta_exc) { // process assert group, negating + } else if (_Ch == _Meta_exc) { // process negative lookahead assertion (?!meow) _Do_assert_group(true); --_Disj_count; return false; - } else if (_Ch == _Meta_equal) { // process assert group + } else if (_Ch == _Meta_equal) { // process positive lookahead assertion (?=meow) _Do_assert_group(false); --_Disj_count; return false; @@ -5008,10 +5007,10 @@ _Parser2<_FwdIt, _Elem, _RxTraits>::_Parser2( const _RxTraits& _Tr, _FwdIt _Pfirst, _FwdIt _Plast, regex_constants::syntax_option_type _Fx) : _Pat(_Pfirst), _End(_Plast), _Nfa(_Tr, _Fx), _Traits(_Tr), _Flags(_Fx) { - constexpr unsigned long long _ECMA_flags = _L_ext_rep | _L_alt_pipe | _L_nex_grp | _L_nex_rep | _L_nc_grp - | _L_asrt_gen | _L_asrt_wrd | _L_bckr | _L_ngr_rep | _L_esc_uni - | _L_esc_hex | _L_esc_bsp | _L_esc_ffn | _L_esc_wsd | _L_esc_ctrl - | _L_bzr_chr | _L_grp_esc | _L_ident_ECMA | _L_empty_grp; + constexpr unsigned long long _ECMA_flags = _L_ext_rep | _L_alt_pipe | _L_nex_grp | _L_nex_rep | _L_nc_asrt + | _L_asrt_wrd | _L_bckr | _L_ngr_rep | _L_esc_uni | _L_esc_hex | _L_esc_bsp + | _L_esc_ffn | _L_esc_wsd | _L_esc_ctrl | _L_bzr_chr | _L_grp_esc + | _L_ident_ECMA | _L_empty_grp; constexpr unsigned long long _Basic_flags = _L_bckr | _L_lim_bckr | _L_anch_rstr | _L_star_beg | _L_empty_grp | _L_brk_bal | _L_brk_rstr | _L_dsh_rstr | _L_mtch_long; From cfaf2df16f37540c9b5b316bfb9edc0bdeb287b7 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 22 May 2025 05:36:58 -0700 Subject: [PATCH 19/21] Renumber `_Lang_flags2`. --- stl/inc/regex | 52 +++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index e83ee402c4e..5ea107724dc 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1851,32 +1851,32 @@ enum _Lang_flags2 : unsigned long long { // describe language properties _L_nex_grp = 0x000000008ULL, // has non-escaped capture groups _L_nex_rep = 0x000000010ULL, // has non-escaped repeats _L_nc_asrt = 0x000000020ULL, // has non-capture groups (?:xxx) and generalized assertions (?=xxx), (?!xxx) - _L_asrt_wrd = 0x000000080ULL, // has word boundary assertions (\b, \B) - _L_bckr = 0x000000100ULL, // has backreferences (ERE doesn't) - _L_lim_bckr = 0x000000200ULL, // has limited backreferences (BRE \1-\9) - _L_ngr_rep = 0x000000400ULL, // has non-greedy repeats - _L_esc_uni = 0x000000800ULL, // has Unicode escape sequences - _L_esc_hex = 0x000001000ULL, // has hexadecimal escape sequences - _L_esc_oct = 0x000002000ULL, // has octal escape sequences - _L_esc_bsp = 0x000004000ULL, // has backspace escape in character classes - _L_esc_ffnx = 0x000008000ULL, // has extra file escapes (\a and \b) - _L_esc_ffn = 0x000010000ULL, // has limited file escapes (\[fnrtv]) - _L_esc_wsd = 0x000020000ULL, // has w, s, and d character set escapes - _L_esc_ctrl = 0x000040000ULL, // has control escape - _L_no_nl = 0x000080000ULL, // no newline in pattern or matching text - _L_bzr_chr = 0x000100000ULL, // \0 is a valid character constant - _L_grp_esc = 0x000200000ULL, // \ is special character in group - _L_ident_ECMA = 0x000400000ULL, // ECMA identity escape (not identifierpart) - _L_ident_ERE = 0x000800000ULL, // ERE identity escape (.[\*^$, plus {+?}() - _L_ident_awk = 0x001000000ULL, // awk identity escape ( ERE plus "/) - _L_anch_rstr = 0x002000000ULL, // anchor restricted to beginning/end - _L_star_beg = 0x004000000ULL, // star okay at beginning of RE/expr (BRE) - _L_empty_grp = 0x008000000ULL, // empty group allowed (ERE prohibits "()") - _L_paren_bal = 0x010000000ULL, // ')'/'}' special only after '('/'{' - _L_brk_bal = 0x020000000ULL, // ']' special only after '[' (ERE, BRE) - _L_brk_rstr = 0x040000000ULL, // ']' not special when first character in set - _L_dsh_rstr = 0x080000000ULL, // '-' forbidden at range start in set except when first character (ERE, BRE) - _L_mtch_long = 0x100000000ULL, // find longest match (ERE, BRE) + _L_asrt_wrd = 0x000000040ULL, // has word boundary assertions (\b, \B) + _L_bckr = 0x000000080ULL, // has backreferences (ERE doesn't) + _L_lim_bckr = 0x000000100ULL, // has limited backreferences (BRE \1-\9) + _L_ngr_rep = 0x000000200ULL, // has non-greedy repeats + _L_esc_uni = 0x000000400ULL, // has Unicode escape sequences + _L_esc_hex = 0x000000800ULL, // has hexadecimal escape sequences + _L_esc_oct = 0x000001000ULL, // has octal escape sequences + _L_esc_bsp = 0x000002000ULL, // has backspace escape in character classes + _L_esc_ffnx = 0x000004000ULL, // has extra file escapes (\a and \b) + _L_esc_ffn = 0x000008000ULL, // has limited file escapes (\[fnrtv]) + _L_esc_wsd = 0x000010000ULL, // has w, s, and d character set escapes + _L_esc_ctrl = 0x000020000ULL, // has control escape + _L_no_nl = 0x000040000ULL, // no newline in pattern or matching text + _L_bzr_chr = 0x000080000ULL, // \0 is a valid character constant + _L_grp_esc = 0x000100000ULL, // \ is special character in group + _L_ident_ECMA = 0x000200000ULL, // ECMA identity escape (not identifierpart) + _L_ident_ERE = 0x000400000ULL, // ERE identity escape (.[\*^$, plus {+?}() + _L_ident_awk = 0x000800000ULL, // awk identity escape ( ERE plus "/) + _L_anch_rstr = 0x001000000ULL, // anchor restricted to beginning/end + _L_star_beg = 0x002000000ULL, // star okay at beginning of RE/expr (BRE) + _L_empty_grp = 0x004000000ULL, // empty group allowed (ERE prohibits "()") + _L_paren_bal = 0x008000000ULL, // ')'/'}' special only after '('/'{' + _L_brk_bal = 0x010000000ULL, // ']' special only after '[' (ERE, BRE) + _L_brk_rstr = 0x020000000ULL, // ']' not special when first character in set + _L_dsh_rstr = 0x040000000ULL, // '-' forbidden at range start in set except when first character (ERE, BRE) + _L_mtch_long = 0x080000000ULL, // find longest match (ERE, BRE) }; class _Regex_base : public _Container_base { // base class for basic_regex to construct and destroy proxy From 4f84d6db86340e05ef0d227d7de4028e262c240c Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 22 May 2025 06:12:48 -0700 Subject: [PATCH 20/21] Improve `_Lang_flags2` comments. Use muellerj2's superior descriptions of `_L_alt_nl` and `_L_no_nl`. Note that `_L_no_nl` is (grep, egrep). Note that `_L_esc_oct` and `_L_esc_ffnx` are (awk). `_L_esc_ffn` confusingly said "(\[fnrtv])" when other comments like `_L_ident_ERE` mean square brackets literally. Spell out "(\f \n \r \t \v)" for clarity and improved searchability. Rephrase `_L_ident_awk`'s comment for clarity. Note that `_L_anch_rstr` is (BRE) only, `_L_paren_bal` is (ERE) only, and `_L_brk_rstr` is (ERE, BRE). --- stl/inc/regex | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index 5ea107724dc..045ca9b605e 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1847,7 +1847,7 @@ private: enum _Lang_flags2 : unsigned long long { // describe language properties _L_ext_rep = 0x000000001ULL, // + and ? repetitions _L_alt_pipe = 0x000000002ULL, // uses '|' for alternation - _L_alt_nl = 0x000000004ULL, // uses '\n' for alternation (grep, egrep) + _L_alt_nl = 0x000000004ULL, // newlines outside parentheses/brackets represent alternations (grep, egrep) _L_nex_grp = 0x000000008ULL, // has non-escaped capture groups _L_nex_rep = 0x000000010ULL, // has non-escaped repeats _L_nc_asrt = 0x000000020ULL, // has non-capture groups (?:xxx) and generalized assertions (?=xxx), (?!xxx) @@ -1857,24 +1857,24 @@ enum _Lang_flags2 : unsigned long long { // describe language properties _L_ngr_rep = 0x000000200ULL, // has non-greedy repeats _L_esc_uni = 0x000000400ULL, // has Unicode escape sequences _L_esc_hex = 0x000000800ULL, // has hexadecimal escape sequences - _L_esc_oct = 0x000001000ULL, // has octal escape sequences + _L_esc_oct = 0x000001000ULL, // has octal escape sequences (awk) _L_esc_bsp = 0x000002000ULL, // has backspace escape in character classes - _L_esc_ffnx = 0x000004000ULL, // has extra file escapes (\a and \b) - _L_esc_ffn = 0x000008000ULL, // has limited file escapes (\[fnrtv]) + _L_esc_ffnx = 0x000004000ULL, // has extra file escapes (\a and \b) (awk) + _L_esc_ffn = 0x000008000ULL, // has limited file escapes (\f \n \r \t \v) _L_esc_wsd = 0x000010000ULL, // has w, s, and d character set escapes _L_esc_ctrl = 0x000020000ULL, // has control escape - _L_no_nl = 0x000040000ULL, // no newline in pattern or matching text + _L_no_nl = 0x000040000ULL, // newlines within parentheses/brackets are syntax errors (grep, egrep) _L_bzr_chr = 0x000080000ULL, // \0 is a valid character constant _L_grp_esc = 0x000100000ULL, // \ is special character in group _L_ident_ECMA = 0x000200000ULL, // ECMA identity escape (not identifierpart) _L_ident_ERE = 0x000400000ULL, // ERE identity escape (.[\*^$, plus {+?}() - _L_ident_awk = 0x000800000ULL, // awk identity escape ( ERE plus "/) - _L_anch_rstr = 0x001000000ULL, // anchor restricted to beginning/end + _L_ident_awk = 0x000800000ULL, // awk identity escape (awk additionally supports " and / characters) + _L_anch_rstr = 0x001000000ULL, // anchor restricted to beginning/end (BRE) _L_star_beg = 0x002000000ULL, // star okay at beginning of RE/expr (BRE) _L_empty_grp = 0x004000000ULL, // empty group allowed (ERE prohibits "()") - _L_paren_bal = 0x008000000ULL, // ')'/'}' special only after '('/'{' + _L_paren_bal = 0x008000000ULL, // ')'/'}' special only after '('/'{' (ERE) _L_brk_bal = 0x010000000ULL, // ']' special only after '[' (ERE, BRE) - _L_brk_rstr = 0x020000000ULL, // ']' not special when first character in set + _L_brk_rstr = 0x020000000ULL, // ']' not special when first character in set (ERE, BRE) _L_dsh_rstr = 0x040000000ULL, // '-' forbidden at range start in set except when first character (ERE, BRE) _L_mtch_long = 0x080000000ULL, // find longest match (ERE, BRE) }; From e9eb1c67c1d1a73ad5a35a98f9ded0986f83ec43 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 22 May 2025 06:21:45 -0700 Subject: [PATCH 21/21] Rename to `_L_non_greedy`. --- stl/inc/regex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index 045ca9b605e..3e7e51b2f27 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1854,7 +1854,7 @@ enum _Lang_flags2 : unsigned long long { // describe language properties _L_asrt_wrd = 0x000000040ULL, // has word boundary assertions (\b, \B) _L_bckr = 0x000000080ULL, // has backreferences (ERE doesn't) _L_lim_bckr = 0x000000100ULL, // has limited backreferences (BRE \1-\9) - _L_ngr_rep = 0x000000200ULL, // has non-greedy repeats + _L_non_greedy = 0x000000200ULL, // has non-greedy repeats _L_esc_uni = 0x000000400ULL, // has Unicode escape sequences _L_esc_hex = 0x000000800ULL, // has hexadecimal escape sequences _L_esc_oct = 0x000001000ULL, // has octal escape sequences (awk) @@ -4795,7 +4795,7 @@ void _Parser2<_FwdIt, _Elem, _RxTraits>::_Quantifier() { // check for quantifier } _Next(); - const bool _Greedy = !(_L_flags & _L_ngr_rep) || _Mchar != _Meta_query; + const bool _Greedy = !(_L_flags & _L_non_greedy) || _Mchar != _Meta_query; if (!_Greedy) { // add non-greedy repeat node _Next(); } @@ -5008,9 +5008,9 @@ _Parser2<_FwdIt, _Elem, _RxTraits>::_Parser2( : _Pat(_Pfirst), _End(_Plast), _Nfa(_Tr, _Fx), _Traits(_Tr), _Flags(_Fx) { constexpr unsigned long long _ECMA_flags = _L_ext_rep | _L_alt_pipe | _L_nex_grp | _L_nex_rep | _L_nc_asrt - | _L_asrt_wrd | _L_bckr | _L_ngr_rep | _L_esc_uni | _L_esc_hex | _L_esc_bsp - | _L_esc_ffn | _L_esc_wsd | _L_esc_ctrl | _L_bzr_chr | _L_grp_esc - | _L_ident_ECMA | _L_empty_grp; + | _L_asrt_wrd | _L_bckr | _L_non_greedy | _L_esc_uni | _L_esc_hex + | _L_esc_bsp | _L_esc_ffn | _L_esc_wsd | _L_esc_ctrl | _L_bzr_chr + | _L_grp_esc | _L_ident_ECMA | _L_empty_grp; constexpr unsigned long long _Basic_flags = _L_bckr | _L_lim_bckr | _L_anch_rstr | _L_star_beg | _L_empty_grp | _L_brk_bal | _L_brk_rstr | _L_dsh_rstr | _L_mtch_long;