| /*============================================================================= |
| Boost.Wave: A Standard compliant C++ preprocessor library |
| Definition of the preprocessor context |
| |
| http://www.boost.org/ |
| |
| Copyright (c) 2001-2010 Hartmut Kaiser. 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(CPP_CONTEXT_HPP_907485E2_6649_4A87_911B_7F7225F3E5B8_INCLUDED) |
| #define CPP_CONTEXT_HPP_907485E2_6649_4A87_911B_7F7225F3E5B8_INCLUDED |
| |
| #include <string> |
| #include <vector> |
| #include <stack> |
| |
| #include <boost/concept_check.hpp> |
| #include <boost/noncopyable.hpp> |
| #include <boost/filesystem/path.hpp> |
| #include <boost/mpl/if.hpp> |
| #include <boost/type_traits/is_same.hpp> |
| #include <boost/pool/pool_alloc.hpp> |
| |
| #include <boost/wave/wave_config.hpp> |
| #if BOOST_WAVE_SERIALIZATION != 0 |
| #include <boost/serialization/serialization.hpp> |
| #include <boost/wave/wave_config_constant.hpp> |
| #endif |
| #include <boost/wave/token_ids.hpp> |
| |
| #include <boost/wave/util/unput_queue_iterator.hpp> |
| #include <boost/wave/util/cpp_ifblock.hpp> |
| #include <boost/wave/util/cpp_include_paths.hpp> |
| #include <boost/wave/util/iteration_context.hpp> |
| #include <boost/wave/util/cpp_iterator.hpp> |
| #include <boost/wave/util/cpp_macromap.hpp> |
| |
| #include <boost/wave/preprocessing_hooks.hpp> |
| #include <boost/wave/whitespace_handling.hpp> |
| #include <boost/wave/cpp_iteration_context.hpp> |
| #include <boost/wave/language_support.hpp> |
| |
| // this must occur after all of the includes and before any code appears |
| #ifdef BOOST_HAS_ABI_HEADERS |
| #include BOOST_ABI_PREFIX |
| #endif |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| namespace boost { |
| namespace wave { |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // The C/C++ preprocessor context template class |
| // |
| // The boost::wave::context template is the main interface class to |
| // control the behavior of the preprocessing engine. |
| // |
| // The following template parameters has to be supplied: |
| // |
| // IteratorT The iterator type of the underlying input stream |
| // LexIteratorT The lexer iterator type to use as the token factory |
| // InputPolicyT The input policy type to use for loading the files |
| // to be included. This template parameter is optional and |
| // defaults to the |
| // iteration_context_policies::load_file_to_string |
| // type. |
| // HooksT The hooks policy to use for different notification |
| // callbacks. This template parameter is optional and |
| // defaults to the |
| // context_policies::default_preprocessing_hooks |
| // type. |
| // DerivedT The type of the type being derived from the context |
| // type (if any). This template parameter is optional and |
| // defaults to 'this_type', which means that the context |
| // type will be used assuming no derived type exists. |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| struct this_type {}; |
| |
| template < |
| typename IteratorT, |
| typename LexIteratorT, |
| typename InputPolicyT = iteration_context_policies::load_file_to_string, |
| typename HooksT = context_policies::eat_whitespace<typename LexIteratorT::token_type>, |
| typename DerivedT = this_type |
| > |
| class context : private boost::noncopyable |
| { |
| private: |
| typedef typename mpl::if_< |
| is_same<DerivedT, this_type>, context, DerivedT |
| >::type actual_context_type; |
| |
| public: |
| |
| // concept checks |
| // the given iterator should be at least a forward iterator type |
| BOOST_CLASS_REQUIRE(IteratorT, boost, ForwardIteratorConcept); |
| |
| // public typedefs |
| typedef typename LexIteratorT::token_type token_type; |
| typedef typename token_type::string_type string_type; |
| |
| typedef IteratorT target_iterator_type; |
| typedef LexIteratorT lexer_type; |
| typedef pp_iterator<context> iterator_type; |
| |
| typedef InputPolicyT input_policy_type; |
| typedef typename token_type::position_type position_type; |
| |
| // type of a token sequence |
| typedef std::list<token_type, boost::fast_pool_allocator<token_type> > |
| token_sequence_type; |
| // type of the policies |
| typedef HooksT hook_policy_type; |
| |
| private: |
| // stack of shared_ptr's to the pending iteration contexts |
| typedef boost::shared_ptr<base_iteration_context<context, lexer_type> > |
| iteration_ptr_type; |
| typedef boost::wave::util::iteration_context_stack<iteration_ptr_type> |
| iteration_context_stack_type; |
| typedef typename iteration_context_stack_type::size_type iter_size_type; |
| |
| context *this_() { return this; } // avoid warning in constructor |
| |
| public: |
| context(target_iterator_type const &first_, target_iterator_type const &last_, |
| char const *fname = "<Unknown>", HooksT const &hooks_ = HooksT()) |
| : first(first_), last(last_), filename(fname) |
| , has_been_initialized(false) |
| #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 |
| , current_filename(fname) |
| #endif |
| , current_relative_filename(fname) |
| , macros(*this_()) |
| , language(language_support( |
| support_cpp |
| | support_option_convert_trigraphs |
| | support_option_emit_line_directives |
| #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 |
| | support_option_include_guard_detection |
| #endif |
| #if BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES != 0 |
| | support_option_emit_pragma_directives |
| #endif |
| | support_option_insert_whitespace |
| )) |
| , hooks(hooks_) |
| { |
| macros.init_predefined_macros(fname); |
| } |
| |
| // default copy constructor |
| // default assignment operator |
| // default destructor |
| |
| // iterator interface |
| iterator_type begin() |
| { |
| std::string fname(filename); |
| if (filename != "<Unknown>" && filename != "<stdin>") { |
| using namespace boost::filesystem; |
| path fpath(complete(path(filename))); |
| fname = fpath.string(); |
| } |
| return iterator_type(*this, first, last, position_type(fname.c_str())); |
| } |
| iterator_type begin( |
| target_iterator_type const &first_, |
| target_iterator_type const &last_) |
| { |
| std::string fname(filename); |
| if (filename != "<Unknown>" && filename != "<stdin>") { |
| using namespace boost::filesystem; |
| path fpath(complete(path(filename))); |
| fname = fpath.string(); |
| } |
| return iterator_type(*this, first_, last_, position_type(fname.c_str())); |
| } |
| iterator_type end() const |
| { return iterator_type(); } |
| |
| // maintain include paths |
| bool add_include_path(char const *path_) |
| { return includes.add_include_path(path_, false);} |
| bool add_sysinclude_path(char const *path_) |
| { return includes.add_include_path(path_, true);} |
| void set_sysinclude_delimiter() { includes.set_sys_include_delimiter(); } |
| typename iteration_context_stack_type::size_type get_iteration_depth() const |
| { return iter_ctxs.size(); } |
| |
| // maintain defined macros |
| #if BOOST_WAVE_ENABLE_COMMANDLINE_MACROS != 0 |
| template <typename StringT> |
| bool add_macro_definition(StringT macrostring, bool is_predefined = false) |
| { |
| return boost::wave::util::add_macro_definition(*this, |
| util::to_string<std::string>(macrostring), is_predefined, |
| get_language()); |
| } |
| #endif |
| // Define and undefine macros, macro introspection |
| template <typename StringT> |
| bool add_macro_definition(StringT const &name, position_type const& pos, |
| bool has_params, std::vector<token_type> ¶meters, |
| token_sequence_type &definition, bool is_predefined = false) |
| { |
| return macros.add_macro( |
| token_type(T_IDENTIFIER, util::to_string<string_type>(name), pos), |
| has_params, parameters, definition, is_predefined); |
| } |
| template <typename StringT> |
| bool is_defined_macro(StringT const &str) const |
| { |
| return macros.is_defined(util::to_string<string_type>(str)); |
| } |
| template <typename StringT> |
| bool get_macro_definition(StringT const &name, |
| bool &has_params, bool &is_predefined, position_type &pos, |
| std::vector<token_type> ¶meters, |
| token_sequence_type &definition) const |
| { |
| return macros.get_macro(util::to_string<string_type>(name), |
| has_params, is_predefined, pos, parameters, definition); |
| } |
| template <typename StringT> |
| bool remove_macro_definition(StringT const& undefname, bool even_predefined = false) |
| { |
| // strip leading and trailing whitespace |
| string_type name = util::to_string<string_type>(undefname); |
| typename string_type::size_type pos = name.find_first_not_of(" \t"); |
| if (pos != string_type::npos) { |
| typename string_type::size_type endpos = name.find_last_not_of(" \t"); |
| name = name.substr(pos, endpos-pos+1); |
| } |
| |
| #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 |
| // ensure this gets removed from the list of include guards as well |
| includes.remove_pragma_once_header( |
| util::to_string<std::string>(name)); |
| #endif |
| return macros.remove_macro(name, macros.get_main_pos(), even_predefined); |
| } |
| void reset_macro_definitions() |
| { macros.reset_macromap(); macros.init_predefined_macros(); } |
| |
| // Iterate over names of defined macros |
| typedef boost::wave::util::macromap<context> macromap_type; |
| typedef typename macromap_type::name_iterator name_iterator; |
| typedef typename macromap_type::const_name_iterator const_name_iterator; |
| |
| name_iterator macro_names_begin() { return macros.begin(); } |
| name_iterator macro_names_end() { return macros.end(); } |
| const_name_iterator macro_names_begin() const { return macros.begin(); } |
| const_name_iterator macro_names_end() const { return macros.end(); } |
| |
| // This version now is used internally mainly, but since it was a documented |
| // API function we leave it in the public interface. |
| bool add_macro_definition(token_type const &name, bool has_params, |
| std::vector<token_type> ¶meters, token_sequence_type &definition, |
| bool is_predefined = false) |
| { |
| return macros.add_macro(name, has_params, parameters, definition, |
| is_predefined); |
| } |
| |
| // get the Wave version information |
| static std::string get_version() |
| { |
| boost::wave::util::predefined_macros p; |
| return util::to_string<std::string>(p.get_fullversion()); |
| } |
| static std::string get_version_string() |
| { |
| boost::wave::util::predefined_macros p; |
| return util::to_string<std::string>(p.get_versionstr()); |
| } |
| |
| // access current language options |
| void set_language(boost::wave::language_support language_, |
| bool reset_macros = true) |
| { |
| language = language_; |
| if (reset_macros) |
| reset_macro_definitions(); |
| } |
| boost::wave::language_support get_language() const { return language; } |
| |
| // change and ask for maximal possible include nesting depth |
| void set_max_include_nesting_depth(iter_size_type new_depth) |
| { iter_ctxs.set_max_include_nesting_depth(new_depth); } |
| iter_size_type get_max_include_nesting_depth() const |
| { return iter_ctxs.get_max_include_nesting_depth(); } |
| |
| // access the policies |
| hook_policy_type &get_hooks() { return hooks; } |
| hook_policy_type const &get_hooks() const { return hooks; } |
| |
| // return type of actually used context type (might be the derived type) |
| actual_context_type& derived() |
| { return *static_cast<actual_context_type*>(this); } |
| actual_context_type const& derived() const |
| { return *static_cast<actual_context_type const*>(this); } |
| |
| // return the directory of the currently preprocessed file |
| boost::filesystem::path get_current_directory() const |
| { return includes.get_current_directory(); } |
| |
| #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) |
| protected: |
| friend class boost::wave::pp_iterator<context>; |
| friend class boost::wave::impl::pp_iterator_functor<context>; |
| #endif |
| |
| // make sure the context has been initialized |
| void init_context() |
| { |
| if (!has_been_initialized) { |
| std::string fname(filename); |
| if (filename != "<Unknown>" && filename != "<stdin>") { |
| using namespace boost::filesystem; |
| path fpath(complete(path(filename))); |
| fname = fpath.string(); |
| includes.set_current_directory(fname.c_str()); |
| } |
| has_been_initialized = true; // execute once |
| } |
| } |
| |
| template <typename IteratorT2> |
| bool is_defined_macro(IteratorT2 const &begin, IteratorT2 const &end) const |
| { return macros.is_defined(begin, end); } |
| |
| // maintain include paths (helper functions) |
| bool find_include_file (std::string &s, std::string &d, bool is_system, |
| char const *current_file) const |
| { return includes.find_include_file(s, d, is_system, current_file); } |
| void set_current_directory(char const *path_) |
| { includes.set_current_directory(path_); } |
| |
| // conditional compilation contexts |
| bool get_if_block_status() const { return ifblocks.get_status(); } |
| bool get_if_block_some_part_status() const |
| { return ifblocks.get_some_part_status(); } |
| bool get_enclosing_if_block_status() const |
| { return ifblocks.get_enclosing_status(); } |
| void enter_if_block(bool new_status) |
| { ifblocks.enter_if_block(new_status); } |
| bool enter_elif_block(bool new_status) |
| { return ifblocks.enter_elif_block(new_status); } |
| bool enter_else_block() { return ifblocks.enter_else_block(); } |
| bool exit_if_block() { return ifblocks.exit_if_block(); } |
| typename boost::wave::util::if_block_stack::size_type get_if_block_depth() const |
| { return ifblocks.get_if_block_depth(); } |
| |
| // stack of iteration contexts |
| iteration_ptr_type pop_iteration_context() |
| { iteration_ptr_type top = iter_ctxs.top(); iter_ctxs.pop(); return top; } |
| void push_iteration_context(position_type const &act_pos, iteration_ptr_type iter_ctx) |
| { iter_ctxs.push(*this, act_pos, iter_ctx); } |
| |
| position_type &get_main_pos() { return macros.get_main_pos(); } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // expand_tokensequence(): |
| // expands all macros contained in a given token sequence, handles '##' |
| // and '#' pp operators and re-scans the resulting sequence |
| // (essentially pre-processes the token sequence). |
| // |
| // The expand_undefined parameter is true during macro expansion inside |
| // a C++ expression given for a #if or #elif statement. |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| template <typename IteratorT2> |
| token_type expand_tokensequence(IteratorT2 &first_, IteratorT2 const &last_, |
| token_sequence_type &pending, token_sequence_type &expanded, |
| bool& seen_newline, bool expand_undefined = false) |
| { |
| return macros.expand_tokensequence(first_, last_, pending, expanded, |
| seen_newline, expand_undefined); |
| } |
| |
| template <typename IteratorT2> |
| void expand_whole_tokensequence(IteratorT2 &first_, IteratorT2 const &last_, |
| token_sequence_type &expanded, bool expand_undefined = true) |
| { |
| macros.expand_whole_tokensequence(expanded, first_, last_, |
| expand_undefined); |
| |
| // remove any contained placeholder |
| boost::wave::util::impl::remove_placeholders(expanded); |
| } |
| |
| public: |
| #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 |
| // support for #pragma once |
| // maintain the real name of the current preprocessed file |
| void set_current_filename(char const *real_name) |
| { current_filename = real_name; } |
| std::string const &get_current_filename() const |
| { return current_filename; } |
| |
| // maintain the list of known headers containing #pragma once |
| bool has_pragma_once(std::string const &filename_) |
| { return includes.has_pragma_once(filename_); } |
| bool add_pragma_once_header(std::string const &filename_, |
| std::string const& guard_name) |
| { |
| get_hooks().detected_include_guard(derived(), filename_, guard_name); |
| return includes.add_pragma_once_header(filename_, guard_name); |
| } |
| bool add_pragma_once_header(token_type const &pragma_, |
| std::string const &filename_) |
| { |
| get_hooks().detected_pragma_once(derived(), pragma_, filename_); |
| return includes.add_pragma_once_header(filename_, |
| "__BOOST_WAVE_PRAGMA_ONCE__"); |
| } |
| #endif |
| |
| void set_current_relative_filename(char const *real_name) |
| { current_relative_filename = real_name; } |
| std::string const &get_current_relative_filename() const |
| { return current_relative_filename; } |
| |
| #if BOOST_WAVE_SERIALIZATION != 0 |
| public: |
| BOOST_STATIC_CONSTANT(unsigned int, version = 0x10); |
| BOOST_STATIC_CONSTANT(unsigned int, version_mask = 0x0f); |
| |
| private: |
| friend class boost::serialization::access; |
| template<class Archive> |
| void save(Archive & ar, const unsigned int version) const |
| { |
| using namespace boost::serialization; |
| |
| string_type cfg(BOOST_PP_STRINGIZE(BOOST_WAVE_CONFIG)); |
| string_type kwd(BOOST_WAVE_PRAGMA_KEYWORD); |
| string_type strtype(BOOST_PP_STRINGIZE((BOOST_WAVE_STRINGTYPE))); |
| ar & make_nvp("config", cfg); |
| ar & make_nvp("pragma_keyword", kwd); |
| ar & make_nvp("string_type", strtype); |
| |
| ar & make_nvp("language_options", language); |
| ar & make_nvp("macro_definitions", macros); |
| ar & make_nvp("include_settings", includes); |
| } |
| template<class Archive> |
| void load(Archive & ar, const unsigned int loaded_version) |
| { |
| using namespace boost::serialization; |
| if (version != (loaded_version & ~version_mask)) { |
| BOOST_WAVE_THROW_CTX((*this), preprocess_exception, |
| incompatible_config, "cpp_context state version", |
| get_main_pos()); |
| return; |
| } |
| |
| // check compatibility of the stored information |
| string_type config, pragma_keyword, string_type_str; |
| |
| // BOOST_PP_STRINGIZE(BOOST_WAVE_CONFIG) |
| ar & make_nvp("config", config); |
| if (config != BOOST_PP_STRINGIZE(BOOST_WAVE_CONFIG)) { |
| BOOST_WAVE_THROW_CTX((*this), preprocess_exception, |
| incompatible_config, "BOOST_WAVE_CONFIG", get_main_pos()); |
| return; |
| } |
| |
| // BOOST_WAVE_PRAGMA_KEYWORD |
| ar & make_nvp("pragma_keyword", pragma_keyword); |
| if (pragma_keyword != BOOST_WAVE_PRAGMA_KEYWORD) { |
| BOOST_WAVE_THROW_CTX((*this), preprocess_exception, |
| incompatible_config, "BOOST_WAVE_PRAGMA_KEYWORD", |
| get_main_pos()); |
| return; |
| } |
| |
| // BOOST_PP_STRINGIZE((BOOST_WAVE_STRINGTYPE)) |
| ar & make_nvp("string_type", string_type_str); |
| if (string_type_str != BOOST_PP_STRINGIZE((BOOST_WAVE_STRINGTYPE))) { |
| BOOST_WAVE_THROW_CTX((*this), preprocess_exception, |
| incompatible_config, "BOOST_WAVE_STRINGTYPE", get_main_pos()); |
| return; |
| } |
| |
| try { |
| // read in the useful bits |
| ar & make_nvp("language_options", language); |
| ar & make_nvp("macro_definitions", macros); |
| ar & make_nvp("include_settings", includes); |
| } |
| catch (boost::wave::preprocess_exception const& e) { |
| // catch version mismatch exceptions and call error handler |
| get_hooks().throw_exception(derived(), e); |
| } |
| } |
| BOOST_SERIALIZATION_SPLIT_MEMBER() |
| #endif |
| |
| private: |
| // the main input stream |
| target_iterator_type first; // underlying input stream |
| target_iterator_type last; |
| std::string filename; // associated main filename |
| bool has_been_initialized; // set cwd once |
| #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 |
| std::string current_filename; // real name of current preprocessed file |
| #endif |
| std::string current_relative_filename; // real relative name of current preprocessed file |
| |
| boost::wave::util::if_block_stack ifblocks; // conditional compilation contexts |
| boost::wave::util::include_paths includes; // lists of include directories to search |
| iteration_context_stack_type iter_ctxs; // iteration contexts |
| macromap_type macros; // map of defined macros |
| boost::wave::language_support language; // supported language/extensions |
| hook_policy_type hooks; // hook policy instance |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| } // namespace wave |
| } // namespace boost |
| |
| #if BOOST_WAVE_SERIALIZATION != 0 |
| namespace boost { namespace serialization { |
| |
| template< |
| typename Iterator, typename LexIterator, |
| typename InputPolicy, typename Hooks |
| > |
| struct tracking_level<boost::wave::context<Iterator, LexIterator, InputPolicy, Hooks> > |
| { |
| typedef mpl::integral_c_tag tag; |
| typedef mpl::int_<track_never> type; |
| BOOST_STATIC_CONSTANT( |
| int, |
| value = tracking_level::type::value |
| ); |
| }; |
| |
| template< |
| typename Iterator, typename LexIterator, |
| typename InputPolicy, typename Hooks |
| > |
| struct version<boost::wave::context<Iterator, LexIterator, InputPolicy, Hooks> > |
| { |
| typedef boost::wave::context<Iterator, LexIterator, InputPolicy, Hooks> |
| target_type; |
| typedef mpl::int_<target_type::version> type; |
| typedef mpl::integral_c_tag tag; |
| BOOST_STATIC_CONSTANT(unsigned int, value = version::type::value); |
| }; |
| |
| }} // namespace boost::serialization |
| #endif |
| |
| // the suffix header occurs after all of the code |
| #ifdef BOOST_HAS_ABI_HEADERS |
| #include BOOST_ABI_SUFFIX |
| #endif |
| |
| #endif // !defined(CPP_CONTEXT_HPP_907485E2_6649_4A87_911B_7F7225F3E5B8_INCLUDED) |