syntax2.h
上传用户:dzyhzl
上传日期:2019-04-29
资源大小:56270k
文件大小:31k
源码类别:

模拟服务器

开发平台:

C/C++

  1. //+---------------------------------------------------------------------------
  2. //
  3. //  Copyright ( C ) Microsoft Corporation, 1994 - 2002.
  4. //
  5. //  File:       syntax2.h
  6. //
  7. //  Contents:   syntax modules for regexpr
  8. //
  9. //  Classes:    perl_syntax, posix_syntax
  10. //
  11. //  Author:     Eric Niebler ( ericne@microsoft.com )
  12. //
  13. //  History:    3-29-00   ericne   Created
  14. //
  15. //----------------------------------------------------------------------------
  16. #ifndef SYNTAX_H
  17. #define SYNTAX_H
  18. #ifdef _MSC_VER
  19. #pragma warning( push )
  20. // warning C4514: '' unreferenced inline function has been removed
  21. // warning C4786: identifier was truncated to '255' characters in the debug information
  22. #pragma warning( disable : 4514 4786 )
  23. #endif
  24. #include <map>
  25. #include <iosfwd>
  26. #include <string>
  27. #include <cctype>
  28. #include <cwctype>
  29. #include <cassert>
  30. #include <iterator>
  31. #include <stdexcept>
  32. #ifndef ARRAYSIZE
  33. # define ARRAYSIZE( a ) (sizeof(a)/sizeof((a)[0]))
  34. #endif
  35. #ifndef UCHAR_MAX
  36. # define UCHAR_MAX 0xff
  37. #endif
  38. #ifndef WCHAR_MAX
  39. # define WCHAR_MAX ( (wchar_t )-1 )
  40. #endif
  41. #if defined(_MSC_VER) & _MSC_VER >= 1300
  42. # define REGEX_DEPRECATED  __declspec(deprecated)
  43. # define REGEX_NOINLINE    __declspec(noinline)
  44. # define REGEX_FORCEINLINE __forceinline
  45. # define REGEX_SELECTANY   __declspec(selectany)
  46. # define REGEX_CDECL       __cdecl
  47. #elif defined(_MSC_VER) & _MSC_VER < 1300
  48. # define REGEX_DEPRECATED
  49. # define REGEX_NOINLINE
  50. # define REGEX_FORCEINLINE __forceinline
  51. # define REGEX_SELECTANY   __declspec(selectany)
  52. # define REGEX_CDECL       __cdecl
  53. #else
  54. # define REGEX_DEPRECATED
  55. # define REGEX_NOINLINE
  56. # define REGEX_FORCEINLINE inline
  57. # define REGEX_SELECTANY
  58. # define REGEX_CDECL
  59. #endif
  60. #define REGEX_STRING(CH,sz) (::regex::detail::literal<CH>::string( sz, L##sz ))
  61. #define REGEX_CHAR(CH,ch) (static_cast<CH>(::regex::detail::literal<CH>::template character<ch,L##ch>::value))
  62. #ifdef _MSC_VER
  63. namespace std
  64. {
  65. template<>
  66. struct iterator_traits< char * >
  67. {    // get traits from iterator _Iter
  68.     typedef random_access_iterator_tag iterator_category;
  69.     typedef char value_type;
  70.     typedef ptrdiff_t difference_type;
  71.     typedef difference_type distance_type;    // retained
  72.     typedef char * pointer;
  73.     typedef char & reference;
  74. };
  75. template<>
  76. struct iterator_traits< char const * >
  77. {    // get traits from iterator _Iter
  78.     typedef random_access_iterator_tag iterator_category;
  79.     typedef char value_type;
  80.     typedef ptrdiff_t difference_type;
  81.     typedef difference_type distance_type;    // retained
  82.     typedef char * pointer;
  83.     typedef char & reference;
  84. };
  85. template<>
  86. struct iterator_traits< wchar_t * >
  87. {    // get traits from iterator _Iter
  88.     typedef random_access_iterator_tag iterator_category;
  89.     typedef wchar_t value_type;
  90.     typedef ptrdiff_t difference_type;
  91.     typedef difference_type distance_type;    // retained
  92.     typedef wchar_t * pointer;
  93.     typedef wchar_t & reference;
  94. };
  95. template<>
  96. struct iterator_traits< wchar_t const * >
  97. {    // get traits from iterator _Iter
  98.     typedef random_access_iterator_tag iterator_category;
  99.     typedef wchar_t value_type;
  100.     typedef ptrdiff_t difference_type;
  101.     typedef difference_type distance_type;    // retained
  102.     typedef wchar_t * pointer;
  103.     typedef wchar_t & reference;
  104. };
  105. #if _MSC_VER < 1300 & ( !defined(_CPPLIB_VER) | _CPPLIB_VER < 308 )
  106. #pragma warning( push )
  107. #pragma warning( disable : 4601 )
  108. #pragma push_macro("max")
  109. #pragma push_macro("min")
  110. #undef max
  111. #undef min
  112. template< typename T >
  113. T const & max( T const & l, T const & r )
  114. {
  115.     return _cpp_max( l, r );
  116. }
  117. template< typename T >
  118. T const & min( T const & l, T const & r )
  119. {
  120.     return _cpp_min( l, r );
  121. }
  122. #pragma pop_macro("min")
  123. #pragma pop_macro("max")
  124. #pragma warning( pop )
  125. #endif
  126. }
  127. #endif
  128. namespace regex
  129. {
  130. class bad_regexpr : public std::invalid_argument
  131. {
  132. public:
  133.     explicit bad_regexpr( std::string const & s )
  134.         : std::invalid_argument( s ) {}
  135.     virtual ~bad_regexpr() throw() {}
  136. };
  137. //
  138. // Flags to control how matching occurs
  139. //
  140. enum REGEX_FLAGS
  141. {
  142.     NOFLAGS       = 0x0000,
  143.     NOCASE        = 0x0001, // ignore case
  144.     GLOBAL        = 0x0002, // match everywhere in the string
  145.     MULTILINE     = 0x0004, // ^ and $ can match internal line breaks
  146.     SINGLELINE    = 0x0008, // . can match newline character
  147.     RIGHTMOST     = 0x0010, // start matching at the right of the string
  148.     NOBACKREFS    = 0x0020, // only meaningful when used with GLOBAL and substitute
  149.     FIRSTBACKREFS = 0x0040, // only meaningful when used with GLOBAL
  150.     ALLBACKREFS   = 0x0080, // only meaningful when used with GLOBAL
  151.     NORMALIZE     = 0x0100, // Preprocess patterns: "\n" => "n", etc.
  152.     EXTENDED      = 0x0200, // ignore whitespace in pattern
  153. };
  154. // For backwards compatibility
  155. REGEX_FLAGS const noflags = NOFLAGS;
  156. // helper functions to make it easier to combine
  157. // the regex flags.
  158. inline REGEX_FLAGS operator|( REGEX_FLAGS f1, REGEX_FLAGS f2 )
  159. {
  160.     return ( REGEX_FLAGS ) ( ( unsigned )f1 | ( unsigned )f2 );
  161. }
  162. inline REGEX_FLAGS & operator|=( REGEX_FLAGS & f1, REGEX_FLAGS f2 )
  163. {
  164.     return f1 = ( f1 | f2 );
  165. }
  166. inline REGEX_FLAGS operator&( REGEX_FLAGS f1, REGEX_FLAGS f2 )
  167. {
  168.     return ( REGEX_FLAGS ) ( ( unsigned )f1 & ( unsigned )f2 );
  169. }
  170. inline REGEX_FLAGS & operator&=( REGEX_FLAGS & f1, REGEX_FLAGS f2 )
  171. {
  172.     return f1 = ( f1 & f2 );
  173. }
  174. #if !defined(_MSC_VER) | _MSC_VER >= 1300
  175. inline REGEX_FLAGS operator~( REGEX_FLAGS f )
  176. {
  177.     return ( REGEX_FLAGS ) ~( unsigned )f;
  178. }
  179. #endif
  180. //
  181. // The following are the tokens that can be emitted by the syntax module.
  182. // Don't reorder this list!!!
  183. //
  184. enum TOKEN
  185. {
  186.     NO_TOKEN = 0,
  187.     // REGULAR TOKENS
  188.     BEGIN_GROUP,
  189.     END_GROUP,
  190.     ALTERNATION,
  191.     BEGIN_LINE,
  192.     END_LINE,
  193.     BEGIN_CHARSET,
  194.     MATCH_ANY,
  195.     ESCAPE,
  196.     // QUANTIFICATION TOKENS
  197.     ONE_OR_MORE,
  198.     ZERO_OR_MORE,
  199.     ZERO_OR_ONE,
  200.     ONE_OR_MORE_MIN,
  201.     ZERO_OR_MORE_MIN,
  202.     ZERO_OR_ONE_MIN,
  203.     BEGIN_RANGE,
  204.     RANGE_SEPARATOR,
  205.     END_RANGE,
  206.     END_RANGE_MIN,
  207.     // ESCAPE SEQUENCES
  208.     ESC_DIGIT,
  209.     ESC_NOT_DIGIT,
  210.     ESC_SPACE,
  211.     ESC_NOT_SPACE,
  212.     ESC_WORD,
  213.     ESC_NOT_WORD,
  214.     ESC_BEGIN_STRING,
  215.     ESC_END_STRING,
  216.     ESC_END_STRING_z,
  217.     ESC_WORD_BOUNDARY,
  218.     ESC_NOT_WORD_BOUNDARY,
  219.     ESC_WORD_START,
  220.     ESC_WORD_STOP,
  221.     ESC_QUOTE_META_ON,
  222.     ESC_QUOTE_META_OFF,
  223.     // SUBSTITUTION TOKENS
  224.     SUBST_BACKREF,
  225.     SUBST_PREMATCH,
  226.     SUBST_POSTMATCH,
  227.     SUBST_MATCH,
  228.     SUBST_ESCAPE,
  229.     SUBST_QUOTE_META_ON,
  230.     SUBST_UPPER_ON,
  231.     SUBST_UPPER_NEXT,
  232.     SUBST_LOWER_ON,
  233.     SUBST_LOWER_NEXT,
  234.     SUBST_ALL_OFF,
  235.     // CHARSET TOKENS
  236.     CHARSET_NEGATE,
  237.     CHARSET_ESCAPE,
  238.     CHARSET_RANGE,
  239.     CHARSET_BACKSPACE,
  240.     CHARSET_END,
  241.     CHARSET_ALNUM,
  242.     CHARSET_NOT_ALNUM,
  243.     CHARSET_ALPHA,
  244.     CHARSET_NOT_ALPHA,
  245.     CHARSET_BLANK,
  246.     CHARSET_NOT_BLANK,
  247.     CHARSET_CNTRL,
  248.     CHARSET_NOT_CNTRL,
  249.     CHARSET_DIGIT,
  250.     CHARSET_NOT_DIGIT,
  251.     CHARSET_GRAPH,
  252.     CHARSET_NOT_GRAPH,
  253.     CHARSET_LOWER,
  254.     CHARSET_NOT_LOWER,
  255.     CHARSET_PRINT,
  256.     CHARSET_NOT_PRINT,
  257.     CHARSET_PUNCT,
  258.     CHARSET_NOT_PUNCT,
  259.     CHARSET_SPACE,
  260.     CHARSET_NOT_SPACE,
  261.     CHARSET_UPPER,
  262.     CHARSET_NOT_UPPER,
  263.     CHARSET_XDIGIT,
  264.     CHARSET_NOT_XDIGIT,
  265.     // EXTENSION TOKENS
  266.     EXT_NOBACKREF,
  267.     EXT_POS_LOOKAHEAD,
  268.     EXT_NEG_LOOKAHEAD,
  269.     EXT_POS_LOOKBEHIND,
  270.     EXT_NEG_LOOKBEHIND,
  271.     EXT_INDEPENDENT,
  272.     EXT_COMMENT,
  273.     EXT_CONDITION,
  274.     EXT_RECURSE,
  275.     EXT_UNKNOWN
  276. };
  277. namespace detail
  278. {
  279. template< typename CH > struct literal;
  280. template<> struct literal<char>
  281. {
  282.     static char const * string( char const * sz, wchar_t const * ) { return sz; }
  283.     template<char ch,wchar_t> struct character { enum { value = ch }; };
  284. };
  285. template<> struct literal<wchar_t>
  286. {
  287.     static wchar_t const * string( char const *, wchar_t const * sz ) { return sz; }
  288.     template<char,wchar_t ch> struct character { enum { value = ch }; };
  289. };
  290. struct posix_charset_type
  291. {
  292.     char const * szcharset;
  293.     size_t       cchars;
  294. };
  295. extern posix_charset_type const g_rgposix_charsets[];
  296. extern size_t const g_cposix_charsets;
  297. template< typename CI >
  298. bool is_posix_charset( CI icur, CI iend, char const * szcharset )
  299. {
  300.     for( ; iend != icur && '' != *szcharset; ++icur, ++szcharset )
  301.     {
  302.         if( *icur != *szcharset )
  303.             return false;
  304.     }
  305.     return '' == *szcharset;
  306. }
  307. // Forward-declare the class that holds all the information
  308. // about the set of characters that can be matched by a charset
  309. struct charset;
  310. void free_charset( charset const * );
  311. template< typename CH >
  312. struct charset_map_node
  313. {
  314.     std::basic_string<CH> m_str;
  315.     charset const * m_rgcharsets[2]; // 0==case, 1==nocase
  316.     charset_map_node()
  317.     {
  318.         m_rgcharsets[0] = m_rgcharsets[1] = NULL;
  319.     }
  320.     charset_map_node( charset_map_node const & node )
  321.     {
  322.         *this = node;
  323.     }
  324.     charset_map_node & operator=( charset_map_node const & node )
  325.     {
  326.         m_str = node.m_str;
  327.         m_rgcharsets[0] = node.m_rgcharsets[0];
  328.         m_rgcharsets[1] = node.m_rgcharsets[1];
  329.         return *this;
  330.     }
  331.     void set( std::basic_string<CH> const & str )
  332.     {
  333.         clear();
  334.         m_str = str;
  335.     }
  336.     void clear()
  337.     {
  338.         std::basic_string<CH>().swap( m_str );
  339.         free_charset( m_rgcharsets[0] );
  340.         free_charset( m_rgcharsets[1] );
  341.         m_rgcharsets[0] = m_rgcharsets[1] = NULL;
  342.     }
  343. };
  344. template< typename CH >
  345. class charset_map
  346. {
  347.     std::map<CH, charset_map_node<CH> > m_map;
  348. public:
  349.     typedef typename std::map<CH, charset_map_node<CH> >::iterator iterator;
  350.     ~charset_map()
  351.     {
  352.         for( iterator iter = m_map.begin(); m_map.end() != iter; ++iter )
  353.             iter->second.clear();
  354.     }
  355.     charset_map_node<CH> & operator[]( CH ch ) { return m_map[ ch ]; }
  356.     iterator begin() { return m_map.begin(); }
  357.     iterator end() { return m_map.end(); }
  358.     iterator find( CH ch ) { return m_map.find( ch ); }
  359.     void erase( iterator iter ) { m_map.erase( iter ); }
  360. };
  361. inline bool regex_isspace( char ch )
  362. {
  363.     return 0 != isspace( ch );
  364. }
  365. inline bool regex_isspace( wchar_t wch )
  366. {
  367.     return 0 != iswspace( wch );
  368. }
  369. } // namespace detail
  370. //
  371. // The perl_syntax class encapsulates the Perl 5 regular expression syntax. It is
  372. // used as a template parameter to basic_rpattern.  To customize regex syntax, create
  373. // your own syntax class and use it as a template parameter instead.
  374. //
  375. class perl_syntax_base
  376. {
  377. protected:
  378.     perl_syntax_base()
  379.     {
  380.     }
  381.     static TOKEN const s_rgreg[ UCHAR_MAX + 1 ];
  382.     static TOKEN const s_rgescape[ UCHAR_MAX + 1 ];
  383.     static TOKEN look_up(  char   ch, TOKEN const rg[] )
  384.     {
  385.         return rg[ static_cast<unsigned char>( ch ) ];
  386.     }
  387.     
  388.     static TOKEN look_up( wchar_t ch, TOKEN const rg[] )
  389.     {
  390.         return UCHAR_MAX < ch ? NO_TOKEN : rg[ static_cast<unsigned char>( ch ) ];
  391.     }
  392. };
  393. // --------------------------------------------------------------------------
  394. //
  395. // Class:       perl_syntax
  396. //
  397. // Description: Module that encapsulates the Perl syntax
  398. //
  399. // Methods:     eat_whitespace             -
  400. //              min_quant                  -
  401. //              perl_syntax                -
  402. //              perl_syntax                -
  403. //              set_flags                  -
  404. //              get_flags                  -
  405. //              reg_token                  -
  406. //              quant_token                -
  407. //              charset_token              -
  408. //              subst_token                -
  409. //              ext_token                  -
  410. //              invalid_charset            -
  411. //              register_intrinsic_charset -
  412. //              _invalid_charset           -
  413. //              _invalid_charset           -
  414. //
  415. // Members:     m_flags                    -
  416. //              s_charset_map              -
  417. //
  418. // Typedefs:    iterator                   -
  419. //              const_iterator             -
  420. //              char_type                  -
  421. //
  422. // History:     11/16/2001 - ericne - Created
  423. //
  424. // --------------------------------------------------------------------------
  425. template< typename CH >
  426. class perl_syntax : protected perl_syntax_base
  427. {
  428. public:
  429.     typedef typename std::basic_string<CH>::iterator iterator;
  430.     typedef typename std::basic_string<CH>::const_iterator const_iterator;
  431.     typedef CH char_type;
  432.     template< typename CH2 > struct rebind { typedef perl_syntax<CH2> other; };
  433. private:
  434.     REGEX_FLAGS m_flags;
  435.     const_iterator eat_whitespace( iterator & icur, const_iterator iend )
  436.     {
  437.         if( m_flags & EXTENDED )
  438.         {
  439.             while( iend != icur && ( REGEX_CHAR(CH,'#') == *icur || detail::regex_isspace( *icur ) ) )
  440.             {
  441.                 if( REGEX_CHAR(CH,'#') == *icur++ )
  442.                 {
  443.                     while( iend != icur && REGEX_CHAR(CH,'n') != *icur++ );
  444.                 }
  445.                 else
  446.                 {
  447.                     for( ; iend != icur && detail::regex_isspace( *icur ); ++icur );
  448.                 }
  449.             }
  450.         }
  451.         return icur;
  452.     }
  453.     bool min_quant( iterator & icur, const_iterator iend )
  454.     {
  455.         return ( iend != eat_whitespace( ++icur, iend ) && REGEX_CHAR(CH,'?') == *icur ? ( ++icur, true ) : false );
  456.     }
  457. public:
  458.     perl_syntax( REGEX_FLAGS flags )
  459.         : m_flags( flags )
  460.     {
  461.     }
  462.     perl_syntax( perl_syntax<CH> const & sy )
  463.         : m_flags( sy.m_flags )
  464.     {
  465.     }
  466.     void set_flags( REGEX_FLAGS flags )
  467.     {
  468.         m_flags = flags;
  469.     }
  470.     REGEX_FLAGS get_flags() const
  471.     {
  472.         return m_flags;
  473.     }
  474.     TOKEN reg_token( iterator & icur, const_iterator iend )
  475.     {
  476.         assert( iend != icur );
  477.         if( iend == eat_whitespace( icur, iend ) )
  478.             return NO_TOKEN;
  479.         TOKEN tok = look_up( *icur, s_rgreg );
  480.         if( tok )
  481.             ++icur;
  482.         if( ESCAPE == tok && iend != icur )
  483.         {
  484.             tok = look_up( *icur, s_rgescape );
  485.             if( tok )
  486.                 ++icur;
  487.             else
  488.                 tok = ESCAPE;
  489.         }
  490.         return tok;
  491.     }
  492.     TOKEN quant_token( iterator & icur, const_iterator iend )
  493.     {
  494.         assert( iend != icur );
  495.         if( iend == eat_whitespace( icur, iend ) )
  496.             return NO_TOKEN;
  497.         TOKEN tok = NO_TOKEN;
  498.         switch( *icur )
  499.         {
  500.         case REGEX_CHAR(CH,'*'):
  501.             tok = min_quant( icur, iend ) ? ZERO_OR_MORE_MIN : ZERO_OR_MORE;
  502.             break;
  503.         case REGEX_CHAR(CH,'+'):
  504.             tok = min_quant( icur, iend ) ? ONE_OR_MORE_MIN : ONE_OR_MORE;
  505.             break;
  506.         case REGEX_CHAR(CH,'?'):
  507.             tok = min_quant( icur, iend ) ? ZERO_OR_ONE_MIN : ZERO_OR_ONE;
  508.             break;
  509.         case REGEX_CHAR(CH,'}'):
  510.             tok = min_quant( icur, iend ) ? END_RANGE_MIN : END_RANGE;
  511.             break;
  512.         case REGEX_CHAR(CH,'{'):
  513.             tok = BEGIN_RANGE;
  514.             ++icur;
  515.             break;
  516.         case REGEX_CHAR(CH,','):
  517.             tok = RANGE_SEPARATOR;
  518.             ++icur;
  519.             break;
  520.         }
  521.         return tok;
  522.     }
  523.     TOKEN charset_token( iterator & icur, const_iterator iend )
  524.     {
  525.         assert( iend != icur );
  526.         TOKEN tok = NO_TOKEN;
  527.         switch( *icur )
  528.         {
  529.         case REGEX_CHAR(CH,'-'):
  530.             tok = CHARSET_RANGE;
  531.             ++icur;
  532.             break;
  533.         case REGEX_CHAR(CH,'^'):
  534.             tok = CHARSET_NEGATE;
  535.             ++icur;
  536.             break;
  537.         case REGEX_CHAR(CH,']'):
  538.             tok = CHARSET_END;
  539.             ++icur;
  540.             break;
  541.         case REGEX_CHAR(CH,'\'):
  542.             tok = CHARSET_ESCAPE;
  543.             if( iend == ++icur )
  544.                 break;
  545.             switch( *icur )
  546.             {
  547.             case REGEX_CHAR(CH,'b'):
  548.                 tok = CHARSET_BACKSPACE;
  549.                 ++icur;
  550.                 break;
  551.             case REGEX_CHAR(CH,'d'):
  552.                 tok = ESC_DIGIT;
  553.                 ++icur;
  554.                 break;
  555.             case REGEX_CHAR(CH,'D'):
  556.                 tok = ESC_NOT_DIGIT;
  557.                 ++icur;
  558.                 break;
  559.             case REGEX_CHAR(CH,'s'):
  560.                 tok = ESC_SPACE;
  561.                 ++icur;
  562.                 break;
  563.             case REGEX_CHAR(CH,'S'):
  564.                 tok = ESC_NOT_SPACE;
  565.                 ++icur;
  566.                 break;
  567.             case REGEX_CHAR(CH,'w'):
  568.                 tok = ESC_WORD;
  569.                 ++icur;
  570.                 break;
  571.             case REGEX_CHAR(CH,'W'):
  572.                 tok = ESC_NOT_WORD;
  573.                 ++icur;
  574.                 break;
  575.             }
  576.             break;
  577.         case REGEX_CHAR(CH,'['):
  578.             if( REGEX_CHAR(CH,':') == *( ++icur )-- )
  579.             {
  580.                 for( size_t i=0; !tok && i < detail::g_cposix_charsets; ++i )
  581.                 {
  582.                     if( detail::is_posix_charset<const_iterator>( icur, iend, detail::g_rgposix_charsets[i].szcharset ) )
  583.                     {
  584.                         tok = TOKEN( CHARSET_ALNUM + i );
  585.                         std::advance( icur, detail::g_rgposix_charsets[i].cchars );
  586.                     }
  587.                 }
  588.             }
  589.             break;
  590.         }
  591.         return tok;
  592.     }
  593.     TOKEN subst_token( iterator & icur, const_iterator iend )
  594.     {
  595.         assert( iend != icur );
  596.         TOKEN tok = NO_TOKEN;
  597.         switch( *icur )
  598.         {
  599.         case REGEX_CHAR(CH,'\'):
  600.             tok = SUBST_ESCAPE;
  601.             if( iend != ++icur )
  602.                 switch( *icur )
  603.                 {
  604.                 case REGEX_CHAR(CH,'Q'):
  605.                     tok = SUBST_QUOTE_META_ON;
  606.                     ++icur;
  607.                     break;
  608.                 case REGEX_CHAR(CH,'U'):
  609.                     tok = SUBST_UPPER_ON;
  610.                     ++icur;
  611.                     break;
  612.                 case REGEX_CHAR(CH,'u'):
  613.                     tok = SUBST_UPPER_NEXT;
  614.                     ++icur;
  615.                     break;
  616.                 case REGEX_CHAR(CH,'L'):
  617.                     tok = SUBST_LOWER_ON;
  618.                     ++icur;
  619.                     break;
  620.                 case REGEX_CHAR(CH,'l'):
  621.                     tok = SUBST_LOWER_NEXT;
  622.                     ++icur;
  623.                     break;
  624.                 case REGEX_CHAR(CH,'E'):
  625.                     tok = SUBST_ALL_OFF;
  626.                     ++icur;
  627.                     break;
  628.                 }
  629.             break;
  630.         case REGEX_CHAR(CH,'$'):
  631.             tok = SUBST_BACKREF;
  632.             if( iend != ++icur )
  633.                 switch( *icur )
  634.                 {
  635.                 case REGEX_CHAR(CH,'&'):
  636.                     tok = SUBST_MATCH;
  637.                     ++icur;
  638.                     break;
  639.                 case REGEX_CHAR(CH,'`'):
  640.                     tok = SUBST_PREMATCH;
  641.                     ++icur;
  642.                     break;
  643.                 case REGEX_CHAR(CH,'''):
  644.                     tok = SUBST_POSTMATCH;
  645.                     ++icur;
  646.                     break;
  647.                 }
  648.             break;
  649.         }
  650.         return tok;
  651.     }
  652.     TOKEN ext_token( iterator & icur, const_iterator iend )
  653.     {
  654.         assert( iend != icur );
  655.         if( iend == eat_whitespace( icur, iend ) )
  656.             return NO_TOKEN;
  657.         bool finclude;
  658.         TOKEN tok = NO_TOKEN;
  659.         if( REGEX_CHAR(CH,'?') == *icur )
  660.         {
  661.             tok = EXT_UNKNOWN;
  662.             ++icur;
  663.             if( m_flags & EXTENDED )
  664.                 for( ; iend != icur && detail::regex_isspace( *icur ); ++icur );
  665.             if( iend != icur )
  666.             {
  667.                 switch( *icur )
  668.                 {
  669.                 case REGEX_CHAR(CH,':'):
  670.                     tok = EXT_NOBACKREF;
  671.                     ++icur;
  672.                     break;
  673.                 case REGEX_CHAR(CH,'='):
  674.                     tok = EXT_POS_LOOKAHEAD;
  675.                     ++icur;
  676.                     break;
  677.                 case REGEX_CHAR(CH,'!'):
  678.                     tok = EXT_NEG_LOOKAHEAD;
  679.                     ++icur;
  680.                     break;
  681.                 case REGEX_CHAR(CH,'#'):
  682.                     tok = EXT_COMMENT;
  683.                     ++icur;
  684.                     break;
  685.                 case REGEX_CHAR(CH,'('):
  686.                     tok = EXT_CONDITION;
  687.                     ++icur;
  688.                     break;
  689.                 case REGEX_CHAR(CH,'R'):
  690.                     tok = EXT_RECURSE;
  691.                     ++icur;
  692.                     break;
  693.                 case REGEX_CHAR(CH,'<'):
  694.                     if( iend == eat_whitespace( ++icur, iend ) )
  695.                         break;
  696.                     switch( *icur )
  697.                     {
  698.                     case REGEX_CHAR(CH,'='):
  699.                         tok = EXT_POS_LOOKBEHIND;
  700.                         ++icur;
  701.                         break;
  702.                     case REGEX_CHAR(CH,'!'):
  703.                         tok = EXT_NEG_LOOKBEHIND;
  704.                         ++icur;
  705.                         break;
  706.                     }
  707.                     break;
  708.                 case REGEX_CHAR(CH,'>'):
  709.                     tok = EXT_INDEPENDENT;
  710.                     ++icur;
  711.                     break;
  712.                 default:
  713.                     finclude = true;
  714.                     do
  715.                     {
  716.                         if( REGEX_CHAR(CH,':') == *icur )
  717.                         {
  718.                             tok = EXT_NOBACKREF;
  719.                             ++icur;
  720.                             break;
  721.                         }
  722.                         if( REGEX_CHAR(CH,')') == *icur )
  723.                         {
  724.                             tok = EXT_NOBACKREF;
  725.                             break;
  726.                         }
  727.                         if( REGEX_CHAR(CH,'-') == *icur && finclude )
  728.                             finclude = false;
  729.                         else if( REGEX_CHAR(CH,'i') == *icur )
  730.                             m_flags = ( REGEX_FLAGS ) ( finclude ? ( m_flags | NOCASE )     : ( m_flags & ~NOCASE ) );
  731.                         else if( REGEX_CHAR(CH,'m') == *icur )
  732.                             m_flags = ( REGEX_FLAGS ) ( finclude ? ( m_flags | MULTILINE )  : ( m_flags & ~MULTILINE ) );
  733.                         else if( REGEX_CHAR(CH,'s') == *icur )
  734.                             m_flags = ( REGEX_FLAGS ) ( finclude ? ( m_flags | SINGLELINE ) : ( m_flags & ~SINGLELINE ) );
  735.                         else if( REGEX_CHAR(CH,'x') == *icur )
  736.                             m_flags = ( REGEX_FLAGS ) ( finclude ? ( m_flags | EXTENDED )   : ( m_flags & ~EXTENDED ) );
  737.                         else
  738.                             break;
  739.                     } while( iend != eat_whitespace( ++icur, iend ) );
  740.                     break;
  741.                 }
  742.             }
  743.         }
  744.         return tok;
  745.     }
  746.     // Functions used for making user-defined intrinsic character sets
  747.     static detail::charset_map<CH> s_charset_map;
  748.     static bool invalid_charset( CH ch )
  749.     {
  750.         return _invalid_charset( ch );
  751.     }
  752.     static void register_intrinsic_charset( CH ch, std::basic_string<CH> const & str ) //throw( bad_regexpr, std::bad_alloc )
  753.     {
  754.         perl_syntax sy( NOFLAGS );
  755.         if( invalid_charset( ch ) )
  756.             throw bad_regexpr( "invalid character specified to register_intrinsic_charset" );
  757.         std::basic_string<CH> pat = str;
  758.         typename std::basic_string<CH>::iterator istart = pat.begin();
  759.         if( BEGIN_CHARSET != sy.reg_token( istart, pat.end() ) )
  760.             throw bad_regexpr( "expecting beginning of charset" );
  761.         regex::detail::charset_map<CH> & charset_map = s_charset_map;
  762.         regex::detail::charset_map_node<CH> & map_node = charset_map[ ch ];
  763.         map_node.set( std::basic_string<CH>( istart, pat.end() ) );
  764.     }
  765.  private:
  766.     static bool _invalid_charset( char ch )
  767.     {
  768.         return NO_TOKEN != s_rgescape[ static_cast<unsigned char>( ch ) ]
  769.             || isdigit( ch ) || 'e' == ch || 'x' == ch || 'c' == ch;
  770.     }
  771.     static bool _invalid_charset( wchar_t ch )
  772.     {
  773.         return UCHAR_MAX >= ch && _invalid_charset( static_cast<char>( ch ) );
  774.     }
  775. };
  776. template< typename CH >
  777. detail::charset_map<CH> perl_syntax<CH>::s_charset_map;
  778. // --------------------------------------------------------------------------
  779. //
  780. // Class:       posix_syntax
  781. //
  782. // Description: Implements the basic POSIX regular expression syntax
  783. //
  784. // Methods:     posix_syntax               -
  785. //              posix_syntax               -
  786. //              get_flags                  -
  787. //              set_flags                  -
  788. //              reg_token                  -
  789. //              quant_token                -
  790. //              charset_token              -
  791. //              subst_token                -
  792. //              ext_token                  -
  793. //              invalid_charset            -
  794. //              register_intrinsic_charset -
  795. //
  796. // Members:     m_flags                    -
  797. //              s_charset_map              -
  798. //
  799. // Typedefs:    iterator                   -
  800. //              const_iterator             -
  801. //              char_type                  -
  802. //
  803. // History:     11/16/2001 - ericne - Created
  804. //
  805. // --------------------------------------------------------------------------
  806. template< typename CH >
  807. class posix_syntax
  808. {
  809.     REGEX_FLAGS m_flags;
  810. public:
  811.     typedef typename std::basic_string<CH>::iterator iterator;
  812.     typedef typename std::basic_string<CH>::const_iterator const_iterator;
  813.     typedef CH char_type;
  814.     template< typename CH2 > struct rebind { typedef posix_syntax<CH2> other; };
  815.     posix_syntax( REGEX_FLAGS flags )
  816.         : m_flags( flags )
  817.     {
  818.     }
  819.     posix_syntax( posix_syntax<CH> const & sy )
  820.         : m_flags( sy.m_flags )
  821.     {
  822.     }
  823.     REGEX_FLAGS get_flags() const
  824.     {
  825.         return m_flags;
  826.     }
  827.     void set_flags( REGEX_FLAGS flags )
  828.     {
  829.         m_flags = flags;
  830.     }
  831.     TOKEN reg_token( iterator & icur, const_iterator iend )
  832.     {
  833.         TOKEN tok = NO_TOKEN;
  834.         switch( *icur )
  835.         {
  836.         case REGEX_CHAR(CH,'.'):
  837.             tok = MATCH_ANY;
  838.             ++icur;
  839.             break;
  840.         case REGEX_CHAR(CH,'^'):
  841.             tok = BEGIN_LINE;
  842.             ++icur;
  843.             break;
  844.         case REGEX_CHAR(CH,'$'):
  845.             tok = END_LINE;
  846.             ++icur;
  847.             break;
  848.         case REGEX_CHAR(CH,'['):
  849.             tok = BEGIN_CHARSET;
  850.             ++icur;
  851.             break;
  852.         case REGEX_CHAR(CH,'\'):
  853.             tok = ESCAPE;
  854.             ++icur;
  855.             if( iend != icur )
  856.             {
  857.                 switch( *icur )
  858.                 {
  859.                 case REGEX_CHAR(CH,'('):
  860.                     tok = BEGIN_GROUP;
  861.                     ++icur;
  862.                     break;
  863.                 case REGEX_CHAR(CH,')'):
  864.                     tok = END_GROUP;
  865.                     ++icur;
  866.                     break;
  867.                 case REGEX_CHAR(CH,'|'):
  868.                     tok = ALTERNATION;
  869.                     ++icur;
  870.                     break;
  871.                 }
  872.             }
  873.             break;
  874.         }
  875.         return tok;
  876.     }
  877.     TOKEN quant_token( iterator & icur, const_iterator iend )
  878.     {
  879.         TOKEN tok = NO_TOKEN;
  880.         switch( *icur )
  881.         {
  882.         case REGEX_CHAR(CH,'*'):
  883.             tok = ZERO_OR_MORE;
  884.             ++icur;
  885.             break;
  886.         case REGEX_CHAR(CH,','):
  887.             tok = RANGE_SEPARATOR;
  888.             ++icur;
  889.             break;
  890.         case REGEX_CHAR(CH,'\'):
  891.             ++icur;
  892.             if( iend != icur )
  893.             {
  894.                 switch( *icur )
  895.                 {
  896.                 case REGEX_CHAR(CH,'?'):
  897.                     tok = ZERO_OR_ONE;
  898.                     ++icur;
  899.                     break;
  900.                 case REGEX_CHAR(CH,'+'):
  901.                     tok = ONE_OR_MORE;
  902.                     ++icur;
  903.                     break;
  904.                 case REGEX_CHAR(CH,'{'):
  905.                     tok = BEGIN_RANGE;
  906.                     ++icur;
  907.                     break;
  908.                 case REGEX_CHAR(CH,'}'):
  909.                     tok = END_RANGE;
  910.                     ++icur;
  911.                     break;
  912.                 default:
  913.                     --icur;
  914.                     break;
  915.                 }
  916.             }
  917.             else
  918.             {
  919.                 --icur;
  920.             }
  921.         }
  922.         return tok;
  923.     }
  924.     TOKEN charset_token( iterator & icur, const_iterator iend )
  925.     {
  926.         TOKEN tok = NO_TOKEN;
  927.         switch( *icur )
  928.         {
  929.         case REGEX_CHAR(CH,'^'):
  930.             tok = CHARSET_NEGATE;
  931.             ++icur;
  932.             break;
  933.         case REGEX_CHAR(CH,'-'):
  934.             tok = CHARSET_RANGE;
  935.             ++icur;
  936.             break;
  937.         case REGEX_CHAR(CH,']'):
  938.             tok = CHARSET_END;
  939.             ++icur;
  940.             break;
  941.         case REGEX_CHAR(CH,'['):
  942.             if( REGEX_CHAR(CH,':') == *( ++icur )-- )
  943.             {
  944.                 for( size_t i=0; !tok && i < detail::g_cposix_charsets; ++i )
  945.                 {
  946.                     if( detail::is_posix_charset<const_iterator>( icur, iend, detail::g_rgposix_charsets[i].szcharset ) )
  947.                     {
  948.                         tok = TOKEN( CHARSET_ALNUM + i );
  949.                         std::advance( icur, detail::g_rgposix_charsets[i].cchars );
  950.                     }
  951.                 }
  952.             }
  953.             break;
  954.         }
  955.         return tok;
  956.     }
  957.     TOKEN subst_token( iterator & icur, const_iterator iend )
  958.     {
  959.         TOKEN tok = NO_TOKEN;
  960.         if( REGEX_CHAR(CH,'\') == *icur )
  961.         {
  962.             tok = SUBST_ESCAPE;
  963.             ++icur;
  964.             if( iend != icur && REGEX_CHAR(CH,'0') <= *icur && REGEX_CHAR(CH,'9') >= *icur )
  965.             {
  966.                 tok = SUBST_BACKREF;
  967.             }
  968.         }
  969.         return tok;
  970.     }
  971.     TOKEN ext_token( iterator &, const_iterator )
  972.     {
  973.         return NO_TOKEN;
  974.     }
  975.     // Functions for making user-defined intrinsic character sets
  976.     static detail::charset_map<CH> s_charset_map;
  977.     static bool invalid_charset( CH ch )
  978.     {
  979.         return _invalid_charset( ch );
  980.     }
  981.     static void register_intrinsic_charset( CH ch, std::basic_string<CH> const & str ) //throw( bad_regexpr, std::bad_alloc )
  982.     {
  983.         posix_syntax sy( NOFLAGS );
  984.         if( invalid_charset( ch ) )
  985.             throw bad_regexpr( "invalid character specified to register_intrinsic_charset" );
  986.         std::basic_string<CH> pat = str;
  987.         typename std::basic_string<CH>::iterator istart = pat.begin();
  988.         if( BEGIN_CHARSET != sy.reg_token( istart, pat.end() ) )
  989.             throw bad_regexpr( "expecting beginning of charset" );
  990.         regex::detail::charset_map<CH> & charset_map = s_charset_map;
  991.         regex::detail::charset_map_node<CH> & map_node = charset_map[ ch ];
  992.         map_node.set( std::basic_string<CH>( istart, pat.end() ) );
  993.     }
  994.  private:
  995.     static bool _invalid_charset( char ch )
  996.     {
  997.         static char const s_invalid[] = "0123456789()|?+{}\exc";
  998.         return NULL != std::char_traits<CH>::find( s_invalid, ARRAYSIZE( s_invalid ) - 1, ch );
  999.     }
  1000.     static bool _invalid_charset( wchar_t ch )
  1001.     {
  1002.         return UCHAR_MAX >= ch && _invalid_charset( static_cast<char>( ch ) );
  1003.     }
  1004. };
  1005. template< typename CH >
  1006. detail::charset_map<CH> posix_syntax<CH>::s_charset_map;
  1007. } // namespace regex
  1008. #ifdef _MSC_VER
  1009. #pragma warning( pop )
  1010. #endif
  1011. #endif