summaryrefslogtreecommitdiff
path: root/boost/wave/util
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/util
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/util')
-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
20 files changed, 11322 insertions, 0 deletions
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());
+ base::reserve(res_arg + 1);
+ }
+
+ void append(const E* s, size_type sz)
+ {
+ // Check for aliasing because std::vector doesn't do it.
+ static std::less_equal<const E*> le;
+ if (!base::empty())
+ {
+ const E* start = &base::front();
+ if (le(start, s) && le(s, start + size()))
+ {
+ // aliased
+ const size_type offset = s - start;
+ reserve(size() + sz);
+ s = &base::front() + offset;
+ }
+ }
+ base::insert(end(), s, s + sz);
+ }
+
+ template <class InputIterator>
+ void append(InputIterator b, InputIterator e)
+ {
+ base::insert(end(), b, e);
+ }
+
+ void resize(size_type n, E c)
+ {
+ base::reserve(n + 1);
+ base::back() = c;
+ base::resize(n + 1, c);
+ base::back() = E();
+ }
+
+ void swap(VectorStringStorage& rhs)
+ { base::swap(rhs); }
+
+ const E* c_str() const
+ { return &*begin(); }
+
+ const E* data() const
+ { return &*begin(); }
+
+ A get_allocator() const
+ { return base::get_allocator(); }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// class template SmallStringOpt
+// Builds the small string optimization over any other storage
+////////////////////////////////////////////////////////////////////////////////
+
+template <class Storage, unsigned int threshold,
+ typename Align = typename Storage::value_type*>
+class SmallStringOpt
+{
+public:
+ typedef typename Storage::value_type value_type;
+ typedef value_type* iterator;
+ typedef const value_type* const_iterator;
+ typedef typename Storage::allocator_type allocator_type;
+ typedef typename allocator_type::size_type size_type;
+
+private:
+ enum { temp1 = threshold * sizeof(value_type) > sizeof(Storage)
+ ? threshold * sizeof(value_type)
+ : sizeof(Storage) };
+
+ enum { temp2 = temp1 > sizeof(Align) ? temp1 : sizeof(Align) };
+
+public:
+ enum { maxSmallString =
+ (temp2 + sizeof(value_type) - 1) / sizeof(value_type) };
+
+private:
+ enum { magic = maxSmallString + 1 };
+
+ union
+ {
+ mutable value_type buf_[maxSmallString + 1];
+ Align align_;
+ };
+
+ Storage& GetStorage()
+ {
+ BOOST_ASSERT(buf_[maxSmallString] == magic);
+ Storage* p = reinterpret_cast<Storage*>(&buf_[0]);
+ return *p;
+ }
+
+ const Storage& GetStorage() const
+ {
+ BOOST_ASSERT(buf_[maxSmallString] == magic);
+ const Storage *p = reinterpret_cast<const Storage*>(&buf_[0]);
+ return *p;
+ }
+
+ bool Small() const
+ {
+ return buf_[maxSmallString] != magic;
+ }
+
+public:
+ SmallStringOpt(const SmallStringOpt& s)
+ {
+ if (s.Small())
+ {
+ flex_string_details::pod_copy(
+ s.buf_,
+ s.buf_ + s.size(),
+ buf_);
+ }
+ else
+ {
+ new(buf_) Storage(s.GetStorage());
+ }
+ buf_[maxSmallString] = s.buf_[maxSmallString];
+ }
+
+ SmallStringOpt(const allocator_type&)
+ {
+ buf_[maxSmallString] = maxSmallString;
+ }
+
+ SmallStringOpt(const value_type* s, size_type len, const allocator_type& a)
+ {
+ if (len <= maxSmallString)
+ {
+ flex_string_details::pod_copy(s, s + len, buf_);
+ buf_[maxSmallString] = value_type(maxSmallString - len);
+ }
+ else
+ {
+ new(buf_) Storage(s, len, a);
+ buf_[maxSmallString] = magic;
+ }
+ }
+
+ SmallStringOpt(size_type len, value_type c, const allocator_type& a)
+ {
+ if (len <= maxSmallString)
+ {
+ flex_string_details::pod_fill(buf_, buf_ + len, c);
+ buf_[maxSmallString] = value_type(maxSmallString - len);
+ }
+ else
+ {
+ new(buf_) Storage(len, c, a);
+ buf_[maxSmallString] = magic;
+ }
+ }
+
+ SmallStringOpt& operator=(const SmallStringOpt& rhs)
+ {
+ reserve(rhs.size());
+ resize(0, 0);
+ append(rhs.data(), rhs.size());
+ return *this;
+ }
+
+ ~SmallStringOpt()
+ {
+ if (!Small()) GetStorage().~Storage();
+ }
+
+ iterator begin()
+ {
+ if (Small()) return buf_;
+ return &*GetStorage().begin();
+ }
+
+ const_iterator begin() const
+ {
+ if (Small()) return buf_;
+ return &*GetStorage().begin();
+ }
+
+ iterator end()
+ {
+ if (Small()) return buf_ + maxSmallString - buf_[maxSmallString];
+ return &*GetStorage().end();
+ }
+
+ const_iterator end() const
+ {
+ if (Small()) return buf_ + maxSmallString - buf_[maxSmallString];
+ return &*GetStorage().end();
+ }
+
+ size_type size() const
+ {
+ BOOST_ASSERT(!Small() || maxSmallString >= buf_[maxSmallString]);
+ return Small()
+ ? maxSmallString - buf_[maxSmallString]
+ : GetStorage().size();
+ }
+
+ size_type max_size() const
+ { return get_allocator().max_size(); }
+
+ size_type capacity() const
+ { return Small() ? maxSmallString : GetStorage().capacity(); }
+
+ void reserve(size_type res_arg)
+ {
+ if (Small())
+ {
+ if (res_arg <= maxSmallString) return;
+ SmallStringOpt temp(*this);
+ this->~SmallStringOpt();
+ new(buf_) Storage(temp.data(), temp.size(),
+ temp.get_allocator());
+ buf_[maxSmallString] = magic;
+ GetStorage().reserve(res_arg);
+ }
+ else
+ {
+ GetStorage().reserve(res_arg);
+ }
+ BOOST_ASSERT(capacity() >= res_arg);
+ }
+
+ void append(const value_type* s, size_type sz)
+ {
+ if (!Small())
+ {
+ GetStorage().append(s, sz);
+ }
+ else
+ {
+ // append to a small string
+ const size_type neededCapacity =
+ maxSmallString - buf_[maxSmallString] + sz;
+
+ if (maxSmallString < neededCapacity)
+ {
+ // need to change storage strategy
+ allocator_type alloc;
+ Storage temp(alloc);
+ temp.reserve(neededCapacity);
+ temp.append(buf_, maxSmallString - buf_[maxSmallString]);
+ temp.append(s, sz);
+ buf_[maxSmallString] = magic;
+ new(buf_) Storage(temp.get_allocator());
+ GetStorage().swap(temp);
+ }
+ else
+ {
+ flex_string_details::pod_move(s, s + sz,
+ buf_ + maxSmallString - buf_[maxSmallString]);
+ buf_[maxSmallString] -= value_type(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 n, value_type c)
+ {
+ if (Small())
+ {
+ if (n > maxSmallString)
+ {
+ // Small string resized to big string
+ SmallStringOpt temp(*this); // can't throw
+ // 11-17-2001: correct exception safety bug
+ Storage newString(temp.data(), temp.size(),
+ temp.get_allocator());
+ newString.resize(n, c);
+ // We make the reasonable assumption that an empty Storage
+ // constructor won't throw
+ this->~SmallStringOpt();
+ new(&buf_[0]) Storage(temp.get_allocator());
+ buf_[maxSmallString] = value_type(magic);
+ GetStorage().swap(newString);
+ }
+ else
+ {
+ // Small string resized to small string
+ // 11-17-2001: bug fix: terminating zero not copied
+ size_type toFill = n > size() ? n - size() : 0;
+ flex_string_details::pod_fill(end(), end() + toFill, c);
+ buf_[maxSmallString] = value_type(maxSmallString - n);
+ }
+ }
+ else
+ {
+ if (n > maxSmallString)
+ {
+ // Big string resized to big string
+ GetStorage().resize(n, c);
+ }
+ else
+ {
+ // Big string resized to small string
+ // 11-17=2001: bug fix in the BOOST_ASSERTion below
+ BOOST_ASSERT(capacity() > n);
+ SmallStringOpt newObj(data(), n, get_allocator());
+ newObj.swap(*this);
+ }
+ }
+ }
+
+ void swap(SmallStringOpt& rhs)
+ {
+ if (Small())
+ {
+ if (rhs.Small())
+ {
+ // Small swapped with small
+ std::swap_ranges(buf_, buf_ + maxSmallString + 1,
+ rhs.buf_);
+ }
+ else
+ {
+ // Small swapped with big
+ // Make a copy of myself - can't throw
+ SmallStringOpt temp(*this);
+ // Nuke myself
+ this->~SmallStringOpt();
+ // Make an empty storage for myself (likely won't throw)
+ new(buf_) Storage(0, value_type(), rhs.get_allocator());
+ buf_[maxSmallString] = magic;
+ // Recurse to this same function
+ swap(rhs);
+ // Nuke rhs
+ rhs.~SmallStringOpt();
+ // Build the new small string into rhs
+ new(&rhs) SmallStringOpt(temp);
+ }
+ }
+ else
+ {
+ if (rhs.Small())
+ {
+ // Big swapped with small
+ // Already implemented, recurse with reversed args
+ rhs.swap(*this);
+ }
+ else
+ {
+ // Big swapped with big
+ GetStorage().swap(rhs.GetStorage());
+ }
+ }
+ }
+
+ const value_type* c_str() const
+ {
+ if (!Small()) return GetStorage().c_str();
+ buf_[maxSmallString - buf_[maxSmallString]] = value_type();
+ return buf_;
+ }
+
+ const value_type* data() const
+ { return Small() ? buf_ : GetStorage().data(); }
+
+ allocator_type get_allocator() const
+ { return allocator_type(); }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// class template CowString
+// Implements Copy on Write over any storage
+////////////////////////////////////////////////////////////////////////////////
+
+template <
+ typename Storage,
+ typename Align = BOOST_DEDUCED_TYPENAME Storage::value_type*
+>
+class CowString
+{
+ typedef typename Storage::value_type E;
+ typedef typename flex_string_details::get_unsigned<E>::result RefCountType;
+
+public:
+ typedef E value_type;
+ typedef typename Storage::iterator iterator;
+ typedef typename Storage::const_iterator const_iterator;
+ typedef typename Storage::allocator_type allocator_type;
+ typedef typename allocator_type::size_type size_type;
+ typedef typename Storage::reference reference;
+
+private:
+ union
+ {
+ mutable char buf_[sizeof(Storage)];
+ Align align_;
+ };
+
+ Storage& Data() const
+ {
+ Storage* p = reinterpret_cast<Storage*>(&buf_[0]);
+ return *p;
+ }
+
+ RefCountType GetRefs() const
+ {
+ const Storage& d = Data();
+ BOOST_ASSERT(d.size() > 0);
+ BOOST_ASSERT(static_cast<RefCountType>(*d.begin()) != 0);
+ return *d.begin();
+ }
+
+ RefCountType& Refs()
+ {
+ Storage& d = Data();
+ BOOST_ASSERT(d.size() > 0);
+ return reinterpret_cast<RefCountType&>(*d.begin());
+ }
+
+ void MakeUnique() const
+ {
+ BOOST_ASSERT(GetRefs() >= 1);
+ if (GetRefs() == 1) return;
+
+ union
+ {
+ char buf_[sizeof(Storage)];
+ Align align_;
+ } temp;
+
+ --(*Data().begin()); // decrement the use count of the remaining object
+
+ Storage* p = reinterpret_cast<Storage*>(&temp.buf_[0]);
+ new(buf_) Storage(
+ *new(p) Storage(Data()),
+ flex_string_details::Shallow());
+ *Data().begin() = 1;
+ }
+
+public:
+ CowString(const CowString& s)
+ {
+ if (s.GetRefs() == (std::numeric_limits<RefCountType>::max)())
+ {
+ // must make a brand new copy
+ new(buf_) Storage(s.Data()); // non shallow
+ Refs() = 1;
+ }
+ else
+ {
+ new(buf_) Storage(s.Data(), flex_string_details::Shallow());
+ ++Refs();
+ }
+ BOOST_ASSERT(Data().size() > 0);
+ }
+
+ CowString(const allocator_type& a)
+ {
+ new(buf_) Storage(1, 1, a);
+ }
+
+ CowString(const E* s, size_type len, const allocator_type& a)
+ {
+ // Warning - MSVC's debugger has trouble tracing through the code below.
+ // It seems to be a const-correctness issue
+ //
+ new(buf_) Storage(a);
+ Data().reserve(len + 1);
+ Data().resize(1, 1);
+ Data().append(s, s + len);
+ }
+
+ CowString(size_type len, E c, const allocator_type& a)
+ {
+ new(buf_) Storage(len + 1, c, a);
+ Refs() = 1;
+ }
+
+ CowString& operator=(const CowString& rhs)
+ {
+// CowString(rhs).swap(*this);
+ if (--Refs() == 0)
+ Data().~Storage();
+ if (rhs.GetRefs() == (std::numeric_limits<RefCountType>::max)())
+ {
+ // must make a brand new copy
+ new(buf_) Storage(rhs.Data()); // non shallow
+ Refs() = 1;
+ }
+ else
+ {
+ new(buf_) Storage(rhs.Data(), flex_string_details::Shallow());
+ ++Refs();
+ }
+ BOOST_ASSERT(Data().size() > 0);
+ return *this;
+ }
+
+ ~CowString()
+ {
+ BOOST_ASSERT(Data().size() > 0);
+ if (--Refs() == 0)
+ Data().~Storage();
+ }
+
+ iterator begin()
+ {
+ BOOST_ASSERT(Data().size() > 0);
+ MakeUnique();
+ return Data().begin() + 1;
+ }
+
+ const_iterator begin() const
+ {
+ BOOST_ASSERT(Data().size() > 0);
+ return Data().begin() + 1;
+ }
+
+ iterator end()
+ {
+ MakeUnique();
+ return Data().end();
+ }
+
+ const_iterator end() const
+ {
+ return Data().end();
+ }
+
+ size_type size() const
+ {
+ BOOST_ASSERT(Data().size() > 0);
+ return Data().size() - 1;
+ }
+
+ size_type max_size() const
+ {
+ BOOST_ASSERT(Data().max_size() > 0);
+ return Data().max_size() - 1;
+ }
+
+ size_type capacity() const
+ {
+ BOOST_ASSERT(Data().capacity() > 0);
+ return Data().capacity() - 1;
+ }
+
+ void resize(size_type n, E c)
+ {
+ BOOST_ASSERT(Data().size() > 0);
+ MakeUnique();
+ Data().resize(n + 1, c);
+ }
+
+ template <class FwdIterator>
+ void append(FwdIterator b, FwdIterator e)
+ {
+ MakeUnique();
+ Data().append(b, e);
+ }
+
+ void reserve(size_type res_arg)
+ {
+ if (capacity() > res_arg) return;
+ MakeUnique();
+ Data().reserve(res_arg + 1);
+ }
+
+ void swap(CowString& rhs)
+ {
+ Data().swap(rhs.Data());
+ }
+
+ const E* c_str() const
+ {
+ BOOST_ASSERT(Data().size() > 0);
+ return Data().c_str() + 1;
+ }
+
+ const E* data() const
+ {
+ BOOST_ASSERT(Data().size() > 0);
+ return Data().data() + 1;
+ }
+
+ allocator_type get_allocator() const
+ {
+ return Data().get_allocator();
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// class template flex_string
+// a std::basic_string compatible implementation
+// Uses a Storage policy
+////////////////////////////////////////////////////////////////////////////////
+
+template <typename E,
+ class T = std::char_traits<E>,
+ class A = std::allocator<E>,
+ class Storage = AllocatorStringStorage<E, A> >
+class flex_string : private Storage
+{
+#if defined(BOOST_WAVE_FLEXSTRING_THROW_ON_ENFORCE)
+ template <typename Exception>
+ static void Enforce(bool condition, Exception*, const char* msg)
+ { if (!condition) boost::throw_exception(Exception(msg)); }
+#else
+ template <typename Exception>
+ static inline void Enforce(bool condition, Exception*, const char* msg)
+ { BOOST_ASSERT(condition && msg); }
+#endif // defined(BOOST_WAVE_FLEXSTRING_THROW_ON_ENFORCE)
+
+#ifndef NDEBUG
+ bool Sane() const
+ {
+ return
+ begin() <= end() &&
+ empty() == (size() == 0) &&
+ empty() == (begin() == end()) &&
+ size() <= max_size() &&
+ capacity() <= max_size() &&
+ size() <= capacity();
+ }
+
+ struct Invariant;
+ friend struct Invariant;
+ struct Invariant
+ {
+ Invariant(const flex_string& s) : s_(s)
+ {
+ BOOST_ASSERT(s_.Sane());
+ }
+ ~Invariant()
+ {
+ BOOST_ASSERT(s_.Sane());
+ }
+ private:
+ const flex_string& s_;
+ Invariant& operator=(const Invariant&);
+ };
+#endif
+
+public:
+ // types
+ typedef T traits_type;
+ typedef typename traits_type::char_type value_type;
+ typedef A allocator_type;
+ typedef typename A::size_type size_type;
+ typedef typename A::difference_type difference_type;
+
+ typedef typename A::reference reference;
+ typedef typename A::const_reference const_reference;
+ typedef typename A::pointer pointer;
+ typedef typename A::const_pointer const_pointer;
+
+ typedef typename Storage::iterator iterator;
+ typedef typename Storage::const_iterator const_iterator;
+
+ typedef boost::reverse_iterator<iterator> reverse_iterator;
+ typedef boost::reverse_iterator<const_iterator> const_reverse_iterator;
+
+ static const size_type npos; // = size_type(-1)
+
+private:
+ static size_type Min(size_type lhs, size_type rhs)
+ { return lhs < rhs ? lhs : rhs; }
+ static void Procust(size_type& n, size_type nmax)
+ { if (n > nmax) n = nmax; }
+
+public:
+ // 21.3.1 construct/copy/destroy
+ explicit flex_string(const A& a = A())
+ : Storage(a)
+ {}
+
+ flex_string(const flex_string& str)
+ : Storage(str)
+ {
+ }
+
+ flex_string(const flex_string& str, size_type pos,
+ size_type n = npos, const A& a = A())
+ : Storage(a)
+ {
+ Enforce(pos <= str.size(), (std::out_of_range*)0, "");
+ assign(str, pos, n);
+ }
+
+ flex_string(const value_type* s, const A& a = A())
+ : Storage(s, traits_type::length(s), a)
+ {}
+
+ flex_string(const value_type* s, size_type n, const A& a = A())
+ : Storage(s, n, a)
+ {}
+
+ flex_string(size_type n, value_type c, const A& a = A())
+ : Storage(n, c, a)
+ {}
+
+ template <class InputIterator>
+ flex_string(InputIterator begin, InputIterator end, const A& a = A())
+ : Storage(a)
+ {
+ assign(begin, end);
+ }
+
+ ~flex_string()
+ {}
+
+ flex_string& operator=(const flex_string& str)
+ {
+ if (this != &str) {
+ Storage& s = *this;
+ s = str;
+ }
+ return *this;
+ }
+
+ flex_string& operator=(const value_type* s)
+ {
+ assign(s);
+ return *this;
+ }
+
+ flex_string& operator=(value_type c)
+ {
+ assign(1, c);
+ return *this;
+ }
+
+ // 21.3.2 iterators:
+ iterator begin()
+ { return Storage::begin(); }
+
+ const_iterator begin() const
+ { return Storage::begin(); }
+
+ iterator end()
+ { return Storage::end(); }
+
+ const_iterator end() const
+ { return Storage::end(); }
+
+ reverse_iterator rbegin()
+ { return reverse_iterator(end()); }
+
+ const_reverse_iterator rbegin() const
+ { return const_reverse_iterator(end()); }
+
+ reverse_iterator rend()
+ { return reverse_iterator(begin()); }
+
+ const_reverse_iterator rend() const
+ { return const_reverse_iterator(begin()); }
+
+#if BOOST_WAVE_FLEX_STRING_SERIALIZATION_HACK != 0
+ // temporary hack to make it easier to serialize flex_string's using
+ // the Boost.Serialization library
+ value_type & back() { return *(begin()+size()-1); }
+ value_type const& back() const { return *(begin()+size()-1); }
+#endif
+
+ // 21.3.3 capacity:
+ size_type size() const
+ { return Storage::size(); }
+
+ size_type length() const
+ { return size(); }
+
+ size_type max_size() const
+ { return Storage::max_size(); }
+
+ void resize(size_type n, value_type c)
+ { Storage::resize(n, c); }
+
+ void resize(size_type n)
+ { resize(n, value_type()); }
+
+ size_type capacity() const
+ { return Storage::capacity(); }
+
+ void reserve(size_type res_arg = 0)
+ {
+ Enforce(res_arg <= max_size(), (std::length_error*)0, "");
+ Storage::reserve(res_arg);
+ }
+
+ void clear()
+ { resize(0); }
+
+ bool empty() const
+ { return size() == 0; }
+
+ // 21.3.4 element access:
+ const_reference operator[](size_type pos) const
+ { return *(begin() + pos); }
+
+ reference operator[](size_type pos)
+ { return *(begin() + pos); }
+
+ const_reference at(size_type n) const
+ {
+ Enforce(n < size(), (std::out_of_range*)0, "");
+ return (*this)[n];
+ }
+
+ reference at(size_type n)
+ {
+ Enforce(n < size(), (std::out_of_range*)0, "");
+ return (*this)[n];
+ }
+
+ // 21.3.5 modifiers:
+ flex_string& operator+=(const flex_string& str)
+ { return append(str); }
+
+ flex_string& operator+=(const value_type* s)
+ { return append(s); }
+
+ flex_string& operator+=(value_type c)
+ {
+ push_back(c);
+ return *this;
+ }
+
+ flex_string& append(const flex_string& str)
+ { return append(str, 0, npos); }
+
+ flex_string& append(const flex_string& str, const size_type pos,
+ size_type n)
+ {
+ const size_type sz = str.size();
+ Enforce(pos <= sz, (std::out_of_range*)0, "");
+ Procust(n, sz - pos);
+ return append(str.c_str() + pos, n);
+ }
+
+ flex_string& append(const value_type* s, const size_type n)
+ {
+#ifndef NDEBUG
+ Invariant checker(*this);
+#endif
+ if (IsAliasedRange(s, s + n))
+ {
+ const size_type offset = s - &*begin();
+ Storage::reserve(size() + n);
+ s = &*begin() + offset;
+ }
+ Storage::append(s, s+ n);
+ return *this;
+ }
+
+ flex_string& append(const value_type* s)
+ { return append(s, traits_type::length(s)); }
+
+ flex_string& append(size_type n, value_type c)
+ {
+ resize(size() + n, c);
+ return *this;
+ }
+
+ template<class InputIterator>
+ flex_string& append(InputIterator first, InputIterator last)
+ {
+ insert(end(), first, last);
+ return *this;
+ }
+
+ void push_back(value_type c)
+ {
+ const size_type cap = capacity();
+ if (size() == cap)
+ {
+ reserve(cap << 1u);
+ }
+ Storage::append(&c, &c + 1);
+ }
+
+ flex_string& assign(const flex_string& str)
+ {
+ if (&str == this) return *this;
+ return assign(str.data(), str.size());
+ }
+
+ flex_string& assign(const flex_string& str, size_type pos,
+ size_type n)
+ {
+ const size_type sz = str.size();
+ Enforce(pos <= str.size(), (std::out_of_range*)0, "");
+ Procust(n, sz - pos);
+ return assign(str.data() + pos, n);
+ }
+
+ flex_string& assign(const value_type* s, size_type n)
+ {
+#ifndef NDEBUG
+ Invariant checker(*this);
+#endif
+ if (size() >= n)
+ {
+ std::copy(s, s + n, begin());
+ resize(n);
+ }
+ else
+ {
+ const value_type *const s2 = s + size();
+ std::copy(s, s2, begin());
+ append(s2, n - size());
+ }
+ return *this;
+ }
+
+ flex_string& assign(const value_type* s)
+ { return assign(s, traits_type::length(s)); }
+
+ template <class ItOrLength, class ItOrChar>
+ flex_string& assign(ItOrLength first_or_n, ItOrChar last_or_c)
+ { return replace(begin(), end(), first_or_n, last_or_c); }
+
+ flex_string& insert(size_type pos1, const flex_string& str)
+ { return insert(pos1, str.data(), str.size()); }
+
+ flex_string& insert(size_type pos1, const flex_string& str,
+ size_type pos2, size_type n)
+ {
+ Enforce(pos2 <= str.length(), (std::out_of_range*)0, "");
+ Procust(n, str.length() - pos2);
+ return insert(pos1, str.data() + pos2, n);
+ }
+
+ flex_string& insert(size_type pos, const value_type* s, size_type n)
+ {
+ Enforce(pos <= length(), (std::out_of_range*)0, "");
+ insert(begin() + pos, s, s + n);
+ return *this;
+ }
+
+ flex_string& insert(size_type pos, const value_type* s)
+ { return insert(pos, s, traits_type::length(s)); }
+
+ flex_string& insert(size_type pos, size_type n, value_type c)
+ {
+ Enforce(pos <= length(), (std::out_of_range*)0, "");
+ insert(begin() + pos, n, c);
+ return *this;
+ }
+
+ iterator insert(iterator p, value_type c = value_type())
+ {
+ const size_type pos = p - begin();
+ insert(pos, &c, 1);
+ return begin() + pos;
+ }
+
+private:
+ // Care must be taken when dereferencing some iterator types.
+ //
+ // Users can implement this function in their namespace if their storage
+ // uses a special iterator type, the function will be found through ADL.
+ template<class Iterator>
+ const typename std::iterator_traits<Iterator>::value_type*
+ DereferenceValidIterator(Iterator it) const
+ {
+ return &*it;
+ }
+
+ // Care must be taken when dereferencing a reverse iterators, hence this
+ // special case. This isn't in the std namespace so as not to pollute it or
+ // create name clashes.
+ template<typename Iterator>
+ const typename std::iterator_traits<Iterator>::value_type*
+ DereferenceValidIterator(std::reverse_iterator<Iterator> it) const
+ {
+ return &*--it;
+ }
+
+ // Determine if the range aliases the current string.
+ //
+ // This method cannot be const because calling begin/end on copy-on-write
+ // implementations must have side effects.
+ // A const version wouldn't make the string unique through this call.
+ template<class Iterator>
+ bool IsAliasedRange(Iterator beginIterator, Iterator endIterator)
+ {
+ if(!empty() && beginIterator != endIterator)
+ {
+ typedef const typename std::iterator_traits<Iterator>::value_type *
+ pointer;
+
+ pointer myBegin(&*begin());
+ pointer myEnd(&*begin() + size());
+ pointer rangeBegin(DereferenceValidIterator(beginIterator));
+
+ const std::less_equal<pointer> less_equal = std::less_equal<pointer>();
+ if(less_equal(myBegin, rangeBegin) && less_equal(rangeBegin, myEnd))
+ return true;
+ }
+ return false;
+ }
+
+ template <int i> class Selector {};
+
+ flex_string& InsertImplDiscr(iterator p,
+ size_type n, value_type c, Selector<1>)
+ {
+#ifndef NDEBUG
+ Invariant checker(*this);
+#endif
+ BOOST_ASSERT(begin() <= p && p <= end());
+ const size_type insertOffset(p - begin());
+ const size_type originalSize(size());
+ if(n < originalSize - insertOffset)
+ {
+ // The new characters fit within the original string.
+ // The characters that are pushed back need to be moved because
+ // they're aliased.
+ // The appended characters will all be overwritten by the move.
+ append(n, value_type(0));
+ value_type* begin(&*begin());
+ flex_string_details::pod_move(begin + insertOffset,
+ begin + originalSize, begin + insertOffset + n);
+ std::fill(begin + insertOffset, begin + insertOffset + n, c);
+ }
+ else
+ {
+ // The new characters exceed the original string.
+ // The characters that are pushed back can simply be copied since
+ // they aren't aliased.
+ // The appended characters will partly be overwritten by the copy.
+ append(n, c);
+ value_type* begin(&*begin());
+ flex_string_details::pod_copy(begin + insertOffset,
+ begin + originalSize, begin + insertOffset + n);
+ std::fill(begin + insertOffset, begin + originalSize, c);
+ }
+ return *this;
+ }
+
+ template<class InputIterator>
+ flex_string& InsertImplDiscr(iterator i,
+ InputIterator b, InputIterator e, Selector<0>)
+ {
+ InsertImpl(i, b, e,
+ typename std::iterator_traits<InputIterator>::iterator_category());
+ return *this;
+ }
+
+ template <class FwdIterator>
+ void InsertImpl(iterator i,
+ FwdIterator s1, FwdIterator s2, std::forward_iterator_tag)
+ {
+ if(s1 == s2)
+ {
+ // Insert an empty range.
+ return;
+ }
+
+ if(IsAliasedRange(s1, s2))
+ {
+ // The source range is contained in the current string, copy it
+ // and recurse.
+ const flex_string temporary(s1, s2);
+ InsertImpl(i, temporary.begin(), temporary.end(),
+ typename std::iterator_traits<FwdIterator>::iterator_category());
+ return;
+ }
+
+#ifndef NDEBUG
+ Invariant checker(*this);
+#endif
+ const size_type pos = i - begin();
+ const typename std::iterator_traits<FwdIterator>::difference_type n2 =
+ std::distance(s1, s2);
+
+ BOOST_ASSERT(n2 >= 0);
+ using namespace flex_string_details;
+ BOOST_ASSERT(pos <= size());
+
+ const typename std::iterator_traits<FwdIterator>::difference_type maxn2 =
+ capacity() - size();
+ if (maxn2 < n2)
+ {
+ // Reallocate the string.
+ BOOST_ASSERT(!IsAliasedRange(s1, s2));
+ reserve(size() + n2);
+ i = begin() + pos;
+ }
+ if (pos + n2 <= size())
+ {
+ const iterator tailBegin = end() - n2;
+ Storage::append(tailBegin, tailBegin + n2);
+ std::copy(reverse_iterator(tailBegin), reverse_iterator(i),
+ reverse_iterator(tailBegin + n2));
+ std::copy(s1, s2, i);
+ }
+ else
+ {
+ FwdIterator t = s1;
+ const size_type old_size = size();
+ std::advance(t, old_size - pos);
+ BOOST_ASSERT(std::distance(t, s2) >= 0);
+ Storage::append(t, s2);
+ Storage::append(data() + pos, data() + old_size);
+ std::copy(s1, t, i);
+ }
+ }
+
+ template <class InputIterator>
+ void InsertImpl(iterator insertPosition,
+ InputIterator inputBegin, InputIterator inputEnd,
+ std::input_iterator_tag)
+ {
+ flex_string temporary(begin(), insertPosition);
+ for (; inputBegin != inputEnd; ++inputBegin)
+ {
+ temporary.push_back(*inputBegin);
+ }
+ temporary.append(insertPosition, end());
+ swap(temporary);
+ }
+
+public:
+ template <class ItOrLength, class ItOrChar>
+ void insert(iterator p, ItOrLength first_or_n, ItOrChar last_or_c)
+ {
+ Selector<std::numeric_limits<ItOrLength>::is_specialized> sel;
+ InsertImplDiscr(p, first_or_n, last_or_c, sel);
+ }
+
+ flex_string& erase(size_type pos = 0, size_type n = npos)
+ {
+#ifndef NDEBUG
+ Invariant checker(*this);
+#endif
+ Enforce(pos <= length(), (std::out_of_range*)0, "");
+ Procust(n, length() - pos);
+ std::copy(begin() + pos + n, end(), begin() + pos);
+ resize(length() - n);
+ return *this;
+ }
+
+ iterator erase(iterator position)
+ {
+ const size_type pos(position - begin());
+ erase(pos, 1);
+ return begin() + pos;
+ }
+
+ iterator erase(iterator first, iterator last)
+ {
+ const size_type pos(first - begin());
+ erase(pos, last - first);
+ return begin() + pos;
+ }
+
+ // Replaces at most n1 chars of *this, starting with pos1 with the content of str
+ flex_string& replace(size_type pos1, size_type n1, const flex_string& str)
+ { return replace(pos1, n1, str, 0, npos); }
+
+ // Replaces at most n1 chars of *this, starting with pos1,
+ // with at most n2 chars of str starting with pos2
+ flex_string& replace(size_type pos1, size_type n1, const flex_string& str,
+ size_type pos2, size_type n2)
+ {
+ Enforce(pos2 <= str.length(), (std::out_of_range*)0, "");
+ return replace(pos1, n1, str.data() + pos2,
+ Min(n2, str.size() - pos2));
+ }
+
+ // Replaces at most n1 chars of *this, starting with pos, with chars from s
+ flex_string& replace(size_type pos, size_type n1, const value_type* s)
+ { return replace(pos, n1, s, traits_type::length(s)); }
+
+ // Replaces at most n1 chars of *this, starting with pos, with n2 occurences of c
+ // consolidated with
+ // Replaces at most n1 chars of *this, starting with pos,
+ // with at most n2 chars of str.
+ // str must have at least n2 chars.
+ template <class StrOrLength, class NumOrChar>
+ flex_string& replace(size_type pos, size_type n1,
+ StrOrLength s_or_n2, NumOrChar n_or_c)
+ {
+#ifndef NDEBUG
+ Invariant checker(*this);
+#endif
+ Enforce(pos <= size(), (std::out_of_range*)0, "");
+ Procust(n1, length() - pos);
+ const iterator b = begin() + pos;
+ return replace(b, b + n1, s_or_n2, n_or_c);
+ }
+
+ flex_string& replace(iterator i1, iterator i2, const flex_string& str)
+ { return replace(i1, i2, str.c_str(), str.length()); }
+
+ flex_string& replace(iterator i1, iterator i2, const value_type* s)
+ { return replace(i1, i2, s, traits_type::length(s)); }
+
+private:
+ flex_string& ReplaceImplDiscr(iterator i1, iterator i2,
+ const value_type* s, size_type n, Selector<2>)
+ {
+ BOOST_ASSERT(i1 <= i2);
+ BOOST_ASSERT(begin() <= i1 && i1 <= end());
+ BOOST_ASSERT(begin() <= i2 && i2 <= end());
+ return replace(i1, i2, s, s + n);
+ }
+
+ flex_string& ReplaceImplDiscr(iterator i1, iterator i2,
+ size_type n2, value_type c, Selector<1>)
+ {
+ const size_type n1 = i2 - i1;
+ if (n1 > n2)
+ {
+ std::fill(i1, i1 + n2, c);
+ erase(i1 + n2, i2);
+ }
+ else
+ {
+ std::fill(i1, i2, c);
+ insert(i2, n2 - n1, c);
+ }
+ return *this;
+ }
+
+ template <class InputIterator>
+ flex_string& ReplaceImplDiscr(iterator i1, iterator i2,
+ InputIterator b, InputIterator e, Selector<0>)
+ {
+ ReplaceImpl(i1, i2, b, e,
+ typename std::iterator_traits<InputIterator>::iterator_category());
+ return *this;
+ }
+
+ template <class FwdIterator>
+ void ReplaceImpl(iterator i1, iterator i2,
+ FwdIterator s1, FwdIterator s2, std::forward_iterator_tag)
+ {
+#ifndef NDEBUG
+ Invariant checker(*this);
+#endif
+ const typename std::iterator_traits<iterator>::difference_type n1 =
+ i2 - i1;
+ BOOST_ASSERT(n1 >= 0);
+ const typename std::iterator_traits<FwdIterator>::difference_type n2 =
+ std::distance(s1, s2);
+ BOOST_ASSERT(n2 >= 0);
+
+ if (IsAliasedRange(s1, s2))
+ {
+ // Aliased replace, copy to new string.
+ flex_string temporary;
+ temporary.reserve(size() - n1 + n2);
+ temporary.append(begin(), i1).append(s1, s2).append(i2, end());
+ swap(temporary);
+ return;
+ }
+
+ if (n1 > n2)
+ {
+ // Shrinks
+ std::copy(s1, s2, i1);
+ erase(i1 + n2, i2);
+ }
+ else
+ {
+ // Grows
+ flex_string_details::copy_n(s1, n1, i1);
+ std::advance(s1, n1);
+ insert(i2, s1, s2);
+ }
+ }
+
+ template <class InputIterator>
+ void ReplaceImpl(iterator i1, iterator i2,
+ InputIterator b, InputIterator e, std::input_iterator_tag)
+ {
+ flex_string temp(begin(), i1);
+ temp.append(b, e).append(i2, end());
+ swap(temp);
+ }
+
+public:
+ template <class T1, class T2>
+ flex_string& replace(iterator i1, iterator i2,
+ T1 first_or_n_or_s, T2 last_or_c_or_n)
+ {
+ const bool
+ num1 = std::numeric_limits<T1>::is_specialized,
+ num2 = std::numeric_limits<T2>::is_specialized;
+ return ReplaceImplDiscr(i1, i2, first_or_n_or_s, last_or_c_or_n,
+ Selector<num1 ? (num2 ? 1 : -1) : (num2 ? 2 : 0)>());
+ }
+
+ size_type copy(value_type* s, size_type n, size_type pos = 0) const
+ {
+ Enforce(pos <= size(), (std::out_of_range*)0, "");
+ n = Min(n, size() - pos);
+
+ flex_string_details::pod_copy(
+ &*begin() + pos,
+ &*begin() + pos + n,
+ s);
+ return n;
+ }
+
+ void swap(flex_string& rhs)
+ {
+ Storage& srhs = rhs;
+ this->Storage::swap(srhs);
+ }
+
+ // 21.3.6 string operations:
+ const value_type* c_str() const
+ { return Storage::c_str(); }
+
+ const value_type* data() const
+ { return Storage::data(); }
+
+ allocator_type get_allocator() const
+ { return Storage::get_allocator(); }
+
+ size_type find(const flex_string& str, size_type pos = 0) const
+ { return find(str.data(), pos, str.length()); }
+
+ size_type find (const value_type* s, size_type pos, size_type n) const
+ {
+ const size_type size_(size());
+ if (n + pos > size_)
+ return npos;
+ for (; pos < size_; ++pos)
+ {
+ if (traits_type::compare(&*begin() + pos, s, n) == 0)
+ {
+ return pos;
+ }
+ }
+ return npos;
+ }
+
+ size_type find (const value_type* s, size_type pos = 0) const
+ { return find(s, pos, traits_type::length(s)); }
+
+ size_type find (value_type c, size_type pos = 0) const
+ { return find(&c, pos, 1); }
+
+ size_type rfind(const flex_string& str, size_type pos = npos) const
+ { return rfind(str.c_str(), pos, str.length()); }
+
+ size_type rfind(const value_type* s, size_type pos, size_type n) const
+ {
+ if (n > length()) return npos;
+ pos = Min(pos, length() - n);
+ if (n == 0) return pos;
+
+ const_iterator i(begin() + pos);
+ for (; ; --i)
+ {
+ if (traits_type::eq(*i, *s)
+ && traits_type::compare(&*i, s, n) == 0)
+ {
+ return i - begin();
+ }
+ if (i == begin()) break;
+ }
+ return npos;
+ }
+
+ size_type rfind(const value_type* s, size_type pos = npos) const
+ { return rfind(s, pos, traits_type::length(s)); }
+
+ size_type rfind(value_type c, size_type pos = npos) const
+ { return rfind(&c, pos, 1); }
+
+ size_type find_first_of(const flex_string& str, size_type pos = 0) const
+ { return find_first_of(str.c_str(), pos, str.length()); }
+
+ size_type find_first_of(const value_type* s,
+ size_type pos, size_type n) const
+ {
+ if (pos > length() || n == 0) return npos;
+ const_iterator i(begin() + pos),
+ finish(end());
+ for (; i != finish; ++i)
+ {
+ if (traits_type::find(s, n, *i) != 0)
+ {
+ return i - begin();
+ }
+ }
+ return npos;
+ }
+
+ size_type find_first_of(const value_type* s, size_type pos = 0) const
+ { return find_first_of(s, pos, traits_type::length(s)); }
+
+ size_type find_first_of(value_type c, size_type pos = 0) const
+ { return find_first_of(&c, pos, 1); }
+
+ size_type find_last_of (const flex_string& str,
+ size_type pos = npos) const
+ { return find_last_of(str.c_str(), pos, str.length()); }
+
+ size_type find_last_of (const value_type* s, size_type pos,
+ size_type n) const
+ {
+ if (!empty() && n > 0)
+ {
+ pos = Min(pos, length() - 1);
+ const_iterator i(begin() + pos);
+ for (;; --i)
+ {
+ if (traits_type::find(s, n, *i) != 0)
+ {
+ return i - begin();
+ }
+ if (i == begin()) break;
+ }
+ }
+ return npos;
+ }
+
+ size_type find_last_of (const value_type* s,
+ size_type pos = npos) const
+ { return find_last_of(s, pos, traits_type::length(s)); }
+
+ size_type find_last_of (value_type c, size_type pos = npos) const
+ { return find_last_of(&c, pos, 1); }
+
+ size_type find_first_not_of(const flex_string& str,
+ size_type pos = 0) const
+ { return find_first_not_of(str.data(), pos, str.size()); }
+
+ size_type find_first_not_of(const value_type* s, size_type pos,
+ size_type n) const
+ {
+ if (pos < length())
+ {
+ const_iterator
+ i(begin() + pos),
+ finish(end());
+ for (; i != finish; ++i)
+ {
+ if (traits_type::find(s, n, *i) == 0)
+ {
+ return i - begin();
+ }
+ }
+ }
+ return npos;
+ }
+
+ size_type find_first_not_of(const value_type* s,
+ size_type pos = 0) const
+ { return find_first_not_of(s, pos, traits_type::length(s)); }
+
+ size_type find_first_not_of(value_type c, size_type pos = 0) const
+ { return find_first_not_of(&c, pos, 1); }
+
+ size_type find_last_not_of(const flex_string& str,
+ size_type pos = npos) const
+ { return find_last_not_of(str.c_str(), pos, str.length()); }
+
+ size_type find_last_not_of(const value_type* s, size_type pos,
+ size_type n) const
+ {
+ if (!empty())
+ {
+ pos = Min(pos, size() - 1);
+ const_iterator i(begin() + pos);
+ for (;; --i)
+ {
+ if (traits_type::find(s, n, *i) == 0)
+ {
+ return i - begin();
+ }
+ if (i == begin()) break;
+ }
+ }
+ return npos;
+ }
+
+ size_type find_last_not_of(const value_type* s,
+ size_type pos = npos) const
+ { return find_last_not_of(s, pos, traits_type::length(s)); }
+
+ size_type find_last_not_of (value_type c, size_type pos = npos) const
+ { return find_last_not_of(&c, pos, 1); }
+
+ flex_string substr(size_type pos = 0, size_type n = npos) const
+ {
+ Enforce(pos <= size(), (std::out_of_range*)0, "");
+ return flex_string(data() + pos, Min(n, size() - pos));
+ }
+
+ std::ptrdiff_t compare(const flex_string& str) const
+ {
+ // FIX due to Goncalo N M de Carvalho July 18, 2005
+ return compare(0, size(), str);
+ }
+
+ std::ptrdiff_t compare(size_type pos1, size_type n1,
+ const flex_string& str) const
+ { return compare(pos1, n1, str.data(), str.size()); }
+
+ // FIX to compare: added the TC
+ // (http://www.comeaucomputing.com/iso/lwg-defects.html number 5)
+ // Thanks to Caleb Epstein for the fix
+ std::ptrdiff_t compare(size_type pos1, size_type n1,
+ const value_type* s) const
+ {
+ return compare(pos1, n1, s, traits_type::length(s));
+ }
+
+ std::ptrdiff_t compare(size_type pos1, size_type n1,
+ const value_type* s, size_type n2) const
+ {
+ Enforce(pos1 <= size(), (std::out_of_range*)0, "");
+ Procust(n1, size() - pos1);
+ const int r = traits_type::compare(pos1 + data(), s, Min(n1, n2));
+ return r != 0 ? r : n1 > n2 ? 1 : n1 < n2 ? -1 : 0;
+ }
+
+ std::ptrdiff_t compare(size_type pos1, size_type n1,
+ const flex_string& str,
+ size_type pos2, size_type n2) const
+ {
+ Enforce(pos2 <= str.size(), (std::out_of_range*)0, "");
+ return compare(pos1, n1, str.data() + pos2, Min(n2, str.size() - pos2));
+ }
+
+ std::ptrdiff_t compare(const value_type* s) const
+ {
+ // Could forward to compare(0, size(), s, traits_type::length(s))
+ // but that does two extra checks
+ const size_type n1(size()), n2(traits_type::length(s));
+ const int r = traits_type::compare(data(), s, Min(n1, n2));
+ return r != 0 ? r : n1 > n2 ? 1 : n1 < n2 ? -1 : 0;
+ }
+};
+
+// non-member functions
+template <typename E, class T, class A, class S>
+flex_string<E, T, A, S> operator+(const flex_string<E, T, A, S>& lhs,
+ const flex_string<E, T, A, S>& rhs)
+{
+ flex_string<E, T, A, S> result;
+ result.reserve(lhs.size() + rhs.size());
+ result.append(lhs).append(rhs);
+ return result;
+}
+
+template <typename E, class T, class A, class S>
+flex_string<E, T, A, S> operator+(const typename flex_string<E, T, A, S>::value_type* lhs,
+ const flex_string<E, T, A, S>& rhs)
+{
+ flex_string<E, T, A, S> result;
+ const typename flex_string<E, T, A, S>::size_type len =
+ flex_string<E, T, A, S>::traits_type::length(lhs);
+ result.reserve(len + rhs.size());
+ result.append(lhs, len).append(rhs);
+ return result;
+}
+
+template <typename E, class T, class A, class S>
+flex_string<E, T, A, S> operator+(
+ typename flex_string<E, T, A, S>::value_type lhs,
+ const flex_string<E, T, A, S>& rhs)
+{
+ flex_string<E, T, A, S> result;
+ result.reserve(1 + rhs.size());
+ result.push_back(lhs);
+ result.append(rhs);
+ return result;
+}
+
+template <typename E, class T, class A, class S>
+flex_string<E, T, A, S> operator+(const flex_string<E, T, A, S>& lhs,
+ const typename flex_string<E, T, A, S>::value_type* rhs)
+{
+ typedef typename flex_string<E, T, A, S>::size_type size_type;
+ typedef typename flex_string<E, T, A, S>::traits_type traits_type;
+
+ flex_string<E, T, A, S> result;
+ const size_type len = traits_type::length(rhs);
+ result.reserve(lhs.size() + len);
+ result.append(lhs).append(rhs, len);
+ return result;
+}
+
+template <typename E, class T, class A, class S>
+flex_string<E, T, A, S> operator+(const flex_string<E, T, A, S>& lhs,
+ typename flex_string<E, T, A, S>::value_type rhs)
+{
+ flex_string<E, T, A, S> result;
+ result.reserve(lhs.size() + 1);
+ result.append(lhs);
+ result.push_back(rhs);
+ return result;
+}
+
+template <typename E, class T, class A, class S>
+inline bool operator==(const flex_string<E, T, A, S>& lhs,
+ const flex_string<E, T, A, S>& rhs)
+{ return lhs.compare(rhs) == 0; }
+
+template <typename E, class T, class A, class S>
+inline bool operator==(const typename flex_string<E, T, A, S>::value_type* lhs,
+ const flex_string<E, T, A, S>& rhs)
+{ return rhs == lhs; }
+
+template <typename E, class T, class A, class S>
+inline bool operator==(const flex_string<E, T, A, S>& lhs,
+ const typename flex_string<E, T, A, S>::value_type* rhs)
+{ return lhs.compare(rhs) == 0; }
+
+template <typename E, class T, class A, class S>
+inline bool operator!=(const flex_string<E, T, A, S>& lhs,
+ const flex_string<E, T, A, S>& rhs)
+{ return !(lhs == rhs); }
+
+template <typename E, class T, class A, class S>
+inline bool operator!=(const typename flex_string<E, T, A, S>::value_type* lhs,
+ const flex_string<E, T, A, S>& rhs)
+{ return !(lhs == rhs); }
+
+template <typename E, class T, class A, class S>
+inline bool operator!=(const flex_string<E, T, A, S>& lhs,
+ const typename flex_string<E, T, A, S>::value_type* rhs)
+{ return !(lhs == rhs); }
+
+template <typename E, class T, class A, class S>
+inline bool operator<(const flex_string<E, T, A, S>& lhs,
+ const flex_string<E, T, A, S>& rhs)
+{ return lhs.compare(rhs) < 0; }
+
+template <typename E, class T, class A, class S>
+inline bool operator<(const flex_string<E, T, A, S>& lhs,
+ const typename flex_string<E, T, A, S>::value_type* rhs)
+{ return lhs.compare(rhs) < 0; }
+
+template <typename E, class T, class A, class S>
+inline bool operator<(const typename flex_string<E, T, A, S>::value_type* lhs,
+ const flex_string<E, T, A, S>& rhs)
+{ return rhs.compare(lhs) > 0; }
+
+template <typename E, class T, class A, class S>
+inline bool operator>(const flex_string<E, T, A, S>& lhs,
+ const flex_string<E, T, A, S>& rhs)
+{ return rhs < lhs; }
+
+template <typename E, class T, class A, class S>
+inline bool operator>(const flex_string<E, T, A, S>& lhs,
+ const typename flex_string<E, T, A, S>::value_type* rhs)
+{ return rhs < lhs; }
+
+template <typename E, class T, class A, class S>
+bool operator>(const typename flex_string<E, T, A, S>::value_type* lhs,
+ const flex_string<E, T, A, S>& rhs)
+{ return rhs < lhs; }
+
+template <typename E, class T, class A, class S>
+inline bool operator<=(const flex_string<E, T, A, S>& lhs,
+ const flex_string<E, T, A, S>& rhs)
+{ return !(rhs < lhs); }
+
+template <typename E, class T, class A, class S>
+inline bool operator<=(const flex_string<E, T, A, S>& lhs,
+ const typename flex_string<E, T, A, S>::value_type* rhs)
+{ return !(rhs < lhs); }
+
+template <typename E, class T, class A, class S>
+bool operator<=(const typename flex_string<E, T, A, S>::value_type* lhs,
+ const flex_string<E, T, A, S>& rhs)
+{ return !(rhs < lhs); }
+
+template <typename E, class T, class A, class S>
+bool operator>=(const flex_string<E, T, A, S>& lhs,
+ const flex_string<E, T, A, S>& rhs)
+{ return !(lhs < rhs); }
+
+template <typename E, class T, class A, class S>
+bool operator>=(const flex_string<E, T, A, S>& lhs,
+ const typename flex_string<E, T, A, S>::value_type* rhs)
+{ return !(lhs < rhs); }
+
+template <typename E, class T, class A, class S>
+inline bool operator>=(const typename flex_string<E, T, A, S>::value_type* lhs,
+ const flex_string<E, T, A, S>& rhs)
+{ return !(lhs < rhs); }
+
+template <typename E, class T, class A, class S>
+void swap(flex_string<E, T, A, S>& lhs, flex_string<E, T, A, S>& rhs)
+{
+ // subclause 21.3.7.8:
+ lhs.swap(rhs);
+}
+
+template <typename E, class T, class A, class S>
+inline std::basic_istream<typename flex_string<E, T, A, S>::value_type,
+ typename flex_string<E, T, A, S>::traits_type>&
+operator>>(
+ std::basic_istream<typename flex_string<E, T, A, S>::value_type,
+ typename flex_string<E, T, A, S>::traits_type>& is,
+ flex_string<E, T, A, S>& str);
+
+template <typename E, class T, class A, class S>
+std::basic_ostream<typename flex_string<E, T, A, S>::value_type,
+ typename flex_string<E, T, A, S>::traits_type>&
+operator<<(
+ std::basic_ostream<typename flex_string<E, T, A, S>::value_type,
+ typename flex_string<E, T, A, S>::traits_type>& os,
+ const flex_string<E, T, A, S>& str)
+{ return os << str.c_str(); }
+
+
+// The getline below implementations are from the SGI STL (http://www.sgi.com/tech/stl/)
+// and come with the following copyright:
+//
+// Permission to use, copy, modify, distribute and sell this software and its
+// documentation for any purpose is hereby granted without fee, provided that
+// the below copyright notice appears in all copies and that both the copyright
+// notice and this permission notice appear in supporting documentation. Silicon
+// Graphics makes no representations about the suitability of this software for
+// any purpose. It is provided "as is" without express or implied warranty.
+//
+// Copyright (c) 1997-1999
+// Silicon Graphics Computer Systems, Inc.
+//
+// Copyright (c) 1994
+// Hewlett-Packard Company
+
+template <typename E, class T, class A, class S>
+std::basic_istream<typename flex_string<E, T, A, S>::value_type,
+ typename flex_string<E, T, A, S>::traits_type>&
+getline(
+ std::basic_istream<typename flex_string<E, T, A, S>::value_type,
+ typename flex_string<E, T, A, S>::traits_type>& is,
+ flex_string<E, T, A, S>& str,
+ typename flex_string<E, T, A, S>::value_type delim)
+{
+ size_t nread = 0;
+ typename std::basic_istream<typename flex_string<E, T, A, S>::value_type,
+ typename flex_string<E, T, A, S>::traits_type>::sentry sentry(is, true);
+
+ if (sentry) {
+ std::basic_streambuf<typename flex_string<E, T, A, S>::value_type,
+ typename flex_string<E, T, A, S>::traits_type>* buf = is.rdbuf();
+ str.clear();
+
+ while (nread < str.max_size()) {
+ int c1 = buf->sbumpc();
+ if (flex_string<E, T, A, S>::traits_type::eq_int_type(c1,
+ flex_string<E, T, A, S>::traits_type::eof()))
+ {
+ is.setstate(std::ios_base::eofbit);
+ break;
+ }
+ else {
+ ++nread;
+ typename flex_string<E, T, A, S>::value_type c =
+ flex_string<E, T, A, S>::traits_type::to_char_type(c1);
+
+ if (!flex_string<E, T, A, S>::traits_type::eq(c, delim))
+ str.push_back(c);
+ else
+ break; // Character is extracted but not appended.
+ }
+ }
+ }
+ if (nread == 0 || nread >= str.max_size())
+ is.setstate(std::ios_base::failbit);
+
+ return is;
+}
+
+template <typename E, class T, class A, class S>
+std::basic_istream<typename flex_string<E, T, A, S>::value_type,
+ typename flex_string<E, T, A, S>::traits_type>&
+getline(
+ std::basic_istream<typename flex_string<E, T, A, S>::value_type,
+ typename flex_string<E, T, A, S>::traits_type>& is,
+ flex_string<E, T, A, S>& str)
+{
+ return getline(is, str, is.widen('\n'));
+}
+
+template <typename E1, class T, class A, class S>
+const typename flex_string<E1, T, A, S>::size_type
+flex_string<E1, T, A, S>::npos = (typename flex_string<E1, T, A, S>::size_type)(-1);
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace util
+} // namespace wave
+} // namespace boost
+
+#if BOOST_WAVE_SERIALIZATION != 0
+///////////////////////////////////////////////////////////////////////////////
+namespace boost { namespace serialization {
+
+#if !defined(BOOST_WAVE_FLEX_STRING_SERIALIZATION_HACK)
+
+// FIXME: This doesn't work because of the missing flex_string::operator>>()
+template <typename E, class T, class A, class S>
+struct implementation_level<boost::wave::util::flex_string<E, T, A, S> >
+{
+ typedef mpl::integral_c_tag tag;
+ typedef mpl::int_<boost::serialization::primitive_type> type;
+ BOOST_STATIC_CONSTANT(
+ int,
+ value = implementation_level::type::value
+ );
+};
+
+#else
+
+// We serialize flex_strings as vectors of char's for now
+template<class Archive, typename E, class T, class A, class S>
+inline void save(Archive & ar,
+ boost::wave::util::flex_string<E, T, A, S> const &t,
+ const unsigned int file_version)
+{
+ boost::serialization::stl::save_collection<
+ Archive, wave::util::flex_string<E, T, A, S> >(ar, t);
+}
+
+template<class Archive, typename E, class T, class A, class S>
+inline void load(Archive & ar, boost::wave::util::flex_string<E, T, A, S> &t,
+ const unsigned int file_version)
+{
+ boost::serialization::stl::load_collection<
+ Archive, boost::wave::util::flex_string<E, T, A, S>,
+ boost::serialization::stl::archive_input_seq<
+ Archive, boost::wave::util::flex_string<E, T, A, S> >,
+ boost::serialization::stl::reserve_imp<
+ boost::wave::util::flex_string<E, T, A, S> >
+ >(ar, t);
+}
+
+// split non-intrusive serialization function member into separate
+// non intrusive save/load member functions
+template<class Archive, typename E, class T, class A, class S>
+inline void serialize(Archive & ar, boost::wave::util::flex_string<E, T, A, S> &t,
+ const unsigned int file_version)
+{
+ boost::serialization::split_free(ar, t, file_version);
+}
+
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+}} // boost::serialization
+#endif
+
+// the suffix header occurs after all of the code
+#ifdef BOOST_HAS_ABI_HEADERS
+#include BOOST_ABI_SUFFIX
+#endif
+
+#endif // FLEX_STRING_INC_
diff --git a/boost/wave/util/functor_input.hpp b/boost/wave/util/functor_input.hpp
new file mode 100644
index 0000000000..d30a090a1a
--- /dev/null
+++ b/boost/wave/util/functor_input.hpp
@@ -0,0 +1,155 @@
+/*=============================================================================
+ 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(FUNCTOR_INPUT_HPP_ED3A4C21_8F8A_453F_B438_08214FAC106A_INCLUDED)
+#define FUNCTOR_INPUT_HPP_ED3A4C21_8F8A_453F_B438_08214FAC106A_INCLUDED
+
+#include <boost/assert.hpp>
+#include <boost/spirit/include/classic_multi_pass.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
+
+///////////////////////////////////////////////////////////////////////////////
+namespace boost {
+namespace wave {
+namespace util {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// class functor_input
+//
+// Implementation of the InputPolicy used by multi_pass
+// functor_input gets tokens from a functor
+// Note: the functor must have a typedef for result_type
+// It also must have a static variable of type result_type defined
+// to represent eof that is called eof.
+//
+// This functor input policy template is essentially the same as the
+// predefined multi_pass functor_input policy. The difference is,
+// that the first token is not read at initialization time, but only
+// just before returning the first token. Additionally it does not
+// call operator new() twice but only once.
+//
+///////////////////////////////////////////////////////////////////////////////
+struct functor_input {
+
+ template <typename FunctorT>
+ class inner {
+ private:
+ typedef typename FunctorT::result_type result_type;
+
+ public:
+ typedef result_type value_type;
+
+ private:
+ struct Data {
+ Data(FunctorT const &ftor_)
+ : ftor(ftor_), was_initialized(false)
+ {}
+
+ FunctorT ftor;
+ value_type curtok;
+ bool was_initialized;
+ };
+
+ // Needed by compilers not implementing the resolution to DR45. For
+ // reference, see
+ // http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#45.
+
+ friend struct Data;
+
+ public:
+ typedef std::ptrdiff_t difference_type;
+ typedef result_type *pointer;
+ typedef result_type &reference;
+
+ protected:
+ inner()
+ : data(0)
+ {}
+
+ inner(FunctorT const &x)
+ : data(new Data(x))
+ {}
+
+ inner(inner const &x)
+ : data(x.data)
+ {}
+
+ void destroy()
+ {
+ delete data;
+ data = 0;
+ }
+
+ bool same_input(inner const &x) const
+ {
+ return data == x.data;
+ }
+
+ void swap(inner &x)
+ {
+ boost::spirit::classic::impl::mp_swap(data, x.data);
+ }
+
+ void ensure_initialized() const
+ {
+ if (data && !data->was_initialized) {
+ data->curtok = (data->ftor)(); // get the first token
+ data->was_initialized = true;
+ }
+ }
+
+ public:
+ reference get_input() const
+ {
+ ensure_initialized();
+ return data->curtok;
+ }
+
+ void advance_input()
+ {
+ BOOST_ASSERT(0 != data);
+ data->curtok = (data->ftor)();
+ data->was_initialized = true;
+ }
+
+ bool input_at_eof() const
+ {
+ ensure_initialized();
+ return !data || data->curtok == data->ftor.eof;
+ }
+
+ FunctorT& get_functor() const
+ {
+ BOOST_ASSERT(0 != data);
+ return data->ftor;
+ }
+
+ private:
+ mutable Data *data;
+ };
+};
+
+///////////////////////////////////////////////////////////////////////////////
+} // 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(FUNCTOR_INPUT_HPP_ED3A4C21_8F8A_453F_B438_08214FAC106A_INCLUDED)
diff --git a/boost/wave/util/insert_whitespace_detection.hpp b/boost/wave/util/insert_whitespace_detection.hpp
new file mode 100644
index 0000000000..8485e9c1d1
--- /dev/null
+++ b/boost/wave/util/insert_whitespace_detection.hpp
@@ -0,0 +1,518 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ Detect the need to insert a whitespace token into the output stream
+
+ 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(INSERT_WHITESPACE_DETECTION_HPP_765EF77B_0513_4967_BDD6_6A38148C4C96_INCLUDED)
+#define INSERT_WHITESPACE_DETECTION_HPP_765EF77B_0513_4967_BDD6_6A38148C4C96_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 util {
+
+namespace impl {
+
+// T_IDENTIFIER
+ template <typename StringT>
+ inline bool
+ would_form_universal_char (StringT const &value)
+ {
+ if ('u' != value[0] && 'U' != value[0])
+ return false;
+ if ('u' == value[0] && value.size() < 5)
+ return false;
+ if ('U' == value[0] && value.size() < 9)
+ return false;
+
+ typename StringT::size_type pos =
+ value.find_first_not_of("0123456789abcdefABCDEF", 1);
+
+ if (StringT::npos == pos ||
+ ('u' == value[0] && pos > 5) ||
+ ('U' == value[0] && pos > 9))
+ {
+ return true; // would form an universal char
+ }
+ return false;
+ }
+ template <typename StringT>
+ inline bool
+ handle_identifier(boost::wave::token_id prev,
+ boost::wave::token_id before, StringT const &value)
+ {
+ using namespace boost::wave;
+ switch (static_cast<unsigned int>(prev)) {
+ case T_IDENTIFIER:
+ case T_NONREPLACABLE_IDENTIFIER:
+ case T_COMPL_ALT:
+ case T_OR_ALT:
+ case T_AND_ALT:
+ case T_NOT_ALT:
+ case T_XOR_ALT:
+ case T_ANDASSIGN_ALT:
+ case T_ORASSIGN_ALT:
+ case T_XORASSIGN_ALT:
+ case T_NOTEQUAL_ALT:
+ case T_FIXEDPOINTLIT:
+ return true;
+
+ case T_FLOATLIT:
+ case T_INTLIT:
+ case T_PP_NUMBER:
+ return (value.size() > 1 || (value[0] != 'e' && value[0] != 'E'));
+
+ // avoid constructing universal characters (\u1234)
+ case TOKEN_FROM_ID('\\', UnknownTokenType):
+ return would_form_universal_char(value);
+ }
+ return false;
+ }
+// T_INTLIT
+ inline bool
+ handle_intlit(boost::wave::token_id prev, boost::wave::token_id /*before*/)
+ {
+ using namespace boost::wave;
+ switch (static_cast<unsigned int>(prev)) {
+ case T_IDENTIFIER:
+ case T_NONREPLACABLE_IDENTIFIER:
+ case T_INTLIT:
+ case T_FLOATLIT:
+ case T_FIXEDPOINTLIT:
+ case T_PP_NUMBER:
+ return true;
+ }
+ return false;
+ }
+// T_FLOATLIT
+ inline bool
+ handle_floatlit(boost::wave::token_id prev,
+ boost::wave::token_id /*before*/)
+ {
+ using namespace boost::wave;
+ switch (static_cast<unsigned int>(prev)) {
+ case T_IDENTIFIER:
+ case T_NONREPLACABLE_IDENTIFIER:
+ case T_INTLIT:
+ case T_FLOATLIT:
+ case T_FIXEDPOINTLIT:
+ case T_PP_NUMBER:
+ return true;
+ }
+ return false;
+ }
+// <% T_LEFTBRACE
+ inline bool
+ handle_alt_leftbrace(boost::wave::token_id prev,
+ boost::wave::token_id /*before*/)
+ {
+ using namespace boost::wave;
+ switch (static_cast<unsigned int>(prev)) {
+ case T_LESS: // <<%
+ case T_SHIFTLEFT: // <<<%
+ return true;
+ }
+ return false;
+ }
+// <: T_LEFTBRACKET
+ inline bool
+ handle_alt_leftbracket(boost::wave::token_id prev,
+ boost::wave::token_id /*before*/)
+ {
+ using namespace boost::wave;
+ switch (static_cast<unsigned int>(prev)) {
+ case T_LESS: // <<:
+ case T_SHIFTLEFT: // <<<:
+ return true;
+ }
+ return false;
+ }
+// T_FIXEDPOINTLIT
+ inline bool
+ handle_fixedpointlit(boost::wave::token_id prev,
+ boost::wave::token_id /*before*/)
+ {
+ using namespace boost::wave;
+ switch (static_cast<unsigned int>(prev)) {
+ case T_IDENTIFIER:
+ case T_NONREPLACABLE_IDENTIFIER:
+ case T_INTLIT:
+ case T_FLOATLIT:
+ case T_FIXEDPOINTLIT:
+ case T_PP_NUMBER:
+ return true;
+ }
+ return false;
+ }
+// T_DOT
+ inline bool
+ handle_dot(boost::wave::token_id prev, boost::wave::token_id before)
+ {
+ using namespace boost::wave;
+ switch (static_cast<unsigned int>(prev)) {
+ case T_DOT:
+ if (T_DOT == before)
+ return true; // ...
+ break;
+ }
+ return false;
+ }
+// T_QUESTION_MARK
+ inline bool
+ handle_questionmark(boost::wave::token_id prev,
+ boost::wave::token_id /*before*/)
+ {
+ using namespace boost::wave;
+ switch(static_cast<unsigned int>(prev)) {
+ case TOKEN_FROM_ID('\\', UnknownTokenType): // \?
+ case T_QUESTION_MARK: // ??
+ return true;
+ }
+ return false;
+ }
+// T_NEWLINE
+ inline bool
+ handle_newline(boost::wave::token_id prev,
+ boost::wave::token_id before)
+ {
+ using namespace boost::wave;
+ switch(static_cast<unsigned int>(prev)) {
+ case TOKEN_FROM_ID('\\', UnknownTokenType): // \ \n
+ case T_DIVIDE:
+ if (T_QUESTION_MARK == before)
+ return true; // ?/\n // may be \\n
+ break;
+ }
+ return false;
+ }
+
+ inline bool
+ handle_parens(boost::wave::token_id prev)
+ {
+ switch (static_cast<unsigned int>(prev)) {
+ case T_LEFTPAREN:
+ case T_RIGHTPAREN:
+ case T_LEFTBRACKET:
+ case T_RIGHTBRACKET:
+ case T_LEFTBRACE:
+ case T_RIGHTBRACE:
+ case T_SEMICOLON:
+ case T_COMMA:
+ case T_COLON:
+ // no insertion between parens/brackets/braces and operators
+ return false;
+
+ default:
+ break;
+ }
+ return true;
+ }
+
+} // namespace impl
+
+class insert_whitespace_detection
+{
+public:
+ insert_whitespace_detection(bool insert_whitespace_ = true)
+ : insert_whitespace(insert_whitespace_),
+ prev(boost::wave::T_EOF), beforeprev(boost::wave::T_EOF)
+ {}
+
+ template <typename StringT>
+ bool must_insert(boost::wave::token_id current, StringT const &value)
+ {
+ if (!insert_whitespace)
+ return false; // skip whitespace insertion alltogether
+
+ using namespace boost::wave;
+ switch (static_cast<unsigned int>(current)) {
+ case T_NONREPLACABLE_IDENTIFIER:
+ case T_IDENTIFIER:
+ return impl::handle_identifier(prev, beforeprev, value);
+ case T_PP_NUMBER:
+ case T_INTLIT:
+ return impl::handle_intlit(prev, beforeprev);
+ case T_FLOATLIT:
+ return impl::handle_floatlit(prev, beforeprev);
+ case T_STRINGLIT:
+ if (TOKEN_FROM_ID('L', IdentifierTokenType) == prev) // 'L'
+ return true;
+ break;
+ case T_LEFTBRACE_ALT:
+ return impl::handle_alt_leftbrace(prev, beforeprev);
+ case T_LEFTBRACKET_ALT:
+ return impl::handle_alt_leftbracket(prev, beforeprev);
+ case T_FIXEDPOINTLIT:
+ return impl::handle_fixedpointlit(prev, beforeprev);
+ case T_DOT:
+ return impl::handle_dot(prev, beforeprev);
+ case T_QUESTION_MARK:
+ return impl::handle_questionmark(prev, beforeprev);
+ case T_NEWLINE:
+ return impl::handle_newline(prev, beforeprev);
+
+ case T_LEFTPAREN:
+ case T_RIGHTPAREN:
+ case T_LEFTBRACKET:
+ case T_RIGHTBRACKET:
+ case T_SEMICOLON:
+ case T_COMMA:
+ case T_COLON:
+ switch (static_cast<unsigned int>(prev)) {
+ case T_LEFTPAREN:
+ case T_RIGHTPAREN:
+ case T_LEFTBRACKET:
+ case T_RIGHTBRACKET:
+ case T_LEFTBRACE:
+ case T_RIGHTBRACE:
+ return false; // no insertion between parens/brackets/braces
+
+ default:
+ if (IS_CATEGORY(prev, OperatorTokenType))
+ return false;
+ break;
+ }
+ break;
+
+ case T_LEFTBRACE:
+ case T_RIGHTBRACE:
+ switch (static_cast<unsigned int>(prev)) {
+ case T_LEFTPAREN:
+ case T_RIGHTPAREN:
+ case T_LEFTBRACKET:
+ case T_RIGHTBRACKET:
+ case T_LEFTBRACE:
+ case T_RIGHTBRACE:
+ case T_SEMICOLON:
+ case T_COMMA:
+ case T_COLON:
+ return false; // no insertion between parens/brackets/braces
+
+ case T_QUESTION_MARK:
+ if (T_QUESTION_MARK == beforeprev)
+ return true;
+ if (IS_CATEGORY(prev, OperatorTokenType))
+ return false;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case T_MINUS:
+ case T_MINUSMINUS:
+ case T_MINUSASSIGN:
+ if (T_MINUS == prev || T_MINUSMINUS == prev)
+ return true;
+ if (!impl::handle_parens(prev))
+ return false;
+ if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev)
+ return true;
+ break;
+
+ case T_PLUS:
+ case T_PLUSPLUS:
+ case T_PLUSASSIGN:
+ if (T_PLUS == prev || T_PLUSPLUS == prev)
+ return true;
+ if (!impl::handle_parens(prev))
+ return false;
+ if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev)
+ return true;
+ break;
+
+ case T_DIVIDE:
+ case T_DIVIDEASSIGN:
+ if (T_DIVIDE == prev)
+ return true;
+ if (!impl::handle_parens(prev))
+ return false;
+ if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev)
+ return true;
+ break;
+
+ case T_EQUAL:
+ case T_ASSIGN:
+ switch (static_cast<unsigned int>(prev)) {
+ case T_PLUSASSIGN:
+ case T_MINUSASSIGN:
+ case T_DIVIDEASSIGN:
+ case T_STARASSIGN:
+ case T_SHIFTRIGHTASSIGN:
+ case T_SHIFTLEFTASSIGN:
+ case T_EQUAL:
+ case T_NOTEQUAL:
+ case T_LESSEQUAL:
+ case T_GREATEREQUAL:
+ case T_LESS:
+ case T_GREATER:
+ case T_PLUS:
+ case T_MINUS:
+ case T_STAR:
+ case T_DIVIDE:
+ case T_ORASSIGN:
+ case T_ANDASSIGN:
+ case T_XORASSIGN:
+ case T_OR:
+ case T_AND:
+ case T_XOR:
+ case T_OROR:
+ case T_ANDAND:
+ return true;
+
+ case T_QUESTION_MARK:
+ if (T_QUESTION_MARK == beforeprev)
+ return true;
+ break;
+
+ default:
+ if (!impl::handle_parens(prev))
+ return false;
+ break;
+ }
+ break;
+
+ case T_GREATER:
+ if (T_MINUS == prev || T_GREATER == prev)
+ return true; // prevent -> or >>
+ if (!impl::handle_parens(prev))
+ return false;
+ if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev)
+ return true;
+ break;
+
+ case T_LESS:
+ if (T_LESS == prev)
+ return true; // prevent <<
+ // fall through
+ case T_CHARLIT:
+ case T_NOT:
+ case T_NOTEQUAL:
+ if (!impl::handle_parens(prev))
+ return false;
+ if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev)
+ return true;
+ break;
+
+ case T_AND:
+ case T_ANDAND:
+ if (!impl::handle_parens(prev))
+ return false;
+ if (T_AND == prev || T_ANDAND == prev)
+ return true;
+ break;
+
+ case T_OR:
+ if (!impl::handle_parens(prev))
+ return false;
+ if (T_OR == prev)
+ return true;
+ break;
+
+ case T_XOR:
+ if (!impl::handle_parens(prev))
+ return false;
+ if (T_XOR == prev)
+ return true;
+ break;
+
+ case T_COMPL_ALT:
+ case T_OR_ALT:
+ case T_AND_ALT:
+ case T_NOT_ALT:
+ case T_XOR_ALT:
+ case T_ANDASSIGN_ALT:
+ case T_ORASSIGN_ALT:
+ case T_XORASSIGN_ALT:
+ case T_NOTEQUAL_ALT:
+ switch (static_cast<unsigned int>(prev)) {
+ case T_LEFTPAREN:
+ case T_RIGHTPAREN:
+ case T_LEFTBRACKET:
+ case T_RIGHTBRACKET:
+ case T_LEFTBRACE:
+ case T_RIGHTBRACE:
+ case T_SEMICOLON:
+ case T_COMMA:
+ case T_COLON:
+ // no insertion between parens/brackets/braces and operators
+ return false;
+
+ case T_IDENTIFIER:
+ if (T_NONREPLACABLE_IDENTIFIER == prev ||
+ IS_CATEGORY(prev, KeywordTokenType))
+ {
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case T_STAR:
+ if (T_STAR == prev)
+ return false; // '*****' do not need to be separated
+ if (T_GREATER== prev &&
+ (T_MINUS == beforeprev || T_MINUSMINUS == beforeprev)
+ )
+ {
+ return true; // prevent ->*
+ }
+ break;
+
+ case T_POUND:
+ if (T_POUND == prev)
+ return true;
+ break;
+ }
+
+ // FIXME: else, handle operators separately (will catch to many cases)
+// if (IS_CATEGORY(current, OperatorTokenType) &&
+// IS_CATEGORY(prev, OperatorTokenType))
+// {
+// return true; // operators must be delimited always
+// }
+ return false;
+ }
+ void shift_tokens (boost::wave::token_id next_id)
+ {
+ if (insert_whitespace) {
+ beforeprev = prev;
+ prev = next_id;
+ }
+ }
+
+private:
+ bool insert_whitespace; // enable this component
+ boost::wave::token_id prev; // the previous analyzed token
+ boost::wave::token_id beforeprev; // the token before the previous
+};
+
+///////////////////////////////////////////////////////////////////////////////
+} // 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(INSERT_WHITESPACE_DETECTION_HPP_765EF77B_0513_4967_BDD6_6A38148C4C96_INCLUDED)
diff --git a/boost/wave/util/interpret_pragma.hpp b/boost/wave/util/interpret_pragma.hpp
new file mode 100644
index 0000000000..e787040b1a
--- /dev/null
+++ b/boost/wave/util/interpret_pragma.hpp
@@ -0,0 +1,210 @@
+/*=============================================================================
+ 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(INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED)
+#define INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED
+
+#include <string>
+#include <list>
+
+#include <boost/spirit/include/classic_core.hpp>
+#include <boost/spirit/include/classic_assign_actor.hpp>
+#include <boost/spirit/include/classic_push_back_actor.hpp>
+#include <boost/spirit/include/classic_confix.hpp>
+
+#include <boost/wave/wave_config.hpp>
+
+#include <boost/wave/util/pattern_parser.hpp>
+#include <boost/wave/util/macro_helpers.hpp>
+
+#include <boost/wave/token_ids.hpp>
+#include <boost/wave/cpp_exceptions.hpp>
+#include <boost/wave/cpp_iteration_context.hpp>
+#include <boost/wave/language_support.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 util {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// The function interpret_pragma interprets the given token sequence as the
+// body of a #pragma directive (or parameter to the _Pragma operator) and
+// executes the actions associated with recognized Wave specific options.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename ContextT, typename IteratorT, typename ContainerT>
+inline bool
+interpret_pragma(ContextT &ctx, typename ContextT::token_type const &act_token,
+ IteratorT it, IteratorT const &end, ContainerT &pending)
+{
+ typedef typename ContextT::token_type token_type;
+ typedef typename token_type::string_type string_type;
+
+ using namespace cpplexer;
+ if (T_IDENTIFIER == token_id(*it)) {
+ // check for pragma wave ...
+ if ((*it).get_value() == BOOST_WAVE_PRAGMA_KEYWORD)
+ {
+ // this is a wave specific option, it should have the form:
+ //
+ // #pragma command option(value)
+ //
+ // where
+ // 'command' is the value of the preprocessor constant
+ // BOOST_WAVE_PRAGMA_KEYWORD (defaults to "wave") and
+ // '(value)' is required only for some pragma directives (this is
+ // optional)
+ //
+ // All recognized #pragma operators are forwarded to the supplied
+ // preprocessing hook.
+ using namespace boost::spirit::classic;
+ token_type option;
+ ContainerT values;
+
+ if (!parse (++it, end,
+ ( ch_p(T_IDENTIFIER)
+ [
+ spirit_assign_actor(option)
+ ]
+ | pattern_p(KeywordTokenType,
+ TokenTypeMask|PPTokenFlag)
+ [
+ spirit_assign_actor(option)
+ ]
+ | pattern_p(OperatorTokenType|AltExtTokenType,
+ ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc.
+ [
+ spirit_assign_actor(option)
+ ]
+ | pattern_p(BoolLiteralTokenType,
+ TokenTypeMask|PPTokenFlag)
+ [
+ spirit_assign_actor(option)
+ ]
+ )
+ >> !comment_nest_p(
+ ch_p(T_LEFTPAREN),
+ ch_p(T_RIGHTPAREN)
+ )[spirit_assign_actor(values)],
+ pattern_p(WhiteSpaceTokenType, TokenTypeMask|PPTokenFlag)).hit)
+ {
+ typename ContextT::string_type msg(
+ impl::as_string<string_type>(it, end));
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ ill_formed_pragma_option,
+ msg.c_str(), act_token.get_position());
+ return false;
+ }
+
+ // remove the falsely matched surrounding parenthesis's
+ if (values.size() >= 2) {
+ BOOST_ASSERT(T_LEFTPAREN == values.front() && T_RIGHTPAREN == values.back());
+ values.erase(values.begin());
+ typename ContainerT::reverse_iterator rit = values.rbegin();
+ values.erase((++rit).base());
+ }
+
+ // decode the option (call the context_policy hook)
+ if (!ctx.get_hooks().interpret_pragma(
+ ctx.derived(), pending, option, values, act_token))
+ {
+ // unknown #pragma option
+ string_type option_str ((*it).get_value());
+
+ option_str += option.get_value();
+ if (values.size() > 0) {
+ option_str += "(";
+ option_str += impl::as_string(values);
+ option_str += ")";
+ }
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ ill_formed_pragma_option,
+ option_str.c_str(), act_token.get_position());
+ return false;
+ }
+ return true;
+ }
+#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
+ else if ((*it).get_value() == "once") {
+ // #pragma once
+ return ctx.add_pragma_once_header(act_token, ctx.get_current_filename());
+ }
+#endif
+#if BOOST_WAVE_SUPPORT_PRAGMA_MESSAGE != 0
+ else if ((*it).get_value() == "message") {
+ // #pragma message(...) or #pragma message ...
+ using namespace boost::spirit::classic;
+ ContainerT values;
+
+ if (!parse (++it, end,
+ ( ( ch_p(T_LEFTPAREN)
+ >> lexeme_d[
+ *(anychar_p[spirit_append_actor(values)] - ch_p(T_RIGHTPAREN))
+ ]
+ >> ch_p(T_RIGHTPAREN)
+ )
+ | lexeme_d[
+ *(anychar_p[spirit_append_actor(values)] - ch_p(T_NEWLINE))
+ ]
+ ),
+ pattern_p(WhiteSpaceTokenType, TokenTypeMask|PPTokenFlag)
+ ).hit
+ )
+ {
+ typename ContextT::string_type msg(
+ impl::as_string<string_type>(it, end));
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ ill_formed_pragma_message,
+ msg.c_str(), act_token.get_position());
+ return false;
+ }
+
+ // remove the falsely matched closing parenthesis/newline
+ if (values.size() > 0) {
+ BOOST_ASSERT(T_RIGHTPAREN == values.back() || T_NEWLINE == values.back());
+ typename ContainerT::reverse_iterator rit = values.rbegin();
+ values.erase((++rit).base());
+ }
+
+ // output the message itself
+ typename ContextT::string_type msg(impl::as_string(values));
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ pragma_message_directive,
+ msg.c_str(), act_token.get_position());
+ return false;
+ }
+#endif
+ }
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+} // 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(INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED)
diff --git a/boost/wave/util/iteration_context.hpp b/boost/wave/util/iteration_context.hpp
new file mode 100644
index 0000000000..8673f46639
--- /dev/null
+++ b/boost/wave/util/iteration_context.hpp
@@ -0,0 +1,83 @@
+/*=============================================================================
+ 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(ITERATION_CONTEXT_HPP_9556CD16_F11E_4ADC_AC8B_FB9A174BE664_INCLUDED)
+#define ITERATION_CONTEXT_HPP_9556CD16_F11E_4ADC_AC8B_FB9A174BE664_INCLUDED
+
+#include <cstdlib>
+#include <cstdio>
+#include <stack>
+
+#include <boost/wave/wave_config.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 util {
+
+///////////////////////////////////////////////////////////////////////////////
+template <typename IterationContextT>
+class iteration_context_stack
+{
+ typedef std::stack<IterationContextT> base_type;
+
+public:
+ typedef typename base_type::size_type size_type;
+
+ iteration_context_stack()
+ : max_include_nesting_depth(BOOST_WAVE_MAX_INCLUDE_LEVEL_DEPTH)
+ {}
+
+ void set_max_include_nesting_depth(size_type new_depth)
+ { max_include_nesting_depth = new_depth; }
+ size_type get_max_include_nesting_depth() const
+ { return max_include_nesting_depth; }
+
+ typename base_type::size_type size() const { return iter_ctx.size(); }
+ typename base_type::value_type &top() { return iter_ctx.top(); }
+ void pop() { iter_ctx.pop(); }
+
+ template <typename Context, typename PositionT>
+ void push(Context& ctx, PositionT const &pos,
+ typename base_type::value_type const &val)
+ {
+ if (iter_ctx.size() == max_include_nesting_depth) {
+ 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)max_include_nesting_depth);
+ BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
+ include_nesting_too_deep, buffer, pos);
+ }
+ iter_ctx.push(val);
+ }
+
+private:
+ size_type max_include_nesting_depth;
+ base_type iter_ctx;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+} // 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(ITERATION_CONTEXT_HPP_9556CD16_F11E_4ADC_AC8B_FB9A174BE664_INCLUDED)
diff --git a/boost/wave/util/macro_definition.hpp b/boost/wave/util/macro_definition.hpp
new file mode 100644
index 0000000000..16be858704
--- /dev/null
+++ b/boost/wave/util/macro_definition.hpp
@@ -0,0 +1,200 @@
+/*=============================================================================
+ 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(MACRO_DEFINITION_HPP_D68A639E_2DA5_4E9C_8ACD_CFE6B903831E_INCLUDED)
+#define MACRO_DEFINITION_HPP_D68A639E_2DA5_4E9C_8ACD_CFE6B903831E_INCLUDED
+
+#include <vector>
+#include <list>
+
+#include <boost/detail/atomic_count.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+#include <boost/wave/wave_config.hpp>
+#if BOOST_WAVE_SERIALIZATION != 0
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/list.hpp>
+#include <boost/serialization/vector.hpp>
+#endif
+
+#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 util {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// macro_definition
+//
+// This class containes all infos for a defined macro.
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename TokenT, typename ContainerT>
+struct macro_definition {
+
+ typedef std::vector<TokenT> parameter_container_type;
+ typedef ContainerT definition_container_type;
+
+ typedef typename parameter_container_type::const_iterator
+ const_parameter_iterator_t;
+ typedef typename definition_container_type::const_iterator
+ const_definition_iterator_t;
+
+ macro_definition(TokenT const &token_, bool has_parameters,
+ bool is_predefined_, long uid_)
+ : macroname(token_), uid(uid_), is_functionlike(has_parameters),
+ replaced_parameters(false), is_available_for_replacement(true),
+ is_predefined(is_predefined_)
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ , has_ellipsis(false)
+#endif
+ , use_count(0)
+ {
+ }
+ // generated copy constructor
+ // generated destructor
+ // generated assignment operator
+
+ // Replace all occurrences of the parameters throughout the macrodefinition
+ // with special parameter tokens to simplify later macro replacement.
+ // Additionally mark all occurrences of the macro name itself throughout
+ // the macro definition
+ void replace_parameters()
+ {
+ using namespace boost::wave;
+
+ if (!replaced_parameters) {
+ typename definition_container_type::iterator end = macrodefinition.end();
+ typename definition_container_type::iterator it = macrodefinition.begin();
+
+ for (/**/; it != end; ++it) {
+ token_id id = *it;
+
+ if (T_IDENTIFIER == id ||
+ IS_CATEGORY(id, KeywordTokenType) ||
+ IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) ||
+ IS_CATEGORY(id, OperatorTokenType))
+ {
+ // may be a parameter to replace
+ const_parameter_iterator_t cend = macroparameters.end();
+ const_parameter_iterator_t cit = macroparameters.begin();
+ for (typename parameter_container_type::size_type i = 0;
+ cit != cend; ++cit, ++i)
+ {
+ if ((*it).get_value() == (*cit).get_value()) {
+ (*it).set_token_id(token_id(T_PARAMETERBASE+i));
+ break;
+ }
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ else if (T_ELLIPSIS == token_id(*cit) &&
+ "__VA_ARGS__" == (*it).get_value())
+ {
+ // __VA_ARGS__ requires special handling
+ (*it).set_token_id(token_id(T_EXTPARAMETERBASE+i));
+ break;
+ }
+#endif
+ }
+ }
+ }
+
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ // we need to know, if the last of the formal arguments is an ellipsis
+ if (macroparameters.size() > 0 &&
+ T_ELLIPSIS == token_id(macroparameters.back()))
+ {
+ has_ellipsis = true;
+ }
+#endif
+ replaced_parameters = true; // do it only once
+ }
+ }
+
+ TokenT macroname; // macro name
+ parameter_container_type macroparameters; // formal parameters
+ definition_container_type macrodefinition; // macro definition token sequence
+ long uid; // unique id of this macro
+ bool is_functionlike;
+ bool replaced_parameters;
+ bool is_available_for_replacement;
+ bool is_predefined;
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ bool has_ellipsis;
+#endif
+ boost::detail::atomic_count use_count;
+
+#if BOOST_WAVE_SERIALIZATION != 0
+ // default constructor is needed for serialization only
+ macro_definition()
+ : uid(0), is_functionlike(false), replaced_parameters(false),
+ is_available_for_replacement(false), is_predefined(false)
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ , has_ellipsis(false)
+#endif
+ , use_count(0)
+ {}
+
+private:
+ friend class boost::serialization::access;
+ template<typename Archive>
+ void serialize(Archive &ar, const unsigned int version)
+ {
+ using namespace boost::serialization;
+ ar & make_nvp("name", macroname);
+ ar & make_nvp("parameters", macroparameters);
+ ar & make_nvp("definition", macrodefinition);
+ ar & make_nvp("uid", uid);
+ ar & make_nvp("is_functionlike", is_functionlike);
+ ar & make_nvp("has_replaced_parameters", replaced_parameters);
+ ar & make_nvp("is_available_for_replacement", is_available_for_replacement);
+ ar & make_nvp("is_predefined", is_predefined);
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ ar & make_nvp("has_ellipsis", has_ellipsis);
+#endif
+ }
+#endif
+};
+
+#if BOOST_WAVE_SERIALIZATION == 0
+///////////////////////////////////////////////////////////////////////////////
+template <typename TokenT, typename ContainerT>
+inline void
+intrusive_ptr_add_ref(macro_definition<TokenT, ContainerT>* p)
+{
+ ++p->use_count;
+}
+
+template <typename TokenT, typename ContainerT>
+inline void
+intrusive_ptr_release(macro_definition<TokenT, ContainerT>* p)
+{
+ if (--p->use_count == 0)
+ delete p;
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+} // 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(MACRO_DEFINITION_HPP_D68A639E_2DA5_4E9C_8ACD_CFE6B903831E_INCLUDED)
diff --git a/boost/wave/util/macro_helpers.hpp b/boost/wave/util/macro_helpers.hpp
new file mode 100644
index 0000000000..4d156638dd
--- /dev/null
+++ b/boost/wave/util/macro_helpers.hpp
@@ -0,0 +1,303 @@
+/*=============================================================================
+ 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(MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED)
+#define MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED
+
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/wave/wave_config.hpp>
+#include <boost/wave/token_ids.hpp>
+#include <boost/wave/cpplexer/validate_universal_char.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
+
+///////////////////////////////////////////////////////////////////////////////
+namespace boost {
+namespace wave {
+namespace util {
+
+namespace impl {
+
+ // escape a string literal (insert '\\' before every '\"', '?' and '\\')
+ template <typename StringT>
+ inline StringT
+ escape_lit(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("\\")
+ + StringT(1, value[pos1]);
+ pos1 = value.find_first_of ("\"\\?", pos = pos1+1);
+ } while (StringT::npos != pos1);
+ result += value.substr(pos);
+ }
+ else {
+ result = value;
+ }
+ return result;
+ }
+
+ // un-escape a string literal (remove '\\' just before '\\', '\"' or '?')
+ template <typename StringT>
+ inline StringT
+ unescape_lit(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 {
+ switch (value[pos1+1]) {
+ case '\\':
+ case '\"':
+ case '?':
+ result = result + value.substr(pos, pos1-pos);
+ pos1 = value.find_first_of ("\\", (pos = pos1+1)+1);
+ break;
+
+ case 'n':
+ result = result + value.substr(pos, pos1-pos) + "\n";
+ pos1 = value.find_first_of ("\\", pos = pos1+1);
+ ++pos;
+ break;
+
+ default:
+ result = result + value.substr(pos, pos1-pos+1);
+ pos1 = value.find_first_of ("\\", pos = pos1+1);
+ }
+
+ } while (pos1 != StringT::npos);
+ result = result + value.substr(pos);
+ }
+ else {
+ // the string doesn't contain any escaped character sequences
+ result = value;
+ }
+ return result;
+ }
+
+ // return the string representation of a token sequence
+ template <typename ContainerT, typename PositionT>
+ inline typename ContainerT::value_type::string_type
+ as_stringlit (ContainerT const &token_sequence, PositionT const &pos)
+ {
+ using namespace boost::wave;
+ typedef typename ContainerT::value_type::string_type string_type;
+
+ string_type result("\"");
+ bool was_whitespace = false;
+ typename ContainerT::const_iterator end = token_sequence.end();
+ for (typename ContainerT::const_iterator it = token_sequence.begin();
+ it != end; ++it)
+ {
+ token_id id = token_id(*it);
+
+ if (IS_CATEGORY(*it, WhiteSpaceTokenType) || T_NEWLINE == id) {
+ if (!was_whitespace) {
+ // C++ standard 16.3.2.2 [cpp.stringize]
+ // Each occurrence of white space between the argument's
+ // preprocessing tokens becomes a single space character in the
+ // character string literal.
+ result += " ";
+ was_whitespace = true;
+ }
+ }
+ else if (T_STRINGLIT == id || T_CHARLIT == id) {
+ // string literals and character literals have to be escaped
+ result += impl::escape_lit((*it).get_value());
+ was_whitespace = false;
+ }
+ else
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ if (T_PLACEMARKER != id)
+#endif
+ {
+ // now append this token to the string
+ result += (*it).get_value();
+ was_whitespace = false;
+ }
+ }
+ result += "\"";
+
+ // validate the resulting literal to contain no invalid universal character
+ // value (throws if invalid chars found)
+ boost::wave::cpplexer::impl::validate_literal(result, pos.get_line(),
+ pos.get_column(), pos.get_file());
+ return result;
+ }
+
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ // return the string representation of a token sequence
+ template <typename ContainerT, typename PositionT>
+ inline typename ContainerT::value_type::string_type
+ as_stringlit (std::vector<ContainerT> const &arguments,
+ typename std::vector<ContainerT>::size_type i, PositionT const &pos)
+ {
+ using namespace boost::wave;
+ typedef typename ContainerT::value_type::string_type string_type;
+
+ BOOST_ASSERT(i < arguments.size());
+
+ string_type result("\"");
+ bool was_whitespace = false;
+
+ for (/**/; i < arguments.size(); ++i) {
+ // stringize all remaining arguments
+ typename ContainerT::const_iterator end = arguments[i].end();
+ for (typename ContainerT::const_iterator it = arguments[i].begin();
+ it != end; ++it)
+ {
+ token_id id = token_id(*it);
+
+ if (IS_CATEGORY(*it, WhiteSpaceTokenType) || T_NEWLINE == id) {
+ if (!was_whitespace) {
+ // C++ standard 16.3.2.2 [cpp.stringize]
+ // Each occurrence of white space between the argument's
+ // preprocessing tokens becomes a single space character in the
+ // character string literal.
+ result += " ";
+ was_whitespace = true;
+ }
+ }
+ else if (T_STRINGLIT == id || T_CHARLIT == id) {
+ // string literals and character literals have to be escaped
+ result += impl::escape_lit((*it).get_value());
+ was_whitespace = false;
+ }
+ else if (T_PLACEMARKER != id) {
+ // now append this token to the string
+ result += (*it).get_value();
+ was_whitespace = false;
+ }
+ }
+
+ // append comma, if not last argument
+ if (i < arguments.size()-1) {
+ result += ",";
+ was_whitespace = false;
+ }
+ }
+ result += "\"";
+
+ // validate the resulting literal to contain no invalid universal character
+ // value (throws if invalid chars found)
+ boost::wave::cpplexer::impl::validate_literal(result, pos.get_line(),
+ pos.get_column(), pos.get_file());
+ return result;
+ }
+#endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+
+ // return the string representation of a token sequence
+ template <typename StringT, typename IteratorT>
+ inline StringT
+ as_string(IteratorT it, IteratorT const& end)
+ {
+ StringT result;
+ for (/**/; it != end; ++it)
+ {
+ result += (*it).get_value();
+ }
+ return result;
+ }
+
+ // return the string representation of a token sequence
+ template <typename ContainerT>
+ inline typename ContainerT::value_type::string_type
+ as_string (ContainerT const &token_sequence)
+ {
+ typedef typename ContainerT::value_type::string_type string_type;
+ return as_string<string_type>(token_sequence.begin(),
+ token_sequence.end());
+ }
+
+#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // Copies all arguments beginning with the given index to the output
+ // sequence. The arguments are separated by commas.
+ //
+ template <typename ContainerT, typename PositionT>
+ void replace_ellipsis (std::vector<ContainerT> const &arguments,
+ typename ContainerT::size_type index,
+ ContainerT &expanded, PositionT const &pos)
+ {
+ using namespace cpplexer;
+ typedef typename ContainerT::value_type token_type;
+
+ token_type comma(T_COMMA, ",", pos);
+ for (/**/; index < arguments.size(); ++index) {
+ ContainerT const &arg = arguments[index];
+
+ std::copy(arg.begin(), arg.end(),
+ std::inserter(expanded, expanded.end()));
+
+ if (index < arguments.size()-1)
+ expanded.push_back(comma);
+ }
+ }
+#endif
+
+ // Skip all whitespace characters and queue the skipped characters into the
+ // given container
+ template <typename IteratorT>
+ inline boost::wave::token_id
+ skip_whitespace(IteratorT &first, IteratorT const &last)
+ {
+ token_id id = util::impl::next_token<IteratorT>::peek(first, last, false);
+ if (IS_CATEGORY(id, WhiteSpaceTokenType)) {
+ do {
+ ++first;
+ id = util::impl::next_token<IteratorT>::peek(first, last, false);
+ } while (IS_CATEGORY(id, WhiteSpaceTokenType));
+ }
+ ++first;
+ return id;
+ }
+
+ template <typename IteratorT, typename ContainerT>
+ inline boost::wave::token_id
+ skip_whitespace(IteratorT &first, IteratorT const &last, ContainerT &queue)
+ {
+ queue.push_back (*first); // queue up the current token
+
+ token_id id = util::impl::next_token<IteratorT>::peek(first, last, false);
+ if (IS_CATEGORY(id, WhiteSpaceTokenType)) {
+ do {
+ queue.push_back(*++first); // queue up the next whitespace
+ id = util::impl::next_token<IteratorT>::peek(first, last, false);
+ } while (IS_CATEGORY(id, WhiteSpaceTokenType));
+ }
+ ++first;
+ return id;
+ }
+
+} // namespace impl
+
+///////////////////////////////////////////////////////////////////////////////
+} // 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(MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED)
diff --git a/boost/wave/util/pattern_parser.hpp b/boost/wave/util/pattern_parser.hpp
new file mode 100644
index 0000000000..876726fe4e
--- /dev/null
+++ b/boost/wave/util/pattern_parser.hpp
@@ -0,0 +1,67 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ Global application configuration
+
+ 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_SPIRIT_PATTERN_PARSER_HPP)
+#define BOOST_SPIRIT_PATTERN_PARSER_HPP
+
+#include <boost/spirit/include/classic_primitives.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
+
+///////////////////////////////////////////////////////////////////////////////
+namespace boost {
+namespace wave {
+namespace util {
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // pattern_and class
+ //
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename CharT = char>
+ struct pattern_and
+ : public boost::spirit::classic::char_parser<pattern_and<CharT> >
+ {
+ pattern_and(CharT pattern_, unsigned long pattern_mask_ = 0UL)
+ : pattern(pattern_),
+ pattern_mask((0UL != pattern_mask_) ?
+ pattern_mask_ : (unsigned long)pattern_)
+ {}
+
+ template <typename T>
+ bool test(T pattern_) const
+ { return ((unsigned long)pattern_ & pattern_mask) == (unsigned long)pattern; }
+
+ CharT pattern;
+ unsigned long pattern_mask;
+ };
+
+ template <typename CharT>
+ inline pattern_and<CharT>
+ pattern_p(CharT pattern, unsigned long pattern_mask = 0UL)
+ { return pattern_and<CharT>(pattern, pattern_mask); }
+
+///////////////////////////////////////////////////////////////////////////////
+} // 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(BOOST_SPIRIT_PATTERN_PARSER_HPP)
diff --git a/boost/wave/util/symbol_table.hpp b/boost/wave/util/symbol_table.hpp
new file mode 100644
index 0000000000..0eda557fba
--- /dev/null
+++ b/boost/wave/util/symbol_table.hpp
@@ -0,0 +1,120 @@
+/*=============================================================================
+ 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(SYMBOL_TABLE_HPP_32B0F7C6_3DD6_4113_95A5_E16516C6F45A_INCLUDED)
+#define SYMBOL_TABLE_HPP_32B0F7C6_3DD6_4113_95A5_E16516C6F45A_INCLUDED
+
+#include <map>
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/intrusive_ptr.hpp>
+
+#if BOOST_WAVE_SERIALIZATION != 0
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/map.hpp>
+#include <boost/shared_ptr.hpp>
+#else
+#include <boost/intrusive_ptr.hpp>
+#endif
+
+#include <boost/iterator/transform_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
+
+///////////////////////////////////////////////////////////////////////////////
+namespace boost {
+namespace wave {
+namespace util {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// The symbol_table class is used for the storage of defined macros.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename StringT, typename MacroDefT>
+struct symbol_table
+#if BOOST_WAVE_SERIALIZATION != 0
+: public std::map<StringT, boost::shared_ptr<MacroDefT> >
+#else
+: public std::map<StringT, boost::intrusive_ptr<MacroDefT> >
+#endif
+{
+#if BOOST_WAVE_SERIALIZATION != 0
+ typedef std::map<StringT, boost::shared_ptr<MacroDefT> > base_type;
+#else
+ typedef std::map<StringT, boost::intrusive_ptr<MacroDefT> > base_type;
+#endif
+ typedef typename base_type::iterator iterator_type;
+ typedef typename base_type::const_iterator const_iterator_type;
+
+ symbol_table(long uid_ = 0)
+ {}
+
+#if BOOST_WAVE_SERIALIZATION != 0
+private:
+ friend class boost::serialization::access;
+ template<typename Archive>
+ void serialize(Archive &ar, const unsigned int version)
+ {
+ using namespace boost::serialization;
+ ar & make_nvp("symbol_table",
+ boost::serialization::base_object<base_type>(*this));
+ }
+#endif
+
+private:
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // This is a special iterator allowing to iterate the names of all defined
+ // macros.
+ //
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename StringT1>
+ struct get_first
+ {
+ typedef StringT1 const& result_type;
+
+ template <typename First, typename Second>
+ StringT1 const& operator() (std::pair<First, Second> const& p) const
+ {
+ return p.first;
+ }
+ };
+ typedef get_first<StringT> unary_functor;
+
+public:
+ typedef transform_iterator<unary_functor, iterator_type>
+ name_iterator;
+ typedef transform_iterator<unary_functor, const_iterator_type>
+ const_name_iterator;
+
+ template <typename Iterator>
+ static
+ transform_iterator<unary_functor, Iterator> make_iterator(Iterator it)
+ {
+ return boost::make_transform_iterator<unary_functor>(it);
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+} // 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(SYMBOL_TABLE_HPP_32B0F7C6_3DD6_4113_95A5_E16516C6F45A_INCLUDED)
diff --git a/boost/wave/util/time_conversion_helper.hpp b/boost/wave/util/time_conversion_helper.hpp
new file mode 100644
index 0000000000..a477607b95
--- /dev/null
+++ b/boost/wave/util/time_conversion_helper.hpp
@@ -0,0 +1,153 @@
+ /*=============================================================================
+ 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(TIME_CONVERSION_HELPER_HPP_DA97E389_1797_43BA_82AE_B071064B3EF4_INCLUDED)
+#define TIME_CONVERSION_HELPER_HPP_DA97E389_1797_43BA_82AE_B071064B3EF4_INCLUDED
+
+#include <ctime>
+#include <cstring>
+
+#include <boost/config.hpp>
+#include <boost/spirit/include/classic_core.hpp>
+#include <boost/spirit/include/classic_symbols.hpp>
+#include <boost/spirit/include/classic_assign_actor.hpp>
+#include <boost/spirit/include/classic_push_back_actor.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 util {
+
+namespace time_conversion {
+
+ using namespace std; // some systems have std::tm etc. in namespace std
+
+///////////////////////////////////////////////////////////////////////////////
+// define, whether the rule's should generate some debug output
+#define TRACE_CPP_TIME_CONVERSION \
+ (BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_TIME_CONVERSION) \
+ /**/
+
+///////////////////////////////////////////////////////////////////////////////
+// Grammar for parsing a date/time string generated by the C++ compiler from
+// __DATE__ and __TIME__
+ class time_conversion_grammar :
+ public boost::spirit::classic::grammar<time_conversion_grammar>
+ {
+ public:
+ time_conversion_grammar() : fYearIsCorrected(false)
+ {
+ using namespace std; // some systems have memset in std
+ memset (&time_stamp, 0, sizeof(tm));
+ BOOST_SPIRIT_DEBUG_TRACE_RULE_NAME(*this, "time_conversion_grammar",
+ TRACE_CPP_TIME_CONVERSION);
+ }
+
+ template <typename ScannerT>
+ struct definition {
+
+ definition(time_conversion_grammar const &self)
+ {
+ using boost::spirit::classic::int_p;
+ using boost::spirit::classic::add;
+
+ char const *m[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+
+ for (int i = 0; i < 12; ++i)
+ add (month, m[i], i);
+
+ time_rule // expected format is 'Dec 29 2001 11:23:59'
+ = month[spirit_assign_actor(self.time_stamp.tm_mon)]
+ >> int_p[spirit_assign_actor(self.time_stamp.tm_mday)]
+ >> int_p[spirit_assign_actor(self.time_stamp.tm_year)]
+ >> int_p[spirit_assign_actor(self.time_stamp.tm_hour)] >> ':'
+ >> int_p[spirit_assign_actor(self.time_stamp.tm_min)] >> ':'
+ >> int_p[spirit_assign_actor(self.time_stamp.tm_sec)]
+ ;
+
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(time_rule, TRACE_CPP_TIME_CONVERSION);
+ }
+
+ boost::spirit::classic::rule<ScannerT> time_rule;
+ boost::spirit::classic::symbols<> month;
+
+ boost::spirit::classic::rule<ScannerT> const&
+ start() const { return time_rule; }
+ };
+
+ void correct_year()
+ {
+ if (!fYearIsCorrected) {
+ time_stamp.tm_year -= 1900;
+ fYearIsCorrected = true;
+ }
+ }
+
+ mutable tm time_stamp;
+ bool fYearIsCorrected;
+ };
+
+///////////////////////////////////////////////////////////////////////////////
+// calculate the time of the compilation as a std::time_t to ensure correctness
+// of the saved dfa table
+ class time_conversion_helper
+ {
+ public:
+ time_conversion_helper(char const *act_time) : compile_time(0)
+ {
+ using namespace boost::spirit::classic;
+
+ time_conversion_grammar g;
+ parse_info<> pi = parse (act_time, g, space_p);
+
+ if (pi.hit) {
+ g.correct_year();
+ compile_time = mktime(&g.time_stamp);
+ }
+ BOOST_ASSERT(0 != compile_time);
+ }
+
+ time_t get_time() const { return compile_time; }
+
+ private:
+ time_t compile_time;
+ };
+
+///////////////////////////////////////////////////////////////////////////////
+#undef TRACE_CPP_TIME_CONVERSION
+} // namespace time_conversion
+
+// import time_conversion into the boost::wave::util namespace
+using namespace time_conversion;
+
+///////////////////////////////////////////////////////////////////////////////
+} // 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(TIME_CONVERSION_HELPER_HPP_DA97E389_1797_43BA_82AE_B071064B3EF4_INCLUDED)
diff --git a/boost/wave/util/transform_iterator.hpp b/boost/wave/util/transform_iterator.hpp
new file mode 100644
index 0000000000..7477bfedbd
--- /dev/null
+++ b/boost/wave/util/transform_iterator.hpp
@@ -0,0 +1,89 @@
+/*=============================================================================
+ 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(TRANSFORM_ITERATOR_HPP_D492C659_88C7_4258_8C42_192F9AE80EC0_INCLUDED)
+#define TRANSFORM_ITERATOR_HPP_D492C659_88C7_4258_8C42_192F9AE80EC0_INCLUDED
+
+#include <boost/config.hpp>
+#include <boost/iterator_adaptors.hpp>
+#include <boost/iterator/transform_iterator.hpp>
+
+#include <boost/assert.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 impl {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// The new Boost.Iterator library already conatins a transform_iterator usable
+// for our needs. The code below wraps this up.
+//
+///////////////////////////////////////////////////////////////////////////////
+ template <class AdaptableUnaryFunctionT, class IteratorT>
+ class ref_transform_iterator_generator
+ {
+ typedef typename AdaptableUnaryFunctionT::result_type return_type;
+ typedef typename AdaptableUnaryFunctionT::argument_type argument_type;
+
+ public:
+ typedef boost::transform_iterator<
+ return_type (*)(argument_type), IteratorT, return_type>
+ type;
+ };
+
+ template <class AdaptableUnaryFunctionT, class IteratorT>
+ inline
+ typename ref_transform_iterator_generator<
+ AdaptableUnaryFunctionT, IteratorT>::type
+ make_ref_transform_iterator(
+ IteratorT base, AdaptableUnaryFunctionT const &f)
+ {
+ typedef typename ref_transform_iterator_generator<
+ AdaptableUnaryFunctionT, IteratorT>::type
+ iterator_type;
+ return iterator_type(base, f.transform);
+ }
+
+ // Retrieve the token value given a parse node
+ // This is used in conjunction with the ref_transform_iterator above, to
+ // get the token values while iterating directly over the parse tree.
+ template <typename TokenT, typename ParseTreeNodeT>
+ struct get_token_value {
+
+ typedef TokenT const &result_type;
+ typedef ParseTreeNodeT const &argument_type;
+
+ static result_type
+ transform (argument_type node)
+ {
+ BOOST_ASSERT(1 == std::distance(node.value.begin(),
+ node.value.end()));
+ return *node.value.begin();
+ }
+ };
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace impl
+} // 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(TRANSFORM_ITERATOR_HPP_D492C659_88C7_4258_8C42_192F9AE80EC0_INCLUDED)
diff --git a/boost/wave/util/unput_queue_iterator.hpp b/boost/wave/util/unput_queue_iterator.hpp
new file mode 100644
index 0000000000..7fc060153b
--- /dev/null
+++ b/boost/wave/util/unput_queue_iterator.hpp
@@ -0,0 +1,295 @@
+/*=============================================================================
+ Boost.Wave: A Standard compliant C++ preprocessor library
+
+ Definition of the unput queue 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(UNPUT_QUEUE_ITERATOR_HPP_76DA23D0_4893_4AD5_ABCC_6CED7CFB89BC_INCLUDED)
+#define UNPUT_QUEUE_ITERATOR_HPP_76DA23D0_4893_4AD5_ABCC_6CED7CFB89BC_INCLUDED
+
+#include <list>
+
+#include <boost/assert.hpp>
+#include <boost/iterator_adaptors.hpp>
+
+#include <boost/wave/wave_config.hpp>
+#include <boost/wave/token_ids.hpp> // token_id
+
+// 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 {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// unput_queue_iterator
+//
+// The unput_queue_iterator templates encapsulates an unput_queue together
+// with the direct input to be read after the unput queue is emptied
+//
+// This version is for the new iterator_adaptors (was released with
+// Boost V1.31.0)
+//
+///////////////////////////////////////////////////////////////////////////////
+template <typename IteratorT, typename TokenT, typename ContainerT>
+class unput_queue_iterator
+: public boost::iterator_adaptor<
+ unput_queue_iterator<IteratorT, TokenT, ContainerT>,
+ IteratorT, TokenT const, std::forward_iterator_tag>
+{
+ typedef boost::iterator_adaptor<
+ unput_queue_iterator<IteratorT, TokenT, ContainerT>,
+ IteratorT, TokenT const, std::forward_iterator_tag>
+ base_type;
+
+public:
+ typedef ContainerT container_type;
+ typedef IteratorT iterator_type;
+
+ unput_queue_iterator(IteratorT const &it, ContainerT &queue)
+ : base_type(it), unput_queue(queue)
+ {}
+
+ ContainerT &get_unput_queue()
+ { return unput_queue; }
+ ContainerT const &get_unput_queue() const
+ { return unput_queue; }
+ IteratorT &get_base_iterator()
+ { return base_type::base_reference(); }
+ IteratorT const &get_base_iterator() const
+ { return base_type::base_reference(); }
+
+ unput_queue_iterator &operator= (unput_queue_iterator const &rhs)
+ {
+ if (this != &rhs) {
+ unput_queue = rhs.unput_queue;
+ base_type::operator=(rhs);
+ }
+ return *this;
+ }
+
+ typename base_type::reference dereference() const
+ {
+ if (!unput_queue.empty())
+ return unput_queue.front();
+ return *base_type::base_reference();
+ }
+
+ void increment()
+ {
+ if (!unput_queue.empty()) {
+ // there exist pending tokens in the unput queue
+ unput_queue.pop_front();
+ }
+ else {
+ // the unput_queue is empty, so advance the base iterator
+ ++base_type::base_reference();
+ }
+ }
+
+ template <
+ typename OtherDerivedT, typename OtherIteratorT,
+ typename V, typename C, typename R, typename D
+ >
+ bool equal(
+ boost::iterator_adaptor<OtherDerivedT, OtherIteratorT, V, C, R, D>
+ const &x) const
+ {
+ // two iterators are equal, if both begin() iterators of the queue
+ // objects are equal and the base iterators are equal as well
+ OtherDerivedT const &rhs = static_cast<OtherDerivedT const &>(x);
+ return
+ ((unput_queue.empty() && rhs.unput_queue.empty()) ||
+ (&unput_queue == &rhs.unput_queue &&
+ unput_queue.begin() == rhs.unput_queue.begin()
+ )
+ ) &&
+ (get_base_iterator() == rhs.get_base_iterator());
+ }
+
+private:
+ ContainerT &unput_queue;
+};
+
+namespace impl {
+
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename IteratorT, typename TokenT, typename ContainerT>
+ struct gen_unput_queue_iterator
+ {
+ typedef ContainerT container_type;
+ typedef IteratorT iterator_type;
+ typedef unput_queue_iterator<IteratorT, TokenT, ContainerT>
+ return_type;
+
+ static container_type last;
+
+ static return_type
+ generate(iterator_type const &it)
+ {
+ return return_type(it, last);
+ }
+
+ static return_type
+ generate(ContainerT &queue, iterator_type const &it)
+ {
+ return return_type(it, queue);
+ }
+ };
+
+ template <typename IteratorT, typename TokenT, typename ContainerT>
+ typename gen_unput_queue_iterator<IteratorT, TokenT, ContainerT>::
+ container_type
+ gen_unput_queue_iterator<IteratorT, TokenT, ContainerT>::last =
+ typename gen_unput_queue_iterator<IteratorT, TokenT, ContainerT>::
+ container_type();
+
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename IteratorT, typename TokenT, typename ContainerT>
+ struct gen_unput_queue_iterator<
+ unput_queue_iterator<IteratorT, TokenT, ContainerT>,
+ TokenT, ContainerT>
+ {
+ typedef ContainerT container_type;
+ typedef unput_queue_iterator<IteratorT, TokenT, ContainerT>
+ iterator_type;
+ typedef unput_queue_iterator<IteratorT, TokenT, ContainerT>
+ return_type;
+
+ static container_type last;
+
+ static return_type
+ generate(iterator_type &it)
+ {
+ return return_type(it.base(), last);
+ }
+
+ static return_type
+ generate(ContainerT &queue, iterator_type &it)
+ {
+ return return_type(it.base(), queue);
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename IteratorT>
+ struct assign_iterator
+ {
+ static void
+ do_ (IteratorT &dest, IteratorT const &src)
+ {
+ dest = src;
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ //
+ // Look for the first non-whitespace token and return this token id.
+ // Note though, that the embedded unput_queues are not touched in any way!
+ //
+ template <typename IteratorT>
+ struct next_token
+ {
+ static boost::wave::token_id
+ peek(IteratorT it, IteratorT end, bool skip_whitespace = true)
+ {
+ using namespace boost::wave;
+ if (skip_whitespace) {
+ for (++it; it != end; ++it) {
+ if (!IS_CATEGORY(*it, WhiteSpaceTokenType) &&
+ T_NEWLINE != token_id(*it))
+ {
+ break; // stop at the first non-whitespace token
+ }
+ }
+ }
+ else {
+ ++it; // we have at least to look ahead
+ }
+ if (it != end)
+ return token_id(*it);
+ return T_EOI;
+ }
+ };
+
+ template <typename IteratorT, typename TokenT, typename ContainerT>
+ struct next_token<
+ unput_queue_iterator<IteratorT, TokenT, ContainerT> > {
+
+ typedef unput_queue_iterator<IteratorT, TokenT, ContainerT> iterator_type;
+
+ static boost::wave::token_id
+ peek(iterator_type it, iterator_type end, bool skip_whitespace = true)
+ {
+ using namespace boost::wave;
+
+ typename iterator_type::container_type &queue = it.get_unput_queue();
+
+ // first try to find it in the unput_queue
+ if (0 != queue.size()) {
+ typename iterator_type::container_type::iterator cit = queue.begin();
+ typename iterator_type::container_type::iterator cend = queue.end();
+
+ if (skip_whitespace) {
+ for (++cit; cit != cend; ++cit) {
+ if (!IS_CATEGORY(*cit, WhiteSpaceTokenType) &&
+ T_NEWLINE != token_id(*cit))
+ {
+ break; // stop at the first non-whitespace token
+ }
+ }
+ }
+ else {
+ ++cit; // we have at least to look ahead
+ }
+ if (cit != cend)
+ return token_id(*cit);
+ }
+
+ // second try to move on into the base iterator stream
+ typename iterator_type::iterator_type base_it = it.get_base_iterator();
+ typename iterator_type::iterator_type base_end = end.get_base_iterator();
+
+ if (0 == queue.size())
+ ++base_it; // advance, if the unput queue is empty
+
+ if (skip_whitespace) {
+ for (/**/; base_it != base_end; ++base_it) {
+ if (!IS_CATEGORY(*base_it, WhiteSpaceTokenType) &&
+ T_NEWLINE != token_id(*base_it))
+ {
+ break; // stop at the first non-whitespace token
+ }
+ }
+ }
+ if (base_it == base_end)
+ return T_EOI;
+
+ return token_id(*base_it);
+ }
+ };
+
+///////////////////////////////////////////////////////////////////////////////
+} // namespace impl
+
+///////////////////////////////////////////////////////////////////////////////
+} // 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(UNPUT_QUEUE_ITERATOR_HPP_76DA23D0_4893_4AD5_ABCC_6CED7CFB89BC_INCLUDED)