1 /*============================================================================= 2 Boost.Wave: A Standard compliant C++ preprocessor library 3 Definition of the preprocessor context 4 5 http://www.boost.org/ 6 7 Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost 8 Software License, Version 1.0. (See accompanying file 9 LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 =============================================================================*/ 11 12 #if !defined(BOOST_CPP_CONTEXT_HPP_907485E2_6649_4A87_911B_7F7225F3E5B8_INCLUDED) 13 #define BOOST_CPP_CONTEXT_HPP_907485E2_6649_4A87_911B_7F7225F3E5B8_INCLUDED 14 15 #include <string> 16 #include <vector> 17 #include <stack> 18 19 #include <boost/concept_check.hpp> 20 #include <boost/noncopyable.hpp> 21 #include <boost/filesystem/path.hpp> 22 #include <boost/mpl/if.hpp> 23 #include <boost/type_traits/is_same.hpp> 24 #include <boost/pool/pool_alloc.hpp> 25 26 #include <boost/wave/wave_config.hpp> 27 #if BOOST_WAVE_SERIALIZATION != 0 28 #include <boost/serialization/serialization.hpp> 29 #include <boost/wave/wave_config_constant.hpp> 30 #endif 31 #include <boost/wave/token_ids.hpp> 32 33 #include <boost/wave/util/unput_queue_iterator.hpp> 34 #include <boost/wave/util/cpp_ifblock.hpp> 35 #include <boost/wave/util/cpp_include_paths.hpp> 36 #include <boost/wave/util/iteration_context.hpp> 37 #include <boost/wave/util/cpp_iterator.hpp> 38 #include <boost/wave/util/cpp_macromap.hpp> 39 40 #include <boost/wave/preprocessing_hooks.hpp> 41 #include <boost/wave/whitespace_handling.hpp> 42 #include <boost/wave/cpp_iteration_context.hpp> 43 #include <boost/wave/language_support.hpp> 44 45 // this must occur after all of the includes and before any code appears 46 #ifdef BOOST_HAS_ABI_HEADERS 47 #include BOOST_ABI_PREFIX 48 #endif 49 50 /////////////////////////////////////////////////////////////////////////////// 51 namespace boost { 52 namespace wave { 53 54 /////////////////////////////////////////////////////////////////////////////// 55 // 56 // The C/C++ preprocessor context template class 57 // 58 // The boost::wave::context template is the main interface class to 59 // control the behavior of the preprocessing engine. 60 // 61 // The following template parameters has to be supplied: 62 // 63 // IteratorT The iterator type of the underlying input stream 64 // LexIteratorT The lexer iterator type to use as the token factory 65 // InputPolicyT The input policy type to use for loading the files 66 // to be included. This template parameter is optional and 67 // defaults to the 68 // iteration_context_policies::load_file_to_string 69 // type. 70 // HooksT The hooks policy to use for different notification 71 // callbacks. This template parameter is optional and 72 // defaults to the 73 // context_policies::default_preprocessing_hooks 74 // type. 75 // DerivedT The type of the type being derived from the context 76 // type (if any). This template parameter is optional and 77 // defaults to 'this_type', which means that the context 78 // type will be used assuming no derived type exists. 79 // 80 /////////////////////////////////////////////////////////////////////////////// 81 82 struct this_type {}; 83 84 template < 85 typename IteratorT, 86 typename LexIteratorT, 87 typename InputPolicyT = iteration_context_policies::load_file_to_string, 88 typename HooksT = context_policies::eat_whitespace<typename LexIteratorT::token_type>, 89 typename DerivedT = this_type 90 > 91 class context : private boost::noncopyable 92 { 93 private: 94 typedef typename mpl::if_< 95 is_same<DerivedT, this_type>, context, DerivedT 96 >::type actual_context_type; 97 98 public: 99 100 // concept checks 101 // the given iterator should be at least a forward iterator type 102 BOOST_CLASS_REQUIRE(IteratorT, boost, ForwardIteratorConcept); 103 104 // public typedefs 105 typedef typename LexIteratorT::token_type token_type; 106 typedef typename token_type::string_type string_type; 107 108 typedef IteratorT target_iterator_type; 109 typedef LexIteratorT lexer_type; 110 typedef pp_iterator<context> iterator_type; 111 112 typedef InputPolicyT input_policy_type; 113 typedef typename token_type::position_type position_type; 114 115 // type of a token sequence 116 typedef std::list<token_type, boost::fast_pool_allocator<token_type> > 117 token_sequence_type; 118 // type of the policies 119 typedef HooksT hook_policy_type; 120 121 private: 122 // stack of shared_ptr's to the pending iteration contexts 123 typedef boost::shared_ptr<base_iteration_context<context, lexer_type> > 124 iteration_ptr_type; 125 typedef boost::wave::util::iteration_context_stack<iteration_ptr_type> 126 iteration_context_stack_type; 127 typedef typename iteration_context_stack_type::size_type iter_size_type; 128 this_()129 context *this_() { return this; } // avoid warning in constructor 130 131 public: context(target_iterator_type const & first_,target_iterator_type const & last_,char const * fname="<Unknown>",HooksT const & hooks_=HooksT ())132 context(target_iterator_type const &first_, target_iterator_type const &last_, 133 char const *fname = "<Unknown>", HooksT const &hooks_ = HooksT()) 134 : first(first_), last(last_), filename(fname) 135 , has_been_initialized(false) 136 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 137 , current_filename(fname) 138 #endif 139 , current_relative_filename(fname) 140 , macros(*this_()) 141 , language(language_support( 142 support_cpp 143 | support_option_convert_trigraphs 144 | support_option_emit_line_directives 145 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 146 | support_option_include_guard_detection 147 #endif 148 #if BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES != 0 149 | support_option_emit_pragma_directives 150 #endif 151 | support_option_insert_whitespace 152 )) 153 , hooks(hooks_) 154 { 155 macros.init_predefined_macros(fname); 156 } 157 158 // default copy constructor 159 // default assignment operator 160 // default destructor 161 162 // iterator interface begin()163 iterator_type begin() 164 { 165 std::string fname(filename); 166 if (filename != "<Unknown>" && filename != "<stdin>") { 167 using namespace boost::filesystem; 168 path fpath(util::complete_path(path(filename))); 169 fname = fpath.string(); 170 } 171 return iterator_type(*this, first, last, position_type(fname.c_str())); 172 } begin(target_iterator_type const & first_,target_iterator_type const & last_)173 iterator_type begin( 174 target_iterator_type const &first_, 175 target_iterator_type const &last_) 176 { 177 std::string fname(filename); 178 if (filename != "<Unknown>" && filename != "<stdin>") { 179 using namespace boost::filesystem; 180 path fpath(util::complete_path(path(filename))); 181 fname = fpath.string(); 182 } 183 return iterator_type(*this, first_, last_, position_type(fname.c_str())); 184 } end() const185 iterator_type end() const 186 { return iterator_type(); } 187 188 // maintain include paths add_include_path(char const * path_)189 bool add_include_path(char const *path_) 190 { return includes.add_include_path(path_, false);} add_sysinclude_path(char const * path_)191 bool add_sysinclude_path(char const *path_) 192 { return includes.add_include_path(path_, true);} set_sysinclude_delimiter()193 void set_sysinclude_delimiter() { includes.set_sys_include_delimiter(); } get_iteration_depth() const194 typename iteration_context_stack_type::size_type get_iteration_depth() const 195 { return iter_ctxs.size(); } 196 197 // maintain defined macros 198 #if BOOST_WAVE_ENABLE_COMMANDLINE_MACROS != 0 199 template <typename StringT> add_macro_definition(StringT macrostring,bool is_predefined=false)200 bool add_macro_definition(StringT macrostring, bool is_predefined = false) 201 { 202 return boost::wave::util::add_macro_definition(*this, 203 util::to_string<std::string>(macrostring), is_predefined, 204 get_language()); 205 } 206 #endif 207 // Define and undefine macros, macro introspection 208 template <typename StringT> add_macro_definition(StringT const & name,position_type const & pos,bool has_params,std::vector<token_type> & parameters,token_sequence_type & definition,bool is_predefined=false)209 bool add_macro_definition(StringT const &name, position_type const& pos, 210 bool has_params, std::vector<token_type> ¶meters, 211 token_sequence_type &definition, bool is_predefined = false) 212 { 213 return macros.add_macro( 214 token_type(T_IDENTIFIER, util::to_string<string_type>(name), pos), 215 has_params, parameters, definition, is_predefined); 216 } 217 template <typename StringT> is_defined_macro(StringT const & str) const218 bool is_defined_macro(StringT const &str) const 219 { 220 return macros.is_defined(util::to_string<string_type>(str)); 221 } 222 template <typename StringT> get_macro_definition(StringT const & name,bool & has_params,bool & is_predefined,position_type & pos,std::vector<token_type> & parameters,token_sequence_type & definition) const223 bool get_macro_definition(StringT const &name, 224 bool &has_params, bool &is_predefined, position_type &pos, 225 std::vector<token_type> ¶meters, 226 token_sequence_type &definition) const 227 { 228 return macros.get_macro(util::to_string<string_type>(name), 229 has_params, is_predefined, pos, parameters, definition); 230 } 231 template <typename StringT> remove_macro_definition(StringT const & undefname,bool even_predefined=false)232 bool remove_macro_definition(StringT const& undefname, bool even_predefined = false) 233 { 234 // strip leading and trailing whitespace 235 string_type name = util::to_string<string_type>(undefname); 236 typename string_type::size_type pos = name.find_first_not_of(" \t"); 237 if (pos != string_type::npos) { 238 typename string_type::size_type endpos = name.find_last_not_of(" \t"); 239 name = name.substr(pos, endpos-pos+1); 240 } 241 242 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 243 // ensure this gets removed from the list of include guards as well 244 includes.remove_pragma_once_header( 245 util::to_string<std::string>(name)); 246 #endif 247 return macros.remove_macro(name, macros.get_main_pos(), even_predefined); 248 } reset_macro_definitions()249 void reset_macro_definitions() 250 { macros.reset_macromap(); macros.init_predefined_macros(); } 251 252 // Iterate over names of defined macros 253 typedef boost::wave::util::macromap<context> macromap_type; 254 typedef typename macromap_type::name_iterator name_iterator; 255 typedef typename macromap_type::const_name_iterator const_name_iterator; 256 macro_names_begin()257 name_iterator macro_names_begin() { return macros.begin(); } macro_names_end()258 name_iterator macro_names_end() { return macros.end(); } macro_names_begin() const259 const_name_iterator macro_names_begin() const { return macros.begin(); } macro_names_end() const260 const_name_iterator macro_names_end() const { return macros.end(); } 261 262 // This version now is used internally mainly, but since it was a documented 263 // API function we leave it in the public interface. add_macro_definition(token_type const & name,bool has_params,std::vector<token_type> & parameters,token_sequence_type & definition,bool is_predefined=false)264 bool add_macro_definition(token_type const &name, bool has_params, 265 std::vector<token_type> ¶meters, token_sequence_type &definition, 266 bool is_predefined = false) 267 { 268 return macros.add_macro(name, has_params, parameters, definition, 269 is_predefined); 270 } 271 272 // get the Wave version information get_version()273 static std::string get_version() 274 { 275 boost::wave::util::predefined_macros p; 276 return util::to_string<std::string>(p.get_fullversion()); 277 } get_version_string()278 static std::string get_version_string() 279 { 280 boost::wave::util::predefined_macros p; 281 return util::to_string<std::string>(p.get_versionstr()); 282 } 283 284 // access current language options set_language(boost::wave::language_support language_,bool reset_macros=true)285 void set_language(boost::wave::language_support language_, 286 bool reset_macros = true) 287 { 288 language = language_; 289 if (reset_macros) 290 reset_macro_definitions(); 291 } get_language() const292 boost::wave::language_support get_language() const { return language; } 293 get_main_pos()294 position_type &get_main_pos() { return macros.get_main_pos(); } get_main_pos() const295 position_type const& get_main_pos() const { return macros.get_main_pos(); } 296 297 // change and ask for maximal possible include nesting depth set_max_include_nesting_depth(iter_size_type new_depth)298 void set_max_include_nesting_depth(iter_size_type new_depth) 299 { iter_ctxs.set_max_include_nesting_depth(new_depth); } get_max_include_nesting_depth() const300 iter_size_type get_max_include_nesting_depth() const 301 { return iter_ctxs.get_max_include_nesting_depth(); } 302 303 // access the policies get_hooks()304 hook_policy_type &get_hooks() { return hooks; } get_hooks() const305 hook_policy_type const &get_hooks() const { return hooks; } 306 307 // return type of actually used context type (might be the derived type) derived()308 actual_context_type& derived() 309 { return *static_cast<actual_context_type*>(this); } derived() const310 actual_context_type const& derived() const 311 { return *static_cast<actual_context_type const*>(this); } 312 313 // return the directory of the currently preprocessed file get_current_directory() const314 boost::filesystem::path get_current_directory() const 315 { return includes.get_current_directory(); } 316 317 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) 318 protected: 319 friend class boost::wave::pp_iterator<context>; 320 friend class boost::wave::impl::pp_iterator_functor<context>; 321 friend class boost::wave::util::macromap<context>; 322 #endif 323 324 // make sure the context has been initialized init_context()325 void init_context() 326 { 327 if (!has_been_initialized) { 328 std::string fname(filename); 329 if (filename != "<Unknown>" && filename != "<stdin>") { 330 using namespace boost::filesystem; 331 path fpath(util::complete_path(path(filename))); 332 fname = fpath.string(); 333 includes.set_current_directory(fname.c_str()); 334 } 335 has_been_initialized = true; // execute once 336 } 337 } 338 339 template <typename IteratorT2> is_defined_macro(IteratorT2 const & begin,IteratorT2 const & end) const340 bool is_defined_macro(IteratorT2 const &begin, IteratorT2 const &end) const 341 { return macros.is_defined(begin, end); } 342 343 // maintain include paths (helper functions) set_current_directory(char const * path_)344 void set_current_directory(char const *path_) 345 { includes.set_current_directory(path_); } 346 347 // conditional compilation contexts get_if_block_status() const348 bool get_if_block_status() const { return ifblocks.get_status(); } get_if_block_some_part_status() const349 bool get_if_block_some_part_status() const 350 { return ifblocks.get_some_part_status(); } get_enclosing_if_block_status() const351 bool get_enclosing_if_block_status() const 352 { return ifblocks.get_enclosing_status(); } enter_if_block(bool new_status)353 void enter_if_block(bool new_status) 354 { ifblocks.enter_if_block(new_status); } enter_elif_block(bool new_status)355 bool enter_elif_block(bool new_status) 356 { return ifblocks.enter_elif_block(new_status); } enter_else_block()357 bool enter_else_block() { return ifblocks.enter_else_block(); } exit_if_block()358 bool exit_if_block() { return ifblocks.exit_if_block(); } get_if_block_depth() const359 typename boost::wave::util::if_block_stack::size_type get_if_block_depth() const 360 { return ifblocks.get_if_block_depth(); } 361 362 // stack of iteration contexts pop_iteration_context()363 iteration_ptr_type pop_iteration_context() 364 { iteration_ptr_type top = iter_ctxs.top(); iter_ctxs.pop(); return top; } push_iteration_context(position_type const & act_pos,iteration_ptr_type iter_ctx)365 void push_iteration_context(position_type const &act_pos, iteration_ptr_type iter_ctx) 366 { iter_ctxs.push(*this, act_pos, iter_ctx); } 367 368 /////////////////////////////////////////////////////////////////////////////// 369 // 370 // expand_tokensequence(): 371 // expands all macros contained in a given token sequence, handles '##' 372 // and '#' pp operators and re-scans the resulting sequence 373 // (essentially pre-processes the token sequence). 374 // 375 // The expand_defined parameter is true during macro expansion inside 376 // a C++ expression given for a #if or #elif statement. 377 // 378 /////////////////////////////////////////////////////////////////////////////// 379 template <typename IteratorT2> expand_tokensequence(IteratorT2 & first_,IteratorT2 const & last_,token_sequence_type & pending,token_sequence_type & expanded,bool & seen_newline,bool expand_defined=false,bool expand_has_include=false)380 token_type expand_tokensequence(IteratorT2 &first_, IteratorT2 const &last_, 381 token_sequence_type &pending, token_sequence_type &expanded, 382 bool& seen_newline, bool expand_defined = false, 383 bool expand_has_include = false) 384 { 385 return macros.expand_tokensequence(first_, last_, pending, expanded, 386 seen_newline, expand_defined, expand_has_include); 387 } 388 389 template <typename IteratorT2> expand_whole_tokensequence(IteratorT2 & first_,IteratorT2 const & last_,token_sequence_type & expanded,bool expand_defined=true,bool expand_has_include=true)390 void expand_whole_tokensequence(IteratorT2 &first_, IteratorT2 const &last_, 391 token_sequence_type &expanded, bool expand_defined = true, 392 bool expand_has_include = true) 393 { 394 macros.expand_whole_tokensequence( 395 expanded, first_, last_, 396 expand_defined, expand_has_include); 397 398 // remove any contained placeholder 399 boost::wave::util::impl::remove_placeholders(expanded); 400 } 401 402 public: 403 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 404 // support for #pragma once 405 // maintain the real name of the current preprocessed file set_current_filename(char const * real_name)406 void set_current_filename(char const *real_name) 407 { current_filename = real_name; } get_current_filename() const408 std::string const &get_current_filename() const 409 { return current_filename; } 410 411 // maintain the list of known headers containing #pragma once has_pragma_once(std::string const & filename_)412 bool has_pragma_once(std::string const &filename_) 413 { return includes.has_pragma_once(filename_); } add_pragma_once_header(std::string const & filename_,std::string const & guard_name)414 bool add_pragma_once_header(std::string const &filename_, 415 std::string const& guard_name) 416 { 417 get_hooks().detected_include_guard(derived(), filename_, guard_name); 418 return includes.add_pragma_once_header(filename_, guard_name); 419 } add_pragma_once_header(token_type const & pragma_,std::string const & filename_)420 bool add_pragma_once_header(token_type const &pragma_, 421 std::string const &filename_) 422 { 423 get_hooks().detected_pragma_once(derived(), pragma_, filename_); 424 return includes.add_pragma_once_header(filename_, 425 "__BOOST_WAVE_PRAGMA_ONCE__"); 426 } 427 #endif 428 set_current_relative_filename(char const * real_name)429 void set_current_relative_filename(char const *real_name) 430 { current_relative_filename = real_name; } get_current_relative_filename() const431 std::string const &get_current_relative_filename() const 432 { return current_relative_filename; } 433 find_include_file(std::string & s,std::string & d,bool is_system,char const * current_file) const434 bool find_include_file (std::string &s, std::string &d, bool is_system, 435 char const *current_file) const 436 { return includes.find_include_file(s, d, is_system, current_file); } 437 438 #if BOOST_WAVE_SERIALIZATION != 0 439 public: 440 BOOST_STATIC_CONSTANT(unsigned int, version = 0x10); 441 BOOST_STATIC_CONSTANT(unsigned int, version_mask = 0x0f); 442 443 private: 444 friend class boost::serialization::access; 445 template<class Archive> save(Archive & ar,const unsigned int version) const446 void save(Archive & ar, const unsigned int version) const 447 { 448 using namespace boost::serialization; 449 450 string_type cfg(BOOST_PP_STRINGIZE(BOOST_WAVE_CONFIG)); 451 string_type kwd(BOOST_WAVE_PRAGMA_KEYWORD); 452 string_type strtype(BOOST_PP_STRINGIZE((BOOST_WAVE_STRINGTYPE))); 453 ar & make_nvp("config", cfg); 454 ar & make_nvp("pragma_keyword", kwd); 455 ar & make_nvp("string_type", strtype); 456 457 ar & make_nvp("language_options", language); 458 ar & make_nvp("macro_definitions", macros); 459 ar & make_nvp("include_settings", includes); 460 } 461 template<class Archive> load(Archive & ar,const unsigned int loaded_version)462 void load(Archive & ar, const unsigned int loaded_version) 463 { 464 using namespace boost::serialization; 465 if (version != (loaded_version & ~version_mask)) { 466 BOOST_WAVE_THROW_CTX((*this), preprocess_exception, 467 incompatible_config, "cpp_context state version", 468 get_main_pos()); 469 return; 470 } 471 472 // check compatibility of the stored information 473 string_type config, pragma_keyword, string_type_str; 474 475 // BOOST_PP_STRINGIZE(BOOST_WAVE_CONFIG) 476 ar & make_nvp("config", config); 477 if (config != BOOST_PP_STRINGIZE(BOOST_WAVE_CONFIG)) { 478 BOOST_WAVE_THROW_CTX((*this), preprocess_exception, 479 incompatible_config, "BOOST_WAVE_CONFIG", get_main_pos()); 480 return; 481 } 482 483 // BOOST_WAVE_PRAGMA_KEYWORD 484 ar & make_nvp("pragma_keyword", pragma_keyword); 485 if (pragma_keyword != BOOST_WAVE_PRAGMA_KEYWORD) { 486 BOOST_WAVE_THROW_CTX((*this), preprocess_exception, 487 incompatible_config, "BOOST_WAVE_PRAGMA_KEYWORD", 488 get_main_pos()); 489 return; 490 } 491 492 // BOOST_PP_STRINGIZE((BOOST_WAVE_STRINGTYPE)) 493 ar & make_nvp("string_type", string_type_str); 494 if (string_type_str != BOOST_PP_STRINGIZE((BOOST_WAVE_STRINGTYPE))) { 495 BOOST_WAVE_THROW_CTX((*this), preprocess_exception, 496 incompatible_config, "BOOST_WAVE_STRINGTYPE", get_main_pos()); 497 return; 498 } 499 500 try { 501 // read in the useful bits 502 ar & make_nvp("language_options", language); 503 ar & make_nvp("macro_definitions", macros); 504 ar & make_nvp("include_settings", includes); 505 } 506 catch (boost::wave::preprocess_exception const& e) { 507 // catch version mismatch exceptions and call error handler 508 get_hooks().throw_exception(derived(), e); 509 } 510 } 511 BOOST_SERIALIZATION_SPLIT_MEMBER() 512 #endif 513 514 private: 515 // the main input stream 516 target_iterator_type first; // underlying input stream 517 target_iterator_type last; 518 std::string filename; // associated main filename 519 bool has_been_initialized; // set cwd once 520 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 521 std::string current_filename; // real name of current preprocessed file 522 #endif 523 std::string current_relative_filename; // real relative name of current preprocessed file 524 525 boost::wave::util::if_block_stack ifblocks; // conditional compilation contexts 526 boost::wave::util::include_paths includes; // lists of include directories to search 527 iteration_context_stack_type iter_ctxs; // iteration contexts 528 macromap_type macros; // map of defined macros 529 boost::wave::language_support language; // supported language/extensions 530 hook_policy_type hooks; // hook policy instance 531 }; 532 533 /////////////////////////////////////////////////////////////////////////////// 534 } // namespace wave 535 } // namespace boost 536 537 #if BOOST_WAVE_SERIALIZATION != 0 538 namespace boost { namespace serialization { 539 540 template< 541 typename Iterator, typename LexIterator, 542 typename InputPolicy, typename Hooks 543 > 544 struct tracking_level<boost::wave::context<Iterator, LexIterator, InputPolicy, Hooks> > 545 { 546 typedef mpl::integral_c_tag tag; 547 typedef mpl::int_<track_never> type; 548 BOOST_STATIC_CONSTANT( 549 int, 550 value = tracking_level::type::value 551 ); 552 }; 553 554 template< 555 typename Iterator, typename LexIterator, 556 typename InputPolicy, typename Hooks 557 > 558 struct version<boost::wave::context<Iterator, LexIterator, InputPolicy, Hooks> > 559 { 560 typedef boost::wave::context<Iterator, LexIterator, InputPolicy, Hooks> 561 target_type; 562 typedef mpl::int_<target_type::version> type; 563 typedef mpl::integral_c_tag tag; 564 BOOST_STATIC_CONSTANT(unsigned int, value = version::type::value); 565 }; 566 567 }} // namespace boost::serialization 568 #endif 569 570 // the suffix header occurs after all of the code 571 #ifdef BOOST_HAS_ABI_HEADERS 572 #include BOOST_ABI_SUFFIX 573 #endif 574 575 #endif // !defined(BOOST_CPP_CONTEXT_HPP_907485E2_6649_4A87_911B_7F7225F3E5B8_INCLUDED) 576