You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
		
		
		
		
		
			
		
			
				
					
					
						
							615 lines
						
					
					
						
							21 KiB
						
					
					
				
			
		
		
	
	
							615 lines
						
					
					
						
							21 KiB
						
					
					
				| /*============================================================================= | |
|     Copyright (c) 2001-2011 Joel de Guzman | |
|     Copyright (c) 2001-2011 Hartmut Kaiser | |
|     Copyright (c)      2010 Bryce Lelbach | |
|  | |
|     Distributed under the Boost Software License, Version 1.0. (See accompanying | |
|     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
| ==============================================================================*/ | |
| #if !defined(BOOST_SPIRIT_CHAR_APRIL_16_2006_1051AM) | |
| #define BOOST_SPIRIT_CHAR_APRIL_16_2006_1051AM | |
|  | |
| #if defined(_MSC_VER) | |
| #pragma once | |
| #endif | |
|  | |
| #include <boost/spirit/home/support/common_terminals.hpp> | |
| #include <boost/spirit/home/support/string_traits.hpp> | |
| #include <boost/spirit/home/support/info.hpp> | |
| #include <boost/spirit/home/support/detail/get_encoding.hpp> | |
| #include <boost/spirit/home/support/char_set/basic_chset.hpp> | |
| #include <boost/spirit/home/qi/char/char_parser.hpp> | |
| #include <boost/spirit/home/qi/char/char_class.hpp> | |
| #include <boost/spirit/home/qi/meta_compiler.hpp> | |
| #include <boost/spirit/home/qi/auxiliary/lazy.hpp> | |
| #include <boost/spirit/home/qi/detail/enable_lit.hpp> | |
| #include <boost/fusion/include/at.hpp> | |
| #include <boost/mpl/if.hpp> | |
| #include <boost/mpl/assert.hpp> | |
| #include <boost/mpl/identity.hpp> | |
| #include <boost/utility/enable_if.hpp> | |
| #include <boost/type_traits/remove_const.hpp> | |
| #include <string> | |
|  | |
| #if defined(_MSC_VER) | |
| #pragma once | |
| #endif | |
|  | |
| namespace boost { namespace spirit | |
| { | |
|     /////////////////////////////////////////////////////////////////////////// | |
|     // Enablers | |
|     /////////////////////////////////////////////////////////////////////////// | |
|     template <typename CharEncoding> | |
|     struct use_terminal<qi::domain | |
|       , terminal< | |
|             tag::char_code<tag::char_, CharEncoding>    // enables char_ | |
|         > | |
|     > : mpl::true_ {}; | |
| 
 | |
|     template <typename CharEncoding, typename A0> | |
|     struct use_terminal<qi::domain | |
|       , terminal_ex< | |
|             tag::char_code<tag::char_, CharEncoding>    // enables char_('x'), char_("x") | |
|           , fusion::vector1<A0>                         // and char_("a-z0-9") | |
|         > | |
|     > : mpl::true_ {}; | |
| 
 | |
|     template <typename CharEncoding, typename A0, typename A1> | |
|     struct use_terminal<qi::domain | |
|       , terminal_ex< | |
|             tag::char_code<tag::char_, CharEncoding>    // enables char_('a','z') | |
|           , fusion::vector2<A0, A1> | |
|         > | |
|     > : mpl::true_ {}; | |
| 
 | |
|     template <typename CharEncoding>                    // enables *lazy* char_('x'), char_("x") | |
|     struct use_lazy_terminal<                           // and char_("a-z0-9") | |
|         qi::domain | |
|       , tag::char_code<tag::char_, CharEncoding> | |
|       , 1 // arity | |
|     > : mpl::true_ {}; | |
| 
 | |
|     template <typename CharEncoding>                    // enables *lazy* char_('a','z') | |
|     struct use_lazy_terminal< | |
|         qi::domain | |
|       , tag::char_code<tag::char_, CharEncoding> | |
|       , 2 // arity | |
|     > : mpl::true_ {}; | |
| 
 | |
|     template <> | |
|     struct use_terminal<qi::domain, char>               // enables 'x' | |
|       : mpl::true_ {}; | |
| 
 | |
|     template <> | |
|     struct use_terminal<qi::domain, char[2]>            // enables "x" | |
|       : mpl::true_ {}; | |
| 
 | |
|     template <> | |
|     struct use_terminal<qi::domain, wchar_t>            // enables wchar_t | |
|       : mpl::true_ {}; | |
| 
 | |
|     template <> | |
|     struct use_terminal<qi::domain, wchar_t[2]>         // enables L"x" | |
|       : mpl::true_ {}; | |
| 
 | |
|     // enables lit(...) | |
|     template <typename A0> | |
|     struct use_terminal<qi::domain | |
|           , terminal_ex<tag::lit, fusion::vector1<A0> > | |
|           , typename enable_if<traits::is_char<A0> >::type> | |
|       : mpl::true_ {}; | |
| }} | |
| 
 | |
| namespace boost { namespace spirit { namespace qi | |
| { | |
| #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS | |
|     using spirit::lit; // lit('x') is equivalent to 'x' | |
| #endif | |
|     using spirit::lit_type; | |
| 
 | |
|     /////////////////////////////////////////////////////////////////////////// | |
|     // Parser for a single character | |
|     /////////////////////////////////////////////////////////////////////////// | |
|     template <typename CharEncoding, bool no_attribute, bool no_case = false> | |
|     struct literal_char | |
|       : char_parser< | |
|             literal_char<CharEncoding, no_attribute, false> | |
|           , typename CharEncoding::char_type | |
|           , typename mpl::if_c<no_attribute, unused_type | |
|               , typename CharEncoding::char_type>::type> | |
|     { | |
|         typedef typename CharEncoding::char_type char_type; | |
|         typedef CharEncoding char_encoding; | |
| 
 | |
|         template <typename Char> | |
|         literal_char(Char ch) | |
|           : ch(static_cast<char_type>(ch)) {} | |
| 
 | |
|         template <typename Context, typename Iterator> | |
|         struct attribute | |
|         { | |
|             typedef typename mpl::if_c< | |
|                 no_attribute, unused_type, char_type>::type | |
|             type; | |
|         }; | |
| 
 | |
|         template <typename CharParam, typename Context> | |
|         bool test(CharParam ch_, Context&) const | |
|         { | |
|             return traits::ischar<CharParam, char_encoding>::call(ch_) && | |
|                    ch == char_type(ch_); | |
|         } | |
| 
 | |
|         template <typename Context> | |
|         info what(Context& /*context*/) const | |
|         { | |
|             return info("literal-char", char_encoding::toucs4(ch)); | |
|         } | |
| 
 | |
|         char_type ch; | |
|     }; | |
| 
 | |
|     template <typename CharEncoding, bool no_attribute> | |
|     struct literal_char<CharEncoding, no_attribute, true> // case insensitive | |
|       : char_parser< | |
|             literal_char<CharEncoding, no_attribute, true> | |
|           , typename mpl::if_c<no_attribute, unused_type | |
|               , typename CharEncoding::char_type>::type> | |
|     { | |
|         typedef typename CharEncoding::char_type char_type; | |
|         typedef CharEncoding char_encoding; | |
| 
 | |
|         literal_char(char_type ch) | |
|           : lo(static_cast<char_type>(char_encoding::tolower(ch))) | |
|           , hi(static_cast<char_type>(char_encoding::toupper(ch))) {} | |
| 
 | |
|         template <typename Context, typename Iterator> | |
|         struct attribute | |
|         { | |
|             typedef typename mpl::if_c< | |
|                 no_attribute, unused_type, char_type>::type | |
|             type; | |
|         }; | |
| 
 | |
|         template <typename CharParam, typename Context> | |
|         bool test(CharParam ch_, Context&) const | |
|         { | |
|             if (!traits::ischar<CharParam, char_encoding>::call(ch_)) | |
|                 return false; | |
| 
 | |
|             char_type ch = char_type(ch_);  // optimize for token based parsing | |
|             return this->lo == ch || this->hi == ch; | |
|         } | |
| 
 | |
|         template <typename Context> | |
|         info what(Context& /*context*/) const | |
|         { | |
|             return info("no-case-literal-char", char_encoding::toucs4(lo)); | |
|         } | |
| 
 | |
|         char_type lo, hi; | |
|     }; | |
| 
 | |
|     /////////////////////////////////////////////////////////////////////////// | |
|     // Parser for a character range | |
|     /////////////////////////////////////////////////////////////////////////// | |
|     template <typename CharEncoding, bool no_case = false> | |
|     struct char_range | |
|       : char_parser<char_range<CharEncoding, false>, typename CharEncoding::char_type> | |
|     { | |
|         typedef typename CharEncoding::char_type char_type; | |
|         typedef CharEncoding char_encoding; | |
| 
 | |
|         char_range(char_type from, char_type to) | |
|           : from(from), to(to) {} | |
| 
 | |
|         template <typename CharParam, typename Context> | |
|         bool test(CharParam ch_, Context&) const | |
|         { | |
|             if (!traits::ischar<CharParam, char_encoding>::call(ch_)) | |
|                 return false; | |
| 
 | |
|             char_type ch = char_type(ch_);  // optimize for token based parsing | |
|             return !(ch < from) && !(to < ch); | |
|         } | |
| 
 | |
|         template <typename Context> | |
|         info what(Context& /*context*/) const | |
|         { | |
|             info result("char-range", char_encoding::toucs4(from)); | |
|             boost::get<std::string>(result.value) += '-'; | |
|             boost::get<std::string>(result.value) += to_utf8(char_encoding::toucs4(to)); | |
|             return result; | |
|         } | |
| 
 | |
|         char_type from, to; | |
|     }; | |
| 
 | |
|     template <typename CharEncoding> | |
|     struct char_range<CharEncoding, true> // case insensitive | |
|       : char_parser<char_range<CharEncoding, true>, typename CharEncoding::char_type> | |
|     { | |
|         typedef typename CharEncoding::char_type char_type; | |
|         typedef CharEncoding char_encoding; | |
| 
 | |
|         char_range(char_type from, char_type to) | |
|           : from_lo(static_cast<char_type>(char_encoding::tolower(from))) | |
|           , to_lo(static_cast<char_type>(char_encoding::tolower(to))) | |
|           , from_hi(static_cast<char_type>(char_encoding::toupper(from))) | |
|           , to_hi(static_cast<char_type>(char_encoding::toupper(to))) | |
|         {} | |
| 
 | |
|         template <typename CharParam, typename Context> | |
|         bool test(CharParam ch_, Context&) const | |
|         { | |
|             if (!traits::ischar<CharParam, char_encoding>::call(ch_)) | |
|                 return false; | |
| 
 | |
|             char_type ch = char_type(ch_);  // optimize for token based parsing | |
|             return (!(ch < from_lo) && !(to_lo < ch)) | |
|                 || (!(ch < from_hi) && !(to_hi < ch)) | |
|             ; | |
|         } | |
| 
 | |
|         template <typename Context> | |
|         info what(Context& /*context*/) const | |
|         { | |
|             info result("no-case-char-range", char_encoding::toucs4(from_lo)); | |
|             boost::get<std::string>(result.value) += '-'; | |
|             boost::get<std::string>(result.value) += to_utf8(char_encoding::toucs4(to_lo)); | |
|             return result; | |
|         } | |
| 
 | |
|         char_type from_lo, to_lo, from_hi, to_hi; | |
|     }; | |
| 
 | |
|     /////////////////////////////////////////////////////////////////////////// | |
|     // Parser for a character set | |
|     /////////////////////////////////////////////////////////////////////////// | |
|     template <typename CharEncoding, bool no_attribute, bool no_case = false> | |
|     struct char_set | |
|       : char_parser<char_set<CharEncoding, no_attribute, false> | |
|           , typename mpl::if_c<no_attribute, unused_type | |
|               , typename CharEncoding::char_type>::type> | |
|     { | |
|         typedef typename CharEncoding::char_type char_type; | |
|         typedef CharEncoding char_encoding; | |
| 
 | |
|         template <typename String> | |
|         char_set(String const& str) | |
|         { | |
|             using spirit::detail::cast_char; | |
| 
 | |
|             typedef typename | |
|                 remove_const< | |
|                     typename traits::char_type_of<String>::type | |
|                 >::type | |
|             in_type; | |
| 
 | |
|             BOOST_SPIRIT_ASSERT_MSG(( | |
|                 (sizeof(char_type) >= sizeof(in_type)) | |
|             ), cannot_convert_string, (String)); | |
| 
 | |
|             in_type const* definition = | |
|                 (in_type const*)traits::get_c_string(str); | |
|             in_type ch = *definition++; | |
|             while (ch) | |
|             { | |
|                 in_type next = *definition++; | |
|                 if (next == '-') | |
|                 { | |
|                     next = *definition++; | |
|                     if (next == 0) | |
|                     { | |
|                         chset.set(cast_char<char_type>(ch)); | |
|                         chset.set('-'); | |
|                         break; | |
|                     } | |
|                     chset.set( | |
|                         cast_char<char_type>(ch), | |
|                         cast_char<char_type>(next) | |
|                     ); | |
|                 } | |
|                 else | |
|                 { | |
|                     chset.set(cast_char<char_type>(ch)); | |
|                 } | |
|                 ch = next; | |
|             } | |
|         } | |
| 
 | |
|         template <typename CharParam, typename Context> | |
|         bool test(CharParam ch, Context&) const | |
|         { | |
|             return traits::ischar<CharParam, char_encoding>::call(ch) && | |
|                    chset.test(char_type(ch)); | |
|         } | |
| 
 | |
|         template <typename Context> | |
|         info what(Context& /*context*/) const | |
|         { | |
|             return info("char-set"); | |
|         } | |
| 
 | |
|         support::detail::basic_chset<char_type> chset; | |
|     }; | |
| 
 | |
|     template <typename CharEncoding, bool no_attribute> | |
|     struct char_set<CharEncoding, no_attribute, true> // case insensitive | |
|       : char_parser<char_set<CharEncoding, no_attribute, true> | |
|           , typename mpl::if_c<no_attribute, unused_type | |
|               , typename CharEncoding::char_type>::type> | |
|     { | |
|         typedef typename CharEncoding::char_type char_type; | |
|         typedef CharEncoding char_encoding; | |
| 
 | |
|         template <typename String> | |
|         char_set(String const& str) | |
|         { | |
|             typedef typename traits::char_type_of<String>::type in_type; | |
| 
 | |
|             BOOST_SPIRIT_ASSERT_MSG(( | |
|                 (sizeof(char_type) == sizeof(in_type)) | |
|             ), cannot_convert_string, (String)); | |
| 
 | |
|             char_type const* definition = | |
|                 (char_type const*)traits::get_c_string(str); | |
|             char_type ch = *definition++; | |
|             while (ch) | |
|             { | |
|                 char_type next = *definition++; | |
|                 if (next == '-') | |
|                 { | |
|                     next = *definition++; | |
|                     if (next == 0) | |
|                     { | |
|                         chset.set(static_cast<char_type>(CharEncoding::tolower(ch))); | |
|                         chset.set(static_cast<char_type>(CharEncoding::toupper(ch))); | |
|                         chset.set('-'); | |
|                         break; | |
|                     } | |
|                     chset.set(static_cast<char_type>(CharEncoding::tolower(ch)) | |
|                       , static_cast<char_type>(CharEncoding::tolower(next))); | |
|                     chset.set(static_cast<char_type>(CharEncoding::toupper(ch)) | |
|                       , static_cast<char_type>(CharEncoding::toupper(next))); | |
|                 } | |
|                 else | |
|                 { | |
|                     chset.set(static_cast<char_type>(CharEncoding::tolower(ch))); | |
|                     chset.set(static_cast<char_type>(CharEncoding::toupper(ch))); | |
|                 } | |
|                 ch = next; | |
|             } | |
|         } | |
| 
 | |
|         template <typename CharParam, typename Context> | |
|         bool test(CharParam ch, Context&) const | |
|         { | |
|             return traits::ischar<CharParam, char_encoding>::call(ch) && | |
|                    chset.test(char_type(ch)); | |
|         } | |
| 
 | |
|         template <typename Context> | |
|         info what(Context& /*context*/) const | |
|         { | |
|             return info("no-case-char-set"); | |
|         } | |
| 
 | |
|         support::detail::basic_chset<char_type> chset; | |
|     }; | |
| 
 | |
|     /////////////////////////////////////////////////////////////////////////// | |
|     // Parser generators: make_xxx function (objects) | |
|     /////////////////////////////////////////////////////////////////////////// | |
|     namespace detail | |
|     { | |
|         template <typename Modifiers, typename Encoding> | |
|         struct basic_literal | |
|         { | |
|             static bool const no_case = | |
|                 has_modifier< | |
|                     Modifiers | |
|                   , tag::char_code_base<tag::no_case> | |
|                 >::value; | |
| 
 | |
|             static bool const no_attr = | |
|                 !has_modifier< | |
|                     Modifiers | |
|                   , tag::lazy_eval | |
|                 >::value; | |
| 
 | |
|             typedef literal_char< | |
|                 typename spirit::detail::get_encoding_with_case< | |
|                     Modifiers, Encoding, no_case>::type | |
|               , no_attr | |
|               , no_case> | |
|             result_type; | |
| 
 | |
|             template <typename Char> | |
|             result_type operator()(Char ch, unused_type) const | |
|             { | |
|                 return result_type(ch); | |
|             } | |
| 
 | |
|             template <typename Char> | |
|             result_type operator()(Char const* str, unused_type) const | |
|             { | |
|                 return result_type(str[0]); | |
|             } | |
|         }; | |
|     } | |
| 
 | |
|     template <typename Modifiers> | |
|     struct make_primitive<char, Modifiers> | |
|       : detail::basic_literal<Modifiers, char_encoding::standard> {}; | |
| 
 | |
|     template <typename Modifiers> | |
|     struct make_primitive<char const(&)[2], Modifiers> | |
|       : detail::basic_literal<Modifiers, char_encoding::standard> {}; | |
| 
 | |
|     template <typename Modifiers> | |
|     struct make_primitive<wchar_t, Modifiers> | |
|       : detail::basic_literal<Modifiers, char_encoding::standard_wide> {}; | |
| 
 | |
|     template <typename Modifiers> | |
|     struct make_primitive<wchar_t const(&)[2], Modifiers> | |
|       : detail::basic_literal<Modifiers, char_encoding::standard_wide> {}; | |
| 
 | |
|     template <typename CharEncoding, typename Modifiers> | |
|     struct make_primitive< | |
|         terminal<tag::char_code<tag::char_, CharEncoding> >, Modifiers> | |
|     { | |
|         typedef typename | |
|             spirit::detail::get_encoding<Modifiers, CharEncoding>::type | |
|         char_encoding; | |
| 
 | |
|         typedef tag::char_code<tag::char_, char_encoding> tag; | |
|         typedef char_class<tag> result_type; | |
|         result_type operator()(unused_type, unused_type) const | |
|         { | |
|             return result_type(); | |
|         } | |
|     }; | |
| 
 | |
|     /////////////////////////////////////////////////////////////////////////// | |
|     // char_('x') | |
|     template <typename CharEncoding, typename Modifiers, typename A0> | |
|     struct make_primitive< | |
|         terminal_ex< | |
|             tag::char_code<tag::char_, CharEncoding> | |
|           , fusion::vector1<A0> > | |
|       , Modifiers> | |
|     { | |
|         static bool const no_case = | |
|             has_modifier<Modifiers, tag::char_code_base<tag::no_case> >::value; | |
| 
 | |
|         typedef typename | |
|             spirit::detail::get_encoding<Modifiers, CharEncoding>::type | |
|         char_encoding; | |
| 
 | |
|         typedef typename | |
|             mpl::if_< | |
|                 traits::is_string<A0> | |
|               , char_set<char_encoding, false, no_case> | |
|               , literal_char<char_encoding, false, no_case> | |
|             >::type | |
|         result_type; | |
| 
 | |
|         template <typename Terminal> | |
|         result_type operator()(Terminal const& term, unused_type) const | |
|         { | |
|             return result_type(fusion::at_c<0>(term.args)); | |
|         } | |
|     }; | |
| 
 | |
|     // lit('x') | |
|     template <typename Modifiers, typename A0> | |
|     struct make_primitive< | |
|         terminal_ex<tag::lit, fusion::vector1<A0> > | |
|       , Modifiers | |
|       , typename enable_if<traits::is_char<A0> >::type> | |
|     { | |
|         static bool const no_case = | |
|             has_modifier< | |
|                 Modifiers | |
|               , tag::char_code_base<tag::no_case> | |
|             >::value; | |
| 
 | |
|         typedef typename traits::char_encoding_from_char< | |
|                 typename traits::char_type_of<A0>::type>::type encoding; | |
| 
 | |
|         typedef literal_char< | |
|             typename spirit::detail::get_encoding_with_case< | |
|                 Modifiers, encoding, no_case>::type | |
|           , true, no_case> | |
|         result_type; | |
| 
 | |
|         template <typename Terminal> | |
|         result_type operator()(Terminal const& term, unused_type) const | |
|         { | |
|             return result_type(fusion::at_c<0>(term.args)); | |
|         } | |
|     }; | |
| 
 | |
|     /////////////////////////////////////////////////////////////////////////// | |
|     template <typename CharEncoding, typename Modifiers, typename Char> | |
|     struct make_primitive< | |
|         terminal_ex< | |
|             tag::char_code<tag::char_, CharEncoding> | |
|           , fusion::vector1<Char(&)[2]> // For single char strings | |
|         > | |
|       , Modifiers> | |
|     { | |
|         static bool const no_case = | |
|             has_modifier<Modifiers, tag::char_code_base<tag::no_case> >::value; | |
| 
 | |
|         typedef typename | |
|             spirit::detail::get_encoding<Modifiers, CharEncoding>::type | |
|         char_encoding; | |
| 
 | |
|         typedef literal_char<char_encoding, false, no_case> result_type; | |
| 
 | |
|         template <typename Terminal> | |
|         result_type operator()(Terminal const& term, unused_type) const | |
|         { | |
|             return result_type(fusion::at_c<0>(term.args)[0]); | |
|         } | |
|     }; | |
| 
 | |
|     template <typename CharEncoding, typename Modifiers, typename A0, typename A1> | |
|     struct make_primitive< | |
|         terminal_ex< | |
|             tag::char_code<tag::char_, CharEncoding> | |
|           , fusion::vector2<A0, A1> | |
|         > | |
|       , Modifiers> | |
|     { | |
|         static bool const no_case = | |
|             has_modifier<Modifiers, tag::char_code_base<tag::no_case> >::value; | |
| 
 | |
|         typedef typename | |
|             spirit::detail::get_encoding<Modifiers, CharEncoding>::type | |
|         char_encoding; | |
| 
 | |
|         typedef char_range<char_encoding, no_case> result_type; | |
| 
 | |
|         template <typename Terminal> | |
|         result_type operator()(Terminal const& term, unused_type) const | |
|         { | |
|             return result_type( | |
|                 fusion::at_c<0>(term.args) | |
|               , fusion::at_c<1>(term.args) | |
|             ); | |
|         } | |
|     }; | |
| 
 | |
|     template <typename CharEncoding, typename Modifiers, typename Char> | |
|     struct make_primitive< | |
|         terminal_ex< | |
|             tag::char_code<tag::char_, CharEncoding> | |
|           , fusion::vector2<Char(&)[2], Char(&)[2]> // For single char strings | |
|         > | |
|       , Modifiers> | |
|     { | |
|         static bool const no_case = | |
|             has_modifier<Modifiers, tag::char_code_base<tag::no_case> >::value; | |
| 
 | |
|         typedef typename | |
|             spirit::detail::get_encoding<Modifiers, CharEncoding>::type | |
|         char_encoding; | |
| 
 | |
|         typedef char_range<char_encoding, no_case> result_type; | |
| 
 | |
|         template <typename Terminal> | |
|         result_type operator()(Terminal const& term, unused_type) const | |
|         { | |
|             return result_type( | |
|                 fusion::at_c<0>(term.args)[0] | |
|               , fusion::at_c<1>(term.args)[0] | |
|             ); | |
|         } | |
|     }; | |
| }}} | |
| 
 | |
| #endif
 | |
| 
 |