1 /*============================================================================= 2 Copyright (c) 2001-2011 Joel de Guzman 3 Copyright (c) 2001-2011 Hartmut Kaiser 4 Copyright (c) 2010 Bryce Lelbach 5 6 Distributed under the Boost Software License, Version 1.0. (See accompanying 7 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 8 ==============================================================================*/ 9 #if !defined(BOOST_SPIRIT_CHAR_APRIL_16_2006_1051AM) 10 #define BOOST_SPIRIT_CHAR_APRIL_16_2006_1051AM 11 12 #if defined(_MSC_VER) 13 #pragma once 14 #endif 15 16 #include <boost/spirit/home/support/common_terminals.hpp> 17 #include <boost/spirit/home/support/string_traits.hpp> 18 #include <boost/spirit/home/support/info.hpp> 19 #include <boost/spirit/home/support/detail/get_encoding.hpp> 20 #include <boost/spirit/home/support/char_set/basic_chset.hpp> 21 #include <boost/spirit/home/qi/char/char_parser.hpp> 22 #include <boost/spirit/home/qi/char/char_class.hpp> 23 #include <boost/spirit/home/qi/meta_compiler.hpp> 24 #include <boost/spirit/home/qi/auxiliary/lazy.hpp> 25 #include <boost/spirit/home/qi/detail/enable_lit.hpp> 26 #include <boost/fusion/include/at.hpp> 27 #include <boost/mpl/if.hpp> 28 #include <boost/mpl/assert.hpp> 29 #include <boost/mpl/identity.hpp> 30 #include <boost/utility/enable_if.hpp> 31 #include <boost/type_traits/remove_const.hpp> 32 #include <string> 33 34 #if defined(_MSC_VER) 35 #pragma once 36 #endif 37 38 namespace boost { namespace spirit 39 { 40 /////////////////////////////////////////////////////////////////////////// 41 // Enablers 42 /////////////////////////////////////////////////////////////////////////// 43 template <typename CharEncoding> 44 struct use_terminal<qi::domain 45 , terminal< 46 tag::char_code<tag::char_, CharEncoding> // enables char_ 47 > 48 > : mpl::true_ {}; 49 50 template <typename CharEncoding, typename A0> 51 struct use_terminal<qi::domain 52 , terminal_ex< 53 tag::char_code<tag::char_, CharEncoding> // enables char_('x'), char_("x") 54 , fusion::vector1<A0> // and char_("a-z0-9") 55 > 56 > : mpl::true_ {}; 57 58 template <typename CharEncoding, typename A0, typename A1> 59 struct use_terminal<qi::domain 60 , terminal_ex< 61 tag::char_code<tag::char_, CharEncoding> // enables char_('a','z') 62 , fusion::vector2<A0, A1> 63 > 64 > : mpl::true_ {}; 65 66 template <typename CharEncoding> // enables *lazy* char_('x'), char_("x") 67 struct use_lazy_terminal< // and char_("a-z0-9") 68 qi::domain 69 , tag::char_code<tag::char_, CharEncoding> 70 , 1 // arity 71 > : mpl::true_ {}; 72 73 template <typename CharEncoding> // enables *lazy* char_('a','z') 74 struct use_lazy_terminal< 75 qi::domain 76 , tag::char_code<tag::char_, CharEncoding> 77 , 2 // arity 78 > : mpl::true_ {}; 79 80 template <> 81 struct use_terminal<qi::domain, char> // enables 'x' 82 : mpl::true_ {}; 83 84 template <> 85 struct use_terminal<qi::domain, char[2]> // enables "x" 86 : mpl::true_ {}; 87 88 template <> 89 struct use_terminal<qi::domain, wchar_t> // enables wchar_t 90 : mpl::true_ {}; 91 92 template <> 93 struct use_terminal<qi::domain, wchar_t[2]> // enables L"x" 94 : mpl::true_ {}; 95 96 // enables lit(...) 97 template <typename A0> 98 struct use_terminal<qi::domain 99 , terminal_ex<tag::lit, fusion::vector1<A0> > 100 , typename enable_if<traits::is_char<A0> >::type> 101 : mpl::true_ {}; 102 }} 103 104 namespace boost { namespace spirit { namespace qi 105 { 106 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS 107 using spirit::lit; // lit('x') is equivalent to 'x' 108 #endif 109 using spirit::lit_type; 110 111 /////////////////////////////////////////////////////////////////////////// 112 // Parser for a single character 113 /////////////////////////////////////////////////////////////////////////// 114 template <typename CharEncoding, bool no_attribute, bool no_case = false> 115 struct literal_char 116 : char_parser< 117 literal_char<CharEncoding, no_attribute, false> 118 , typename CharEncoding::char_type 119 , typename mpl::if_c<no_attribute, unused_type 120 , typename CharEncoding::char_type>::type> 121 { 122 typedef typename CharEncoding::char_type char_type; 123 typedef CharEncoding char_encoding; 124 125 template <typename Char> literal_charboost::spirit::qi::literal_char126 literal_char(Char ch_) 127 : ch(static_cast<char_type>(ch_)) {} 128 129 template <typename Context, typename Iterator> 130 struct attribute 131 { 132 typedef typename mpl::if_c< 133 no_attribute, unused_type, char_type>::type 134 type; 135 }; 136 137 template <typename CharParam, typename Context> testboost::spirit::qi::literal_char138 bool test(CharParam ch_, Context&) const 139 { 140 return traits::ischar<CharParam, char_encoding>::call(ch_) && 141 ch == char_type(ch_); 142 } 143 144 template <typename Context> whatboost::spirit::qi::literal_char145 info what(Context& /*context*/) const 146 { 147 return info("literal-char", char_encoding::toucs4(ch)); 148 } 149 150 char_type ch; 151 }; 152 153 template <typename CharEncoding, bool no_attribute> 154 struct literal_char<CharEncoding, no_attribute, true> // case insensitive 155 : char_parser< 156 literal_char<CharEncoding, no_attribute, true> 157 , typename mpl::if_c<no_attribute, unused_type 158 , typename CharEncoding::char_type>::type> 159 { 160 typedef typename CharEncoding::char_type char_type; 161 typedef CharEncoding char_encoding; 162 literal_charboost::spirit::qi::literal_char163 literal_char(char_type ch) 164 : lo(static_cast<char_type>(char_encoding::tolower(ch))) 165 , hi(static_cast<char_type>(char_encoding::toupper(ch))) {} 166 167 template <typename Context, typename Iterator> 168 struct attribute 169 { 170 typedef typename mpl::if_c< 171 no_attribute, unused_type, char_type>::type 172 type; 173 }; 174 175 template <typename CharParam, typename Context> testboost::spirit::qi::literal_char176 bool test(CharParam ch_, Context&) const 177 { 178 if (!traits::ischar<CharParam, char_encoding>::call(ch_)) 179 return false; 180 181 char_type ch = char_type(ch_); // optimize for token based parsing 182 return this->lo == ch || this->hi == ch; 183 } 184 185 template <typename Context> whatboost::spirit::qi::literal_char186 info what(Context& /*context*/) const 187 { 188 return info("no-case-literal-char", char_encoding::toucs4(lo)); 189 } 190 191 char_type lo, hi; 192 }; 193 194 /////////////////////////////////////////////////////////////////////////// 195 // Parser for a character range 196 /////////////////////////////////////////////////////////////////////////// 197 template <typename CharEncoding, bool no_case = false> 198 struct char_range 199 : char_parser<char_range<CharEncoding, false>, typename CharEncoding::char_type> 200 { 201 typedef typename CharEncoding::char_type char_type; 202 typedef CharEncoding char_encoding; 203 char_rangeboost::spirit::qi::char_range204 char_range(char_type from_, char_type to_) 205 : from(from_), to(to_) {} 206 207 template <typename CharParam, typename Context> testboost::spirit::qi::char_range208 bool test(CharParam ch_, Context&) const 209 { 210 if (!traits::ischar<CharParam, char_encoding>::call(ch_)) 211 return false; 212 213 char_type ch = char_type(ch_); // optimize for token based parsing 214 return !(ch < from) && !(to < ch); 215 } 216 217 template <typename Context> whatboost::spirit::qi::char_range218 info what(Context& /*context*/) const 219 { 220 info result("char-range", char_encoding::toucs4(from)); 221 boost::get<std::string>(result.value) += '-'; 222 boost::get<std::string>(result.value) += to_utf8(char_encoding::toucs4(to)); 223 return result; 224 } 225 226 char_type from, to; 227 }; 228 229 template <typename CharEncoding> 230 struct char_range<CharEncoding, true> // case insensitive 231 : char_parser<char_range<CharEncoding, true>, typename CharEncoding::char_type> 232 { 233 typedef typename CharEncoding::char_type char_type; 234 typedef CharEncoding char_encoding; 235 char_rangeboost::spirit::qi::char_range236 char_range(char_type from, char_type to) 237 : from_lo(static_cast<char_type>(char_encoding::tolower(from))) 238 , to_lo(static_cast<char_type>(char_encoding::tolower(to))) 239 , from_hi(static_cast<char_type>(char_encoding::toupper(from))) 240 , to_hi(static_cast<char_type>(char_encoding::toupper(to))) 241 {} 242 243 template <typename CharParam, typename Context> testboost::spirit::qi::char_range244 bool test(CharParam ch_, Context&) const 245 { 246 if (!traits::ischar<CharParam, char_encoding>::call(ch_)) 247 return false; 248 249 char_type ch = char_type(ch_); // optimize for token based parsing 250 return (!(ch < from_lo) && !(to_lo < ch)) 251 || (!(ch < from_hi) && !(to_hi < ch)) 252 ; 253 } 254 255 template <typename Context> whatboost::spirit::qi::char_range256 info what(Context& /*context*/) const 257 { 258 info result("no-case-char-range", char_encoding::toucs4(from_lo)); 259 boost::get<std::string>(result.value) += '-'; 260 boost::get<std::string>(result.value) += to_utf8(char_encoding::toucs4(to_lo)); 261 return result; 262 } 263 264 char_type from_lo, to_lo, from_hi, to_hi; 265 }; 266 267 /////////////////////////////////////////////////////////////////////////// 268 // Parser for a character set 269 /////////////////////////////////////////////////////////////////////////// 270 template <typename CharEncoding, bool no_attribute, bool no_case = false> 271 struct char_set 272 : char_parser<char_set<CharEncoding, no_attribute, false> 273 , typename mpl::if_c<no_attribute, unused_type 274 , typename CharEncoding::char_type>::type> 275 { 276 typedef typename CharEncoding::char_type char_type; 277 typedef CharEncoding char_encoding; 278 279 template <typename String> char_setboost::spirit::qi::char_set280 char_set(String const& str) 281 { 282 using spirit::detail::cast_char; 283 284 typedef typename 285 remove_const< 286 typename traits::char_type_of<String>::type 287 >::type 288 in_type; 289 290 BOOST_SPIRIT_ASSERT_MSG(( 291 (sizeof(char_type) >= sizeof(in_type)) 292 ), cannot_convert_string, (String)); 293 294 in_type const* definition = 295 (in_type const*)traits::get_c_string(str); 296 in_type ch = *definition++; 297 while (ch) 298 { 299 in_type next = *definition++; 300 if (next == '-') 301 { 302 next = *definition++; 303 if (next == 0) 304 { 305 chset.set(cast_char<char_type>(ch)); 306 chset.set('-'); 307 break; 308 } 309 chset.set( 310 cast_char<char_type>(ch), 311 cast_char<char_type>(next) 312 ); 313 } 314 else 315 { 316 chset.set(cast_char<char_type>(ch)); 317 } 318 ch = next; 319 } 320 } 321 322 template <typename CharParam, typename Context> testboost::spirit::qi::char_set323 bool test(CharParam ch, Context&) const 324 { 325 return traits::ischar<CharParam, char_encoding>::call(ch) && 326 chset.test(char_type(ch)); 327 } 328 329 template <typename Context> whatboost::spirit::qi::char_set330 info what(Context& /*context*/) const 331 { 332 return info("char-set"); 333 } 334 335 support::detail::basic_chset<char_type> chset; 336 }; 337 338 template <typename CharEncoding, bool no_attribute> 339 struct char_set<CharEncoding, no_attribute, true> // case insensitive 340 : char_parser<char_set<CharEncoding, no_attribute, true> 341 , typename mpl::if_c<no_attribute, unused_type 342 , typename CharEncoding::char_type>::type> 343 { 344 typedef typename CharEncoding::char_type char_type; 345 typedef CharEncoding char_encoding; 346 347 template <typename String> char_setboost::spirit::qi::char_set348 char_set(String const& str) 349 { 350 typedef typename traits::char_type_of<String>::type in_type; 351 352 BOOST_SPIRIT_ASSERT_MSG(( 353 (sizeof(char_type) == sizeof(in_type)) 354 ), cannot_convert_string, (String)); 355 356 char_type const* definition = 357 (char_type const*)traits::get_c_string(str); 358 char_type ch = *definition++; 359 while (ch) 360 { 361 char_type next = *definition++; 362 if (next == '-') 363 { 364 next = *definition++; 365 if (next == 0) 366 { 367 chset.set(static_cast<char_type>(CharEncoding::tolower(ch))); 368 chset.set(static_cast<char_type>(CharEncoding::toupper(ch))); 369 chset.set('-'); 370 break; 371 } 372 chset.set(static_cast<char_type>(CharEncoding::tolower(ch)) 373 , static_cast<char_type>(CharEncoding::tolower(next))); 374 chset.set(static_cast<char_type>(CharEncoding::toupper(ch)) 375 , static_cast<char_type>(CharEncoding::toupper(next))); 376 } 377 else 378 { 379 chset.set(static_cast<char_type>(CharEncoding::tolower(ch))); 380 chset.set(static_cast<char_type>(CharEncoding::toupper(ch))); 381 } 382 ch = next; 383 } 384 } 385 386 template <typename CharParam, typename Context> testboost::spirit::qi::char_set387 bool test(CharParam ch, Context&) const 388 { 389 return traits::ischar<CharParam, char_encoding>::call(ch) && 390 chset.test(char_type(ch)); 391 } 392 393 template <typename Context> whatboost::spirit::qi::char_set394 info what(Context& /*context*/) const 395 { 396 return info("no-case-char-set"); 397 } 398 399 support::detail::basic_chset<char_type> chset; 400 }; 401 402 /////////////////////////////////////////////////////////////////////////// 403 // Parser generators: make_xxx function (objects) 404 /////////////////////////////////////////////////////////////////////////// 405 namespace detail 406 { 407 template <typename Modifiers, typename Encoding> 408 struct basic_literal 409 { 410 static bool const no_case = 411 has_modifier< 412 Modifiers 413 , tag::char_code_base<tag::no_case> 414 >::value; 415 416 static bool const no_attr = 417 !has_modifier< 418 Modifiers 419 , tag::lazy_eval 420 >::value; 421 422 typedef literal_char< 423 typename spirit::detail::get_encoding_with_case< 424 Modifiers, Encoding, no_case>::type 425 , no_attr 426 , no_case> 427 result_type; 428 429 template <typename Char> operator ()boost::spirit::qi::detail::basic_literal430 result_type operator()(Char ch, unused_type) const 431 { 432 return result_type(ch); 433 } 434 435 template <typename Char> operator ()boost::spirit::qi::detail::basic_literal436 result_type operator()(Char const* str, unused_type) const 437 { 438 return result_type(str[0]); 439 } 440 }; 441 } 442 443 template <typename Modifiers> 444 struct make_primitive<char, Modifiers> 445 : detail::basic_literal<Modifiers, char_encoding::standard> {}; 446 447 template <typename Modifiers> 448 struct make_primitive<char const(&)[2], Modifiers> 449 : detail::basic_literal<Modifiers, char_encoding::standard> {}; 450 451 template <typename Modifiers> 452 struct make_primitive<wchar_t, Modifiers> 453 : detail::basic_literal<Modifiers, char_encoding::standard_wide> {}; 454 455 template <typename Modifiers> 456 struct make_primitive<wchar_t const(&)[2], Modifiers> 457 : detail::basic_literal<Modifiers, char_encoding::standard_wide> {}; 458 459 template <typename CharEncoding, typename Modifiers> 460 struct make_primitive< 461 terminal<tag::char_code<tag::char_, CharEncoding> >, Modifiers> 462 { 463 typedef typename 464 spirit::detail::get_encoding<Modifiers, CharEncoding>::type 465 char_encoding; 466 467 typedef tag::char_code<tag::char_, char_encoding> tag; 468 typedef char_class<tag> result_type; operator ()boost::spirit::qi::make_primitive469 result_type operator()(unused_type, unused_type) const 470 { 471 return result_type(); 472 } 473 }; 474 475 /////////////////////////////////////////////////////////////////////////// 476 // char_('x') 477 template <typename CharEncoding, typename Modifiers, typename A0> 478 struct make_primitive< 479 terminal_ex< 480 tag::char_code<tag::char_, CharEncoding> 481 , fusion::vector1<A0> > 482 , Modifiers> 483 { 484 static bool const no_case = 485 has_modifier<Modifiers, tag::char_code_base<tag::no_case> >::value; 486 487 typedef typename 488 spirit::detail::get_encoding<Modifiers, CharEncoding>::type 489 char_encoding; 490 491 typedef typename 492 mpl::if_< 493 traits::is_string<A0> 494 , char_set<char_encoding, false, no_case> 495 , literal_char<char_encoding, false, no_case> 496 >::type 497 result_type; 498 499 template <typename Terminal> operator ()boost::spirit::qi::make_primitive500 result_type operator()(Terminal const& term, unused_type) const 501 { 502 return result_type(fusion::at_c<0>(term.args)); 503 } 504 }; 505 506 // lit('x') 507 template <typename Modifiers, typename A0> 508 struct make_primitive< 509 terminal_ex<tag::lit, fusion::vector1<A0> > 510 , Modifiers 511 , typename enable_if<traits::is_char<A0> >::type> 512 { 513 static bool const no_case = 514 has_modifier< 515 Modifiers 516 , tag::char_code_base<tag::no_case> 517 >::value; 518 519 typedef typename traits::char_encoding_from_char< 520 typename traits::char_type_of<A0>::type>::type encoding; 521 522 typedef literal_char< 523 typename spirit::detail::get_encoding_with_case< 524 Modifiers, encoding, no_case>::type 525 , true, no_case> 526 result_type; 527 528 template <typename Terminal> operator ()boost::spirit::qi::make_primitive529 result_type operator()(Terminal const& term, unused_type) const 530 { 531 return result_type(fusion::at_c<0>(term.args)); 532 } 533 }; 534 535 /////////////////////////////////////////////////////////////////////////// 536 template <typename CharEncoding, typename Modifiers, typename Char> 537 struct make_primitive< 538 terminal_ex< 539 tag::char_code<tag::char_, CharEncoding> 540 , fusion::vector1<Char(&)[2]> // For single char strings 541 > 542 , Modifiers> 543 { 544 static bool const no_case = 545 has_modifier<Modifiers, tag::char_code_base<tag::no_case> >::value; 546 547 typedef typename 548 spirit::detail::get_encoding<Modifiers, CharEncoding>::type 549 char_encoding; 550 551 typedef literal_char<char_encoding, false, no_case> result_type; 552 553 template <typename Terminal> operator ()boost::spirit::qi::make_primitive554 result_type operator()(Terminal const& term, unused_type) const 555 { 556 return result_type(fusion::at_c<0>(term.args)[0]); 557 } 558 }; 559 560 template <typename CharEncoding, typename Modifiers, typename A0, typename A1> 561 struct make_primitive< 562 terminal_ex< 563 tag::char_code<tag::char_, CharEncoding> 564 , fusion::vector2<A0, A1> 565 > 566 , Modifiers> 567 { 568 static bool const no_case = 569 has_modifier<Modifiers, tag::char_code_base<tag::no_case> >::value; 570 571 typedef typename 572 spirit::detail::get_encoding<Modifiers, CharEncoding>::type 573 char_encoding; 574 575 typedef char_range<char_encoding, no_case> result_type; 576 577 template <typename Terminal> operator ()boost::spirit::qi::make_primitive578 result_type operator()(Terminal const& term, unused_type) const 579 { 580 return result_type( 581 fusion::at_c<0>(term.args) 582 , fusion::at_c<1>(term.args) 583 ); 584 } 585 }; 586 587 template <typename CharEncoding, typename Modifiers, typename Char> 588 struct make_primitive< 589 terminal_ex< 590 tag::char_code<tag::char_, CharEncoding> 591 , fusion::vector2<Char(&)[2], Char(&)[2]> // For single char strings 592 > 593 , Modifiers> 594 { 595 static bool const no_case = 596 has_modifier<Modifiers, tag::char_code_base<tag::no_case> >::value; 597 598 typedef typename 599 spirit::detail::get_encoding<Modifiers, CharEncoding>::type 600 char_encoding; 601 602 typedef char_range<char_encoding, no_case> result_type; 603 604 template <typename Terminal> operator ()boost::spirit::qi::make_primitive605 result_type operator()(Terminal const& term, unused_type) const 606 { 607 return result_type( 608 fusion::at_c<0>(term.args)[0] 609 , fusion::at_c<1>(term.args)[0] 610 ); 611 } 612 }; 613 }}} 614 615 #endif 616