summaryrefslogtreecommitdiff
path: root/boost/wave
diff options
context:
space:
mode:
authorAnas Nashif <anas.nashif@intel.com>2012-10-30 12:57:26 -0700
committerAnas Nashif <anas.nashif@intel.com>2012-10-30 12:57:26 -0700
commit1a78a62555be32868418fe52f8e330c9d0f95d5a (patch)
treed3765a80e7d3b9640ec2e930743630cd6b9fce2b /boost/wave
downloadboost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.gz
boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.bz2
boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.zip
Imported Upstream version 1.49.0upstream/1.49.0
Diffstat (limited to 'boost/wave')
-rw-r--r--boost/wave/cpp_context.hpp571
-rw-r--r--boost/wave/cpp_exceptions.hpp421
-rw-r--r--boost/wave/cpp_iteration_context.hpp169
-rw-r--r--boost/wave/cpp_throw.hpp180
-rw-r--r--boost/wave/cpplexer/convert_trigraphs.hpp139
-rw-r--r--boost/wave/cpplexer/cpp_lex_interface.hpp73
-rw-r--r--boost/wave/cpplexer/cpp_lex_interface_generator.hpp110
-rw-r--r--boost/wave/cpplexer/cpp_lex_iterator.hpp243
-rw-r--r--boost/wave/cpplexer/cpp_lex_token.hpp335
-rw-r--r--boost/wave/cpplexer/cpplexer_exceptions.hpp290
-rw-r--r--boost/wave/cpplexer/detect_include_guards.hpp263
-rw-r--r--boost/wave/cpplexer/re2clex/aq.hpp64
-rw-r--r--boost/wave/cpplexer/re2clex/cpp_re.hpp57
-rw-r--r--boost/wave/cpplexer/re2clex/cpp_re2c_lexer.hpp429
-rw-r--r--boost/wave/cpplexer/re2clex/scanner.hpp74
-rw-r--r--boost/wave/cpplexer/token_cache.hpp72
-rw-r--r--boost/wave/cpplexer/validate_universal_char.hpp322
-rw-r--r--boost/wave/grammars/cpp_chlit_grammar.hpp354
-rw-r--r--boost/wave/grammars/cpp_defined_grammar.hpp185
-rw-r--r--boost/wave/grammars/cpp_defined_grammar_gen.hpp85
-rw-r--r--boost/wave/grammars/cpp_expression_grammar.hpp870
-rw-r--r--boost/wave/grammars/cpp_expression_grammar_gen.hpp75
-rw-r--r--boost/wave/grammars/cpp_expression_value.hpp883
-rw-r--r--boost/wave/grammars/cpp_grammar.hpp765
-rw-r--r--boost/wave/grammars/cpp_grammar_gen.hpp110
-rw-r--r--boost/wave/grammars/cpp_intlit_grammar.hpp188
-rw-r--r--boost/wave/grammars/cpp_literal_grammar_gen.hpp77
-rw-r--r--boost/wave/grammars/cpp_predef_macros_gen.hpp80
-rw-r--r--boost/wave/grammars/cpp_predef_macros_grammar.hpp178
-rw-r--r--boost/wave/grammars/cpp_value_error.hpp51
-rw-r--r--boost/wave/language_support.hpp215
-rw-r--r--boost/wave/preprocessing_hooks.hpp818
-rw-r--r--boost/wave/token_ids.hpp378
-rw-r--r--boost/wave/util/cpp_ifblock.hpp161
-rw-r--r--boost/wave/util/cpp_include_paths.hpp553
-rw-r--r--boost/wave/util/cpp_iterator.hpp2571
-rw-r--r--boost/wave/util/cpp_macromap.hpp1942
-rw-r--r--boost/wave/util/cpp_macromap_predef.hpp288
-rw-r--r--boost/wave/util/cpp_macromap_utils.hpp575
-rw-r--r--boost/wave/util/file_position.hpp195
-rw-r--r--boost/wave/util/filesystem_compatibility.hpp172
-rw-r--r--boost/wave/util/flex_string.hpp2672
-rw-r--r--boost/wave/util/functor_input.hpp155
-rw-r--r--boost/wave/util/insert_whitespace_detection.hpp518
-rw-r--r--boost/wave/util/interpret_pragma.hpp210
-rw-r--r--boost/wave/util/iteration_context.hpp83
-rw-r--r--boost/wave/util/macro_definition.hpp200
-rw-r--r--boost/wave/util/macro_helpers.hpp303
-rw-r--r--boost/wave/util/pattern_parser.hpp67
-rw-r--r--boost/wave/util/symbol_table.hpp120
-rw-r--r--boost/wave/util/time_conversion_helper.hpp153
-rw-r--r--boost/wave/util/transform_iterator.hpp89
-rw-r--r--boost/wave/util/unput_queue_iterator.hpp295
-rw-r--r--boost/wave/wave_config.hpp491
-rw-r--r--boost/wave/wave_config_constant.hpp91
-rw-r--r--boost/wave/wave_version.hpp26
-rw-r--r--boost/wave/whitespace_handling.hpp296
57 files changed, 21350 insertions, 0 deletions
diff --git a/boost/wave/cpp_context.hpp b/boost/wave/cpp_context.hpp
new file mode 100644
index 0000000000..f053cdb815
--- /dev/null
+++ b/boost/wave/cpp_context.hpp
@@ -0,0 +1,571 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+ Definition of the preprocessor context
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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(util::complete_path(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(util::complete_path(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> &parameters,
+ 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> &parameters,
+ 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> &parameters, 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; }
+
+ position_type &get_main_pos() { return macros.get_main_pos(); }
+ position_type const& get_main_pos() const { return macros.get_main_pos(); }
+
+// 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(util::complete_path(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)
+ 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); }
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// 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; }
+
+ 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); }
+
+#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)
diff --git a/boost/wave/cpp_exceptions.hpp b/boost/wave/cpp_exceptions.hpp
new file mode 100644
index 0000000000..3fbd61af96
--- /dev/null
+++ b/boost/wave/cpp_exceptions.hpp
@@ -0,0 +1,421 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_EXCEPTIONS_HPP_5190E447_A781_4521_A275_5134FF9917D7_INCLUDED)
+#define CPP_EXCEPTIONS_HPP_5190E447_A781_4521_A275_5134FF9917D7_INCLUDED
+
+#include <exception>
+#include <string>
+#include <limits>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/wave/wave_config.hpp>
+#include <boost/wave/cpp_throw.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 {
+
+///////////////////////////////////////////////////////////////////////////////
+// exception severity
+namespace util {
+
+ enum severity {
+ severity_remark = 0,
+ severity_warning,
+ severity_error,
+ severity_fatal,
+ severity_commandline_error,
+ last_severity_code = severity_commandline_error
+ };
+
+ inline char const *
+ get_severity(int level)
+ {
+ static char const *severity_text[] =
+ {
+ "remark", // severity_remark
+ "warning", // severity_warning
+ "error", // severity_error
+ "fatal error", // severity_fatal
+ "command line error" // severity_commandline_error
+ };
+ BOOST_ASSERT(severity_remark <= level &&
+ level <= last_severity_code);
+ return severity_text[level];
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// cpp_exception, the base class for all specific C preprocessor exceptions
+class BOOST_SYMBOL_VISIBLE cpp_exception
+: public std::exception
+{
+public:
+ cpp_exception(int line_, int column_, char const *filename_) throw()
+ : line(line_), column(column_)
+ {
+ unsigned int off = 0;
+ while (off < sizeof(filename)-1 && *filename_)
+ filename[off++] = *filename_++;
+ filename[off] = 0;
+ }
+ ~cpp_exception() throw() {}
+
+ virtual char const *what() const throw() = 0; // to be overloaded
+ virtual char const *description() const throw() = 0;
+ virtual int get_errorcode() const throw() = 0;
+ virtual int get_severity() const throw() = 0;
+ virtual char const* get_related_name() const throw() = 0;
+ virtual bool is_recoverable() const throw() = 0;
+
+ int line_no() const throw() { return line; }
+ int column_no() const throw() { return column; }
+ char const *file_name() const throw() { return filename; }
+
+protected:
+ char filename[512];
+ int line;
+ int column;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// preprocessor error
+class BOOST_SYMBOL_VISIBLE preprocess_exception :
+ public cpp_exception
+{
+public:
+ enum error_code {
+ no_error = 0,
+ unexpected_error,
+ macro_redefinition,
+ macro_insertion_error,
+ bad_include_file,
+ bad_include_statement,
+ ill_formed_directive,
+ error_directive,
+ warning_directive,
+ ill_formed_expression,
+ missing_matching_if,
+ missing_matching_endif,
+ ill_formed_operator,
+ bad_define_statement,
+ bad_define_statement_va_args,
+ too_few_macroarguments,
+ too_many_macroarguments,
+ empty_macroarguments,
+ improperly_terminated_macro,
+ bad_line_statement,
+ bad_line_number,
+ bad_line_filename,
+ bad_undefine_statement,
+ bad_macro_definition,
+ illegal_redefinition,
+ duplicate_parameter_name,
+ invalid_concat,
+ last_line_not_terminated,
+ ill_formed_pragma_option,
+ include_nesting_too_deep,
+ misplaced_operator,
+ alreadydefined_name,
+ undefined_macroname,
+ invalid_macroname,
+ unexpected_qualified_name,
+ division_by_zero,
+ integer_overflow,
+ illegal_operator_redefinition,
+ ill_formed_integer_literal,
+ ill_formed_character_literal,
+ unbalanced_if_endif,
+ character_literal_out_of_range,
+ could_not_open_output_file,
+ incompatible_config,
+ ill_formed_pragma_message,
+ pragma_message_directive,
+ last_error_number = pragma_message_directive
+ };
+
+ preprocess_exception(char const *what_, error_code code, int line_,
+ int column_, char const *filename_) throw()
+ : cpp_exception(line_, column_, filename_),
+ code(code)
+ {
+ unsigned int off = 0;
+ while (off < sizeof(buffer) && *what_)
+ buffer[off++] = *what_++;
+ buffer[off] = 0;
+ }
+ ~preprocess_exception() throw() {}
+
+ virtual char const *what() const throw()
+ {
+ return "boost::wave::preprocess_exception";
+ }
+ virtual char const *description() const throw()
+ {
+ return buffer;
+ }
+ virtual int get_severity() const throw()
+ {
+ return severity_level(code);
+ }
+ virtual int get_errorcode() const throw()
+ {
+ return code;
+ }
+ virtual char const* get_related_name() const throw()
+ {
+ return "<unknown>";
+ }
+ virtual bool is_recoverable() const throw()
+ {
+ switch (get_errorcode()) {
+ // these are the exceptions thrown during processing not supposed to
+ // produce any tokens on the context::iterator level
+ case preprocess_exception::no_error: // just a placeholder
+ case preprocess_exception::macro_redefinition:
+ case preprocess_exception::macro_insertion_error:
+ case preprocess_exception::bad_macro_definition:
+ case preprocess_exception::illegal_redefinition:
+ case preprocess_exception::duplicate_parameter_name:
+ case preprocess_exception::invalid_macroname:
+ case preprocess_exception::bad_include_file:
+ case preprocess_exception::bad_include_statement:
+ case preprocess_exception::ill_formed_directive:
+ case preprocess_exception::error_directive:
+ case preprocess_exception::warning_directive:
+ case preprocess_exception::ill_formed_expression:
+ case preprocess_exception::missing_matching_if:
+ case preprocess_exception::missing_matching_endif:
+ case preprocess_exception::unbalanced_if_endif:
+ case preprocess_exception::bad_define_statement:
+ case preprocess_exception::bad_define_statement_va_args:
+ case preprocess_exception::bad_line_statement:
+ case preprocess_exception::bad_line_number:
+ case preprocess_exception::bad_line_filename:
+ case preprocess_exception::bad_undefine_statement:
+ case preprocess_exception::division_by_zero:
+ case preprocess_exception::integer_overflow:
+ case preprocess_exception::ill_formed_integer_literal:
+ case preprocess_exception::ill_formed_character_literal:
+ case preprocess_exception::character_literal_out_of_range:
+ case preprocess_exception::last_line_not_terminated:
+ case preprocess_exception::include_nesting_too_deep:
+ case preprocess_exception::illegal_operator_redefinition:
+ case preprocess_exception::incompatible_config:
+ case preprocess_exception::ill_formed_pragma_option:
+ case preprocess_exception::ill_formed_pragma_message:
+ case preprocess_exception::pragma_message_directive:
+ return true;
+
+ case preprocess_exception::unexpected_error:
+ case preprocess_exception::ill_formed_operator:
+ case preprocess_exception::too_few_macroarguments:
+ case preprocess_exception::too_many_macroarguments:
+ case preprocess_exception::empty_macroarguments:
+ case preprocess_exception::improperly_terminated_macro:
+ case preprocess_exception::invalid_concat:
+ case preprocess_exception::could_not_open_output_file:
+ break;
+ }
+ return false;
+ }
+
+ static char const *error_text(int code)
+ {
+ // error texts in this array must appear in the same order as the items in
+ // the error enum above
+ static char const *preprocess_exception_errors[] = {
+ "no error", // no_error
+ "unexpected error (should not happen)", // unexpected_error
+ "illegal macro redefinition", // macro_redefinition
+ "macro definition failed (out of memory?)", // macro_insertion_error
+ "could not find include file", // bad_include_file
+ "ill formed #include directive", // bad_include_statement
+ "ill formed preprocessor directive", // ill_formed_directive
+ "encountered #error directive or #pragma wave stop()", // error_directive
+ "encountered #warning directive", // warning_directive
+ "ill formed preprocessor expression", // ill_formed_expression
+ "the #if for this directive is missing", // missing_matching_if
+ "detected at least one missing #endif directive", // missing_matching_endif
+ "ill formed preprocessing operator", // ill_formed_operator
+ "ill formed #define directive", // bad_define_statement
+ "__VA_ARGS__ can only appear in the "
+ "expansion of a C99 variadic macro", // bad_define_statement_va_args
+ "too few macro arguments", // too_few_macroarguments
+ "too many macro arguments", // too_many_macroarguments
+ "empty macro arguments are not supported in pure C++ mode, "
+ "use variadics mode to allow these", // empty_macroarguments
+ "improperly terminated macro invocation "
+ "or replacement-list terminates in partial "
+ "macro expansion (not supported yet)", // improperly_terminated_macro
+ "ill formed #line directive", // bad_line_statement
+ "line number argument of #line directive "
+ "should consist out of decimal digits "
+ "only and must be in range of [1..INT_MAX]", // bad_line_number
+ "filename argument of #line directive should "
+ "be a narrow string literal", // bad_line_filename
+ "#undef may not be used on this predefined name", // bad_undefine_statement
+ "invalid macro definition", // bad_macro_definition
+ "this predefined name may not be redefined", // illegal_redefinition
+ "duplicate macro parameter name", // duplicate_parameter_name
+ "pasting the following two tokens does not "
+ "give a valid preprocessing token", // invalid_concat
+ "last line of file ends without a newline", // last_line_not_terminated
+ "unknown or illformed pragma option", // ill_formed_pragma_option
+ "include files nested too deep", // include_nesting_too_deep
+ "misplaced operator defined()", // misplaced_operator
+ "the name is already used in this scope as "
+ "a macro or scope name", // alreadydefined_name
+ "undefined macro or scope name may not be imported", // undefined_macroname
+ "ill formed macro name", // invalid_macroname
+ "qualified names are supported in C++0x mode only", // unexpected_qualified_name
+ "division by zero in preprocessor expression", // division_by_zero
+ "integer overflow in preprocessor expression", // integer_overflow
+ "this cannot be used as a macro name as it is "
+ "an operator in C++", // illegal_operator_redefinition
+ "ill formed integer literal or integer constant too large", // ill_formed_integer_literal
+ "ill formed character literal", // ill_formed_character_literal
+ "unbalanced #if/#endif in include file", // unbalanced_if_endif
+ "expression contains out of range character literal", // character_literal_out_of_range
+ "could not open output file", // could_not_open_output_file
+ "incompatible state information", // incompatible_config
+ "illformed pragma message", // ill_formed_pragma_message
+ "encountered #pragma message directive" // pragma_message_directive
+ };
+ BOOST_ASSERT(no_error <= code && code <= last_error_number);
+ return preprocess_exception_errors[code];
+ }
+
+ static util::severity severity_level(int code)
+ {
+ static util::severity preprocess_exception_severity[] = {
+ util::severity_remark, // no_error
+ util::severity_fatal, // unexpected_error
+ util::severity_warning, // macro_redefinition
+ util::severity_fatal, // macro_insertion_error
+ util::severity_error, // bad_include_file
+ util::severity_error, // bad_include_statement
+ util::severity_error, // ill_formed_directive
+ util::severity_fatal, // error_directive
+ util::severity_warning, // warning_directive
+ util::severity_error, // ill_formed_expression
+ util::severity_error, // missing_matching_if
+ util::severity_error, // missing_matching_endif
+ util::severity_error, // ill_formed_operator
+ util::severity_error, // bad_define_statement
+ util::severity_error, // bad_define_statement_va_args
+ util::severity_warning, // too_few_macroarguments
+ util::severity_warning, // too_many_macroarguments
+ util::severity_warning, // empty_macroarguments
+ util::severity_error, // improperly_terminated_macro
+ util::severity_warning, // bad_line_statement
+ util::severity_warning, // bad_line_number
+ util::severity_warning, // bad_line_filename
+ util::severity_warning, // bad_undefine_statement
+ util::severity_commandline_error, // bad_macro_definition
+ util::severity_warning, // illegal_redefinition
+ util::severity_error, // duplicate_parameter_name
+ util::severity_error, // invalid_concat
+ util::severity_warning, // last_line_not_terminated
+ util::severity_warning, // ill_formed_pragma_option
+ util::severity_fatal, // include_nesting_too_deep
+ util::severity_error, // misplaced_operator
+ util::severity_error, // alreadydefined_name
+ util::severity_error, // undefined_macroname
+ util::severity_error, // invalid_macroname
+ util::severity_error, // unexpected_qualified_name
+ util::severity_fatal, // division_by_zero
+ util::severity_error, // integer_overflow
+ util::severity_error, // illegal_operator_redefinition
+ util::severity_error, // ill_formed_integer_literal
+ util::severity_error, // ill_formed_character_literal
+ util::severity_warning, // unbalanced_if_endif
+ util::severity_warning, // character_literal_out_of_range
+ util::severity_error, // could_not_open_output_file
+ util::severity_remark, // incompatible_config
+ util::severity_warning, // ill_formed_pragma_message
+ util::severity_remark, // pragma_message_directive
+ };
+ BOOST_ASSERT(no_error <= code && code <= last_error_number);
+ return preprocess_exception_severity[code];
+ }
+ static char const *severity_text(int code)
+ {
+ return util::get_severity(severity_level(code));
+ }
+
+private:
+ char buffer[512];
+ error_code code;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Error during macro handling, this exception contains the related macro name
+class BOOST_SYMBOL_VISIBLE macro_handling_exception :
+ public preprocess_exception
+{
+public:
+ macro_handling_exception(char const *what_, error_code code, int line_,
+ int column_, char const *filename_, char const *macroname) throw()
+ : preprocess_exception(what_, code, line_, column_, filename_)
+ {
+ unsigned int off = 0;
+ while (off < sizeof(name) && *macroname)
+ name[off++] = *macroname++;
+ name[off] = 0;
+ }
+ ~macro_handling_exception() throw() {}
+
+ virtual char const *what() const throw()
+ {
+ return "boost::wave::macro_handling_exception";
+ }
+ char const* get_related_name() const throw()
+ {
+ return name;
+ }
+
+private:
+ char name[512];
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// The is_recoverable() function allows to decide, whether it is possible
+// simply to continue after a given exception was thrown by Wave.
+//
+// This is kind of a hack to allow to recover from certain errors as long as
+// Wave doesn't provide better means of error recovery.
+//
+///////////////////////////////////////////////////////////////////////////////
+inline bool
+is_recoverable(cpp_exception const& e)
+{
+ return e.is_recoverable();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_EXCEPTIONS_HPP_5190E447_A781_4521_A275_5134FF9917D7_INCLUDED)
diff --git a/boost/wave/cpp_iteration_context.hpp b/boost/wave/cpp_iteration_context.hpp
new file mode 100644
index 0000000000..bf9f734cdb
--- /dev/null
+++ b/boost/wave/cpp_iteration_context.hpp
@@ -0,0 +1,169 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+ Definition of the preprocessor context
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_ITERATION_CONTEXT_HPP_00312288_9DDB_4668_AFE5_25D3994FD095_INCLUDED)
+#define CPP_ITERATION_CONTEXT_HPP_00312288_9DDB_4668_AFE5_25D3994FD095_INCLUDED
+
+#include <iterator>
+#include <fstream>
+#if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)
+#include <sstream>
+#endif
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/wave/cpp_exceptions.hpp>
+#include <boost/wave/language_support.hpp>
+#include <boost/wave/util/file_position.hpp>
+// #include <boost/spirit/include/iterator/classic_multi_pass.hpp> // make_multi_pass
+
+// 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 {
+namespace iteration_context_policies {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// The iteration_context_policies templates are policies for the
+// boost::wave::iteration_context which allows to control, how a given
+// input file is to be represented by a pair of iterators pointing to the
+// begin and the end of the resulting input sequence.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // load_file_to_string
+ //
+ // Loads a file into a string and returns the iterators pointing to
+ // the beginning and the end of the loaded string.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+ struct load_file_to_string
+ {
+ template <typename IterContextT>
+ class inner
+ {
+ public:
+ template <typename PositionT>
+ static void init_iterators(IterContextT &iter_ctx,
+ PositionT const &act_pos, language_support language)
+ {
+ typedef typename IterContextT::iterator_type iterator_type;
+
+ // read in the file
+ std::ifstream instream(iter_ctx.filename.c_str());
+ if (!instream.is_open()) {
+ BOOST_WAVE_THROW_CTX(iter_ctx.ctx, preprocess_exception,
+ bad_include_file, iter_ctx.filename.c_str(), act_pos);
+ return;
+ }
+ instream.unsetf(std::ios::skipws);
+
+ iter_ctx.instring.assign(
+ std::istreambuf_iterator<char>(instream.rdbuf()),
+ std::istreambuf_iterator<char>());
+
+ iter_ctx.first = iterator_type(
+ iter_ctx.instring.begin(), iter_ctx.instring.end(),
+ PositionT(iter_ctx.filename), language);
+ iter_ctx.last = iterator_type();
+ }
+
+ private:
+ std::string instring;
+ };
+ };
+
+} // namespace iteration_context_policies
+
+///////////////////////////////////////////////////////////////////////////////
+// Base class for iteration contexts
+template <typename ContextT, typename IteratorT>
+struct base_iteration_context
+{
+ enum file_type
+ {
+ // this iteration context handles ...
+ main_file, // ... the main preprocessed file
+ system_header, // ... a header file included used #include <>
+ user_header // ... a header file included using #include ""
+ };
+
+ base_iteration_context(ContextT& ctx_,
+ BOOST_WAVE_STRINGTYPE const &fname, std::size_t if_block_depth = 0)
+ : real_filename(fname), real_relative_filename(fname), filename(fname),
+ line(1), emitted_lines(0), if_block_depth(if_block_depth), ctx(ctx_)
+ {}
+ base_iteration_context(ContextT& ctx_,
+ IteratorT const &first_, IteratorT const &last_,
+ BOOST_WAVE_STRINGTYPE const &fname, std::size_t if_block_depth = 0,
+ file_type type = main_file)
+ : first(first_), last(last_), real_filename(fname),
+ real_relative_filename(fname), filename(fname),
+ line(1), emitted_lines(0), if_block_depth(if_block_depth), ctx(ctx_)
+ {}
+
+// the actual input stream
+ IteratorT first; // actual input stream position
+ IteratorT last; // end of input stream
+ BOOST_WAVE_STRINGTYPE real_filename; // real name of the current file
+ BOOST_WAVE_STRINGTYPE real_relative_filename; // real relative name of the current file
+ BOOST_WAVE_STRINGTYPE filename; // actual processed file
+ unsigned int line; // line counter of underlying stream
+ unsigned int emitted_lines; // count of emitted newlines
+ std::size_t if_block_depth; // depth of #if block recursion
+ ContextT& ctx; // corresponding context<> object
+ file_type type; // the type of the handled file
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+template <
+ typename ContextT, typename IteratorT,
+ typename InputPolicyT = typename ContextT::input_policy_type
+>
+struct iteration_context
+: public base_iteration_context<ContextT, IteratorT>,
+ public InputPolicyT::template
+ inner<iteration_context<ContextT, IteratorT, InputPolicyT> >
+{
+ typedef IteratorT iterator_type;
+ typedef typename IteratorT::token_type::position_type position_type;
+
+ typedef base_iteration_context<ContextT, IteratorT> base_type;
+ typedef iteration_context<ContextT, IteratorT, InputPolicyT> self_type;
+
+ iteration_context(ContextT& ctx, BOOST_WAVE_STRINGTYPE const &fname,
+ position_type const &act_pos,
+ boost::wave::language_support language_,
+ typename base_type::file_type type = base_type::main_file)
+ : base_iteration_context<ContextT, IteratorT>(ctx, fname, type)
+ {
+ InputPolicyT::template inner<self_type>::init_iterators(
+ *this, act_pos, language_);
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_ITERATION_CONTEXT_HPP_00312288_9DDB_4668_AFE5_25D3994FD095_INCLUDED)
diff --git a/boost/wave/cpp_throw.hpp b/boost/wave/cpp_throw.hpp
new file mode 100644
index 0000000000..010e5719db
--- /dev/null
+++ b/boost/wave/cpp_throw.hpp
@@ -0,0 +1,180 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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(BOOST_WAVE_CPP_THROW_HPP_INCLUDED)
+#define BOOST_WAVE_CPP_THROW_HPP_INCLUDED
+
+#include <string>
+#include <boost/throw_exception.hpp>
+
+#ifdef BOOST_NO_STRINGSTREAM
+#include <strstream>
+#else
+#include <sstream>
+#endif
+
+namespace boost { namespace wave { namespace util
+{
+#ifdef BOOST_NO_STRINGSTREAM
+ template <typename Exception, typename S1, typename Pos>
+ void throw_(typename Exception::error_code code, S1 msg, Pos const& pos)
+ {
+ std::strstream stream;
+ stream << Exception::severity_text(code) << ": "
+ << Exception::error_text(code);
+ if (msg[0] != 0)
+ stream << ": " << msg;
+ stream << std::ends;
+ std::string throwmsg = stream.str(); stream.freeze(false);
+ boost::throw_exception(Exception(throwmsg.c_str(), code,
+ pos.get_line(), pos.get_column(), pos.get_file().c_str()));
+ }
+
+ template <typename Exception, typename Context, typename S1, typename Pos>
+ void throw_(Context& ctx, typename Exception::error_code code,
+ S1 msg, Pos const& pos)
+ {
+ std::strstream stream;
+ stream << Exception::severity_text(code) << ": "
+ << Exception::error_text(code);
+ if (msg[0] != 0)
+ stream << ": " << msg;
+ stream << std::ends;
+ std::string throwmsg = stream.str(); stream.freeze(false);
+ ctx.get_hooks().throw_exception(ctx.derived(),
+ Exception(throwmsg.c_str(), code, pos.get_line(), pos.get_column(),
+ pos.get_file().c_str()));
+ }
+
+ template <typename Exception, typename S1, typename Pos, typename S2>
+ void throw_(typename Exception::error_code code, S1 msg, Pos const& pos,
+ S2 name)
+ {
+ std::strstream stream;
+ stream << Exception::severity_text(code) << ": "
+ << Exception::error_text(code);
+ if (msg[0] != 0)
+ stream << ": " << msg;
+ stream << std::ends;
+ std::string throwmsg = stream.str(); stream.freeze(false);
+ boost::throw_exception(Exception(throwmsg.c_str(), code,
+ pos.get_line(), pos.get_column(), pos.get_file().c_str(), name));
+ }
+
+ template <typename Exception, typename Context, typename S1, typename Pos,
+ typename S2>
+ void throw_(Context& ctx, typename Exception::error_code code,
+ S1 msg, Pos const& pos, S2 name)
+ {
+ std::strstream stream;
+ stream << Exception::severity_text(code) << ": "
+ << Exception::error_text(code);
+ if (msg[0] != 0)
+ stream << ": " << msg;
+ stream << std::ends;
+ std::string throwmsg = stream.str(); stream.freeze(false);
+ ctx.get_hooks().throw_exception(ctx.derived(),
+ Exception(throwmsg.c_str(), code, pos.get_line(), pos.get_column(),
+ pos.get_file().c_str(), name));
+ }
+#else
+ template <typename Exception, typename S1, typename Pos>
+ void throw_(typename Exception::error_code code, S1 msg, Pos const& pos)
+ {
+ std::stringstream stream;
+ stream << Exception::severity_text(code) << ": "
+ << Exception::error_text(code);
+ if (msg[0] != 0)
+ stream << ": " << msg;
+ stream << std::ends;
+ std::string throwmsg = stream.str();
+ boost::throw_exception(Exception(throwmsg.c_str(), code,
+ pos.get_line(), pos.get_column(), pos.get_file().c_str()));
+ }
+
+ template <typename Exception, typename Context, typename S1, typename Pos>
+ void throw_(Context& ctx, typename Exception::error_code code,
+ S1 msg, Pos const& pos)
+ {
+ std::stringstream stream;
+ stream << Exception::severity_text(code) << ": "
+ << Exception::error_text(code);
+ if (msg[0] != 0)
+ stream << ": " << msg;
+ stream << std::ends;
+ std::string throwmsg = stream.str();
+ ctx.get_hooks().throw_exception(ctx.derived(),
+ Exception(throwmsg.c_str(), code, pos.get_line(), pos.get_column(),
+ pos.get_file().c_str()));
+ }
+
+ template <typename Exception, typename S1, typename Pos, typename S2>
+ void throw_(typename Exception::error_code code, S1 msg, Pos const& pos,
+ S2 name)
+ {
+ std::stringstream stream;
+ stream << Exception::severity_text(code) << ": "
+ << Exception::error_text(code);
+ if (msg[0] != 0)
+ stream << ": " << msg;
+ stream << std::ends;
+ std::string throwmsg = stream.str();
+ boost::throw_exception(Exception(throwmsg.c_str(), code,
+ pos.get_line(), pos.get_column(), pos.get_file().c_str(), name));
+ }
+
+ template <typename Exception, typename Context, typename S1, typename Pos1,
+ typename S2>
+ void throw_(Context& ctx, typename Exception::error_code code,
+ S1 msg, Pos1 const& pos, S2 name)
+ {
+ std::stringstream stream;
+ stream << Exception::severity_text(code) << ": "
+ << Exception::error_text(code);
+ if (msg[0] != 0)
+ stream << ": " << msg;
+ stream << std::ends;
+ std::string throwmsg = stream.str();
+ ctx.get_hooks().throw_exception(ctx.derived(),
+ Exception(throwmsg.c_str(), code, pos.get_line(), pos.get_column(),
+ pos.get_file().c_str(), name));
+ }
+#endif
+}}}
+
+///////////////////////////////////////////////////////////////////////////////
+// helper macro for throwing exceptions
+#if !defined(BOOST_WAVE_THROW)
+#define BOOST_WAVE_THROW(cls, code, msg, act_pos) \
+ boost::wave::util::throw_<cls>(cls::code, msg, act_pos) \
+ /**/
+
+#define BOOST_WAVE_THROW_CTX(ctx, cls, code, msg, act_pos) \
+ boost::wave::util::throw_<cls>(ctx, cls::code, msg, act_pos) \
+ /**/
+#endif // BOOST_WAVE_THROW
+
+///////////////////////////////////////////////////////////////////////////////
+// helper macro for throwing exceptions with additional parameter
+#if !defined(BOOST_WAVE_THROW_NAME_CTX)
+#define BOOST_WAVE_THROW_NAME_CTX(ctx, cls, code, msg, act_pos, name) \
+ boost::wave::util::throw_<cls>(cls::code, msg, act_pos, name) \
+ /**/
+#endif // BOOST_WAVE_THROW_NAME_CTX
+
+///////////////////////////////////////////////////////////////////////////////
+// helper macro for throwing exceptions with additional parameter
+#if !defined(BOOST_WAVE_THROW_VAR_CTX)
+#define BOOST_WAVE_THROW_VAR_CTX(ctx, cls, code, msg, act_pos) \
+ boost::wave::util::throw_<cls>(ctx, code, msg, act_pos) \
+ /**/
+#endif // BOOST_WAVE_THROW_VAR_CTX
+
+#endif // !defined(BOOST_WAVE_CPP_THROW_HPP_INCLUDED)
diff --git a/boost/wave/cpplexer/convert_trigraphs.hpp b/boost/wave/cpplexer/convert_trigraphs.hpp
new file mode 100644
index 0000000000..8f80cfba49
--- /dev/null
+++ b/boost/wave/cpplexer/convert_trigraphs.hpp
@@ -0,0 +1,139 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ Grammar for universal character validation (see C++ standard: Annex E)
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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(CONVERT_TRIGRAPHS_HK050403_INCLUDED)
+#define CONVERT_TRIGRAPHS_HK050403_INCLUDED
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/wave/cpplexer/cpplexer_exceptions.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 {
+namespace cpplexer {
+namespace impl {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Test, whether the given string represents a valid trigraph sequence
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename StringT>
+inline bool
+is_trigraph(StringT const& trigraph)
+{
+ if (trigraph.size() < 3 || '?' != trigraph[0] || '?' != trigraph[1])
+ return false;
+
+ switch (trigraph[2]) {
+ case '\'': case '=': case '/': case '(':
+ case ')': case '<': case '>': case '!':
+ case '-':
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// convert_trigraph
+//
+// The function convert_trigraph() converts a single trigraph character
+// sequence into the corresponding character.
+//
+// If the given character sequence doesn't form a valid trigraph sequence
+// no conversion is performed.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename StringT>
+inline StringT
+convert_trigraph(StringT const &trigraph)
+{
+StringT result (trigraph);
+
+ if (is_trigraph(trigraph)) {
+ switch (trigraph[2]) {
+ case '\'': result = "^"; break;
+ case '=': result = "#"; break;
+ case '/': result = "\\"; break;
+ case '(': result = "["; break;
+ case ')': result = "]"; break;
+ case '<': result = "{"; break;
+ case '>': result = "}"; break;
+ case '!': result = "|"; break;
+ case '-': result = "~"; break;
+ }
+ }
+ return result;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// convert_trigraphs
+//
+// The function convert_trigraph() converts all trigraphs in the given
+// string into the corresponding characters.
+//
+// If one of the given character sequences doesn't form a valid trigraph
+// sequence no conversion is performed.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename StringT>
+inline StringT
+convert_trigraphs(StringT const &value)
+{
+ StringT result;
+ typename StringT::size_type pos = 0;
+ typename StringT::size_type pos1 = value.find_first_of ("?", 0);
+ if (StringT::npos != pos1) {
+ do {
+ result += value.substr(pos, pos1-pos);
+ StringT trigraph (value.substr(pos1));
+ if (is_trigraph(trigraph)) {
+ result += convert_trigraph(trigraph);
+ pos1 = value.find_first_of ("?", pos = pos1+3);
+ }
+ else {
+ result += value[pos1];
+ pos1 = value.find_first_of ("?", pos = pos1+1);
+ }
+ } while (StringT::npos != pos1);
+ result += value.substr(pos);
+ }
+ else {
+ result = value;
+ }
+ return result;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace impl
+} // namespace cpplexer
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CONVERT_TRIGRAPHS_HK050403_INCLUDED)
+
+
diff --git a/boost/wave/cpplexer/cpp_lex_interface.hpp b/boost/wave/cpplexer/cpp_lex_interface.hpp
new file mode 100644
index 0000000000..c69f8aaa53
--- /dev/null
+++ b/boost/wave/cpplexer/cpp_lex_interface.hpp
@@ -0,0 +1,73 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ Definition of the abstract lexer interface
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_LEX_INTERFACE_HPP_E83F52A4_90AC_4FBE_A9A7_B65F7F94C497_INCLUDED)
+#define CPP_LEX_INTERFACE_HPP_E83F52A4_90AC_4FBE_A9A7_B65F7F94C497_INCLUDED
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/wave/util/file_position.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
+
+// suppress warnings about dependent classes not being exported from the dll
+#ifdef BOOST_MSVC
+#pragma warning(push)
+#pragma warning(disable : 4251 4231 4660)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+namespace boost {
+namespace wave {
+namespace cpplexer {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// The lex_input_interface decouples the lex_iterator_shim from the actual
+// lexer. This is done to allow compile time reduction.
+// Thanks to JCAB for having this idea.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename TokenT>
+struct lex_input_interface
+{
+ typedef typename TokenT::position_type position_type;
+
+ lex_input_interface() {}
+ virtual ~lex_input_interface() {}
+
+ virtual TokenT& get(TokenT&) = 0;
+ virtual void set_position(position_type const &pos) = 0;
+#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+ virtual bool has_include_guards(std::string& guard_name) const = 0;
+#endif
+};
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace cpplexer
+} // namespace wave
+} // namespace boost
+
+#ifdef BOOST_MSVC
+#pragma warning(pop)
+#endif
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_LEX_INTERFACE_HPP_E83F52A4_90AC_4FBE_A9A7_B65F7F94C497_INCLUDED)
diff --git a/boost/wave/cpplexer/cpp_lex_interface_generator.hpp b/boost/wave/cpplexer/cpp_lex_interface_generator.hpp
new file mode 100644
index 0000000000..8e1bd7726c
--- /dev/null
+++ b/boost/wave/cpplexer/cpp_lex_interface_generator.hpp
@@ -0,0 +1,110 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ Definition of the abstract lexer interface
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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(BOOST_WAVE_LEX_INTERFACE_GENERATOR_HPP_INCLUDED)
+#define BOOST_WAVE_LEX_INTERFACE_GENERATOR_HPP_INCLUDED
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/wave/util/file_position.hpp>
+#include <boost/wave/language_support.hpp>
+#include <boost/wave/cpplexer/cpp_lex_interface.hpp>
+#include <boost/wave/cpplexer/cpp_lex_token.hpp> // lex_token
+
+// this must occur after all of the includes and before any code appears
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_PREFIX
+#endif
+
+// suppress warnings about dependent classes not being exported from the dll
+#ifdef BOOST_MSVC
+#pragma warning(push)
+#pragma warning(disable : 4251 4231 4660)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+namespace boost {
+namespace wave {
+namespace cpplexer {
+
+#if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0
+#define BOOST_WAVE_NEW_LEXER_DECL BOOST_WAVE_DECL
+#else
+#define BOOST_WAVE_NEW_LEXER_DECL
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// new_lexer_gen: generates a new instance of the required C++ lexer
+//
+///////////////////////////////////////////////////////////////////////////////
+template <
+ typename IteratorT,
+ typename PositionT = boost::wave::util::file_position_type,
+ typename TokenT = lex_token<PositionT>
+>
+struct BOOST_WAVE_NEW_LEXER_DECL new_lexer_gen
+{
+// The NewLexer function allows the opaque generation of a new lexer object.
+// It is coupled to the token type to allow to decouple the lexer/token
+// configurations at compile time.
+ static lex_input_interface<TokenT> *
+ new_lexer(IteratorT const &first, IteratorT const &last,
+ PositionT const &pos, boost::wave::language_support language);
+};
+
+#undef BOOST_WAVE_NEW_LEXER_DECL
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// The lex_input_interface_generator helps to instantiate a concrete lexer
+// to be used by the Wave preprocessor module.
+// This is done to allow compile time reduction.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename TokenT>
+struct lex_input_interface_generator
+: lex_input_interface<TokenT>
+{
+ typedef typename lex_input_interface<TokenT>::position_type position_type;
+
+ lex_input_interface_generator() {}
+ ~lex_input_interface_generator() {}
+
+// The new_lexer function allows the opaque generation of a new lexer object.
+// It is coupled to the token type to allow to distinguish different
+// lexer/token configurations at compile time.
+ template <typename IteratorT>
+ static lex_input_interface<TokenT> *
+ new_lexer(IteratorT const &first, IteratorT const &last,
+ position_type const &pos, boost::wave::language_support language)
+ {
+ return new_lexer_gen<IteratorT, position_type, TokenT>::new_lexer (
+ first, last, pos, language);
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace cpplexer
+} // namespace wave
+} // namespace boost
+
+#ifdef BOOST_MSVC
+#pragma warning(pop)
+#endif
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(BOOST_WAVE_LEX_INTERFACE_GENERATOR_HPP_INCLUDED)
diff --git a/boost/wave/cpplexer/cpp_lex_iterator.hpp b/boost/wave/cpplexer/cpp_lex_iterator.hpp
new file mode 100644
index 0000000000..fe93888af5
--- /dev/null
+++ b/boost/wave/cpplexer/cpp_lex_iterator.hpp
@@ -0,0 +1,243 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ Definition of the lexer iterator
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_LEX_ITERATOR_HPP_AF0C37E3_CBD8_4F33_A225_51CF576FA61F_INCLUDED)
+#define CPP_LEX_ITERATOR_HPP_AF0C37E3_CBD8_4F33_A225_51CF576FA61F_INCLUDED
+
+#include <string>
+
+#include <boost/assert.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/spirit/include/support_multi_pass.hpp>
+
+#include <boost/wave/util/file_position.hpp>
+#include <boost/wave/util/functor_input.hpp>
+#include <boost/wave/cpplexer/cpp_lex_interface_generator.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
+
+#if 0 != __COMO_VERSION__ || !BOOST_WORKAROUND(BOOST_MSVC, <= 1310)
+#define BOOST_WAVE_EOF_PREFIX static
+#else
+#define BOOST_WAVE_EOF_PREFIX
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+namespace boost {
+namespace wave {
+namespace cpplexer {
+namespace impl {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// lex_iterator_functor_shim
+//
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename TokenT>
+class lex_iterator_functor_shim
+{
+ typedef typename TokenT::position_type position_type;
+
+public:
+ lex_iterator_functor_shim()
+#if /*0 != __DECCXX_VER || */defined(__PGI)
+ : eof()
+#endif
+ {}
+
+#if BOOST_WORKAROUND(BOOST_MSVC, <= 1310)
+ lex_iterator_functor_shim& operator= (lex_iterator_functor_shim const& rhs)
+ { return *this; } // nothing to do here
+#endif
+
+// interface to the iterator_policies::split_functor_input policy
+ typedef TokenT result_type;
+ typedef lex_iterator_functor_shim unique;
+ typedef lex_input_interface<TokenT>* shared;
+
+ BOOST_WAVE_EOF_PREFIX result_type const eof;
+
+ template <typename MultiPass>
+ static result_type& get_next(MultiPass& mp, result_type& result)
+ {
+ return mp.shared()->ftor->get(result);
+ }
+
+ // this will be called whenever the last reference to a multi_pass will
+ // be released
+ template <typename MultiPass>
+ static void destroy(MultiPass& mp)
+ {
+ delete mp.shared()->ftor;
+ }
+
+ template <typename MultiPass>
+ static void set_position(MultiPass& mp, position_type const &pos)
+ {
+ mp.shared()->ftor->set_position(pos);
+ }
+#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+ template <typename MultiPass>
+ static bool has_include_guards(MultiPass& mp, std::string& guard_name)
+ {
+ return mp.shared()->ftor->has_include_guards(guard_name);
+ }
+#endif
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// eof token
+#if 0 != __COMO_VERSION__ || !BOOST_WORKAROUND(BOOST_MSVC, <= 1310)
+template <typename TokenT>
+typename lex_iterator_functor_shim<TokenT>::result_type const
+ lex_iterator_functor_shim<TokenT>::eof;
+#endif // 0 != __COMO_VERSION__
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace impl
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// lex_iterator
+//
+// A generic C++ lexer interface class, which allows to plug in different
+// lexer implementations. The interface between the lexer type used and
+// the preprocessor component depends on the token type only (template
+// parameter TokenT).
+// Additionally, the following requirements apply:
+//
+// - the lexer type should have a function implemented, which returnes
+// the next lexed token from the input stream:
+// typename TokenT get();
+// - at the end of the input stream this function should return the
+// eof token equivalent
+// - the lexer should implement a constructor taking two iterators
+// pointing to the beginning and the end of the input stream,
+// a third parameter containing the name of the parsed input file
+// and a 4th parameter of the type boost::wave::language_support
+// which specifies, which language subset should be supported (C++,
+// C99, C++0x etc.).
+//
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// Divide the given functor type into its components (unique and shared)
+// and build a std::pair from these parts
+template <typename FunctorData>
+struct make_multi_pass
+{
+ typedef
+ std::pair<typename FunctorData::unique, typename FunctorData::shared>
+ functor_data_type;
+ typedef typename FunctorData::result_type result_type;
+
+ typedef boost::spirit::iterator_policies::split_functor_input input_policy;
+ typedef boost::spirit::iterator_policies::ref_counted ownership_policy;
+#if defined(BOOST_WAVE_DEBUG)
+ typedef boost::spirit::iterator_policies::buf_id_check check_policy;
+#else
+ typedef boost::spirit::iterator_policies::no_check check_policy;
+#endif
+ typedef boost::spirit::iterator_policies::split_std_deque storage_policy;
+
+ typedef boost::spirit::iterator_policies::default_policy<
+ ownership_policy, check_policy, input_policy, storage_policy>
+ policy_type;
+ typedef boost::spirit::multi_pass<functor_data_type, policy_type> type;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+template <typename TokenT>
+class lex_iterator
+: public make_multi_pass<impl::lex_iterator_functor_shim<TokenT> >::type
+{
+ typedef impl::lex_iterator_functor_shim<TokenT> input_policy_type;
+
+ typedef typename make_multi_pass<input_policy_type>::type base_type;
+ typedef typename make_multi_pass<input_policy_type>::functor_data_type
+ functor_data_type;
+
+ typedef typename input_policy_type::unique unique_functor_type;
+ typedef typename input_policy_type::shared shared_functor_type;
+
+public:
+ typedef TokenT token_type;
+
+ lex_iterator()
+ {}
+
+ template <typename IteratorT>
+ lex_iterator(IteratorT const &first, IteratorT const &last,
+ typename TokenT::position_type const &pos,
+ boost::wave::language_support language)
+ : base_type(
+ functor_data_type(
+ unique_functor_type(),
+ lex_input_interface_generator<TokenT>
+ ::new_lexer(first, last, pos, language)
+ )
+ )
+ {}
+
+ void set_position(typename TokenT::position_type const &pos)
+ {
+ typedef typename TokenT::position_type position_type;
+
+ // set the new position in the current token
+ token_type const& currtoken = this->base_type::dereference(*this);
+ position_type currpos = currtoken.get_position();
+
+ currpos.set_file(pos.get_file());
+ currpos.set_line(pos.get_line());
+ const_cast<token_type&>(currtoken).set_position(currpos);
+
+ // set the new position for future tokens as well
+ if (token_type::string_type::npos !=
+ currtoken.get_value().find_first_of('\n'))
+ {
+ currpos.set_line(pos.get_line() + 1);
+ }
+ unique_functor_type::set_position(*this, currpos);
+ }
+
+#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+ // return, whether the current file has include guards
+ // this function returns meaningful results only if the file was scanned
+ // completely
+ bool has_include_guards(std::string& guard_name) const
+ {
+ return unique_functor_type::has_include_guards(*this, guard_name);
+ }
+#endif
+};
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace cpplexer
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#undef BOOST_WAVE_EOF_PREFIX
+
+#endif // !defined(CPP_LEX_ITERATOR_HPP_AF0C37E3_CBD8_4F33_A225_51CF576FA61F_INCLUDED)
diff --git a/boost/wave/cpplexer/cpp_lex_token.hpp b/boost/wave/cpplexer/cpp_lex_token.hpp
new file mode 100644
index 0000000000..81e589539f
--- /dev/null
+++ b/boost/wave/cpplexer/cpp_lex_token.hpp
@@ -0,0 +1,335 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ A generic C++ lexer token definition
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_TOKEN_HPP_53A13BD2_FBAA_444B_9B8B_FCB225C2BBA8_INCLUDED)
+#define CPP_TOKEN_HPP_53A13BD2_FBAA_444B_9B8B_FCB225C2BBA8_INCLUDED
+
+#include <boost/wave/wave_config.hpp>
+#if BOOST_WAVE_SERIALIZATION != 0
+#include <boost/serialization/serialization.hpp>
+#endif
+#include <boost/wave/util/file_position.hpp>
+#include <boost/wave/token_ids.hpp>
+#include <boost/wave/language_support.hpp>
+
+#include <boost/throw_exception.hpp>
+#include <boost/pool/singleton_pool.hpp>
+#include <boost/detail/atomic_count.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 {
+namespace cpplexer {
+
+namespace impl {
+
+template <typename StringTypeT, typename PositionT>
+class token_data
+{
+public:
+ typedef StringTypeT string_type;
+ typedef PositionT position_type;
+
+ // default constructed tokens correspond to EOI tokens
+ token_data()
+ : id(T_EOI), refcnt(1)
+ {}
+
+ // construct an invalid token
+ explicit token_data(int)
+ : id(T_UNKNOWN), refcnt(1)
+ {}
+
+ token_data(token_id id_, string_type const &value_, position_type const &pos_)
+ : id(id_), value(value_), pos(pos_), refcnt(1)
+ {}
+
+ token_data(token_data const& rhs)
+ : id(rhs.id), value(rhs.value), pos(rhs.pos), refcnt(1)
+ {}
+
+ ~token_data()
+ {}
+
+ std::size_t addref() { return ++refcnt; }
+ std::size_t release() { return --refcnt; }
+ std::size_t get_refcnt() const { return refcnt; }
+
+// accessors
+ operator token_id() const { return id; }
+ string_type const &get_value() const { return value; }
+ position_type const &get_position() const { return pos; }
+
+ void set_token_id (token_id id_) { id = id_; }
+ void set_value (string_type const &value_) { value = value_; }
+ void set_position (position_type const &pos_) { pos = pos_; }
+
+ friend bool operator== (token_data const& lhs, token_data const& rhs)
+ {
+ // two tokens are considered equal even if they refer to different
+ // positions
+ return (lhs.id == rhs.id && lhs.value == rhs.value) ? true : false;
+ }
+
+ void init(token_id id_, string_type const &value_, position_type const &pos_)
+ {
+ BOOST_ASSERT(refcnt == 1);
+ id = id_;
+ value = value_;
+ pos = pos_;
+ }
+
+ void init(token_data const& rhs)
+ {
+ BOOST_ASSERT(refcnt == 1);
+ id = rhs.id;
+ value = rhs.value;
+ pos = rhs.pos;
+ }
+
+ static void *operator new(std::size_t size);
+ static void operator delete(void *p, std::size_t size);
+
+#if defined(BOOST_SPIRIT_DEBUG)
+// debug support
+ void print (std::ostream &stream) const
+ {
+ stream << get_token_name(id) << "(";
+ for (std::size_t i = 0; i < value.size(); ++i) {
+ switch (value[i]) {
+ case '\r': stream << "\\r"; break;
+ case '\n': stream << "\\n"; break;
+ default:
+ stream << value[i];
+ break;
+ }
+ }
+ stream << ")";
+ }
+#endif // defined(BOOST_SPIRIT_DEBUG)
+
+#if BOOST_WAVE_SERIALIZATION != 0
+ friend class boost::serialization::access;
+ template<typename Archive>
+ void serialize(Archive &ar, const unsigned int version)
+ {
+ using namespace boost::serialization;
+ ar & make_nvp("id", id);
+ ar & make_nvp("value", value);
+ ar & make_nvp("position", pos);
+ }
+#endif
+
+private:
+ token_id id; // the token id
+ string_type value; // the text, which was parsed into this token
+ position_type pos; // the original file position
+ boost::detail::atomic_count refcnt;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+struct token_data_tag {};
+
+template <typename StringTypeT, typename PositionT>
+inline void *
+token_data<StringTypeT, PositionT>::operator new(std::size_t size)
+{
+ BOOST_ASSERT(sizeof(token_data<StringTypeT, PositionT>) == size);
+ typedef boost::singleton_pool<
+ token_data_tag, sizeof(token_data<StringTypeT, PositionT>)
+ > pool_type;
+
+ void *ret = pool_type::malloc();
+ if (0 == ret)
+ boost::throw_exception(std::bad_alloc());
+ return ret;
+}
+
+template <typename StringTypeT, typename PositionT>
+inline void
+token_data<StringTypeT, PositionT>::operator delete(void *p, std::size_t size)
+{
+ BOOST_ASSERT(sizeof(token_data<StringTypeT, PositionT>) == size);
+ typedef boost::singleton_pool<
+ token_data_tag, sizeof(token_data<StringTypeT, PositionT>)
+ > pool_type;
+
+ if (0 != p)
+ pool_type::free(p);
+}
+
+} // namespace impl
+
+///////////////////////////////////////////////////////////////////////////////
+// forward declaration of the token type
+template <typename PositionT = boost::wave::util::file_position_type>
+class lex_token;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// lex_token
+//
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename PositionT>
+class lex_token
+{
+public:
+ typedef BOOST_WAVE_STRINGTYPE string_type;
+ typedef PositionT position_type;
+
+private:
+ typedef impl::token_data<string_type, position_type> data_type;
+
+public:
+ // default constructed tokens correspond to EOI tokens
+ lex_token()
+ : data(0)
+ {}
+
+ // construct an invalid token
+ explicit lex_token(int)
+ : data(new data_type(0))
+ {}
+
+ lex_token(lex_token const& rhs)
+ : data(rhs.data)
+ {
+ if (0 != data)
+ data->addref();
+ }
+
+ lex_token(token_id id_, string_type const &value_, PositionT const &pos_)
+ : data(new data_type(id_, value_, pos_))
+ {}
+
+ ~lex_token()
+ {
+ if (0 != data && 0 == data->release())
+ delete data;
+ data = 0;
+ }
+
+ lex_token& operator=(lex_token const& rhs)
+ {
+ if (&rhs != this) {
+ if (0 != data && 0 == data->release())
+ delete data;
+
+ data = rhs.data;
+ if (0 != data)
+ data->addref();
+ }
+ return *this;
+ }
+
+// accessors
+ operator token_id() const { return 0 != data ? token_id(*data) : T_EOI; }
+ string_type const &get_value() const { return data->get_value(); }
+ position_type const &get_position() const { return data->get_position(); }
+ bool is_eoi() const { return 0 == data || token_id(*data) == T_EOI; }
+ bool is_valid() const { return 0 != data && token_id(*data) != T_UNKNOWN; }
+
+ void set_token_id (token_id id_) { make_unique(); data->set_token_id(id_); }
+ void set_value (string_type const &value_) { make_unique(); data->set_value(value_); }
+ void set_position (position_type const &pos_) { make_unique(); data->set_position(pos_); }
+
+ friend bool operator== (lex_token const& lhs, lex_token const& rhs)
+ {
+ if (0 == rhs.data)
+ return 0 == lhs.data;
+ if (0 == lhs.data)
+ return false;
+ return *(lhs.data) == *(rhs.data);
+ }
+
+// debug support
+#if BOOST_WAVE_DUMP_PARSE_TREE != 0
+// access functions for the tree_to_xml functionality
+ static int get_token_id(lex_token const &t)
+ { return token_id(t); }
+ static string_type get_token_value(lex_token const &t)
+ { return t.get_value(); }
+#endif
+
+#if defined(BOOST_SPIRIT_DEBUG)
+// debug support
+ void print (std::ostream &stream) const
+ {
+ data->print(stream);
+ }
+#endif // defined(BOOST_SPIRIT_DEBUG)
+
+private:
+#if BOOST_WAVE_SERIALIZATION != 0
+ friend class boost::serialization::access;
+ template<typename Archive>
+ void serialize(Archive &ar, const unsigned int version)
+ {
+ data->serialize(ar, version);
+ }
+#endif
+
+ // make a unique copy of the current object
+ void make_unique()
+ {
+ if (1 == data->get_refcnt())
+ return;
+
+ data_type* newdata = new data_type(*data) ;
+
+ data->release(); // release this reference, can't get zero
+ data = newdata;
+ }
+
+ data_type* data;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// This overload is needed by the multi_pass/functor_input_policy to
+// validate a token instance. It has to be defined in the same namespace
+// as the token class itself to allow ADL to find it.
+///////////////////////////////////////////////////////////////////////////////
+template <typename Position>
+inline bool
+token_is_valid(lex_token<Position> const& t)
+{
+ return t.is_valid();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+#if defined(BOOST_SPIRIT_DEBUG)
+template <typename PositionT>
+inline std::ostream &
+operator<< (std::ostream &stream, lex_token<PositionT> const &object)
+{
+ object.print(stream);
+ return stream;
+}
+#endif // defined(BOOST_SPIRIT_DEBUG)
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace cpplexer
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_TOKEN_HPP_53A13BD2_FBAA_444B_9B8B_FCB225C2BBA8_INCLUDED)
diff --git a/boost/wave/cpplexer/cpplexer_exceptions.hpp b/boost/wave/cpplexer/cpplexer_exceptions.hpp
new file mode 100644
index 0000000000..5ef0ca26e6
--- /dev/null
+++ b/boost/wave/cpplexer/cpplexer_exceptions.hpp
@@ -0,0 +1,290 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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(CPPLEXER_EXCEPTIONS_HPP_1A09DE1A_6D1F_4091_AF7F_5F13AB0D31AB_INCLUDED)
+#define CPPLEXER_EXCEPTIONS_HPP_1A09DE1A_6D1F_4091_AF7F_5F13AB0D31AB_INCLUDED
+
+#include <exception>
+#include <string>
+
+#include <boost/assert.hpp>
+#include <boost/config.hpp>
+#include <boost/throw_exception.hpp>
+
+#include <boost/wave/wave_config.hpp>
+
+// this must occur after all of the includes and before any code appears
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_PREFIX
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// helper macro for throwing exceptions
+#if !defined(BOOST_WAVE_LEXER_THROW)
+#ifdef BOOST_NO_STRINGSTREAM
+#include <strstream>
+#define BOOST_WAVE_LEXER_THROW(cls, code, msg, line, column, name) \
+ { \
+ using namespace boost::wave; \
+ std::strstream stream; \
+ stream << cls::severity_text(cls::code) << ": " \
+ << cls::error_text(cls::code); \
+ if ((msg)[0] != 0) stream << ": " << (msg); \
+ stream << std::ends; \
+ std::string throwmsg = stream.str(); stream.freeze(false); \
+ boost::throw_exception(cls(throwmsg.c_str(), cls::code, line, column, \
+ name)); \
+ } \
+ /**/
+#else
+#include <sstream>
+#define BOOST_WAVE_LEXER_THROW(cls, code, msg, line, column, name) \
+ { \
+ using namespace boost::wave; \
+ std::stringstream stream; \
+ stream << cls::severity_text(cls::code) << ": " \
+ << cls::error_text(cls::code); \
+ if ((msg)[0] != 0) stream << ": " << (msg); \
+ stream << std::ends; \
+ boost::throw_exception(cls(stream.str().c_str(), cls::code, line, column, \
+ name)); \
+ } \
+ /**/
+#endif // BOOST_NO_STRINGSTREAM
+#endif // BOOST_WAVE_LEXER_THROW
+
+#if !defined(BOOST_WAVE_LEXER_THROW_VAR)
+#ifdef BOOST_NO_STRINGSTREAM
+#include <strstream>
+#define BOOST_WAVE_LEXER_THROW_VAR(cls, codearg, msg, line, column, name) \
+ { \
+ using namespace boost::wave; \
+ cls::error_code code = static_cast<cls::error_code>(codearg); \
+ std::strstream stream; \
+ stream << cls::severity_text(code) << ": " \
+ << cls::error_text(code); \
+ if ((msg)[0] != 0) stream << ": " << (msg); \
+ stream << std::ends; \
+ std::string throwmsg = stream.str(); stream.freeze(false); \
+ boost::throw_exception(cls(throwmsg.c_str(), code, line, column, \
+ name)); \
+ } \
+ /**/
+#else
+#include <sstream>
+#define BOOST_WAVE_LEXER_THROW_VAR(cls, codearg, msg, line, column, name) \
+ { \
+ using namespace boost::wave; \
+ cls::error_code code = static_cast<cls::error_code>(codearg); \
+ std::stringstream stream; \
+ stream << cls::severity_text(code) << ": " \
+ << cls::error_text(code); \
+ if ((msg)[0] != 0) stream << ": " << (msg); \
+ stream << std::ends; \
+ boost::throw_exception(cls(stream.str().c_str(), code, line, column, \
+ name)); \
+ } \
+ /**/
+#endif // BOOST_NO_STRINGSTREAM
+#endif // BOOST_WAVE_LEXER_THROW
+
+///////////////////////////////////////////////////////////////////////////////
+namespace boost {
+namespace wave {
+namespace cpplexer {
+
+///////////////////////////////////////////////////////////////////////////////
+// exception severity
+namespace util {
+
+ enum severity {
+ severity_remark = 0,
+ severity_warning,
+ severity_error,
+ severity_fatal
+ };
+
+ inline char const *
+ get_severity(severity level)
+ {
+ static char const *severity_text[] =
+ {
+ "remark", // severity_remark
+ "warning", // severity_warning
+ "error", // severity_error
+ "fatal error" // severity_fatal
+ };
+ BOOST_ASSERT(severity_remark <= level && level <= severity_fatal);
+ return severity_text[level];
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// cpplexer_exception, the base class for all specific C++ lexer exceptions
+class BOOST_SYMBOL_VISIBLE cpplexer_exception
+: public std::exception
+{
+public:
+ cpplexer_exception(int line_, int column_, char const *filename_) throw()
+ : line(line_), column(column_)
+ {
+ unsigned int off = 0;
+ while (off < sizeof(filename)-1 && *filename_)
+ filename[off++] = *filename_++;
+ filename[off] = 0;
+ }
+ ~cpplexer_exception() throw() {}
+
+ virtual char const *what() const throw() = 0; // to be overloaded
+ virtual char const *description() const throw() = 0;
+ virtual int get_errorcode() const throw() = 0;
+ virtual int get_severity() const throw() = 0;
+ virtual bool is_recoverable() const throw() = 0;
+
+ int line_no() const throw() { return line; }
+ int column_no() const throw() { return column; }
+ char const *file_name() const throw() { return filename; }
+
+protected:
+ char filename[512];
+ int line;
+ int column;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// lexing_exception error
+class BOOST_SYMBOL_VISIBLE lexing_exception :
+ public cpplexer_exception
+{
+public:
+ enum error_code {
+ unexpected_error = 0,
+ universal_char_invalid = 1,
+ universal_char_base_charset = 2,
+ universal_char_not_allowed = 3,
+ invalid_long_long_literal = 4,
+ generic_lexing_error = 5,
+ generic_lexing_warning = 6
+ };
+
+ lexing_exception(char const *what_, error_code code, int line_,
+ int column_, char const *filename_) throw()
+ : cpplexer_exception(line_, column_, filename_),
+ level(severity_level(code)), code(code)
+ {
+ unsigned int off = 0;
+ while (off < sizeof(buffer) && *what_)
+ buffer[off++] = *what_++;
+ buffer[off] = 0;
+ }
+ ~lexing_exception() throw() {}
+
+ virtual char const *what() const throw()
+ {
+ return "boost::wave::lexing_exception";
+ }
+ virtual char const *description() const throw()
+ {
+ return buffer;
+ }
+ virtual int get_severity() const throw()
+ {
+ return level;
+ }
+ virtual int get_errorcode() const throw()
+ {
+ return code;
+ }
+ virtual bool is_recoverable() const throw()
+ {
+ switch (get_errorcode()) {
+ case lexing_exception::universal_char_invalid:
+ case lexing_exception::universal_char_base_charset:
+ case lexing_exception::universal_char_not_allowed:
+ case lexing_exception::invalid_long_long_literal:
+ case lexing_exception::generic_lexing_warning:
+ case lexing_exception::generic_lexing_error:
+ return true; // for now allow all exceptions to be recoverable
+
+ case lexing_exception::unexpected_error:
+ default:
+ break;
+ }
+ return false;
+ }
+
+ static char const *error_text(int code)
+ {
+ // error texts in this array must appear in the same order as the items in
+ // the error enum above
+ static char const *preprocess_exception_errors[] = {
+ "unexpected error (should not happen)", // unexpected_error
+ "universal character name specifies an invalid character", // universal_char_invalid
+ "a universal character name cannot designate a character in the "
+ "basic character set", // universal_char_base_charset
+ "this universal character is not allowed in an identifier", // universal_char_not_allowed
+ "long long suffixes are not allowed in pure C++ mode, "
+ "enable long_long mode to allow these", // invalid_long_long_literal
+ "generic lexer error", // generic_lexing_error
+ "generic lexer warning" // generic_lexing_warning
+ };
+ return preprocess_exception_errors[code];
+ }
+
+ static util::severity severity_level(int code)
+ {
+ static util::severity preprocess_exception_severity[] = {
+ util::severity_fatal, // unexpected_error
+ util::severity_error, // universal_char_invalid
+ util::severity_error, // universal_char_base_charset
+ util::severity_error, // universal_char_not_allowed
+ util::severity_warning, // invalid_long_long_literal
+ util::severity_error, // generic_lexing_error
+ util::severity_warning // invalid_long_long_literal
+ };
+ return preprocess_exception_severity[code];
+ }
+ static char const *severity_text(int code)
+ {
+ return util::get_severity(severity_level(code));
+ }
+
+private:
+ char buffer[512];
+ util::severity level;
+ error_code code;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// The is_recoverable() function allows to decide, whether it is possible
+// simply to continue after a given exception was thrown by Wave.
+//
+// This is kind of a hack to allow to recover from certain errors as long as
+// Wave doesn't provide better means of error recovery.
+//
+///////////////////////////////////////////////////////////////////////////////
+inline bool
+is_recoverable(lexing_exception const& e)
+{
+ return e.is_recoverable();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace cpplexer
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPPLEXER_EXCEPTIONS_HPP_1A09DE1A_6D1F_4091_AF7F_5F13AB0D31AB_INCLUDED)
diff --git a/boost/wave/cpplexer/detect_include_guards.hpp b/boost/wave/cpplexer/detect_include_guards.hpp
new file mode 100644
index 0000000000..09463ff8ea
--- /dev/null
+++ b/boost/wave/cpplexer/detect_include_guards.hpp
@@ -0,0 +1,263 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ State machine detecting include guards in an included file.
+ This detects two forms of include guards:
+
+ #ifndef INCLUDE_GUARD_MACRO
+ #define INCLUDE_GUARD_MACRO
+ ...
+ #endif
+
+ or
+
+ if !defined(INCLUDE_GUARD_MACRO)
+ #define INCLUDE_GUARD_MACRO
+ ...
+ #endif
+
+ note, that the parenthesis are optional (i.e. !defined INCLUDE_GUARD_MACRO
+ will work as well). The code allows for any whitespace, newline and single
+ '#' tokens before the #if/#ifndef and after the final #endif.
+
+ Copyright (c) 2001-2011 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(DETECT_INCLUDE_GUARDS_HK060304_INCLUDED)
+#define DETECT_INCLUDE_GUARDS_HK060304_INCLUDED
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/wave/token_ids.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 {
+namespace cpplexer {
+
+template <typename Token>
+class include_guards
+{
+public:
+ include_guards()
+ : state(&include_guards::state_0), detected_guards(false),
+ current_state(true), if_depth(0)
+ {}
+
+ Token& detect_guard(Token& t)
+ { return current_state ? (this->*state)(t) : t; }
+ bool detected(std::string& guard_name_) const
+ {
+ if (detected_guards) {
+ guard_name_ = guard_name.c_str();
+ return true;
+ }
+ return false;
+ }
+
+private:
+ typedef Token& state_type(Token& t);
+ state_type include_guards::* state;
+
+ bool detected_guards;
+ bool current_state;
+ typename Token::string_type guard_name;
+ int if_depth;
+
+ state_type state_0, state_1, state_2, state_3, state_4, state_5;
+ state_type state_1a, state_1b, state_1c, state_1d, state_1e;
+
+ bool is_skippable(token_id id) const
+ {
+ return (T_POUND == BASE_TOKEN(id) ||
+ IS_CATEGORY(id, WhiteSpaceTokenType) ||
+ IS_CATEGORY(id, EOLTokenType));
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// state 0: beginning of a file, tries to recognize #ifndef or #if tokens
+template <typename Token>
+inline Token&
+include_guards<Token>::state_0(Token& t)
+{
+ token_id id = token_id(t);
+ if (T_PP_IFNDEF == id)
+ state = &include_guards::state_1;
+ else if (T_PP_IF == id)
+ state = &include_guards::state_1a;
+ else if (!is_skippable(id))
+ current_state = false;
+ return t;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// state 1: found #ifndef, looking for T_IDENTIFIER
+template <typename Token>
+inline Token&
+include_guards<Token>::state_1(Token& t)
+{
+ token_id id = token_id(t);
+ if (T_IDENTIFIER == id) {
+ guard_name = t.get_value();
+ state = &include_guards::state_2;
+ }
+ else if (!is_skippable(id))
+ current_state = false;
+ return t;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// state 1a: found T_PP_IF, looking for T_NOT ("!")
+template <typename Token>
+inline Token&
+include_guards<Token>::state_1a(Token& t)
+{
+ token_id id = token_id(t);
+ if (T_NOT == BASE_TOKEN(id))
+ state = &include_guards::state_1b;
+ else if (!is_skippable(id))
+ current_state = false;
+ return t;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// state 1b: found T_NOT, looking for 'defined'
+template <typename Token>
+inline Token&
+include_guards<Token>::state_1b(Token& t)
+{
+ token_id id = token_id(t);
+ if (T_IDENTIFIER == id && t.get_value() == "defined")
+ state = &include_guards::state_1c;
+ else if (!is_skippable(id))
+ current_state = false;
+ return t;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// state 1c: found 'defined', looking for (optional) T_LEFTPAREN
+template <typename Token>
+inline Token&
+include_guards<Token>::state_1c(Token& t)
+{
+ token_id id = token_id(t);
+ if (T_LEFTPAREN == id)
+ state = &include_guards::state_1d;
+ else if (T_IDENTIFIER == id) {
+ guard_name = t.get_value();
+ state = &include_guards::state_2;
+ }
+ else if (!is_skippable(id))
+ current_state = false;
+ return t;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// state 1d: found T_LEFTPAREN, looking for T_IDENTIFIER guard
+template <typename Token>
+inline Token&
+include_guards<Token>::state_1d(Token& t)
+{
+ token_id id = token_id(t);
+ if (T_IDENTIFIER == id) {
+ guard_name = t.get_value();
+ state = &include_guards::state_1e;
+ }
+ else if (!is_skippable(id))
+ current_state = false;
+ return t;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// state 1e: found T_IDENTIFIER guard, looking for T_RIGHTPAREN
+template <typename Token>
+inline Token&
+include_guards<Token>::state_1e(Token& t)
+{
+ token_id id = token_id(t);
+ if (T_RIGHTPAREN == id)
+ state = &include_guards::state_2;
+ else if (!is_skippable(id))
+ current_state = false;
+ return t;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// state 2: found T_IDENTIFIER, looking for #define
+template <typename Token>
+inline Token&
+include_guards<Token>::state_2(Token& t)
+{
+ token_id id = token_id(t);
+ if (T_PP_DEFINE == id)
+ state = &include_guards::state_3;
+ else if (!is_skippable(id))
+ current_state = false;
+ return t;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// state 3: found #define, looking for T_IDENTIFIER as recognized by state 1
+template <typename Token>
+inline Token&
+include_guards<Token>::state_3(Token& t)
+{
+ token_id id = token_id(t);
+ if (T_IDENTIFIER == id && t.get_value() == guard_name)
+ state = &include_guards::state_4;
+ else if (!is_skippable(id))
+ current_state = false;
+ return t;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// state 4: found guard T_IDENTIFIER, looking for #endif
+template <typename Token>
+inline Token&
+include_guards<Token>::state_4(Token& t)
+{
+ token_id id = token_id(t);
+ if (T_PP_IF == id || T_PP_IFDEF == id || T_PP_IFNDEF == id)
+ ++if_depth;
+ else if (T_PP_ENDIF == id) {
+ if (if_depth > 0)
+ --if_depth;
+ else
+ state = &include_guards::state_5;
+ }
+ return t;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// state 5: found final #endif, looking for T_EOF
+template <typename Token>
+inline Token&
+include_guards<Token>::state_5(Token& t)
+{
+ token_id id = token_id(t);
+ if (T_EOF == id)
+ detected_guards = current_state;
+ else if (!is_skippable(id))
+ current_state = false;
+ return t;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace cpplexer
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !DETECT_INCLUDE_GUARDS_HK060304_INCLUDED
diff --git a/boost/wave/cpplexer/re2clex/aq.hpp b/boost/wave/cpplexer/re2clex/aq.hpp
new file mode 100644
index 0000000000..7b24359a48
--- /dev/null
+++ b/boost/wave/cpplexer/re2clex/aq.hpp
@@ -0,0 +1,64 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ Copyright (c) 2001 Daniel C. Nuffer.
+ Copyright (c) 2001-2011 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(AQ_HPP_A21D9145_B643_44C0_81E7_DB346DD67EE1_INCLUDED)
+#define AQ_HPP_A21D9145_B643_44C0_81E7_DB346DD67EE1_INCLUDED
+
+#include <boost/wave/wave_config.hpp>
+#include <cstdlib>
+
+// 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 {
+namespace cpplexer {
+namespace re2clex {
+
+typedef std::size_t aq_stdelement;
+
+typedef struct tag_aq_queuetype
+{
+ std::size_t head;
+ std::size_t tail;
+ std::size_t size;
+ std::size_t max_size;
+ aq_stdelement* queue;
+} aq_queuetype;
+
+typedef aq_queuetype* aq_queue;
+
+int aq_enqueue(aq_queue q, aq_stdelement e);
+int aq_enqueue_front(aq_queue q, aq_stdelement e);
+int aq_serve(aq_queue q, aq_stdelement *e);
+int aq_pop(aq_queue q);
+#define AQ_EMPTY(q) (q->size == 0)
+#define AQ_FULL(q) (q->size == q->max_size)
+int aq_grow(aq_queue q);
+
+BOOST_WAVE_DECL aq_queue aq_create(void);
+BOOST_WAVE_DECL void aq_terminate(aq_queue q);
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace re2clex
+} // namespace cpplexer
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(AQ_HPP_A21D9145_B643_44C0_81E7_DB346DD67EE1_INCLUDED)
diff --git a/boost/wave/cpplexer/re2clex/cpp_re.hpp b/boost/wave/cpplexer/re2clex/cpp_re.hpp
new file mode 100644
index 0000000000..5febbb4a20
--- /dev/null
+++ b/boost/wave/cpplexer/re2clex/cpp_re.hpp
@@ -0,0 +1,57 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ Re2C based C++ lexer
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_RE_HPP_B76C4F5E_63E9_4B8A_9975_EC32FA6BF027_INCLUDED)
+#define CPP_RE_HPP_B76C4F5E_63E9_4B8A_9975_EC32FA6BF027_INCLUDED
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/wave/token_ids.hpp>
+
+// this must occur after all of the includes and before any code appears
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_PREFIX
+#endif
+
+// suppress warnings about dependent classes not being exported from the dll
+#ifdef BOOST_MSVC
+#pragma warning(push)
+#pragma warning(disable : 4251 4231 4660)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+namespace boost {
+namespace wave {
+namespace cpplexer {
+namespace re2clex {
+
+struct Scanner;
+
+///////////////////////////////////////////////////////////////////////////////
+// The scanner function to call whenever a new token is requested
+BOOST_WAVE_DECL boost::wave::token_id scan(Scanner *s);
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace re2clex
+} // namespace cpplexer
+} // namespace wave
+} // namespace boost
+
+#ifdef BOOST_MSVC
+#pragma warning(pop)
+#endif
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_RE_HPP_B76C4F5E_63E9_4B8A_9975_EC32FA6BF027_INCLUDED)
diff --git a/boost/wave/cpplexer/re2clex/cpp_re2c_lexer.hpp b/boost/wave/cpplexer/re2clex/cpp_re2c_lexer.hpp
new file mode 100644
index 0000000000..748738544b
--- /dev/null
+++ b/boost/wave/cpplexer/re2clex/cpp_re2c_lexer.hpp
@@ -0,0 +1,429 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ Re2C based C++ lexer
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_RE2C_LEXER_HPP_B81A2629_D5B1_4944_A97D_60254182B9A8_INCLUDED)
+#define CPP_RE2C_LEXER_HPP_B81A2629_D5B1_4944_A97D_60254182B9A8_INCLUDED
+
+#include <string>
+#include <cstdio>
+#include <cstdarg>
+#if defined(BOOST_SPIRIT_DEBUG)
+#include <iostream>
+#endif // defined(BOOST_SPIRIT_DEBUG)
+
+#include <boost/concept_check.hpp>
+#include <boost/assert.hpp>
+#include <boost/spirit/include/classic_core.hpp>
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/wave/language_support.hpp>
+#include <boost/wave/token_ids.hpp>
+#include <boost/wave/util/file_position.hpp>
+#include <boost/wave/cpplexer/validate_universal_char.hpp>
+#include <boost/wave/cpplexer/cpplexer_exceptions.hpp>
+#include <boost/wave/cpplexer/token_cache.hpp>
+#include <boost/wave/cpplexer/convert_trigraphs.hpp>
+
+#include <boost/wave/cpplexer/cpp_lex_interface.hpp>
+#include <boost/wave/cpplexer/re2clex/scanner.hpp>
+#include <boost/wave/cpplexer/re2clex/cpp_re.hpp>
+#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+#include <boost/wave/cpplexer/detect_include_guards.hpp>
+#endif
+
+#include <boost/wave/cpplexer/cpp_lex_interface_generator.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 {
+namespace cpplexer {
+namespace re2clex {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// encapsulation of the re2c based cpp lexer
+//
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename IteratorT,
+ typename PositionT = boost::wave::util::file_position_type,
+ typename TokenT = lex_token<PositionT> >
+class lexer
+{
+public:
+ typedef TokenT token_type;
+ typedef typename token_type::string_type string_type;
+
+ lexer(IteratorT const &first, IteratorT const &last,
+ PositionT const &pos, boost::wave::language_support language_);
+ ~lexer();
+
+ token_type& get(token_type&);
+ void set_position(PositionT const &pos)
+ {
+ // set position has to change the file name and line number only
+ filename = pos.get_file();
+ scanner.line = pos.get_line();
+// scanner.column = scanner.curr_column = pos.get_column();
+ scanner.file_name = filename.c_str();
+ }
+#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+ bool has_include_guards(std::string& guard_name) const
+ {
+ return guards.detected(guard_name);
+ }
+#endif
+
+// error reporting from the re2c generated lexer
+ static int report_error(Scanner const* s, int code, char const *, ...);
+
+private:
+ static char const *tok_names[];
+
+ Scanner scanner;
+ string_type filename;
+ string_type value;
+ bool at_eof;
+ boost::wave::language_support language;
+#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+ include_guards<token_type> guards;
+#endif
+
+#if BOOST_WAVE_SUPPORT_THREADING == 0
+ static token_cache<string_type> const cache;
+#else
+ token_cache<string_type> const cache;
+#endif
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// initialize cpp lexer
+template <typename IteratorT, typename PositionT, typename TokenT>
+inline
+lexer<IteratorT, PositionT, TokenT>::lexer(IteratorT const &first,
+ IteratorT const &last, PositionT const &pos,
+ boost::wave::language_support language_)
+ : filename(pos.get_file()), at_eof(false), language(language_)
+#if BOOST_WAVE_SUPPORT_THREADING != 0
+ , cache()
+#endif
+{
+ using namespace std; // some systems have memset in std
+ memset(&scanner, '\0', sizeof(Scanner));
+ scanner.eol_offsets = aq_create();
+ if (first != last) {
+ scanner.first = scanner.act = (uchar *)&(*first);
+ scanner.last = scanner.first + std::distance(first, last);
+ }
+ scanner.line = pos.get_line();
+ scanner.column = scanner.curr_column = pos.get_column();
+ scanner.error_proc = report_error;
+ scanner.file_name = filename.c_str();
+
+#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
+ scanner.enable_ms_extensions = true;
+#else
+ scanner.enable_ms_extensions = false;
+#endif
+
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ scanner.act_in_c99_mode = boost::wave::need_c99(language_);
+#endif
+
+#if BOOST_WAVE_SUPPORT_IMPORT_KEYWORD != 0
+ scanner.enable_import_keyword = !boost::wave::need_c99(language_);
+#else
+ scanner.enable_import_keyword = false;
+#endif
+
+ scanner.detect_pp_numbers = boost::wave::need_prefer_pp_numbers(language_);
+ scanner.single_line_only = boost::wave::need_single_line(language_);
+
+#if BOOST_WAVE_SUPPORT_CPP0X != 0
+ scanner.act_in_cpp0x_mode = boost::wave::need_cpp0x(language_);
+#else
+ scanner.act_in_cpp0x_mode = false;
+#endif
+}
+
+template <typename IteratorT, typename PositionT, typename TokenT>
+inline
+lexer<IteratorT, PositionT, TokenT>::~lexer()
+{
+ using namespace std; // some systems have free in std
+ aq_terminate(scanner.eol_offsets);
+ free(scanner.bot);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// get the next token from the input stream
+template <typename IteratorT, typename PositionT, typename TokenT>
+inline TokenT&
+lexer<IteratorT, PositionT, TokenT>::get(TokenT& result)
+{
+ if (at_eof)
+ return result = token_type(); // return T_EOI
+
+ unsigned int actline = scanner.line;
+ token_id id = token_id(scan(&scanner));
+
+ switch (static_cast<unsigned int>(id)) {
+ case T_IDENTIFIER:
+ // test identifier characters for validity (throws if invalid chars found)
+ value = string_type((char const *)scanner.tok,
+ scanner.cur-scanner.tok);
+ if (!boost::wave::need_no_character_validation(language))
+ impl::validate_identifier_name(value, actline, scanner.column, filename);
+ break;
+
+ case T_STRINGLIT:
+ case T_CHARLIT:
+ case T_RAWSTRINGLIT:
+ // test literal characters for validity (throws if invalid chars found)
+ value = string_type((char const *)scanner.tok,
+ scanner.cur-scanner.tok);
+ if (boost::wave::need_convert_trigraphs(language))
+ value = impl::convert_trigraphs(value);
+ if (!boost::wave::need_no_character_validation(language))
+ impl::validate_literal(value, actline, scanner.column, filename);
+ break;
+
+#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
+ case T_PP_HHEADER:
+ case T_PP_QHEADER:
+ case T_PP_INCLUDE:
+ // convert to the corresponding ..._next token, if appropriate
+ {
+ value = string_type((char const *)scanner.tok,
+ scanner.cur-scanner.tok);
+
+ // Skip '#' and whitespace and see whether we find an 'include_next' here.
+ typename string_type::size_type start = value.find("include");
+ if (value.compare(start, 12, "include_next", 12) == 0)
+ id = token_id(id | AltTokenType);
+ break;
+ }
+#endif
+
+ case T_LONGINTLIT: // supported in C++0x, C99 and long_long mode
+ value = string_type((char const *)scanner.tok,
+ scanner.cur-scanner.tok);
+ if (!boost::wave::need_long_long(language)) {
+ // syntax error: not allowed in C++ mode
+ BOOST_WAVE_LEXER_THROW(lexing_exception, invalid_long_long_literal,
+ value.c_str(), actline, scanner.column, filename.c_str());
+ }
+ break;
+
+ case T_OCTALINT:
+ case T_DECIMALINT:
+ case T_HEXAINT:
+ case T_INTLIT:
+ case T_FLOATLIT:
+ case T_FIXEDPOINTLIT:
+ case T_CCOMMENT:
+ case T_CPPCOMMENT:
+ case T_SPACE:
+ case T_SPACE2:
+ case T_ANY:
+ case T_PP_NUMBER:
+ value = string_type((char const *)scanner.tok,
+ scanner.cur-scanner.tok);
+ break;
+
+ case T_EOF:
+ // T_EOF is returned as a valid token, the next call will return T_EOI,
+ // i.e. the actual end of input
+ at_eof = true;
+ value.clear();
+ break;
+
+ case T_OR_TRIGRAPH:
+ case T_XOR_TRIGRAPH:
+ case T_LEFTBRACE_TRIGRAPH:
+ case T_RIGHTBRACE_TRIGRAPH:
+ case T_LEFTBRACKET_TRIGRAPH:
+ case T_RIGHTBRACKET_TRIGRAPH:
+ case T_COMPL_TRIGRAPH:
+ case T_POUND_TRIGRAPH:
+ if (boost::wave::need_convert_trigraphs(language)) {
+ value = cache.get_token_value(BASEID_FROM_TOKEN(id));
+ }
+ else {
+ value = string_type((char const *)scanner.tok,
+ scanner.cur-scanner.tok);
+ }
+ break;
+
+ case T_ANY_TRIGRAPH:
+ if (boost::wave::need_convert_trigraphs(language)) {
+ value = impl::convert_trigraph(
+ string_type((char const *)scanner.tok));
+ }
+ else {
+ value = string_type((char const *)scanner.tok,
+ scanner.cur-scanner.tok);
+ }
+ break;
+
+ default:
+ if (CATEGORY_FROM_TOKEN(id) != EXTCATEGORY_FROM_TOKEN(id) ||
+ IS_CATEGORY(id, UnknownTokenType))
+ {
+ value = string_type((char const *)scanner.tok,
+ scanner.cur-scanner.tok);
+ }
+ else {
+ value = cache.get_token_value(id);
+ }
+ break;
+ }
+
+// std::cerr << boost::wave::get_token_name(id) << ": " << value << std::endl;
+
+ // the re2c lexer reports the new line number for newline tokens
+ result = token_type(id, value, PositionT(filename, actline, scanner.column));
+
+#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+ return guards.detect_guard(result);
+#else
+ return result;
+#endif
+}
+
+template <typename IteratorT, typename PositionT, typename TokenT>
+inline int
+lexer<IteratorT, PositionT, TokenT>::report_error(Scanner const *s, int errcode,
+ char const *msg, ...)
+{
+ BOOST_ASSERT(0 != s);
+ BOOST_ASSERT(0 != msg);
+
+ using namespace std; // some system have vsprintf in namespace std
+
+ char buffer[200]; // should be large enough
+ va_list params;
+ va_start(params, msg);
+ vsprintf(buffer, msg, params);
+ va_end(params);
+
+ BOOST_WAVE_LEXER_THROW_VAR(lexing_exception, errcode, buffer, s->line,
+ s->column, s->file_name);
+// BOOST_UNREACHABLE_RETURN(0);
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// lex_functor
+//
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename IteratorT,
+ typename PositionT = boost::wave::util::file_position_type,
+ typename TokenT = typename lexer<IteratorT, PositionT>::token_type>
+class lex_functor
+: public lex_input_interface_generator<TokenT>
+{
+public:
+ typedef TokenT token_type;
+
+ lex_functor(IteratorT const &first, IteratorT const &last,
+ PositionT const &pos, boost::wave::language_support language)
+ : re2c_lexer(first, last, pos, language)
+ {}
+ virtual ~lex_functor() {}
+
+// get the next token from the input stream
+ token_type& get(token_type& result) { return re2c_lexer.get(result); }
+ void set_position(PositionT const &pos) { re2c_lexer.set_position(pos); }
+#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+ bool has_include_guards(std::string& guard_name) const
+ { return re2c_lexer.has_include_guards(guard_name); }
+#endif
+
+private:
+ lexer<IteratorT, PositionT, TokenT> re2c_lexer;
+};
+
+#if BOOST_WAVE_SUPPORT_THREADING == 0
+///////////////////////////////////////////////////////////////////////////////
+template <typename IteratorT, typename PositionT, typename TokenT>
+token_cache<typename lexer<IteratorT, PositionT, TokenT>::string_type> const
+ lexer<IteratorT, PositionT, TokenT>::cache =
+ token_cache<typename lexer<IteratorT, PositionT, TokenT>::string_type>();
+#endif
+
+} // namespace re2clex
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// The new_lexer_gen<>::new_lexer function (declared in cpp_lex_interface.hpp)
+// should be defined inline, if the lex_functor shouldn't be instantiated
+// separately from the lex_iterator.
+//
+// Separate (explicit) instantiation helps to reduce compilation time.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0
+#define BOOST_WAVE_RE2C_NEW_LEXER_INLINE
+#else
+#define BOOST_WAVE_RE2C_NEW_LEXER_INLINE inline
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// The 'new_lexer' function allows the opaque generation of a new lexer object.
+// It is coupled to the iterator type to allow to decouple the lexer/iterator
+// configurations at compile time.
+//
+// This function is declared inside the cpp_lex_token.hpp file, which is
+// referenced by the source file calling the lexer and the source file, which
+// instantiates the lex_functor. But is is defined here, so it will be
+// instantiated only while compiling the source file, which instantiates the
+// lex_functor. While the cpp_re2c_token.hpp file may be included everywhere,
+// this file (cpp_re2c_lexer.hpp) should be included only once. This allows
+// to decouple the lexer interface from the lexer implementation and reduces
+// compilation time.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename IteratorT, typename PositionT, typename TokenT>
+BOOST_WAVE_RE2C_NEW_LEXER_INLINE
+lex_input_interface<TokenT> *
+new_lexer_gen<IteratorT, PositionT, TokenT>::new_lexer(IteratorT const &first,
+ IteratorT const &last, PositionT const &pos,
+ boost::wave::language_support language)
+{
+ using re2clex::lex_functor;
+ return new lex_functor<IteratorT, PositionT, TokenT>(first, last, pos, language);
+}
+
+#undef BOOST_WAVE_RE2C_NEW_LEXER_INLINE
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace cpplexer
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_RE2C_LEXER_HPP_B81A2629_D5B1_4944_A97D_60254182B9A8_INCLUDED)
diff --git a/boost/wave/cpplexer/re2clex/scanner.hpp b/boost/wave/cpplexer/re2clex/scanner.hpp
new file mode 100644
index 0000000000..e052558e6d
--- /dev/null
+++ b/boost/wave/cpplexer/re2clex/scanner.hpp
@@ -0,0 +1,74 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ Copyright (c) 2001 Daniel C. Nuffer.
+ Copyright (c) 2001-2011 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(SCANNER_HPP_F4FB01EB_E75C_4537_A146_D34B9895EF37_INCLUDED)
+#define SCANNER_HPP_F4FB01EB_E75C_4537_A146_D34B9895EF37_INCLUDED
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/wave/cpplexer/re2clex/aq.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 {
+namespace cpplexer {
+namespace re2clex {
+
+struct Scanner;
+typedef unsigned char uchar;
+typedef int (* ReportErrorProc)(struct Scanner const *, int errorcode,
+ char const *, ...);
+
+typedef struct Scanner {
+ uchar* first; /* start of input buffer */
+ uchar* act; /* act position of input buffer */
+ uchar* last; /* end (one past last char) of input buffer */
+ uchar* bot; /* beginning of the current buffer */
+ uchar* top; /* top of the current buffer */
+ uchar* eof; /* when we read in the last buffer, will point 1 past the
+ end of the file, otherwise 0 */
+ uchar* tok; /* points to the beginning of the current token */
+ uchar* ptr; /* used for YYMARKER - saves backtracking info */
+ uchar* cur; /* saves the cursor (maybe is redundant with tok?) */
+ uchar* lim; /* used for YYLIMIT - points to the end of the buffer */
+ /* (lim == top) except for the last buffer, it points to
+ the end of the input (lim == eof - 1) */
+ unsigned int line; /* current line being lex'ed */
+ unsigned int column; /* current token start column position */
+ unsigned int curr_column; /* current column position */
+ ReportErrorProc error_proc; /* must be != 0, this function is called to
+ report an error */
+ char const *file_name; /* name of the lex'ed file */
+ aq_queue eol_offsets;
+ bool enable_ms_extensions; /* enable MS extensions */
+ bool act_in_c99_mode; /* lexer works in C99 mode */
+ bool detect_pp_numbers; /* lexer should prefer to detect pp-numbers */
+ bool enable_import_keyword; /* recognize import as a keyword */
+ bool single_line_only; /* don't report missing eol's in C++ comments */
+ bool act_in_cpp0x_mode; /* lexer works in C++0x mode */
+} Scanner;
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace re2clex
+} // namespace cpplexer
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(SCANNER_HPP_F4FB01EB_E75C_4537_A146_D34B9895EF37_INCLUDED)
diff --git a/boost/wave/cpplexer/token_cache.hpp b/boost/wave/cpplexer/token_cache.hpp
new file mode 100644
index 0000000000..4dedb48f24
--- /dev/null
+++ b/boost/wave/cpplexer/token_cache.hpp
@@ -0,0 +1,72 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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(TOKEN_CACHE_HPP_4D2320B7_1D56_4113_A114_397E70FA438C_INCLUDED)
+#define TOKEN_CACHE_HPP_4D2320B7_1D56_4113_A114_397E70FA438C_INCLUDED
+
+#include <vector>
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/wave/token_ids.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 {
+namespace cpplexer {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// The token_cache template is used to cache the tokens corresponding to the
+// keywords, operators and other constant language elements.
+//
+// This avoids repeated construction of these tokens, which is especially
+// effective when used in conjunction with a copy on write string
+// implementation (COW string).
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename StringT>
+class token_cache
+{
+public:
+ token_cache()
+ : cache(T_LAST_TOKEN - T_FIRST_TOKEN)
+ {
+ typename std::vector<StringT>::iterator it = cache.begin();
+ for (unsigned int i = T_FIRST_TOKEN; i < T_LAST_TOKEN; ++i, ++it)
+ {
+ *it = StringT(boost::wave::get_token_value(token_id(i)));
+ }
+ }
+
+ StringT const &get_token_value(token_id id) const
+ {
+ return cache[BASEID_FROM_TOKEN(id) - T_FIRST_TOKEN];
+ }
+
+private:
+ std::vector<StringT> cache;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace cpplexer
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(TOKEN_CACHE_HPP_4D2320B7_1D56_4113_A114_397E70FA438C_INCLUDED)
diff --git a/boost/wave/cpplexer/validate_universal_char.hpp b/boost/wave/cpplexer/validate_universal_char.hpp
new file mode 100644
index 0000000000..09b0a06c92
--- /dev/null
+++ b/boost/wave/cpplexer/validate_universal_char.hpp
@@ -0,0 +1,322 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ Grammar for universal character validation (see C++ standard: Annex E)
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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(VALIDATE_UNIVERSAL_CHAR_HPP_55F1B811_CD76_4C72_8344_CBC69CF3B339_INCLUDED)
+#define VALIDATE_UNIVERSAL_CHAR_HPP_55F1B811_CD76_4C72_8344_CBC69CF3B339_INCLUDED
+
+#include <boost/assert.hpp>
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/wave/util/file_position.hpp>
+#include <boost/wave/cpplexer/cpplexer_exceptions.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 {
+namespace cpplexer {
+namespace impl {
+
+enum universal_char_type {
+ universal_char_type_valid = 0,
+ universal_char_type_invalid = 1,
+ universal_char_type_base_charset = 2,
+ universal_char_type_not_allowed_for_identifiers = 3
+};
+
+///////////////////////////////////////////////////////////////////////////
+//
+// is_range is a helper function for the classification by brute force
+// below
+//
+///////////////////////////////////////////////////////////////////////////
+inline bool
+in_range(unsigned long ch, unsigned long l, unsigned long u)
+{
+ return (l <= ch && ch <= u);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// classify_universal_char
+//
+// This function classifies an universal character value into 4 subranges:
+// universal_char_type_valid
+// the universal character value is valid for identifiers
+// universal_char_type_invalid
+// the universal character value is not valid for its usage inside
+// identifiers (see C++ Standard: 2.2.2 [lex.charset])
+// universal_char_type_base_charset
+// the universal character value designates a character from the base
+// character set
+// universal_char_type_not_allowed_for_identifiers
+// the universal character value is not allowed in an identifier
+//
+// Implementation note:
+// This classification isn't implemented very effectively here. This
+// function should be rewritten with some range run matching algorithm.
+//
+///////////////////////////////////////////////////////////////////////////////
+inline universal_char_type
+classify_universal_char (unsigned long ch)
+{
+// test for invalid characters
+ if (ch <= 0x0020 || in_range(ch, 0x007f, 0x009f))
+ return universal_char_type_invalid;
+
+// test for characters in the range of the base character set
+ if (in_range(ch, 0x0021, 0x005f) || in_range(ch, 0x0061, 0x007e))
+ return universal_char_type_base_charset;
+
+// test for additional valid character values (see C++ Standard: Annex E)
+ if (in_range(ch, 0x00c0, 0x00d6) || in_range(ch, 0x00d8, 0x00f6) ||
+ in_range(ch, 0x00f8, 0x01f5) || in_range(ch, 0x01fa, 0x0217) ||
+ in_range(ch, 0x0250, 0x02a8) || in_range(ch, 0x1e00, 0x1e9a) ||
+ in_range(ch, 0x1ea0, 0x1ef9))
+ {
+ return universal_char_type_valid; // Latin
+ }
+
+ if (0x0384 == ch || in_range(ch, 0x0388, 0x038a) ||
+ 0x038c == ch || in_range(ch, 0x038e, 0x03a1) ||
+ in_range(ch, 0x03a3, 0x03ce) || in_range(ch, 0x03d0, 0x03d6) ||
+ 0x03da == ch || 0x03dc == ch || 0x03de == ch || 0x03e0 == ch ||
+ in_range(ch, 0x03e2, 0x03f3) || in_range(ch, 0x1f00, 0x1f15) ||
+ in_range(ch, 0x1f18, 0x1f1d) || in_range(ch, 0x1f20, 0x1f45) ||
+ in_range(ch, 0x1f48, 0x1f4d) || in_range(ch, 0x1f50, 0x1f57) ||
+ 0x1f59 == ch || 0x1f5b == ch || 0x1f5d == ch ||
+ in_range(ch, 0x1f5f, 0x1f7d) || in_range(ch, 0x1f80, 0x1fb4) ||
+ in_range(ch, 0x1fb6, 0x1fbc) || in_range(ch, 0x1fc2, 0x1fc4) ||
+ in_range(ch, 0x1fc6, 0x1fcc) || in_range(ch, 0x1fd0, 0x1fd3) ||
+ in_range(ch, 0x1fd6, 0x1fdb) || in_range(ch, 0x1fe0, 0x1fec) ||
+ in_range(ch, 0x1ff2, 0x1ff4) || in_range(ch, 0x1ff6, 0x1ffc))
+ {
+ return universal_char_type_valid; // Greek
+ }
+
+ if (in_range(ch, 0x0401, 0x040d) || in_range(ch, 0x040f, 0x044f) ||
+ in_range(ch, 0x0451, 0x045c) || in_range(ch, 0x045e, 0x0481) ||
+ in_range(ch, 0x0490, 0x04c4) || in_range(ch, 0x04c7, 0x04c8) ||
+ in_range(ch, 0x04cb, 0x04cc) || in_range(ch, 0x04d0, 0x04eb) ||
+ in_range(ch, 0x04ee, 0x04f5) || in_range(ch, 0x04f8, 0x04f9))
+ {
+ return universal_char_type_valid; // Cyrillic
+ }
+
+ if (in_range(ch, 0x0531, 0x0556) || in_range(ch, 0x0561, 0x0587))
+ return universal_char_type_valid; // Armenian
+
+ if (in_range(ch, 0x05d0, 0x05ea) || in_range(ch, 0x05f0, 0x05f4))
+ return universal_char_type_valid; // Hebrew
+
+ if (in_range(ch, 0x0621, 0x063a) || in_range(ch, 0x0640, 0x0652) ||
+ in_range(ch, 0x0670, 0x06b7) || in_range(ch, 0x06ba, 0x06be) ||
+ in_range(ch, 0x06c0, 0x06ce) || in_range(ch, 0x06e5, 0x06e7))
+ {
+ return universal_char_type_valid; // Arabic
+ }
+
+ if (in_range(ch, 0x0905, 0x0939) || in_range(ch, 0x0958, 0x0962))
+ return universal_char_type_valid; // Devanagari
+
+ if (in_range(ch, 0x0985, 0x098c) || in_range(ch, 0x098f, 0x0990) ||
+ in_range(ch, 0x0993, 0x09a8) || in_range(ch, 0x09aa, 0x09b0) ||
+ 0x09b2 == ch || in_range(ch, 0x09b6, 0x09b9) ||
+ in_range(ch, 0x09dc, 0x09dd) || in_range(ch, 0x09df, 0x09e1) ||
+ in_range(ch, 0x09f0, 0x09f1))
+ {
+ return universal_char_type_valid; // Bengali
+ }
+
+ if (in_range(ch, 0x0a05, 0x0a0a) || in_range(ch, 0x0a0f, 0x0a10) ||
+ in_range(ch, 0x0a13, 0x0a28) || in_range(ch, 0x0a2a, 0x0a30) ||
+ in_range(ch, 0x0a32, 0x0a33) || in_range(ch, 0x0a35, 0x0a36) ||
+ in_range(ch, 0x0a38, 0x0a39) || in_range(ch, 0x0a59, 0x0a5c) ||
+ 0x0a5e == ch)
+ {
+ return universal_char_type_valid; // Gurmukhi
+ }
+
+ if (in_range(ch, 0x0a85, 0x0a8b) || 0x0a8d == ch ||
+ in_range(ch, 0x0a8f, 0x0a91) || in_range(ch, 0x0a93, 0x0aa8) ||
+ in_range(ch, 0x0aaa, 0x0ab0) || in_range(ch, 0x0ab2, 0x0ab3) ||
+ in_range(ch, 0x0ab5, 0x0ab9) || 0x0ae0 == ch)
+ {
+ return universal_char_type_valid; // Gujarati
+ }
+
+ if (in_range(ch, 0x0b05, 0x0b0c) || in_range(ch, 0x0b0f, 0x0b10) ||
+ in_range(ch, 0x0b13, 0x0b28) || in_range(ch, 0x0b2a, 0x0b30) ||
+ in_range(ch, 0x0b32, 0x0b33) || in_range(ch, 0x0b36, 0x0b39) ||
+ in_range(ch, 0x0b5c, 0x0b5d) || in_range(ch, 0x0b5f, 0x0b61))
+ {
+ return universal_char_type_valid; // Oriya
+ }
+
+ if (in_range(ch, 0x0b85, 0x0b8a) || in_range(ch, 0x0b8e, 0x0b90) ||
+ in_range(ch, 0x0b92, 0x0b95) || in_range(ch, 0x0b99, 0x0b9a) ||
+ 0x0b9c == ch || in_range(ch, 0x0b9e, 0x0b9f) ||
+ in_range(ch, 0x0ba3, 0x0ba4) || in_range(ch, 0x0ba8, 0x0baa) ||
+ in_range(ch, 0x0bae, 0x0bb5) || in_range(ch, 0x0bb7, 0x0bb9))
+ {
+ return universal_char_type_valid; // Tamil
+ }
+
+ if (in_range(ch, 0x0c05, 0x0c0c) || in_range(ch, 0x0c0e, 0x0c10) ||
+ in_range(ch, 0x0c12, 0x0c28) || in_range(ch, 0x0c2a, 0x0c33) ||
+ in_range(ch, 0x0c35, 0x0c39) || in_range(ch, 0x0c60, 0x0c61))
+ {
+ return universal_char_type_valid; // Telugu
+ }
+
+ if (in_range(ch, 0x0c85, 0x0c8c) || in_range(ch, 0x0c8e, 0x0c90) ||
+ in_range(ch, 0x0c92, 0x0ca8) || in_range(ch, 0x0caa, 0x0cb3) ||
+ in_range(ch, 0x0cb5, 0x0cb9) || in_range(ch, 0x0ce0, 0x0ce1))
+ {
+ return universal_char_type_valid; // Kannada
+ }
+
+ if (in_range(ch, 0x0d05, 0x0d0c) || in_range(ch, 0x0d0e, 0x0d10) ||
+ in_range(ch, 0x0d12, 0x0d28) || in_range(ch, 0x0d2a, 0x0d39) ||
+ in_range(ch, 0x0d60, 0x0d61))
+ {
+ return universal_char_type_valid; // Malayalam
+ }
+
+ if (in_range(ch, 0x0e01, 0x0e30) || in_range(ch, 0x0e32, 0x0e33) ||
+ in_range(ch, 0x0e40, 0x0e46) || in_range(ch, 0x0e4f, 0x0e5b))
+ {
+ return universal_char_type_valid; // Thai
+ }
+
+ return universal_char_type_not_allowed_for_identifiers;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// validate_identifier_name
+//
+// The validate_identifier_name function tests a given identifier name for
+// its validity with regard to eventually contained universal characters.
+// These should be in valid ranges (see the function
+// classify_universal_char above).
+//
+// If the identifier name contains invalid or not allowed universal
+// characters a corresponding lexing_exception is thrown.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename StringT>
+inline void
+validate_identifier_name (StringT const &name, int line, int column,
+ StringT const &file_name)
+{
+ using namespace std; // some systems have strtoul in namespace std::
+
+typename StringT::size_type pos = name.find_first_of('\\');
+
+ while (StringT::npos != pos) {
+ // the identifier name contains a backslash (must be universal char)
+ BOOST_ASSERT('u' == name[pos+1] || 'U' == name[pos+1]);
+
+ StringT uchar_val(name.substr(pos+2, ('u' == name[pos+1]) ? 4 : 8));
+ universal_char_type type =
+ classify_universal_char(strtoul(uchar_val.c_str(), 0, 16));
+
+ if (universal_char_type_valid != type) {
+ // an invalid char was found, so throw an exception
+ StringT error_uchar(name.substr(pos, ('u' == name[pos+1]) ? 6 : 10));
+
+ if (universal_char_type_invalid == type) {
+ BOOST_WAVE_LEXER_THROW(lexing_exception, universal_char_invalid,
+ error_uchar, line, column, file_name.c_str());
+ }
+ else if (universal_char_type_base_charset == type) {
+ BOOST_WAVE_LEXER_THROW(lexing_exception, universal_char_base_charset,
+ error_uchar, line, column, file_name.c_str());
+ }
+ else {
+ BOOST_WAVE_LEXER_THROW(lexing_exception, universal_char_not_allowed,
+ error_uchar, line, column, file_name.c_str());
+ }
+ }
+
+ // find next universal char (if appropriate)
+ pos = name.find_first_of('\\', pos+2);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// validate_literal
+//
+// The validate_literal function tests a given string or character literal
+// for its validity with regard to eventually contained universal
+// characters. These should be in valid ranges (see the function
+// classify_universal_char above).
+//
+// If the string or character literal contains invalid or not allowed
+// universal characters a corresponding lexing_exception is thrown.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename StringT>
+inline void
+validate_literal (StringT const &name, int line, int column,
+ StringT const &file_name)
+{
+ using namespace std; // some systems have strtoul in namespace std::
+
+typename StringT::size_type pos = name.find_first_of('\\');
+
+ while (StringT::npos != pos) {
+ // the literal contains a backslash (may be universal char)
+ if ('u' == name[pos+1] || 'U' == name[pos+1]) {
+ StringT uchar_val(name.substr(pos+2, ('u' == name[pos+1]) ? 4 : 8));
+ universal_char_type type =
+ classify_universal_char(strtoul(uchar_val.c_str(), 0, 16));
+
+ if (universal_char_type_valid != type &&
+ universal_char_type_not_allowed_for_identifiers != type)
+ {
+ // an invalid char was found, so throw an exception
+ StringT error_uchar(name.substr(pos, ('u' == name[pos+1]) ? 6 : 10));
+
+ if (universal_char_type_invalid == type) {
+ BOOST_WAVE_LEXER_THROW(lexing_exception, universal_char_invalid,
+ error_uchar, line, column, file_name.c_str());
+ }
+ else {
+ BOOST_WAVE_LEXER_THROW(lexing_exception, universal_char_base_charset,
+ error_uchar, line, column, file_name.c_str());
+ }
+ }
+ }
+
+ // find next universal char (if appropriate)
+ pos = name.find_first_of('\\', pos+2);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace impl
+} // namespace cpplexer
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(VALIDATE_UNIVERSAL_CHAR_HPP_55F1B811_CD76_4C72_8344_CBC69CF3B339_INCLUDED)
diff --git a/boost/wave/grammars/cpp_chlit_grammar.hpp b/boost/wave/grammars/cpp_chlit_grammar.hpp
new file mode 100644
index 0000000000..c494f9f973
--- /dev/null
+++ b/boost/wave/grammars/cpp_chlit_grammar.hpp
@@ -0,0 +1,354 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_CHLIT_GRAMMAR_HPP_9527D349_6592_449A_A409_42A001E6C64C_INCLUDED)
+#define CPP_CHLIT_GRAMMAR_HPP_9527D349_6592_449A_A409_42A001E6C64C_INCLUDED
+
+#include <limits> // std::numeric_limits
+#include <climits> // CHAR_BIT
+
+#include <boost/wave/wave_config.hpp>
+
+#include <boost/static_assert.hpp>
+#include <boost/cstdint.hpp>
+
+#include <boost/spirit/include/classic_core.hpp>
+#include <boost/spirit/include/classic_closure.hpp>
+#include <boost/spirit/include/classic_if.hpp>
+#include <boost/spirit/include/classic_assign_actor.hpp>
+#include <boost/spirit/include/classic_push_back_actor.hpp>
+
+#include <boost/spirit/include/phoenix1_operators.hpp>
+#include <boost/spirit/include/phoenix1_primitives.hpp>
+#include <boost/spirit/include/phoenix1_statements.hpp>
+#include <boost/spirit/include/phoenix1_functions.hpp>
+
+#include <boost/wave/cpp_exceptions.hpp>
+#include <boost/wave/grammars/cpp_literal_grammar_gen.hpp>
+
+#if !defined(spirit_append_actor)
+#define spirit_append_actor(actor) boost::spirit::classic::push_back_a(actor)
+#define spirit_assign_actor(actor) boost::spirit::classic::assign_a(actor)
+#endif // !defined(spirit_append_actor)
+
+// this must occur after all of the includes and before any code appears
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_PREFIX
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Reusable grammar to parse a C++ style character literal
+//
+///////////////////////////////////////////////////////////////////////////////
+namespace boost {
+namespace wave {
+namespace grammars {
+
+namespace closures {
+
+ struct chlit_closure
+ : boost::spirit::classic::closure<chlit_closure, boost::uint32_t, bool>
+ {
+ member1 value;
+ member2 long_lit;
+ };
+}
+
+namespace impl {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// compose a multibyte character literal
+//
+///////////////////////////////////////////////////////////////////////////////
+ struct compose_character_literal {
+
+ template <typename A1, typename A2, typename A3, typename A4>
+ struct result
+ {
+ typedef void type;
+ };
+
+ void
+ operator()(boost::uint32_t& value, bool long_lit, bool& overflow,
+ boost::uint32_t character) const
+ {
+ // The following assumes that wchar_t is max. 32 Bit
+ BOOST_STATIC_ASSERT(sizeof(wchar_t) <= 4);
+
+ static boost::uint32_t masks[] = {
+ 0x000000ff, 0x0000ffff, 0x00ffffff, 0xffffffff
+ };
+ static boost::uint32_t overflow_masks[] = {
+ 0xff000000, 0xffff0000, 0xffffff00, 0xffffffff
+ };
+
+ if (long_lit) {
+ // make sure no overflow will occur below
+ if ((value & overflow_masks[sizeof(wchar_t)-1]) != 0) {
+ overflow |= true;
+ }
+ else {
+ // calculate the new value (avoiding a warning regarding
+ // shifting count >= size of the type)
+ value <<= CHAR_BIT * (sizeof(wchar_t)-1);
+ value <<= CHAR_BIT;
+ value |= character & masks[sizeof(wchar_t)-1];
+ }
+ }
+ else {
+ // make sure no overflow will occur below
+ if ((value & overflow_masks[sizeof(char)-1]) != 0) {
+ overflow |= true;
+ }
+ else {
+ // calculate the new value
+ value <<= CHAR_BIT * sizeof(char);
+ value |= character & masks[sizeof(char)-1];
+ }
+ }
+ }
+ };
+ phoenix::function<compose_character_literal> const compose;
+
+} // namespace impl
+
+///////////////////////////////////////////////////////////////////////////////
+// define, whether the rule's should generate some debug output
+#define TRACE_CHLIT_GRAMMAR \
+ bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_CHLIT_GRAMMAR) \
+ /**/
+
+struct chlit_grammar :
+ public boost::spirit::classic::grammar<chlit_grammar,
+ closures::chlit_closure::context_t>
+{
+ chlit_grammar()
+ : overflow(false)
+ {
+ BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "chlit_grammar",
+ TRACE_CHLIT_GRAMMAR);
+ }
+
+ // no need for copy constructor/assignment operator
+ chlit_grammar(chlit_grammar const&);
+ chlit_grammar& operator=(chlit_grammar const&);
+
+ template <typename ScannerT>
+ struct definition
+ {
+ typedef boost::spirit::classic::rule<
+ ScannerT, closures::chlit_closure::context_t>
+ rule_t;
+
+ rule_t ch_lit;
+
+ definition(chlit_grammar const &self)
+ {
+ using namespace boost::spirit::classic;
+ namespace phx = phoenix;
+
+ // special parsers for '\x..' and L'\x....'
+ typedef uint_parser<
+ unsigned int, 16, 1, 2 * sizeof(char)
+ > hex_char_parser_type;
+ typedef uint_parser<
+ unsigned int, 16, 1, 2 * sizeof(wchar_t)
+ > hex_wchar_parser_type;
+
+ // the rule for a character literal
+ ch_lit
+ = eps_p[self.value = phx::val(0), self.long_lit = phx::val(false)]
+ >> !ch_p('L')[self.long_lit = phx::val(true)]
+ >> ch_p('\'')
+ >> +( (
+ ch_p('\\')
+ >> ( ch_p('a') // BEL
+ [
+ impl::compose(self.value, self.long_lit,
+ phx::var(self.overflow), phx::val(0x07))
+ ]
+ | ch_p('b') // BS
+ [
+ impl::compose(self.value, self.long_lit,
+ phx::var(self.overflow), phx::val(0x08))
+ ]
+ | ch_p('t') // HT
+ [
+ impl::compose(self.value, self.long_lit,
+ phx::var(self.overflow), phx::val(0x09))
+ ]
+ | ch_p('n') // NL
+ [
+ impl::compose(self.value, self.long_lit,
+ phx::var(self.overflow), phx::val(0x0a))
+ ]
+ | ch_p('v') // VT
+ [
+ impl::compose(self.value, self.long_lit,
+ phx::var(self.overflow), phx::val(0x0b))
+ ]
+ | ch_p('f') // FF
+ [
+ impl::compose(self.value, self.long_lit,
+ phx::var(self.overflow), phx::val(0x0c))
+ ]
+ | ch_p('r') // CR
+ [
+ impl::compose(self.value, self.long_lit,
+ phx::var(self.overflow), phx::val(0x0d))
+ ]
+ | ch_p('?')
+ [
+ impl::compose(self.value, self.long_lit,
+ phx::var(self.overflow), phx::val('?'))
+ ]
+ | ch_p('\'')
+ [
+ impl::compose(self.value, self.long_lit,
+ phx::var(self.overflow), phx::val('\''))
+ ]
+ | ch_p('\"')
+ [
+ impl::compose(self.value, self.long_lit,
+ phx::var(self.overflow), phx::val('\"'))
+ ]
+ | ch_p('\\')
+ [
+ impl::compose(self.value, self.long_lit,
+ phx::var(self.overflow), phx::val('\\'))
+ ]
+ | ch_p('x')
+ >> if_p(self.long_lit)
+ [
+ hex_wchar_parser_type()
+ [
+ impl::compose(self.value, self.long_lit,
+ phx::var(self.overflow), phx::arg1)
+ ]
+ ]
+ .else_p
+ [
+ hex_char_parser_type()
+ [
+ impl::compose(self.value, self.long_lit,
+ phx::var(self.overflow), phx::arg1)
+ ]
+ ]
+ | ch_p('u')
+ >> uint_parser<unsigned int, 16, 4, 4>()
+ [
+ impl::compose(self.value, self.long_lit,
+ phx::var(self.overflow), phx::arg1)
+ ]
+ | ch_p('U')
+ >> uint_parser<unsigned int, 16, 8, 8>()
+ [
+ impl::compose(self.value, self.long_lit,
+ phx::var(self.overflow), phx::arg1)
+ ]
+ | uint_parser<unsigned int, 8, 1, 3>()
+ [
+ impl::compose(self.value, self.long_lit,
+ phx::var(self.overflow), phx::arg1)
+ ]
+ )
+ )
+ | ~eps_p(ch_p('\'')) >> anychar_p
+ [
+ impl::compose(self.value, self.long_lit,
+ phx::var(self.overflow), phx::arg1)
+ ]
+ )
+ >> ch_p('\'')
+ ;
+
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(ch_lit, TRACE_CHLIT_GRAMMAR);
+ }
+
+ // start rule of this grammar
+ rule_t const& start() const
+ { return ch_lit; }
+ };
+
+ // flag signaling integer overflow during value composition
+ mutable bool overflow;
+};
+
+#undef TRACE_CHLIT_GRAMMAR
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// The following function is defined here, to allow the separation of
+// the compilation of the intlit_grammap from the function using it.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0
+#define BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE
+#else
+#define BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE inline
+#endif
+
+template <typename IntegralResult, typename TokenT>
+BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE
+IntegralResult
+chlit_grammar_gen<IntegralResult, TokenT>::evaluate(TokenT const &token, value_error &status)
+{
+ using namespace boost::spirit::classic;
+
+chlit_grammar g;
+IntegralResult result = 0;
+typename TokenT::string_type const &token_val = token.get_value();
+parse_info<typename TokenT::string_type::const_iterator> hit =
+ parse(token_val.begin(), token_val.end(), g[spirit_assign_actor(result)]);
+
+ if (!hit.hit) {
+ BOOST_WAVE_THROW(preprocess_exception, ill_formed_character_literal,
+ token_val.c_str(), token.get_position());
+ }
+ else {
+ // range check
+ if ('L' == token_val[0]) {
+ // recognized wide character
+ if (g.overflow ||
+ result > (IntegralResult)(std::numeric_limits<wchar_t>::max)())
+ {
+ // out of range
+ status = error_character_overflow;
+ }
+ }
+ else {
+ // recognized narrow ('normal') character
+ if (g.overflow ||
+ result > (IntegralResult)(std::numeric_limits<unsigned char>::max)())
+ {
+ // out of range
+ status = error_character_overflow;
+ }
+ }
+ }
+ return result;
+}
+
+#undef BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace grammars
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_CHLIT_GRAMMAR_HPP_9527D349_6592_449A_A409_42A001E6C64C_INCLUDED)
diff --git a/boost/wave/grammars/cpp_defined_grammar.hpp b/boost/wave/grammars/cpp_defined_grammar.hpp
new file mode 100644
index 0000000000..d6d3422fe8
--- /dev/null
+++ b/boost/wave/grammars/cpp_defined_grammar.hpp
@@ -0,0 +1,185 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_DEFINED_GRAMMAR_HPP_F48287B2_DC67_40A8_B4A1_800EFBD67869_INCLUDED)
+#define CPP_DEFINED_GRAMMAR_HPP_F48287B2_DC67_40A8_B4A1_800EFBD67869_INCLUDED
+
+#include <boost/wave/wave_config.hpp>
+
+#include <boost/assert.hpp>
+#include <boost/spirit/include/classic_core.hpp>
+#include <boost/spirit/include/classic_closure.hpp>
+#include <boost/spirit/include/classic_assign_actor.hpp>
+#include <boost/spirit/include/classic_push_back_actor.hpp>
+
+#include <boost/wave/token_ids.hpp>
+#include <boost/wave/util/pattern_parser.hpp>
+#include <boost/wave/grammars/cpp_defined_grammar_gen.hpp>
+
+#if !defined(spirit_append_actor)
+#define spirit_append_actor(actor) boost::spirit::classic::push_back_a(actor)
+#define spirit_assign_actor(actor) boost::spirit::classic::assign_a(actor)
+#endif // !defined(spirit_append_actor)
+
+// 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 {
+namespace grammars {
+
+///////////////////////////////////////////////////////////////////////////////
+// define, whether the rule's should generate some debug output
+#define TRACE_CPP_DEFINED_GRAMMAR \
+ bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_DEFINED_GRAMMAR) \
+ /**/
+
+template <typename ContainerT>
+struct defined_grammar :
+ public boost::spirit::classic::grammar<defined_grammar<ContainerT> >
+{
+ defined_grammar(ContainerT &result_seq_)
+ : result_seq(result_seq_)
+ {
+ BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "defined_grammar",
+ TRACE_CPP_DEFINED_GRAMMAR);
+ }
+
+ template <typename ScannerT>
+ struct definition
+ {
+ typedef boost::spirit::classic::rule<ScannerT> rule_t;
+
+ rule_t defined_op;
+ rule_t identifier;
+
+ definition(defined_grammar const &self)
+ {
+ using namespace boost::spirit::classic;
+ using namespace boost::wave;
+ using namespace boost::wave::util;
+
+ defined_op // parens not required, see C++ standard 16.1.1
+ = ch_p(T_IDENTIFIER) // token contains 'defined'
+ >> (
+ ( ch_p(T_LEFTPAREN)
+ >> identifier
+ >> ch_p(T_RIGHTPAREN)
+ )
+ | identifier
+ )
+ ;
+
+ identifier
+ = ch_p(T_IDENTIFIER)
+ [
+ spirit_append_actor(self.result_seq)
+ ]
+ | pattern_p(KeywordTokenType, TokenTypeMask|PPTokenFlag)
+ [
+ spirit_append_actor(self.result_seq)
+ ]
+ | pattern_p(OperatorTokenType|AltExtTokenType,
+ ExtTokenTypeMask|PPTokenFlag)
+ [
+ spirit_append_actor(self.result_seq)
+ ]
+ | pattern_p(BoolLiteralTokenType, TokenTypeMask|PPTokenFlag)
+ [
+ spirit_append_actor(self.result_seq)
+ ]
+ ;
+
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(defined_op, TRACE_CPP_DEFINED_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(identifier, TRACE_CPP_DEFINED_GRAMMAR);
+ }
+
+ // start rule of this grammar
+ rule_t const& start() const
+ { return defined_op; }
+ };
+
+ ContainerT &result_seq;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+#undef TRACE_CPP_DEFINED_GRAMMAR
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// The following parse function is defined here, to allow the separation of
+// the compilation of the defined_grammar from the function
+// using it.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0
+#define BOOST_WAVE_DEFINED_GRAMMAR_GEN_INLINE
+#else
+#define BOOST_WAVE_DEFINED_GRAMMAR_GEN_INLINE inline
+#endif
+
+// The parse_operator_define function is instantiated manually twice to
+// simplify the explicit specialization of this template. This way the user
+// has only to specify one template parameter (the lexer type) to correctly
+// formulate the required explicit specialization.
+// This results in no code overhead, because otherwise the function would be
+// generated by the compiler twice anyway.
+
+template <typename LexIteratorT>
+BOOST_WAVE_DEFINED_GRAMMAR_GEN_INLINE
+boost::spirit::classic::parse_info<
+ typename defined_grammar_gen<LexIteratorT>::iterator1_type
+>
+defined_grammar_gen<LexIteratorT>::parse_operator_defined (
+ iterator1_type const &first, iterator1_type const &last,
+ token_sequence_type &found_qualified_name)
+{
+ using namespace boost::spirit::classic;
+ using namespace boost::wave;
+
+ defined_grammar<token_sequence_type> g(found_qualified_name);
+ return boost::spirit::classic::parse (
+ first, last, g, ch_p(T_SPACE) | ch_p(T_CCOMMENT));
+}
+
+template <typename LexIteratorT>
+BOOST_WAVE_DEFINED_GRAMMAR_GEN_INLINE
+boost::spirit::classic::parse_info<
+ typename defined_grammar_gen<LexIteratorT>::iterator2_type
+>
+defined_grammar_gen<LexIteratorT>::parse_operator_defined (
+ iterator2_type const &first, iterator2_type const &last,
+ token_sequence_type &found_qualified_name)
+{
+ using namespace boost::spirit::classic;
+ using namespace boost::wave;
+
+ defined_grammar<token_sequence_type> g(found_qualified_name);
+ return boost::spirit::classic::parse (
+ first, last, g, ch_p(T_SPACE) | ch_p(T_CCOMMENT));
+}
+
+#undef BOOST_WAVE_DEFINED_GRAMMAR_GEN_INLINE
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace grammars
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_DEFINED_GRAMMAR_HPP_F48287B2_DC67_40A8_B4A1_800EFBD67869_INCLUDED)
diff --git a/boost/wave/grammars/cpp_defined_grammar_gen.hpp b/boost/wave/grammars/cpp_defined_grammar_gen.hpp
new file mode 100644
index 0000000000..3da519e917
--- /dev/null
+++ b/boost/wave/grammars/cpp_defined_grammar_gen.hpp
@@ -0,0 +1,85 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_DEFINED_GRAMMAR_GEN_HPP_825BE9F5_98A3_400D_A97C_AD76B3B08632_INCLUDED)
+#define CPP_DEFINED_GRAMMAR_GEN_HPP_825BE9F5_98A3_400D_A97C_AD76B3B08632_INCLUDED
+
+#include <boost/wave/wave_config.hpp>
+
+#include <list>
+
+#include <boost/spirit/include/classic_parser.hpp>
+#include <boost/pool/pool_alloc.hpp>
+
+#include <boost/wave/util/unput_queue_iterator.hpp>
+
+// this must occur after all of the includes and before any code appears
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_PREFIX
+#endif
+
+// suppress warnings about dependent classes not being exported from the dll
+#ifdef BOOST_MSVC
+#pragma warning(push)
+#pragma warning(disable : 4251 4231 4660)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+namespace boost {
+namespace wave {
+namespace grammars {
+
+template <typename LexIteratorT>
+struct BOOST_WAVE_DECL defined_grammar_gen
+{
+ typedef typename LexIteratorT::token_type token_type;
+ typedef std::list<token_type, boost::fast_pool_allocator<token_type> >
+ token_sequence_type;
+
+// The parse_operator_defined function is instantiated manually twice to
+// simplify the explicit specialization of this template. This way the user
+// has only to specify one template parameter (the lexer iterator type) to
+// correctly formulate the required explicit specialization.
+// This results in no code overhead, because otherwise the function would be
+// generated by the compiler twice anyway.
+
+ typedef boost::wave::util::unput_queue_iterator<
+ typename token_sequence_type::iterator, token_type, token_sequence_type>
+ iterator1_type;
+
+ typedef boost::wave::util::unput_queue_iterator<
+ LexIteratorT, token_type, token_sequence_type>
+ iterator2_type;
+
+// parse the operator defined and return the found qualified name
+ static boost::spirit::classic::parse_info<iterator1_type>
+ parse_operator_defined (iterator1_type const &first,
+ iterator1_type const &last, token_sequence_type &found_qualified_name);
+
+ static boost::spirit::classic::parse_info<iterator2_type>
+ parse_operator_defined (iterator2_type const &first,
+ iterator2_type const &last, token_sequence_type &found_qualified_name);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace grammars
+} // namespace wave
+} // namespace boost
+
+#ifdef BOOST_MSVC
+#pragma warning(pop)
+#endif
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_DEFINED_GRAMMAR_GEN_HPP_825BE9F5_98A3_400D_A97C_AD76B3B08632_INCLUDED)
diff --git a/boost/wave/grammars/cpp_expression_grammar.hpp b/boost/wave/grammars/cpp_expression_grammar.hpp
new file mode 100644
index 0000000000..a52d36a5c8
--- /dev/null
+++ b/boost/wave/grammars/cpp_expression_grammar.hpp
@@ -0,0 +1,870 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_EXPRESSION_GRAMMAR_HPP_099CD1A4_A6C0_44BE_8F24_0B00F5BE5674_INCLUDED)
+#define CPP_EXPRESSION_GRAMMAR_HPP_099CD1A4_A6C0_44BE_8F24_0B00F5BE5674_INCLUDED
+
+#include <boost/wave/wave_config.hpp>
+
+#include <boost/assert.hpp>
+#include <boost/spirit/include/classic_core.hpp>
+#include <boost/spirit/include/classic_closure.hpp>
+#include <boost/spirit/include/classic_if.hpp>
+#include <boost/spirit/include/classic_assign_actor.hpp>
+#include <boost/spirit/include/classic_push_back_actor.hpp>
+
+#include <boost/spirit/include/phoenix1_functions.hpp>
+#include <boost/spirit/include/phoenix1_operators.hpp>
+#include <boost/spirit/include/phoenix1_primitives.hpp>
+#include <boost/spirit/include/phoenix1_statements.hpp>
+#include <boost/spirit/include/phoenix1_casts.hpp>
+
+#include <boost/wave/token_ids.hpp>
+
+#include <boost/wave/cpp_exceptions.hpp>
+#include <boost/wave/grammars/cpp_expression_grammar_gen.hpp>
+#include <boost/wave/grammars/cpp_literal_grammar_gen.hpp>
+#include <boost/wave/grammars/cpp_expression_value.hpp>
+#include <boost/wave/util/pattern_parser.hpp>
+#include <boost/wave/util/macro_helpers.hpp>
+
+#if !defined(spirit_append_actor)
+#define spirit_append_actor(actor) boost::spirit::classic::push_back_a(actor)
+#define spirit_assign_actor(actor) boost::spirit::classic::assign_a(actor)
+#endif // !defined(spirit_append_actor)
+
+// this must occur after all of the includes and before any code appears
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_PREFIX
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Encapsulation of the grammar for evaluation of constant preprocessor
+// expressions
+//
+///////////////////////////////////////////////////////////////////////////////
+namespace boost {
+namespace wave {
+namespace grammars {
+namespace closures {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// define the closure type used throughout the C++ expression grammar
+//
+// Throughout this grammar all literal tokens are stored into a
+// closure_value variables, which converts the types appropriately, where
+// required.
+//
+///////////////////////////////////////////////////////////////////////////////
+ struct cpp_expr_closure
+ : boost::spirit::classic::closure<cpp_expr_closure, closure_value>
+ {
+ member1 val;
+ };
+
+} // namespace closures
+
+namespace impl {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// convert the given token value (integer literal) to a unsigned long
+//
+///////////////////////////////////////////////////////////////////////////////
+ struct convert_intlit {
+
+ template <typename ArgT>
+ struct result {
+
+ typedef boost::wave::grammars::closures::closure_value type;
+ };
+
+ template <typename TokenT>
+ boost::wave::grammars::closures::closure_value
+ operator()(TokenT const &token) const
+ {
+ typedef boost::wave::grammars::closures::closure_value return_type;
+ bool is_unsigned = false;
+ uint_literal_type ul = intlit_grammar_gen<TokenT>::evaluate(token,
+ is_unsigned);
+
+ return is_unsigned ?
+ return_type(ul) : return_type(static_cast<int_literal_type>(ul));
+ }
+ };
+ phoenix::function<convert_intlit> const as_intlit;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Convert the given token value (character literal) to a unsigned int
+//
+///////////////////////////////////////////////////////////////////////////////
+ struct convert_chlit {
+
+ template <typename ArgT>
+ struct result {
+
+ typedef boost::wave::grammars::closures::closure_value type;
+ };
+
+ template <typename TokenT>
+ boost::wave::grammars::closures::closure_value
+ operator()(TokenT const &token) const
+ {
+ typedef boost::wave::grammars::closures::closure_value return_type;
+ value_error status = error_noerror;
+
+ // If the literal is a wchar_t and wchar_t is represented by a
+ // signed integral type, then the created value will be signed as
+ // well, otherwise we assume unsigned values.
+#if BOOST_WAVE_WCHAR_T_SIGNEDNESS == BOOST_WAVE_WCHAR_T_AUTOSELECT
+ if ('L' == token.get_value()[0] && std::numeric_limits<wchar_t>::is_signed)
+ {
+ int value = chlit_grammar_gen<int, TokenT>::evaluate(token, status);
+ return return_type(value, status);
+ }
+#elif BOOST_WAVE_WCHAR_T_SIGNEDNESS == BOOST_WAVE_WCHAR_T_FORCE_SIGNED
+ if ('L' == token.get_value()[0])
+ {
+ int value = chlit_grammar_gen<int, TokenT>::evaluate(token, status);
+ return return_type(value, status);
+ }
+#endif
+
+ unsigned int value = chlit_grammar_gen<unsigned int, TokenT>::evaluate(token, status);
+ return return_type(value, status);
+ }
+ };
+ phoenix::function<convert_chlit> const as_chlit;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Handle the ?: operator with correct type and error propagation
+//
+////////////////////////////////////////////////////////////////////////////////
+ struct operator_questionmark {
+
+ template <typename CondT, typename Arg1T, typename Arg2T>
+ struct result {
+
+ typedef boost::wave::grammars::closures::closure_value type;
+ };
+
+ template <typename CondT, typename Arg1T, typename Arg2T>
+ boost::wave::grammars::closures::closure_value
+ operator()(CondT const &cond, Arg1T &val1, Arg2T const &val2) const
+ {
+ return val1.handle_questionmark(cond, val2);
+ }
+ };
+ phoenix::function<operator_questionmark> const questionmark;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Handle type conversion conserving error conditions
+//
+///////////////////////////////////////////////////////////////////////////////
+ struct operator_to_bool {
+
+ template <typename ArgT>
+ struct result {
+
+ typedef boost::wave::grammars::closures::closure_value type;
+ };
+
+ template <typename ArgT>
+ boost::wave::grammars::closures::closure_value
+ operator()(ArgT &val) const
+ {
+ typedef boost::wave::grammars::closures::closure_value return_type;
+ return return_type(
+ boost::wave::grammars::closures::as_bool(val), val.is_valid());
+ }
+ };
+ phoenix::function<operator_to_bool> const to_bool;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Handle explicit type conversion
+//
+///////////////////////////////////////////////////////////////////////////////
+ struct operator_as_bool {
+
+ template <typename ArgT>
+ struct result {
+
+ typedef bool type;
+ };
+
+ template <typename ArgT>
+ bool
+ operator()(ArgT &val) const
+ {
+ return boost::wave::grammars::closures::as_bool(val);
+ }
+ };
+ phoenix::function<operator_as_bool> const as_bool;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Handle closure value operators with proper error propagation
+//
+///////////////////////////////////////////////////////////////////////////////
+#define BOOST_WAVE_BINARYOP(op, optok) \
+ struct operator_binary_ ## op { \
+ \
+ template <typename Arg1T, typename Arg2T> \
+ struct result { \
+ \
+ typedef boost::wave::grammars::closures::closure_value type; \
+ }; \
+ \
+ template <typename Arg1T, typename Arg2T> \
+ boost::wave::grammars::closures::closure_value \
+ operator()(Arg1T &val1, Arg2T &val2) const \
+ { \
+ return val1 optok val2; \
+ } \
+ }; \
+ phoenix::function<operator_binary_ ## op> const binary_ ## op \
+ /**/
+
+ BOOST_WAVE_BINARYOP(and, &&);
+ BOOST_WAVE_BINARYOP(or, ||);
+
+ BOOST_WAVE_BINARYOP(bitand, &);
+ BOOST_WAVE_BINARYOP(bitor, |);
+ BOOST_WAVE_BINARYOP(bitxor, ^);
+
+ BOOST_WAVE_BINARYOP(lesseq, <=);
+ BOOST_WAVE_BINARYOP(less, <);
+ BOOST_WAVE_BINARYOP(greater, >);
+ BOOST_WAVE_BINARYOP(greateq, >=);
+ BOOST_WAVE_BINARYOP(eq, ==);
+ BOOST_WAVE_BINARYOP(ne, !=);
+
+#undef BOOST_WAVE_BINARYOP
+
+///////////////////////////////////////////////////////////////////////////////
+#define BOOST_WAVE_UNARYOP(op, optok) \
+ struct operator_unary_ ## op { \
+ \
+ template <typename ArgT> \
+ struct result { \
+ \
+ typedef boost::wave::grammars::closures::closure_value type; \
+ }; \
+ \
+ template <typename ArgT> \
+ boost::wave::grammars::closures::closure_value \
+ operator()(ArgT &val) const \
+ { \
+ return optok val; \
+ } \
+ }; \
+ phoenix::function<operator_unary_ ## op> const unary_ ## op \
+ /**/
+
+ BOOST_WAVE_UNARYOP(neg, !);
+
+#undef BOOST_WAVE_UNARYOP
+
+} // namespace impl
+
+///////////////////////////////////////////////////////////////////////////////
+// define, whether the rule's should generate some debug output
+#define TRACE_CPP_EXPR_GRAMMAR \
+ bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_CPP_EXPR_GRAMMAR) \
+ /**/
+
+struct expression_grammar :
+ public boost::spirit::classic::grammar<
+ expression_grammar,
+ closures::cpp_expr_closure::context_t
+ >
+{
+ expression_grammar()
+ {
+ BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "expression_grammar",
+ TRACE_CPP_EXPR_GRAMMAR);
+ }
+
+ // no need for copy constructor/assignment operator
+ expression_grammar(expression_grammar const&);
+ expression_grammar& operator= (expression_grammar const&);
+
+ template <typename ScannerT>
+ struct definition
+ {
+ typedef closures::cpp_expr_closure closure_type;
+ typedef boost::spirit::classic::rule<ScannerT, closure_type::context_t> rule_t;
+ typedef boost::spirit::classic::rule<ScannerT> simple_rule_t;
+
+ simple_rule_t pp_expression;
+
+ rule_t const_exp;
+ rule_t logical_or_exp, logical_and_exp;
+ rule_t inclusive_or_exp, exclusive_or_exp, and_exp;
+ rule_t cmp_equality, cmp_relational;
+ rule_t shift_exp;
+ rule_t add_exp, multiply_exp;
+ rule_t unary_exp, primary_exp, constant;
+
+ rule_t const_exp_nocalc;
+ rule_t logical_or_exp_nocalc, logical_and_exp_nocalc;
+ rule_t inclusive_or_exp_nocalc, exclusive_or_exp_nocalc, and_exp_nocalc;
+ rule_t cmp_equality_nocalc, cmp_relational_nocalc;
+ rule_t shift_exp_nocalc;
+ rule_t add_exp_nocalc, multiply_exp_nocalc;
+ rule_t unary_exp_nocalc, primary_exp_nocalc, constant_nocalc;
+
+ boost::spirit::classic::subrule<0, closure_type::context_t> const_exp_subrule;
+
+ definition(expression_grammar const &self)
+ {
+ using namespace boost::spirit::classic;
+ using namespace phoenix;
+ using namespace boost::wave;
+ using boost::wave::util::pattern_p;
+
+ pp_expression
+ = const_exp[self.val = arg1]
+ ;
+
+ const_exp
+ = logical_or_exp[const_exp.val = arg1]
+ >> !(const_exp_subrule =
+ ch_p(T_QUESTION_MARK)
+ >> const_exp
+ [
+ const_exp_subrule.val = arg1
+ ]
+ >> ch_p(T_COLON)
+ >> const_exp
+ [
+ const_exp_subrule.val =
+ impl::questionmark(const_exp.val,
+ const_exp_subrule.val, arg1)
+ ]
+ )[const_exp.val = arg1]
+ ;
+
+ logical_or_exp
+ = logical_and_exp[logical_or_exp.val = arg1]
+ >> *( if_p(impl::as_bool(logical_or_exp.val))
+ [
+ // if one of the || operators is true, no more
+ // evaluation is required
+ pattern_p(T_OROR, MainTokenMask)
+ >> logical_and_exp_nocalc
+ [
+ logical_or_exp.val =
+ impl::to_bool(logical_or_exp.val)
+ ]
+ ]
+ .else_p
+ [
+ pattern_p(T_OROR, MainTokenMask)
+ >> logical_and_exp
+ [
+ logical_or_exp.val =
+ impl::binary_or(logical_or_exp.val, arg1)
+ ]
+ ]
+ )
+ ;
+
+ logical_and_exp
+ = inclusive_or_exp[logical_and_exp.val = arg1]
+ >> *( if_p(impl::as_bool(logical_and_exp.val))
+ [
+ pattern_p(T_ANDAND, MainTokenMask)
+ >> inclusive_or_exp
+ [
+ logical_and_exp.val =
+ impl::binary_and(logical_and_exp.val, arg1)
+ ]
+ ]
+ .else_p
+ [
+ // if one of the && operators is false, no more
+ // evaluation is required
+ pattern_p(T_ANDAND, MainTokenMask)
+ >> inclusive_or_exp_nocalc
+ [
+ logical_and_exp.val =
+ impl::to_bool(logical_and_exp.val)
+ ]
+ ]
+ )
+ ;
+
+ inclusive_or_exp
+ = exclusive_or_exp[inclusive_or_exp.val = arg1]
+ >> *( pattern_p(T_OR, MainTokenMask)
+ >> exclusive_or_exp
+ [
+ inclusive_or_exp.val =
+ impl::binary_bitor(inclusive_or_exp.val, arg1)
+ ]
+ )
+ ;
+
+ exclusive_or_exp
+ = and_exp[exclusive_or_exp.val = arg1]
+ >> *( pattern_p(T_XOR, MainTokenMask)
+ >> and_exp
+ [
+ exclusive_or_exp.val =
+ impl::binary_bitxor(exclusive_or_exp.val, arg1)
+ ]
+ )
+ ;
+
+ and_exp
+ = cmp_equality[and_exp.val = arg1]
+ >> *( pattern_p(T_AND, MainTokenMask)
+ >> cmp_equality
+ [
+ and_exp.val =
+ impl::binary_bitand(and_exp.val, arg1)
+ ]
+ )
+ ;
+
+ cmp_equality
+ = cmp_relational[cmp_equality.val = arg1]
+ >> *( ch_p(T_EQUAL)
+ >> cmp_relational
+ [
+ cmp_equality.val =
+ impl::binary_eq(cmp_equality.val, arg1)
+ ]
+ | pattern_p(T_NOTEQUAL, MainTokenMask)
+ >> cmp_relational
+ [
+ cmp_equality.val =
+ impl::binary_ne(cmp_equality.val, arg1)
+ ]
+ )
+ ;
+
+ cmp_relational
+ = shift_exp[cmp_relational.val = arg1]
+ >> *( ch_p(T_LESSEQUAL)
+ >> shift_exp
+ [
+ cmp_relational.val =
+ impl::binary_lesseq(cmp_relational.val, arg1)
+ ]
+ | ch_p(T_GREATEREQUAL)
+ >> shift_exp
+ [
+ cmp_relational.val =
+ impl::binary_greateq(cmp_relational.val, arg1)
+ ]
+ | ch_p(T_LESS)
+ >> shift_exp
+ [
+ cmp_relational.val =
+ impl::binary_less(cmp_relational.val, arg1)
+ ]
+ | ch_p(T_GREATER)
+ >> shift_exp
+ [
+ cmp_relational.val =
+ impl::binary_greater(cmp_relational.val, arg1)
+ ]
+ )
+ ;
+
+ shift_exp
+ = add_exp[shift_exp.val = arg1]
+ >> *( ch_p(T_SHIFTLEFT)
+ >> add_exp
+ [
+ shift_exp.val <<= arg1
+ ]
+ | ch_p(T_SHIFTRIGHT)
+ >> add_exp
+ [
+ shift_exp.val >>= arg1
+ ]
+ )
+ ;
+
+ add_exp
+ = multiply_exp[add_exp.val = arg1]
+ >> *( ch_p(T_PLUS)
+ >> multiply_exp
+ [
+ add_exp.val += arg1
+ ]
+ | ch_p(T_MINUS)
+ >> multiply_exp
+ [
+ add_exp.val -= arg1
+ ]
+ )
+ ;
+
+ multiply_exp
+ = unary_exp[multiply_exp.val = arg1]
+ >> *( ch_p(T_STAR)
+ >> unary_exp
+ [
+ multiply_exp.val *= arg1
+ ]
+ | ch_p(T_DIVIDE)
+ >> unary_exp
+ [
+ multiply_exp.val /= arg1
+ ]
+ | ch_p(T_PERCENT)
+ >> unary_exp
+ [
+ multiply_exp.val %= arg1
+ ]
+ )
+ ;
+
+ unary_exp
+ = primary_exp[unary_exp.val = arg1]
+ | ch_p(T_PLUS) >> unary_exp
+ [
+ unary_exp.val = arg1
+ ]
+ | ch_p(T_MINUS) >> unary_exp
+ [
+ unary_exp.val = -arg1
+ ]
+ | pattern_p(T_COMPL, MainTokenMask) >> unary_exp
+ [
+ unary_exp.val = ~arg1
+ ]
+ | pattern_p(T_NOT, MainTokenMask) >> unary_exp
+ [
+ unary_exp.val = impl::unary_neg(arg1)
+ ]
+ ;
+
+ primary_exp
+ = constant[primary_exp.val = arg1]
+ | ch_p(T_LEFTPAREN)
+ >> const_exp[primary_exp.val = arg1]
+ >> ch_p(T_RIGHTPAREN)
+ ;
+
+ constant
+ = ch_p(T_PP_NUMBER)
+ [
+ constant.val = impl::as_intlit(arg1)
+ ]
+ | ch_p(T_INTLIT)
+ [
+ constant.val = impl::as_intlit(arg1)
+ ]
+ | ch_p(T_CHARLIT)
+ [
+ constant.val = impl::as_chlit(arg1)
+ ]
+ ;
+
+ // here follows the same grammar, but without any embedded
+ // calculations
+ const_exp_nocalc
+ = logical_or_exp_nocalc
+ >> !( ch_p(T_QUESTION_MARK)
+ >> const_exp_nocalc
+ >> ch_p(T_COLON)
+ >> const_exp_nocalc
+ )
+ ;
+
+ logical_or_exp_nocalc
+ = logical_and_exp_nocalc
+ >> *( pattern_p(T_OROR, MainTokenMask)
+ >> logical_and_exp_nocalc
+ )
+ ;
+
+ logical_and_exp_nocalc
+ = inclusive_or_exp_nocalc
+ >> *( pattern_p(T_ANDAND, MainTokenMask)
+ >> inclusive_or_exp_nocalc
+ )
+ ;
+
+ inclusive_or_exp_nocalc
+ = exclusive_or_exp_nocalc
+ >> *( pattern_p(T_OR, MainTokenMask)
+ >> exclusive_or_exp_nocalc
+ )
+ ;
+
+ exclusive_or_exp_nocalc
+ = and_exp_nocalc
+ >> *( pattern_p(T_XOR, MainTokenMask)
+ >> and_exp_nocalc
+ )
+ ;
+
+ and_exp_nocalc
+ = cmp_equality_nocalc
+ >> *( pattern_p(T_AND, MainTokenMask)
+ >> cmp_equality_nocalc
+ )
+ ;
+
+ cmp_equality_nocalc
+ = cmp_relational_nocalc
+ >> *( ch_p(T_EQUAL)
+ >> cmp_relational_nocalc
+ | pattern_p(T_NOTEQUAL, MainTokenMask)
+ >> cmp_relational_nocalc
+ )
+ ;
+
+ cmp_relational_nocalc
+ = shift_exp_nocalc
+ >> *( ch_p(T_LESSEQUAL)
+ >> shift_exp_nocalc
+ | ch_p(T_GREATEREQUAL)
+ >> shift_exp_nocalc
+ | ch_p(T_LESS)
+ >> shift_exp_nocalc
+ | ch_p(T_GREATER)
+ >> shift_exp_nocalc
+ )
+ ;
+
+ shift_exp_nocalc
+ = add_exp_nocalc
+ >> *( ch_p(T_SHIFTLEFT)
+ >> add_exp_nocalc
+ | ch_p(T_SHIFTRIGHT)
+ >> add_exp_nocalc
+ )
+ ;
+
+ add_exp_nocalc
+ = multiply_exp_nocalc
+ >> *( ch_p(T_PLUS)
+ >> multiply_exp_nocalc
+ | ch_p(T_MINUS)
+ >> multiply_exp_nocalc
+ )
+ ;
+
+ multiply_exp_nocalc
+ = unary_exp_nocalc
+ >> *( ch_p(T_STAR)
+ >> unary_exp_nocalc
+ | ch_p(T_DIVIDE)
+ >> unary_exp_nocalc
+ | ch_p(T_PERCENT)
+ >> unary_exp_nocalc
+ )
+ ;
+
+ unary_exp_nocalc
+ = primary_exp_nocalc
+ | ch_p(T_PLUS) >> unary_exp_nocalc
+ | ch_p(T_MINUS) >> unary_exp_nocalc
+ | pattern_p(T_COMPL, MainTokenMask) >> unary_exp_nocalc
+ | pattern_p(T_NOT, MainTokenMask) >> unary_exp_nocalc
+ ;
+
+ primary_exp_nocalc
+ = constant_nocalc
+ | ch_p(T_LEFTPAREN)
+ >> const_exp_nocalc
+ >> ch_p(T_RIGHTPAREN)
+ ;
+
+ constant_nocalc
+ = ch_p(T_PP_NUMBER)
+ | ch_p(T_INTLIT)
+ | ch_p(T_CHARLIT)
+ ;
+
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(pp_expression, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(const_exp, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(logical_or_exp, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(logical_and_exp, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(inclusive_or_exp, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(exclusive_or_exp, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(and_exp, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(cmp_equality, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(cmp_relational, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(shift_exp, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(add_exp, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(multiply_exp, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(unary_exp, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(primary_exp, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(constant, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(const_exp_subrule, TRACE_CPP_EXPR_GRAMMAR);
+
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(const_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(logical_or_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(logical_and_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(inclusive_or_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(exclusive_or_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(and_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(cmp_equality_nocalc, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(cmp_relational_nocalc, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(shift_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(add_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(multiply_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(unary_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(primary_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(constant_nocalc, TRACE_CPP_EXPR_GRAMMAR);
+ }
+
+ // start rule of this grammar
+ simple_rule_t const& start() const
+ { return pp_expression; }
+ };
+};
+
+///////////////////////////////////////////////////////////////////////////////
+#undef TRACE_CPP_EXPR_GRAMMAR
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// The following function is defined here, to allow the separation of
+// the compilation of the expression_grammar from the function using it.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0
+#define BOOST_WAVE_EXPRGRAMMAR_GEN_INLINE
+#else
+#define BOOST_WAVE_EXPRGRAMMAR_GEN_INLINE inline
+#endif
+
+template <typename TokenT>
+BOOST_WAVE_EXPRGRAMMAR_GEN_INLINE
+bool
+expression_grammar_gen<TokenT>::evaluate(
+ typename token_sequence_type::const_iterator const &first,
+ typename token_sequence_type::const_iterator const &last,
+ typename token_type::position_type const &act_pos,
+ bool if_block_status, value_error &status)
+{
+ using namespace boost::spirit::classic;
+ using namespace boost::wave;
+ using namespace boost::wave::grammars::closures;
+
+ using boost::wave::util::impl::as_string;
+
+ typedef typename token_sequence_type::const_iterator iterator_type;
+ typedef typename token_sequence_type::value_type::string_type string_type;
+
+ parse_info<iterator_type> hit(first);
+ closure_value result; // expression result
+
+#if !defined(BOOST_NO_EXCEPTIONS)
+ try
+#endif
+ {
+ expression_grammar g; // expression grammar
+ hit = parse (first, last, g[spirit_assign_actor(result)],
+ ch_p(T_SPACE) | ch_p(T_CCOMMENT) | ch_p(T_CPPCOMMENT));
+
+ if (!hit.hit) {
+ // expression is illformed
+ if (if_block_status) {
+ string_type expression = as_string<string_type>(first, last);
+ if (0 == expression.size())
+ expression = "<empty expression>";
+ BOOST_WAVE_THROW(preprocess_exception, ill_formed_expression,
+ expression.c_str(), act_pos);
+ return false;
+ }
+ else {
+ // as the if_block_status is false no errors will be reported
+ return false;
+ }
+ }
+ }
+#if !defined(BOOST_NO_EXCEPTIONS)
+ catch (boost::wave::preprocess_exception const& e) {
+ // expression is illformed
+ if (if_block_status) {
+ boost::throw_exception(e);
+ return false;
+ }
+ else {
+ // as the if_block_status is false no errors will be reported
+ return false;
+ }
+ }
+#endif
+
+ if (!hit.full) {
+ // The token list starts with a valid expression, but there remains
+ // something. If the remainder consists out of whitespace only, the
+ // expression is still valid.
+ iterator_type next = hit.stop;
+
+ while (next != last) {
+ switch (static_cast<unsigned int>(token_id(*next))) {
+ case T_SPACE:
+ case T_SPACE2:
+ case T_CCOMMENT:
+ break; // ok continue
+
+ case T_NEWLINE:
+ case T_EOF:
+ case T_CPPCOMMENT: // contains newline
+ return as_bool(result); // expression is valid
+
+ default:
+ // expression is illformed
+ if (if_block_status) {
+ string_type expression = as_string<string_type>(first, last);
+ if (0 == expression.size())
+ expression = "<empty expression>";
+ BOOST_WAVE_THROW(preprocess_exception, ill_formed_expression,
+ expression.c_str(), act_pos);
+ return false;
+ }
+ else {
+ // as the if_block_status is false no errors will be reported
+ return false;
+ }
+ }
+ ++next;
+ }
+ }
+
+ if (error_noerror != result.is_valid()) // division or other error by zero occurred
+ status = result.is_valid();
+
+// token sequence is a valid expression
+ return as_bool(result);
+}
+
+#undef BOOST_WAVE_EXPRGRAMMAR_GEN_INLINE
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace grammars
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_EXPRESSION_GRAMMAR_HPP_099CD1A4_A6C0_44BE_8F24_0B00F5BE5674_INCLUDED)
diff --git a/boost/wave/grammars/cpp_expression_grammar_gen.hpp b/boost/wave/grammars/cpp_expression_grammar_gen.hpp
new file mode 100644
index 0000000000..593c97786b
--- /dev/null
+++ b/boost/wave/grammars/cpp_expression_grammar_gen.hpp
@@ -0,0 +1,75 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_EXPRESSION_GRAMMAR_GEN_HPP_42399258_6CDC_4101_863D_5C7D95B5A6CA_INCLUDED)
+#define CPP_EXPRESSION_GRAMMAR_GEN_HPP_42399258_6CDC_4101_863D_5C7D95B5A6CA_INCLUDED
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/wave/cpp_iteration_context.hpp>
+#include <boost/wave/grammars/cpp_value_error.hpp>
+
+#include <list>
+#include <boost/pool/pool_alloc.hpp>
+
+// this must occur after all of the includes and before any code appears
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_PREFIX
+#endif
+
+// suppress warnings about dependent classes not being exported from the dll
+#ifdef BOOST_MSVC
+#pragma warning(push)
+#pragma warning(disable : 4251 4231 4660)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+namespace boost {
+namespace wave {
+namespace grammars {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// expression_grammar_gen template class
+//
+// This template helps separating the compilation of the
+// expression_grammar class from the compilation of the main
+// pp_iterator. This is done to safe compilation time.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename TokenT>
+struct BOOST_WAVE_DECL expression_grammar_gen {
+
+ typedef TokenT token_type;
+ typedef std::list<token_type, boost::fast_pool_allocator<token_type> >
+ token_sequence_type;
+
+ static bool evaluate(
+ typename token_sequence_type::const_iterator const &first,
+ typename token_sequence_type::const_iterator const &last,
+ typename token_type::position_type const &tok,
+ bool if_block_status, value_error &status);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace grammars
+} // namespace wave
+} // namespace boost
+
+#ifdef BOOST_MSVC
+#pragma warning(pop)
+#endif
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_EXPRESSION_GRAMMAR_GEN_HPP_42399258_6CDC_4101_863D_5C7D95B5A6CA_INCLUDED)
diff --git a/boost/wave/grammars/cpp_expression_value.hpp b/boost/wave/grammars/cpp_expression_value.hpp
new file mode 100644
index 0000000000..0cd6e13bc1
--- /dev/null
+++ b/boost/wave/grammars/cpp_expression_value.hpp
@@ -0,0 +1,883 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_EXPRESSION_VALUE_HPP_452FE66D_8754_4107_AF1E_E42255A0C18A_INCLUDED)
+#define CPP_EXPRESSION_VALUE_HPP_452FE66D_8754_4107_AF1E_E42255A0C18A_INCLUDED
+
+#if defined (BOOST_SPIRIT_DEBUG)
+#include <iostream>
+#endif // defined(BOOST_SPIRIT_DEBUG)
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/wave/grammars/cpp_value_error.hpp> // value_error
+
+// 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 {
+namespace grammars {
+namespace closures {
+
+class closure_value;
+inline bool as_bool(closure_value const& v);
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// The closure_value class represents the closure type, which is used for the
+// expression grammar.
+//
+// This class was introduced to allow the expression grammar to respect
+// the numeric type of a numeric literal or expression result.
+//
+///////////////////////////////////////////////////////////////////////////////
+class closure_value {
+public:
+
+ enum value_type {
+ is_int = 1,
+ is_uint = 2,
+ is_bool = 3
+ };
+
+ closure_value(value_error valid_ = error_noerror)
+ : type(is_int), valid(valid_)
+ { value.i = 0; }
+ explicit closure_value(int i, value_error valid_ = error_noerror)
+ : type(is_int), valid(valid_)
+ { value.i = i; }
+ explicit closure_value(unsigned int ui, value_error valid_ = error_noerror)
+ : type(is_uint), valid(valid_)
+ { value.ui = ui; }
+ explicit closure_value(int_literal_type i, value_error valid_ = error_noerror)
+ : type(is_int), valid(valid_)
+ { value.i = i; }
+ explicit closure_value(uint_literal_type ui, value_error valid_ = error_noerror)
+ : type(is_uint), valid(valid_)
+ { value.ui = ui; }
+ explicit closure_value(bool b, value_error valid_ = error_noerror)
+ : type(is_bool), valid(valid_)
+ { value.b = b; }
+
+ value_type get_type() const { return type; }
+ value_error is_valid() const { return valid; }
+
+// explicit conversion
+ friend int_literal_type as_int(closure_value const& v)
+ {
+ switch (v.type) {
+ case is_uint: return v.value.ui;
+ case is_bool: return v.value.b ? 1 : 0;
+ case is_int: break;
+ }
+ return v.value.i;
+ }
+ friend uint_literal_type as_uint(closure_value const& v)
+ {
+ switch (v.type) {
+ case is_uint: return v.value.ui;
+ case is_bool: return v.value.b ? 1 : 0;
+ case is_int: break;
+ }
+ return v.value.i;
+ }
+ friend int_literal_type as_long(closure_value const& v)
+ {
+ switch (v.type) {
+ case is_uint: return v.value.ui;
+ case is_bool: return v.value.b ? 1 : 0;
+ case is_int: break;
+ }
+ return v.value.i;
+ }
+ friend uint_literal_type as_ulong(closure_value const& v)
+ {
+ switch (v.type) {
+ case is_uint: return v.value.ui;
+ case is_bool: return v.value.b ? 1 : 0;
+ case is_int: break;
+ }
+ return v.value.i;
+ }
+ friend bool as_bool(closure_value const& v)
+ {
+ switch (v.type) {
+ case is_uint: return v.value.ui != 0;
+ case is_bool: return v.value.b;
+ case is_int: break;
+ }
+ return v.value.i != 0.0;
+ }
+
+// assignment
+ closure_value &operator= (closure_value const &rhs)
+ {
+ switch (rhs.get_type()) {
+ case is_int:
+ value.i = as_long(rhs);
+ type = is_int;
+ break;
+
+ case is_uint:
+ value.ui = as_ulong(rhs);
+ type = is_uint;
+ break;
+
+ case is_bool:
+ value.b = as_bool(rhs);
+ type = is_bool;
+ break;
+ }
+ valid = rhs.valid;
+ return *this;
+ }
+ closure_value &operator= (int rhs)
+ {
+ type = is_int;
+ value.i = rhs;
+ valid = error_noerror;
+ return *this;
+ }
+ closure_value &operator= (unsigned int rhs)
+ {
+ type = is_uint;
+ value.ui = rhs;
+ valid = error_noerror;
+ return *this;
+ }
+ closure_value &operator= (int_literal_type rhs)
+ {
+ type = is_int;
+ value.i = rhs;
+ valid = error_noerror;
+ return *this;
+ }
+ closure_value &operator= (uint_literal_type rhs)
+ {
+ type = is_uint;
+ value.ui = rhs;
+ valid = error_noerror;
+ return *this;
+ }
+ closure_value &operator= (bool rhs)
+ {
+ type = is_bool;
+ value.b = rhs;
+ valid = error_noerror;
+ return *this;
+ }
+
+// arithmetics
+ closure_value &operator+= (closure_value const &rhs)
+ {
+ switch (type) {
+ case is_int:
+ switch(rhs.type) {
+ case is_bool:
+ {
+ int_literal_type result = value.i + as_long(rhs);
+ if ((rhs.value.i > 0L && value.i > result) ||
+ (rhs.value.i < 0L && value.i < result))
+ {
+ valid = error_integer_overflow;
+ }
+ else {
+ value.i = result;
+ }
+ }
+ break;
+
+ case is_int:
+ {
+ int_literal_type result = value.i + rhs.value.i;
+ if ((rhs.value.i > 0L && value.i > result) ||
+ (rhs.value.i < 0L && value.i < result))
+ {
+ valid = error_integer_overflow;
+ }
+ else {
+ value.i = result;
+ }
+ }
+ break;
+
+ case is_uint:
+ {
+ uint_literal_type result = value.ui + rhs.value.ui;
+ if (result < value.ui) {
+ valid = error_integer_overflow;
+ }
+ else {
+ value.ui = result;
+ type = is_uint;
+ }
+ }
+ break;
+ }
+ break;
+
+ case is_uint:
+ {
+ uint_literal_type result = value.ui + as_ulong(rhs);
+ if (result < value.ui) {
+ valid = error_integer_overflow;
+ }
+ else {
+ value.ui = result;
+ }
+ }
+ break;
+
+ case is_bool:
+ value.i = value.b + as_bool(rhs);
+ type = is_int;
+ }
+ valid = (value_error)(valid | rhs.valid);
+ return *this;
+ }
+ closure_value &operator-= (closure_value const &rhs)
+ {
+ switch (type) {
+ case is_int:
+ switch(rhs.type) {
+ case is_bool:
+ {
+ int_literal_type result = value.i - as_long(rhs);
+ if ((rhs.value.i > 0L && result > value.i) ||
+ (rhs.value.i < 0L && result < value.i))
+ {
+ valid = error_integer_overflow;
+ }
+ else {
+ value.i = result;
+ }
+ }
+ break;
+
+ case is_int:
+ {
+ int_literal_type result = value.i - rhs.value.i;
+ if ((rhs.value.i > 0L && result > value.i) ||
+ (rhs.value.i < 0L && result < value.i))
+ {
+ valid = error_integer_overflow;
+ }
+ else {
+ value.i = result;
+ }
+ }
+ break;
+
+ case is_uint:
+ {
+ uint_literal_type result = value.ui - rhs.value.ui;
+ if (result > value.ui) {
+ valid = error_integer_overflow;
+ }
+ else {
+ value.ui = result;
+ type = is_uint;
+ }
+ }
+ break;
+ }
+ break;
+
+ case is_uint:
+ switch(rhs.type) {
+ case is_bool:
+ {
+ uint_literal_type result = value.ui - as_ulong(rhs);
+ if (result > value.ui)
+ {
+ valid = error_integer_overflow;
+ }
+ else {
+ value.ui = result;
+ }
+ }
+ break;
+
+ case is_int:
+ {
+ uint_literal_type result = value.ui - rhs.value.i;
+ if ((rhs.value.i > 0L && result > value.ui) ||
+ (rhs.value.i < 0L && result < value.ui))
+ {
+ valid = error_integer_overflow;
+ }
+ else {
+ value.ui = result;
+ }
+ }
+ break;
+
+ case is_uint:
+ {
+ uint_literal_type result = value.ui - rhs.value.ui;
+ if (result > value.ui) {
+ valid = error_integer_overflow;
+ }
+ else {
+ value.ui = result;
+ }
+ }
+ break;
+ }
+ break;
+
+ case is_bool:
+ value.i = value.b - as_bool(rhs);
+ type = is_int;
+ }
+ valid = (value_error)(valid | rhs.valid);
+ return *this;
+ }
+ closure_value &operator*= (closure_value const &rhs)
+ {
+ switch (type) {
+ case is_int:
+ switch(rhs.type) {
+ case is_bool: value.i *= as_long(rhs); break;
+ case is_int:
+ {
+ int_literal_type result = value.i * rhs.value.i;
+ if (0 != value.i && 0 != rhs.value.i &&
+ (result / value.i != rhs.value.i ||
+ result / rhs.value.i != value.i)
+ )
+ {
+ valid = error_integer_overflow;
+ }
+ else {
+ value.i = result;
+ }
+ }
+ break;
+
+ case is_uint:
+ {
+ uint_literal_type result = value.ui * rhs.value.ui;
+ if (0 != value.ui && 0 != rhs.value.ui &&
+ (result / value.ui != rhs.value.ui ||
+ result / rhs.value.ui != value.ui)
+ )
+ {
+ valid = error_integer_overflow;
+ }
+ else {
+ value.ui = result;
+ type = is_uint;
+ }
+ }
+ break;
+ }
+ break;
+
+ case is_uint:
+ {
+ uint_literal_type rhs_val = as_ulong(rhs);
+ uint_literal_type result = value.ui * rhs_val;
+ if (0 != value.ui && 0 != rhs_val &&
+ (result / value.ui != rhs_val ||
+ result / rhs_val != value.ui)
+ )
+ {
+ valid = error_integer_overflow;
+ }
+ else {
+ value.ui = result;
+ type = is_uint;
+ }
+ }
+ break;
+
+ case is_bool:
+ switch (rhs.type) {
+ case is_int:
+ value.i = (value.b ? 1 : 0) * rhs.value.i;
+ type = is_int;
+ break;
+
+ case is_uint:
+ value.ui = (value.b ? 1 : 0) * rhs.value.ui;
+ type = is_uint;
+ break;
+
+ case is_bool:
+ value.b = 0 != ((value.b ? 1 : 0) * (rhs.value.b ? 1 : 0));
+ break;
+ }
+ }
+ valid = (value_error)(valid | rhs.valid);
+ return *this;
+ }
+ closure_value &operator/= (closure_value const &rhs)
+ {
+ switch (type) {
+ case is_int:
+ switch(rhs.type) {
+ case is_bool:
+ case is_int:
+ if (as_long(rhs) != 0) {
+ if (value.i == -value.i && -1 == rhs.value.i) {
+ // LONG_MIN / -1 on two's complement
+ valid = error_integer_overflow;
+ }
+ else {
+ value.i /= as_long(rhs);
+ }
+ }
+ else {
+ valid = error_division_by_zero; // division by zero
+ }
+ break;
+
+ case is_uint:
+ if (rhs.value.ui != 0) {
+ value.ui /= rhs.value.ui;
+ type = is_uint;
+ }
+ else {
+ valid = error_division_by_zero; // division by zero
+ }
+ break;
+ }
+ break;
+
+ case is_uint:
+ if (as_ulong(rhs) != 0)
+ value.ui /= as_ulong(rhs);
+ else
+ valid = error_division_by_zero; // division by zero
+ break;
+
+ case is_bool:
+ if (as_bool(rhs)) {
+ switch(rhs.type) {
+ case is_int:
+ value.i = (value.b ? 1 : 0) / rhs.value.i;
+ type = is_int;
+ break;
+
+ case is_uint:
+ value.i = (value.b ? 1 : 0) / rhs.value.ui;
+ type = is_int;
+ break;
+
+ case is_bool:
+ break;
+ }
+ }
+ else {
+ valid = error_division_by_zero; // division by zero
+ }
+ }
+ return *this;
+ }
+ closure_value &operator%= (closure_value const &rhs)
+ {
+ switch (type) {
+ case is_int:
+ switch(rhs.type) {
+ case is_bool:
+ case is_int:
+ if (as_long(rhs) != 0) {
+ if (value.i == -value.i && -1 == rhs.value.i) {
+ // LONG_MIN % -1 on two's complement
+ valid = error_integer_overflow;
+ }
+ else {
+ value.i %= as_long(rhs);
+ }
+ }
+ else {
+ valid = error_division_by_zero; // division by zero
+ }
+ break;
+
+ case is_uint:
+ if (rhs.value.ui != 0) {
+ value.ui %= rhs.value.ui;
+ type = is_uint;
+ }
+ else {
+ valid = error_division_by_zero; // division by zero
+ }
+ break;
+ }
+ break;
+
+ case is_uint:
+ if (as_ulong(rhs) != 0)
+ value.ui %= as_ulong(rhs);
+ else
+ valid = error_division_by_zero; // division by zero
+ break;
+
+ case is_bool:
+ if (as_bool(rhs)) {
+ switch(rhs.type) {
+ case is_int:
+ value.i = (value.b ? 1 : 0) % rhs.value.i;
+ type = is_int;
+ break;
+
+ case is_uint:
+ value.i = (value.b ? 1 : 0) % rhs.value.ui;
+ type = is_int;
+ break;
+
+ case is_bool:
+ break;
+ }
+ }
+ else {
+ valid = error_division_by_zero; // division by zero
+ }
+ }
+ return *this;
+ }
+
+ friend closure_value
+ operator- (closure_value const &rhs)
+ {
+ switch (rhs.type) {
+ case is_int:
+ {
+ int_literal_type value = as_long(rhs);
+ if (value != 0 && value == -value)
+ return closure_value(-value, error_integer_overflow);
+ return closure_value(-value, rhs.valid);
+ }
+
+ case is_bool: return closure_value(-as_long(rhs), rhs.valid);
+ case is_uint: break;
+ }
+
+ int_literal_type value = as_ulong(rhs);
+ if (value != 0 && value == -value)
+ return closure_value(-value, error_integer_overflow);
+ return closure_value(-value, rhs.valid);
+ }
+ friend closure_value
+ operator~ (closure_value const &rhs)
+ {
+ return closure_value(~as_ulong(rhs), rhs.valid);
+ }
+ friend closure_value
+ operator! (closure_value const &rhs)
+ {
+ switch (rhs.type) {
+ case is_int: return closure_value(!as_long(rhs), rhs.valid);
+ case is_bool: return closure_value(!as_bool(rhs), rhs.valid);
+ case is_uint: break;
+ }
+ return closure_value(!as_ulong(rhs), rhs.valid);
+ }
+
+// comparison
+ friend closure_value
+ operator== (closure_value const &lhs, closure_value const &rhs)
+ {
+ bool cmp = false;
+ switch (lhs.type) {
+ case is_int:
+ switch(rhs.type) {
+ case is_bool: cmp = as_bool(lhs) == rhs.value.b; break;
+ case is_int: cmp = lhs.value.i == rhs.value.i; break;
+ case is_uint: cmp = lhs.value.ui == rhs.value.ui; break;
+ }
+ break;
+
+ case is_uint: cmp = lhs.value.ui == as_ulong(rhs); break;
+ case is_bool: cmp = lhs.value.b == as_bool(rhs); break;
+ }
+ return closure_value(cmp, (value_error)(lhs.valid | rhs.valid));
+ }
+ friend closure_value
+ operator!= (closure_value const &lhs, closure_value const &rhs)
+ {
+ return closure_value(!as_bool(lhs == rhs), (value_error)(lhs.valid | rhs.valid));
+ }
+ friend closure_value
+ operator> (closure_value const &lhs, closure_value const &rhs)
+ {
+ bool cmp = false;
+ switch (lhs.type) {
+ case is_int:
+ switch(rhs.type) {
+ case is_bool: cmp = lhs.value.i > as_long(rhs); break;
+ case is_int: cmp = lhs.value.i > rhs.value.i; break;
+ case is_uint: cmp = lhs.value.ui > rhs.value.ui; break;
+ }
+ break;
+
+ case is_uint: cmp = lhs.value.ui > as_ulong(rhs); break;
+ case is_bool: cmp = lhs.value.b > as_bool(rhs); break;
+ }
+ return closure_value(cmp, (value_error)(lhs.valid | rhs.valid));
+ }
+ friend closure_value
+ operator< (closure_value const &lhs, closure_value const &rhs)
+ {
+ bool cmp = false;
+ switch (lhs.type) {
+ case is_int:
+ switch(rhs.type) {
+ case is_bool: cmp = lhs.value.i < as_long(rhs); break;
+ case is_int: cmp = lhs.value.i < rhs.value.i; break;
+ case is_uint: cmp = lhs.value.ui < rhs.value.ui; break;
+ }
+ break;
+
+ case is_uint: cmp = lhs.value.ui < as_ulong(rhs); break;
+ case is_bool: cmp = as_bool(lhs) < as_bool(rhs); break;
+ }
+ return closure_value(cmp, (value_error)(lhs.valid | rhs.valid));
+ }
+ friend closure_value
+ operator<= (closure_value const &lhs, closure_value const &rhs)
+ {
+ return closure_value(!as_bool(lhs > rhs), (value_error)(lhs.valid | rhs.valid));
+ }
+ friend closure_value
+ operator>= (closure_value const &lhs, closure_value const &rhs)
+ {
+ return closure_value(!as_bool(lhs < rhs), (value_error)(lhs.valid | rhs.valid));
+ }
+
+ closure_value &
+ operator<<= (closure_value const &rhs)
+ {
+ switch (type) {
+ case is_bool:
+ case is_int:
+ switch (rhs.type) {
+ case is_bool:
+ case is_int:
+ {
+ int_literal_type shift_by = as_long(rhs);
+
+ if (shift_by > 64)
+ shift_by = 64;
+ else if (shift_by < -64)
+ shift_by = -64;
+ value.i <<= shift_by;
+ }
+ break;
+
+ case is_uint:
+ {
+ uint_literal_type shift_by = as_ulong(rhs);
+
+ if (shift_by > 64)
+ shift_by = 64;
+ value.ui <<= shift_by;
+
+ // Note: The usual arithmetic conversions are not performed on
+ // bit shift operations.
+ }
+ break;
+ }
+ break;
+
+ case is_uint:
+ switch (rhs.type) {
+ case is_bool:
+ case is_int:
+ {
+ int_literal_type shift_by = as_long(rhs);
+
+ if (shift_by > 64)
+ shift_by = 64;
+ else if (shift_by < -64)
+ shift_by = -64;
+ value.ui <<= shift_by;
+ }
+ break;
+
+ case is_uint:
+ {
+ uint_literal_type shift_by = as_ulong(rhs);
+
+ if (shift_by > 64)
+ shift_by = 64;
+ value.ui <<= shift_by;
+ }
+ break;
+ }
+ }
+ valid = (value_error)(valid | rhs.valid);
+ return *this;
+ }
+
+ closure_value &
+ operator>>= (closure_value const &rhs)
+ {
+ switch (type) {
+ case is_bool:
+ case is_int:
+ switch (rhs.type) {
+ case is_bool:
+ case is_int:
+ {
+ int_literal_type shift_by = as_long(rhs);
+
+ if (shift_by > 64)
+ shift_by = 64;
+ else if (shift_by < -64)
+ shift_by = -64;
+ value.i >>= shift_by;
+ }
+ break;
+
+ case is_uint:
+ {
+ uint_literal_type shift_by = as_ulong(rhs);
+
+ if (shift_by > 64)
+ shift_by = 64;
+ value.ui >>= shift_by;
+
+ // Note: The usual arithmetic conversions are not performed on
+ // bit shift operations.
+ }
+ break;
+ }
+ break;
+
+ case is_uint:
+ switch (rhs.type) {
+ case is_bool:
+ case is_int:
+ {
+ int_literal_type shift_by = as_long(rhs);
+
+ if (shift_by > 64)
+ shift_by = 64;
+ else if (shift_by < -64)
+ shift_by = -64;
+ value.ui >>= shift_by;
+ }
+ break;
+
+ case is_uint:
+ {
+ uint_literal_type shift_by = as_ulong(rhs);
+
+ if (shift_by > 64)
+ shift_by = 64;
+ value.ui >>= shift_by;
+ }
+ break;
+ }
+ break;
+ }
+ valid = (value_error)(valid | rhs.valid);
+ return *this;
+ }
+
+ friend closure_value
+ operator|| (closure_value const &lhs, closure_value const &rhs)
+ {
+ bool result = as_bool(lhs) || as_bool(rhs);
+ return closure_value(result, (value_error)(lhs.valid | rhs.valid));
+ }
+
+ friend closure_value
+ operator&& (closure_value const &lhs, closure_value const &rhs)
+ {
+ bool result = as_bool(lhs) && as_bool(rhs);
+ return closure_value(result, (value_error)(lhs.valid | rhs.valid));
+ }
+
+ friend closure_value
+ operator| (closure_value const &lhs, closure_value const &rhs)
+ {
+ uint_literal_type result = as_ulong(lhs) | as_ulong(rhs);
+ return closure_value(result, (value_error)(lhs.valid | rhs.valid));
+ }
+
+ friend closure_value
+ operator& (closure_value const &lhs, closure_value const &rhs)
+ {
+ uint_literal_type result = as_ulong(lhs) & as_ulong(rhs);
+ return closure_value(result, (value_error)(lhs.valid | rhs.valid));
+ }
+
+ friend closure_value
+ operator^ (closure_value const &lhs, closure_value const &rhs)
+ {
+ uint_literal_type result = as_ulong(lhs) ^ as_ulong(rhs);
+ return closure_value(result, (value_error)(lhs.valid | rhs.valid));
+ }
+
+ // handle the ?: operator
+ closure_value &
+ handle_questionmark(closure_value const &cond, closure_value const &val2)
+ {
+ switch (type) {
+ case is_int:
+ switch (val2.type) {
+ case is_bool: value.b = as_bool(cond) ? value.b : as_bool(val2); break;
+ case is_int: value.i = as_bool(cond) ? value.i : as_long(val2); break;
+ case is_uint:
+ value.ui = as_bool(cond) ? value.ui : as_ulong(val2);
+ type = is_uint; // changing type!
+ break;
+ }
+ break;
+
+ case is_uint: value.ui = as_bool(cond) ? value.ui : as_ulong(val2); break;
+ case is_bool: value.b = as_bool(cond) ? value.b : as_bool(val2); break;
+ }
+ valid = as_bool(cond) ? valid : val2.valid;
+ return *this;
+ }
+
+#if defined (BOOST_SPIRIT_DEBUG)
+ friend std::ostream&
+ operator<< (std::ostream &o, closure_value const &val)
+ {
+ switch (val.type) {
+ case is_int: o << "int(" << as_long(val) << ")"; break;
+ case is_uint: o << "unsigned int(" << as_ulong(val) << ")"; break;
+ case is_bool: o << "bool(" << as_bool(val) << ")"; break;
+ }
+ return o;
+ }
+#endif // defined(BOOST_SPIRIT_DEBUG)
+
+private:
+ value_type type;
+ union {
+ int_literal_type i;
+ uint_literal_type ui;
+ bool b;
+ } value;
+ value_error valid;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace closures
+} // namespace grammars
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_EXPRESSION_VALUE_HPP_452FE66D_8754_4107_AF1E_E42255A0C18A_INCLUDED)
diff --git a/boost/wave/grammars/cpp_grammar.hpp b/boost/wave/grammars/cpp_grammar.hpp
new file mode 100644
index 0000000000..d309e2e39b
--- /dev/null
+++ b/boost/wave/grammars/cpp_grammar.hpp
@@ -0,0 +1,765 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_GRAMMAR_HPP_FEAEBC2E_2734_428B_A7CA_85E5A415E23E_INCLUDED)
+#define CPP_GRAMMAR_HPP_FEAEBC2E_2734_428B_A7CA_85E5A415E23E_INCLUDED
+
+#include <boost/spirit/include/classic_core.hpp>
+#include <boost/spirit/include/classic_parse_tree.hpp>
+#include <boost/spirit/include/classic_parse_tree_utils.hpp>
+#include <boost/spirit/include/classic_confix.hpp>
+#include <boost/spirit/include/classic_lists.hpp>
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/pool/pool_alloc.hpp>
+
+#if BOOST_WAVE_DUMP_PARSE_TREE != 0
+#include <map>
+#include <boost/spirit/include/classic_tree_to_xml.hpp>
+#endif
+
+#include <boost/wave/token_ids.hpp>
+#include <boost/wave/grammars/cpp_grammar_gen.hpp>
+#include <boost/wave/util/pattern_parser.hpp>
+
+#include <boost/wave/cpp_exceptions.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 {
+namespace grammars {
+
+namespace impl {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// store_found_eof
+//
+// The store_found_eof functor sets a given flag if the T_EOF token was
+// found during the parsing process
+//
+///////////////////////////////////////////////////////////////////////////////
+
+ struct store_found_eof {
+
+ store_found_eof(bool &found_eof_) : found_eof(found_eof_) {}
+
+ template <typename TokenT>
+ void operator()(TokenT const &/*token*/) const
+ {
+ found_eof = true;
+ }
+
+ bool &found_eof;
+ };
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// store_found_directive
+//
+// The store_found_directive functor stores the token_id of the recognized
+// pp directive
+//
+///////////////////////////////////////////////////////////////////////////////
+
+ template <typename TokenT>
+ struct store_found_directive {
+
+ store_found_directive(TokenT &found_directive_)
+ : found_directive(found_directive_) {}
+
+ void operator()(TokenT const &token) const
+ {
+ found_directive = token;
+ }
+
+ TokenT &found_directive;
+ };
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// store_found_eoltokens
+//
+// The store_found_eoltokens functor stores the token sequence of the
+// line ending for a particular pp directive
+//
+///////////////////////////////////////////////////////////////////////////////
+
+ template <typename ContainerT>
+ struct store_found_eoltokens {
+
+ store_found_eoltokens(ContainerT &found_eoltokens_)
+ : found_eoltokens(found_eoltokens_) {}
+
+ template <typename IteratorT>
+ void operator()(IteratorT const &first, IteratorT const& last) const
+ {
+ std::copy(first, last,
+ std::inserter(found_eoltokens, found_eoltokens.end()));
+ }
+
+ ContainerT &found_eoltokens;
+ };
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// flush_underlying_parser
+//
+// The flush_underlying_parser flushes the underlying
+// multi_pass_iterator during the normal parsing process. This is
+// used at certain points during the parsing process, when it is
+// clear, that no backtracking is needed anymore and the input
+// gathered so far may be discarded.
+//
+///////////////////////////////////////////////////////////////////////////////
+ struct flush_underlying_parser
+ : public boost::spirit::classic::parser<flush_underlying_parser>
+ {
+ typedef flush_underlying_parser this_t;
+
+ template <typename ScannerT>
+ typename boost::spirit::classic::parser_result<this_t, ScannerT>::type
+ parse(ScannerT const& scan) const
+ {
+ scan.first.clear_queue();
+ return scan.empty_match();
+ }
+ };
+
+ flush_underlying_parser const
+ flush_underlying_parser_p = flush_underlying_parser();
+
+} // anonymous namespace
+
+///////////////////////////////////////////////////////////////////////////////
+// define, whether the rule's should generate some debug output
+#define TRACE_CPP_GRAMMAR \
+ bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_CPP_GRAMMAR) \
+ /**/
+
+///////////////////////////////////////////////////////////////////////////////
+// Encapsulation of the C++ preprocessor grammar.
+template <typename TokenT, typename ContainerT>
+struct cpp_grammar :
+ public boost::spirit::classic::grammar<cpp_grammar<TokenT, ContainerT> >
+{
+ typedef typename TokenT::position_type position_type;
+ typedef cpp_grammar<TokenT, ContainerT> grammar_type;
+ typedef impl::store_found_eof store_found_eof_type;
+ typedef impl::store_found_directive<TokenT> store_found_directive_type;
+ typedef impl::store_found_eoltokens<ContainerT> store_found_eoltokens_type;
+
+ template <typename ScannerT>
+ struct definition
+ {
+ // non-parse_tree generating rule type
+ typedef typename ScannerT::iteration_policy_t iteration_policy_t;
+ typedef boost::spirit::classic::match_policy match_policy_t;
+ typedef typename ScannerT::action_policy_t action_policy_t;
+ typedef
+ boost::spirit::classic::scanner_policies<
+ iteration_policy_t, match_policy_t, action_policy_t>
+ policies_t;
+ typedef
+ boost::spirit::classic::scanner<typename ScannerT::iterator_t, policies_t>
+ non_tree_scanner_t;
+ typedef
+ boost::spirit::classic::rule<
+ non_tree_scanner_t, boost::spirit::classic::dynamic_parser_tag>
+ no_tree_rule_type;
+
+ // 'normal' (parse_tree generating) rule type
+ typedef
+ boost::spirit::classic::rule<
+ ScannerT, boost::spirit::classic::dynamic_parser_tag>
+ rule_type;
+
+ rule_type pp_statement, macro_include_file;
+// rule_type include_file, system_include_file;
+ rule_type plain_define, macro_definition, macro_parameters;
+ rule_type undefine;
+ rule_type ppifdef, ppifndef, ppif, ppelif;
+// rule_type ppelse, ppendif;
+ rule_type ppline;
+ rule_type pperror;
+ rule_type ppwarning;
+ rule_type pppragma;
+ rule_type illformed;
+ rule_type ppqualifiedname;
+ rule_type eol_tokens;
+ no_tree_rule_type ppsp;
+#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
+ rule_type ppregion;
+ rule_type ppendregion;
+#endif
+
+ definition(cpp_grammar const &self)
+ {
+ // import the spirit and cpplexer namespaces here
+ using namespace boost::spirit::classic;
+ using namespace boost::wave;
+ using namespace boost::wave::util;
+
+ // set the rule id's for later use
+ pp_statement.set_id(BOOST_WAVE_PP_STATEMENT_ID);
+// include_file.set_id(BOOST_WAVE_INCLUDE_FILE_ID);
+// system_include_file.set_id(BOOST_WAVE_SYSINCLUDE_FILE_ID);
+ macro_include_file.set_id(BOOST_WAVE_MACROINCLUDE_FILE_ID);
+ plain_define.set_id(BOOST_WAVE_PLAIN_DEFINE_ID);
+ macro_parameters.set_id(BOOST_WAVE_MACRO_PARAMETERS_ID);
+ macro_definition.set_id(BOOST_WAVE_MACRO_DEFINITION_ID);
+ undefine.set_id(BOOST_WAVE_UNDEFINE_ID);
+ ppifdef.set_id(BOOST_WAVE_IFDEF_ID);
+ ppifndef.set_id(BOOST_WAVE_IFNDEF_ID);
+ ppif.set_id(BOOST_WAVE_IF_ID);
+ ppelif.set_id(BOOST_WAVE_ELIF_ID);
+// ppelse.set_id(BOOST_WAVE_ELSE_ID);
+// ppendif.set_id(BOOST_WAVE_ENDIF_ID);
+ ppline.set_id(BOOST_WAVE_LINE_ID);
+ pperror.set_id(BOOST_WAVE_ERROR_ID);
+ ppwarning.set_id(BOOST_WAVE_WARNING_ID);
+ pppragma.set_id(BOOST_WAVE_PRAGMA_ID);
+ illformed.set_id(BOOST_WAVE_ILLFORMED_ID);
+ ppsp.set_id(BOOST_WAVE_PPSPACE_ID);
+ ppqualifiedname.set_id(BOOST_WAVE_PPQUALIFIEDNAME_ID);
+#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
+ ppregion.set_id(BOOST_WAVE_REGION_ID);
+ ppendregion.set_id(BOOST_WAVE_ENDREGION_ID);
+#endif
+
+#if BOOST_WAVE_DUMP_PARSE_TREE != 0
+ self.map_rule_id_to_name.init_rule_id_to_name_map(self);
+#endif
+
+ // recognizes preprocessor directives only
+
+ // C++ standard 16.1: A preprocessing directive consists of a sequence
+ // of preprocessing tokens. The first token in the sequence is #
+ // preprocessing token that is either the first character in the source
+ // file (optionally after white space containing no new-line
+ // characters) or that follows white space containing at least one
+ // new-line character. The last token in the sequence is the first
+ // new-line character that follows the first token in the sequence.
+
+ pp_statement
+ = ( plain_define
+// | include_file
+// | system_include_file
+ | ppif
+ | ppelif
+ | ppifndef
+ | ppifdef
+ | undefine
+// | ppelse
+ | macro_include_file
+ | ppline
+ | pppragma
+ | pperror
+ | ppwarning
+// | ppendif
+#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
+ | ppregion
+ | ppendregion
+#endif
+ | illformed
+ )
+ >> eol_tokens
+ [ store_found_eoltokens_type(self.found_eoltokens) ]
+// In parser debug mode it is useful not to flush the underlying stream
+// to allow its investigation in the debugger and to see the correct
+// output in the printed debug log..
+// Note: this may break the parser, though.
+#if !(defined(BOOST_SPIRIT_DEBUG) && \
+ (BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_CPP_GRAMMAR) \
+ )
+ >> impl::flush_underlying_parser_p
+#endif // !(defined(BOOST_SPIRIT_DEBUG) &&
+ ;
+
+// // #include ...
+// include_file // include "..."
+// = ch_p(T_PP_QHEADER)
+// [ store_found_directive_type(self.found_directive) ]
+// #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
+// | ch_p(T_PP_QHEADER_NEXT)
+// [ store_found_directive_type(self.found_directive) ]
+// #endif
+// ;
+
+// system_include_file // include <...>
+// = ch_p(T_PP_HHEADER)
+// [ store_found_directive_type(self.found_directive) ]
+// #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
+// | ch_p(T_PP_HHEADER_NEXT)
+// [ store_found_directive_type(self.found_directive) ]
+// #endif
+// ;
+
+ macro_include_file // include ...anything else...
+ = no_node_d
+ [
+ ch_p(T_PP_INCLUDE)
+ [ store_found_directive_type(self.found_directive) ]
+#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
+ | ch_p(T_PP_INCLUDE_NEXT)
+ [ store_found_directive_type(self.found_directive) ]
+#endif
+ ]
+ >> *( anychar_p -
+ (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
+ )
+ ;
+
+ // #define FOO foo (with optional parameters)
+ plain_define
+ = no_node_d
+ [
+ ch_p(T_PP_DEFINE)
+ [ store_found_directive_type(self.found_directive) ]
+ >> +ppsp
+ ]
+ >> ( ch_p(T_IDENTIFIER)
+ | pattern_p(KeywordTokenType,
+ TokenTypeMask|PPTokenFlag)
+ | pattern_p(OperatorTokenType|AltExtTokenType,
+ ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc.
+ | pattern_p(BoolLiteralTokenType,
+ TokenTypeMask|PPTokenFlag) // true/false
+ )
+ >> ( ( no_node_d[eps_p(ch_p(T_LEFTPAREN))]
+ >> macro_parameters
+ >> !macro_definition
+ )
+ | !( no_node_d[+ppsp]
+ >> macro_definition
+ )
+ )
+ ;
+
+ // parameter list
+ // normal C++ mode
+ macro_parameters
+ = confix_p(
+ no_node_d[ch_p(T_LEFTPAREN) >> *ppsp],
+ !list_p(
+ ( ch_p(T_IDENTIFIER)
+ | pattern_p(KeywordTokenType,
+ TokenTypeMask|PPTokenFlag)
+ | pattern_p(OperatorTokenType|AltExtTokenType,
+ ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc.
+ | pattern_p(BoolLiteralTokenType,
+ TokenTypeMask|PPTokenFlag) // true/false
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ | ch_p(T_ELLIPSIS)
+#endif
+ ),
+ no_node_d[*ppsp >> ch_p(T_COMMA) >> *ppsp]
+ ),
+ no_node_d[*ppsp >> ch_p(T_RIGHTPAREN)]
+ )
+ ;
+
+ // macro body (anything left until eol)
+ macro_definition
+ = no_node_d[*ppsp]
+ >> *( anychar_p -
+ (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
+ )
+ ;
+
+ // #undef FOO
+ undefine
+ = no_node_d
+ [
+ ch_p(T_PP_UNDEF)
+ [ store_found_directive_type(self.found_directive) ]
+ >> +ppsp
+ ]
+ >> ( ch_p(T_IDENTIFIER)
+ | pattern_p(KeywordTokenType,
+ TokenTypeMask|PPTokenFlag)
+ | pattern_p(OperatorTokenType|AltExtTokenType,
+ ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc.
+ | pattern_p(BoolLiteralTokenType,
+ TokenTypeMask|PPTokenFlag) // true/false
+ )
+ ;
+
+ // #ifdef et.al.
+ ppifdef
+ = no_node_d
+ [
+ ch_p(T_PP_IFDEF)
+ [ store_found_directive_type(self.found_directive) ]
+ >> +ppsp
+ ]
+ >> ppqualifiedname
+ ;
+
+ ppifndef
+ = no_node_d
+ [
+ ch_p(T_PP_IFNDEF)
+ [ store_found_directive_type(self.found_directive) ]
+ >> +ppsp
+ ]
+ >> ppqualifiedname
+ ;
+
+ ppif
+ = no_node_d
+ [
+ ch_p(T_PP_IF)
+ [ store_found_directive_type(self.found_directive) ]
+// >> *ppsp
+ ]
+ >> +( anychar_p -
+ (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
+ )
+ ;
+
+// ppelse
+// = no_node_d
+// [
+// ch_p(T_PP_ELSE)
+// [ store_found_directive_type(self.found_directive) ]
+// ]
+// ;
+
+ ppelif
+ = no_node_d
+ [
+ ch_p(T_PP_ELIF)
+ [ store_found_directive_type(self.found_directive) ]
+// >> *ppsp
+ ]
+ >> +( anychar_p -
+ (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
+ )
+ ;
+
+// ppendif
+// = no_node_d
+// [
+// ch_p(T_PP_ENDIF)
+// [ store_found_directive_type(self.found_directive) ]
+// ]
+// ;
+
+ // #line ...
+ ppline
+ = no_node_d
+ [
+ ch_p(T_PP_LINE)
+ [ store_found_directive_type(self.found_directive) ]
+ >> *ppsp
+ ]
+ >> +( anychar_p -
+ (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
+ )
+ ;
+
+#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
+ // #region ...
+ ppregion
+ = no_node_d
+ [
+ ch_p(T_MSEXT_PP_REGION)
+ [ store_found_directive_type(self.found_directive) ]
+ >> +ppsp
+ ]
+ >> ppqualifiedname
+ ;
+
+ // #endregion
+ ppendregion
+ = no_node_d
+ [
+ ch_p(T_MSEXT_PP_ENDREGION)
+ [ store_found_directive_type(self.found_directive) ]
+ ]
+ ;
+#endif
+
+ // # something else (ill formed preprocessor directive)
+ illformed // for error reporting
+ = no_node_d
+ [
+ pattern_p(T_POUND, MainTokenMask)
+ >> *ppsp
+ ]
+ >> ( anychar_p -
+ (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
+ )
+ >> no_node_d
+ [
+ *( anychar_p -
+ (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
+ )
+ ]
+ ;
+
+ // #error
+ pperror
+ = no_node_d
+ [
+ ch_p(T_PP_ERROR)
+ [ store_found_directive_type(self.found_directive) ]
+ >> *ppsp
+ ]
+ >> *( anychar_p -
+ (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
+ )
+ ;
+
+ // #warning
+ ppwarning
+ = no_node_d
+ [
+ ch_p(T_PP_WARNING)
+ [ store_found_directive_type(self.found_directive) ]
+ >> *ppsp
+ ]
+ >> *( anychar_p -
+ (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
+ )
+ ;
+
+ // #pragma ...
+ pppragma
+ = no_node_d
+ [
+ ch_p(T_PP_PRAGMA)
+ [ store_found_directive_type(self.found_directive) ]
+ ]
+ >> *( anychar_p -
+ (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
+ )
+ ;
+
+ ppqualifiedname
+ = no_node_d[*ppsp]
+ >> ( ch_p(T_IDENTIFIER)
+ | pattern_p(KeywordTokenType,
+ TokenTypeMask|PPTokenFlag)
+ | pattern_p(OperatorTokenType|AltExtTokenType,
+ ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc.
+ | pattern_p(BoolLiteralTokenType,
+ TokenTypeMask|PPTokenFlag) // true/false
+ )
+ ;
+
+ // auxiliary helper rules
+ ppsp // valid space in a line with a preprocessor directive
+ = ch_p(T_SPACE) | ch_p(T_CCOMMENT)
+ ;
+
+ // end of line tokens
+ eol_tokens
+ = no_node_d
+ [
+ *( ch_p(T_SPACE)
+ | ch_p(T_CCOMMENT)
+ )
+ >> ( ch_p(T_NEWLINE)
+ | ch_p(T_CPPCOMMENT)
+ | ch_p(T_EOF)
+ [ store_found_eof_type(self.found_eof) ]
+ )
+ ]
+ ;
+
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(pp_statement, TRACE_CPP_GRAMMAR);
+// BOOST_SPIRIT_DEBUG_TRACE_RULE(include_file, TRACE_CPP_GRAMMAR);
+// BOOST_SPIRIT_DEBUG_TRACE_RULE(system_include_file, TRACE_CPP_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_include_file, TRACE_CPP_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(plain_define, TRACE_CPP_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_definition, TRACE_CPP_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_parameters, TRACE_CPP_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(undefine, TRACE_CPP_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(ppifdef, TRACE_CPP_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(ppifndef, TRACE_CPP_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(ppif, TRACE_CPP_GRAMMAR);
+// BOOST_SPIRIT_DEBUG_TRACE_RULE(ppelse, TRACE_CPP_GRAMMAR);
+// BOOST_SPIRIT_DEBUG_TRACE_RULE(ppelif, TRACE_CPP_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(ppendif, TRACE_CPP_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(ppline, TRACE_CPP_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(pperror, TRACE_CPP_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(ppwarning, TRACE_CPP_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(illformed, TRACE_CPP_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(ppsp, TRACE_CPP_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(ppqualifiedname, TRACE_CPP_GRAMMAR);
+#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(ppregion, TRACE_CPP_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(ppendregion, TRACE_CPP_GRAMMAR);
+#endif
+ }
+
+ // start rule of this grammar
+ rule_type const& start() const
+ { return pp_statement; }
+ };
+
+ bool &found_eof;
+ TokenT &found_directive;
+ ContainerT &found_eoltokens;
+
+ cpp_grammar(bool &found_eof_, TokenT &found_directive_,
+ ContainerT &found_eoltokens_)
+ : found_eof(found_eof_),
+ found_directive(found_directive_),
+ found_eoltokens(found_eoltokens_)
+ {
+ BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "cpp_grammar",
+ TRACE_CPP_GRAMMAR);
+ }
+
+#if BOOST_WAVE_DUMP_PARSE_TREE != 0
+// helper function and data to get readable names of the rules known to us
+ struct map_ruleid_to_name :
+ public std::map<boost::spirit::classic::parser_id, std::string>
+ {
+ typedef std::map<boost::spirit::classic::parser_id, std::string> base_type;
+
+ void init_rule_id_to_name_map(cpp_grammar const &self)
+ {
+ struct {
+ int parser_id;
+ char const *rule_name;
+ }
+ init_ruleid_name_map[] = {
+ { BOOST_WAVE_PP_STATEMENT_ID, "pp_statement" },
+// { BOOST_WAVE_INCLUDE_FILE_ID, "include_file" },
+// { BOOST_WAVE_SYSINCLUDE_FILE_ID, "system_include_file" },
+ { BOOST_WAVE_MACROINCLUDE_FILE_ID, "macro_include_file" },
+ { BOOST_WAVE_PLAIN_DEFINE_ID, "plain_define" },
+ { BOOST_WAVE_MACRO_PARAMETERS_ID, "macro_parameters" },
+ { BOOST_WAVE_MACRO_DEFINITION_ID, "macro_definition" },
+ { BOOST_WAVE_UNDEFINE_ID, "undefine" },
+ { BOOST_WAVE_IFDEF_ID, "ppifdef" },
+ { BOOST_WAVE_IFNDEF_ID, "ppifndef" },
+ { BOOST_WAVE_IF_ID, "ppif" },
+ { BOOST_WAVE_ELIF_ID, "ppelif" },
+// { BOOST_WAVE_ELSE_ID, "ppelse" },
+// { BOOST_WAVE_ENDIF_ID, "ppendif" },
+ { BOOST_WAVE_LINE_ID, "ppline" },
+ { BOOST_WAVE_ERROR_ID, "pperror" },
+ { BOOST_WAVE_WARNING_ID, "ppwarning" },
+ { BOOST_WAVE_PRAGMA_ID, "pppragma" },
+ { BOOST_WAVE_ILLFORMED_ID, "illformed" },
+ { BOOST_WAVE_PPSPACE_ID, "ppspace" },
+ { BOOST_WAVE_PPQUALIFIEDNAME_ID, "ppqualifiedname" },
+#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
+ { BOOST_WAVE_REGION_ID, "ppregion" },
+ { BOOST_WAVE_ENDREGION_ID, "ppendregion" },
+#endif
+ { 0 }
+ };
+
+ // initialize parser_id to rule_name map
+ for (int i = 0; 0 != init_ruleid_name_map[i].parser_id; ++i)
+ base_type::insert(base_type::value_type(
+ boost::spirit::classic::parser_id(init_ruleid_name_map[i].parser_id),
+ std::string(init_ruleid_name_map[i].rule_name))
+ );
+ }
+ };
+ mutable map_ruleid_to_name map_rule_id_to_name;
+#endif // WAVE_DUMP_PARSE_TREE != 0
+};
+
+///////////////////////////////////////////////////////////////////////////////
+#undef TRACE_CPP_GRAMMAR
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Special parse function generating a parse tree using a given node_factory.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename NodeFactoryT, typename IteratorT, typename ParserT>
+inline boost::spirit::classic::tree_parse_info<IteratorT, NodeFactoryT>
+parsetree_parse(IteratorT const& first_, IteratorT const& last,
+ boost::spirit::classic::parser<ParserT> const& p)
+{
+ using namespace boost::spirit::classic;
+
+ typedef pt_match_policy<IteratorT, NodeFactoryT> pt_match_policy_type;
+ typedef scanner_policies<iteration_policy, pt_match_policy_type>
+ scanner_policies_type;
+ typedef scanner<IteratorT, scanner_policies_type> scanner_type;
+
+ scanner_policies_type policies;
+ IteratorT first = first_;
+ scanner_type scan(first, last, policies);
+ tree_match<IteratorT, NodeFactoryT> hit = p.derived().parse(scan);
+ return tree_parse_info<IteratorT, NodeFactoryT>(
+ first, hit, hit && (first == last), hit.length(), hit.trees);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// The following parse function is defined here, to allow the separation of
+// the compilation of the cpp_grammar from the function using it.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0
+#define BOOST_WAVE_GRAMMAR_GEN_INLINE
+#else
+#define BOOST_WAVE_GRAMMAR_GEN_INLINE inline
+#endif
+
+template <typename LexIteratorT, typename TokenContainerT>
+BOOST_WAVE_GRAMMAR_GEN_INLINE
+boost::spirit::classic::tree_parse_info<
+ LexIteratorT,
+ typename cpp_grammar_gen<LexIteratorT, TokenContainerT>::node_factory_type
+>
+cpp_grammar_gen<LexIteratorT, TokenContainerT>::parse_cpp_grammar (
+ LexIteratorT const &first, LexIteratorT const &last,
+ position_type const &act_pos, bool &found_eof,
+ token_type &found_directive, token_container_type &found_eoltokens)
+{
+ using namespace boost::spirit::classic;
+ using namespace boost::wave;
+
+ cpp_grammar<token_type, TokenContainerT> g(found_eof, found_directive, found_eoltokens);
+ tree_parse_info<LexIteratorT, node_factory_type> hit =
+ parsetree_parse<node_factory_type>(first, last, g);
+
+#if BOOST_WAVE_DUMP_PARSE_TREE != 0
+ if (hit.match) {
+ tree_to_xml (BOOST_WAVE_DUMP_PARSE_TREE_OUT, hit.trees, "",
+ g.map_rule_id_to_name, &token_type::get_token_id,
+ &token_type::get_token_value);
+ }
+#endif
+
+ return hit;
+}
+
+#undef BOOST_WAVE_GRAMMAR_GEN_INLINE
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace grammars
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_GRAMMAR_HPP_FEAEBC2E_2734_428B_A7CA_85E5A415E23E_INCLUDED)
diff --git a/boost/wave/grammars/cpp_grammar_gen.hpp b/boost/wave/grammars/cpp_grammar_gen.hpp
new file mode 100644
index 0000000000..d582a07144
--- /dev/null
+++ b/boost/wave/grammars/cpp_grammar_gen.hpp
@@ -0,0 +1,110 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_GRAMMAR_GEN_HPP_80CB8A59_5411_4E45_B406_62531A12FB99_INCLUDED)
+#define CPP_GRAMMAR_GEN_HPP_80CB8A59_5411_4E45_B406_62531A12FB99_INCLUDED
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/wave/language_support.hpp>
+
+#include <boost/spirit/include/classic_nil.hpp>
+#include <boost/spirit/include/classic_parse_tree.hpp>
+
+#include <boost/pool/pool_alloc.hpp>
+
+// this must occur after all of the includes and before any code appears
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_PREFIX
+#endif
+
+// suppress warnings about dependent classes not being exported from the dll
+#ifdef BOOST_MSVC
+#pragma warning(push)
+#pragma warning(disable : 4251 4231 4660)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+namespace boost {
+namespace wave {
+namespace grammars {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Here are the node id's of the different node of the cpp_grammar
+//
+///////////////////////////////////////////////////////////////////////////////
+#define BOOST_WAVE_PP_STATEMENT_ID 1
+#define BOOST_WAVE_INCLUDE_FILE_ID 2
+#define BOOST_WAVE_SYSINCLUDE_FILE_ID 3
+#define BOOST_WAVE_MACROINCLUDE_FILE_ID 4
+#define BOOST_WAVE_PLAIN_DEFINE_ID 5
+#define BOOST_WAVE_MACRO_PARAMETERS_ID 6
+#define BOOST_WAVE_MACRO_DEFINITION_ID 7
+#define BOOST_WAVE_UNDEFINE_ID 8
+#define BOOST_WAVE_IFDEF_ID 9
+#define BOOST_WAVE_IFNDEF_ID 10
+#define BOOST_WAVE_IF_ID 11
+#define BOOST_WAVE_ELIF_ID 12
+#define BOOST_WAVE_ELSE_ID 13
+#define BOOST_WAVE_ENDIF_ID 14
+#define BOOST_WAVE_LINE_ID 15
+#define BOOST_WAVE_ERROR_ID 16
+#define BOOST_WAVE_WARNING_ID 17
+#define BOOST_WAVE_PRAGMA_ID 18
+#define BOOST_WAVE_ILLFORMED_ID 19
+#define BOOST_WAVE_PPSPACE_ID 20
+#define BOOST_WAVE_PPQUALIFIEDNAME_ID 21
+#define BOOST_WAVE_REGION_ID 22
+#define BOOST_WAVE_ENDREGION_ID 23
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// cpp_grammar_gen template class
+//
+// This template helps separating the compilation of the cpp_grammar
+// class from the compilation of the main pp_iterator. This is done to
+// safe compilation time.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename LexIteratorT, typename TokenContainerT>
+struct BOOST_WAVE_DECL cpp_grammar_gen
+{
+ typedef LexIteratorT iterator_type;
+ typedef typename LexIteratorT::token_type token_type;
+ typedef TokenContainerT token_container_type;
+ typedef typename token_type::position_type position_type;
+ typedef boost::spirit::classic::node_val_data_factory<
+// boost::spirit::nil_t,
+// boost::pool_allocator<boost::spirit::nil_t>
+ > node_factory_type;
+
+// parse the cpp_grammar and return the resulting parse tree
+ static boost::spirit::classic::tree_parse_info<iterator_type, node_factory_type>
+ parse_cpp_grammar (iterator_type const &first, iterator_type const &last,
+ position_type const &act_pos, bool &found_eof,
+ token_type &found_directive, token_container_type &found_eoltokens);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace grammars
+} // namespace wave
+} // namespace boost
+
+#ifdef BOOST_MSVC
+#pragma warning(pop)
+#endif
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_GRAMMAR_GEN_HPP_80CB8A59_5411_4E45_B406_62531A12FB99_INCLUDED)
diff --git a/boost/wave/grammars/cpp_intlit_grammar.hpp b/boost/wave/grammars/cpp_intlit_grammar.hpp
new file mode 100644
index 0000000000..96ac8f62c1
--- /dev/null
+++ b/boost/wave/grammars/cpp_intlit_grammar.hpp
@@ -0,0 +1,188 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_INTLIT_GRAMMAR_HPP_2E1E70B1_F15C_4132_8554_10A231B0D91C_INCLUDED)
+#define CPP_INTLIT_GRAMMAR_HPP_2E1E70B1_F15C_4132_8554_10A231B0D91C_INCLUDED
+
+#include <boost/wave/wave_config.hpp>
+
+#include <boost/spirit/include/classic_core.hpp>
+#include <boost/spirit/include/classic_closure.hpp>
+#include <boost/spirit/include/classic_assign_actor.hpp>
+#include <boost/spirit/include/classic_push_back_actor.hpp>
+
+#include <boost/spirit/include/phoenix1_operators.hpp>
+#include <boost/spirit/include/phoenix1_primitives.hpp>
+#include <boost/spirit/include/phoenix1_statements.hpp>
+
+#include <boost/wave/cpp_exceptions.hpp>
+#include <boost/wave/grammars/cpp_literal_grammar_gen.hpp>
+
+#if !defined(spirit_append_actor)
+#define spirit_append_actor(actor) boost::spirit::classic::push_back_a(actor)
+#define spirit_assign_actor(actor) boost::spirit::classic::assign_a(actor)
+#endif // !defined(spirit_append_actor)
+
+// this must occur after all of the includes and before any code appears
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_PREFIX
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Reusable grammar for parsing of C++ style integer literals
+//
+///////////////////////////////////////////////////////////////////////////////
+namespace boost {
+namespace wave {
+namespace grammars {
+
+///////////////////////////////////////////////////////////////////////////////
+namespace closures {
+
+ struct intlit_closure
+ : boost::spirit::classic::closure<intlit_closure, uint_literal_type>
+ {
+ member1 val;
+ };
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// define, whether the rule's should generate some debug output
+#define TRACE_INTLIT_GRAMMAR \
+ bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_INTLIT_GRAMMAR) \
+ /**/
+
+struct intlit_grammar :
+ boost::spirit::classic::grammar<intlit_grammar, closures::intlit_closure::context_t>
+{
+ intlit_grammar(bool &is_unsigned_) : is_unsigned(is_unsigned_)
+ {
+ BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "intlit_grammar",
+ TRACE_INTLIT_GRAMMAR);
+ }
+
+ template <typename ScannerT>
+ struct definition
+ {
+ typedef boost::spirit::classic::rule<ScannerT> rule_t;
+
+ rule_t int_lit;
+ boost::spirit::classic::subrule<0> sub_int_lit;
+ boost::spirit::classic::subrule<1> oct_lit;
+ boost::spirit::classic::subrule<2> hex_lit;
+ boost::spirit::classic::subrule<3> dec_lit;
+
+ definition(intlit_grammar const &self)
+ {
+ using namespace boost::spirit::classic;
+ namespace phx = phoenix;
+
+
+ int_lit = (
+ sub_int_lit =
+ ( ch_p('0')[self.val = 0] >> (hex_lit | oct_lit)
+ | dec_lit
+ )
+ >> !as_lower_d[
+ (ch_p('u')[phx::var(self.is_unsigned) = true] || ch_p('l'))
+ | (ch_p('l') || ch_p('u')[phx::var(self.is_unsigned) = true])
+ ]
+ ,
+
+ hex_lit =
+ (ch_p('X') | ch_p('x'))
+ >> uint_parser<uint_literal_type, 16>()
+ [
+ self.val = phx::arg1,
+ phx::var(self.is_unsigned) = true
+ ]
+ ,
+
+ oct_lit =
+ !uint_parser<uint_literal_type, 8>()
+ [
+ self.val = phx::arg1,
+ phx::var(self.is_unsigned) = true
+ ]
+ ,
+
+ dec_lit =
+ uint_parser<uint_literal_type, 10>()
+ [
+ self.val = phx::arg1
+ ]
+ )
+ ;
+
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(int_lit, TRACE_INTLIT_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(sub_int_lit, TRACE_INTLIT_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(hex_lit, TRACE_INTLIT_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(oct_lit, TRACE_INTLIT_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(dec_lit, TRACE_INTLIT_GRAMMAR);
+ }
+
+ // start rule of this grammar
+ rule_t const& start() const
+ { return int_lit; }
+ };
+
+ bool &is_unsigned;
+};
+
+#undef TRACE_INTLIT_GRAMMAR
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// The following function is defined here, to allow the separation of
+// the compilation of the intlit_grammar from the function using it.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0
+#define BOOST_WAVE_INTLITGRAMMAR_GEN_INLINE
+#else
+#define BOOST_WAVE_INTLITGRAMMAR_GEN_INLINE inline
+#endif
+
+template <typename TokenT>
+BOOST_WAVE_INTLITGRAMMAR_GEN_INLINE
+uint_literal_type
+intlit_grammar_gen<TokenT>::evaluate(TokenT const &token,
+ bool &is_unsigned)
+{
+ using namespace boost::spirit::classic;
+
+intlit_grammar g(is_unsigned);
+uint_literal_type result = 0;
+typename TokenT::string_type const &token_val = token.get_value();
+parse_info<typename TokenT::string_type::const_iterator> hit =
+ parse(token_val.begin(), token_val.end(), g[spirit_assign_actor(result)]);
+
+ if (!hit.hit) {
+ BOOST_WAVE_THROW(preprocess_exception, ill_formed_integer_literal,
+ token_val.c_str(), token.get_position());
+ }
+ return result;
+}
+
+#undef BOOST_WAVE_INTLITGRAMMAR_GEN_INLINE
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace grammars
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_INTLIT_GRAMMAR_HPP_2E1E70B1_F15C_4132_8554_10A231B0D91C_INCLUDED)
diff --git a/boost/wave/grammars/cpp_literal_grammar_gen.hpp b/boost/wave/grammars/cpp_literal_grammar_gen.hpp
new file mode 100644
index 0000000000..f6e24159bd
--- /dev/null
+++ b/boost/wave/grammars/cpp_literal_grammar_gen.hpp
@@ -0,0 +1,77 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_LITERAL_GRAMMAR_GEN_HPP_67794A6C_468A_4AAB_A757_DEDDB182F5A0_INCLUDED)
+#define CPP_LITERAL_GRAMMAR_GEN_HPP_67794A6C_468A_4AAB_A757_DEDDB182F5A0_INCLUDED
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/wave/grammars/cpp_value_error.hpp>
+
+// this must occur after all of the includes and before any code appears
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_PREFIX
+#endif
+
+// suppress warnings about dependent classes not being exported from the dll
+#ifdef BOOST_MSVC
+#pragma warning(push)
+#pragma warning(disable : 4251 4231 4660)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+namespace boost {
+namespace wave {
+namespace grammars {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// cpp_intlit_grammar_gen template class
+//
+// This template helps separating the compilation of the intlit_grammar
+// class from the compilation of the expression_grammar. This is done
+// to safe compilation time.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename TokenT>
+struct BOOST_WAVE_DECL intlit_grammar_gen {
+
+ static uint_literal_type evaluate(TokenT const &tok, bool &is_unsigned);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// cpp_chlit_grammar_gen template class
+//
+// This template helps separating the compilation of the chlit_grammar
+// class from the compilation of the expression_grammar. This is done
+// to safe compilation time.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename IntegralResult, typename TokenT>
+struct BOOST_WAVE_DECL chlit_grammar_gen {
+
+ static IntegralResult evaluate(TokenT const &tok, value_error& status);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace grammars
+} // namespace wave
+} // namespace boost
+
+#ifdef BOOST_MSVC
+#pragma warning(pop)
+#endif
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_LITERAL_GRAMMAR_GEN_HPP_67794A6C_468A_4AAB_A757_DEDDB182F5A0_INCLUDED)
diff --git a/boost/wave/grammars/cpp_predef_macros_gen.hpp b/boost/wave/grammars/cpp_predef_macros_gen.hpp
new file mode 100644
index 0000000000..4e66a53cbd
--- /dev/null
+++ b/boost/wave/grammars/cpp_predef_macros_gen.hpp
@@ -0,0 +1,80 @@
+/*=============================================================================
+ A Standard compliant C++ preprocessor
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_PREDEF_MACROS_GEN_HPP_CADB6D2C_76A4_4988_83E1_EFFC6902B9A2_INCLUDED)
+#define CPP_PREDEF_MACROS_GEN_HPP_CADB6D2C_76A4_4988_83E1_EFFC6902B9A2_INCLUDED
+
+#include <boost/spirit/include/classic_parse_tree.hpp>
+
+#include <boost/wave/wave_config.hpp>
+
+// this must occur after all of the includes and before any code appears
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_PREFIX
+#endif
+
+// suppress warnings about dependent classes not being exported from the dll
+#ifdef BOOST_MSVC
+#pragma warning(push)
+#pragma warning(disable : 4251 4231 4660)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+namespace boost {
+namespace wave {
+namespace grammars {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Here are the node id's of the different node of the cpp_grammar
+//
+///////////////////////////////////////////////////////////////////////////////
+#define BOOST_WAVE_PLAIN_DEFINE_ID 5
+#define BOOST_WAVE_MACRO_PARAMETERS_ID 6
+#define BOOST_WAVE_MACRO_DEFINITION_ID 7
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// predefined_macros_grammar_gen template class
+//
+// This template helps separating the compilation of the
+// predefined_macros_grammar class from the compilation of the
+// main pp_iterator. This is done to safe compilation time.
+//
+// This class helps parsing command line given macro definitions in a
+// similar way, as macros are parsed by the cpp_grammar class.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename LexIteratorT>
+struct BOOST_WAVE_DECL predefined_macros_grammar_gen
+{
+ typedef LexIteratorT iterator_type;
+
+// parse the cpp_grammar and return the resulting parse tree
+ static boost::spirit::classic::tree_parse_info<iterator_type>
+ parse_predefined_macro (iterator_type const &first, iterator_type const &last);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace grammars
+} // namespace wave
+} // namespace boost
+
+#ifdef BOOST_MSVC
+#pragma warning(pop)
+#endif
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_PREDEF_MACROS_GEN_HPP_CADB6D2C_76A4_4988_83E1_EFFC6902B9A2_INCLUDED)
diff --git a/boost/wave/grammars/cpp_predef_macros_grammar.hpp b/boost/wave/grammars/cpp_predef_macros_grammar.hpp
new file mode 100644
index 0000000000..9d35a2f461
--- /dev/null
+++ b/boost/wave/grammars/cpp_predef_macros_grammar.hpp
@@ -0,0 +1,178 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_PREDEF_MACROS_GRAMMAR_HPP_53858C9A_C202_4D60_AD92_DC9CAE4DBB43_INCLUDED)
+#define CPP_PREDEF_MACROS_GRAMMAR_HPP_53858C9A_C202_4D60_AD92_DC9CAE4DBB43_INCLUDED
+
+#include <boost/spirit/include/classic_core.hpp>
+#include <boost/spirit/include/classic_parse_tree.hpp>
+#include <boost/spirit/include/classic_confix.hpp>
+#include <boost/spirit/include/classic_lists.hpp>
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/wave/token_ids.hpp>
+#include <boost/wave/grammars/cpp_predef_macros_gen.hpp>
+#include <boost/wave/util/pattern_parser.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 {
+namespace grammars {
+
+///////////////////////////////////////////////////////////////////////////////
+// define, whether the rule's should generate some debug output
+#define TRACE_PREDEF_MACROS_GRAMMAR \
+ bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_PREDEF_MACROS_GRAMMAR) \
+ /**/
+
+///////////////////////////////////////////////////////////////////////////////
+// Encapsulation of the grammar for command line driven predefined macros.
+struct predefined_macros_grammar :
+ public boost::spirit::classic::grammar<predefined_macros_grammar>
+{
+ template <typename ScannerT>
+ struct definition
+ {
+ // 'normal' (parse_tree generating) rule type
+ typedef boost::spirit::classic::rule<
+ ScannerT, boost::spirit::classic::dynamic_parser_tag>
+ rule_type;
+
+ rule_type plain_define, macro_definition, macro_parameters;
+
+ definition(predefined_macros_grammar const &/*self*/)
+ {
+ // import the spirit and cpplexer namespaces here
+ using namespace boost::spirit::classic;
+ using namespace boost::wave;
+ using namespace boost::wave::util;
+
+ // set the rule id's for later use
+ plain_define.set_id(BOOST_WAVE_PLAIN_DEFINE_ID);
+ macro_parameters.set_id(BOOST_WAVE_MACRO_PARAMETERS_ID);
+ macro_definition.set_id(BOOST_WAVE_MACRO_DEFINITION_ID);
+
+ // recognizes command line defined macro syntax, i.e.
+ // -DMACRO
+ // -DMACRO=
+ // -DMACRO=value
+ // -DMACRO(x)
+ // -DMACRO(x)=
+ // -DMACRO(x)=value
+
+ // This grammar resembles the overall structure of the cpp_grammar to
+ // make it possible to reuse the parse tree traversal code
+ plain_define
+ = ( ch_p(T_IDENTIFIER)
+ | pattern_p(KeywordTokenType,
+ TokenTypeMask|PPTokenFlag)
+ | pattern_p(OperatorTokenType|AltExtTokenType,
+ ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc.
+ | pattern_p(BoolLiteralTokenType,
+ TokenTypeMask|PPTokenFlag) // true/false
+ )
+ >> !macro_parameters
+ >> !macro_definition
+ ;
+
+ // parameter list
+ macro_parameters
+ = confix_p(
+ no_node_d[ch_p(T_LEFTPAREN) >> *ch_p(T_SPACE)],
+ !list_p(
+ ( ch_p(T_IDENTIFIER)
+ | pattern_p(KeywordTokenType,
+ TokenTypeMask|PPTokenFlag)
+ | pattern_p(OperatorTokenType|AltExtTokenType,
+ ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc.
+ | pattern_p(BoolLiteralTokenType,
+ TokenTypeMask|PPTokenFlag) // true/false
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ | ch_p(T_ELLIPSIS)
+#endif
+ ),
+ no_node_d
+ [
+ *ch_p(T_SPACE) >> ch_p(T_COMMA) >> *ch_p(T_SPACE)
+ ]
+ ),
+ no_node_d[*ch_p(T_SPACE) >> ch_p(T_RIGHTPAREN)]
+ )
+ ;
+
+ // macro body (anything left until eol)
+ macro_definition
+ = no_node_d[ch_p(T_ASSIGN)]
+ >> *anychar_p
+ ;
+
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(plain_define, TRACE_PREDEF_MACROS_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_definition, TRACE_PREDEF_MACROS_GRAMMAR);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_parameters, TRACE_PREDEF_MACROS_GRAMMAR);
+ }
+
+ // start rule of this grammar
+ rule_type const& start() const
+ { return plain_define; }
+ };
+
+ predefined_macros_grammar()
+ {
+ BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this,
+ "predefined_macros_grammar", TRACE_PREDEF_MACROS_GRAMMAR);
+ }
+
+};
+
+///////////////////////////////////////////////////////////////////////////////
+#undef TRACE_PREDEF_MACROS_GRAMMAR
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// The following parse function is defined here, to allow the separation of
+// the compilation of the cpp_predefined_macros_grammar from the function
+// using it.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0
+#define BOOST_WAVE_PREDEF_MACROS_GRAMMAR_GEN_INLINE
+#else
+#define BOOST_WAVE_PREDEF_MACROS_GRAMMAR_GEN_INLINE inline
+#endif
+
+template <typename LexIteratorT>
+BOOST_WAVE_PREDEF_MACROS_GRAMMAR_GEN_INLINE
+boost::spirit::classic::tree_parse_info<LexIteratorT>
+predefined_macros_grammar_gen<LexIteratorT>::parse_predefined_macro (
+ LexIteratorT const &first, LexIteratorT const &last)
+{
+ predefined_macros_grammar g;
+ return boost::spirit::classic::pt_parse (first, last, g);
+}
+
+#undef BOOST_WAVE_PREDEF_MACROS_GRAMMAR_GEN_INLINE
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace grammars
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_PREDEF_MACROS_GRAMMAR_HPP_53858C9A_C202_4D60_AD92_DC9CAE4DBB43_INCLUDED)
diff --git a/boost/wave/grammars/cpp_value_error.hpp b/boost/wave/grammars/cpp_value_error.hpp
new file mode 100644
index 0000000000..9cba99a264
--- /dev/null
+++ b/boost/wave/grammars/cpp_value_error.hpp
@@ -0,0 +1,51 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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(BOOST_WAVE_CPP_VALUE_ERROR_INCLUDED)
+#define BOOST_WAVE_CPP_VALUE_ERROR_INCLUDED
+
+#include <boost/wave/wave_config.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 {
+namespace grammars {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// value_error enum type
+//
+// This is used to encode any error occurred during the evaluation of a
+// conditional preprocessor expression
+//
+///////////////////////////////////////////////////////////////////////////////
+enum value_error {
+ error_noerror = 0x0,
+ error_division_by_zero = 0x1,
+ error_integer_overflow = 0x2,
+ error_character_overflow = 0x4
+};
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace grammars
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(BOOST_WAVE_CPP_VALUE_ERROR_INCLUDED)
diff --git a/boost/wave/language_support.hpp b/boost/wave/language_support.hpp
new file mode 100644
index 0000000000..f4e599894a
--- /dev/null
+++ b/boost/wave/language_support.hpp
@@ -0,0 +1,215 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+ Definition of the various language support constants
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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(LANGUAGE_SUPPORT_HPP_93EDD057_2DEF_44BC_BC9F_FDABB9F51AFA_INCLUDED)
+#define LANGUAGE_SUPPORT_HPP_93EDD057_2DEF_44BC_BC9F_FDABB9F51AFA_INCLUDED
+
+#include <boost/wave/wave_config.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 {
+
+enum language_support {
+// support flags for C++98
+ support_normal = 0x01,
+ support_cpp = support_normal,
+
+ support_option_long_long = 0x02,
+
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+// support flags for C99
+ support_option_variadics = 0x04,
+ support_c99 = support_option_variadics | support_option_long_long | 0x08,
+#endif
+#if BOOST_WAVE_SUPPORT_CPP0X != 0
+ support_cpp0x = support_option_variadics | support_option_long_long | 0x10,
+#endif
+
+ support_option_mask = 0xFFB0,
+ support_option_emit_contnewlines = 0x0040,
+ support_option_insert_whitespace = 0x0080,
+ support_option_preserve_comments = 0x0100,
+ support_option_no_character_validation = 0x0200,
+ support_option_convert_trigraphs = 0x0400,
+ support_option_single_line = 0x0800,
+ support_option_prefer_pp_numbers = 0x1000,
+ support_option_emit_line_directives = 0x2000,
+ support_option_include_guard_detection = 0x4000,
+ support_option_emit_pragma_directives = 0x8000
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// need_cpp
+//
+// Extract, if the language to support is C++98
+//
+///////////////////////////////////////////////////////////////////////////////
+inline bool
+need_cpp(language_support language)
+{
+ return (language & ~support_option_mask) == support_cpp;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// need_cpp0x
+//
+// Extract, if the language to support is C++0x
+//
+///////////////////////////////////////////////////////////////////////////////
+#if BOOST_WAVE_SUPPORT_CPP0X != 0
+
+inline bool
+need_cpp0x(language_support language)
+{
+ return (language & ~support_option_mask) == support_cpp0x;
+}
+
+#else
+
+inline bool
+need_cpp0x(language_support language)
+{
+ return false;
+}
+
+#endif
+
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+///////////////////////////////////////////////////////////////////////////////
+//
+// need_c99
+//
+// Extract, if the language to support is C99
+//
+///////////////////////////////////////////////////////////////////////////////
+inline bool
+need_c99(language_support language)
+{
+ return (language & ~support_option_mask) == support_c99;
+}
+
+#else // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+
+///////////////////////////////////////////////////////////////////////////////
+inline bool
+need_variadics(language_support language)
+{
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+inline language_support
+enable_variadics(language_support language, bool enable = true)
+{
+ return language;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+inline bool
+need_c99(language_support language)
+{
+ return false;
+}
+
+#endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// get_support_options
+//
+// Set preserve comments support in the language to support
+//
+///////////////////////////////////////////////////////////////////////////////
+inline language_support
+get_support_options(language_support language)
+{
+ return static_cast<language_support>(language & support_option_mask);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// set_support_options
+//
+// Set language option (for fine tuning of lexer behavior)
+//
+///////////////////////////////////////////////////////////////////////////////
+inline language_support
+set_support_options(language_support language, language_support option)
+{
+ return static_cast<language_support>(
+ (language & ~support_option_mask) | (option & support_option_mask));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Get and set different language options
+#define BOOST_WAVE_NEED_OPTION(option) \
+ inline bool need_ ## option(language_support language) \
+ { \
+ return (language & support_option_ ## option) ? true : false; \
+ } \
+ /**/
+
+#define BOOST_WAVE_ENABLE_OPTION(option) \
+ inline language_support \
+ enable_ ## option(language_support language, bool enable = true) \
+ { \
+ if (enable) \
+ return static_cast<language_support>(language | support_option_ ## option); \
+ return static_cast<language_support>(language & ~support_option_ ## option); \
+ } \
+ /**/
+
+#define BOOST_WAVE_OPTION(option) \
+ BOOST_WAVE_NEED_OPTION(option) \
+ BOOST_WAVE_ENABLE_OPTION(option) \
+ /**/
+
+///////////////////////////////////////////////////////////////////////////////
+BOOST_WAVE_OPTION(long_long) // support_option_long_long
+BOOST_WAVE_OPTION(no_character_validation) // support_option_no_character_validation
+BOOST_WAVE_OPTION(preserve_comments) // support_option_preserve_comments
+BOOST_WAVE_OPTION(prefer_pp_numbers) // support_option_prefer_pp_numbers
+BOOST_WAVE_OPTION(emit_line_directives) // support_option_emit_line_directives
+BOOST_WAVE_OPTION(single_line) // support_option_single_line
+BOOST_WAVE_OPTION(convert_trigraphs) // support_option_convert_trigraphs
+#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+BOOST_WAVE_OPTION(include_guard_detection) // support_option_include_guard_detection
+#endif
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+BOOST_WAVE_OPTION(variadics) // support_option_variadics
+#endif
+#if BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES != 0
+BOOST_WAVE_OPTION(emit_pragma_directives) // support_option_emit_pragma_directives
+#endif
+BOOST_WAVE_OPTION(insert_whitespace) // support_option_insert_whitespace
+BOOST_WAVE_OPTION(emit_contnewlines) // support_option_emit_contnewlines
+
+#undef BOOST_WAVE_NEED_OPTION
+#undef BOOST_WAVE_ENABLE_OPTION
+#undef BOOST_WAVE_OPTION
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(LANGUAGE_SUPPORT_HPP_93EDD057_2DEF_44BC_BC9F_FDABB9F51AFA_INCLUDED)
diff --git a/boost/wave/preprocessing_hooks.hpp b/boost/wave/preprocessing_hooks.hpp
new file mode 100644
index 0000000000..b57311323b
--- /dev/null
+++ b/boost/wave/preprocessing_hooks.hpp
@@ -0,0 +1,818 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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(DEFAULT_PREPROCESSING_HOOKS_HPP_INCLUDED)
+#define DEFAULT_PREPROCESSING_HOOKS_HPP_INCLUDED
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/wave/util/cpp_include_paths.hpp>
+
+#include <vector>
+
+// 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 {
+namespace context_policies {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// The default_preprocessing_hooks class is a placeholder for all
+// preprocessing hooks called from inside the preprocessing engine
+//
+///////////////////////////////////////////////////////////////////////////////
+struct default_preprocessing_hooks
+{
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'expanding_function_like_macro' is called, whenever a
+ // function-like macro is to be expanded.
+ //
+ // The parameter 'macrodef' marks the position, where the macro to expand
+ // is defined.
+ //
+ // The parameter 'formal_args' holds the formal arguments used during the
+ // definition of the macro.
+ //
+ // The parameter 'definition' holds the macro definition for the macro to
+ // trace.
+ //
+ // The parameter 'macro_call' marks the position, where this macro invoked.
+ //
+ // The parameter 'arguments' holds the macro arguments used during the
+ // invocation of the macro
+ //
+ // The parameters 'seqstart' and 'seqend' point into the input token
+ // stream allowing to access the whole token sequence comprising the macro
+ // invocation (starting with the opening parenthesis and ending after the
+ // closing one).
+ //
+ // The return value defines whether the corresponding macro will be
+ // expanded (return false) or will be copied to the output (return true).
+ // Note: the whole argument list is copied unchanged to the output as well
+ // without any further processing.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ // old signature
+ template <typename TokenT, typename ContainerT>
+ void expanding_function_like_macro(
+ TokenT const& macrodef, std::vector<TokenT> const& formal_args,
+ ContainerT const& definition,
+ TokenT const& macrocall, std::vector<ContainerT> const& arguments)
+ {}
+#else
+ // new signature
+ template <typename ContextT, typename TokenT, typename ContainerT, typename IteratorT>
+ bool
+ expanding_function_like_macro(ContextT const& ctx,
+ TokenT const& macrodef, std::vector<TokenT> const& formal_args,
+ ContainerT const& definition,
+ TokenT const& macrocall, std::vector<ContainerT> const& arguments,
+ IteratorT const& seqstart, IteratorT const& seqend)
+ { return false; } // default is to normally expand the macro
+#endif
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'expanding_object_like_macro' is called, whenever a
+ // object-like macro is to be expanded .
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ // The parameter 'macro' marks the position, where the macro to expand
+ // is defined.
+ //
+ // The definition 'definition' holds the macro definition for the macro to
+ // trace.
+ //
+ // The parameter 'macrocall' marks the position, where this macro invoked.
+ //
+ // The return value defines whether the corresponding macro will be
+ // expanded (return false) or will be copied to the output (return true).
+ //
+ ///////////////////////////////////////////////////////////////////////////
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ // old signature
+ template <typename TokenT, typename ContainerT>
+ void expanding_object_like_macro(TokenT const& macro,
+ ContainerT const& definition, TokenT const& macrocall)
+ {}
+#else
+ // new signature
+ template <typename ContextT, typename TokenT, typename ContainerT>
+ bool
+ expanding_object_like_macro(ContextT const& ctx, TokenT const& macro,
+ ContainerT const& definition, TokenT const& macrocall)
+ { return false; } // default is to normally expand the macro
+#endif
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'expanded_macro' is called, whenever the expansion of a
+ // macro is finished but before the rescanning process starts.
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ // The parameter 'result' contains the token sequence generated as the
+ // result of the macro expansion.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ // old signature
+ template <typename ContainerT>
+ void expanded_macro(ContainerT const& result)
+ {}
+#else
+ // new signature
+ template <typename ContextT, typename ContainerT>
+ void expanded_macro(ContextT const& ctx, ContainerT const& result)
+ {}
+#endif
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'rescanned_macro' is called, whenever the rescanning of a
+ // macro is finished.
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ // The parameter 'result' contains the token sequence generated as the
+ // result of the rescanning.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ // old signature
+ template <typename ContainerT>
+ void rescanned_macro(ContainerT const& result)
+ {}
+#else
+ // new signature
+ template <typename ContextT, typename ContainerT>
+ void rescanned_macro(ContextT const& ctx, ContainerT const& result)
+ {}
+#endif
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'locate_include_file' is called, whenever a #include
+ // directive was encountered. It is supposed to locate the given file and
+ // should return the full file name of the located file. This file name
+ // is expected to uniquely identify the referenced file.
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ // The parameter 'file_path' contains the (expanded) file name found after
+ // the #include directive. This parameter holds the string as it is
+ // specified in the #include directive, i.e. <file> or "file" will result
+ // in a parameter value 'file'.
+ //
+ // The parameter 'is_system' is set to 'true' if this call happens as a
+ // result of a #include '<file>' directive, it is 'false' otherwise, i.e.
+ // for #include "file" directives.
+ //
+ // The parameter 'current_name' is only used if a #include_next directive
+ // was encountered (and BOOST_WAVE_SUPPORT_INCLUDE_NEXT was defined to be
+ // non-zero). In this case it points to unique full name of the current
+ // include file (if any). Otherwise this parameter is set to NULL.
+ //
+ // The parameter 'dir_path' on return is expected to hold the directory
+ // part of the located file.
+ //
+ // The parameter 'native_name' on return is expected to hold the unique
+ // full file name of the located file.
+ //
+ // The return value defines whether the file was located successfully.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename ContextT>
+ bool
+ locate_include_file(ContextT& ctx, std::string &file_path,
+ bool is_system, char const *current_name, std::string &dir_path,
+ std::string &native_name)
+ {
+ if (!ctx.find_include_file (file_path, dir_path, is_system, current_name))
+ return false; // could not locate file
+
+ namespace fs = boost::filesystem;
+
+ fs::path native_path(wave::util::create_path(file_path));
+ if (!fs::exists(native_path)) {
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_file,
+ file_path.c_str(), ctx.get_main_pos());
+ return false;
+ }
+
+ // return the unique full file system path of the located file
+ native_name = wave::util::native_file_string(native_path);
+
+ return true; // include file has been located successfully
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'found_include_directive' is called, whenever a #include
+ // directive was located.
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ // The parameter 'filename' contains the (expanded) file name found after
+ // the #include directive. This has the format '<file>', '"file"' or
+ // 'file'.
+ // The formats '<file>' or '"file"' are used for #include directives found
+ // in the preprocessed token stream, the format 'file' is used for files
+ // specified through the --force_include command line argument.
+ //
+ // The parameter 'include_next' is set to true if the found directive was
+ // a #include_next directive and the BOOST_WAVE_SUPPORT_INCLUDE_NEXT
+ // preprocessing constant was defined to something != 0.
+ //
+ // The return value defines whether the found file will be included
+ // (return false) or will be skipped (return true).
+ //
+ ///////////////////////////////////////////////////////////////////////////
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ // old signature
+ void
+ found_include_directive(std::string const& filename, bool include_next)
+ {}
+#else
+ // new signature
+ template <typename ContextT>
+ bool
+ found_include_directive(ContextT const& ctx, std::string const& filename,
+ bool include_next)
+ {
+ return false; // ok to include this file
+ }
+#endif
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'opened_include_file' is called, whenever a file referred
+ // by an #include directive was successfully located and opened.
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ // The parameter 'filename' contains the file system path of the
+ // opened file (this is relative to the directory of the currently
+ // processed file or a absolute path depending on the paths given as the
+ // include search paths).
+ //
+ // The include_depth parameter contains the current include file depth.
+ //
+ // The is_system_include parameter denotes whether the given file was
+ // found as a result of a #include <...> directive.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ // old signature
+ void
+ opened_include_file(std::string const& relname, std::string const& absname,
+ std::size_t include_depth, bool is_system_include)
+ {}
+#else
+ // new signature
+ template <typename ContextT>
+ void
+ opened_include_file(ContextT const& ctx, std::string const& relname,
+ std::string const& absname, bool is_system_include)
+ {}
+#endif
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'returning_from_include_file' is called, whenever an
+ // included file is about to be closed after it's processing is complete.
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ // old signature
+ void
+ returning_from_include_file()
+ {}
+#else
+ // new signature
+ template <typename ContextT>
+ void
+ returning_from_include_file(ContextT const& ctx)
+ {}
+#endif
+
+#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'detected_include_guard' is called whenever either a
+ // include file is about to be added to the list of #pragma once headers.
+ // That means this header file will not be opened and parsed again even
+ // if it is specified in a later #include directive.
+ // This function is called as the result of a detected include guard
+ // scheme.
+ //
+ // The implemented heuristics for include guards detects two forms of
+ // include guards:
+ //
+ // #ifndef INCLUDE_GUARD_MACRO
+ // #define INCLUDE_GUARD_MACRO
+ // ...
+ // #endif
+ //
+ // or
+ //
+ // if !defined(INCLUDE_GUARD_MACRO)
+ // #define INCLUDE_GUARD_MACRO
+ // ...
+ // #endif
+ //
+ // note, that the parenthesis are optional (i.e. !defined INCLUDE_GUARD_MACRO
+ // will work as well). The code allows for any whitespace, newline and single
+ // '#' tokens before the #if/#ifndef and after the final #endif.
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ // The parameter 'filename' contains the file system path of the
+ // opened file (this is relative to the directory of the currently
+ // processed file or a absolute path depending on the paths given as the
+ // include search paths).
+ //
+ // The parameter contains the name of the detected include guard.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename ContextT>
+ void
+ detected_include_guard(ContextT const& ctx, std::string const& filename,
+ std::string const& include_guard)
+ {}
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'detected_pragma_once' is called whenever either a
+ // include file is about to be added to the list of #pragma once headers.
+ // That means this header file will not be opened and parsed again even
+ // if it is specified in a later #include directive.
+ // This function is called as the result of a detected directive
+ // #pragma once.
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ // The parameter pragma_token refers to the token "#pragma" triggering
+ // this preprocessing hook.
+ //
+ // The parameter 'filename' contains the file system path of the
+ // opened file (this is relative to the directory of the currently
+ // processed file or a absolute path depending on the paths given as the
+ // include search paths).
+ //
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename ContextT, typename TokenT>
+ void
+ detected_pragma_once(ContextT const& ctx, TokenT const& pragma_token,
+ std::string const& filename)
+ {}
+#endif
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'interpret_pragma' is called, whenever a '#pragma command'
+ // directive is found which isn't known to the core Wave library, where
+ // 'command' is the value defined as the BOOST_WAVE_PRAGMA_KEYWORD constant
+ // which defaults to "wave".
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ // The parameter 'pending' may be used to push tokens back into the input
+ // stream, which are to be used as the replacement text for the whole
+ // #pragma directive.
+ //
+ // The parameter 'option' contains the name of the interpreted pragma.
+ //
+ // The parameter 'values' holds the values of the parameter provided to
+ // the pragma operator.
+ //
+ // The parameter 'act_token' contains the actual #pragma token, which may
+ // be used for error output.
+ //
+ // If the return value is 'false', the whole #pragma directive is
+ // interpreted as unknown and a corresponding error message is issued. A
+ // return value of 'true' signs a successful interpretation of the given
+ // #pragma.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename ContextT, typename ContainerT>
+ bool
+ interpret_pragma(ContextT const& ctx, ContainerT &pending,
+ typename ContextT::token_type const& option, ContainerT const& values,
+ typename ContextT::token_type const& act_token)
+ {
+ return false;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'emit_line_directive' is called whenever a #line directive
+ // has to be emitted into the generated output.
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ // The parameter 'pending' may be used to push tokens back into the input
+ // stream, which are to be used instead of the default output generated
+ // for the #line directive.
+ //
+ // The parameter 'act_token' contains the actual #pragma token, which may
+ // be used for error output. The line number stored in this token can be
+ // used as the line number emitted as part of the #line directive.
+ //
+ // If the return value is 'false', a default #line directive is emitted
+ // by the library. A return value of 'true' will inhibit any further
+ // actions, the tokens contained in 'pending' will be copied verbatim
+ // to the output.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename ContextT, typename ContainerT>
+ bool
+ emit_line_directive(ContextT const& ctx, ContainerT &pending,
+ typename ContextT::token_type const& act_token)
+ {
+ return false;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'defined_macro' is called, whenever a macro was defined
+ // successfully.
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ // The parameter 'name' is a reference to the token holding the macro name.
+ //
+ // The parameter 'is_functionlike' is set to true, whenever the newly
+ // defined macro is defined as a function like macro.
+ //
+ // The parameter 'parameters' holds the parameter tokens for the macro
+ // definition. If the macro has no parameters or if it is a object like
+ // macro, then this container is empty.
+ //
+ // The parameter 'definition' contains the token sequence given as the
+ // replacement sequence (definition part) of the newly defined macro.
+ //
+ // The parameter 'is_predefined' is set to true for all macros predefined
+ // during the initialization phase of the library.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ // old signature
+ template <typename TokenT, typename ParametersT, typename DefinitionT>
+ void
+ defined_macro(TokenT const& macro_name, bool is_functionlike,
+ ParametersT const& parameters, DefinitionT const& definition,
+ bool is_predefined)
+ {}
+#else
+ // new signature
+ template <
+ typename ContextT, typename TokenT, typename ParametersT,
+ typename DefinitionT
+ >
+ void
+ defined_macro(ContextT const& ctx, TokenT const& macro_name,
+ bool is_functionlike, ParametersT const& parameters,
+ DefinitionT const& definition, bool is_predefined)
+ {}
+#endif
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'undefined_macro' is called, whenever a macro definition
+ // was removed successfully.
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ // The parameter 'name' holds the name of the macro, which definition was
+ // removed.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ // old signature
+ template <typename TokenT>
+ void
+ undefined_macro(TokenT const& macro_name)
+ {}
+#else
+ // new signature
+ template <typename ContextT, typename TokenT>
+ void
+ undefined_macro(ContextT const& ctx, TokenT const& macro_name)
+ {}
+#endif
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'found_directive' is called, whenever a preprocessor
+ // directive was encountered, but before the corresponding action is
+ // executed.
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ // The parameter 'directive' is a reference to the token holding the
+ // preprocessing directive.
+ //
+ // The return value defines whether the given expression has to be
+ // to be executed in a normal way (return 'false'), or if it has to be
+ // skipped altogether (return 'true'), which means it gets replaced in the
+ // output by a single newline.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ // old signature
+ template <typename TokenT>
+ void
+ found_directive(TokenT const& directive)
+ {}
+#else
+ // new signature
+ template <typename ContextT, typename TokenT>
+ bool
+ found_directive(ContextT const& ctx, TokenT const& directive)
+ { return false; } // by default we never skip any directives
+#endif
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'found_unknown_directive' is called, whenever an unknown
+ // preprocessor directive was encountered.
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ // The parameter 'line' holds the tokens of the entire source line
+ // containing the unknown directive.
+ //
+ // The parameter 'pending' may be used to push tokens back into the input
+ // stream, which are to be used as the replacement text for the whole
+ // line containing the unknown directive.
+ //
+ // The return value defines whether the given expression has been
+ // properly interpreted by the hook function or not. If this function
+ // returns 'false', the library will raise an 'ill_formed_directive'
+ // preprocess_exception. Otherwise the tokens pushed back into 'pending'
+ // are passed on to the user program.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename ContextT, typename ContainerT>
+ bool
+ found_unknown_directive(ContextT const& ctx, ContainerT const& line,
+ ContainerT& pending)
+ { return false; } // by default we never interpret unknown directives
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'evaluated_conditional_expression' is called, whenever a
+ // conditional preprocessing expression was evaluated (the expression
+ // given to a #if, #elif, #ifdef or #ifndef directive)
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ // The parameter 'directive' is a reference to the token holding the
+ // corresponding preprocessing directive.
+ //
+ // The parameter 'expression' holds the non-expanded token sequence
+ // comprising the evaluated expression.
+ //
+ // The parameter expression_value contains the result of the evaluation of
+ // the expression in the current preprocessing context.
+ //
+ // The return value defines whether the given expression has to be
+ // evaluated again, allowing to decide which of the conditional branches
+ // should be expanded. You need to return 'true' from this hook function
+ // to force the expression to be re-evaluated.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ // old signature
+ template <typename ContainerT>
+ void
+ evaluated_conditional_expression(ContainerT const& expression,
+ bool expression_value)
+ {}
+#else
+ // new signature
+ template <typename ContextT, typename TokenT, typename ContainerT>
+ bool
+ evaluated_conditional_expression(ContextT const& ctx,
+ TokenT const& directive, ContainerT const& expression,
+ bool expression_value)
+ { return false; } // ok to continue, do not re-evaluate expression
+#endif
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'skipped_token' is called, whenever a token is about to be
+ // skipped due to a false preprocessor condition (code fragments to be
+ // skipped inside the not evaluated conditional #if/#else/#endif branches).
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ // The parameter 'token' refers to the token to be skipped.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ // old signature
+ template <typename TokenT>
+ void
+ skipped_token(TokenT const& token)
+ {}
+#else
+ // new signature
+ template <typename ContextT, typename TokenT>
+ void
+ skipped_token(ContextT const& ctx, TokenT const& token)
+ {}
+#endif
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'generated_token' will be called by the library whenever a
+ // token is about to be returned from the library.
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ // The parameter 't' is the token about to be returned from the library.
+ // This function may alter the token, but in this case it must be
+ // implemented with a corresponding signature:
+ //
+ // TokenT const&
+ // generated_token(ContextT const& ctx, TokenT& t);
+ //
+ // which makes it possible to modify the token in place.
+ //
+ // The default behavior is to return the token passed as the parameter
+ // without modification.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename ContextT, typename TokenT>
+ TokenT const&
+ generated_token(ContextT const& ctx, TokenT const& t)
+ { return t; }
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'may_skip_whitespace' will be called by the
+ // library, whenever it must be tested whether a specific token refers to
+ // whitespace and this whitespace has to be skipped.
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ // The 'token' parameter holds a reference to the current token. The policy
+ // is free to change this token if needed.
+ //
+ // The 'skipped_newline' parameter holds a reference to a boolean value
+ // which should be set to true by the policy function whenever a newline
+ // is going to be skipped.
+ //
+ // If the return value is true, the given token is skipped and the
+ // preprocessing continues to the next token. If the return value is
+ // false, the given token is returned to the calling application.
+ //
+ // ATTENTION!
+ // Caution has to be used, because by returning true the policy function
+ // is able to force skipping even significant tokens, not only whitespace.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename ContextT, typename TokenT>
+ bool
+ may_skip_whitespace(ContextT const& ctx, TokenT& token, bool& skipped_newline)
+ { return false; }
+
+#if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'found_warning_directive' will be called by the library
+ // whenever a #warning directive is found.
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ // The parameter 'message' references the argument token sequence of the
+ // encountered #warning directive.
+ //
+ // If the return value is false, the library throws a preprocessor
+ // exception of the type 'warning_directive', if the return value is true
+ // the execution continues as if no #warning directive has been found.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename ContextT, typename ContainerT>
+ bool
+ found_warning_directive(ContextT const& ctx, ContainerT const& message)
+ { return false; }
+#endif
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'found_error_directive' will be called by the library
+ // whenever a #error directive is found.
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ // The parameter 'message' references the argument token sequence of the
+ // encountered #error directive.
+ //
+ // If the return value is false, the library throws a preprocessor
+ // exception of the type 'error_directive', if the return value is true
+ // the execution continues as if no #error directive has been found.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename ContextT, typename ContainerT>
+ bool
+ found_error_directive(ContextT const& ctx, ContainerT const& message)
+ { return false; }
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'found_line_directive' will be called by the library
+ // whenever a #line directive is found.
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ // The parameter 'arguments' references the argument token sequence of the
+ // encountered #line directive.
+ //
+ // The parameter 'line' contains the recognized line number from the #line
+ // directive.
+ //
+ // The parameter 'filename' references the recognized file name from the
+ // #line directive (if there was one given).
+ //
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename ContextT, typename ContainerT>
+ void
+ found_line_directive(ContextT const& ctx, ContainerT const& arguments,
+ unsigned int line, std::string const& filename)
+ {}
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // The function 'throw_exception' will be called by the library whenever a
+ // preprocessing exception occurs.
+ //
+ // The parameter 'ctx' is a reference to the context object used for
+ // instantiating the preprocessing iterators by the user.
+ //
+ // The parameter 'e' is the exception object containing detailed error
+ // information.
+ //
+ // The default behavior is to call the function boost::throw_exception.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename ContextT, typename ExceptionT>
+ void
+ throw_exception(ContextT const& ctx, ExceptionT const& e)
+ {
+ boost::throw_exception(e);
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace context_policies
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(DEFAULT_PREPROCESSING_HOOKS_HPP_INCLUDED)
diff --git a/boost/wave/token_ids.hpp b/boost/wave/token_ids.hpp
new file mode 100644
index 0000000000..a2edba7e08
--- /dev/null
+++ b/boost/wave/token_ids.hpp
@@ -0,0 +1,378 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+ The definition of a default set of token identifiers and related
+ functions.
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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(TOKEN_IDS_HPP_414E9A58_F079_4789_8AFF_513815CE475B_INCLUDED)
+#define TOKEN_IDS_HPP_414E9A58_F079_4789_8AFF_513815CE475B_INCLUDED
+
+#include <string>
+
+#include <boost/wave/wave_config.hpp>
+
+// this must occur after all of the includes and before any code appears
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_PREFIX
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Allow external redefinition of the token identifiers to use
+#if !defined(BOOST_WAVE_TOKEN_IDS_DEFINED)
+#define BOOST_WAVE_TOKEN_IDS_DEFINED
+
+#if (defined (__FreeBSD__) || defined (__DragonFly__) || defined (__OpenBSD__)) && defined (T_DIVIDE)
+#undef T_DIVIDE
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+namespace boost {
+namespace wave {
+
+///////////////////////////////////////////////////////////////////////////////
+// assemble tokenids
+#define TOKEN_FROM_ID(id, cat) ((id) | (cat))
+#define ID_FROM_TOKEN(tok) ((tok) & ~TokenTypeMask)
+#define BASEID_FROM_TOKEN(tok) ((tok) & ~ExtTokenTypeMask)
+
+///////////////////////////////////////////////////////////////////////////////
+// the token_category helps to classify the different token types
+enum token_category {
+ IdentifierTokenType = 0x10080000,
+ ParameterTokenType = 0x11080000,
+ ExtParameterTokenType = 0x11180000,
+ KeywordTokenType = 0x20080000,
+ OperatorTokenType = 0x30080000,
+ LiteralTokenType = 0x40080000,
+ IntegerLiteralTokenType = 0x41080000,
+ FloatingLiteralTokenType = 0x42080000,
+ StringLiteralTokenType = 0x43080000,
+ CharacterLiteralTokenType = 0x44080000,
+ BoolLiteralTokenType = 0x45080000,
+ PPTokenType = 0x50080000,
+ PPConditionalTokenType = 0x50880000,
+
+ UnknownTokenType = 0xA0000000,
+ EOLTokenType = 0xB0000000,
+ EOFTokenType = 0xC0000000,
+ WhiteSpaceTokenType = 0xD0000000,
+ InternalTokenType = 0xE0080000,
+
+ TokenTypeMask = 0xFF000000,
+ AltTokenType = 0x00100000,
+ TriGraphTokenType = 0x00200000,
+ AltExtTokenType = 0x00500000, // and, bit_and etc.
+ PPTokenFlag = 0x00080000, // these are 'real' pp-tokens
+ ExtTokenTypeMask = 0xFFF00000,
+ ExtTokenOnlyMask = 0x00F00000,
+ TokenValueMask = 0x000FFFFF,
+ MainTokenMask = 0xFF0FFFFF // TokenTypeMask|TokenValueMask
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// the token_id assigns unique numbers to the different C++ lexemes
+enum token_id {
+ T_UNKNOWN = 0,
+ T_FIRST_TOKEN = 256,
+ T_AND = TOKEN_FROM_ID(T_FIRST_TOKEN, OperatorTokenType),
+ T_AND_ALT = TOKEN_FROM_ID(T_FIRST_TOKEN, OperatorTokenType|AltExtTokenType),
+ T_ANDAND = TOKEN_FROM_ID(257, OperatorTokenType),
+ T_ANDAND_ALT = TOKEN_FROM_ID(257, OperatorTokenType|AltExtTokenType),
+ T_ASSIGN = TOKEN_FROM_ID(258, OperatorTokenType),
+ T_ANDASSIGN = TOKEN_FROM_ID(259, OperatorTokenType),
+ T_ANDASSIGN_ALT = TOKEN_FROM_ID(259, OperatorTokenType|AltExtTokenType),
+ T_OR = TOKEN_FROM_ID(260, OperatorTokenType),
+ T_OR_ALT = TOKEN_FROM_ID(260, OperatorTokenType|AltExtTokenType),
+ T_OR_TRIGRAPH = TOKEN_FROM_ID(260, OperatorTokenType|TriGraphTokenType),
+ T_ORASSIGN = TOKEN_FROM_ID(261, OperatorTokenType),
+ T_ORASSIGN_ALT = TOKEN_FROM_ID(261, OperatorTokenType|AltExtTokenType),
+ T_ORASSIGN_TRIGRAPH = TOKEN_FROM_ID(261, OperatorTokenType|TriGraphTokenType),
+ T_XOR = TOKEN_FROM_ID(262, OperatorTokenType),
+ T_XOR_ALT = TOKEN_FROM_ID(262, OperatorTokenType|AltExtTokenType),
+ T_XOR_TRIGRAPH = TOKEN_FROM_ID(262, OperatorTokenType|TriGraphTokenType),
+ T_XORASSIGN = TOKEN_FROM_ID(263, OperatorTokenType),
+ T_XORASSIGN_ALT = TOKEN_FROM_ID(263, OperatorTokenType|AltExtTokenType),
+ T_XORASSIGN_TRIGRAPH = TOKEN_FROM_ID(263, OperatorTokenType|TriGraphTokenType),
+ T_COMMA = TOKEN_FROM_ID(264, OperatorTokenType),
+ T_COLON = TOKEN_FROM_ID(265, OperatorTokenType),
+ T_DIVIDE = TOKEN_FROM_ID(266, OperatorTokenType),
+ T_DIVIDEASSIGN = TOKEN_FROM_ID(267, OperatorTokenType),
+ T_DOT = TOKEN_FROM_ID(268, OperatorTokenType),
+ T_DOTSTAR = TOKEN_FROM_ID(269, OperatorTokenType),
+ T_ELLIPSIS = TOKEN_FROM_ID(270, OperatorTokenType),
+ T_EQUAL = TOKEN_FROM_ID(271, OperatorTokenType),
+ T_GREATER = TOKEN_FROM_ID(272, OperatorTokenType),
+ T_GREATEREQUAL = TOKEN_FROM_ID(273, OperatorTokenType),
+ T_LEFTBRACE = TOKEN_FROM_ID(274, OperatorTokenType),
+ T_LEFTBRACE_ALT = TOKEN_FROM_ID(274, OperatorTokenType|AltTokenType),
+ T_LEFTBRACE_TRIGRAPH = TOKEN_FROM_ID(274, OperatorTokenType|TriGraphTokenType),
+ T_LESS = TOKEN_FROM_ID(275, OperatorTokenType),
+ T_LESSEQUAL = TOKEN_FROM_ID(276, OperatorTokenType),
+ T_LEFTPAREN = TOKEN_FROM_ID(277, OperatorTokenType),
+ T_LEFTBRACKET = TOKEN_FROM_ID(278, OperatorTokenType),
+ T_LEFTBRACKET_ALT = TOKEN_FROM_ID(278, OperatorTokenType|AltTokenType),
+ T_LEFTBRACKET_TRIGRAPH = TOKEN_FROM_ID(278, OperatorTokenType|TriGraphTokenType),
+ T_MINUS = TOKEN_FROM_ID(279, OperatorTokenType),
+ T_MINUSASSIGN = TOKEN_FROM_ID(280, OperatorTokenType),
+ T_MINUSMINUS = TOKEN_FROM_ID(281, OperatorTokenType),
+ T_PERCENT = TOKEN_FROM_ID(282, OperatorTokenType),
+ T_PERCENTASSIGN = TOKEN_FROM_ID(283, OperatorTokenType),
+ T_NOT = TOKEN_FROM_ID(284, OperatorTokenType),
+ T_NOT_ALT = TOKEN_FROM_ID(284, OperatorTokenType|AltExtTokenType),
+ T_NOTEQUAL = TOKEN_FROM_ID(285, OperatorTokenType),
+ T_NOTEQUAL_ALT = TOKEN_FROM_ID(285, OperatorTokenType|AltExtTokenType),
+ T_OROR = TOKEN_FROM_ID(286, OperatorTokenType),
+ T_OROR_ALT = TOKEN_FROM_ID(286, OperatorTokenType|AltExtTokenType),
+ T_OROR_TRIGRAPH = TOKEN_FROM_ID(286, OperatorTokenType|TriGraphTokenType),
+ T_PLUS = TOKEN_FROM_ID(287, OperatorTokenType),
+ T_PLUSASSIGN = TOKEN_FROM_ID(288, OperatorTokenType),
+ T_PLUSPLUS = TOKEN_FROM_ID(289, OperatorTokenType),
+ T_ARROW = TOKEN_FROM_ID(290, OperatorTokenType),
+ T_ARROWSTAR = TOKEN_FROM_ID(291, OperatorTokenType),
+ T_QUESTION_MARK = TOKEN_FROM_ID(292, OperatorTokenType),
+ T_RIGHTBRACE = TOKEN_FROM_ID(293, OperatorTokenType),
+ T_RIGHTBRACE_ALT = TOKEN_FROM_ID(293, OperatorTokenType|AltTokenType),
+ T_RIGHTBRACE_TRIGRAPH = TOKEN_FROM_ID(293, OperatorTokenType|TriGraphTokenType),
+ T_RIGHTPAREN = TOKEN_FROM_ID(294, OperatorTokenType),
+ T_RIGHTBRACKET = TOKEN_FROM_ID(295, OperatorTokenType),
+ T_RIGHTBRACKET_ALT = TOKEN_FROM_ID(295, OperatorTokenType|AltTokenType),
+ T_RIGHTBRACKET_TRIGRAPH = TOKEN_FROM_ID(295, OperatorTokenType|TriGraphTokenType),
+ T_COLON_COLON = TOKEN_FROM_ID(296, OperatorTokenType),
+ T_SEMICOLON = TOKEN_FROM_ID(297, OperatorTokenType),
+ T_SHIFTLEFT = TOKEN_FROM_ID(298, OperatorTokenType),
+ T_SHIFTLEFTASSIGN = TOKEN_FROM_ID(299, OperatorTokenType),
+ T_SHIFTRIGHT = TOKEN_FROM_ID(300, OperatorTokenType),
+ T_SHIFTRIGHTASSIGN = TOKEN_FROM_ID(301, OperatorTokenType),
+ T_STAR = TOKEN_FROM_ID(302, OperatorTokenType),
+ T_COMPL = TOKEN_FROM_ID(303, OperatorTokenType),
+ T_COMPL_ALT = TOKEN_FROM_ID(303, OperatorTokenType|AltExtTokenType),
+ T_COMPL_TRIGRAPH = TOKEN_FROM_ID(303, OperatorTokenType|TriGraphTokenType),
+ T_STARASSIGN = TOKEN_FROM_ID(304, OperatorTokenType),
+ T_ASM = TOKEN_FROM_ID(305, KeywordTokenType),
+ T_AUTO = TOKEN_FROM_ID(306, KeywordTokenType),
+ T_BOOL = TOKEN_FROM_ID(307, KeywordTokenType),
+ T_FALSE = TOKEN_FROM_ID(308, BoolLiteralTokenType),
+ T_TRUE = TOKEN_FROM_ID(309, BoolLiteralTokenType),
+ T_BREAK = TOKEN_FROM_ID(310, KeywordTokenType),
+ T_CASE = TOKEN_FROM_ID(311, KeywordTokenType),
+ T_CATCH = TOKEN_FROM_ID(312, KeywordTokenType),
+ T_CHAR = TOKEN_FROM_ID(313, KeywordTokenType),
+ T_CLASS = TOKEN_FROM_ID(314, KeywordTokenType),
+ T_CONST = TOKEN_FROM_ID(315, KeywordTokenType),
+ T_CONSTCAST = TOKEN_FROM_ID(316, KeywordTokenType),
+ T_CONTINUE = TOKEN_FROM_ID(317, KeywordTokenType),
+ T_DEFAULT = TOKEN_FROM_ID(318, KeywordTokenType),
+ T_DELETE = TOKEN_FROM_ID(319, KeywordTokenType),
+ T_DO = TOKEN_FROM_ID(320, KeywordTokenType),
+ T_DOUBLE = TOKEN_FROM_ID(321, KeywordTokenType),
+ T_DYNAMICCAST = TOKEN_FROM_ID(322, KeywordTokenType),
+ T_ELSE = TOKEN_FROM_ID(323, KeywordTokenType),
+ T_ENUM = TOKEN_FROM_ID(324, KeywordTokenType),
+ T_EXPLICIT = TOKEN_FROM_ID(325, KeywordTokenType),
+ T_EXPORT = TOKEN_FROM_ID(326, KeywordTokenType),
+ T_EXTERN = TOKEN_FROM_ID(327, KeywordTokenType),
+ T_FLOAT = TOKEN_FROM_ID(328, KeywordTokenType),
+ T_FOR = TOKEN_FROM_ID(329, KeywordTokenType),
+ T_FRIEND = TOKEN_FROM_ID(330, KeywordTokenType),
+ T_GOTO = TOKEN_FROM_ID(331, KeywordTokenType),
+ T_IF = TOKEN_FROM_ID(332, KeywordTokenType),
+ T_INLINE = TOKEN_FROM_ID(333, KeywordTokenType),
+ T_INT = TOKEN_FROM_ID(334, KeywordTokenType),
+ T_LONG = TOKEN_FROM_ID(335, KeywordTokenType),
+ T_MUTABLE = TOKEN_FROM_ID(336, KeywordTokenType),
+ T_NAMESPACE = TOKEN_FROM_ID(337, KeywordTokenType),
+ T_NEW = TOKEN_FROM_ID(338, KeywordTokenType),
+ T_OPERATOR = TOKEN_FROM_ID(339, KeywordTokenType),
+ T_PRIVATE = TOKEN_FROM_ID(340, KeywordTokenType),
+ T_PROTECTED = TOKEN_FROM_ID(341, KeywordTokenType),
+ T_PUBLIC = TOKEN_FROM_ID(342, KeywordTokenType),
+ T_REGISTER = TOKEN_FROM_ID(343, KeywordTokenType),
+ T_REINTERPRETCAST = TOKEN_FROM_ID(344, KeywordTokenType),
+ T_RETURN = TOKEN_FROM_ID(345, KeywordTokenType),
+ T_SHORT = TOKEN_FROM_ID(346, KeywordTokenType),
+ T_SIGNED = TOKEN_FROM_ID(347, KeywordTokenType),
+ T_SIZEOF = TOKEN_FROM_ID(348, KeywordTokenType),
+ T_STATIC = TOKEN_FROM_ID(349, KeywordTokenType),
+ T_STATICCAST = TOKEN_FROM_ID(350, KeywordTokenType),
+ T_STRUCT = TOKEN_FROM_ID(351, KeywordTokenType),
+ T_SWITCH = TOKEN_FROM_ID(352, KeywordTokenType),
+ T_TEMPLATE = TOKEN_FROM_ID(353, KeywordTokenType),
+ T_THIS = TOKEN_FROM_ID(354, KeywordTokenType),
+ T_THROW = TOKEN_FROM_ID(355, KeywordTokenType),
+ T_TRY = TOKEN_FROM_ID(356, KeywordTokenType),
+ T_TYPEDEF = TOKEN_FROM_ID(357, KeywordTokenType),
+ T_TYPEID = TOKEN_FROM_ID(358, KeywordTokenType),
+ T_TYPENAME = TOKEN_FROM_ID(359, KeywordTokenType),
+ T_UNION = TOKEN_FROM_ID(360, KeywordTokenType),
+ T_UNSIGNED = TOKEN_FROM_ID(361, KeywordTokenType),
+ T_USING = TOKEN_FROM_ID(362, KeywordTokenType),
+ T_VIRTUAL = TOKEN_FROM_ID(363, KeywordTokenType),
+ T_VOID = TOKEN_FROM_ID(364, KeywordTokenType),
+ T_VOLATILE = TOKEN_FROM_ID(365, KeywordTokenType),
+ T_WCHART = TOKEN_FROM_ID(366, KeywordTokenType),
+ T_WHILE = TOKEN_FROM_ID(367, KeywordTokenType),
+ T_PP_DEFINE = TOKEN_FROM_ID(368, PPTokenType),
+ T_PP_IF = TOKEN_FROM_ID(369, PPConditionalTokenType),
+ T_PP_IFDEF = TOKEN_FROM_ID(370, PPConditionalTokenType),
+ T_PP_IFNDEF = TOKEN_FROM_ID(371, PPConditionalTokenType),
+ T_PP_ELSE = TOKEN_FROM_ID(372, PPConditionalTokenType),
+ T_PP_ELIF = TOKEN_FROM_ID(373, PPConditionalTokenType),
+ T_PP_ENDIF = TOKEN_FROM_ID(374, PPConditionalTokenType),
+ T_PP_ERROR = TOKEN_FROM_ID(375, PPTokenType),
+ T_PP_LINE = TOKEN_FROM_ID(376, PPTokenType),
+ T_PP_PRAGMA = TOKEN_FROM_ID(377, PPTokenType),
+ T_PP_UNDEF = TOKEN_FROM_ID(378, PPTokenType),
+ T_PP_WARNING = TOKEN_FROM_ID(379, PPTokenType),
+ T_IDENTIFIER = TOKEN_FROM_ID(380, IdentifierTokenType),
+ T_OCTALINT = TOKEN_FROM_ID(381, IntegerLiteralTokenType),
+ T_DECIMALINT = TOKEN_FROM_ID(382, IntegerLiteralTokenType),
+ T_HEXAINT = TOKEN_FROM_ID(383, IntegerLiteralTokenType),
+ T_INTLIT = TOKEN_FROM_ID(384, IntegerLiteralTokenType),
+ T_LONGINTLIT = TOKEN_FROM_ID(385, IntegerLiteralTokenType),
+ T_FLOATLIT = TOKEN_FROM_ID(386, FloatingLiteralTokenType),
+ T_FIXEDPOINTLIT = TOKEN_FROM_ID(386, FloatingLiteralTokenType|AltTokenType), // IDL specific
+ T_CCOMMENT = TOKEN_FROM_ID(387, WhiteSpaceTokenType|AltTokenType),
+ T_CPPCOMMENT = TOKEN_FROM_ID(388, WhiteSpaceTokenType|AltTokenType),
+ T_CHARLIT = TOKEN_FROM_ID(389, CharacterLiteralTokenType),
+ T_STRINGLIT = TOKEN_FROM_ID(390, StringLiteralTokenType),
+ T_CONTLINE = TOKEN_FROM_ID(391, EOLTokenType),
+ T_SPACE = TOKEN_FROM_ID(392, WhiteSpaceTokenType),
+ T_SPACE2 = TOKEN_FROM_ID(393, WhiteSpaceTokenType),
+ T_NEWLINE = TOKEN_FROM_ID(394, EOLTokenType),
+ T_GENERATEDNEWLINE = TOKEN_FROM_ID(394, EOLTokenType|AltTokenType),
+ T_POUND_POUND = TOKEN_FROM_ID(395, OperatorTokenType),
+ T_POUND_POUND_ALT = TOKEN_FROM_ID(395, OperatorTokenType|AltTokenType),
+ T_POUND_POUND_TRIGRAPH = TOKEN_FROM_ID(395, OperatorTokenType|TriGraphTokenType),
+ T_POUND = TOKEN_FROM_ID(396, OperatorTokenType),
+ T_POUND_ALT = TOKEN_FROM_ID(396, OperatorTokenType|AltTokenType),
+ T_POUND_TRIGRAPH = TOKEN_FROM_ID(396, OperatorTokenType|TriGraphTokenType),
+ T_ANY = TOKEN_FROM_ID(397, UnknownTokenType),
+ T_ANY_TRIGRAPH = TOKEN_FROM_ID(397, UnknownTokenType|TriGraphTokenType),
+ T_PP_INCLUDE = TOKEN_FROM_ID(398, PPTokenType),
+ T_PP_QHEADER = TOKEN_FROM_ID(399, PPTokenType),
+ T_PP_HHEADER = TOKEN_FROM_ID(400, PPTokenType),
+ T_PP_INCLUDE_NEXT = TOKEN_FROM_ID(398, PPTokenType|AltTokenType),
+ T_PP_QHEADER_NEXT = TOKEN_FROM_ID(399, PPTokenType|AltTokenType),
+ T_PP_HHEADER_NEXT = TOKEN_FROM_ID(400, PPTokenType|AltTokenType),
+ T_EOF = TOKEN_FROM_ID(401, EOFTokenType), // end of file reached
+ T_EOI = TOKEN_FROM_ID(402, EOFTokenType), // end of input reached
+ T_PP_NUMBER = TOKEN_FROM_ID(403, InternalTokenType),
+
+// MS extensions
+ T_MSEXT_INT8 = TOKEN_FROM_ID(404, KeywordTokenType),
+ T_MSEXT_INT16 = TOKEN_FROM_ID(405, KeywordTokenType),
+ T_MSEXT_INT32 = TOKEN_FROM_ID(406, KeywordTokenType),
+ T_MSEXT_INT64 = TOKEN_FROM_ID(407, KeywordTokenType),
+ T_MSEXT_BASED = TOKEN_FROM_ID(408, KeywordTokenType),
+ T_MSEXT_DECLSPEC = TOKEN_FROM_ID(409, KeywordTokenType),
+ T_MSEXT_CDECL = TOKEN_FROM_ID(410, KeywordTokenType),
+ T_MSEXT_FASTCALL = TOKEN_FROM_ID(411, KeywordTokenType),
+ T_MSEXT_STDCALL = TOKEN_FROM_ID(412, KeywordTokenType),
+ T_MSEXT_TRY = TOKEN_FROM_ID(413, KeywordTokenType),
+ T_MSEXT_EXCEPT = TOKEN_FROM_ID(414, KeywordTokenType),
+ T_MSEXT_FINALLY = TOKEN_FROM_ID(415, KeywordTokenType),
+ T_MSEXT_LEAVE = TOKEN_FROM_ID(416, KeywordTokenType),
+ T_MSEXT_INLINE = TOKEN_FROM_ID(417, KeywordTokenType),
+ T_MSEXT_ASM = TOKEN_FROM_ID(418, KeywordTokenType),
+
+ T_MSEXT_PP_REGION = TOKEN_FROM_ID(419, PPTokenType),
+ T_MSEXT_PP_ENDREGION = TOKEN_FROM_ID(420, PPTokenType),
+
+// import is needed to be a keyword for the C++ module Standards proposal
+ T_IMPORT = TOKEN_FROM_ID(421, KeywordTokenType),
+
+// C++0x keywords
+ T_ALIGNAS = TOKEN_FROM_ID(422, KeywordTokenType),
+ T_ALIGNOF = TOKEN_FROM_ID(423, KeywordTokenType),
+ T_CHAR16_T = TOKEN_FROM_ID(424, KeywordTokenType),
+ T_CHAR32_T = TOKEN_FROM_ID(425, KeywordTokenType),
+ T_CONSTEXPR = TOKEN_FROM_ID(426, KeywordTokenType),
+ T_DECLTYPE = TOKEN_FROM_ID(427, KeywordTokenType),
+ T_NOEXCEPT = TOKEN_FROM_ID(428, KeywordTokenType),
+ T_NULLPTR = TOKEN_FROM_ID(429, KeywordTokenType),
+ T_STATICASSERT = TOKEN_FROM_ID(430, KeywordTokenType),
+ T_THREADLOCAL = TOKEN_FROM_ID(431, KeywordTokenType),
+ T_RAWSTRINGLIT = TOKEN_FROM_ID(432, StringLiteralTokenType),
+
+ T_LAST_TOKEN_ID,
+ T_LAST_TOKEN = ID_FROM_TOKEN(T_LAST_TOKEN_ID & ~PPTokenFlag),
+
+// pseudo tokens to help streamlining macro replacement, these should not
+// returned from the lexer nor should these be returned from the pp-iterator
+ T_NONREPLACABLE_IDENTIFIER = TOKEN_FROM_ID(T_LAST_TOKEN+1, IdentifierTokenType),
+ T_PLACEHOLDER = TOKEN_FROM_ID(T_LAST_TOKEN+2, WhiteSpaceTokenType),
+ T_PLACEMARKER = TOKEN_FROM_ID(T_LAST_TOKEN+3, InternalTokenType),
+ T_PARAMETERBASE = TOKEN_FROM_ID(T_LAST_TOKEN+4, ParameterTokenType),
+ T_EXTPARAMETERBASE = TOKEN_FROM_ID(T_LAST_TOKEN+4, ExtParameterTokenType)
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// redefine the TOKEN_FROM_ID macro to be more type safe
+#undef TOKEN_FROM_ID
+#define TOKEN_FROM_ID(id, cat) boost::wave::token_id((id) | (cat))
+
+#undef ID_FROM_TOKEN
+#define ID_FROM_TOKEN(tok) \
+ boost::wave::token_id((tok) & \
+ ~(boost::wave::TokenTypeMask|boost::wave::PPTokenFlag)) \
+ /**/
+
+#undef BASEID_FROM_TOKEN
+#define BASEID_FROM_TOKEN(tok) \
+ boost::wave::token_id((tok) & \
+ ~(boost::wave::ExtTokenTypeMask|boost::wave::PPTokenFlag)) \
+ /**/
+#define BASE_TOKEN(tok) \
+ boost::wave::token_id((tok) & boost::wave::MainTokenMask) \
+ /**/
+#define CATEGORY_FROM_TOKEN(tok) ((tok) & boost::wave::TokenTypeMask)
+#define EXTCATEGORY_FROM_TOKEN(tok) ((tok) & boost::wave::ExtTokenTypeMask)
+#define IS_CATEGORY(tok, cat) \
+ ((CATEGORY_FROM_TOKEN(tok) == CATEGORY_FROM_TOKEN(cat)) ? true : false) \
+ /**/
+#define IS_EXTCATEGORY(tok, cat) \
+ ((EXTCATEGORY_FROM_TOKEN(tok) == EXTCATEGORY_FROM_TOKEN(cat)) ? true : false) \
+ /**/
+
+///////////////////////////////////////////////////////////////////////////////
+// verify whether the given token(-id) represents a valid pp_token
+inline bool is_pp_token(boost::wave::token_id id)
+{
+ return (id & boost::wave::PPTokenFlag) ? true : false;
+}
+
+template <typename TokenT>
+inline bool is_pp_token(TokenT const& tok)
+{
+ return is_pp_token(boost::wave::token_id(tok));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// return a token name
+BOOST_WAVE_DECL
+BOOST_WAVE_STRINGTYPE get_token_name(token_id tokid);
+
+///////////////////////////////////////////////////////////////////////////////
+// return a token name
+BOOST_WAVE_DECL
+char const *get_token_value(token_id tokid);
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace wave
+} // namespace boost
+
+#endif // #if !defined(BOOST_WAVE_TOKEN_IDS_DEFINED)
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(TOKEN_IDS_HPP_414E9A58_F079_4789_8AFF_513815CE475B_INCLUDED)
+
diff --git a/boost/wave/util/cpp_ifblock.hpp b/boost/wave/util/cpp_ifblock.hpp
new file mode 100644
index 0000000000..f89f9eaf66
--- /dev/null
+++ b/boost/wave/util/cpp_ifblock.hpp
@@ -0,0 +1,161 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_IFBLOCK_HPP_D4676B36_00C5_41F4_BC9F_9CBBAE3B8006_INCLUDED)
+#define CPP_IFBLOCK_HPP_D4676B36_00C5_41F4_BC9F_9CBBAE3B8006_INCLUDED
+
+#include <stack>
+#include <boost/wave/wave_config.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 {
+namespace util {
+
+///////////////////////////////////////////////////////////////////////////////
+// the class if_blocks handles recursive conditional compilation contexts
+class if_block
+{
+public:
+ if_block() :
+ status(true), some_part_status(true),
+ enclosing_status(true), is_in_else(false)
+ {
+ }
+ if_block(bool status_, bool enclosing_status_) :
+ status(status_),
+ some_part_status(status_),
+ enclosing_status(enclosing_status_),
+ is_in_else(false)
+ {
+ }
+
+ void set_status(bool status_)
+ {
+ status = status_;
+ if (status_)
+ some_part_status = true;
+ }
+ bool get_status() const { return status; }
+ bool get_some_part_status() const { return some_part_status; }
+ bool get_enclosing_status() const { return enclosing_status; }
+ bool get_in_else() const { return is_in_else; }
+ void set_in_else() { is_in_else = true; }
+
+private:
+ bool status; // Current block is true
+ bool some_part_status; // One of the preceding or current #if/#elif was true
+ bool enclosing_status; // Enclosing #if block is true
+ bool is_in_else; // Inside the #else part
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// stack of conditional compilation contexts
+class if_block_stack
+: private std::stack<if_block>
+{
+public:
+ typedef std::stack<if_block>::size_type size_type;
+
+ void enter_if_block(bool new_status)
+ {
+ // If enclosing block is false, then this block is also false
+ bool enclosing_status = get_status();
+ this->push (value_type (new_status && enclosing_status, enclosing_status));
+ }
+ bool enter_elif_block(bool new_status)
+ {
+ if (!is_inside_ifpart())
+ return false; // #elif without matching #if
+
+ if (get_enclosing_status()) {
+ if (get_status()) {
+ // entered a (false) #elif block from a true block
+ this->top().set_status(false);
+ }
+ else if (new_status && !this->top().get_some_part_status()) {
+ // Entered true #elif block and no previous block was true
+ this->top().set_status(new_status);
+ }
+ }
+ return true;
+ }
+ bool enter_else_block()
+ {
+ if (!is_inside_ifpart())
+ return false; // #else without matching #if
+
+ if (get_enclosing_status()) {
+ if (!this->top().get_some_part_status()) {
+ // Entered (true) #else block and no previous block was true
+ this->top().set_status(true);
+ }
+ else if (get_status()) {
+ // Entered (false) #else block from true block
+ this->top().set_status(false);
+ }
+
+ // Set else flag
+ this->top().set_in_else();
+ }
+ return true;
+ }
+ bool exit_if_block()
+ {
+ if (0 == this->size())
+ return false; // #endif without matching #if
+
+ this->pop();
+ return true;
+ }
+
+// return, whether the top (innermost) condition is true or false
+ bool get_status() const
+ {
+ return 0 == this->size() || this->top().get_status();
+ }
+ bool get_some_part_status() const
+ {
+ return 0 == this->size() || this->top().get_some_part_status();
+ }
+ bool get_enclosing_status() const
+ {
+ return 0 == this->size() || this->top().get_enclosing_status();
+ }
+
+ size_type get_if_block_depth() const { return this->size(); }
+
+protected:
+ bool is_inside_ifpart() const
+ {
+ return 0 != this->size() && !this->top().get_in_else();
+ }
+ bool is_inside_elsepart() const
+ {
+ return 0 != this->size() && this->top().get_in_else();
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace util
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_IFBLOCK_HPP_D4676B36_00C5_41F4_BC9F_9CBBAE3B8006_INCLUDED)
diff --git a/boost/wave/util/cpp_include_paths.hpp b/boost/wave/util/cpp_include_paths.hpp
new file mode 100644
index 0000000000..29c2bec3c9
--- /dev/null
+++ b/boost/wave/util/cpp_include_paths.hpp
@@ -0,0 +1,553 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_INCLUDE_PATHS_HPP_AF620DA4_B3D2_4221_AD91_8A1ABFFB6944_INCLUDED)
+#define CPP_INCLUDE_PATHS_HPP_AF620DA4_B3D2_4221_AD91_8A1ABFFB6944_INCLUDED
+
+#include <string>
+#include <list>
+#include <utility>
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/wave/util/filesystem_compatibility.hpp>
+
+#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/member.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#endif
+
+#if BOOST_WAVE_SERIALIZATION != 0
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/utility.hpp>
+#include <boost/serialization/collections_save_imp.hpp>
+#include <boost/serialization/collections_load_imp.hpp>
+#include <boost/serialization/split_free.hpp>
+#endif
+
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/operations.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 { namespace util {
+
+#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+///////////////////////////////////////////////////////////////////////////////
+// Tags for accessing both sides of a bidirectional map
+struct from {};
+struct to {};
+
+///////////////////////////////////////////////////////////////////////////////
+// The class template bidirectional_map wraps the specification
+// of a bidirectional map based on multi_index_container.
+template<typename FromType, typename ToType>
+struct bidirectional_map
+{
+ typedef std::pair<FromType, ToType> value_type;
+
+#if defined(BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS) || \
+ (defined(BOOST_MSVC) && \
+ ( (BOOST_MSVC < 1300) || (BOOST_MSVC == 1600) )) || \
+ (defined(BOOST_INTEL_CXX_VERSION) && \
+ (defined(_MSC_VER) && (BOOST_INTEL_CXX_VERSION <= 700)))
+
+ BOOST_STATIC_CONSTANT(unsigned, from_offset = offsetof(value_type, first));
+ BOOST_STATIC_CONSTANT(unsigned, to_offset = offsetof(value_type, second));
+
+ typedef boost::multi_index::multi_index_container<
+ value_type,
+ boost::multi_index::indexed_by<
+ boost::multi_index::ordered_unique<
+ boost::multi_index::tag<from>,
+ boost::multi_index::member_offset<value_type, FromType, from_offset>
+ >,
+ boost::multi_index::ordered_non_unique<
+ boost::multi_index::tag<to>,
+ boost::multi_index::member_offset<value_type, ToType, to_offset>
+ >
+ >
+ > type;
+
+#else
+
+ typedef boost::multi_index::multi_index_container<
+ value_type,
+ boost::multi_index::indexed_by<
+ boost::multi_index::ordered_unique<
+ boost::multi_index::tag<from>,
+ boost::multi_index::member<value_type, FromType, &value_type::first>
+ >,
+ boost::multi_index::ordered_non_unique<
+ boost::multi_index::tag<to>,
+ boost::multi_index::member<value_type, ToType, &value_type::second>
+ >
+ >
+ > type;
+
+#endif
+};
+#endif // BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+
+#if BOOST_WAVE_SERIALIZATION != 0
+struct load_filepos
+{
+ static unsigned int get_line() { return 0; }
+ static unsigned int get_column() { return 0; }
+ static std::string get_file() { return "<loading-state>"; }
+};
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// include_paths - controlling the include path search order
+//
+// General notes:
+//
+// Any directories specified with the 'add_include_path()' function before
+// the function 'set_sys_include_delimiter()' is called are searched only
+// for the case of '#include "file"' directives, they are not searched for
+// '#include <file>' directives. If additional directories are specified
+// with the 'add_include_path()' function after a call to the function
+// 'set_sys_include_delimiter()', these directories are searched for all
+// '#include' directives.
+//
+// In addition, a call to the function 'set_sys_include_delimiter()'
+// inhibits the use of the current directory as the first search directory
+// for '#include "file"' directives. Therefore, the current directory is
+// searched only if it is requested explicitly with a call to the function
+// 'add_include_path(".")'.
+//
+// Calling both functions, the 'set_sys_include_delimiter()' and
+// 'add_include_path(".")' allows you to control precisely which
+// directories are searched before the current one and which are searched
+// after.
+//
+///////////////////////////////////////////////////////////////////////////////
+class include_paths
+{
+private:
+ typedef std::list<std::pair<boost::filesystem::path, std::string> >
+ include_list_type;
+ typedef include_list_type::value_type include_value_type;
+
+#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+ typedef bidirectional_map<std::string, std::string>::type
+ pragma_once_set_type;
+#endif
+
+public:
+ include_paths()
+ : was_sys_include_path(false),
+ current_dir(initial_path()),
+ current_rel_dir(initial_path())
+ {}
+
+ bool add_include_path(char const *path_, bool is_system = false)
+ {
+ return add_include_path(path_, (is_system || was_sys_include_path) ?
+ system_include_paths : user_include_paths);
+ }
+ void set_sys_include_delimiter() { was_sys_include_path = true; }
+ bool find_include_file (std::string &s, std::string &dir, bool is_system,
+ char const *current_file) const;
+ void set_current_directory(char const *path_);
+ boost::filesystem::path get_current_directory() const
+ { return current_dir; }
+
+protected:
+ bool find_include_file (std::string &s, std::string &dir,
+ include_list_type const &pathes, char const *) const;
+ bool add_include_path(char const *path_, include_list_type &pathes_);
+
+private:
+ include_list_type user_include_paths;
+ include_list_type system_include_paths;
+ bool was_sys_include_path; // saw a set_sys_include_delimiter()
+ boost::filesystem::path current_dir;
+ boost::filesystem::path current_rel_dir;
+
+#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+public:
+ bool has_pragma_once(std::string const &filename)
+ {
+ using boost::multi_index::get;
+ return get<from>(pragma_once_files).find(filename) != pragma_once_files.end();
+ }
+ bool add_pragma_once_header(std::string const &filename,
+ std::string const& guard_name)
+ {
+ typedef pragma_once_set_type::value_type value_type;
+ return pragma_once_files.insert(value_type(filename, guard_name)).second;
+ }
+ bool remove_pragma_once_header(std::string const& guard_name)
+ {
+ typedef pragma_once_set_type::index_iterator<to>::type to_iterator;
+ typedef std::pair<to_iterator, to_iterator> range_type;
+
+ range_type r = pragma_once_files.get<to>().equal_range(guard_name);
+ if (r.first != r.second) {
+ using boost::multi_index::get;
+ get<to>(pragma_once_files).erase(r.first, r.second);
+ return true;
+ }
+ return false;
+ }
+
+private:
+ pragma_once_set_type pragma_once_files;
+#endif
+
+#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<typename Archive>
+ void save(Archive & ar, const unsigned int version) const
+ {
+ using namespace boost::serialization;
+#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+ ar & make_nvp("pragma_once_files", pragma_once_files);
+#endif
+ ar & make_nvp("user_include_paths", user_include_paths);
+ ar & make_nvp("system_include_paths", system_include_paths);
+ ar & make_nvp("was_sys_include_path", was_sys_include_path);
+ }
+ template<typename Archive>
+ void load(Archive & ar, const unsigned int loaded_version)
+ {
+ using namespace boost::serialization;
+ if (version != (loaded_version & ~version_mask)) {
+ BOOST_WAVE_THROW(preprocess_exception, incompatible_config,
+ "cpp_include_path state version", load_filepos());
+ return;
+ }
+
+#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+ ar & make_nvp("pragma_once_files", pragma_once_files);
+#endif
+ // verify that the old include paths match the current ones
+ include_list_type user_paths, system_paths;
+ ar & make_nvp("user_include_paths", user_paths);
+ ar & make_nvp("system_include_paths", system_paths);
+
+ if (user_paths != user_include_paths)
+ {
+ BOOST_WAVE_THROW(preprocess_exception, incompatible_config,
+ "user include paths", load_filepos());
+ return;
+ }
+ if (system_paths != system_include_paths)
+ {
+ BOOST_WAVE_THROW(preprocess_exception, incompatible_config,
+ "system include paths", load_filepos());
+ return;
+ }
+
+ ar & make_nvp("was_sys_include_path", was_sys_include_path);
+ }
+ BOOST_SERIALIZATION_SPLIT_MEMBER()
+#endif
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Add an include path to one of the search lists (user include path or system
+// include path).
+inline
+bool include_paths::add_include_path (
+ char const *path_, include_list_type &pathes_)
+{
+ namespace fs = boost::filesystem;
+ if (path_) {
+ fs::path newpath = util::complete_path(create_path(path_), current_dir);
+
+ if (!fs::exists(newpath) || !fs::is_directory(newpath)) {
+ // the given path does not form a name of a valid file system directory
+ // item
+ return false;
+ }
+
+ pathes_.push_back (include_value_type(newpath, path_));
+ return true;
+ }
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Find an include file by traversing the list of include directories
+inline
+bool include_paths::find_include_file (std::string &s, std::string &dir,
+ include_list_type const &pathes, char const *current_file) const
+{
+ namespace fs = boost::filesystem;
+ typedef include_list_type::const_iterator const_include_list_iter_t;
+
+ const_include_list_iter_t it = pathes.begin();
+ const_include_list_iter_t include_paths_end = pathes.end();
+
+#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
+ if (0 != current_file) {
+ // re-locate the directory of the current file (#include_next handling)
+
+ // #include_next does not distinguish between <file> and "file"
+ // inclusion, nor does it check that the file you specify has the same
+ // name as the current file. It simply looks for the file named, starting
+ // with the directory in the search path after the one where the current
+ // file was found.
+
+ fs::path file_path (create_path(current_file));
+ for (/**/; it != include_paths_end; ++it) {
+ fs::path currpath (create_path((*it).first.string()));
+ if (std::equal(currpath.begin(), currpath.end(), file_path.begin()))
+ {
+ ++it; // start searching with the next directory
+ break;
+ }
+ }
+ }
+#endif
+
+ for (/**/; it != include_paths_end; ++it) {
+ fs::path currpath (create_path(s));
+ if (!currpath.has_root_directory()) {
+ currpath = create_path((*it).first.string());
+ currpath /= create_path(s); // append filename
+ }
+
+ if (fs::exists(currpath)) {
+ fs::path dirpath (create_path(s));
+ if (!dirpath.has_root_directory()) {
+ dirpath = create_path((*it).second);
+ dirpath /= create_path(s);
+ }
+
+ dir = dirpath.string();
+ s = normalize(currpath).string(); // found the required file
+ return true;
+ }
+ }
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Find an include file by searching the user and system includes in the
+// correct sequence (as it was configured by the user of the driver program)
+inline bool
+include_paths::find_include_file (std::string &s, std::string &dir,
+ bool is_system, char const *current_file) const
+{
+ namespace fs = boost::filesystem;
+
+// if not system include (<...>), then search current directory first
+ if (!is_system) {
+ if (!was_sys_include_path) { // set_sys_include_delimiter() not called
+ // first have a look at the current directory
+ fs::path currpath (create_path(s));
+ if (!currpath.has_root_directory()) {
+ currpath = create_path(current_dir.string());
+ currpath /= create_path(s);
+ }
+
+ if (fs::exists(currpath) && 0 == current_file) {
+ // if 0 != current_path (#include_next handling) it can't be
+ // the file in the current directory
+ fs::path dirpath (create_path(s));
+ if (!dirpath.has_root_directory()) {
+ dirpath = create_path(current_rel_dir.string());
+ dirpath /= create_path(s);
+ }
+
+ dir = dirpath.string();
+ s = normalize(currpath).string(); // found in local directory
+ return true;
+ }
+
+ // iterate all user include file directories to find the file
+ if (find_include_file(s, dir, user_include_paths, current_file))
+ return true;
+
+ // ... fall through
+ }
+ else {
+ // if set_sys_include_delimiter() was called, then user include files
+ // are searched in the user search path only
+ return find_include_file(s, dir, user_include_paths, current_file);
+ }
+
+ // if nothing found, fall through
+ // ...
+ }
+
+// iterate all system include file directories to find the file
+ return find_include_file (s, dir, system_include_paths, current_file);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Set current directory from a given file name
+
+inline bool
+as_relative_to(boost::filesystem::path const& path,
+ boost::filesystem::path const& base, boost::filesystem::path& result)
+{
+ if (path.has_root_path()) {
+ if (path.root_path() == base.root_path())
+ return as_relative_to(path.relative_path(), base.relative_path(), result);
+
+ result = path; // that's our result
+ }
+ else {
+ if (base.has_root_path()) {
+ // cannot find relative path from a relative path and a rooted base
+ return false;
+ }
+ else {
+ typedef boost::filesystem::path::const_iterator path_iterator;
+ path_iterator path_it = path.begin();
+ path_iterator base_it = base.begin();
+ while (path_it != path.end() && base_it != base.end() ) {
+ if (*path_it != *base_it)
+ break;
+ ++path_it; ++base_it;
+ }
+
+ for (/**/; base_it != base.end(); ++base_it)
+ result /= "..";
+
+ for (/**/; path_it != path.end(); ++path_it)
+ result /= *path_it;
+ }
+ }
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+inline
+void include_paths::set_current_directory(char const *path_)
+{
+ namespace fs = boost::filesystem;
+
+ fs::path filepath (create_path(path_));
+ fs::path filename = util::complete_path(filepath, current_dir);
+ if (fs::exists(filename) && fs::is_directory(filename)) {
+ current_rel_dir.clear();
+ if (!as_relative_to(filepath, current_dir, current_rel_dir))
+ current_rel_dir = filepath;
+ current_dir = filename;
+ }
+ else {
+ current_rel_dir.clear();
+ if (!as_relative_to(branch_path(filepath), current_dir, current_rel_dir))
+ current_rel_dir = branch_path(filepath);
+ current_dir = branch_path(filename);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+}}} // namespace boost::wave::util
+
+#if BOOST_WAVE_SERIALIZATION != 0
+///////////////////////////////////////////////////////////////////////////////
+namespace boost { namespace serialization {
+
+///////////////////////////////////////////////////////////////////////////////
+// Serialization support for boost::filesystem::path
+template<class Archive>
+inline void save (Archive & ar, boost::filesystem::path const& p,
+ const unsigned int /* file_version */)
+{
+ using namespace boost::serialization;
+ std::string path_str(p.native_file_string());
+ ar & make_nvp("filepath", path_str);
+}
+
+template<class Archive>
+inline void load (Archive & ar, boost::filesystem::path &p,
+ const unsigned int /* file_version */)
+{
+ using namespace boost::serialization;
+ std::string path_str;
+ ar & make_nvp("filepath", path_str);
+ p = wave::util::create_path(path_str);
+}
+
+// split non-intrusive serialization function member into separate
+// non intrusive save/load member functions
+template<class Archive>
+inline void serialize (Archive & ar, boost::filesystem::path &p,
+ const unsigned int file_version)
+{
+ boost::serialization::split_free(ar, p, file_version);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Serialization support for the used multi_index
+template<class Archive>
+inline void save (Archive & ar,
+ const typename boost::wave::util::bidirectional_map<
+ std::string, std::string
+ >::type &t,
+ const unsigned int /* file_version */)
+{
+ boost::serialization::stl::save_collection<
+ Archive,
+ typename boost::wave::util::bidirectional_map<
+ std::string, std::string
+ >::type
+ >(ar, t);
+}
+
+template<class Archive>
+inline void load (Archive & ar,
+ typename boost::wave::util::bidirectional_map<std::string, std::string>::type &t,
+ const unsigned int /* file_version */)
+{
+ typedef typename boost::wave::util::bidirectional_map<
+ std::string, std::string
+ >::type map_type;
+ boost::serialization::stl::load_collection<
+ Archive, map_type,
+ boost::serialization::stl::archive_input_unique<Archive, map_type>,
+ boost::serialization::stl::no_reserve_imp<map_type>
+ >(ar, t);
+}
+
+// split non-intrusive serialization function member into separate
+// non intrusive save/load member functions
+template<class Archive>
+inline void serialize (Archive & ar,
+ typename boost::wave::util::bidirectional_map<
+ std::string, std::string
+ >::type &t,
+ const unsigned int file_version)
+{
+ boost::serialization::split_free(ar, t, file_version);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+}} // namespace boost::serialization
+
+BOOST_CLASS_VERSION(boost::wave::util::include_paths,
+ boost::wave::util::include_paths::version);
+
+#endif // BOOST_WAVE_SERIALIZATION != 0
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_INCLUDE_PATHS_HPP_AF620DA4_B3D2_4221_AD91_8A1ABFFB6944_INCLUDED)
diff --git a/boost/wave/util/cpp_iterator.hpp b/boost/wave/util/cpp_iterator.hpp
new file mode 100644
index 0000000000..8441b41faa
--- /dev/null
+++ b/boost/wave/util/cpp_iterator.hpp
@@ -0,0 +1,2571 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ Definition of the preprocessor iterator
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_ITERATOR_HPP_175CA88F_7273_43FA_9039_BCF7459E1F29_INCLUDED)
+#define CPP_ITERATOR_HPP_175CA88F_7273_43FA_9039_BCF7459E1F29_INCLUDED
+
+#include <string>
+#include <vector>
+#include <list>
+#include <cstdlib>
+#include <cctype>
+
+#include <boost/assert.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/spirit/include/classic_multi_pass.hpp>
+#include <boost/spirit/include/classic_parse_tree_utils.hpp>
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/pool/pool_alloc.hpp>
+
+#include <boost/wave/util/insert_whitespace_detection.hpp>
+#include <boost/wave/util/macro_helpers.hpp>
+#include <boost/wave/util/cpp_macromap_utils.hpp>
+#include <boost/wave/util/interpret_pragma.hpp>
+#include <boost/wave/util/transform_iterator.hpp>
+#include <boost/wave/util/functor_input.hpp>
+#include <boost/wave/util/filesystem_compatibility.hpp>
+
+#include <boost/wave/grammars/cpp_grammar_gen.hpp>
+#include <boost/wave/grammars/cpp_expression_grammar_gen.hpp>
+#if BOOST_WAVE_ENABLE_COMMANDLINE_MACROS != 0
+#include <boost/wave/grammars/cpp_predef_macros_gen.hpp>
+#endif
+
+#include <boost/wave/whitespace_handling.hpp>
+#include <boost/wave/cpp_iteration_context.hpp>
+#include <boost/wave/cpp_exceptions.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 {
+namespace util {
+
+///////////////////////////////////////////////////////////////////////////////
+// retrieve the macro name from the parse tree
+template <
+ typename ContextT, typename ParseNodeT, typename TokenT,
+ typename PositionT
+>
+inline bool
+retrieve_macroname(ContextT& ctx, ParseNodeT const &node,
+ boost::spirit::classic::parser_id id, TokenT &macroname, PositionT& act_pos,
+ bool update_position)
+{
+ParseNodeT const *name_node = 0;
+
+ using boost::spirit::classic::find_node;
+ if (!find_node(node, id, &name_node))
+ {
+ // ill formed define statement (unexpected, should not happen)
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_define_statement,
+ "bad parse tree (unexpected)", act_pos);
+ return false;
+ }
+
+typename ParseNodeT::children_t const &children = name_node->children;
+
+ if (0 == children.size() ||
+ children.front().value.begin() == children.front().value.end())
+ {
+ // ill formed define statement (unexpected, should not happen)
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_define_statement,
+ "bad parse tree (unexpected)", act_pos);
+ return false;
+ }
+
+// retrieve the macro name
+ macroname = *children.front().value.begin();
+ if (update_position) {
+ macroname.set_position(act_pos);
+ act_pos.set_column(act_pos.get_column() + macroname.get_value().size());
+ }
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// retrieve the macro parameters or the macro definition from the parse tree
+template <typename ParseNodeT, typename ContainerT, typename PositionT>
+inline bool
+retrieve_macrodefinition(
+ ParseNodeT const &node, boost::spirit::classic::parser_id id,
+ ContainerT &macrodefinition, PositionT& act_pos, bool update_position)
+{
+ using namespace boost::wave;
+ typedef typename ParseNodeT::const_tree_iterator const_tree_iterator;
+
+// find macro parameters/macro definition inside the parse tree
+std::pair<const_tree_iterator, const_tree_iterator> nodes;
+
+ using boost::spirit::classic::get_node_range;
+ if (get_node_range(node, id, nodes)) {
+ // copy all parameters to the supplied container
+ typename ContainerT::iterator last_nonwhite = macrodefinition.end();
+ const_tree_iterator end = nodes.second;
+
+ for (const_tree_iterator cit = nodes.first; cit != end; ++cit) {
+ if ((*cit).value.begin() != (*cit).value.end()) {
+ typename ContainerT::iterator inserted = macrodefinition.insert(
+ macrodefinition.end(), *(*cit).value.begin());
+
+ if (!IS_CATEGORY(macrodefinition.back(), WhiteSpaceTokenType) &&
+ T_NEWLINE != token_id(macrodefinition.back()) &&
+ T_EOF != token_id(macrodefinition.back()))
+ {
+ last_nonwhite = inserted;
+ }
+
+ if (update_position) {
+ (*inserted).set_position(act_pos);
+ act_pos.set_column(
+ act_pos.get_column() + (*inserted).get_value().size());
+ }
+ }
+ }
+
+ // trim trailing whitespace (leading whitespace is trimmed by the grammar)
+ if (last_nonwhite != macrodefinition.end()) {
+ if (update_position) {
+ act_pos.set_column((*last_nonwhite).get_position().get_column() +
+ (*last_nonwhite).get_value().size());
+ }
+ macrodefinition.erase(++last_nonwhite, macrodefinition.end());
+ }
+ return true;
+ }
+ return false;
+}
+
+#if BOOST_WAVE_ENABLE_COMMANDLINE_MACROS != 0
+///////////////////////////////////////////////////////////////////////////////
+// add an additional predefined macro given by a string (MACRO(x)=definition)
+template <typename ContextT>
+bool add_macro_definition(ContextT &ctx, std::string macrostring,
+ bool is_predefined, boost::wave::language_support language)
+{
+ typedef typename ContextT::token_type token_type;
+ typedef typename ContextT::lexer_type lexer_type;
+ typedef typename token_type::position_type position_type;
+ typedef boost::wave::grammars::predefined_macros_grammar_gen<lexer_type>
+ predef_macros_type;
+
+ using namespace boost::wave;
+ using namespace std; // isspace is in std namespace for some systems
+
+// skip leading whitespace
+std::string::iterator begin = macrostring.begin();
+std::string::iterator end = macrostring.end();
+
+ while(begin != end && isspace(*begin))
+ ++begin;
+
+// parse the macro definition
+position_type act_pos("<command line>");
+boost::spirit::classic::tree_parse_info<lexer_type> hit =
+ predef_macros_type::parse_predefined_macro(
+ lexer_type(begin, end, position_type(), language), lexer_type());
+
+ if (!hit.match || (!hit.full && T_EOF != token_id(*hit.stop))) {
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_macro_definition,
+ macrostring.c_str(), act_pos);
+ return false;
+ }
+
+// retrieve the macro definition from the parse tree
+token_type macroname;
+std::vector<token_type> macroparameters;
+typename ContextT::token_sequence_type macrodefinition;
+bool has_parameters = false;
+
+ if (!boost::wave::util::retrieve_macroname(ctx, *hit.trees.begin(),
+ BOOST_WAVE_PLAIN_DEFINE_ID, macroname, act_pos, true))
+ return false;
+ has_parameters = boost::wave::util::retrieve_macrodefinition(*hit.trees.begin(),
+ BOOST_WAVE_MACRO_PARAMETERS_ID, macroparameters, act_pos, true);
+ boost::wave::util::retrieve_macrodefinition(*hit.trees.begin(),
+ BOOST_WAVE_MACRO_DEFINITION_ID, macrodefinition, act_pos, true);
+
+// If no macrodefinition is given, and the macro string does not end with a
+// '=', then the macro should be defined with the value '1'
+ if (0 == macrodefinition.size() &&
+ '=' != macrostring[macrostring.size()-1])
+ {
+ macrodefinition.push_back(token_type(T_INTLIT, "1", act_pos));
+ }
+
+// add the new macro to the macromap
+ return ctx.add_macro_definition(macroname, has_parameters, macroparameters,
+ macrodefinition, is_predefined);
+}
+#endif // BOOST_WAVE_ENABLE_COMMANDLINE_MACROS != 0
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace util
+
+///////////////////////////////////////////////////////////////////////////////
+// forward declaration
+template <typename ContextT> class pp_iterator;
+
+namespace impl {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// pp_iterator_functor
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+class pp_iterator_functor {
+
+public:
+// interface to the boost::spirit::classic::iterator_policies::functor_input policy
+ typedef typename ContextT::token_type result_type;
+
+// eof token
+ static result_type const eof;
+
+private:
+// type of a token sequence
+ typedef typename ContextT::token_sequence_type token_sequence_type;
+
+ typedef typename ContextT::lexer_type lexer_type;
+ typedef typename result_type::string_type string_type;
+ typedef typename result_type::position_type position_type;
+ typedef boost::wave::grammars::cpp_grammar_gen<lexer_type, token_sequence_type>
+ cpp_grammar_type;
+
+// iteration context related types (an iteration context represents a current
+// position in an included file)
+ typedef base_iteration_context<ContextT, lexer_type>
+ base_iteration_context_type;
+ typedef iteration_context<ContextT, lexer_type> iteration_context_type;
+
+// parse tree related types
+ typedef typename cpp_grammar_type::node_factory_type node_factory_type;
+ typedef boost::spirit::classic::tree_parse_info<lexer_type, node_factory_type>
+ tree_parse_info_type;
+ typedef boost::spirit::classic::tree_match<lexer_type, node_factory_type>
+ parse_tree_match_type;
+ typedef typename parse_tree_match_type::node_t parse_node_type; // tree_node<node_val_data<> >
+ typedef typename parse_tree_match_type::parse_node_t parse_node_value_type; // node_val_data<>
+ typedef typename parse_tree_match_type::container_t parse_tree_type; // parse_node_type::children_t
+
+public:
+ template <typename IteratorT>
+ pp_iterator_functor(ContextT &ctx_, IteratorT const &first_,
+ IteratorT const &last_, typename ContextT::position_type const &pos_)
+ : ctx(ctx_),
+ iter_ctx(new base_iteration_context_type(ctx,
+ lexer_type(first_, last_, pos_,
+ boost::wave::enable_prefer_pp_numbers(ctx.get_language())),
+ lexer_type(),
+ pos_.get_file().c_str()
+ )),
+ seen_newline(true), skipped_newline(false),
+ must_emit_line_directive(false), act_pos(ctx_.get_main_pos()),
+ whitespace(boost::wave::need_insert_whitespace(ctx.get_language()))
+ {
+ act_pos.set_file(pos_.get_file());
+#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+ ctx_.set_current_filename(pos_.get_file().c_str());
+#endif
+ iter_ctx->emitted_lines = (unsigned int)(-1); // force #line directive
+ }
+
+// get the next preprocessed token
+ result_type const &operator()();
+
+// get the last recognized token (for error processing etc.)
+ result_type const &current_token() const { return act_token; }
+
+protected:
+ friend class pp_iterator<ContextT>;
+ bool on_include_helper(char const *t, char const *s, bool is_system,
+ bool include_next);
+
+protected:
+ result_type const &get_next_token();
+ result_type const &pp_token();
+
+ template <typename IteratorT>
+ bool extract_identifier(IteratorT &it);
+ template <typename IteratorT>
+ bool ensure_is_last_on_line(IteratorT& it, bool call_hook = true);
+ template <typename IteratorT>
+ bool skip_to_eol_with_check(IteratorT &it, bool call_hook = true);
+
+ bool pp_directive();
+ template <typename IteratorT>
+ bool handle_pp_directive(IteratorT &it);
+ bool dispatch_directive(tree_parse_info_type const &hit,
+ result_type const& found_directive,
+ token_sequence_type const& found_eoltokens);
+ void replace_undefined_identifiers(token_sequence_type &expanded);
+
+ void on_include(string_type const &s, bool is_system, bool include_next);
+ void on_include(typename parse_tree_type::const_iterator const &begin,
+ typename parse_tree_type::const_iterator const &end, bool include_next);
+
+ void on_define(parse_node_type const &node);
+ void on_undefine(lexer_type const &it);
+
+ void on_ifdef(result_type const& found_directive, lexer_type const &it);
+// typename parse_tree_type::const_iterator const &end);
+ void on_ifndef(result_type const& found_directive, lexer_type const& it);
+// typename parse_tree_type::const_iterator const &end);
+ void on_else();
+ void on_endif();
+ void on_illformed(typename result_type::string_type s);
+
+ void on_line(typename parse_tree_type::const_iterator const &begin,
+ typename parse_tree_type::const_iterator const &end);
+ void on_if(result_type const& found_directive,
+ typename parse_tree_type::const_iterator const &begin,
+ typename parse_tree_type::const_iterator const &end);
+ void on_elif(result_type const& found_directive,
+ typename parse_tree_type::const_iterator const &begin,
+ typename parse_tree_type::const_iterator const &end);
+ void on_error(typename parse_tree_type::const_iterator const &begin,
+ typename parse_tree_type::const_iterator const &end);
+#if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
+ void on_warning(typename parse_tree_type::const_iterator const &begin,
+ typename parse_tree_type::const_iterator const &end);
+#endif
+ bool on_pragma(typename parse_tree_type::const_iterator const &begin,
+ typename parse_tree_type::const_iterator const &end);
+
+ bool emit_line_directive();
+ bool returned_from_include();
+
+ bool interpret_pragma(token_sequence_type const &pragma_body,
+ token_sequence_type &result);
+
+private:
+ ContextT &ctx; // context, this iterator is associated with
+ boost::shared_ptr<base_iteration_context_type> iter_ctx;
+
+ bool seen_newline; // needed for recognizing begin of line
+ bool skipped_newline; // a newline has been skipped since last one
+ bool must_emit_line_directive; // must emit a line directive
+ result_type act_token; // current token
+ typename result_type::position_type &act_pos; // current fileposition (references the macromap)
+
+ token_sequence_type unput_queue; // tokens to be preprocessed again
+ token_sequence_type pending_queue; // tokens already preprocessed
+
+ // detect whether to insert additional whitespace in between two adjacent
+ // tokens, which otherwise would form a different token type, if
+ // re-tokenized
+ boost::wave::util::insert_whitespace_detection whitespace;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// eof token
+template <typename ContextT>
+typename pp_iterator_functor<ContextT>::result_type const
+ pp_iterator_functor<ContextT>::eof;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// returned_from_include()
+//
+// Tests if it is necessary to pop the include file context (eof inside
+// a file was reached). If yes, it pops this context. Preprocessing will
+// continue with the next outer file scope.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline bool
+pp_iterator_functor<ContextT>::returned_from_include()
+{
+ if (iter_ctx->first == iter_ctx->last && ctx.get_iteration_depth() > 0) {
+ // call the include policy trace function
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ ctx.get_hooks().returning_from_include_file();
+#else
+ ctx.get_hooks().returning_from_include_file(ctx.derived());
+#endif
+
+ // restore the previous iteration context after finishing the preprocessing
+ // of the included file
+ BOOST_WAVE_STRINGTYPE oldfile = iter_ctx->real_filename;
+ position_type old_pos (act_pos);
+
+ // if this file has include guards handle it as if it had a #pragma once
+#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+ if (need_include_guard_detection(ctx.get_language())) {
+ std::string guard_name;
+ if (iter_ctx->first.has_include_guards(guard_name))
+ ctx.add_pragma_once_header(ctx.get_current_filename(), guard_name);
+ }
+#endif
+ iter_ctx = ctx.pop_iteration_context();
+
+ must_emit_line_directive = true;
+ iter_ctx->emitted_lines = (unsigned int)(-1); // force #line directive
+ seen_newline = true;
+
+ // restore current file position
+ act_pos.set_file(iter_ctx->filename);
+ act_pos.set_line(iter_ctx->line);
+ act_pos.set_column(0);
+
+ // restore the actual current file and directory
+#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+ namespace fs = boost::filesystem;
+ fs::path rfp(wave::util::create_path(iter_ctx->real_filename.c_str()));
+ std::string real_filename(rfp.string());
+ ctx.set_current_filename(real_filename.c_str());
+#endif
+ ctx.set_current_directory(iter_ctx->real_filename.c_str());
+ ctx.set_current_relative_filename(iter_ctx->real_relative_filename.c_str());
+
+ // ensure the integrity of the #if/#endif stack
+ // report unbalanced #if/#endif now to make it possible to recover properly
+ if (iter_ctx->if_block_depth != ctx.get_if_block_depth()) {
+ using boost::wave::util::impl::escape_lit;
+ BOOST_WAVE_STRINGTYPE msg(escape_lit(oldfile));
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, unbalanced_if_endif,
+ msg.c_str(), old_pos);
+ }
+ return true;
+ }
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// operator()(): get the next preprocessed token
+//
+// throws a preprocess_exception, if appropriate
+//
+///////////////////////////////////////////////////////////////////////////////
+namespace impl {
+
+ // It may be necessary to emit a #line directive either
+ // - when comments need to be preserved: if the current token is not a
+ // whitespace, except comments
+ // - when comments are to be skipped: if the current token is not a
+ // whitespace token.
+ template <typename ContextT>
+ bool consider_emitting_line_directive(ContextT const& ctx, token_id id)
+ {
+ if (need_preserve_comments(ctx.get_language())) {
+ if (!IS_CATEGORY(id, EOLTokenType) && !IS_CATEGORY(id, EOFTokenType))
+ {
+ return true;
+ }
+ }
+ if (!IS_CATEGORY(id, WhiteSpaceTokenType) &&
+ !IS_CATEGORY(id, EOLTokenType) && !IS_CATEGORY(id, EOFTokenType))
+ {
+ return true;
+ }
+ return false;
+ }
+}
+
+template <typename ContextT>
+inline typename pp_iterator_functor<ContextT>::result_type const &
+pp_iterator_functor<ContextT>::operator()()
+{
+ using namespace boost::wave;
+
+ // make sure the cwd has been initialized
+ ctx.init_context();
+
+ // loop over skip able whitespace until something significant is found
+ bool was_seen_newline = seen_newline;
+ token_id id = T_UNKNOWN;
+
+ try { // catch lexer exceptions
+ do {
+ // get_next_token assigns result to act_token member
+ if (skipped_newline)
+ seen_newline = true;
+ get_next_token();
+
+ // if comments shouldn't be preserved replace them with newlines
+ id = token_id(act_token);
+ if (!need_preserve_comments(ctx.get_language()) &&
+ (T_CPPCOMMENT == id || context_policies::util::ccomment_has_newline(act_token)))
+ {
+ act_token.set_token_id(id = T_NEWLINE);
+ act_token.set_value("\n");
+ }
+
+ } while (ctx.get_hooks().may_skip_whitespace(ctx.derived(), act_token, skipped_newline));
+ }
+ catch (boost::wave::cpplexer::lexing_exception const& e) {
+ // dispatch any lexer exceptions to the context hook function
+ ctx.get_hooks().throw_exception(ctx.derived(), e);
+ return act_token;
+ }
+
+// if there were skipped any newlines, we must emit a #line directive
+ if ((must_emit_line_directive || (was_seen_newline && skipped_newline)) &&
+ impl::consider_emitting_line_directive(ctx, id))
+ {
+ // must emit a #line directive
+ if (need_emit_line_directives(ctx.get_language()) && emit_line_directive())
+ {
+ skipped_newline = false;
+ ctx.get_hooks().may_skip_whitespace(ctx.derived(), act_token, skipped_newline); // feed ws eater FSM
+ id = token_id(act_token);
+ }
+ }
+
+// cleanup of certain tokens required
+ seen_newline = false;
+ switch (static_cast<unsigned int>(id)) {
+ case T_NONREPLACABLE_IDENTIFIER:
+ act_token.set_token_id(id = T_IDENTIFIER);
+ break;
+
+ case T_GENERATEDNEWLINE: // was generated by emit_line_directive()
+ act_token.set_token_id(id = T_NEWLINE);
+ ++iter_ctx->emitted_lines;
+ seen_newline = true;
+ break;
+
+ case T_NEWLINE:
+ case T_CPPCOMMENT:
+ seen_newline = true;
+ ++iter_ctx->emitted_lines;
+ break;
+
+#if BOOST_WAVE_SUPPORT_CPP0X != 0
+ case T_RAWSTRINGLIT:
+ iter_ctx->emitted_lines +=
+ context_policies::util::rawstring_count_newlines(act_token);
+ break;
+#endif
+
+ case T_CCOMMENT: // will come here only if whitespace is preserved
+ iter_ctx->emitted_lines +=
+ context_policies::util::ccomment_count_newlines(act_token);
+ break;
+
+ case T_PP_NUMBER: // re-tokenize the pp-number
+ {
+ token_sequence_type rescanned;
+
+ std::string pp_number(
+ util::to_string<std::string>(act_token.get_value()));
+
+ lexer_type it = lexer_type(pp_number.begin(),
+ pp_number.end(), act_token.get_position(),
+ ctx.get_language());
+ lexer_type end = lexer_type();
+
+ for (/**/; it != end && T_EOF != token_id(*it); ++it)
+ rescanned.push_back(*it);
+
+ pending_queue.splice(pending_queue.begin(), rescanned);
+ act_token = pending_queue.front();
+ id = token_id(act_token);
+ pending_queue.pop_front();
+ }
+ break;
+
+ case T_EOF:
+ seen_newline = true;
+ break;
+
+ default: // make sure whitespace at line begin keeps seen_newline status
+ if (IS_CATEGORY(id, WhiteSpaceTokenType))
+ seen_newline = was_seen_newline;
+ break;
+ }
+
+ if (whitespace.must_insert(id, act_token.get_value())) {
+ // must insert some whitespace into the output stream to avoid adjacent
+ // tokens, which would form different (and wrong) tokens
+ whitespace.shift_tokens(T_SPACE);
+ pending_queue.push_front(act_token); // push this token back
+ return act_token = result_type(T_SPACE,
+ typename result_type::string_type(" "),
+ act_token.get_position());
+ }
+ whitespace.shift_tokens(id);
+ return ctx.get_hooks().generated_token(ctx.derived(), act_token);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline typename pp_iterator_functor<ContextT>::result_type const &
+pp_iterator_functor<ContextT>::get_next_token()
+{
+ using namespace boost::wave;
+
+// if there is something in the unput_queue, then return the next token from
+// there (all tokens in the queue are preprocessed already)
+ if (!pending_queue.empty() || !unput_queue.empty())
+ return pp_token(); // return next token
+
+// test for EOF, if there is a pending input context, pop it back and continue
+// parsing with it
+bool returned_from_include_file = returned_from_include();
+
+// try to generate the next token
+ if (iter_ctx->first != iter_ctx->last) {
+ do {
+ // If there are pending tokens in the queue, we'll have to return
+ // these. This may happen from a #pragma directive, which got replaced
+ // by some token sequence.
+ if (!pending_queue.empty()) {
+ util::on_exit::pop_front<token_sequence_type>
+ pop_front_token(pending_queue);
+
+ return act_token = pending_queue.front();
+ }
+
+ // adjust the current position (line and column)
+ bool was_seen_newline = seen_newline || returned_from_include_file;
+
+ // fetch the current token
+ act_token = *iter_ctx->first;
+ act_pos = act_token.get_position();
+
+ // act accordingly on the current token
+ token_id id = token_id(act_token);
+
+ if (T_EOF == id) {
+ // returned from an include file, continue with the next token
+ whitespace.shift_tokens(T_EOF);
+ ++iter_ctx->first;
+
+ // now make sure this line has a newline
+ if ((!seen_newline || act_pos.get_column() > 1) &&
+ !need_single_line(ctx.get_language()))
+ {
+ // warn, if this file does not end with a newline
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ last_line_not_terminated, "", act_pos);
+ }
+ continue; // if this is the main file, the while loop breaks
+ }
+ else if (T_NEWLINE == id || T_CPPCOMMENT == id) {
+ // a newline is to be returned ASAP, a C++ comment too
+ // (the C++ comment token includes the trailing newline)
+ seen_newline = true;
+ ++iter_ctx->first;
+
+ if (!ctx.get_if_block_status()) {
+ // skip this token because of the disabled #if block
+ whitespace.shift_tokens(id); // whitespace controller
+ util::impl::call_skipped_token_hook(ctx, act_token);
+ continue;
+ }
+ return act_token;
+ }
+ seen_newline = false;
+
+ if (was_seen_newline && pp_directive()) {
+ // a pp directive was found
+// pending_queue.push_back(result_type(T_NEWLINE, "\n", act_pos));
+// seen_newline = true;
+// must_emit_line_directive = true;
+
+ // loop to the next token to analyze
+ // simply fall through, since the iterator was already adjusted
+ // correctly
+ }
+ else if (ctx.get_if_block_status()) {
+ // preprocess this token, eat up more, if appropriate, return
+ // the next preprocessed token
+ return pp_token();
+ }
+ else {
+ // compilation condition is false: if the current token is a
+ // newline, account for it, otherwise discard the actual token and
+ // try the next one
+ if (T_NEWLINE == token_id(act_token)) {
+ seen_newline = true;
+ must_emit_line_directive = true;
+ }
+
+ // next token
+ util::impl::call_skipped_token_hook(ctx, act_token);
+ ++iter_ctx->first;
+ }
+
+ } while ((iter_ctx->first != iter_ctx->last) ||
+ (returned_from_include_file = returned_from_include()));
+
+ // overall eof reached
+ if (ctx.get_if_block_depth() > 0 && !need_single_line(ctx.get_language()))
+ {
+ // missing endif directive(s)
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ missing_matching_endif, "", act_pos);
+ }
+ }
+ else {
+ act_token = eof; // this is the last token
+ }
+
+// whitespace.shift_tokens(T_EOF); // whitespace controller
+ return act_token; // return eof token
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// emit_line_directive(): emits a line directive from the act_token data
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline bool
+pp_iterator_functor<ContextT>::emit_line_directive()
+{
+ using namespace boost::wave;
+
+typename ContextT::position_type pos = act_token.get_position();
+
+// if (must_emit_line_directive &&
+// iter_ctx->emitted_lines+1 == act_pos.get_line() &&
+// iter_ctx->filename == act_pos.get_file())
+// {
+// must_emit_line_directive = false;
+// return false;
+// }
+
+ if (must_emit_line_directive ||
+ iter_ctx->emitted_lines+1 != act_pos.get_line())
+ {
+ // unput the current token
+ pending_queue.push_front(act_token);
+ pos.set_line(act_pos.get_line());
+
+ if (iter_ctx->emitted_lines+2 == act_pos.get_line()) {
+ // prefer to output a single newline instead of the #line directive
+// whitespace.shift_tokens(T_NEWLINE);
+ act_token = result_type(T_NEWLINE, "\n", pos);
+ }
+ else {
+ // account for the newline emitted here
+ act_pos.set_line(act_pos.get_line()-1);
+ iter_ctx->emitted_lines = act_pos.get_line()-1;
+
+ token_sequence_type pending;
+
+ if (!ctx.get_hooks().emit_line_directive(ctx, pending, act_token))
+ {
+ unsigned int column = 6;
+
+ // the hook did not generate anything, emit default #line
+ pos.set_column(1);
+ pending.push_back(result_type(T_PP_LINE, "#line", pos));
+
+ pos.set_column(column); // account for '#line'
+ pending.push_back(result_type(T_SPACE, " ", pos));
+
+ // 21 is the max required size for a 64 bit integer represented as a
+ // string
+ char buffer[22];
+
+ using namespace std; // for some systems sprintf is in namespace std
+ sprintf (buffer, "%d", pos.get_line());
+
+ pos.set_column(++column); // account for ' '
+ pending.push_back(result_type(T_INTLIT, buffer, pos));
+ pos.set_column(column += (unsigned int)strlen(buffer)); // account for <number>
+ pending.push_back(result_type(T_SPACE, " ", pos));
+ pos.set_column(++column); // account for ' '
+
+ std::string file("\"");
+ boost::filesystem::path filename(
+ wave::util::create_path(act_pos.get_file().c_str()));
+
+ using wave::util::impl::escape_lit;
+ file += escape_lit(wave::util::native_file_string(filename)) + "\"";
+
+ pending.push_back(result_type(T_STRINGLIT, file.c_str(), pos));
+ pos.set_column(column += (unsigned int)file.size()); // account for filename
+ pending.push_back(result_type(T_GENERATEDNEWLINE, "\n", pos));
+ }
+
+ // if there is some replacement text, insert it into the pending queue
+ if (!pending.empty()) {
+ pending_queue.splice(pending_queue.begin(), pending);
+ act_token = pending_queue.front();
+ pending_queue.pop_front();
+ }
+ }
+
+ must_emit_line_directive = false; // we are now in sync
+ return true;
+ }
+
+ must_emit_line_directive = false; // we are now in sync
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// pptoken(): return the next preprocessed token
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline typename pp_iterator_functor<ContextT>::result_type const &
+pp_iterator_functor<ContextT>::pp_token()
+{
+ using namespace boost::wave;
+
+token_id id = token_id(*iter_ctx->first);
+
+ // eat all T_PLACEHOLDER tokens, eventually slipped through out of the
+ // macro engine
+ do {
+ if (!pending_queue.empty()) {
+ // if there are pending tokens in the queue, return the first one
+ act_token = pending_queue.front();
+ pending_queue.pop_front();
+ act_pos = act_token.get_position();
+ }
+ else if (!unput_queue.empty()
+ || T_IDENTIFIER == id
+ || IS_CATEGORY(id, KeywordTokenType)
+ || IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType)
+ || IS_CATEGORY(id, BoolLiteralTokenType))
+ {
+ // call the lexer, preprocess the required number of tokens, put them
+ // into the unput queue
+ act_token = ctx.expand_tokensequence(iter_ctx->first,
+ iter_ctx->last, pending_queue, unput_queue, skipped_newline);
+ }
+ else {
+ // simply return the next token
+ act_token = *iter_ctx->first;
+ ++iter_ctx->first;
+ }
+ id = token_id(act_token);
+
+ } while (T_PLACEHOLDER == id);
+ return act_token;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// pp_directive(): recognize a preprocessor directive
+//
+///////////////////////////////////////////////////////////////////////////////
+namespace impl {
+
+ // call 'found_directive' preprocessing hook
+ template <typename ContextT>
+ bool call_found_directive_hook(ContextT& ctx,
+ typename ContextT::token_type const& found_directive)
+ {
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ ctx.get_hooks().found_directive(found_directive);
+#else
+ if (ctx.get_hooks().found_directive(ctx.derived(), found_directive))
+ return true; // skip this directive and return newline only
+#endif
+ return false;
+ }
+
+// // call 'skipped_token' preprocessing hook
+// template <typename ContextT>
+// void call_skipped_token_hook(ContextT& ctx,
+// typename ContextT::token_type const& skipped)
+// {
+// #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+// ctx.get_hooks().skipped_token(skipped);
+// #else
+// ctx.get_hooks().skipped_token(ctx.derived(), skipped);
+// #endif
+// }
+
+ template <typename ContextT, typename IteratorT>
+ bool next_token_is_pp_directive(ContextT &ctx, IteratorT &it, IteratorT const &end)
+ {
+ using namespace boost::wave;
+
+ token_id id = T_UNKNOWN;
+ for (/**/; it != end; ++it) {
+ id = token_id(*it);
+ if (!IS_CATEGORY(id, WhiteSpaceTokenType))
+ break; // skip leading whitespace
+ if (IS_CATEGORY(id, EOLTokenType) || IS_CATEGORY(id, EOFTokenType))
+ break; // do not enter a new line
+ if (T_CPPCOMMENT == id ||
+ context_policies::util::ccomment_has_newline(*it))
+ {
+ break;
+ }
+
+ // this token gets skipped
+ util::impl::call_skipped_token_hook(ctx, *it);
+ }
+ BOOST_ASSERT(it == end || id != T_UNKNOWN);
+ return it != end && IS_CATEGORY(id, PPTokenType);
+ }
+
+ // verify that there isn't anything significant left on the line
+ template <typename ContextT, typename IteratorT>
+ bool pp_is_last_on_line(ContextT &ctx, IteratorT &it, IteratorT const &end,
+ bool call_hook = true)
+ {
+ using namespace boost::wave;
+
+ // this token gets skipped
+ if (call_hook)
+ util::impl::call_skipped_token_hook(ctx, *it);
+
+ for (++it; it != end; ++it) {
+ token_id id = token_id(*it);
+
+ if (T_CPPCOMMENT == id || T_NEWLINE == id ||
+ context_policies::util::ccomment_has_newline(*it))
+ {
+ if (call_hook)
+ util::impl::call_skipped_token_hook(ctx, *it);
+ ++it; // skip eol/C/C++ comment
+ return true; // no more significant tokens on this line
+ }
+
+ if (!IS_CATEGORY(id, WhiteSpaceTokenType))
+ break;
+
+ // this token gets skipped
+ if (call_hook)
+ util::impl::call_skipped_token_hook(ctx, *it);
+ }
+ return false;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename ContextT, typename IteratorT>
+ bool skip_to_eol(ContextT &ctx, IteratorT &it, IteratorT const &end,
+ bool call_hook = true)
+ {
+ using namespace boost::wave;
+
+ for (/**/; it != end; ++it) {
+ token_id id = token_id(*it);
+
+ if (T_CPPCOMMENT == id || T_NEWLINE == id ||
+ context_policies::util::ccomment_has_newline(*it))
+ {
+ // always call hook for eol
+ util::impl::call_skipped_token_hook(ctx, *it);
+ ++it; // skip eol/C/C++ comment
+ return true; // found eol
+ }
+
+ if (call_hook)
+ util::impl::call_skipped_token_hook(ctx, *it);
+ }
+ return false;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename ContextT, typename ContainerT>
+ inline void
+ remove_leading_whitespace(ContextT &ctx, ContainerT& c, bool call_hook = true)
+ {
+ typename ContainerT::iterator it = c.begin();
+ while (IS_CATEGORY(*it, WhiteSpaceTokenType)) {
+ typename ContainerT::iterator save = it++;
+ if (call_hook)
+ util::impl::call_skipped_token_hook(ctx, *save);
+ c.erase(save);
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename IteratorT>
+inline bool
+pp_iterator_functor<ContextT>::extract_identifier(IteratorT &it)
+{
+ token_id id = util::impl::skip_whitespace(it, iter_ctx->last);
+ if (T_IDENTIFIER == id || IS_CATEGORY(id, KeywordTokenType) ||
+ IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) ||
+ IS_CATEGORY(id, BoolLiteralTokenType))
+ {
+ IteratorT save = it;
+ if (impl::pp_is_last_on_line(ctx, save, iter_ctx->last, false))
+ return true;
+ }
+
+ // report the ill formed directive
+ impl::skip_to_eol(ctx, it, iter_ctx->last);
+
+string_type str(util::impl::as_string<string_type>(iter_ctx->first, it));
+
+ seen_newline = true;
+ iter_ctx->first = it;
+ on_illformed(str);
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename IteratorT>
+inline bool
+pp_iterator_functor<ContextT>::ensure_is_last_on_line(IteratorT& it, bool call_hook)
+{
+ if (!impl::pp_is_last_on_line(ctx, it, iter_ctx->last, call_hook))
+ {
+ // enable error recovery (start over with the next line)
+ impl::skip_to_eol(ctx, it, iter_ctx->last);
+
+ string_type str(util::impl::as_string<string_type>(
+ iter_ctx->first, it));
+
+ seen_newline = true;
+ iter_ctx->first = it;
+
+ // report an invalid directive
+ on_illformed(str);
+ return false;
+ }
+
+ if (it == iter_ctx->last && !need_single_line(ctx.get_language()))
+ {
+ // The line doesn't end with an eol but eof token.
+ seen_newline = true; // allow to resume after warning
+ iter_ctx->first = it;
+
+ // Trigger a warning that the last line was not terminated with a
+ // newline.
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ last_line_not_terminated, "", act_pos);
+
+ return false;
+ }
+ return true;
+}
+
+template <typename ContextT>
+template <typename IteratorT>
+inline bool
+pp_iterator_functor<ContextT>::skip_to_eol_with_check(IteratorT &it, bool call_hook)
+{
+ typename ContextT::string_type value ((*it).get_value());
+ if (!impl::skip_to_eol(ctx, it, iter_ctx->last, call_hook) &&
+ !need_single_line(ctx.get_language()))
+ {
+ // The line doesn't end with an eol but eof token.
+ seen_newline = true; // allow to resume after warning
+ iter_ctx->first = it;
+
+ // Trigger a warning, that the last line was not terminated with a
+ // newline.
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ last_line_not_terminated, "", act_pos);
+ return false;
+ }
+
+// normal line ending reached, adjust iterator and flag
+ seen_newline = true;
+ iter_ctx->first = it;
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// handle_pp_directive: handle certain pp_directives
+template <typename ContextT>
+template <typename IteratorT>
+inline bool
+pp_iterator_functor<ContextT>::handle_pp_directive(IteratorT &it)
+{
+ token_id id = token_id(*it);
+ bool can_exit = true;
+ bool call_hook_in_skip = true;
+ if (!ctx.get_if_block_status()) {
+ if (IS_EXTCATEGORY(*it, PPConditionalTokenType)) {
+ // simulate the if block hierarchy
+ switch (static_cast<unsigned int>(id)) {
+ case T_PP_IFDEF: // #ifdef
+ case T_PP_IFNDEF: // #ifndef
+ case T_PP_IF: // #if
+ ctx.enter_if_block(false);
+ break;
+
+ case T_PP_ELIF: // #elif
+ if (!ctx.get_enclosing_if_block_status()) {
+ if (!ctx.enter_elif_block(false)) {
+ // #else without matching #if
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ missing_matching_if, "#elif", act_pos);
+ return true; // do not analyze this directive any further
+ }
+ }
+ else {
+ can_exit = false; // #elif is not always safe to skip
+ }
+ break;
+
+ case T_PP_ELSE: // #else
+ case T_PP_ENDIF: // #endif
+ {
+ // handle this directive
+ if (T_PP_ELSE == token_id(*it))
+ on_else();
+ else
+ on_endif();
+
+ // make sure, there are no (non-whitespace) tokens left on
+ // this line
+ ensure_is_last_on_line(it);
+
+ // we skipped to the end of this line already
+ seen_newline = true;
+ iter_ctx->first = it;
+ }
+ return true;
+
+ default: // #something else
+ on_illformed((*it).get_value());
+ break;
+ }
+ }
+ else {
+ util::impl::call_skipped_token_hook(ctx, *it);
+ ++it;
+ }
+ }
+ else {
+ // try to handle the simple pp directives without parsing
+ result_type directive = *it;
+ bool include_next = false;
+ switch (static_cast<unsigned int>(id)) {
+ case T_PP_QHEADER: // #include "..."
+#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
+ case T_PP_QHEADER_NEXT:
+#endif
+ include_next = (T_PP_QHEADER_NEXT == id) ? true : false;
+ if (!impl::call_found_directive_hook(ctx, *it))
+ {
+ string_type dir((*it).get_value());
+
+ // make sure, there are no (non-whitespace) tokens left on
+ // this line
+ if (ensure_is_last_on_line(it))
+ {
+ seen_newline = true;
+ iter_ctx->first = it;
+ on_include (dir, false, include_next);
+ }
+ return true;
+ }
+ break;
+
+ case T_PP_HHEADER: // #include <...>
+#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
+ case T_PP_HHEADER_NEXT:
+#endif
+ include_next = (T_PP_HHEADER_NEXT == id) ? true : false;
+ if (!impl::call_found_directive_hook(ctx, *it))
+ {
+ string_type dir((*it).get_value());
+
+ // make sure, there are no (non-whitespace) tokens left on
+ // this line
+ if (ensure_is_last_on_line(it))
+ {
+ seen_newline = true;
+ iter_ctx->first = it;
+ on_include (dir, true, include_next);
+ }
+ return true;
+ }
+ break;
+
+ case T_PP_ELSE: // #else
+ case T_PP_ENDIF: // #endif
+ if (!impl::call_found_directive_hook(ctx, *it))
+ {
+ // handle this directive
+ if (T_PP_ELSE == token_id(*it))
+ on_else();
+ else
+ on_endif();
+
+ // make sure, there are no (non-whitespace) tokens left on
+ // this line
+ ensure_is_last_on_line(it);
+
+ // we skipped to the end of this line already
+ seen_newline = true;
+ iter_ctx->first = it;
+ return true;
+ }
+ break;
+
+ // extract everything on this line as arguments
+// case T_PP_IF: // #if
+// case T_PP_ELIF: // #elif
+// case T_PP_ERROR: // #error
+// case T_PP_WARNING: // #warning
+// case T_PP_PRAGMA: // #pragma
+// case T_PP_LINE: // #line
+// break;
+
+ // extract first non-whitespace token as argument
+ case T_PP_UNDEF: // #undef
+ if (!impl::call_found_directive_hook(ctx, *it) &&
+ extract_identifier(it))
+ {
+ on_undefine(it);
+ }
+ call_hook_in_skip = false;
+ break;
+
+ case T_PP_IFDEF: // #ifdef
+ if (!impl::call_found_directive_hook(ctx, *it) &&
+ extract_identifier(it))
+ {
+ on_ifdef(directive, it);
+ }
+ call_hook_in_skip = false;
+ break;
+
+ case T_PP_IFNDEF: // #ifndef
+ if (!impl::call_found_directive_hook(ctx, *it) &&
+ extract_identifier(it))
+ {
+ on_ifndef(directive, it);
+ }
+ call_hook_in_skip = false;
+ break;
+
+#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
+// case T_MSEXT_PP_REGION: // #region ...
+// break;
+//
+// case T_MSEXT_PP_ENDREGION: // #endregion
+// break;
+#endif
+
+ default:
+ can_exit = false;
+ break;
+ }
+ }
+
+// start over with the next line, if only possible
+ if (can_exit) {
+ skip_to_eol_with_check(it, call_hook_in_skip);
+ return true; // may be safely ignored
+ }
+ return false; // do not ignore this pp directive
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// pp_directive(): recognize a preprocessor directive
+template <typename ContextT>
+inline bool
+pp_iterator_functor<ContextT>::pp_directive()
+{
+ using namespace cpplexer;
+
+// test, if the next non-whitespace token is a pp directive
+lexer_type it = iter_ctx->first;
+
+ if (!impl::next_token_is_pp_directive(ctx, it, iter_ctx->last)) {
+ // skip null pp directive (no need to do it via the parser)
+ if (it != iter_ctx->last && T_POUND == BASE_TOKEN(token_id(*it))) {
+ if (impl::pp_is_last_on_line(ctx, it, iter_ctx->last)) {
+ // start over with the next line
+ seen_newline = true;
+ iter_ctx->first = it;
+ return true;
+ }
+ else if (ctx.get_if_block_status()) {
+ // report invalid pp directive
+ impl::skip_to_eol(ctx, it, iter_ctx->last);
+ seen_newline = true;
+
+ string_type str(boost::wave::util::impl::as_string<string_type>(
+ iter_ctx->first, it));
+
+ token_sequence_type faulty_line;
+
+ for (/**/; iter_ctx->first != it; ++iter_ctx->first)
+ faulty_line.push_back(*iter_ctx->first);
+
+ token_sequence_type pending;
+ if (ctx.get_hooks().found_unknown_directive(ctx, faulty_line, pending))
+ {
+ // if there is some replacement text, insert it into the pending queue
+ if (!pending.empty())
+ pending_queue.splice(pending_queue.begin(), pending);
+ return true;
+ }
+
+ // default behavior is to throw an exception
+ on_illformed(str);
+ }
+ }
+
+ // this line does not contain a pp directive, so simply return
+ return false;
+ }
+
+// found eof
+ if (it == iter_ctx->last)
+ return false;
+
+// ignore/handle all pp directives not related to conditional compilation while
+// if block status is false
+ if (handle_pp_directive(it)) {
+ // we may skip pp directives only if the current if block status is
+ // false or if it was a #include directive we could handle directly
+ return true; // the pp directive has been handled/skipped
+ }
+
+// found a pp directive, so try to identify it, start with the pp_token
+bool found_eof = false;
+result_type found_directive;
+token_sequence_type found_eoltokens;
+
+tree_parse_info_type hit = cpp_grammar_type::parse_cpp_grammar(
+ it, iter_ctx->last, act_pos, found_eof, found_directive, found_eoltokens);
+
+ if (hit.match) {
+ // position the iterator past the matched sequence to allow
+ // resynchronization, if an error occurs
+ iter_ctx->first = hit.stop;
+ seen_newline = true;
+ must_emit_line_directive = true;
+
+ // found a valid pp directive, dispatch to the correct function to handle
+ // the found pp directive
+ bool result = dispatch_directive (hit, found_directive, found_eoltokens);
+
+ if (found_eof && !need_single_line(ctx.get_language())) {
+ // The line was terminated with an end of file token.
+ // So trigger a warning, that the last line was not terminated with a
+ // newline.
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ last_line_not_terminated, "", act_pos);
+ }
+ return result;
+ }
+ else if (token_id(found_directive) != T_EOF) {
+ // recognized invalid directive
+ impl::skip_to_eol(ctx, it, iter_ctx->last);
+ seen_newline = true;
+
+ string_type str(boost::wave::util::impl::as_string<string_type>(
+ iter_ctx->first, it));
+ iter_ctx->first = it;
+
+ // report the ill formed directive
+ on_illformed(str);
+ }
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// dispatch_directive(): dispatch a recognized preprocessor directive
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline bool
+pp_iterator_functor<ContextT>::dispatch_directive(
+ tree_parse_info_type const &hit, result_type const& found_directive,
+ token_sequence_type const& found_eoltokens)
+{
+ using namespace cpplexer;
+
+ typedef typename parse_tree_type::const_iterator const_child_iterator_t;
+
+// this iterator points to the root node of the parse tree
+const_child_iterator_t begin = hit.trees.begin();
+
+// decide, which preprocessor directive was found
+parse_tree_type const &root = (*begin).children;
+parse_node_value_type const &nodeval = get_first_leaf(*root.begin()).value;
+//long node_id = nodeval.id().to_long();
+
+const_child_iterator_t begin_child_it = (*root.begin()).children.begin();
+const_child_iterator_t end_child_it = (*root.begin()).children.end();
+
+token_id id = token_id(found_directive);
+
+ // call preprocessing hook
+ if (impl::call_found_directive_hook(ctx, found_directive))
+ return true; // skip this directive and return newline only
+
+ switch (static_cast<unsigned int>(id)) {
+// case T_PP_QHEADER: // #include "..."
+// #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
+// case T_PP_QHEADER_NEXT: // #include_next "..."
+// #endif
+// on_include ((*nodeval.begin()).get_value(), false,
+// T_PP_QHEADER_NEXT == id);
+// break;
+
+// case T_PP_HHEADER: // #include <...>
+// #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
+// case T_PP_HHEADER_NEXT: // #include_next <...>
+// #endif
+// on_include ((*nodeval.begin()).get_value(), true,
+// T_PP_HHEADER_NEXT == id);
+// break;
+
+ case T_PP_INCLUDE: // #include ...
+#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
+ case T_PP_INCLUDE_NEXT: // #include_next ...
+#endif
+ on_include (begin_child_it, end_child_it, T_PP_INCLUDE_NEXT == id);
+ break;
+
+ case T_PP_DEFINE: // #define
+ on_define (*begin);
+ break;
+
+// case T_PP_UNDEF: // #undef
+// on_undefine(*nodeval.begin());
+// break;
+//
+// case T_PP_IFDEF: // #ifdef
+// on_ifdef(found_directive, begin_child_it, end_child_it);
+// break;
+//
+// case T_PP_IFNDEF: // #ifndef
+// on_ifndef(found_directive, begin_child_it, end_child_it);
+// break;
+
+ case T_PP_IF: // #if
+ on_if(found_directive, begin_child_it, end_child_it);
+ break;
+
+ case T_PP_ELIF: // #elif
+ on_elif(found_directive, begin_child_it, end_child_it);
+ break;
+
+// case T_PP_ELSE: // #else
+// on_else();
+// break;
+
+// case T_PP_ENDIF: // #endif
+// on_endif();
+// break;
+
+ case T_PP_LINE: // #line
+ on_line(begin_child_it, end_child_it);
+ break;
+
+ case T_PP_ERROR: // #error
+ on_error(begin_child_it, end_child_it);
+ break;
+
+#if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
+ case T_PP_WARNING: // #warning
+ on_warning(begin_child_it, end_child_it);
+ break;
+#endif
+
+ case T_PP_PRAGMA: // #pragma
+ return on_pragma(begin_child_it, end_child_it);
+
+#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
+ case T_MSEXT_PP_REGION:
+ case T_MSEXT_PP_ENDREGION:
+ break; // ignore these
+#endif
+
+ default: // #something else
+ on_illformed((*nodeval.begin()).get_value());
+
+ // if we end up here, we have been instructed to ignore the error, so
+ // we simply copy the whole construct to the output
+ {
+ token_sequence_type expanded;
+ get_token_value<result_type, parse_node_type> get_value;
+
+ std::copy(make_ref_transform_iterator(begin_child_it, get_value),
+ make_ref_transform_iterator(end_child_it, get_value),
+ std::inserter(expanded, expanded.end()));
+ pending_queue.splice(pending_queue.begin(), expanded);
+ }
+ break;
+ }
+
+ // properly skip trailing newline for all directives
+ typename token_sequence_type::const_iterator eol = found_eoltokens.begin();
+ impl::skip_to_eol(ctx, eol, found_eoltokens.end());
+ return true; // return newline only
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// on_include: handle #include <...> or #include "..." directives
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline void
+pp_iterator_functor<ContextT>::on_include (string_type const &s,
+ bool is_system, bool include_next)
+{
+ BOOST_ASSERT(ctx.get_if_block_status());
+
+// strip quotes first, extract filename
+typename string_type::size_type pos_end = s.find_last_of(is_system ? '>' : '\"');
+
+ if (string_type::npos == pos_end) {
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_statement,
+ s.c_str(), act_pos);
+ return;
+ }
+
+typename string_type::size_type pos_begin =
+ s.find_last_of(is_system ? '<' : '\"', pos_end-1);
+
+ if (string_type::npos == pos_begin) {
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_statement,
+ s.c_str(), act_pos);
+ return;
+ }
+
+std::string file_token(s.substr(pos_begin, pos_end-pos_begin+1).c_str());
+std::string file_path(s.substr(pos_begin+1, pos_end-pos_begin-1).c_str());
+
+// finally include the file
+ on_include_helper(file_token.c_str(), file_path.c_str(), is_system,
+ include_next);
+}
+
+template <typename ContextT>
+inline bool
+pp_iterator_functor<ContextT>::on_include_helper (char const *f, char const *s,
+ bool is_system, bool include_next)
+{
+ namespace fs = boost::filesystem;
+
+// try to locate the given file, searching through the include path lists
+std::string file_path(s);
+std::string dir_path;
+#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
+char const *current_name = include_next ? iter_ctx->real_filename.c_str() : 0;
+#else
+char const *current_name = 0; // never try to match current file name
+#endif
+
+// call the 'found_include_directive' hook function
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ ctx.get_hooks().found_include_directive(f, include_next);
+#else
+ if (ctx.get_hooks().found_include_directive(ctx.derived(), f, include_next))
+ return true; // client returned false: skip file to include
+#endif
+
+ file_path = util::impl::unescape_lit(file_path);
+ std::string native_path_str;
+
+ if (!ctx.get_hooks().locate_include_file(ctx, file_path, is_system,
+ current_name, dir_path, native_path_str))
+ {
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_file,
+ file_path.c_str(), act_pos);
+ return false;
+ }
+
+// test, if this file is known through a #pragma once directive
+#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+ if (!ctx.has_pragma_once(native_path_str))
+#endif
+ {
+ // the new include file determines the actual current directory
+ ctx.set_current_directory(native_path_str.c_str());
+
+ // preprocess the opened file
+ boost::shared_ptr<base_iteration_context_type> new_iter_ctx (
+ new iteration_context_type(ctx, native_path_str.c_str(), act_pos,
+ boost::wave::enable_prefer_pp_numbers(ctx.get_language()),
+ is_system ? base_iteration_context_type::system_header :
+ base_iteration_context_type::user_header));
+
+ // call the include policy trace function
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ ctx.get_hooks().opened_include_file(dir_path, file_path,
+ ctx.get_iteration_depth(), is_system);
+#else
+ ctx.get_hooks().opened_include_file(ctx.derived(), dir_path, file_path,
+ is_system);
+#endif
+
+ // store current file position
+ iter_ctx->real_relative_filename = ctx.get_current_relative_filename().c_str();
+ iter_ctx->filename = act_pos.get_file();
+ iter_ctx->line = act_pos.get_line();
+ iter_ctx->if_block_depth = ctx.get_if_block_depth();
+ iter_ctx->emitted_lines = (unsigned int)(-1); // force #line directive
+
+ // push the old iteration context onto the stack and continue with the new
+ ctx.push_iteration_context(act_pos, iter_ctx);
+ iter_ctx = new_iter_ctx;
+ seen_newline = true; // fake a newline to trigger pp_directive
+ must_emit_line_directive = true;
+
+ act_pos.set_file(iter_ctx->filename); // initialize file position
+#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+ fs::path rfp(wave::util::create_path(iter_ctx->real_filename.c_str()));
+ std::string real_filename(rfp.string());
+ ctx.set_current_filename(real_filename.c_str());
+#endif
+
+ ctx.set_current_relative_filename(dir_path.c_str());
+ iter_ctx->real_relative_filename = dir_path.c_str();
+
+ act_pos.set_line(iter_ctx->line);
+ act_pos.set_column(0);
+ }
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// on_include(): handle #include ... directives
+//
+///////////////////////////////////////////////////////////////////////////////
+
+namespace impl {
+
+ // trim all whitespace from the beginning and the end of the given string
+ template <typename StringT>
+ inline StringT
+ trim_whitespace(StringT const &s)
+ {
+ typedef typename StringT::size_type size_type;
+
+ size_type first = s.find_first_not_of(" \t\v\f");
+ if (StringT::npos == first)
+ return StringT();
+ size_type last = s.find_last_not_of(" \t\v\f");
+ return s.substr(first, last-first+1);
+ }
+}
+
+template <typename ContextT>
+inline void
+pp_iterator_functor<ContextT>::on_include(
+ typename parse_tree_type::const_iterator const &begin,
+ typename parse_tree_type::const_iterator const &end, bool include_next)
+{
+ BOOST_ASSERT(ctx.get_if_block_status());
+
+// preprocess the given token sequence (the body of the #include directive)
+get_token_value<result_type, parse_node_type> get_value;
+token_sequence_type expanded;
+token_sequence_type toexpand;
+
+ std::copy(make_ref_transform_iterator(begin, get_value),
+ make_ref_transform_iterator(end, get_value),
+ std::inserter(toexpand, toexpand.end()));
+
+ typename token_sequence_type::iterator begin2 = toexpand.begin();
+ ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded,
+ false);
+
+// now, include the file
+string_type s (impl::trim_whitespace(boost::wave::util::impl::as_string(expanded)));
+bool is_system = '<' == s[0] && '>' == s[s.size()-1];
+
+ if (!is_system && !('\"' == s[0] && '\"' == s[s.size()-1])) {
+ // should resolve into something like <...> or "..."
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_statement,
+ s.c_str(), act_pos);
+ return;
+ }
+ on_include(s, is_system, include_next);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// on_define(): handle #define directives
+//
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename ContextT>
+inline void
+pp_iterator_functor<ContextT>::on_define (parse_node_type const &node)
+{
+ BOOST_ASSERT(ctx.get_if_block_status());
+
+// retrieve the macro definition from the parse tree
+result_type macroname;
+std::vector<result_type> macroparameters;
+token_sequence_type macrodefinition;
+bool has_parameters = false;
+position_type pos(act_token.get_position());
+
+ if (!boost::wave::util::retrieve_macroname(ctx, node,
+ BOOST_WAVE_PLAIN_DEFINE_ID, macroname, pos, false))
+ return;
+ has_parameters = boost::wave::util::retrieve_macrodefinition(node,
+ BOOST_WAVE_MACRO_PARAMETERS_ID, macroparameters, pos, false);
+ boost::wave::util::retrieve_macrodefinition(node,
+ BOOST_WAVE_MACRO_DEFINITION_ID, macrodefinition, pos, false);
+
+ if (has_parameters) {
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ if (boost::wave::need_variadics(ctx.get_language())) {
+ // test whether ellipsis are given, and if yes, if these are placed as the
+ // last argument, test if __VA_ARGS__ is used as a macro parameter name
+ using namespace cpplexer;
+ typedef typename std::vector<result_type>::iterator
+ parameter_iterator_t;
+
+ bool seen_ellipses = false;
+ parameter_iterator_t end = macroparameters.end();
+ for (parameter_iterator_t pit = macroparameters.begin();
+ pit != end; ++pit)
+ {
+ if (seen_ellipses) {
+ // ellipses are not the last given formal argument
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ bad_define_statement, macroname.get_value().c_str(),
+ (*pit).get_position());
+ return;
+ }
+ if (T_ELLIPSIS == token_id(*pit))
+ seen_ellipses = true;
+
+ // can't use __VA_ARGS__ as a argument name
+ if ("__VA_ARGS__" == (*pit).get_value()) {
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ bad_define_statement_va_args,
+ macroname.get_value().c_str(), (*pit).get_position());
+ return;
+ }
+ }
+
+ // if there wasn't an ellipsis, then there shouldn't be a __VA_ARGS__
+ // placeholder in the definition too [C99 Standard 6.10.3.5]
+ if (!seen_ellipses) {
+ typedef typename token_sequence_type::iterator definition_iterator_t;
+
+ bool seen_va_args = false;
+ definition_iterator_t pend = macrodefinition.end();
+ for (definition_iterator_t dit = macrodefinition.begin();
+ dit != pend; ++dit)
+ {
+ if (T_IDENTIFIER == token_id(*dit) &&
+ "__VA_ARGS__" == (*dit).get_value())
+ {
+ seen_va_args = true;
+ }
+ }
+ if (seen_va_args) {
+ // must not have seen __VA_ARGS__ placeholder
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ bad_define_statement_va_args,
+ macroname.get_value().c_str(), act_token.get_position());
+ return;
+ }
+ }
+ }
+ else
+#endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ {
+ // test, that there is no T_ELLIPSES given
+ using namespace cpplexer;
+ typedef typename std::vector<result_type>::iterator
+ parameter_iterator_t;
+
+ parameter_iterator_t end = macroparameters.end();
+ for (parameter_iterator_t pit = macroparameters.begin();
+ pit != end; ++pit)
+ {
+ if (T_ELLIPSIS == token_id(*pit)) {
+ // if variadics are disabled, no ellipses should be given
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ bad_define_statement, macroname.get_value().c_str(),
+ (*pit).get_position());
+ return;
+ }
+ }
+ }
+ }
+
+// add the new macro to the macromap
+ ctx.add_macro_definition(macroname, has_parameters, macroparameters,
+ macrodefinition);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// on_undefine(): handle #undef directives
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline void
+pp_iterator_functor<ContextT>::on_undefine (lexer_type const &it)
+{
+ BOOST_ASSERT(ctx.get_if_block_status());
+
+// retrieve the macro name to undefine from the parse tree
+ ctx.remove_macro_definition((*it).get_value()); // throws for predefined macros
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// on_ifdef(): handle #ifdef directives
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline void
+pp_iterator_functor<ContextT>::on_ifdef(
+ result_type const& found_directive, lexer_type const &it)
+// typename parse_tree_type::const_iterator const &it)
+// typename parse_tree_type::const_iterator const &end)
+{
+// get_token_value<result_type, parse_node_type> get_value;
+// token_sequence_type toexpand;
+//
+// std::copy(make_ref_transform_iterator((*begin).children.begin(), get_value),
+// make_ref_transform_iterator((*begin).children.end(), get_value),
+// std::inserter(toexpand, toexpand.end()));
+
+bool is_defined = false;
+token_sequence_type directive;
+
+ directive.insert(directive.end(), *it);
+
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ is_defined = ctx.is_defined_macro((*it).get_value()); // toexpand.begin(), toexpand.end());
+ ctx.get_hooks().evaluated_conditional_expression(directive, is_defined);
+#else
+ do {
+ is_defined = ctx.is_defined_macro((*it).get_value()); // toexpand.begin(), toexpand.end());
+ } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(),
+ found_directive, directive, is_defined));
+#endif
+ ctx.enter_if_block(is_defined);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// on_ifndef(): handle #ifndef directives
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline void
+pp_iterator_functor<ContextT>::on_ifndef(
+ result_type const& found_directive, lexer_type const &it)
+// typename parse_tree_type::const_iterator const &it)
+// typename parse_tree_type::const_iterator const &end)
+{
+// get_token_value<result_type, parse_node_type> get_value;
+// token_sequence_type toexpand;
+//
+// std::copy(make_ref_transform_iterator((*begin).children.begin(), get_value),
+// make_ref_transform_iterator((*begin).children.end(), get_value),
+// std::inserter(toexpand, toexpand.end()));
+
+bool is_defined = false;
+token_sequence_type directive;
+
+ directive.insert(directive.end(), *it);
+
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ is_defined = ctx.is_defined_macro((*it).get_value()); // toexpand.begin(), toexpand.end());
+ ctx.get_hooks().evaluated_conditional_expression(directive, is_defined);
+#else
+ do {
+ is_defined = ctx.is_defined_macro((*it).get_value()); // toexpand.begin(), toexpand.end());
+ } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(),
+ found_directive, directive, is_defined));
+#endif
+ ctx.enter_if_block(!is_defined);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// on_else(): handle #else directives
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline void
+pp_iterator_functor<ContextT>::on_else()
+{
+ if (!ctx.enter_else_block()) {
+ // #else without matching #if
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, missing_matching_if,
+ "#else", act_pos);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// on_endif(): handle #endif directives
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline void
+pp_iterator_functor<ContextT>::on_endif()
+{
+ if (!ctx.exit_if_block()) {
+ // #endif without matching #if
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, missing_matching_if,
+ "#endif", act_pos);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// replace all remaining (== undefined) identifiers with an integer literal '0'
+template <typename ContextT>
+inline void
+pp_iterator_functor<ContextT>::replace_undefined_identifiers(
+ token_sequence_type &expanded)
+{
+ typename token_sequence_type::iterator exp_end = expanded.end();
+ for (typename token_sequence_type::iterator exp_it = expanded.begin();
+ exp_it != exp_end; ++exp_it)
+ {
+ using namespace boost::wave;
+
+ token_id id = token_id(*exp_it);
+ if (IS_CATEGORY(id, IdentifierTokenType) ||
+ IS_CATEGORY(id, KeywordTokenType))
+ {
+ (*exp_it).set_token_id(T_INTLIT);
+ (*exp_it).set_value("0");
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// on_if(): handle #if directives
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline void
+pp_iterator_functor<ContextT>::on_if(
+ result_type const& found_directive,
+ typename parse_tree_type::const_iterator const &begin,
+ typename parse_tree_type::const_iterator const &end)
+{
+// preprocess the given sequence into the provided list
+get_token_value<result_type, parse_node_type> get_value;
+token_sequence_type toexpand;
+
+ std::copy(make_ref_transform_iterator(begin, get_value),
+ make_ref_transform_iterator(end, get_value),
+ std::inserter(toexpand, toexpand.end()));
+
+ impl::remove_leading_whitespace(ctx, toexpand);
+
+bool if_status = false;
+grammars::value_error status = grammars::error_noerror;
+token_sequence_type expanded;
+
+ do {
+ expanded.clear();
+
+ typename token_sequence_type::iterator begin2 = toexpand.begin();
+ ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded);
+
+ // replace all remaining (== undefined) identifiers with an integer literal '0'
+ replace_undefined_identifiers(expanded);
+
+#if BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS != 0
+ {
+ string_type outstr(boost::wave::util::impl::as_string(toexpand));
+ outstr += "(" + boost::wave::util::impl::as_string(expanded) + ")";
+ BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS_OUT << "#if " << outstr
+ << std::endl;
+ }
+#endif
+ try {
+ // parse the expression and enter the #if block
+ if_status = grammars::expression_grammar_gen<result_type>::
+ evaluate(expanded.begin(), expanded.end(), act_pos,
+ ctx.get_if_block_status(), status);
+ }
+ catch (boost::wave::preprocess_exception const& e) {
+ // any errors occurred have to be dispatched to the context hooks
+ ctx.get_hooks().throw_exception(ctx.derived(), e);
+ break;
+ }
+
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ ctx.get_hooks().evaluated_conditional_expression(toexpand, if_status);
+ } while (false);
+#else
+ } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(),
+ found_directive, toexpand, if_status)
+ && status == grammars::error_noerror);
+#endif
+
+ ctx.enter_if_block(if_status);
+ if (grammars::error_noerror != status) {
+ // division or other error by zero occurred
+ string_type expression = util::impl::as_string(expanded);
+ if (0 == expression.size())
+ expression = "<empty expression>";
+
+ if (grammars::error_division_by_zero & status) {
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, division_by_zero,
+ expression.c_str(), act_pos);
+ }
+ else if (grammars::error_integer_overflow & status) {
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, integer_overflow,
+ expression.c_str(), act_pos);
+ }
+ else if (grammars::error_character_overflow & status) {
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ character_literal_out_of_range, expression.c_str(), act_pos);
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// on_elif(): handle #elif directives
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline void
+pp_iterator_functor<ContextT>::on_elif(
+ result_type const& found_directive,
+ typename parse_tree_type::const_iterator const &begin,
+ typename parse_tree_type::const_iterator const &end)
+{
+// preprocess the given sequence into the provided list
+get_token_value<result_type, parse_node_type> get_value;
+token_sequence_type toexpand;
+
+ std::copy(make_ref_transform_iterator(begin, get_value),
+ make_ref_transform_iterator(end, get_value),
+ std::inserter(toexpand, toexpand.end()));
+
+ impl::remove_leading_whitespace(ctx, toexpand);
+
+// check current if block status
+ if (ctx.get_if_block_some_part_status()) {
+ if (!ctx.enter_elif_block(false)) {
+ // #else without matching #if
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ missing_matching_if, "#elif", act_pos);
+ // fall through...
+ }
+
+ // skip all the expression and the trailing whitespace
+ typename token_sequence_type::iterator begin2 = toexpand.begin();
+
+ impl::skip_to_eol(ctx, begin2, toexpand.end());
+ return; // one of previous #if/#elif was true, so don't enter this #elif
+ }
+
+// preprocess the given sequence into the provided list
+bool if_status = false;
+grammars::value_error status = grammars::error_noerror;
+token_sequence_type expanded;
+
+ do {
+ expanded.clear();
+
+ typename token_sequence_type::iterator begin2 = toexpand.begin();
+ ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded);
+
+ // replace all remaining (== undefined) identifiers with an integer literal '0'
+ replace_undefined_identifiers(expanded);
+
+#if BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS != 0
+ {
+ string_type outstr(boost::wave::util::impl::as_string(toexpand));
+ outstr += "(" + boost::wave::util::impl::as_string(expanded) + ")";
+ BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS_OUT << "#elif " << outstr << std::endl;
+ }
+#endif
+
+ try {
+ // parse the expression and enter the #elif block
+ if_status = grammars::expression_grammar_gen<result_type>::
+ evaluate(expanded.begin(), expanded.end(), act_pos,
+ ctx.get_if_block_status(), status);
+ }
+ catch (boost::wave::preprocess_exception const& e) {
+ // any errors occurred have to be dispatched to the context hooks
+ ctx.get_hooks().throw_exception(ctx.derived(), e);
+ }
+
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ ctx.get_hooks().evaluated_conditional_expression(toexpand, if_status);
+ } while (false);
+#else
+ } while (ctx.get_hooks().evaluated_conditional_expression(ctx.derived(),
+ found_directive, toexpand, if_status)
+ && status == grammars::error_noerror);
+#endif
+
+ if (!ctx.enter_elif_block(if_status)) {
+ // #elif without matching #if
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, missing_matching_if,
+ "#elif", act_pos);
+ return;
+ }
+
+ if (grammars::error_noerror != status) {
+ // division or other error by zero occurred
+ string_type expression = util::impl::as_string(expanded);
+ if (0 == expression.size())
+ expression = "<empty expression>";
+
+ if (grammars::error_division_by_zero & status) {
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, division_by_zero,
+ expression.c_str(), act_pos);
+ }
+ else if (grammars::error_integer_overflow & status) {
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ integer_overflow, expression.c_str(), act_pos);
+ }
+ else if (grammars::error_character_overflow & status) {
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ character_literal_out_of_range, expression.c_str(), act_pos);
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// on_illformed(): handles the illegal directive
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline void
+pp_iterator_functor<ContextT>::on_illformed(
+ typename result_type::string_type s)
+{
+ BOOST_ASSERT(ctx.get_if_block_status());
+
+ // some messages have more than one newline at the end
+ typename string_type::size_type p = s.find_last_not_of('\n');
+ if (string_type::npos != p)
+ s = s.substr(0, p+1);
+
+ // throw the exception
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, ill_formed_directive,
+ s.c_str(), act_pos);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// on_line(): handle #line directives
+//
+///////////////////////////////////////////////////////////////////////////////
+
+namespace impl {
+
+ template <typename IteratorT, typename StringT>
+ bool retrieve_line_info (IteratorT first, IteratorT const &last,
+ unsigned int &line, StringT &file,
+ boost::wave::preprocess_exception::error_code& error)
+ {
+ using namespace boost::wave;
+ token_id id = token_id(*first);
+ if (T_PP_NUMBER == id || T_INTLIT == id) {
+ // extract line number
+ using namespace std; // some systems have atoi in namespace std
+ line = (unsigned int)atoi((*first).get_value().c_str());
+ if (0 == line)
+ error = preprocess_exception::bad_line_number;
+
+ // re-extract line number with spirit to diagnose overflow
+ using namespace boost::spirit::classic;
+ if (!parse((*first).get_value().c_str(), int_p).full)
+ error = preprocess_exception::bad_line_number;
+
+ // extract file name (if it is given)
+ while (++first != last && IS_CATEGORY(*first, WhiteSpaceTokenType))
+ /**/; // skip whitespace
+
+ if (first != last) {
+ if (T_STRINGLIT != token_id(*first)) {
+ error = preprocess_exception::bad_line_filename;
+ return false;
+ }
+
+ StringT const &file_lit = (*first).get_value();
+
+ if ('L' == file_lit[0]) {
+ error = preprocess_exception::bad_line_filename;
+ return false; // shouldn't be a wide character string
+ }
+
+ file = file_lit.substr(1, file_lit.size()-2);
+
+ // test if there is other junk on this line
+ while (++first != last && IS_CATEGORY(*first, WhiteSpaceTokenType))
+ /**/; // skip whitespace
+ }
+ return first == last;
+ }
+ error = preprocess_exception::bad_line_statement;
+ return false;
+ }
+}
+
+template <typename ContextT>
+inline void
+pp_iterator_functor<ContextT>::on_line(
+ typename parse_tree_type::const_iterator const &begin,
+ typename parse_tree_type::const_iterator const &end)
+{
+ BOOST_ASSERT(ctx.get_if_block_status());
+
+// Try to extract the line number and file name from the given token list
+// directly. If that fails, preprocess the whole token sequence and try again
+// to extract this information.
+token_sequence_type expanded;
+get_token_value<result_type, parse_node_type> get_value;
+
+ typedef typename ref_transform_iterator_generator<
+ get_token_value<result_type, parse_node_type>,
+ typename parse_tree_type::const_iterator
+ >::type const_tree_iterator_t;
+
+const_tree_iterator_t first = make_ref_transform_iterator(begin, get_value);
+const_tree_iterator_t last = make_ref_transform_iterator(end, get_value);
+
+// try to interpret the #line body as a number followed by an optional
+// string literal
+unsigned int line = 0;
+preprocess_exception::error_code error = preprocess_exception::no_error;
+string_type file_name;
+token_sequence_type toexpand;
+
+ std::copy(first, last, std::inserter(toexpand, toexpand.end()));
+ if (!impl::retrieve_line_info(first, last, line, file_name, error)) {
+ // preprocess the body of this #line message
+ typename token_sequence_type::iterator begin2 = toexpand.begin();
+ ctx.expand_whole_tokensequence(begin2, toexpand.end(),
+ expanded, false);
+
+ error = preprocess_exception::no_error;
+ if (!impl::retrieve_line_info(expanded.begin(), expanded.end(),
+ line, file_name, error))
+ {
+ typename ContextT::string_type msg(
+ boost::wave::util::impl::as_string(expanded));
+ BOOST_WAVE_THROW_VAR_CTX(ctx, preprocess_exception, error,
+ msg.c_str(), act_pos);
+ return;
+ }
+
+ // call the corresponding pp hook function
+ ctx.get_hooks().found_line_directive(ctx.derived(), expanded, line,
+ file_name.c_str());
+ }
+ else {
+ // call the corresponding pp hook function
+ ctx.get_hooks().found_line_directive(ctx.derived(), toexpand, line,
+ file_name.c_str());
+ }
+
+// the queues should be empty at this point
+ BOOST_ASSERT(unput_queue.empty());
+ BOOST_ASSERT(pending_queue.empty());
+
+// make sure error recovery starts on the next line
+ must_emit_line_directive = true;
+
+// diagnose possible error in detected line directive
+ if (error != preprocess_exception::no_error) {
+ typename ContextT::string_type msg(
+ boost::wave::util::impl::as_string(expanded));
+ BOOST_WAVE_THROW_VAR_CTX(ctx, preprocess_exception, error,
+ msg.c_str(), act_pos);
+ return;
+ }
+
+// set new line number/filename only if ok
+ if (!file_name.empty()) { // reuse current file name
+ using boost::wave::util::impl::unescape_lit;
+ act_pos.set_file(unescape_lit(file_name).c_str());
+ }
+ act_pos.set_line(line);
+ iter_ctx->first.set_position(act_pos);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// on_error(): handle #error directives
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline void
+pp_iterator_functor<ContextT>::on_error(
+ typename parse_tree_type::const_iterator const &begin,
+ typename parse_tree_type::const_iterator const &end)
+{
+ BOOST_ASSERT(ctx.get_if_block_status());
+
+// preprocess the given sequence into the provided list
+token_sequence_type expanded;
+get_token_value<result_type, parse_node_type> get_value;
+
+typename ref_transform_iterator_generator<
+ get_token_value<result_type, parse_node_type>,
+ typename parse_tree_type::const_iterator
+ >::type first = make_ref_transform_iterator(begin, get_value);
+
+#if BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY != 0
+// preprocess the body of this #error message
+token_sequence_type toexpand;
+
+ std::copy(first, make_ref_transform_iterator(end, get_value),
+ std::inserter(toexpand, toexpand.end()));
+
+ typename token_sequence_type::iterator begin2 = toexpand.begin();
+ ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded,
+ false);
+ if (!ctx.get_hooks().found_error_directive(ctx.derived(), toexpand))
+#else
+// simply copy the body of this #error message to the issued diagnostic
+// message
+ std::copy(first, make_ref_transform_iterator(end, get_value),
+ std::inserter(expanded, expanded.end()));
+ if (!ctx.get_hooks().found_error_directive(ctx.derived(), expanded))
+#endif
+ {
+ // report the corresponding error
+ BOOST_WAVE_STRINGTYPE msg(boost::wave::util::impl::as_string(expanded));
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, error_directive,
+ msg.c_str(), act_pos);
+ }
+}
+
+#if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
+///////////////////////////////////////////////////////////////////////////////
+//
+// on_warning(): handle #warning directives
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline void
+pp_iterator_functor<ContextT>::on_warning(
+ typename parse_tree_type::const_iterator const &begin,
+ typename parse_tree_type::const_iterator const &end)
+{
+ BOOST_ASSERT(ctx.get_if_block_status());
+
+// preprocess the given sequence into the provided list
+token_sequence_type expanded;
+get_token_value<result_type, parse_node_type> get_value;
+
+typename ref_transform_iterator_generator<
+ get_token_value<result_type, parse_node_type>,
+ typename parse_tree_type::const_iterator
+ >::type first = make_ref_transform_iterator(begin, get_value);
+
+#if BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY != 0
+// preprocess the body of this #warning message
+token_sequence_type toexpand;
+
+ std::copy(first, make_ref_transform_iterator(end, get_value),
+ std::inserter(toexpand, toexpand.end()));
+
+ typename token_sequence_type::iterator begin2 = toexpand.begin();
+ ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded,
+ false);
+ if (!ctx.get_hooks().found_warning_directive(ctx.derived(), toexpand))
+#else
+// simply copy the body of this #warning message to the issued diagnostic
+// message
+ std::copy(first, make_ref_transform_iterator(end, get_value),
+ std::inserter(expanded, expanded.end()));
+ if (!ctx.get_hooks().found_warning_directive(ctx.derived(), expanded))
+#endif
+ {
+ // report the corresponding error
+ BOOST_WAVE_STRINGTYPE msg(boost::wave::util::impl::as_string(expanded));
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, warning_directive,
+ msg.c_str(), act_pos);
+ }
+}
+#endif // BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// on_pragma(): handle #pragma directives
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline bool
+pp_iterator_functor<ContextT>::on_pragma(
+ typename parse_tree_type::const_iterator const &begin,
+ typename parse_tree_type::const_iterator const &end)
+{
+ using namespace boost::wave;
+
+ BOOST_ASSERT(ctx.get_if_block_status());
+
+// Look at the pragma token sequence and decide, if the first token is STDC
+// (see C99 standard [6.10.6.2]), if it is, the sequence must _not_ be
+// preprocessed.
+token_sequence_type expanded;
+get_token_value<result_type, parse_node_type> get_value;
+
+ typedef typename ref_transform_iterator_generator<
+ get_token_value<result_type, parse_node_type>,
+ typename parse_tree_type::const_iterator
+ >::type const_tree_iterator_t;
+
+const_tree_iterator_t first = make_ref_transform_iterator(begin, get_value);
+const_tree_iterator_t last = make_ref_transform_iterator(end, get_value);
+
+ expanded.push_back(result_type(T_PP_PRAGMA, "#pragma", act_token.get_position()));
+ expanded.push_back(result_type(T_SPACE, " ", act_token.get_position()));
+
+ while (++first != last && IS_CATEGORY(*first, WhiteSpaceTokenType))
+ expanded.push_back(*first); // skip whitespace
+
+ if (first != last) {
+ if (T_IDENTIFIER == token_id(*first) &&
+ boost::wave::need_c99(ctx.get_language()) &&
+ (*first).get_value() == "STDC")
+ {
+ // do _not_ preprocess the token sequence
+ std::copy(first, last, std::inserter(expanded, expanded.end()));
+ }
+ else {
+#if BOOST_WAVE_PREPROCESS_PRAGMA_BODY != 0
+ // preprocess the given tokensequence
+ token_sequence_type toexpand;
+
+ std::copy(first, last, std::inserter(toexpand, toexpand.end()));
+
+ typename token_sequence_type::iterator begin2 = toexpand.begin();
+ ctx.expand_whole_tokensequence(begin2, toexpand.end(),
+ expanded, false);
+#else
+ // do _not_ preprocess the token sequence
+ std::copy(first, last, std::inserter(expanded, expanded.end()));
+#endif
+ }
+ }
+ expanded.push_back(result_type(T_NEWLINE, "\n", act_token.get_position()));
+
+// the queues should be empty at this point
+ BOOST_ASSERT(unput_queue.empty());
+ BOOST_ASSERT(pending_queue.empty());
+
+// try to interpret the expanded #pragma body
+ token_sequence_type pending;
+ if (interpret_pragma(expanded, pending)) {
+ // if there is some replacement text, insert it into the pending queue
+ if (!pending.empty())
+ pending_queue.splice(pending_queue.begin(), pending);
+ return true; // this #pragma was successfully recognized
+ }
+
+#if BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES != 0
+// Move the resulting token sequence into the pending_queue, so it will be
+// returned to the caller.
+ if (boost::wave::need_emit_pragma_directives(ctx.get_language())) {
+ pending_queue.splice(pending_queue.begin(), expanded);
+ return false; // return the whole #pragma directive
+ }
+#endif
+ return true; // skip the #pragma at all
+}
+
+template <typename ContextT>
+inline bool
+pp_iterator_functor<ContextT>::interpret_pragma(
+ token_sequence_type const &pragma_body, token_sequence_type &result)
+{
+ using namespace cpplexer;
+
+ typename token_sequence_type::const_iterator end = pragma_body.end();
+ typename token_sequence_type::const_iterator it = pragma_body.begin();
+ for (++it; it != end && IS_CATEGORY(*it, WhiteSpaceTokenType); ++it)
+ /**/; // skip whitespace
+
+ if (it == end) // eof reached
+ return false;
+
+ return boost::wave::util::interpret_pragma(
+ ctx.derived(), act_token, it, end, result);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace impl
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// pp_iterator
+//
+// The boost::wave::pp_iterator template is the iterator, through which
+// the resulting preprocessed input stream is accessible.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename ContextT>
+class pp_iterator
+: public boost::spirit::classic::multi_pass<
+ boost::wave::impl::pp_iterator_functor<ContextT>,
+ boost::wave::util::functor_input
+ >
+{
+public:
+ typedef boost::wave::impl::pp_iterator_functor<ContextT> input_policy_type;
+
+private:
+ typedef
+ boost::spirit::classic::multi_pass<input_policy_type, boost::wave::util::functor_input>
+ base_type;
+ typedef pp_iterator<ContextT> self_type;
+ typedef boost::wave::util::functor_input functor_input_type;
+
+public:
+ pp_iterator()
+ {}
+
+ template <typename IteratorT>
+ pp_iterator(ContextT &ctx, IteratorT const &first, IteratorT const &last,
+ typename ContextT::position_type const &pos)
+ : base_type(input_policy_type(ctx, first, last, pos))
+ {}
+
+ bool force_include(char const *path_, bool is_last)
+ {
+ bool result = this->get_functor().on_include_helper(path_, path_,
+ false, false);
+ if (is_last) {
+ this->functor_input_type::
+ template inner<input_policy_type>::advance_input();
+ }
+ return result;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_ITERATOR_HPP_175CA88F_7273_43FA_9039_BCF7459E1F29_INCLUDED)
diff --git a/boost/wave/util/cpp_macromap.hpp b/boost/wave/util/cpp_macromap.hpp
new file mode 100644
index 0000000000..8b155b83af
--- /dev/null
+++ b/boost/wave/util/cpp_macromap.hpp
@@ -0,0 +1,1942 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ Macro expansion engine
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_MACROMAP_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED)
+#define CPP_MACROMAP_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED
+
+#include <cstdlib>
+#include <cstdio>
+#include <ctime>
+
+#include <list>
+#include <map>
+#include <set>
+#include <vector>
+#include <iterator>
+#include <algorithm>
+
+#include <boost/assert.hpp>
+#include <boost/wave/wave_config.hpp>
+#if BOOST_WAVE_SERIALIZATION != 0
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#endif
+
+#include <boost/filesystem/path.hpp>
+
+#include <boost/wave/util/time_conversion_helper.hpp>
+#include <boost/wave/util/unput_queue_iterator.hpp>
+#include <boost/wave/util/macro_helpers.hpp>
+#include <boost/wave/util/macro_definition.hpp>
+#include <boost/wave/util/symbol_table.hpp>
+#include <boost/wave/util/cpp_macromap_utils.hpp>
+#include <boost/wave/util/cpp_macromap_predef.hpp>
+#include <boost/wave/util/filesystem_compatibility.hpp>
+#include <boost/wave/grammars/cpp_defined_grammar_gen.hpp>
+
+#include <boost/wave/wave_version.hpp>
+#include <boost/wave/cpp_exceptions.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 { namespace util {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// macromap
+//
+// This class holds all currently defined macros and on demand expands
+// those macro definitions
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+class macromap {
+
+ typedef macromap<ContextT> self_type;
+ typedef typename ContextT::token_type token_type;
+ typedef typename token_type::string_type string_type;
+ typedef typename token_type::position_type position_type;
+
+ typedef typename ContextT::token_sequence_type definition_container_type;
+ typedef std::vector<token_type> parameter_container_type;
+
+ typedef macro_definition<token_type, definition_container_type>
+ macro_definition_type;
+ typedef symbol_table<string_type, macro_definition_type>
+ defined_macros_type;
+ typedef typename defined_macros_type::value_type::second_type
+ macro_ref_type;
+
+public:
+ macromap(ContextT &ctx_)
+ : current_macros(0), defined_macros(new defined_macros_type(1)),
+ main_pos("", 0), ctx(ctx_), macro_uid(1)
+ {
+ current_macros = defined_macros.get();
+ }
+ ~macromap() {}
+
+// Add a new macro to the given macro scope
+ bool add_macro(token_type const &name, bool has_parameters,
+ parameter_container_type &parameters,
+ definition_container_type &definition, bool is_predefined = false,
+ defined_macros_type *scope = 0);
+
+// Tests, whether the given macro name is defined in the given macro scope
+ bool is_defined(string_type const &name,
+ typename defined_macros_type::iterator &it,
+ defined_macros_type *scope = 0) const;
+
+// expects a token sequence as its parameters
+ template <typename IteratorT>
+ bool is_defined(IteratorT const &begin, IteratorT const &end) const;
+
+// expects an arbitrary string as its parameter
+ bool is_defined(string_type const &str) const;
+
+// Get the macro definition for the given macro scope
+ bool get_macro(string_type const &name, bool &has_parameters,
+ bool &is_predefined, position_type &pos,
+ parameter_container_type &parameters,
+ definition_container_type &definition,
+ defined_macros_type *scope = 0) const;
+
+// Remove a macro name from the given macro scope
+ bool remove_macro(string_type const &name, position_type const& pos,
+ bool even_predefined = false);
+
+ template <typename IteratorT, typename ContainerT>
+ token_type const &expand_tokensequence(IteratorT &first,
+ IteratorT const &last, ContainerT &pending, ContainerT &expanded,
+ bool& seen_newline, bool expand_operator_defined);
+
+// Expand all macros inside the given token sequence
+ template <typename IteratorT, typename ContainerT>
+ void expand_whole_tokensequence(ContainerT &expanded,
+ IteratorT &first, IteratorT const &last,
+ bool expand_operator_defined);
+
+// Init the predefined macros (add them to the given scope)
+ void init_predefined_macros(char const *fname = "<Unknown>",
+ defined_macros_type *scope = 0, bool at_global_scope = true);
+ void predefine_macro(defined_macros_type *scope, string_type const &name,
+ token_type const &t);
+
+// Init the internal macro symbol namespace
+ void reset_macromap();
+
+ position_type &get_main_pos() { return main_pos; }
+ position_type const& get_main_pos() const { return main_pos; }
+
+// interface for macro name introspection
+ typedef typename defined_macros_type::name_iterator name_iterator;
+ typedef typename defined_macros_type::const_name_iterator const_name_iterator;
+
+ name_iterator begin()
+ { return defined_macros_type::make_iterator(current_macros->begin()); }
+ name_iterator end()
+ { return defined_macros_type::make_iterator(current_macros->end()); }
+ const_name_iterator begin() const
+ { return defined_macros_type::make_iterator(current_macros->begin()); }
+ const_name_iterator end() const
+ { return defined_macros_type::make_iterator(current_macros->end()); }
+
+protected:
+// Helper functions for expanding all macros in token sequences
+ template <typename IteratorT, typename ContainerT>
+ token_type const &expand_tokensequence_worker(ContainerT &pending,
+ unput_queue_iterator<IteratorT, token_type, ContainerT> &first,
+ unput_queue_iterator<IteratorT, token_type, ContainerT> const &last,
+ bool& seen_newline, bool expand_operator_defined);
+
+// Collect all arguments supplied to a macro invocation
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ template <typename IteratorT, typename ContainerT, typename SizeT>
+ typename std::vector<ContainerT>::size_type collect_arguments (
+ token_type const curr_token, std::vector<ContainerT> &arguments,
+ IteratorT &next, IteratorT const &end, SizeT const &parameter_count,
+ bool& seen_newline);
+#else
+ template <typename IteratorT, typename ContainerT, typename SizeT>
+ typename std::vector<ContainerT>::size_type collect_arguments (
+ token_type const curr_token, std::vector<ContainerT> &arguments,
+ IteratorT &next, IteratorT &endparen, IteratorT const &end,
+ SizeT const &parameter_count, bool& seen_newline);
+#endif
+
+// Expand a single macro name
+ template <typename IteratorT, typename ContainerT>
+ bool expand_macro(ContainerT &pending, token_type const &name,
+ typename defined_macros_type::iterator it,
+ IteratorT &first, IteratorT const &last,
+ bool& seen_newline, bool expand_operator_defined,
+ defined_macros_type *scope = 0, ContainerT *queue_symbol = 0);
+
+// Expand a predefined macro (__LINE__, __FILE__ and __INCLUDE_LEVEL__)
+ template <typename ContainerT>
+ bool expand_predefined_macro(token_type const &curr_token,
+ ContainerT &expanded);
+
+// Expand a single macro argument
+ template <typename ContainerT>
+ void expand_argument (typename std::vector<ContainerT>::size_type arg,
+ std::vector<ContainerT> &arguments,
+ std::vector<ContainerT> &expanded_args, bool expand_operator_defined,
+ std::vector<bool> &has_expanded_args);
+
+// Expand the replacement list (replaces parameters with arguments)
+ template <typename ContainerT>
+ void expand_replacement_list(
+ macro_definition_type const &macrodefinition,
+ std::vector<ContainerT> &arguments,
+ bool expand_operator_defined, ContainerT &expanded);
+
+// Rescans the replacement list for macro expansion
+ template <typename IteratorT, typename ContainerT>
+ void rescan_replacement_list(token_type const &curr_token,
+ macro_definition_type &macrodef, ContainerT &replacement_list,
+ ContainerT &expanded, bool expand_operator_defined,
+ IteratorT &nfirst, IteratorT const &nlast);
+
+// Resolves the operator defined() and replces the token with "0" or "1"
+ template <typename IteratorT, typename ContainerT>
+ token_type const &resolve_defined(IteratorT &first, IteratorT const &last,
+ ContainerT &expanded);
+
+// Resolve operator _Pragma or the #pragma directive
+ template <typename IteratorT, typename ContainerT>
+ bool resolve_operator_pragma(IteratorT &first,
+ IteratorT const &last, ContainerT &expanded, bool& seen_newline);
+
+// Handle the concatenation operator '##'
+ template <typename ContainerT>
+ bool concat_tokensequence(ContainerT &expanded);
+
+ template <typename ContainerT>
+ bool is_valid_concat(string_type new_value,
+ position_type const &pos, ContainerT &rescanned);
+
+#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<typename Archive>
+ void save(Archive &ar, const unsigned int version) const
+ {
+ using namespace boost::serialization;
+ ar & make_nvp("defined_macros", defined_macros);
+ }
+ template<typename Archive>
+ void load(Archive &ar, const unsigned int loaded_version)
+ {
+ using namespace boost::serialization;
+ if (version != (loaded_version & ~version_mask)) {
+ BOOST_WAVE_THROW(preprocess_exception, incompatible_config,
+ "cpp_context state version", get_main_pos());
+ }
+ ar & make_nvp("defined_macros", defined_macros);
+ current_macros = defined_macros.get();
+ }
+ BOOST_SERIALIZATION_SPLIT_MEMBER()
+#endif
+
+private:
+ defined_macros_type *current_macros; // current symbol table
+ boost::shared_ptr<defined_macros_type> defined_macros; // global symbol table
+
+ token_type act_token; // current token
+ position_type main_pos; // last token position in the pp_iterator
+ string_type base_name; // the name to be expanded by __BASE_FILE__
+ ContextT &ctx; // context object associated with the macromap
+ long macro_uid;
+ predefined_macros predef; // predefined macro support
+};
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// add_macro(): adds a new macro to the macromap
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline bool
+macromap<ContextT>::add_macro(token_type const &name, bool has_parameters,
+ parameter_container_type &parameters, definition_container_type &definition,
+ bool is_predefined, defined_macros_type *scope)
+{
+ if (!is_predefined && impl::is_special_macroname (name.get_value())) {
+ // exclude special macro names
+ BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
+ illegal_redefinition, name.get_value().c_str(), main_pos,
+ name.get_value().c_str());
+ return false;
+ }
+ if (boost::wave::need_variadics(ctx.get_language()) &&
+ "__VA_ARGS__" == name.get_value())
+ {
+ // can't use __VA_ARGS__ as a macro name
+ BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
+ bad_define_statement_va_args, name.get_value().c_str(), main_pos,
+ name.get_value().c_str());
+ return false;
+ }
+ if (AltExtTokenType == (token_id(name) & ExtTokenOnlyMask)) {
+ // exclude special operator names
+ BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
+ illegal_operator_redefinition, name.get_value().c_str(), main_pos,
+ name.get_value().c_str());
+ return false;
+ }
+
+// try to define the new macro
+defined_macros_type *current_scope = scope ? scope : current_macros;
+typename defined_macros_type::iterator it = current_scope->find(name.get_value());
+
+ if (it != current_scope->end()) {
+ // redefinition, should not be different
+ macro_definition_type* macrodef = (*it).second.get();
+ if (macrodef->is_functionlike != has_parameters ||
+ !impl::parameters_equal(macrodef->macroparameters, parameters) ||
+ !impl::definition_equals(macrodef->macrodefinition, definition))
+ {
+ BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
+ macro_redefinition, name.get_value().c_str(), main_pos,
+ name.get_value().c_str());
+ }
+ return false;
+ }
+
+// test the validity of the parameter names
+ if (has_parameters) {
+ std::set<typename token_type::string_type> names;
+
+ typedef typename parameter_container_type::iterator
+ parameter_iterator_type;
+ typedef typename std::set<typename token_type::string_type>::iterator
+ name_iterator_type;
+
+ parameter_iterator_type end = parameters.end();
+ for (parameter_iterator_type itp = parameters.begin(); itp != end; ++itp)
+ {
+ name_iterator_type pit = names.find((*itp).get_value());
+
+ if (pit != names.end()) {
+ // duplicate parameter name
+ BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
+ duplicate_parameter_name, (*pit).c_str(), main_pos,
+ name.get_value().c_str());
+ return false;
+ }
+ names.insert((*itp).get_value());
+ }
+ }
+
+// insert a new macro node
+ std::pair<typename defined_macros_type::iterator, bool> p =
+ current_scope->insert(
+ typename defined_macros_type::value_type(
+ name.get_value(),
+ macro_ref_type(new macro_definition_type(name,
+ has_parameters, is_predefined, ++macro_uid)
+ )
+ )
+ );
+
+ if (!p.second) {
+ BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
+ macro_insertion_error, name.get_value().c_str(), main_pos,
+ name.get_value().c_str());
+ return false;
+ }
+
+// add the parameters and the definition
+ std::swap((*p.first).second->macroparameters, parameters);
+ std::swap((*p.first).second->macrodefinition, definition);
+
+// call the context supplied preprocessing hook
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ ctx.get_hooks().defined_macro(name, has_parameters,
+ (*p.first).second->macroparameters,
+ (*p.first).second->macrodefinition, is_predefined);
+#else
+ ctx.get_hooks().defined_macro(ctx.derived(), name, has_parameters,
+ (*p.first).second->macroparameters,
+ (*p.first).second->macrodefinition, is_predefined);
+#endif
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// is_defined(): returns, whether a given macro is already defined
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline bool
+macromap<ContextT>::is_defined(typename token_type::string_type const &name,
+ typename defined_macros_type::iterator &it,
+ defined_macros_type *scope) const
+{
+ if (0 == scope) scope = current_macros;
+
+ if ((it = scope->find(name)) != scope->end())
+ return true; // found in symbol table
+
+// quick pre-check
+ if (name.size() < 8 || '_' != name[0] || '_' != name[1])
+ return false; // quick check failed
+
+ return name == "__LINE__" || name == "__FILE__" ||
+ name == "__INCLUDE_LEVEL__";
+}
+
+template <typename ContextT>
+template <typename IteratorT>
+inline bool
+macromap<ContextT>::is_defined(IteratorT const &begin,
+ IteratorT const &end) const
+{
+// in normal mode the name under inspection should consist of an identifier
+// only
+token_id id = token_id(*begin);
+
+ if (T_IDENTIFIER != id &&
+ !IS_CATEGORY(id, KeywordTokenType) &&
+ !IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) &&
+ !IS_CATEGORY(id, BoolLiteralTokenType))
+ {
+ std::string msg(impl::get_full_name(begin, end));
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, invalid_macroname,
+ msg.c_str(), main_pos);
+ return false;
+ }
+
+IteratorT it = begin;
+string_type name ((*it).get_value());
+typename defined_macros_type::iterator cit;
+
+ if (++it != end) {
+ // there should be only one token as the inspected name
+ std::string msg(impl::get_full_name(begin, end));
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, invalid_macroname,
+ msg.c_str(), main_pos);
+ return false;
+ }
+ return is_defined(name, cit, 0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// same as above, only takes an arbitrary string type as its parameter
+template <typename ContextT>
+inline bool
+macromap<ContextT>::is_defined(string_type const &str) const
+{
+ typename defined_macros_type::iterator cit;
+ return is_defined(str, cit, 0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Get the macro definition for the given macro scope
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline bool
+macromap<ContextT>::get_macro(string_type const &name, bool &has_parameters,
+ bool &is_predefined, position_type &pos,
+ parameter_container_type &parameters,
+ definition_container_type &definition,
+ defined_macros_type *scope) const
+{
+ typename defined_macros_type::iterator it;
+ if (!is_defined(name, it, scope))
+ return false;
+
+macro_definition_type &macro_def = *(*it).second.get();
+
+ has_parameters = macro_def.is_functionlike;
+ is_predefined = macro_def.is_predefined;
+ pos = macro_def.macroname.get_position();
+ parameters = macro_def.macroparameters;
+ definition = macro_def.macrodefinition;
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// remove_macro(): remove a macro from the macromap
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline bool
+macromap<ContextT>::remove_macro(string_type const &name,
+ position_type const& pos, bool even_predefined)
+{
+ typename defined_macros_type::iterator it = current_macros->find(name);
+
+ if (it != current_macros->end()) {
+ if ((*it).second->is_predefined) {
+ if (!even_predefined || impl::is_special_macroname(name)) {
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ bad_undefine_statement, name.c_str(), main_pos);
+ return false;
+ }
+ }
+ current_macros->erase(it);
+
+ // call the context supplied preprocessing hook function
+ token_type tok(T_IDENTIFIER, name, pos);
+
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ ctx.get_hooks().undefined_macro(tok);
+#else
+ ctx.get_hooks().undefined_macro(ctx.derived(), tok);
+#endif
+ return true;
+ }
+ else if (impl::is_special_macroname(name)) {
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_undefine_statement,
+ name.c_str(), pos);
+ }
+ return false; // macro was not defined
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// expand_tokensequence
+//
+// This function is a helper function which wraps the given iterator
+// range into corresponding unput_iterator's and calls the main workhorse
+// of the macro expansion engine (the function expand_tokensequence_worker)
+//
+// This is the top level macro expansion function called from the
+// preprocessing iterator component only.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename IteratorT, typename ContainerT>
+inline typename ContextT::token_type const &
+macromap<ContextT>::expand_tokensequence(IteratorT &first,
+ IteratorT const &last, ContainerT &pending, ContainerT &expanded,
+ bool& seen_newline, bool expand_operator_defined)
+{
+ typedef impl::gen_unput_queue_iterator<IteratorT, token_type, ContainerT>
+ gen_type;
+ typedef typename gen_type::return_type iterator_type;
+
+ iterator_type first_it = gen_type::generate(expanded, first);
+ iterator_type last_it = gen_type::generate(last);
+
+on_exit::assign<IteratorT, iterator_type> on_exit(first, first_it);
+
+ return expand_tokensequence_worker(pending, first_it, last_it,
+ seen_newline, expand_operator_defined);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// expand_tokensequence_worker
+//
+// This function is the main workhorse of the macro expansion engine. It
+// expands as much tokens as needed to identify the next preprocessed
+// token to return to the caller.
+// It returns the next preprocessed token.
+//
+// The iterator 'first' is adjusted accordingly.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename IteratorT, typename ContainerT>
+inline typename ContextT::token_type const &
+macromap<ContextT>::expand_tokensequence_worker(
+ ContainerT &pending,
+ unput_queue_iterator<IteratorT, token_type, ContainerT> &first,
+ unput_queue_iterator<IteratorT, token_type, ContainerT> const &last,
+ bool& seen_newline, bool expand_operator_defined)
+{
+// if there exist pending tokens (tokens, which are already preprocessed), then
+// return the next one from there
+ if (!pending.empty()) {
+ on_exit::pop_front<definition_container_type> pop_front_token(pending);
+
+ return act_token = pending.front();
+ }
+
+// analyze the next element of the given sequence, if it is an
+// T_IDENTIFIER token, try to replace this as a macro etc.
+ using namespace boost::wave;
+ typedef unput_queue_iterator<IteratorT, token_type, ContainerT> iterator_type;
+
+ if (first != last) {
+ token_id id = token_id(*first);
+
+ // ignore placeholder tokens
+ if (T_PLACEHOLDER == id) {
+ token_type placeholder = *first;
+
+ ++first;
+ if (first == last)
+ return act_token = placeholder;
+ id = token_id(*first);
+ }
+
+ if (T_IDENTIFIER == id || IS_CATEGORY(id, KeywordTokenType) ||
+ IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) ||
+ IS_CATEGORY(id, BoolLiteralTokenType))
+ {
+ // try to replace this identifier as a macro
+ if (expand_operator_defined && (*first).get_value() == "defined") {
+ // resolve operator defined()
+ return resolve_defined(first, last, pending);
+ }
+ else if (boost::wave::need_variadics(ctx.get_language()) &&
+ (*first).get_value() == "_Pragma")
+ {
+ // in C99 mode only: resolve the operator _Pragma
+ token_type curr_token = *first;
+
+ if (!resolve_operator_pragma(first, last, pending, seen_newline) ||
+ pending.size() > 0)
+ {
+ // unknown to us pragma or supplied replacement, return the
+ // next token
+ on_exit::pop_front<definition_container_type> pop_token(pending);
+
+ return act_token = pending.front();
+ }
+
+ // the operator _Pragma() was eaten completely, continue
+ return act_token = token_type(T_PLACEHOLDER, "_",
+ curr_token.get_position());
+ }
+
+ token_type name_token (*first);
+ typename defined_macros_type::iterator it;
+
+ if (is_defined(name_token.get_value(), it)) {
+ // the current token contains an identifier, which is currently
+ // defined as a macro
+ if (expand_macro(pending, name_token, it, first, last,
+ seen_newline, expand_operator_defined))
+ {
+ // the tokens returned by expand_macro should be rescanned
+ // beginning at the last token of the returned replacement list
+ if (first != last) {
+ // splice the last token back into the input queue
+ typename ContainerT::reverse_iterator rit = pending.rbegin();
+
+ first.get_unput_queue().splice(
+ first.get_unput_queue().begin(), pending,
+ (++rit).base(), pending.end());
+ }
+
+ // fall through ...
+ }
+ else if (!pending.empty()) {
+ // return the first token from the pending queue
+ on_exit::pop_front<definition_container_type> pop_queue (pending);
+
+ return act_token = pending.front();
+ }
+ else {
+ // macro expansion reached the eoi
+ return act_token = token_type();
+ }
+
+ // return the next preprocessed token
+ return expand_tokensequence_worker(pending, first, last,
+ seen_newline, expand_operator_defined);
+ }
+// else if (expand_operator_defined) {
+// // in preprocessing conditionals undefined identifiers and keywords
+// // are to be replaced with '0' (see. C++ standard 16.1.4, [cpp.cond])
+// return act_token =
+// token_type(T_INTLIT, "0", (*first++).get_position());
+// }
+ else {
+ act_token = name_token;
+ ++first;
+ return act_token;
+ }
+ }
+ else if (expand_operator_defined && IS_CATEGORY(*first, BoolLiteralTokenType)) {
+ // expanding a constant expression inside #if/#elif, special handling
+ // of 'true' and 'false'
+
+ // all remaining identifiers and keywords, except for true and false,
+ // are replaced with the pp-number 0 (C++ standard 16.1.4, [cpp.cond])
+ return act_token = token_type(T_INTLIT, T_TRUE != id ? "0" : "1",
+ (*first++).get_position());
+ }
+ else {
+ act_token = *first;
+ ++first;
+ return act_token;
+ }
+ }
+ return act_token = token_type(); // eoi
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// collect_arguments(): collect the actual arguments of a macro invocation
+//
+// return the number of successfully detected non-empty arguments
+//
+///////////////////////////////////////////////////////////////////////////////
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+template <typename ContextT>
+template <typename IteratorT, typename ContainerT, typename SizeT>
+inline typename std::vector<ContainerT>::size_type
+macromap<ContextT>::collect_arguments (token_type const curr_token,
+ std::vector<ContainerT> &arguments, IteratorT &next,
+ IteratorT const &end, SizeT const &parameter_count, bool& seen_newline)
+#else
+template <typename ContextT>
+template <typename IteratorT, typename ContainerT, typename SizeT>
+inline typename std::vector<ContainerT>::size_type
+macromap<ContextT>::collect_arguments (token_type const curr_token,
+ std::vector<ContainerT> &arguments, IteratorT &next, IteratorT &endparen,
+ IteratorT const &end, SizeT const &parameter_count, bool& seen_newline)
+#endif
+{
+ using namespace boost::wave;
+
+ arguments.push_back(ContainerT());
+
+// collect the actual arguments
+typename std::vector<ContainerT>::size_type count_arguments = 0;
+int nested_parenthesis_level = 1;
+ContainerT *argument = &arguments[0];
+bool was_whitespace = false;
+token_type startof_argument_list = *next;
+
+ while (++next != end && nested_parenthesis_level) {
+ token_id id = token_id(*next);
+
+ if (0 == parameter_count &&
+ !IS_CATEGORY((*next), WhiteSpaceTokenType) && id != T_NEWLINE &&
+ id != T_RIGHTPAREN && id != T_LEFTPAREN)
+ {
+ // there shouldn't be any arguments
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ too_many_macroarguments, curr_token.get_value().c_str(),
+ main_pos);
+ return 0;
+ }
+
+ switch (static_cast<unsigned int>(id)) {
+ case T_LEFTPAREN:
+ ++nested_parenthesis_level;
+ argument->push_back(*next);
+ was_whitespace = false;
+ break;
+
+ case T_RIGHTPAREN:
+ {
+ if (--nested_parenthesis_level >= 1)
+ argument->push_back(*next);
+ else {
+ // found closing parenthesis
+// trim_sequence(argument);
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS == 0
+ endparen = next;
+#endif
+ if (parameter_count > 0) {
+ if (argument->empty() ||
+ impl::is_whitespace_only(*argument))
+ {
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ if (boost::wave::need_variadics(ctx.get_language())) {
+ // store a placemarker as the argument
+ argument->push_back(token_type(T_PLACEMARKER, "\xA7",
+ (*next).get_position()));
+ ++count_arguments;
+ }
+#endif
+ }
+ else {
+ ++count_arguments;
+ }
+ }
+ }
+ was_whitespace = false;
+ }
+ break;
+
+ case T_COMMA:
+ if (1 == nested_parenthesis_level) {
+ // next parameter
+// trim_sequence(argument);
+ if (argument->empty() ||
+ impl::is_whitespace_only(*argument))
+ {
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ if (boost::wave::need_variadics(ctx.get_language())) {
+ // store a placemarker as the argument
+ argument->push_back(token_type(T_PLACEMARKER, "\xA7",
+ (*next).get_position()));
+ ++count_arguments;
+ }
+#endif
+ }
+ else {
+ ++count_arguments;
+ }
+ arguments.push_back(ContainerT()); // add new arg
+ argument = &arguments[arguments.size()-1];
+ }
+ else {
+ // surrounded by parenthesises, so store to current argument
+ argument->push_back(*next);
+ }
+ was_whitespace = false;
+ break;
+
+ case T_NEWLINE:
+ seen_newline = true;
+ /* fall through */
+ case T_SPACE:
+ case T_SPACE2:
+ case T_CCOMMENT:
+ if (!was_whitespace)
+ argument->push_back(token_type(T_SPACE, " ", (*next).get_position()));
+ was_whitespace = true;
+ break; // skip whitespace
+
+ case T_PLACEHOLDER:
+ break; // ignore placeholder
+
+ default:
+ argument->push_back(*next);
+ was_whitespace = false;
+ break;
+ }
+ }
+
+ if (nested_parenthesis_level >= 1) {
+ // missing ')': improperly terminated macro invocation
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ improperly_terminated_macro, "missing ')'", main_pos);
+ return 0;
+ }
+
+// if no argument was expected and we didn't find any, than remove the empty
+// element
+ if (0 == parameter_count && 0 == count_arguments) {
+ BOOST_ASSERT(1 == arguments.size());
+ arguments.clear();
+ }
+ return count_arguments;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// expand_whole_tokensequence
+//
+// fully expands a given token sequence
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename IteratorT, typename ContainerT>
+inline void
+macromap<ContextT>::expand_whole_tokensequence(ContainerT &expanded,
+ IteratorT &first, IteratorT const &last,
+ bool expand_operator_defined)
+{
+ typedef impl::gen_unput_queue_iterator<IteratorT, token_type, ContainerT>
+ gen_type;
+ typedef typename gen_type::return_type iterator_type;
+
+ ContainerT empty;
+ iterator_type first_it = gen_type::generate(empty, first);
+ iterator_type last_it = gen_type::generate(last);
+
+ on_exit::assign<IteratorT, iterator_type> on_exit(first, first_it);
+ ContainerT pending_queue;
+ bool seen_newline;
+
+ while (!pending_queue.empty() || first_it != last_it) {
+ expanded.push_back(
+ expand_tokensequence_worker(pending_queue, first_it,
+ last_it, seen_newline, expand_operator_defined)
+ );
+ }
+
+// should have returned all expanded tokens
+ BOOST_ASSERT(pending_queue.empty()/* && unput_queue.empty()*/);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// expand_argument
+//
+// fully expands the given argument of a macro call
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename ContainerT>
+inline void
+macromap<ContextT>::expand_argument (
+ typename std::vector<ContainerT>::size_type arg,
+ std::vector<ContainerT> &arguments, std::vector<ContainerT> &expanded_args,
+ bool expand_operator_defined, std::vector<bool> &has_expanded_args)
+{
+ if (!has_expanded_args[arg]) {
+ // expand the argument only once
+ typedef typename std::vector<ContainerT>::value_type::iterator
+ argument_iterator_type;
+
+ argument_iterator_type begin_it = arguments[arg].begin();
+ argument_iterator_type end_it = arguments[arg].end();
+
+ expand_whole_tokensequence(expanded_args[arg], begin_it, end_it,
+ expand_operator_defined);
+ impl::remove_placeholders(expanded_args[arg]);
+ has_expanded_args[arg] = true;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// expand_replacement_list
+//
+// fully expands the replacement list of a given macro with the
+// actual arguments/expanded arguments
+// handles the '#' [cpp.stringize] and the '##' [cpp.concat] operator
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename ContainerT>
+inline void
+macromap<ContextT>::expand_replacement_list(
+ macro_definition_type const &macrodef,
+ std::vector<ContainerT> &arguments, bool expand_operator_defined,
+ ContainerT &expanded)
+{
+ using namespace boost::wave;
+ typedef typename macro_definition_type::const_definition_iterator_t
+ macro_definition_iter_t;
+
+std::vector<ContainerT> expanded_args(arguments.size());
+std::vector<bool> has_expanded_args(arguments.size());
+bool seen_concat = false;
+bool adjacent_concat = false;
+bool adjacent_stringize = false;
+
+ macro_definition_iter_t cend = macrodef.macrodefinition.end();
+ for (macro_definition_iter_t cit = macrodef.macrodefinition.begin();
+ cit != cend; ++cit)
+ {
+ bool use_replaced_arg = true;
+ token_id base_id = BASE_TOKEN(token_id(*cit));
+
+ if (T_POUND_POUND == base_id) {
+ // concatenation operator
+ adjacent_concat = true;
+ seen_concat = true;
+ }
+ else if (T_POUND == base_id) {
+ // stringize operator
+ adjacent_stringize = true;
+ }
+ else {
+ if (adjacent_stringize || adjacent_concat ||
+ T_POUND_POUND == impl::next_token<macro_definition_iter_t>
+ ::peek(cit, cend))
+ {
+ use_replaced_arg = false;
+ }
+ if (adjacent_concat) // spaces after '##' ?
+ adjacent_concat = IS_CATEGORY(*cit, WhiteSpaceTokenType);
+ }
+
+ if (IS_CATEGORY((*cit), ParameterTokenType)) {
+ // copy argument 'i' instead of the parameter token i
+ typename ContainerT::size_type i;
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ bool is_ellipsis = false;
+
+ if (IS_EXTCATEGORY((*cit), ExtParameterTokenType)) {
+ BOOST_ASSERT(boost::wave::need_variadics(ctx.get_language()));
+ i = token_id(*cit) - T_EXTPARAMETERBASE;
+ is_ellipsis = true;
+ }
+ else
+#endif
+ {
+ i = token_id(*cit) - T_PARAMETERBASE;
+ }
+
+ BOOST_ASSERT(i < arguments.size());
+ if (use_replaced_arg) {
+
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ if (is_ellipsis) {
+ position_type const &pos = (*cit).get_position();
+
+ BOOST_ASSERT(boost::wave::need_variadics(ctx.get_language()));
+
+ // ensure all variadic arguments to be expanded
+ for (typename vector<ContainerT>::size_type arg = i;
+ arg < expanded_args.size(); ++arg)
+ {
+ expand_argument(arg, arguments, expanded_args,
+ expand_operator_defined, has_expanded_args);
+ }
+ impl::replace_ellipsis(expanded_args, i, expanded, pos);
+ }
+ else
+#endif
+ {
+ // ensure argument i to be expanded
+ expand_argument(i, arguments, expanded_args,
+ expand_operator_defined, has_expanded_args);
+
+ // replace argument
+ ContainerT const &arg = expanded_args[i];
+
+ std::copy(arg.begin(), arg.end(),
+ std::inserter(expanded, expanded.end()));
+ }
+ }
+ else if (adjacent_stringize &&
+ !IS_CATEGORY(*cit, WhiteSpaceTokenType))
+ {
+ // stringize the current argument
+ BOOST_ASSERT(!arguments[i].empty());
+
+ // safe a copy of the first tokens position (not a reference!)
+ position_type pos ((*arguments[i].begin()).get_position());
+
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ if (is_ellipsis && boost::wave::need_variadics(ctx.get_language())) {
+ impl::trim_sequence_left(arguments[i]);
+ impl::trim_sequence_right(arguments.back());
+ expanded.push_back(token_type(T_STRINGLIT,
+ impl::as_stringlit(arguments, i, pos), pos));
+ }
+ else
+#endif
+ {
+ impl::trim_sequence(arguments[i]);
+ expanded.push_back(token_type(T_STRINGLIT,
+ impl::as_stringlit(arguments[i], pos), pos));
+ }
+ adjacent_stringize = false;
+ }
+ else {
+ // simply copy the original argument (adjacent '##' or '#')
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ if (is_ellipsis) {
+ position_type const &pos = (*cit).get_position();
+
+ impl::trim_sequence_left(arguments[i]);
+ impl::trim_sequence_right(arguments.back());
+ BOOST_ASSERT(boost::wave::need_variadics(ctx.get_language()));
+ impl::replace_ellipsis(arguments, i, expanded, pos);
+ }
+ else
+#endif
+ {
+ ContainerT &arg = arguments[i];
+
+ impl::trim_sequence(arg);
+ std::copy(arg.begin(), arg.end(),
+ std::inserter(expanded, expanded.end()));
+ }
+ }
+ }
+ else if (!adjacent_stringize || T_POUND != base_id) {
+ // insert the actual replacement token (if it is not the '#' operator)
+ expanded.push_back(*cit);
+ }
+ }
+
+ if (adjacent_stringize) {
+ // error, '#' should not be the last token
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, ill_formed_operator,
+ "stringize ('#')", main_pos);
+ return;
+ }
+
+// handle the cpp.concat operator
+ if (seen_concat)
+ concat_tokensequence(expanded);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// rescan_replacement_list
+//
+// As the name implies, this function is used to rescan the replacement list
+// after the first macro substitution phase.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename IteratorT, typename ContainerT>
+inline void
+macromap<ContextT>::rescan_replacement_list(token_type const &curr_token,
+ macro_definition_type &macro_def, ContainerT &replacement_list,
+ ContainerT &expanded, bool expand_operator_defined,
+ IteratorT &nfirst, IteratorT const &nlast)
+{
+ if (!replacement_list.empty()) {
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ // remove the placemarkers
+ if (boost::wave::need_variadics(ctx.get_language())) {
+ typename ContainerT::iterator end = replacement_list.end();
+ typename ContainerT::iterator it = replacement_list.begin();
+
+ while (it != end) {
+ using namespace boost::wave;
+ if (T_PLACEMARKER == token_id(*it)) {
+ typename ContainerT::iterator placemarker = it;
+
+ ++it;
+ replacement_list.erase(placemarker);
+ }
+ else {
+ ++it;
+ }
+ }
+ }
+#endif
+
+ // rescan the replacement list, during this rescan the current macro under
+ // expansion isn't available as an expandable macro
+ on_exit::reset<bool> on_exit(macro_def.is_available_for_replacement, false);
+ typename ContainerT::iterator begin_it = replacement_list.begin();
+ typename ContainerT::iterator end_it = replacement_list.end();
+
+ expand_whole_tokensequence(expanded, begin_it, end_it,
+ expand_operator_defined);
+
+ // trim replacement list, leave placeholder tokens untouched
+ impl::trim_replacement_list(expanded);
+ }
+
+ if (expanded.empty()) {
+ // the resulting replacement list should contain at least a placeholder
+ // token
+ expanded.push_back(token_type(T_PLACEHOLDER, "_", curr_token.get_position()));
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// expand_macro(): expands a defined macro
+//
+// This functions tries to expand the macro, to which points the 'first'
+// iterator. The functions eats up more tokens, if the macro to expand is
+// a function-like macro.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename IteratorT, typename ContainerT>
+inline bool
+macromap<ContextT>::expand_macro(ContainerT &expanded,
+ token_type const &curr_token, typename defined_macros_type::iterator it,
+ IteratorT &first, IteratorT const &last,
+ bool& seen_newline, bool expand_operator_defined,
+ defined_macros_type *scope, ContainerT *queue_symbol)
+{
+ using namespace boost::wave;
+
+ if (0 == scope) scope = current_macros;
+
+ BOOST_ASSERT(T_IDENTIFIER == token_id(curr_token) ||
+ IS_CATEGORY(token_id(curr_token), KeywordTokenType) ||
+ IS_EXTCATEGORY(token_id(curr_token), OperatorTokenType|AltExtTokenType) ||
+ IS_CATEGORY(token_id(curr_token), BoolLiteralTokenType));
+
+ if (it == scope->end()) {
+ ++first; // advance
+
+ // try to expand a predefined macro (__FILE__, __LINE__ or __INCLUDE_LEVEL__)
+ if (expand_predefined_macro(curr_token, expanded))
+ return false;
+
+ // not defined as a macro
+ if (0 != queue_symbol) {
+ expanded.splice(expanded.end(), *queue_symbol);
+ }
+ else {
+ expanded.push_back(curr_token);
+ }
+ return false;
+ }
+
+// ensure the parameters to be replaced with special parameter tokens
+macro_definition_type &macro_def = *(*it).second.get();
+
+ macro_def.replace_parameters();
+
+// test if this macro is currently available for replacement
+ if (!macro_def.is_available_for_replacement) {
+ // this macro is marked as non-replaceable
+ // copy the macro name itself
+ if (0 != queue_symbol) {
+ queue_symbol->push_back(token_type(T_NONREPLACABLE_IDENTIFIER,
+ curr_token.get_value(), curr_token.get_position()));
+ expanded.splice(expanded.end(), *queue_symbol);
+ }
+ else {
+ expanded.push_back(token_type(T_NONREPLACABLE_IDENTIFIER,
+ curr_token.get_value(), curr_token.get_position()));
+ }
+ ++first;
+ return false;
+ }
+
+// try to replace the current identifier as a function-like macro
+ContainerT replacement_list;
+
+ if (T_LEFTPAREN == impl::next_token<IteratorT>::peek(first, last)) {
+ // called as a function-like macro
+ impl::skip_to_token(ctx, first, last, T_LEFTPAREN, seen_newline);
+
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS == 0
+ IteratorT seqstart = first;
+ IteratorT seqend = first;
+#endif
+
+ if (macro_def.is_functionlike) {
+ // defined as a function-like macro
+
+ // collect the arguments
+ std::vector<ContainerT> arguments;
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ typename std::vector<ContainerT>::size_type count_args =
+ collect_arguments (curr_token, arguments, first, last,
+ macro_def.macroparameters.size(), seen_newline);
+#else
+ typename std::vector<ContainerT>::size_type count_args =
+ collect_arguments (curr_token, arguments, first, seqend, last,
+ macro_def.macroparameters.size(), seen_newline);
+#endif
+
+ // verify the parameter count
+ if (count_args < macro_def.macroparameters.size() ||
+ arguments.size() < macro_def.macroparameters.size())
+ {
+ if (count_args != arguments.size()) {
+ // must been at least one empty argument in C++ mode
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ empty_macroarguments, curr_token.get_value().c_str(),
+ main_pos);
+ }
+ else {
+ // too few macro arguments
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ too_few_macroarguments, curr_token.get_value().c_str(),
+ main_pos);
+ }
+ return false;
+ }
+
+ if (count_args > macro_def.macroparameters.size() ||
+ arguments.size() > macro_def.macroparameters.size())
+ {
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ if (!macro_def.has_ellipsis)
+#endif
+ {
+ // too many macro arguments
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ too_many_macroarguments,
+ curr_token.get_value().c_str(), main_pos);
+ return false;
+ }
+ }
+
+ // inject tracing support
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ ctx.get_hooks().expanding_function_like_macro(
+ macro_def.macroname, macro_def.macroparameters,
+ macro_def.macrodefinition, curr_token, arguments);
+#else
+ if (ctx.get_hooks().expanding_function_like_macro(ctx.derived(),
+ macro_def.macroname, macro_def.macroparameters,
+ macro_def.macrodefinition, curr_token, arguments,
+ seqstart, seqend))
+ {
+ // do not expand this macro, just copy the whole sequence
+ expanded.push_back(curr_token);
+ std::copy(seqstart, first,
+ std::inserter(expanded, expanded.end()));
+ return false; // no further preprocessing required
+ }
+#endif
+
+ // expand the replacement list of this macro
+ expand_replacement_list(macro_def, arguments, expand_operator_defined,
+ replacement_list);
+ }
+ else {
+ // defined as an object-like macro
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ ctx.get_hooks().expanding_object_like_macro(
+ macro_def.macroname, macro_def.macrodefinition, curr_token);
+#else
+ if (ctx.get_hooks().expanding_object_like_macro(ctx.derived(),
+ macro_def.macroname, macro_def.macrodefinition, curr_token))
+ {
+ // do not expand this macro, just copy the whole sequence
+ expanded.push_back(curr_token);
+ return false; // no further preprocessing required
+ }
+#endif
+
+ bool found = false;
+ impl::find_concat_operator concat_tag(found);
+
+ std::remove_copy_if(macro_def.macrodefinition.begin(),
+ macro_def.macrodefinition.end(),
+ std::inserter(replacement_list, replacement_list.end()),
+ concat_tag);
+
+ // handle concatenation operators
+ if (found && !concat_tokensequence(replacement_list))
+ return false;
+ }
+ }
+ else {
+ // called as an object like macro
+ if ((*it).second->is_functionlike) {
+ // defined as a function-like macro
+ if (0 != queue_symbol) {
+ queue_symbol->push_back(curr_token);
+ expanded.splice(expanded.end(), *queue_symbol);
+ }
+ else {
+ expanded.push_back(curr_token);
+ }
+ ++first; // skip macro name
+ return false; // no further preprocessing required
+ }
+ else {
+ // defined as an object-like macro (expand it)
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ ctx.get_hooks().expanding_object_like_macro(
+ macro_def.macroname, macro_def.macrodefinition, curr_token);
+#else
+ if (ctx.get_hooks().expanding_object_like_macro(ctx.derived(),
+ macro_def.macroname, macro_def.macrodefinition, curr_token))
+ {
+ // do not expand this macro, just copy the whole sequence
+ expanded.push_back(curr_token);
+ ++first; // skip macro name
+ return false; // no further preprocessing required
+ }
+#endif
+
+ bool found = false;
+ impl::find_concat_operator concat_tag(found);
+
+ std::remove_copy_if(macro_def.macrodefinition.begin(),
+ macro_def.macrodefinition.end(),
+ std::inserter(replacement_list, replacement_list.end()),
+ concat_tag);
+
+ // handle concatenation operators
+ if (found && !concat_tokensequence(replacement_list))
+ return false;
+
+ ++first; // skip macro name
+ }
+ }
+
+// rescan the replacement list
+ContainerT expanded_list;
+
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ ctx.get_hooks().expanded_macro(replacement_list);
+#else
+ ctx.get_hooks().expanded_macro(ctx.derived(), replacement_list);
+#endif
+
+ rescan_replacement_list(curr_token, macro_def, replacement_list,
+ expanded_list, expand_operator_defined, first, last);
+
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ ctx.get_hooks().rescanned_macro(expanded_list);
+#else
+ ctx.get_hooks().rescanned_macro(ctx.derived(), expanded_list);
+#endif
+ expanded.splice(expanded.end(), expanded_list);
+ return true; // rescan is required
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// If the token under inspection points to a certain predefined macro it will
+// be expanded, otherwise false is returned.
+// (only __FILE__, __LINE__ and __INCLUDE_LEVEL__ macros are expanded here)
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename ContainerT>
+inline bool
+macromap<ContextT>::expand_predefined_macro(token_type const &curr_token,
+ ContainerT &expanded)
+{
+ using namespace boost::wave;
+
+string_type const &value = curr_token.get_value();
+
+ if (value.size() < 8 || '_' != value[0] || '_' != value[1])
+ return false; // quick check failed
+
+ if (value == "__LINE__") {
+ // expand the __LINE__ macro
+ char buffer[22]; // 21 bytes holds all NUL-terminated unsigned 64-bit numbers
+
+ using namespace std; // for some systems sprintf is in namespace std
+ sprintf(buffer, "%d", main_pos.get_line());
+ expanded.push_back(token_type(T_INTLIT, buffer, curr_token.get_position()));
+ return true;
+ }
+ else if (value == "__FILE__") {
+ // expand the __FILE__ macro
+ namespace fs = boost::filesystem;
+
+ std::string file("\"");
+ fs::path filename(wave::util::create_path(main_pos.get_file().c_str()));
+
+ using boost::wave::util::impl::escape_lit;
+ file += escape_lit(wave::util::native_file_string(filename)) + "\"";
+ expanded.push_back(token_type(T_STRINGLIT, file.c_str(),
+ curr_token.get_position()));
+ return true;
+ }
+ else if (value == "__INCLUDE_LEVEL__") {
+ // expand the __INCLUDE_LEVEL__ macro
+ char buffer[22]; // 21 bytes holds all NUL-terminated unsigned 64-bit numbers
+
+ using namespace std; // for some systems sprintf is in namespace std
+ sprintf(buffer, "%d", (int)ctx.get_iteration_depth());
+ expanded.push_back(token_type(T_INTLIT, buffer, curr_token.get_position()));
+ return true;
+ }
+ return false; // no predefined token
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// resolve_defined(): resolve the operator defined() and replace it with the
+// correct T_INTLIT token
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename IteratorT, typename ContainerT>
+inline typename ContextT::token_type const &
+macromap<ContextT>::resolve_defined(IteratorT &first,
+ IteratorT const &last, ContainerT &pending)
+{
+ using namespace boost::wave;
+ using namespace boost::wave::grammars;
+
+ContainerT result;
+IteratorT start = first;
+boost::spirit::classic::parse_info<IteratorT> hit =
+ defined_grammar_gen<typename ContextT::lexer_type>::
+ parse_operator_defined(start, last, result);
+
+ if (!hit.hit) {
+ string_type msg ("defined(): ");
+ msg = msg + util::impl::as_string<string_type>(first, last);
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, ill_formed_expression,
+ msg.c_str(), main_pos);
+
+ // insert a dummy token
+ pending.push_back(token_type(T_INTLIT, "0", main_pos));
+ }
+ else {
+ impl::assign_iterator<IteratorT>::do_(first, hit.stop);
+
+ // insert a token, which reflects the outcome
+ pending.push_back(token_type(T_INTLIT,
+ is_defined(result.begin(), result.end()) ? "1" : "0",
+ main_pos));
+ }
+
+on_exit::pop_front<definition_container_type> pop_front_token(pending);
+
+ return act_token = pending.front();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// resolve_operator_pragma(): resolve the operator _Pragma() and dispatch to
+// the associated action
+//
+// This function returns true, if the pragma was correctly interpreted.
+// The iterator 'first' is positioned behind the closing ')'.
+// This function returns false, if the _Pragma was not known, the
+// preprocessed token sequence is pushed back to the 'pending' sequence.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename IteratorT, typename ContainerT>
+inline bool
+macromap<ContextT>::resolve_operator_pragma(IteratorT &first,
+ IteratorT const &last, ContainerT &pending, bool& seen_newline)
+{
+// isolate the parameter of the operator _Pragma
+ token_type pragma_token = *first;
+
+ if (!impl::skip_to_token(ctx, first, last, T_LEFTPAREN, seen_newline)) {
+ // illformed operator _Pragma
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, ill_formed_expression,
+ "operator _Pragma()", pragma_token.get_position());
+ return false;
+ }
+
+ std::vector<ContainerT> arguments;
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ typename std::vector<ContainerT>::size_type count_args =
+ collect_arguments (pragma_token, arguments, first, last, 1, seen_newline);
+#else
+ IteratorT endparen = first;
+ typename std::vector<ContainerT>::size_type count_args =
+ collect_arguments (pragma_token, arguments, first, endparen, last, 1,
+ seen_newline);
+#endif
+
+// verify the parameter count
+ if (pragma_token.get_position().get_file().empty())
+ pragma_token.set_position(act_token.get_position());
+
+ if (count_args < 1 || arguments.size() < 1) {
+ // too few macro arguments
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, too_few_macroarguments,
+ pragma_token.get_value().c_str(), pragma_token.get_position());
+ return false;
+ }
+ if (count_args > 1 || arguments.size() > 1) {
+ // too many macro arguments
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, too_many_macroarguments,
+ pragma_token.get_value().c_str(), pragma_token.get_position());
+ return false;
+ }
+
+// preprocess the pragma token body
+ typedef typename std::vector<ContainerT>::value_type::iterator
+ argument_iterator_type;
+
+ ContainerT expanded;
+ argument_iterator_type begin_it = arguments[0].begin();
+ argument_iterator_type end_it = arguments[0].end();
+ expand_whole_tokensequence(expanded, begin_it, end_it, false);
+
+// un-escape the parameter of the operator _Pragma
+ typedef typename token_type::string_type string_type;
+
+ string_type pragma_cmd;
+ typename ContainerT::const_iterator end_exp = expanded.end();
+ for (typename ContainerT::const_iterator it_exp = expanded.begin();
+ it_exp != end_exp; ++it_exp)
+ {
+ if (T_EOF == token_id(*it_exp))
+ break;
+ if (IS_CATEGORY(*it_exp, WhiteSpaceTokenType))
+ continue;
+
+ if (T_STRINGLIT != token_id(*it_exp)) {
+ // ill formed operator _Pragma
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ ill_formed_pragma_option, "_Pragma",
+ pragma_token.get_position());
+ return false;
+ }
+ if (pragma_cmd.size() > 0) {
+ // there should be exactly one string literal (string literals are to
+ // be concatenated at translation phase 6, but _Pragma operators are
+ // to be executed at translation phase 4)
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ ill_formed_pragma_option, "_Pragma",
+ pragma_token.get_position());
+ return false;
+ }
+
+ // remove the '\"' and concat all given string literal-values
+ string_type token_str = (*it_exp).get_value();
+ pragma_cmd += token_str.substr(1, token_str.size() - 2);
+ }
+ string_type pragma_cmd_unesc = impl::unescape_lit(pragma_cmd);
+
+// tokenize the pragma body
+ typedef typename ContextT::lexer_type lexer_type;
+
+ ContainerT pragma;
+ std::string pragma_cmd_str(pragma_cmd_unesc.c_str());
+ lexer_type it = lexer_type(pragma_cmd_str.begin(), pragma_cmd_str.end(),
+ pragma_token.get_position(), ctx.get_language());
+ lexer_type end = lexer_type();
+ for (/**/; it != end; ++it)
+ pragma.push_back(*it);
+
+// analyze the preprocessed token sequence and eventually dispatch to the
+// associated action
+ if (interpret_pragma(ctx, pragma_token, pragma.begin(), pragma.end(),
+ pending))
+ {
+ return true; // successfully recognized a wave specific pragma
+ }
+
+// unknown pragma token sequence, push it back and return to the caller
+ pending.push_front(token_type(T_SPACE, " ", pragma_token.get_position()));
+ pending.push_front(token_type(T_RIGHTPAREN, ")", pragma_token.get_position()));
+ pending.push_front(token_type(T_STRINGLIT, string_type("\"") + pragma_cmd + "\"",
+ pragma_token.get_position()));
+ pending.push_front(token_type(T_LEFTPAREN, "(", pragma_token.get_position()));
+ pending.push_front(pragma_token);
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Test, whether the result of a concat operator is well formed or not.
+//
+// This is done by re-scanning (re-tokenizing) the resulting token sequence,
+// which should give back exactly one token.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+template <typename ContainerT>
+inline bool
+macromap<ContextT>::is_valid_concat(string_type new_value,
+ position_type const &pos, ContainerT &rescanned)
+{
+// re-tokenize the newly generated string
+ typedef typename ContextT::lexer_type lexer_type;
+
+ std::string value_to_test(new_value.c_str());
+
+ boost::wave::language_support lang =
+ boost::wave::enable_prefer_pp_numbers(ctx.get_language());
+ lang = boost::wave::enable_single_line(lang);
+
+ lexer_type it = lexer_type(value_to_test.begin(), value_to_test.end(), pos,
+ lang);
+ lexer_type end = lexer_type();
+ for (/**/; it != end && T_EOF != token_id(*it); ++it)
+ {
+ // as of Wave V2.0.7 pasting of tokens is valid only if the resulting
+ // tokens are pp_tokens (as mandated by C++0x)
+ if (!is_pp_token(*it))
+ return false;
+ rescanned.push_back(*it);
+ }
+
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ if (boost::wave::need_variadics(ctx.get_language()))
+ return true; // in variadics mode token pasting is well defined
+#endif
+
+// test if the newly generated token sequence contains more than 1 token
+ return 1 == rescanned.size();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Handle all occurrences of the concatenation operator '##' inside the given
+// token sequence.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename Context>
+inline void report_invalid_concatenation(Context& ctx,
+ typename Context::token_type const& prev,
+ typename Context::token_type const& next,
+ typename Context::position_type const& main_pos)
+{
+typename Context::string_type error_string("\"");
+
+ error_string += prev.get_value();
+ error_string += "\" and \"";
+ error_string += next.get_value();
+ error_string += "\"";
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, invalid_concat,
+ error_string.c_str(), main_pos);
+}
+
+template <typename ContextT>
+template <typename ContainerT>
+inline bool
+macromap<ContextT>::concat_tokensequence(ContainerT &expanded)
+{
+ using namespace boost::wave;
+ typedef typename ContainerT::iterator iterator_type;
+
+ iterator_type end = expanded.end();
+ iterator_type prev = end;
+ for (iterator_type it = expanded.begin(); it != end; /**/)
+ {
+ if (T_POUND_POUND == BASE_TOKEN(token_id(*it))) {
+ iterator_type next = it;
+
+ ++next;
+ if (prev == end || next == end) {
+ // error, '##' should be in between two tokens
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ ill_formed_operator, "concat ('##')", main_pos);
+ return false;
+ }
+
+ // replace prev##next with the concatenated value, skip whitespace
+ // before and after the '##' operator
+ while (IS_CATEGORY(*next, WhiteSpaceTokenType)) {
+ ++next;
+ if (next == end) {
+ // error, '##' should be in between two tokens
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ ill_formed_operator, "concat ('##')", main_pos);
+ return false;
+ }
+ }
+
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ if (boost::wave::need_variadics(ctx.get_language())) {
+ if (T_PLACEMARKER == token_id(*next)) {
+ // remove the '##' and the next tokens from the sequence
+ iterator_type first_to_delete = prev;
+
+ expanded.erase(++first_to_delete, ++next);
+ it = next;
+ continue;
+ }
+ else if (T_PLACEMARKER == token_id(*prev)) {
+ // remove the '##' and the next tokens from the sequence
+ iterator_type first_to_delete = prev;
+
+ *prev = *next;
+ expanded.erase(++first_to_delete, ++next);
+ it = next;
+ continue;
+ }
+ }
+#endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+
+ // test if the concat operator has to concatenate two unrelated
+ // tokens i.e. the result yields more then one token
+ string_type concat_result;
+ ContainerT rescanned;
+
+ concat_result = ((*prev).get_value() + (*next).get_value());
+
+ // analyze the validity of the concatenation result
+ if (!is_valid_concat(concat_result, (*prev).get_position(),
+ rescanned) &&
+ !IS_CATEGORY(*prev, WhiteSpaceTokenType) &&
+ !IS_CATEGORY(*next, WhiteSpaceTokenType))
+ {
+ report_invalid_concatenation(ctx, *prev, *next, main_pos);
+ return false;
+ }
+
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ if (boost::wave::need_variadics(ctx.get_language())) {
+ // remove the prev, '##' and the next tokens from the sequence
+ expanded.erase(prev, ++next); // remove not needed tokens
+
+ // some stl implementations clear() the container if we erased all
+ // the elements, which orphans all iterators. we re-initialize these
+ // here
+ if (expanded.empty())
+ end = next = expanded.end();
+
+ // replace the old token (pointed to by *prev) with the re-tokenized
+ // sequence
+ expanded.splice(next, rescanned);
+
+ // the last token of the inserted sequence is the new previous
+ prev = next;
+ if (next != expanded.end())
+ --prev;
+ }
+ else
+#endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ {
+ // we leave the token_id unchanged, but unmark the token as
+ // disabled, if appropriate
+ (*prev).set_value(concat_result);
+ if (T_NONREPLACABLE_IDENTIFIER == token_id(*prev))
+ (*prev).set_token_id(T_IDENTIFIER);
+
+ // remove the '##' and the next tokens from the sequence
+ iterator_type first_to_delete = prev;
+
+ expanded.erase(++first_to_delete, ++next);
+ }
+ it = next;
+ continue;
+ }
+
+ // save last non-whitespace token position
+ if (!IS_CATEGORY(*it, WhiteSpaceTokenType))
+ prev = it;
+
+ ++it; // next token, please
+ }
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// predefine_macro(): predefine a single macro
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline void
+macromap<ContextT>::predefine_macro(defined_macros_type *scope,
+ string_type const &name, token_type const &t)
+{
+definition_container_type macrodefinition;
+std::vector<token_type> param;
+
+ macrodefinition.push_back(t);
+ add_macro(token_type(T_IDENTIFIER, name, t.get_position()),
+ false, param, macrodefinition, true, scope);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// init_predefined_macros(): init the predefined macros
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline void
+macromap<ContextT>::init_predefined_macros(char const *fname,
+ defined_macros_type *scope, bool at_global_scope)
+{
+// if no scope is given, use the current one
+defined_macros_type *current_scope = scope ? scope : current_macros;
+
+// first, add the static macros
+position_type pos("<built-in>");
+
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ if (boost::wave::need_c99(ctx.get_language())) {
+ // define C99 specifics
+ for (int i = 0; 0 != predef.static_data_c99(i).name; ++i) {
+ predefined_macros::static_macros const& m = predef.static_data_c99(i);
+ predefine_macro(current_scope, m.name,
+ token_type(m.token_id, m.value, pos));
+ }
+ }
+ else
+#endif
+ {
+#if BOOST_WAVE_SUPPORT_CPP0X != 0
+ if (boost::wave::need_cpp0x(ctx.get_language())) {
+ // define C++0x specifics
+ for (int i = 0; 0 != predef.static_data_cpp0x(i).name; ++i) {
+ predefined_macros::static_macros const& m = predef.static_data_cpp0x(i);
+ predefine_macro(current_scope, m.name,
+ token_type(m.token_id, m.value, pos));
+ }
+ }
+ else
+#endif
+ {
+ // define C++ specifics
+ for (int i = 0; 0 != predef.static_data_cpp(i).name; ++i) {
+ predefined_macros::static_macros const& m = predef.static_data_cpp(i);
+ predefine_macro(current_scope, m.name,
+ token_type(m.token_id, m.value, pos));
+ }
+
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ // define __WAVE_HAS_VARIADICS__, if appropriate
+ if (boost::wave::need_variadics(ctx.get_language())) {
+ predefine_macro(current_scope, "__WAVE_HAS_VARIADICS__",
+ token_type(T_INTLIT, "1", pos));
+ }
+#endif
+ }
+ }
+
+// predefine the __BASE_FILE__ macro which contains the main file name
+ namespace fs = boost::filesystem;
+ if (string_type(fname) != "<Unknown>") {
+ fs::path filename(create_path(fname));
+
+ using boost::wave::util::impl::escape_lit;
+ predefine_macro(current_scope, "__BASE_FILE__",
+ token_type(T_STRINGLIT, string_type("\"") +
+ escape_lit(native_file_string(filename)).c_str() + "\"", pos));
+ base_name = fname;
+ }
+ else if (!base_name.empty()) {
+ fs::path filename(create_path(base_name.c_str()));
+
+ using boost::wave::util::impl::escape_lit;
+ predefine_macro(current_scope, "__BASE_FILE__",
+ token_type(T_STRINGLIT, string_type("\"") +
+ escape_lit(native_file_string(filename)).c_str() + "\"", pos));
+ }
+
+// now add the dynamic macros
+ for (int j = 0; 0 != predef.dynamic_data(j).name; ++j) {
+ predefined_macros::dynamic_macros const& m = predef.dynamic_data(j);
+ predefine_macro(current_scope, m.name,
+ token_type(m.token_id, (predef.* m.generator)(), pos));
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// reset_macromap(): initialize the internal macro symbol namespace
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT>
+inline void
+macromap<ContextT>::reset_macromap()
+{
+ current_macros->clear();
+ predef.reset();
+ act_token = token_type();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+}}} // namespace boost::wave::util
+
+#if BOOST_WAVE_SERIALIZATION != 0
+namespace boost { namespace serialization {
+
+template<typename ContextT>
+struct version<boost::wave::util::macromap<ContextT> >
+{
+ typedef boost::wave::util::macromap<ContextT> 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_MACROMAP_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED)
diff --git a/boost/wave/util/cpp_macromap_predef.hpp b/boost/wave/util/cpp_macromap_predef.hpp
new file mode 100644
index 0000000000..0725a36306
--- /dev/null
+++ b/boost/wave/util/cpp_macromap_predef.hpp
@@ -0,0 +1,288 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ Definition of the predefined macros
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_MACROMAP_PREDEF_HPP_HK041119)
+#define CPP_MACROMAP_PREDEF_HPP_HK041119
+
+#include <cstdio>
+#include <boost/assert.hpp>
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/wave/wave_config_constant.hpp>
+#include <boost/wave/token_ids.hpp>
+#include <boost/wave/util/time_conversion_helper.hpp> // time_conversion_helper
+
+// this must occur after all of the includes and before any code appears
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_PREFIX
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// This file contains the definition of functions needed for the management
+// of static and dynamic predefined macros, such as __DATE__, __TIME__ etc.
+//
+// Note: __FILE__, __LINE__ and __INCLUDE_LEVEL__ are handled in the file
+// cpp_macromap.hpp.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+namespace boost {
+namespace wave {
+namespace util {
+
+ ///////////////////////////////////////////////////////////////////////////
+ class predefined_macros
+ {
+ typedef BOOST_WAVE_STRINGTYPE string_type;
+
+ public:
+ // list of static predefined macros
+ struct static_macros {
+ char const *name;
+ boost::wave::token_id token_id;
+ char const *value;
+ };
+
+ // list of dynamic predefined macros
+ struct dynamic_macros {
+ char const *name;
+ boost::wave::token_id token_id;
+ string_type (predefined_macros:: *generator)() const;
+ };
+
+ private:
+ boost::wave::util::time_conversion_helper compilation_time_;
+ string_type datestr_; // __DATE__
+ string_type timestr_; // __TIME__
+ string_type version_; // __SPIRIT_PP_VERSION__/__WAVE_VERSION__
+ string_type versionstr_; // __SPIRIT_PP_VERSION_STR__/__WAVE_VERSION_STR__
+
+ protected:
+ void reset_datestr()
+ {
+ static const char *const monthnames[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+
+ // for some systems sprintf, time_t etc. is in namespace std
+ using namespace std;
+
+ time_t tt = time(0);
+ struct tm *tb = 0;
+
+ if (tt != (time_t)-1) {
+ char buffer[sizeof("\"Oct 11 1347\"")+1];
+
+ tb = localtime (&tt);
+ sprintf (buffer, "\"%s %2d %4d\"",
+ monthnames[tb->tm_mon], tb->tm_mday, tb->tm_year + 1900);
+ datestr_ = buffer;
+ }
+ else {
+ datestr_ = "\"??? ?? ????\"";
+ }
+ }
+
+ void reset_timestr()
+ {
+ // for some systems sprintf, time_t etc. is in namespace std
+ using namespace std;
+
+ time_t tt = time(0);
+ struct tm *tb = 0;
+
+ if (tt != (time_t)-1) {
+ char buffer[sizeof("\"12:34:56\"")+1];
+
+ tb = localtime (&tt);
+ sprintf (buffer, "\"%02d:%02d:%02d\"", tb->tm_hour,
+ tb->tm_min, tb->tm_sec);
+ timestr_ = buffer;
+ }
+ else {
+ timestr_ = "\"??:??:??\"";
+ }
+ }
+
+ void reset_version()
+ {
+ char buffer[sizeof("0x00000000")+1];
+
+ // for some systems sprintf, time_t etc. is in namespace std
+ using namespace std;
+
+ // calculate the number of days since Dec 13 2001
+ // (the day the Wave project was started)
+ tm first_day;
+
+ using namespace std; // for some systems memset is in namespace std
+ memset (&first_day, 0, sizeof(tm));
+ first_day.tm_mon = 11; // Dec
+ first_day.tm_mday = 13; // 13
+ first_day.tm_year = 101; // 2001
+
+ long seconds = long(difftime(compilation_time_.get_time(), mktime(&first_day)));
+
+ sprintf(buffer, "0x%02d%1d%1d%04ld", BOOST_WAVE_VERSION_MAJOR,
+ BOOST_WAVE_VERSION_MINOR, BOOST_WAVE_VERSION_SUBMINOR,
+ seconds/(3600*24));
+ version_ = buffer;
+ }
+
+ void reset_versionstr()
+ {
+ char buffer[sizeof("\"00.00.00.0000 \"")+sizeof(BOOST_PLATFORM)+sizeof(BOOST_COMPILER)+4];
+
+ // for some systems sprintf, time_t etc. is in namespace std
+ using namespace std;
+
+ // calculate the number of days since Dec 13 2001
+ // (the day the Wave project was started)
+ tm first_day;
+
+ memset (&first_day, 0, sizeof(tm));
+ first_day.tm_mon = 11; // Dec
+ first_day.tm_mday = 13; // 13
+ first_day.tm_year = 101; // 2001
+
+ long seconds = long(difftime(compilation_time_.get_time(), mktime(&first_day)));
+
+ sprintf(buffer, "\"%d.%d.%d.%ld [%s/%s]\"", BOOST_WAVE_VERSION_MAJOR,
+ BOOST_WAVE_VERSION_MINOR, BOOST_WAVE_VERSION_SUBMINOR,
+ seconds/(3600*24), BOOST_PLATFORM, BOOST_COMPILER);
+ versionstr_ = buffer;
+ }
+
+ // dynamic predefined macros
+ string_type get_date() const { return datestr_; } // __DATE__
+ string_type get_time() const { return timestr_; } // __TIME__
+
+ // __SPIRIT_PP__/__WAVE__
+ string_type get_version() const
+ {
+ char buffer[sizeof("0x0000")+1];
+
+ using namespace std; // for some systems sprintf is in namespace std
+ sprintf(buffer, "0x%02d%1d%1d", BOOST_WAVE_VERSION_MAJOR,
+ BOOST_WAVE_VERSION_MINOR, BOOST_WAVE_VERSION_SUBMINOR);
+ return buffer;
+ }
+
+ // __WAVE_CONFIG__
+ string_type get_config() const
+ {
+ char buffer[sizeof("0x00000000")+1];
+
+ using namespace std; // for some systems sprintf is in namespace std
+ sprintf(buffer, "0x%08x", BOOST_WAVE_CONFIG);
+ return buffer;
+ }
+
+ public:
+ predefined_macros()
+ : compilation_time_(__DATE__ " " __TIME__)
+ {
+ reset();
+ reset_version();
+ reset_versionstr();
+ }
+
+ void reset()
+ {
+ reset_datestr();
+ reset_timestr();
+ }
+
+ // __SPIRIT_PP_VERSION__/__WAVE_VERSION__
+ string_type get_fullversion() const { return version_; }
+
+ // __SPIRIT_PP_VERSION_STR__/__WAVE_VERSION_STR__
+ string_type get_versionstr() const { return versionstr_; }
+
+ // C++ mode
+ static_macros const& static_data_cpp(std::size_t i) const
+ {
+ static static_macros data[] = {
+ { "__STDC__", T_INTLIT, "1" },
+ { "__cplusplus", T_INTLIT, "199711L" },
+ { 0, T_EOF, 0 }
+ };
+ BOOST_ASSERT(i < sizeof(data)/sizeof(data[0]));
+ return data[i];
+ }
+
+#if BOOST_WAVE_SUPPORT_CPP0X != 0
+ // C++0x mode
+ static_macros const& static_data_cpp0x(std::size_t i) const
+ {
+ static static_macros data[] = {
+ { "__STDC__", T_INTLIT, "1" },
+ { "__cplusplus", T_INTLIT, "201103L" },
+ { "__STDC_VERSION__", T_INTLIT, "199901L" },
+ { "__STDC_HOSTED__", T_INTLIT, "0" },
+ { "__WAVE_HAS_VARIADICS__", T_INTLIT, "1" },
+ { 0, T_EOF, 0 }
+ };
+ BOOST_ASSERT(i < sizeof(data)/sizeof(data[0]));
+ return data[i];
+ }
+#endif
+
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ // C99 mode
+ static_macros const& static_data_c99(std::size_t i) const
+ {
+ static static_macros data[] = {
+ { "__STDC__", T_INTLIT, "1" },
+ { "__STDC_VERSION__", T_INTLIT, "199901L" },
+ { "__STDC_HOSTED__", T_INTLIT, "0" },
+ { "__WAVE_HAS_VARIADICS__", T_INTLIT, "1" },
+ { 0, T_EOF, 0 }
+ };
+ BOOST_ASSERT(i < sizeof(data)/sizeof(data[0]));
+ return data[i];
+ }
+#endif
+
+ dynamic_macros const& dynamic_data(std::size_t i) const
+ {
+ static dynamic_macros data[] = {
+ { "__DATE__", T_STRINGLIT, &predefined_macros::get_date },
+ { "__TIME__", T_STRINGLIT, &predefined_macros::get_time },
+ { "__SPIRIT_PP__", T_INTLIT, &predefined_macros::get_version },
+ { "__SPIRIT_PP_VERSION__", T_INTLIT, &predefined_macros::get_fullversion },
+ { "__SPIRIT_PP_VERSION_STR__", T_STRINGLIT, &predefined_macros::get_versionstr },
+ { "__WAVE__", T_INTLIT, &predefined_macros::get_version },
+ { "__WAVE_VERSION__", T_INTLIT, &predefined_macros::get_fullversion },
+ { "__WAVE_VERSION_STR__", T_STRINGLIT, &predefined_macros::get_versionstr },
+ { "__WAVE_CONFIG__", T_INTLIT, &predefined_macros::get_config },
+ { 0, T_EOF, 0 }
+ };
+ BOOST_ASSERT(i < sizeof(data)/sizeof(data[0]));
+ return data[i];
+ }
+ }; // predefined_macros
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace util
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_MACROMAP_PREDEF_HPP_HK041119)
diff --git a/boost/wave/util/cpp_macromap_utils.hpp b/boost/wave/util/cpp_macromap_utils.hpp
new file mode 100644
index 0000000000..84b5b03de6
--- /dev/null
+++ b/boost/wave/util/cpp_macromap_utils.hpp
@@ -0,0 +1,575 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ Token sequence analysis and transformation helper functions
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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_MACROMAP_UTIL_HPP_HK041119)
+#define CPP_MACROMAP_UTIL_HPP_HK041119
+
+#include <boost/assert.hpp>
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/wave/token_ids.hpp>
+#include <boost/wave/util/unput_queue_iterator.hpp>
+
+// this must occur after all of the includes and before any code appears
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_PREFIX
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// This file contains the definition of several token sequence analyze
+// and transformation utility functions needed during macro handling.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+namespace boost {
+namespace wave {
+namespace util {
+
+///////////////////////////////////////////////////////////////////////////////
+namespace on_exit {
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // On destruction pop the first element of the list given as the argument
+ //
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename ContainerT>
+ class pop_front {
+ public:
+ pop_front(ContainerT &list_) : list(list_) {}
+ ~pop_front() { list.pop_front(); }
+
+ private:
+ ContainerT &list;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // Append a given list to the list given as argument
+ // On destruction pop the first element of the list given as argument
+ //
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename ContainerT>
+ class splice_pop_front {
+ public:
+ splice_pop_front(ContainerT &list_, ContainerT &queue)
+ : list(list_)
+ {
+ list.splice(list.end(), queue);
+ }
+ ~splice_pop_front() { list.pop_front(); }
+
+ private:
+ ContainerT &list;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // On destruction reset a referenced value to its initial state
+ //
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename TypeT>
+ class reset {
+ public:
+ reset(TypeT &target_value_, TypeT new_value)
+ : target_value(target_value_), old_value(target_value_)
+ {
+ target_value_ = new_value;
+ }
+ ~reset() { target_value = old_value; }
+
+ private:
+ TypeT &target_value;
+ TypeT old_value;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // On destruction assign the given iterator back
+ //
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename IteratorT, typename UnputIteratorT>
+ class assign
+ {
+ public:
+ assign(IteratorT &it_, UnputIteratorT const &uit_)
+ : it(it_), uit(uit_) {}
+ ~assign() { it = uit.base(); }
+
+ private:
+ IteratorT &it;
+ UnputIteratorT const &uit;
+ };
+
+ template <typename IteratorT>
+ class assign<IteratorT, IteratorT> {
+ public:
+ assign(IteratorT &it_, IteratorT const &uit_)
+ : it(it_), uit(uit_) {}
+ ~assign() { it = uit; }
+
+ private:
+ IteratorT &it;
+ IteratorT const &uit;
+ };
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace on_exit
+
+///////////////////////////////////////////////////////////////////////////////
+namespace impl {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Test, whether a given identifier resolves to a predefined name
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename StringT>
+inline bool
+is_special_macroname (StringT const &name)
+{
+ if (name.size() < 7)
+ return false;
+
+ if ("defined" == name)
+ return true;
+
+ if ('_' == name[0] && '_' == name[1]) {
+ StringT str = name.substr(2);
+
+ if (str == "cplusplus" || str == "STDC__" ||
+ str == "TIME__" || str == "DATE__" ||
+ str == "LINE__" || str == "FILE__" ||
+ str == "INCLUDE_LEVEL__")
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Test, whether two tokens are to be considered equal (different sequences
+// of whitespace are considered to be equal)
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename TokenT>
+inline bool
+token_equals(TokenT const &left, TokenT const &right)
+{
+ using namespace boost::wave;
+
+ if (IS_CATEGORY(left, ParameterTokenType)) {
+ // if the existing token is of type T_PARAMETERBASE, then the right token
+ // must be of type T_IDENTIFIER or a keyword
+ token_id id = token_id(right);
+
+ return (T_IDENTIFIER == id ||
+ IS_CATEGORY(id, KeywordTokenType) ||
+ IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) ||
+ IS_CATEGORY(id, BoolLiteralTokenType)) &&
+ left.get_value() == right.get_value();
+ }
+
+ // if the left token has whitespace, the value is irrelevant
+ return token_id(left) == token_id(right) && (
+ IS_CATEGORY(left, WhiteSpaceTokenType) ||
+ left.get_value() == right.get_value()
+ );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Tests, whether two macro definitions are equal
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContainerT>
+inline bool
+definition_equals(ContainerT const &definition,
+ ContainerT const &new_definition)
+{
+ typedef typename ContainerT::const_iterator const_iterator_type;
+
+const_iterator_type first1 = definition.begin();
+const_iterator_type last1 = definition.end();
+const_iterator_type first2 = new_definition.begin();
+const_iterator_type last2 = new_definition.end();
+
+ while (first1 != last1 && first2 != last2 && token_equals(*first1, *first2))
+ {
+ // skip whitespace, if both sequences have a whitespace next
+ token_id id1 = next_token<const_iterator_type>::peek(first1, last1, false);
+ token_id id2 = next_token<const_iterator_type>::peek(first2, last2, false);
+
+ if (IS_CATEGORY(id1, WhiteSpaceTokenType) &&
+ IS_CATEGORY(id2, WhiteSpaceTokenType))
+ {
+ // all consecutive whitespace tokens count as one whitespace
+ // adjust first1 and first2 accordingly
+ skip_whitespace(first1, last1);
+ skip_whitespace(first2, last2);
+ }
+ else if (!IS_CATEGORY(id1, WhiteSpaceTokenType) &&
+ !IS_CATEGORY(id2, WhiteSpaceTokenType))
+ {
+ ++first1;
+ ++first2;
+ }
+ else {
+ // the sequences differ
+ break;
+ }
+ }
+ return (first1 == last1 && first2 == last2) ? true : false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Tests, whether two given sets of macro parameters are equal
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContainerT>
+inline bool
+parameters_equal(ContainerT const &parameters, ContainerT const &new_parameters)
+{
+ if (parameters.size() != new_parameters.size())
+ return false; // different parameter count
+
+ typedef typename ContainerT::const_iterator const_iterator_type;
+
+const_iterator_type first1 = parameters.begin();
+const_iterator_type last1 = parameters.end();
+const_iterator_type first2 = new_parameters.begin();
+const_iterator_type last2 = new_parameters.end();
+
+ while (first1 != last1 && first2 != last2) {
+ // parameters are different, if the corresponding tokens are different
+ using namespace boost::wave;
+ if (token_id(*first1) != token_id(*first2) ||
+ (*first1).get_value() != (*first2).get_value())
+ {
+ break;
+ }
+ ++first1;
+ ++first2;
+ }
+ return (first1 == last1 && first2 == last2) ? true : false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Strip leading and trailing whitespace from the given token sequence
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContainerT>
+inline void
+trim_replacement_list (ContainerT &replacement_list)
+{
+ using namespace boost::wave;
+
+// strip leading whitespace
+ if (replacement_list.size() > 0) {
+ typename ContainerT::iterator end = replacement_list.end();
+ typename ContainerT::iterator it = replacement_list.begin();
+
+ while (it != end && IS_CATEGORY(*it, WhiteSpaceTokenType)) {
+ token_id id(*it);
+ if (T_PLACEHOLDER != id && T_PLACEMARKER != id) {
+ typename ContainerT::iterator next = it;
+ ++next;
+ replacement_list.erase(it);
+ it = next;
+ }
+ else {
+ ++it;
+ }
+ }
+ }
+
+// strip trailing whitespace
+ if (replacement_list.size() > 0) {
+ typename ContainerT::reverse_iterator rend = replacement_list.rend();
+ typename ContainerT::reverse_iterator rit = replacement_list.rbegin();
+
+ while (rit != rend && IS_CATEGORY(*rit, WhiteSpaceTokenType))
+ ++rit;
+
+ typename ContainerT::iterator end = replacement_list.end();
+ typename ContainerT::iterator it = rit.base();
+
+ while (it != end && IS_CATEGORY(*it, WhiteSpaceTokenType)) {
+ token_id id(*it);
+ if (T_PLACEHOLDER != id && T_PLACEMARKER != id) {
+ typename ContainerT::iterator next = it;
+ ++next;
+ replacement_list.erase(it);
+ it = next;
+ }
+ else {
+ ++it;
+ }
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Tests, whether the given token sequence consists out of whitespace only
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContainerT>
+inline bool
+is_whitespace_only (ContainerT const &argument)
+{
+ typename ContainerT::const_iterator end = argument.end();
+ for (typename ContainerT::const_iterator it = argument.begin();
+ it != end; ++it)
+ {
+ if (!IS_CATEGORY(*it, WhiteSpaceTokenType))
+ return false;
+ }
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Remove all placeholder tokens from the given token sequence
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContainerT>
+inline void
+remove_placeholders (ContainerT &replacement_list)
+{
+ using namespace boost::wave;
+
+// strip leading whitespace
+ if (replacement_list.size() > 0) {
+ typename ContainerT::iterator end = replacement_list.end();
+ typename ContainerT::iterator it = replacement_list.begin();
+
+ while (it != end) {
+ token_id id(*it);
+ if (T_PLACEHOLDER == id || T_PLACEMARKER == id) {
+ typename ContainerT::iterator next = it;
+ ++next;
+ replacement_list.erase(it);
+ it = next;
+ }
+ else {
+ ++it;
+ }
+ }
+
+ // remove all 'new' leading and trailing whitespace
+ if (is_whitespace_only(replacement_list))
+ trim_replacement_list(replacement_list);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Remove all whitespace tokens on the left side of the given token sequence
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContainerT>
+inline void
+trim_sequence_left (ContainerT &argument)
+{
+ using namespace boost::wave;
+
+// strip leading whitespace (should be only one token)
+ if (argument.size() > 0 &&
+ IS_CATEGORY(argument.front(), WhiteSpaceTokenType))
+ {
+ argument.pop_front();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Remove all whitespace tokens on the right side of the given token sequence
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContainerT>
+inline void
+trim_sequence_right (ContainerT &argument)
+{
+ using namespace boost::wave;
+
+// strip trailing whitespace (should be only one token)
+ if (argument.size() > 0 &&
+ IS_CATEGORY(argument.back(), WhiteSpaceTokenType))
+ {
+ argument.pop_back();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Remove all whitespace tokens on the left and right sides of the given token
+// sequence
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContainerT>
+inline void
+trim_sequence (ContainerT &argument)
+{
+ trim_sequence_left(argument);
+ trim_sequence_right(argument);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// call 'skipped_token' preprocessing hook
+template <typename ContextT>
+void call_skipped_token_hook(ContextT& ctx,
+ typename ContextT::token_type const& skipped)
+{
+#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
+ ctx.get_hooks().skipped_token(skipped);
+#else
+ ctx.get_hooks().skipped_token(ctx.derived(), skipped);
+#endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Skip forward to a given token
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT, typename IteratorT>
+inline bool
+skip_to_token(ContextT& ctx, IteratorT &it, IteratorT const &end,
+ token_id id, bool& seen_newline)
+{
+ using namespace boost::wave;
+ if (token_id(*it) == id)
+ return true;
+
+// call_skipped_token_hook(ctx, *it);
+ if (++it == end)
+ return false;
+
+ while (IS_CATEGORY(*it, WhiteSpaceTokenType) ||
+ T_NEWLINE == token_id(*it))
+ {
+ if (T_NEWLINE == token_id(*it))
+ seen_newline = true;
+
+// call_skipped_token_hook(ctx, *it);
+ if (++it == end)
+ return false;
+ }
+ return token_id(*it) == id;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Get the full name of a given macro name (concatenate the string
+// representations of the single tokens).
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename IteratorT>
+inline std::string
+get_full_name(IteratorT const &begin, IteratorT const &end)
+{
+ std::string full_name;
+ for (IteratorT err_it = begin; err_it != end; ++err_it)
+ full_name += (*err_it).get_value().c_str();
+
+ return full_name;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// The following predicate is used in conjunction with the remove_copy_if
+// algorithm to allow the detection of an eventually copied operator ##.
+// No removal is performed in any case.
+//
+///////////////////////////////////////////////////////////////////////////////
+class find_concat_operator {
+public:
+ find_concat_operator(bool &found_) : found_concat(found_) {}
+
+ template <typename TokenT>
+ bool operator()(TokenT const &tok)
+ {
+ using namespace boost::wave;
+ if (T_POUND_POUND == BASE_TOKEN(token_id(tok)))
+ found_concat = true;
+ return false;
+ }
+
+private:
+ bool &found_concat;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Convert a string of an arbitrary string compatible type to a internal
+// string (BOOST_WAVE_STRING)
+template <typename Target, typename Src>
+struct to_string_helper
+{
+ typedef Target type;
+
+ static Target call(Src const& str)
+ {
+ return Target(str.c_str());
+ }
+};
+
+// do nothing if types are equal
+template <typename Src>
+struct to_string_helper<Src, Src>
+{
+ typedef Src const& type;
+
+ static Src const& call(Src const& str)
+ {
+ return str;
+ }
+};
+
+template <typename Target>
+struct to_string_helper<Target, char const*>
+{
+ typedef Target type;
+
+ static Target call(char const* str)
+ {
+ return Target(str);
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace impl
+
+template <typename Target, typename Src>
+inline typename impl::to_string_helper<Target, Src>::type
+to_string(Src const& src)
+{
+ return impl::to_string_helper<Target, Src>::call(src);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace util
+} // namespace wave
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(CPP_MACROMAP_UTIL_HPP_HK041119)
diff --git a/boost/wave/util/file_position.hpp b/boost/wave/util/file_position.hpp
new file mode 100644
index 0000000000..87f6f77375
--- /dev/null
+++ b/boost/wave/util/file_position.hpp
@@ -0,0 +1,195 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ Definition of the position_iterator and file_position templates
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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(FILE_POSITION_H_52BDEDF7_DAD3_4F24_802F_E66BB8098F68_INCLUDED)
+#define FILE_POSITION_H_52BDEDF7_DAD3_4F24_802F_E66BB8098F68_INCLUDED
+
+#include <string>
+#include <ostream>
+
+#include <boost/assert.hpp>
+#include <boost/spirit/include/classic_version.hpp>
+#include <boost/spirit/include/classic_position_iterator.hpp>
+#include <boost/wave/wave_config.hpp>
+#if BOOST_WAVE_SERIALIZATION != 0
+#include <boost/serialization/serialization.hpp>
+#endif
+
+// 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 {
+namespace util {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// file_position
+//
+// A structure to hold positional information. This includes the filename,
+// line number and column number of a current token position.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename StringT>
+struct file_position {
+
+public:
+ typedef StringT string_type;
+
+ file_position()
+ : file(), line(1), column(1)
+ {}
+ explicit file_position(string_type const& file_, std::size_t line_ = 1,
+ std::size_t column_ = 1)
+ : file(file_), line(line_), column(column_)
+ {}
+
+// accessors
+ string_type const &get_file() const { return file; }
+ std::size_t get_line() const { return line; }
+ std::size_t get_column() const { return column; }
+
+ void set_file(string_type const &file_)
+ {
+ file = file_;
+ }
+ void set_line(std::size_t line_) { line = line_; }
+ void set_column(std::size_t column_) { column = column_; }
+
+private:
+#if BOOST_WAVE_SERIALIZATION != 0
+ friend class boost::serialization::access;
+ template<typename Archive>
+ void serialize(Archive &ar, const unsigned int version)
+ {
+ using namespace boost::serialization;
+ ar & make_nvp("filename", file);
+ ar & make_nvp("line", line);
+ ar & make_nvp("column", column);
+ }
+#endif
+
+ string_type file;
+ std::size_t line;
+ std::size_t column;
+};
+
+template <typename StringT>
+bool operator== (file_position<StringT> const &lhs,
+ file_position<StringT> const &rhs)
+{
+ return lhs.get_column() == rhs.get_column() &&
+ lhs.get_line() == rhs.get_line() && lhs.get_file() == rhs.get_file();
+}
+
+template <typename StringT>
+inline std::ostream &
+operator<< (std::ostream &o, file_position<StringT> const &pos)
+{
+ o << pos.get_file() << ":" << pos.get_line() << ":" << pos.get_column();
+ return o;
+}
+
+typedef file_position<BOOST_WAVE_STRINGTYPE> file_position_type;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// position_iterator
+//
+// The position_iterator used by Wave is now based on the corresponding Spirit
+// type. This type is used with our own file_position though. The needed
+// specialization of the boost::spirit::classic::position_policy class is
+// provided below.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename IteratorT, typename PositionT>
+struct position_iterator
+: boost::spirit::classic::position_iterator<IteratorT, PositionT>
+{
+ typedef boost::spirit::classic::position_iterator<IteratorT, PositionT> base_type;
+
+ position_iterator()
+ {
+ }
+
+ position_iterator(IteratorT const &begin, IteratorT const &end,
+ PositionT const &pos)
+ : base_type(begin, end, pos)
+ {
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace util
+} // namespace wave
+
+///////////////////////////////////////////////////////////////////////////////
+
+namespace spirit { namespace classic {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// The boost::spirit::classic::position_policy has to be specialized for our
+// file_position class
+//
+///////////////////////////////////////////////////////////////////////////////
+
+ template <>
+ class position_policy<boost::wave::util::file_position_type> {
+
+ public:
+ position_policy()
+ : m_CharsPerTab(4)
+ {}
+
+ void next_line(boost::wave::util::file_position_type &pos)
+ {
+ pos.set_line(pos.get_line() + 1);
+ pos.set_column(1);
+ }
+
+ void set_tab_chars(unsigned int chars)
+ {
+ m_CharsPerTab = chars;
+ }
+
+ void next_char(boost::wave::util::file_position_type &pos)
+ {
+ pos.set_column(pos.get_column() + 1);
+ }
+
+ void tabulation(boost::wave::util::file_position_type &pos)
+ {
+ pos.set_column(pos.get_column() + m_CharsPerTab -
+ (pos.get_column() - 1) % m_CharsPerTab);
+ }
+
+ private:
+ unsigned int m_CharsPerTab;
+ };
+
+///////////////////////////////////////////////////////////////////////////////
+}} // namespace spirit::classic
+
+} // namespace boost
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // !defined(FILE_POSITION_H_52BDEDF7_DAD3_4F24_802F_E66BB8098F68_INCLUDED)
diff --git a/boost/wave/util/filesystem_compatibility.hpp b/boost/wave/util/filesystem_compatibility.hpp
new file mode 100644
index 0000000000..5bd924af72
--- /dev/null
+++ b/boost/wave/util/filesystem_compatibility.hpp
@@ -0,0 +1,172 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ http://www.boost.org/
+
+ Copyright (c) 2001-2011 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(BOOST_WAVE_FILESYSTEM_COMPATIBILITY_MAR_09_2009_0142PM)
+#define BOOST_WAVE_FILESYSTEM_COMPATIBILITY_MAR_09_2009_0142PM
+
+#include <string>
+
+#include <boost/version.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/operations.hpp>
+
+namespace boost { namespace wave { namespace util
+{
+///////////////////////////////////////////////////////////////////////////////
+// filesystem wrappers allowing to handle different Boost versions
+#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED)
+// interface wrappers for older Boost versions
+ inline boost::filesystem::path initial_path()
+ {
+ return boost::filesystem::initial_path();
+ }
+
+ inline boost::filesystem::path current_path()
+ {
+ return boost::filesystem::current_path();
+ }
+
+ template <typename String>
+ inline boost::filesystem::path create_path(String const& p)
+ {
+#if BOOST_FILESYSTEM_VERSION >= 3
+ return boost::filesystem::path(p);
+#else
+ return boost::filesystem::path(p, boost::filesystem::native);
+#endif
+ }
+
+ inline std::string leaf(boost::filesystem::path const& p)
+ {
+#if BOOST_FILESYSTEM_VERSION >= 3
+ return p.leaf().string();
+#else
+ return p.leaf();
+#endif
+ }
+
+ inline boost::filesystem::path branch_path(boost::filesystem::path const& p)
+ {
+ return p.branch_path();
+ }
+
+ inline boost::filesystem::path normalize(boost::filesystem::path& p)
+ {
+ return p.normalize();
+ }
+
+ inline std::string native_file_string(boost::filesystem::path const& p)
+ {
+#if BOOST_FILESYSTEM_VERSION >= 3
+ return p.string();
+#else
+ return p.native_file_string();
+#endif
+ }
+
+ inline boost::filesystem::path complete_path(
+ boost::filesystem::path const& p)
+ {
+#if BOOST_FILESYSTEM_VERSION >= 3
+ return boost::filesystem3::complete(p, initial_path());
+#else
+ return boost::filesystem::complete(p, initial_path());
+#endif
+ }
+
+ inline boost::filesystem::path complete_path(
+ boost::filesystem::path const& p, boost::filesystem::path const& base)
+ {
+#if BOOST_FILESYSTEM_VERSION >= 3
+ return boost::filesystem3::complete(p, base);
+#else
+ return boost::filesystem::complete(p, base);
+#endif
+ }
+
+#else
+
+// interface wrappers if deprecated functions do not exist
+ inline boost::filesystem::path initial_path()
+ {
+#if BOOST_FILESYSTEM_VERSION >= 3
+ return boost::filesystem3::detail::initial_path();
+#else
+ return boost::filesystem::initial_path<boost::filesystem::path>();
+#endif
+ }
+
+ inline boost::filesystem::path current_path()
+ {
+#if BOOST_FILESYSTEM_VERSION >= 3
+ return boost::filesystem3::current_path();
+#else
+ return boost::filesystem::current_path<boost::filesystem::path>();
+#endif
+ }
+
+ template <typename String>
+ inline boost::filesystem::path create_path(String const& p)
+ {
+ return boost::filesystem::path(p);
+ }
+
+ inline std::string leaf(boost::filesystem::path const& p)
+ {
+#if BOOST_VERSION >= 104600 && BOOST_FILESYSTEM_VERSION >= 3
+ return p.filename().string();
+#else
+ return p.filename();
+#endif
+ }
+
+ inline boost::filesystem::path branch_path(boost::filesystem::path const& p)
+ {
+ return p.parent_path();
+ }
+
+ inline boost::filesystem::path normalize(boost::filesystem::path& p)
+ {
+ return p; // function doesn't exist anymore
+ }
+
+ inline std::string native_file_string(boost::filesystem::path const& p)
+ {
+#if BOOST_VERSION >= 104600
+ return p.string();
+#else
+ return p.file_string();
+#endif
+ }
+
+ inline boost::filesystem::path complete_path(
+ boost::filesystem::path const& p)
+ {
+#if BOOST_VERSION >= 104600 && BOOST_FILESYSTEM_VERSION >= 3
+ return boost::filesystem::absolute(p, initial_path());
+#else
+ return boost::filesystem::complete(p, initial_path());
+#endif
+ }
+
+ inline boost::filesystem::path complete_path(
+ boost::filesystem::path const& p, boost::filesystem::path const& base)
+ {
+#if BOOST_VERSION >= 104600 && BOOST_FILESYSTEM_VERSION >= 3
+ return boost::filesystem::absolute(p, base);
+#else
+ return boost::filesystem::complete(p, base);
+#endif
+ }
+#endif
+
+}}}
+
+#endif
diff --git a/boost/wave/util/flex_string.hpp b/boost/wave/util/flex_string.hpp
new file mode 100644
index 0000000000..da16235676
--- /dev/null
+++ b/boost/wave/util/flex_string.hpp
@@ -0,0 +1,2672 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+ http://www.boost.org/
+
+ Copyright (c) 2001 by Andrei Alexandrescu. 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)
+=============================================================================*/
+
+// This code is taken from:
+// Andrei Alexandrescu, Generic<Programming>: A Policy-Based basic_string
+// Implementation. http://www.cuj.com/documents/s=7994/cujcexp1906alexandr/
+//
+// #HK030306:
+// - Moved into the namespace boost::wave::util
+// - Added a bunch of missing typename(s)
+// - Integrated with boost config
+// - Added a missing header include
+// - Added special constructors and operator= to allow CowString to be
+// a real COW-string (removed unnecessary data copying)
+// - Fixed a string terminating bug in append
+//
+// #HK040109:
+// - Incorporated the changes from Andrei's latest version of this class
+//
+// #HK070307:
+// - Once again incorporated the changes from Andrei's latest version of
+// this class
+//
+// #HK090523:
+// - Incorporated the changes from latest version of flex_string as
+// maintained in Loki
+
+#ifndef FLEX_STRING_INC_
+#define FLEX_STRING_INC_
+
+/*
+////////////////////////////////////////////////////////////////////////////////
+template <typename E, class A = @>
+class StoragePolicy
+{
+ typedef E value_type;
+ typedef @ iterator;
+ typedef @ const_iterator;
+ typedef A allocator_type;
+ typedef @ size_type;
+
+ StoragePolicy(const StoragePolicy& s);
+ StoragePolicy(const A&);
+ StoragePolicy(const E* s, size_type len, const A&);
+ StoragePolicy(size_type len, E c, const A&);
+ ~StoragePolicy();
+
+ iterator begin();
+ const_iterator begin() const;
+ iterator end();
+ const_iterator end() const;
+
+ size_type size() const;
+ size_type max_size() const;
+ size_type capacity() const;
+
+ void reserve(size_type res_arg);
+
+ void append(const E* s, size_type sz);
+
+ template <class InputIterator>
+ void append(InputIterator b, InputIterator e);
+
+ void resize(size_type newSize, E fill);
+
+ void swap(StoragePolicy& rhs);
+
+ const E* c_str() const;
+ const E* data() const;
+
+ A get_allocator() const;
+};
+////////////////////////////////////////////////////////////////////////////////
+*/
+
+#include <boost/config.hpp>
+#include <boost/assert.hpp>
+#include <boost/throw_exception.hpp>
+
+#include <boost/iterator/reverse_iterator.hpp>
+
+#include <boost/wave/wave_config.hpp>
+#if BOOST_WAVE_SERIALIZATION != 0
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/split_free.hpp>
+#include <boost/serialization/collections_save_imp.hpp>
+#include <boost/serialization/collections_load_imp.hpp>
+#define BOOST_WAVE_FLEX_STRING_SERIALIZATION_HACK 1
+#endif
+
+#include <memory>
+#include <new>
+#include <string>
+#include <vector>
+#include <algorithm>
+#include <functional>
+#include <limits>
+#include <stdexcept>
+#include <ios>
+
+#include <cstddef>
+#include <cstring>
+#include <cstdlib>
+
+// 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 {
+namespace util {
+
+namespace flex_string_details
+{
+ template <class InIt, class OutIt>
+ OutIt copy_n(InIt b,
+ typename std::iterator_traits<InIt>::difference_type n, OutIt d)
+ {
+ for (/**/; n != 0; --n, ++b, ++d)
+ {
+ *d = *b;
+ }
+ return d;
+ }
+
+ template <class Pod, class T>
+ inline void pod_fill(Pod* b, Pod* e, T c)
+ {
+ switch ((e - b) & 7)
+ {
+ case 0:
+ while (b != e)
+ {
+ *b = c; ++b;
+ case 7: *b = c; ++b;
+ case 6: *b = c; ++b;
+ case 5: *b = c; ++b;
+ case 4: *b = c; ++b;
+ case 3: *b = c; ++b;
+ case 2: *b = c; ++b;
+ case 1: *b = c; ++b;
+ }
+ }
+ }
+
+ template <class Pod>
+ inline void pod_move(const Pod* b, const Pod* e, Pod* d)
+ {
+ using namespace std;
+ memmove(d, b, (e - b) * sizeof(*b));
+ }
+
+ template <class Pod>
+ inline Pod* pod_copy(const Pod* b, const Pod* e, Pod* d)
+ {
+ const std::size_t s = e - b;
+ using namespace std;
+ memcpy(d, b, s * sizeof(*b));
+ return d + s;
+ }
+
+ template <typename T> struct get_unsigned
+ {
+ typedef T result;
+ };
+
+ template <> struct get_unsigned<char>
+ {
+ typedef unsigned char result;
+ };
+
+ template <> struct get_unsigned<signed char>
+ {
+ typedef unsigned char result;
+ };
+
+ template <> struct get_unsigned<short int>
+ {
+ typedef unsigned short int result;
+ };
+
+ template <> struct get_unsigned<int>
+ {
+ typedef unsigned int result;
+ };
+
+ template <> struct get_unsigned<long int>
+ {
+ typedef unsigned long int result;
+ };
+
+ enum Shallow {};
+}
+
+template <class T> class mallocator
+{
+public:
+ typedef T value_type;
+ typedef value_type* pointer;
+ typedef const value_type* const_pointer;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+ typedef std::size_t size_type;
+ //typedef unsigned int size_type;
+ //typedef std::ptrdiff_t difference_type;
+ typedef int difference_type;
+
+ template <class U>
+ struct rebind { typedef mallocator<U> other; };
+
+ mallocator() {}
+ mallocator(const mallocator&) {}
+ //template <class U>
+ //mallocator(const mallocator<U>&) {}
+ ~mallocator() {}
+
+ pointer address(reference x) const { return &x; }
+ const_pointer address(const_reference x) const
+ {
+ return x;
+ }
+
+ pointer allocate(size_type n, const_pointer = 0)
+ {
+ using namespace std;
+ void* p = malloc(n * sizeof(T));
+ if (!p) boost::throw_exception(std::bad_alloc());
+ return static_cast<pointer>(p);
+ }
+
+ void deallocate(pointer p, size_type)
+ {
+ using namespace std;
+ free(p);
+ }
+
+ size_type max_size() const
+ {
+ return static_cast<size_type>(-1) / sizeof(T);
+ }
+
+ void construct(pointer p, const value_type& x)
+ {
+ new(p) value_type(x);
+ }
+
+ void destroy(pointer p)
+ {
+ p->~value_type();
+ }
+
+private:
+ void operator=(const mallocator&);
+};
+
+template<> class mallocator<void>
+{
+ typedef void value_type;
+ typedef void* pointer;
+ typedef const void* const_pointer;
+
+ template <class U>
+ struct rebind { typedef mallocator<U> other; };
+};
+
+template <class T>
+inline bool operator==(const mallocator<T>&,
+ const mallocator<T>&) {
+ return true;
+}
+
+template <class T>
+inline bool operator!=(const mallocator<T>&,
+ const mallocator<T>&) {
+ return false;
+}
+
+template <class Allocator>
+typename Allocator::pointer Reallocate(
+ Allocator& alloc,
+ typename Allocator::pointer p,
+ typename Allocator::size_type oldObjCount,
+ typename Allocator::size_type newObjCount,
+ void*)
+{
+ // @@@ not implemented
+ return NULL;
+}
+
+template <class Allocator>
+typename Allocator::pointer Reallocate(
+ Allocator& alloc,
+ typename Allocator::pointer p,
+ typename Allocator::size_type oldObjCount,
+ typename Allocator::size_type newObjCount,
+ mallocator<void>*)
+{
+ // @@@ not implemented
+ return NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// class template SimpleStringStorage
+// Allocates memory with malloc
+////////////////////////////////////////////////////////////////////////////////
+
+template <typename E, class A = std::allocator<E> >
+class SimpleStringStorage
+{
+ // The "public" below exists because MSVC can't do template typedefs
+public:
+ struct Data
+ {
+ Data() : pEnd_(buffer_), pEndOfMem_(buffer_) { buffer_[0] = E(0); }
+
+ E* pEnd_;
+ E* pEndOfMem_;
+ E buffer_[1];
+ };
+ static const Data emptyString_;
+
+ typedef typename A::size_type size_type;
+
+private:
+ Data* pData_;
+
+ void Init(size_type size, size_type capacity)
+ {
+ BOOST_ASSERT(size <= capacity);
+ if (capacity == 0)
+ {
+ pData_ = const_cast<Data*>(&emptyString_);
+ }
+ else
+ {
+ // 11-17-2000: comment added:
+ // No need to allocate (capacity + 1) to
+ // accommodate the terminating 0, because Data already
+ // has one one character in there
+ pData_ = static_cast<Data*>(
+ malloc(sizeof(Data) + capacity * sizeof(E)));
+ if (!pData_) boost::throw_exception(std::bad_alloc());
+ pData_->pEnd_ = pData_->buffer_ + size;
+ pData_->pEndOfMem_ = pData_->buffer_ + capacity;
+ }
+ }
+
+private:
+ // Warning - this doesn't initialize pData_. Used in reserve()
+ SimpleStringStorage()
+ { }
+
+public:
+ typedef E value_type;
+ typedef E* iterator;
+ typedef const E* const_iterator;
+ typedef A allocator_type;
+
+ SimpleStringStorage(const SimpleStringStorage& rhs)
+ {
+ const size_type sz = rhs.size();
+ Init(sz, sz);
+ if (sz) flex_string_details::pod_copy(rhs.begin(), rhs.end(), begin());
+ }
+
+ SimpleStringStorage(const SimpleStringStorage& s,
+ flex_string_details::Shallow)
+ : pData_(s.pData_)
+ {
+ }
+
+ SimpleStringStorage(const A&)
+ { pData_ = const_cast<Data*>(&emptyString_); }
+
+ SimpleStringStorage(const E* s, size_type len, const A&)
+ {
+ Init(len, len);
+ flex_string_details::pod_copy(s, s + len, begin());
+ }
+
+ SimpleStringStorage(size_type len, E c, const A&)
+ {
+ Init(len, len);
+ flex_string_details::pod_fill(begin(), end(), c);
+ }
+
+ SimpleStringStorage& operator=(const SimpleStringStorage& rhs)
+ {
+ const size_type sz = rhs.size();
+ reserve(sz);
+ flex_string_details::pod_copy(&*rhs.begin(), &*rhs.end(), begin());
+ pData_->pEnd_ = &*begin() + sz;
+ return *this;
+ }
+
+ ~SimpleStringStorage()
+ {
+ BOOST_ASSERT(begin() <= end());
+ if (pData_ != &emptyString_) free(pData_);
+ }
+
+ iterator begin()
+ { return pData_->buffer_; }
+
+ const_iterator begin() const
+ { return pData_->buffer_; }
+
+ iterator end()
+ { return pData_->pEnd_; }
+
+ const_iterator end() const
+ { return pData_->pEnd_; }
+
+ size_type size() const
+ { return pData_->pEnd_ - pData_->buffer_; }
+
+ size_type max_size() const
+ { return std::size_t(-1) / sizeof(E) - sizeof(Data) - 1; }
+
+ size_type capacity() const
+ { return pData_->pEndOfMem_ - pData_->buffer_; }
+
+ void reserve(size_type res_arg)
+ {
+ if (res_arg <= capacity())
+ {
+ // @@@ insert shrinkage here if you wish
+ return;
+ }
+
+ if (pData_ == &emptyString_)
+ {
+ Init(0, res_arg);
+ }
+ else
+ {
+ const size_type sz = size();
+
+ void* p = realloc(pData_,
+ sizeof(Data) + res_arg * sizeof(E));
+ if (!p) boost::throw_exception(std::bad_alloc());
+
+ if (p != pData_)
+ {
+ pData_ = static_cast<Data*>(p);
+ pData_->pEnd_ = pData_->buffer_ + sz;
+ }
+ pData_->pEndOfMem_ = pData_->buffer_ + res_arg;
+ }
+ }
+
+ void append(const E* s, size_type sz)
+ {
+ const size_type neededCapacity = size() + sz;
+
+ if (capacity() < neededCapacity)
+ {
+ const iterator b = begin();
+ static std::less_equal<const E*> le;
+ if (le(b, s) && le(s, end()))
+ {
+ // aliased
+ const size_type offset = s - b;
+ reserve(neededCapacity);
+ s = begin() + offset;
+ }
+ else
+ {
+ reserve(neededCapacity);
+ }
+ }
+ flex_string_details::pod_copy(s, s + sz, end());
+ pData_->pEnd_ += sz;
+ }
+
+ template <class InputIterator>
+ void append(InputIterator b, InputIterator e)
+ {
+ // @@@ todo: optimize this depending on iterator type
+ for (; b != e; ++b)
+ {
+ *this += *b;
+ }
+ }
+
+ void resize(size_type newSize, E fill)
+ {
+ const int delta = int(newSize - size());
+ if (delta == 0) return;
+
+ if (delta > 0)
+ {
+ if (newSize > capacity())
+ {
+ reserve(newSize);
+ }
+ E* e = &*end();
+ flex_string_details::pod_fill(e, e + delta, fill);
+ }
+ pData_->pEnd_ = pData_->buffer_ + newSize;
+ }
+
+ void swap(SimpleStringStorage& rhs)
+ {
+ std::swap(pData_, rhs.pData_);
+ }
+
+ const E* c_str() const
+ {
+ if (pData_ != &emptyString_) *pData_->pEnd_ = E();
+ return pData_->buffer_;
+ }
+
+ const E* data() const
+ { return pData_->buffer_; }
+
+ A get_allocator() const
+ { return A(); }
+};
+
+template <typename E, class A>
+const typename SimpleStringStorage<E, A>::Data
+SimpleStringStorage<E, A>::emptyString_ =
+ typename SimpleStringStorage<E, A>::Data();
+
+////////////////////////////////////////////////////////////////////////////////
+// class template AllocatorStringStorage
+// Allocates with your allocator
+// Takes advantage of the Empty Base Optimization if available
+////////////////////////////////////////////////////////////////////////////////
+
+template <typename E, class A = std::allocator<E> >
+class AllocatorStringStorage : public A
+{
+ typedef typename A::size_type size_type;
+ typedef typename SimpleStringStorage<E, A>::Data Data;
+
+ void* Alloc(size_type sz, const void* p = 0)
+ {
+ return A::allocate(1 + (sz - 1) / sizeof(E),
+ static_cast<const char*>(p));
+ }
+
+ void* Realloc(void* p, size_type oldSz, size_type newSz)
+ {
+ void* r = Alloc(newSz);
+ flex_string_details::pod_copy(p, p + Min(oldSz, newSz), r);
+ Free(p, oldSz);
+ return r;
+ }
+
+ void Free(void* p, size_type sz)
+ {
+ A::deallocate(static_cast<E*>(p), sz);
+ }
+
+ Data* pData_;
+
+ void Init(size_type size, size_type cap)
+ {
+ BOOST_ASSERT(size <= cap);
+
+ if (cap == 0)
+ {
+ pData_ = const_cast<Data*>(
+ &SimpleStringStorage<E, A>::emptyString_);
+ }
+ else
+ {
+ pData_ = static_cast<Data*>(Alloc(
+ cap * sizeof(E) + sizeof(Data)));
+ pData_->pEnd_ = pData_->buffer_ + size;
+ pData_->pEndOfMem_ = pData_->buffer_ + cap;
+ }
+ }
+
+public:
+ typedef E value_type;
+ typedef E* iterator;
+ typedef const E* const_iterator;
+ typedef A allocator_type;
+
+ AllocatorStringStorage()
+ : A(), pData_(0)
+ {
+ }
+
+ AllocatorStringStorage(const AllocatorStringStorage& rhs)
+ : A(rhs.get_allocator())
+ {
+ const size_type sz = rhs.size();
+ Init(sz, sz);
+ if (sz) flex_string_details::pod_copy(rhs.begin(), rhs.end(), begin());
+ }
+
+ AllocatorStringStorage(const AllocatorStringStorage& s,
+ flex_string_details::Shallow)
+ : A(s.get_allocator())
+ {
+ pData_ = s.pData_;
+ }
+
+ AllocatorStringStorage(const A& a) : A(a)
+ {
+ pData_ = const_cast<Data*>(
+ &SimpleStringStorage<E, A>::emptyString_);
+ }
+
+ AllocatorStringStorage(const E* s, size_type len, const A& a)
+ : A(a)
+ {
+ Init(len, len);
+ flex_string_details::pod_copy(s, s + len, begin());
+ }
+
+ AllocatorStringStorage(size_type len, E c, const A& a)
+ : A(a)
+ {
+ Init(len, len);
+ flex_string_details::pod_fill(&*begin(), &*end(), c);
+ }
+
+ AllocatorStringStorage& operator=(const AllocatorStringStorage& rhs)
+ {
+ const size_type sz = rhs.size();
+ reserve(sz);
+ flex_string_details::pod_copy(&*rhs.begin(), &*rhs.end(), begin());
+ pData_->pEnd_ = &*begin() + rhs.size();
+ return *this;
+ }
+
+ ~AllocatorStringStorage()
+ {
+ if (capacity())
+ {
+ Free(pData_,
+ sizeof(Data) + capacity() * sizeof(E));
+ }
+ }
+
+ iterator begin()
+ { return pData_->buffer_; }
+
+ const_iterator begin() const
+ { return pData_->buffer_; }
+
+ iterator end()
+ { return pData_->pEnd_; }
+
+ const_iterator end() const
+ { return pData_->pEnd_; }
+
+ size_type size() const
+ { return size_type(end() - begin()); }
+
+ size_type max_size() const
+ { return A::max_size(); }
+
+ size_type capacity() const
+ { return size_type(pData_->pEndOfMem_ - pData_->buffer_); }
+
+ void resize(size_type n, E c)
+ {
+ reserve(n);
+ iterator newEnd = begin() + n;
+ iterator oldEnd = end();
+ if (newEnd > oldEnd)
+ {
+ // Copy the characters
+ flex_string_details::pod_fill(oldEnd, newEnd, c);
+ }
+ if (capacity()) pData_->pEnd_ = newEnd;
+ }
+
+ void reserve(size_type res_arg)
+ {
+ if (res_arg <= capacity())
+ {
+ // @@@ shrink to fit here
+ return;
+ }
+
+ A& myAlloc = *this;
+ AllocatorStringStorage newStr(myAlloc);
+ newStr.Init(size(), res_arg);
+
+ flex_string_details::pod_copy(begin(), end(), newStr.begin());
+
+ swap(newStr);
+ }
+
+ template <class ForwardIterator>
+ void append(ForwardIterator b, ForwardIterator e)
+ {
+ const size_type
+ sz = std::distance(b, e),
+ neededCapacity = size() + sz;
+
+ if (capacity() < neededCapacity)
+ {
+// typedef std::less_equal<const E*> le_type;
+// BOOST_ASSERT(!(le_type()(begin(), &*b) && le_type()(&*b, end())));
+ reserve(neededCapacity);
+ }
+ std::copy(b, e, end());
+ pData_->pEnd_ += sz;
+ }
+
+ void swap(AllocatorStringStorage& rhs)
+ {
+ // @@@ The following line is commented due to a bug in MSVC
+ //std::swap(lhsAlloc, rhsAlloc);
+ std::swap(pData_, rhs.pData_);
+ }
+
+ const E* c_str() const
+ {
+ if (pData_ != &SimpleStringStorage<E, A>::emptyString_)
+ {
+ *pData_->pEnd_ = E();
+ }
+ return &*begin();
+ }
+
+ const E* data() const
+ { return &*begin(); }
+
+ A get_allocator() const
+ { return *this; }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// class template VectorStringStorage
+// Uses std::vector
+// Takes advantage of the Empty Base Optimization if available
+////////////////////////////////////////////////////////////////////////////////
+
+template <typename E, class A = std::allocator<E> >
+class VectorStringStorage : protected std::vector<E, A>
+{
+ typedef std::vector<E, A> base;
+
+public: // protected:
+ typedef E value_type;
+ typedef typename base::iterator iterator;
+ typedef typename base::const_iterator const_iterator;
+ typedef A allocator_type;
+ typedef typename A::size_type size_type;
+
+ VectorStringStorage(const VectorStringStorage& s) : base(s)
+ { }
+
+ VectorStringStorage(const A& a) : base(1, E(), a)
+ { }
+
+ VectorStringStorage(const E* s, size_type len, const A& a)
+ : base(a)
+ {
+ base::reserve(len + 1);
+ base::insert(base::end(), s, s + len);
+ // Terminating zero
+ base::insert(base::end(), E());
+ }
+
+ VectorStringStorage(size_type len, E c, const A& a)
+ : base(len + 1, c, a)
+ {
+ // Terminating zero
+ base::back() = E();
+ }
+
+ VectorStringStorage& operator=(const VectorStringStorage& rhs)
+ {
+ base& v = *this;
+ v = rhs;
+ return *this;
+ }
+
+ iterator begin()
+ { return base::begin(); }
+
+ const_iterator begin() const
+ { return base::begin(); }
+
+ iterator end()
+ { return base::end() - 1; }
+
+ const_iterator end() const
+ { return base::end() - 1; }
+
+ size_type size() const
+ { return base::size() - 1; }
+
+ size_type max_size() const
+ { return base::max_size() - 1; }
+
+ size_type capacity() const
+ { return base::capacity() - 1; }
+
+ void reserve(size_type res_arg)
+ {
+ BOOST_ASSERT(res_arg < max_size());