diff options
author | Anas Nashif <anas.nashif@intel.com> | 2012-10-30 12:57:26 -0700 |
---|---|---|
committer | Anas Nashif <anas.nashif@intel.com> | 2012-10-30 12:57:26 -0700 |
commit | 1a78a62555be32868418fe52f8e330c9d0f95d5a (patch) | |
tree | d3765a80e7d3b9640ec2e930743630cd6b9fce2b /boost/wave | |
download | boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.gz boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.bz2 boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.zip |
Imported Upstream version 1.49.0upstream/1.49.0
Diffstat (limited to 'boost/wave')
57 files changed, 21350 insertions, 0 deletions
diff --git a/boost/wave/cpp_context.hpp b/boost/wave/cpp_context.hpp new file mode 100644 index 0000000000..f053cdb815 --- /dev/null +++ b/boost/wave/cpp_context.hpp @@ -0,0 +1,571 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + Definition of the preprocessor context + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_CONTEXT_HPP_907485E2_6649_4A87_911B_7F7225F3E5B8_INCLUDED) +#define CPP_CONTEXT_HPP_907485E2_6649_4A87_911B_7F7225F3E5B8_INCLUDED + +#include <string> +#include <vector> +#include <stack> + +#include <boost/concept_check.hpp> +#include <boost/noncopyable.hpp> +#include <boost/filesystem/path.hpp> +#include <boost/mpl/if.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/pool/pool_alloc.hpp> + +#include <boost/wave/wave_config.hpp> +#if BOOST_WAVE_SERIALIZATION != 0 +#include <boost/serialization/serialization.hpp> +#include <boost/wave/wave_config_constant.hpp> +#endif +#include <boost/wave/token_ids.hpp> + +#include <boost/wave/util/unput_queue_iterator.hpp> +#include <boost/wave/util/cpp_ifblock.hpp> +#include <boost/wave/util/cpp_include_paths.hpp> +#include <boost/wave/util/iteration_context.hpp> +#include <boost/wave/util/cpp_iterator.hpp> +#include <boost/wave/util/cpp_macromap.hpp> + +#include <boost/wave/preprocessing_hooks.hpp> +#include <boost/wave/whitespace_handling.hpp> +#include <boost/wave/cpp_iteration_context.hpp> +#include <boost/wave/language_support.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { + +/////////////////////////////////////////////////////////////////////////////// +// +// The C/C++ preprocessor context template class +// +// The boost::wave::context template is the main interface class to +// control the behavior of the preprocessing engine. +// +// The following template parameters has to be supplied: +// +// IteratorT The iterator type of the underlying input stream +// LexIteratorT The lexer iterator type to use as the token factory +// InputPolicyT The input policy type to use for loading the files +// to be included. This template parameter is optional and +// defaults to the +// iteration_context_policies::load_file_to_string +// type. +// HooksT The hooks policy to use for different notification +// callbacks. This template parameter is optional and +// defaults to the +// context_policies::default_preprocessing_hooks +// type. +// DerivedT The type of the type being derived from the context +// type (if any). This template parameter is optional and +// defaults to 'this_type', which means that the context +// type will be used assuming no derived type exists. +// +/////////////////////////////////////////////////////////////////////////////// + +struct this_type {}; + +template < + typename IteratorT, + typename LexIteratorT, + typename InputPolicyT = iteration_context_policies::load_file_to_string, + typename HooksT = context_policies::eat_whitespace<typename LexIteratorT::token_type>, + typename DerivedT = this_type +> +class context : private boost::noncopyable +{ +private: + typedef typename mpl::if_< + is_same<DerivedT, this_type>, context, DerivedT + >::type actual_context_type; + +public: + +// concept checks +// the given iterator should be at least a forward iterator type + BOOST_CLASS_REQUIRE(IteratorT, boost, ForwardIteratorConcept); + +// public typedefs + typedef typename LexIteratorT::token_type token_type; + typedef typename token_type::string_type string_type; + + typedef IteratorT target_iterator_type; + typedef LexIteratorT lexer_type; + typedef pp_iterator<context> iterator_type; + + typedef InputPolicyT input_policy_type; + typedef typename token_type::position_type position_type; + +// type of a token sequence + typedef std::list<token_type, boost::fast_pool_allocator<token_type> > + token_sequence_type; +// type of the policies + typedef HooksT hook_policy_type; + +private: +// stack of shared_ptr's to the pending iteration contexts + typedef boost::shared_ptr<base_iteration_context<context, lexer_type> > + iteration_ptr_type; + typedef boost::wave::util::iteration_context_stack<iteration_ptr_type> + iteration_context_stack_type; + typedef typename iteration_context_stack_type::size_type iter_size_type; + + context *this_() { return this; } // avoid warning in constructor + +public: + context(target_iterator_type const &first_, target_iterator_type const &last_, + char const *fname = "<Unknown>", HooksT const &hooks_ = HooksT()) + : first(first_), last(last_), filename(fname) + , has_been_initialized(false) +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + , current_filename(fname) +#endif + , current_relative_filename(fname) + , macros(*this_()) + , language(language_support( + support_cpp + | support_option_convert_trigraphs + | support_option_emit_line_directives +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + | support_option_include_guard_detection +#endif +#if BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES != 0 + | support_option_emit_pragma_directives +#endif + | support_option_insert_whitespace + )) + , hooks(hooks_) + { + macros.init_predefined_macros(fname); + } + +// default copy constructor +// default assignment operator +// default destructor + +// iterator interface + iterator_type begin() + { + std::string fname(filename); + if (filename != "<Unknown>" && filename != "<stdin>") { + using namespace boost::filesystem; + path fpath(util::complete_path(path(filename))); + fname = fpath.string(); + } + return iterator_type(*this, first, last, position_type(fname.c_str())); + } + iterator_type begin( + target_iterator_type const &first_, + target_iterator_type const &last_) + { + std::string fname(filename); + if (filename != "<Unknown>" && filename != "<stdin>") { + using namespace boost::filesystem; + path fpath(util::complete_path(path(filename))); + fname = fpath.string(); + } + return iterator_type(*this, first_, last_, position_type(fname.c_str())); + } + iterator_type end() const + { return iterator_type(); } + +// maintain include paths + bool add_include_path(char const *path_) + { return includes.add_include_path(path_, false);} + bool add_sysinclude_path(char const *path_) + { return includes.add_include_path(path_, true);} + void set_sysinclude_delimiter() { includes.set_sys_include_delimiter(); } + typename iteration_context_stack_type::size_type get_iteration_depth() const + { return iter_ctxs.size(); } + +// maintain defined macros +#if BOOST_WAVE_ENABLE_COMMANDLINE_MACROS != 0 + template <typename StringT> + bool add_macro_definition(StringT macrostring, bool is_predefined = false) + { + return boost::wave::util::add_macro_definition(*this, + util::to_string<std::string>(macrostring), is_predefined, + get_language()); + } +#endif +// Define and undefine macros, macro introspection + template <typename StringT> + bool add_macro_definition(StringT const &name, position_type const& pos, + bool has_params, std::vector<token_type> ¶meters, + token_sequence_type &definition, bool is_predefined = false) + { + return macros.add_macro( + token_type(T_IDENTIFIER, util::to_string<string_type>(name), pos), + has_params, parameters, definition, is_predefined); + } + template <typename StringT> + bool is_defined_macro(StringT const &str) const + { + return macros.is_defined(util::to_string<string_type>(str)); + } + template <typename StringT> + bool get_macro_definition(StringT const &name, + bool &has_params, bool &is_predefined, position_type &pos, + std::vector<token_type> ¶meters, + token_sequence_type &definition) const + { + return macros.get_macro(util::to_string<string_type>(name), + has_params, is_predefined, pos, parameters, definition); + } + template <typename StringT> + bool remove_macro_definition(StringT const& undefname, bool even_predefined = false) + { + // strip leading and trailing whitespace + string_type name = util::to_string<string_type>(undefname); + typename string_type::size_type pos = name.find_first_not_of(" \t"); + if (pos != string_type::npos) { + typename string_type::size_type endpos = name.find_last_not_of(" \t"); + name = name.substr(pos, endpos-pos+1); + } + +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + // ensure this gets removed from the list of include guards as well + includes.remove_pragma_once_header( + util::to_string<std::string>(name)); +#endif + return macros.remove_macro(name, macros.get_main_pos(), even_predefined); + } + void reset_macro_definitions() + { macros.reset_macromap(); macros.init_predefined_macros(); } + +// Iterate over names of defined macros + typedef boost::wave::util::macromap<context> macromap_type; + typedef typename macromap_type::name_iterator name_iterator; + typedef typename macromap_type::const_name_iterator const_name_iterator; + + name_iterator macro_names_begin() { return macros.begin(); } + name_iterator macro_names_end() { return macros.end(); } + const_name_iterator macro_names_begin() const { return macros.begin(); } + const_name_iterator macro_names_end() const { return macros.end(); } + +// This version now is used internally mainly, but since it was a documented +// API function we leave it in the public interface. + bool add_macro_definition(token_type const &name, bool has_params, + std::vector<token_type> ¶meters, token_sequence_type &definition, + bool is_predefined = false) + { + return macros.add_macro(name, has_params, parameters, definition, + is_predefined); + } + +// get the Wave version information + static std::string get_version() + { + boost::wave::util::predefined_macros p; + return util::to_string<std::string>(p.get_fullversion()); + } + static std::string get_version_string() + { + boost::wave::util::predefined_macros p; + return util::to_string<std::string>(p.get_versionstr()); + } + +// access current language options + void set_language(boost::wave::language_support language_, + bool reset_macros = true) + { + language = language_; + if (reset_macros) + reset_macro_definitions(); + } + boost::wave::language_support get_language() const { return language; } + + position_type &get_main_pos() { return macros.get_main_pos(); } + position_type const& get_main_pos() const { return macros.get_main_pos(); } + +// change and ask for maximal possible include nesting depth + void set_max_include_nesting_depth(iter_size_type new_depth) + { iter_ctxs.set_max_include_nesting_depth(new_depth); } + iter_size_type get_max_include_nesting_depth() const + { return iter_ctxs.get_max_include_nesting_depth(); } + +// access the policies + hook_policy_type &get_hooks() { return hooks; } + hook_policy_type const &get_hooks() const { return hooks; } + +// return type of actually used context type (might be the derived type) + actual_context_type& derived() + { return *static_cast<actual_context_type*>(this); } + actual_context_type const& derived() const + { return *static_cast<actual_context_type const*>(this); } + +// return the directory of the currently preprocessed file + boost::filesystem::path get_current_directory() const + { return includes.get_current_directory(); } + +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) +protected: + friend class boost::wave::pp_iterator<context>; + friend class boost::wave::impl::pp_iterator_functor<context>; +#endif + +// make sure the context has been initialized + void init_context() + { + if (!has_been_initialized) { + std::string fname(filename); + if (filename != "<Unknown>" && filename != "<stdin>") { + using namespace boost::filesystem; + path fpath(util::complete_path(path(filename))); + fname = fpath.string(); + includes.set_current_directory(fname.c_str()); + } + has_been_initialized = true; // execute once + } + } + + template <typename IteratorT2> + bool is_defined_macro(IteratorT2 const &begin, IteratorT2 const &end) const + { return macros.is_defined(begin, end); } + +// maintain include paths (helper functions) + void set_current_directory(char const *path_) + { includes.set_current_directory(path_); } + +// conditional compilation contexts + bool get_if_block_status() const { return ifblocks.get_status(); } + bool get_if_block_some_part_status() const + { return ifblocks.get_some_part_status(); } + bool get_enclosing_if_block_status() const + { return ifblocks.get_enclosing_status(); } + void enter_if_block(bool new_status) + { ifblocks.enter_if_block(new_status); } + bool enter_elif_block(bool new_status) + { return ifblocks.enter_elif_block(new_status); } + bool enter_else_block() { return ifblocks.enter_else_block(); } + bool exit_if_block() { return ifblocks.exit_if_block(); } + typename boost::wave::util::if_block_stack::size_type get_if_block_depth() const + { return ifblocks.get_if_block_depth(); } + +// stack of iteration contexts + iteration_ptr_type pop_iteration_context() + { iteration_ptr_type top = iter_ctxs.top(); iter_ctxs.pop(); return top; } + void push_iteration_context(position_type const &act_pos, iteration_ptr_type iter_ctx) + { iter_ctxs.push(*this, act_pos, iter_ctx); } + +/////////////////////////////////////////////////////////////////////////////// +// +// expand_tokensequence(): +// expands all macros contained in a given token sequence, handles '##' +// and '#' pp operators and re-scans the resulting sequence +// (essentially pre-processes the token sequence). +// +// The expand_undefined parameter is true during macro expansion inside +// a C++ expression given for a #if or #elif statement. +// +/////////////////////////////////////////////////////////////////////////////// + template <typename IteratorT2> + token_type expand_tokensequence(IteratorT2 &first_, IteratorT2 const &last_, + token_sequence_type &pending, token_sequence_type &expanded, + bool& seen_newline, bool expand_undefined = false) + { + return macros.expand_tokensequence(first_, last_, pending, expanded, + seen_newline, expand_undefined); + } + + template <typename IteratorT2> + void expand_whole_tokensequence(IteratorT2 &first_, IteratorT2 const &last_, + token_sequence_type &expanded, bool expand_undefined = true) + { + macros.expand_whole_tokensequence(expanded, first_, last_, + expand_undefined); + + // remove any contained placeholder + boost::wave::util::impl::remove_placeholders(expanded); + } + +public: +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 +// support for #pragma once +// maintain the real name of the current preprocessed file + void set_current_filename(char const *real_name) + { current_filename = real_name; } + std::string const &get_current_filename() const + { return current_filename; } + +// maintain the list of known headers containing #pragma once + bool has_pragma_once(std::string const &filename_) + { return includes.has_pragma_once(filename_); } + bool add_pragma_once_header(std::string const &filename_, + std::string const& guard_name) + { + get_hooks().detected_include_guard(derived(), filename_, guard_name); + return includes.add_pragma_once_header(filename_, guard_name); + } + bool add_pragma_once_header(token_type const &pragma_, + std::string const &filename_) + { + get_hooks().detected_pragma_once(derived(), pragma_, filename_); + return includes.add_pragma_once_header(filename_, + "__BOOST_WAVE_PRAGMA_ONCE__"); + } +#endif + + void set_current_relative_filename(char const *real_name) + { current_relative_filename = real_name; } + std::string const &get_current_relative_filename() const + { return current_relative_filename; } + + bool find_include_file (std::string &s, std::string &d, bool is_system, + char const *current_file) const + { return includes.find_include_file(s, d, is_system, current_file); } + +#if BOOST_WAVE_SERIALIZATION != 0 +public: + BOOST_STATIC_CONSTANT(unsigned int, version = 0x10); + BOOST_STATIC_CONSTANT(unsigned int, version_mask = 0x0f); + +private: + friend class boost::serialization::access; + template<class Archive> + void save(Archive & ar, const unsigned int version) const + { + using namespace boost::serialization; + + string_type cfg(BOOST_PP_STRINGIZE(BOOST_WAVE_CONFIG)); + string_type kwd(BOOST_WAVE_PRAGMA_KEYWORD); + string_type strtype(BOOST_PP_STRINGIZE((BOOST_WAVE_STRINGTYPE))); + ar & make_nvp("config", cfg); + ar & make_nvp("pragma_keyword", kwd); + ar & make_nvp("string_type", strtype); + + ar & make_nvp("language_options", language); + ar & make_nvp("macro_definitions", macros); + ar & make_nvp("include_settings", includes); + } + template<class Archive> + void load(Archive & ar, const unsigned int loaded_version) + { + using namespace boost::serialization; + if (version != (loaded_version & ~version_mask)) { + BOOST_WAVE_THROW_CTX((*this), preprocess_exception, + incompatible_config, "cpp_context state version", + get_main_pos()); + return; + } + + // check compatibility of the stored information + string_type config, pragma_keyword, string_type_str; + + // BOOST_PP_STRINGIZE(BOOST_WAVE_CONFIG) + ar & make_nvp("config", config); + if (config != BOOST_PP_STRINGIZE(BOOST_WAVE_CONFIG)) { + BOOST_WAVE_THROW_CTX((*this), preprocess_exception, + incompatible_config, "BOOST_WAVE_CONFIG", get_main_pos()); + return; + } + + // BOOST_WAVE_PRAGMA_KEYWORD + ar & make_nvp("pragma_keyword", pragma_keyword); + if (pragma_keyword != BOOST_WAVE_PRAGMA_KEYWORD) { + BOOST_WAVE_THROW_CTX((*this), preprocess_exception, + incompatible_config, "BOOST_WAVE_PRAGMA_KEYWORD", + get_main_pos()); + return; + } + + // BOOST_PP_STRINGIZE((BOOST_WAVE_STRINGTYPE)) + ar & make_nvp("string_type", string_type_str); + if (string_type_str != BOOST_PP_STRINGIZE((BOOST_WAVE_STRINGTYPE))) { + BOOST_WAVE_THROW_CTX((*this), preprocess_exception, + incompatible_config, "BOOST_WAVE_STRINGTYPE", get_main_pos()); + return; + } + + try { + // read in the useful bits + ar & make_nvp("language_options", language); + ar & make_nvp("macro_definitions", macros); + ar & make_nvp("include_settings", includes); + } + catch (boost::wave::preprocess_exception const& e) { + // catch version mismatch exceptions and call error handler + get_hooks().throw_exception(derived(), e); + } + } + BOOST_SERIALIZATION_SPLIT_MEMBER() +#endif + +private: +// the main input stream + target_iterator_type first; // underlying input stream + target_iterator_type last; + std::string filename; // associated main filename + bool has_been_initialized; // set cwd once +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + std::string current_filename; // real name of current preprocessed file +#endif + std::string current_relative_filename; // real relative name of current preprocessed file + + boost::wave::util::if_block_stack ifblocks; // conditional compilation contexts + boost::wave::util::include_paths includes; // lists of include directories to search + iteration_context_stack_type iter_ctxs; // iteration contexts + macromap_type macros; // map of defined macros + boost::wave::language_support language; // supported language/extensions + hook_policy_type hooks; // hook policy instance +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace wave +} // namespace boost + +#if BOOST_WAVE_SERIALIZATION != 0 +namespace boost { namespace serialization { + +template< + typename Iterator, typename LexIterator, + typename InputPolicy, typename Hooks +> +struct tracking_level<boost::wave::context<Iterator, LexIterator, InputPolicy, Hooks> > +{ + typedef mpl::integral_c_tag tag; + typedef mpl::int_<track_never> type; + BOOST_STATIC_CONSTANT( + int, + value = tracking_level::type::value + ); +}; + +template< + typename Iterator, typename LexIterator, + typename InputPolicy, typename Hooks +> +struct version<boost::wave::context<Iterator, LexIterator, InputPolicy, Hooks> > +{ + typedef boost::wave::context<Iterator, LexIterator, InputPolicy, Hooks> + target_type; + typedef mpl::int_<target_type::version> type; + typedef mpl::integral_c_tag tag; + BOOST_STATIC_CONSTANT(unsigned int, value = version::type::value); +}; + +}} // namespace boost::serialization +#endif + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPP_CONTEXT_HPP_907485E2_6649_4A87_911B_7F7225F3E5B8_INCLUDED) diff --git a/boost/wave/cpp_exceptions.hpp b/boost/wave/cpp_exceptions.hpp new file mode 100644 index 0000000000..3fbd61af96 --- /dev/null +++ b/boost/wave/cpp_exceptions.hpp @@ -0,0 +1,421 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_EXCEPTIONS_HPP_5190E447_A781_4521_A275_5134FF9917D7_INCLUDED) +#define CPP_EXCEPTIONS_HPP_5190E447_A781_4521_A275_5134FF9917D7_INCLUDED + +#include <exception> +#include <string> +#include <limits> + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/throw_exception.hpp> +#include <boost/wave/wave_config.hpp> +#include <boost/wave/cpp_throw.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { + +/////////////////////////////////////////////////////////////////////////////// +// exception severity +namespace util { + + enum severity { + severity_remark = 0, + severity_warning, + severity_error, + severity_fatal, + severity_commandline_error, + last_severity_code = severity_commandline_error + }; + + inline char const * + get_severity(int level) + { + static char const *severity_text[] = + { + "remark", // severity_remark + "warning", // severity_warning + "error", // severity_error + "fatal error", // severity_fatal + "command line error" // severity_commandline_error + }; + BOOST_ASSERT(severity_remark <= level && + level <= last_severity_code); + return severity_text[level]; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// cpp_exception, the base class for all specific C preprocessor exceptions +class BOOST_SYMBOL_VISIBLE cpp_exception +: public std::exception +{ +public: + cpp_exception(int line_, int column_, char const *filename_) throw() + : line(line_), column(column_) + { + unsigned int off = 0; + while (off < sizeof(filename)-1 && *filename_) + filename[off++] = *filename_++; + filename[off] = 0; + } + ~cpp_exception() throw() {} + + virtual char const *what() const throw() = 0; // to be overloaded + virtual char const *description() const throw() = 0; + virtual int get_errorcode() const throw() = 0; + virtual int get_severity() const throw() = 0; + virtual char const* get_related_name() const throw() = 0; + virtual bool is_recoverable() const throw() = 0; + + int line_no() const throw() { return line; } + int column_no() const throw() { return column; } + char const *file_name() const throw() { return filename; } + +protected: + char filename[512]; + int line; + int column; +}; + +/////////////////////////////////////////////////////////////////////////////// +// preprocessor error +class BOOST_SYMBOL_VISIBLE preprocess_exception : + public cpp_exception +{ +public: + enum error_code { + no_error = 0, + unexpected_error, + macro_redefinition, + macro_insertion_error, + bad_include_file, + bad_include_statement, + ill_formed_directive, + error_directive, + warning_directive, + ill_formed_expression, + missing_matching_if, + missing_matching_endif, + ill_formed_operator, + bad_define_statement, + bad_define_statement_va_args, + too_few_macroarguments, + too_many_macroarguments, + empty_macroarguments, + improperly_terminated_macro, + bad_line_statement, + bad_line_number, + bad_line_filename, + bad_undefine_statement, + bad_macro_definition, + illegal_redefinition, + duplicate_parameter_name, + invalid_concat, + last_line_not_terminated, + ill_formed_pragma_option, + include_nesting_too_deep, + misplaced_operator, + alreadydefined_name, + undefined_macroname, + invalid_macroname, + unexpected_qualified_name, + division_by_zero, + integer_overflow, + illegal_operator_redefinition, + ill_formed_integer_literal, + ill_formed_character_literal, + unbalanced_if_endif, + character_literal_out_of_range, + could_not_open_output_file, + incompatible_config, + ill_formed_pragma_message, + pragma_message_directive, + last_error_number = pragma_message_directive + }; + + preprocess_exception(char const *what_, error_code code, int line_, + int column_, char const *filename_) throw() + : cpp_exception(line_, column_, filename_), + code(code) + { + unsigned int off = 0; + while (off < sizeof(buffer) && *what_) + buffer[off++] = *what_++; + buffer[off] = 0; + } + ~preprocess_exception() throw() {} + + virtual char const *what() const throw() + { + return "boost::wave::preprocess_exception"; + } + virtual char const *description() const throw() + { + return buffer; + } + virtual int get_severity() const throw() + { + return severity_level(code); + } + virtual int get_errorcode() const throw() + { + return code; + } + virtual char const* get_related_name() const throw() + { + return "<unknown>"; + } + virtual bool is_recoverable() const throw() + { + switch (get_errorcode()) { + // these are the exceptions thrown during processing not supposed to + // produce any tokens on the context::iterator level + case preprocess_exception::no_error: // just a placeholder + case preprocess_exception::macro_redefinition: + case preprocess_exception::macro_insertion_error: + case preprocess_exception::bad_macro_definition: + case preprocess_exception::illegal_redefinition: + case preprocess_exception::duplicate_parameter_name: + case preprocess_exception::invalid_macroname: + case preprocess_exception::bad_include_file: + case preprocess_exception::bad_include_statement: + case preprocess_exception::ill_formed_directive: + case preprocess_exception::error_directive: + case preprocess_exception::warning_directive: + case preprocess_exception::ill_formed_expression: + case preprocess_exception::missing_matching_if: + case preprocess_exception::missing_matching_endif: + case preprocess_exception::unbalanced_if_endif: + case preprocess_exception::bad_define_statement: + case preprocess_exception::bad_define_statement_va_args: + case preprocess_exception::bad_line_statement: + case preprocess_exception::bad_line_number: + case preprocess_exception::bad_line_filename: + case preprocess_exception::bad_undefine_statement: + case preprocess_exception::division_by_zero: + case preprocess_exception::integer_overflow: + case preprocess_exception::ill_formed_integer_literal: + case preprocess_exception::ill_formed_character_literal: + case preprocess_exception::character_literal_out_of_range: + case preprocess_exception::last_line_not_terminated: + case preprocess_exception::include_nesting_too_deep: + case preprocess_exception::illegal_operator_redefinition: + case preprocess_exception::incompatible_config: + case preprocess_exception::ill_formed_pragma_option: + case preprocess_exception::ill_formed_pragma_message: + case preprocess_exception::pragma_message_directive: + return true; + + case preprocess_exception::unexpected_error: + case preprocess_exception::ill_formed_operator: + case preprocess_exception::too_few_macroarguments: + case preprocess_exception::too_many_macroarguments: + case preprocess_exception::empty_macroarguments: + case preprocess_exception::improperly_terminated_macro: + case preprocess_exception::invalid_concat: + case preprocess_exception::could_not_open_output_file: + break; + } + return false; + } + + static char const *error_text(int code) + { + // error texts in this array must appear in the same order as the items in + // the error enum above + static char const *preprocess_exception_errors[] = { + "no error", // no_error + "unexpected error (should not happen)", // unexpected_error + "illegal macro redefinition", // macro_redefinition + "macro definition failed (out of memory?)", // macro_insertion_error + "could not find include file", // bad_include_file + "ill formed #include directive", // bad_include_statement + "ill formed preprocessor directive", // ill_formed_directive + "encountered #error directive or #pragma wave stop()", // error_directive + "encountered #warning directive", // warning_directive + "ill formed preprocessor expression", // ill_formed_expression + "the #if for this directive is missing", // missing_matching_if + "detected at least one missing #endif directive", // missing_matching_endif + "ill formed preprocessing operator", // ill_formed_operator + "ill formed #define directive", // bad_define_statement + "__VA_ARGS__ can only appear in the " + "expansion of a C99 variadic macro", // bad_define_statement_va_args + "too few macro arguments", // too_few_macroarguments + "too many macro arguments", // too_many_macroarguments + "empty macro arguments are not supported in pure C++ mode, " + "use variadics mode to allow these", // empty_macroarguments + "improperly terminated macro invocation " + "or replacement-list terminates in partial " + "macro expansion (not supported yet)", // improperly_terminated_macro + "ill formed #line directive", // bad_line_statement + "line number argument of #line directive " + "should consist out of decimal digits " + "only and must be in range of [1..INT_MAX]", // bad_line_number + "filename argument of #line directive should " + "be a narrow string literal", // bad_line_filename + "#undef may not be used on this predefined name", // bad_undefine_statement + "invalid macro definition", // bad_macro_definition + "this predefined name may not be redefined", // illegal_redefinition + "duplicate macro parameter name", // duplicate_parameter_name + "pasting the following two tokens does not " + "give a valid preprocessing token", // invalid_concat + "last line of file ends without a newline", // last_line_not_terminated + "unknown or illformed pragma option", // ill_formed_pragma_option + "include files nested too deep", // include_nesting_too_deep + "misplaced operator defined()", // misplaced_operator + "the name is already used in this scope as " + "a macro or scope name", // alreadydefined_name + "undefined macro or scope name may not be imported", // undefined_macroname + "ill formed macro name", // invalid_macroname + "qualified names are supported in C++0x mode only", // unexpected_qualified_name + "division by zero in preprocessor expression", // division_by_zero + "integer overflow in preprocessor expression", // integer_overflow + "this cannot be used as a macro name as it is " + "an operator in C++", // illegal_operator_redefinition + "ill formed integer literal or integer constant too large", // ill_formed_integer_literal + "ill formed character literal", // ill_formed_character_literal + "unbalanced #if/#endif in include file", // unbalanced_if_endif + "expression contains out of range character literal", // character_literal_out_of_range + "could not open output file", // could_not_open_output_file + "incompatible state information", // incompatible_config + "illformed pragma message", // ill_formed_pragma_message + "encountered #pragma message directive" // pragma_message_directive + }; + BOOST_ASSERT(no_error <= code && code <= last_error_number); + return preprocess_exception_errors[code]; + } + + static util::severity severity_level(int code) + { + static util::severity preprocess_exception_severity[] = { + util::severity_remark, // no_error + util::severity_fatal, // unexpected_error + util::severity_warning, // macro_redefinition + util::severity_fatal, // macro_insertion_error + util::severity_error, // bad_include_file + util::severity_error, // bad_include_statement + util::severity_error, // ill_formed_directive + util::severity_fatal, // error_directive + util::severity_warning, // warning_directive + util::severity_error, // ill_formed_expression + util::severity_error, // missing_matching_if + util::severity_error, // missing_matching_endif + util::severity_error, // ill_formed_operator + util::severity_error, // bad_define_statement + util::severity_error, // bad_define_statement_va_args + util::severity_warning, // too_few_macroarguments + util::severity_warning, // too_many_macroarguments + util::severity_warning, // empty_macroarguments + util::severity_error, // improperly_terminated_macro + util::severity_warning, // bad_line_statement + util::severity_warning, // bad_line_number + util::severity_warning, // bad_line_filename + util::severity_warning, // bad_undefine_statement + util::severity_commandline_error, // bad_macro_definition + util::severity_warning, // illegal_redefinition + util::severity_error, // duplicate_parameter_name + util::severity_error, // invalid_concat + util::severity_warning, // last_line_not_terminated + util::severity_warning, // ill_formed_pragma_option + util::severity_fatal, // include_nesting_too_deep + util::severity_error, // misplaced_operator + util::severity_error, // alreadydefined_name + util::severity_error, // undefined_macroname + util::severity_error, // invalid_macroname + util::severity_error, // unexpected_qualified_name + util::severity_fatal, // division_by_zero + util::severity_error, // integer_overflow + util::severity_error, // illegal_operator_redefinition + util::severity_error, // ill_formed_integer_literal + util::severity_error, // ill_formed_character_literal + util::severity_warning, // unbalanced_if_endif + util::severity_warning, // character_literal_out_of_range + util::severity_error, // could_not_open_output_file + util::severity_remark, // incompatible_config + util::severity_warning, // ill_formed_pragma_message + util::severity_remark, // pragma_message_directive + }; + BOOST_ASSERT(no_error <= code && code <= last_error_number); + return preprocess_exception_severity[code]; + } + static char const *severity_text(int code) + { + return util::get_severity(severity_level(code)); + } + +private: + char buffer[512]; + error_code code; +}; + +/////////////////////////////////////////////////////////////////////////////// +// Error during macro handling, this exception contains the related macro name +class BOOST_SYMBOL_VISIBLE macro_handling_exception : + public preprocess_exception +{ +public: + macro_handling_exception(char const *what_, error_code code, int line_, + int column_, char const *filename_, char const *macroname) throw() + : preprocess_exception(what_, code, line_, column_, filename_) + { + unsigned int off = 0; + while (off < sizeof(name) && *macroname) + name[off++] = *macroname++; + name[off] = 0; + } + ~macro_handling_exception() throw() {} + + virtual char const *what() const throw() + { + return "boost::wave::macro_handling_exception"; + } + char const* get_related_name() const throw() + { + return name; + } + +private: + char name[512]; +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// The is_recoverable() function allows to decide, whether it is possible +// simply to continue after a given exception was thrown by Wave. +// +// This is kind of a hack to allow to recover from certain errors as long as +// Wave doesn't provide better means of error recovery. +// +/////////////////////////////////////////////////////////////////////////////// +inline bool +is_recoverable(cpp_exception const& e) +{ + return e.is_recoverable(); +} + +/////////////////////////////////////////////////////////////////////////////// +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPP_EXCEPTIONS_HPP_5190E447_A781_4521_A275_5134FF9917D7_INCLUDED) diff --git a/boost/wave/cpp_iteration_context.hpp b/boost/wave/cpp_iteration_context.hpp new file mode 100644 index 0000000000..bf9f734cdb --- /dev/null +++ b/boost/wave/cpp_iteration_context.hpp @@ -0,0 +1,169 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + Definition of the preprocessor context + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_ITERATION_CONTEXT_HPP_00312288_9DDB_4668_AFE5_25D3994FD095_INCLUDED) +#define CPP_ITERATION_CONTEXT_HPP_00312288_9DDB_4668_AFE5_25D3994FD095_INCLUDED + +#include <iterator> +#include <fstream> +#if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS) +#include <sstream> +#endif + +#include <boost/wave/wave_config.hpp> +#include <boost/wave/cpp_exceptions.hpp> +#include <boost/wave/language_support.hpp> +#include <boost/wave/util/file_position.hpp> +// #include <boost/spirit/include/iterator/classic_multi_pass.hpp> // make_multi_pass + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace iteration_context_policies { + +/////////////////////////////////////////////////////////////////////////////// +// +// The iteration_context_policies templates are policies for the +// boost::wave::iteration_context which allows to control, how a given +// input file is to be represented by a pair of iterators pointing to the +// begin and the end of the resulting input sequence. +// +/////////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////// + // + // load_file_to_string + // + // Loads a file into a string and returns the iterators pointing to + // the beginning and the end of the loaded string. + // + /////////////////////////////////////////////////////////////////////////// + struct load_file_to_string + { + template <typename IterContextT> + class inner + { + public: + template <typename PositionT> + static void init_iterators(IterContextT &iter_ctx, + PositionT const &act_pos, language_support language) + { + typedef typename IterContextT::iterator_type iterator_type; + + // read in the file + std::ifstream instream(iter_ctx.filename.c_str()); + if (!instream.is_open()) { + BOOST_WAVE_THROW_CTX(iter_ctx.ctx, preprocess_exception, + bad_include_file, iter_ctx.filename.c_str(), act_pos); + return; + } + instream.unsetf(std::ios::skipws); + + iter_ctx.instring.assign( + std::istreambuf_iterator<char>(instream.rdbuf()), + std::istreambuf_iterator<char>()); + + iter_ctx.first = iterator_type( + iter_ctx.instring.begin(), iter_ctx.instring.end(), + PositionT(iter_ctx.filename), language); + iter_ctx.last = iterator_type(); + } + + private: + std::string instring; + }; + }; + +} // namespace iteration_context_policies + +/////////////////////////////////////////////////////////////////////////////// +// Base class for iteration contexts +template <typename ContextT, typename IteratorT> +struct base_iteration_context +{ + enum file_type + { + // this iteration context handles ... + main_file, // ... the main preprocessed file + system_header, // ... a header file included used #include <> + user_header // ... a header file included using #include "" + }; + + base_iteration_context(ContextT& ctx_, + BOOST_WAVE_STRINGTYPE const &fname, std::size_t if_block_depth = 0) + : real_filename(fname), real_relative_filename(fname), filename(fname), + line(1), emitted_lines(0), if_block_depth(if_block_depth), ctx(ctx_) + {} + base_iteration_context(ContextT& ctx_, + IteratorT const &first_, IteratorT const &last_, + BOOST_WAVE_STRINGTYPE const &fname, std::size_t if_block_depth = 0, + file_type type = main_file) + : first(first_), last(last_), real_filename(fname), + real_relative_filename(fname), filename(fname), + line(1), emitted_lines(0), if_block_depth(if_block_depth), ctx(ctx_) + {} + +// the actual input stream + IteratorT first; // actual input stream position + IteratorT last; // end of input stream + BOOST_WAVE_STRINGTYPE real_filename; // real name of the current file + BOOST_WAVE_STRINGTYPE real_relative_filename; // real relative name of the current file + BOOST_WAVE_STRINGTYPE filename; // actual processed file + unsigned int line; // line counter of underlying stream + unsigned int emitted_lines; // count of emitted newlines + std::size_t if_block_depth; // depth of #if block recursion + ContextT& ctx; // corresponding context<> object + file_type type; // the type of the handled file +}; + +/////////////////////////////////////////////////////////////////////////////// +// +template < + typename ContextT, typename IteratorT, + typename InputPolicyT = typename ContextT::input_policy_type +> +struct iteration_context +: public base_iteration_context<ContextT, IteratorT>, + public InputPolicyT::template + inner<iteration_context<ContextT, IteratorT, InputPolicyT> > +{ + typedef IteratorT iterator_type; + typedef typename IteratorT::token_type::position_type position_type; + + typedef base_iteration_context<ContextT, IteratorT> base_type; + typedef iteration_context<ContextT, IteratorT, InputPolicyT> self_type; + + iteration_context(ContextT& ctx, BOOST_WAVE_STRINGTYPE const &fname, + position_type const &act_pos, + boost::wave::language_support language_, + typename base_type::file_type type = base_type::main_file) + : base_iteration_context<ContextT, IteratorT>(ctx, fname, type) + { + InputPolicyT::template inner<self_type>::init_iterators( + *this, act_pos, language_); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPP_ITERATION_CONTEXT_HPP_00312288_9DDB_4668_AFE5_25D3994FD095_INCLUDED) diff --git a/boost/wave/cpp_throw.hpp b/boost/wave/cpp_throw.hpp new file mode 100644 index 0000000000..010e5719db --- /dev/null +++ b/boost/wave/cpp_throw.hpp @@ -0,0 +1,180 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(BOOST_WAVE_CPP_THROW_HPP_INCLUDED) +#define BOOST_WAVE_CPP_THROW_HPP_INCLUDED + +#include <string> +#include <boost/throw_exception.hpp> + +#ifdef BOOST_NO_STRINGSTREAM +#include <strstream> +#else +#include <sstream> +#endif + +namespace boost { namespace wave { namespace util +{ +#ifdef BOOST_NO_STRINGSTREAM + template <typename Exception, typename S1, typename Pos> + void throw_(typename Exception::error_code code, S1 msg, Pos const& pos) + { + std::strstream stream; + stream << Exception::severity_text(code) << ": " + << Exception::error_text(code); + if (msg[0] != 0) + stream << ": " << msg; + stream << std::ends; + std::string throwmsg = stream.str(); stream.freeze(false); + boost::throw_exception(Exception(throwmsg.c_str(), code, + pos.get_line(), pos.get_column(), pos.get_file().c_str())); + } + + template <typename Exception, typename Context, typename S1, typename Pos> + void throw_(Context& ctx, typename Exception::error_code code, + S1 msg, Pos const& pos) + { + std::strstream stream; + stream << Exception::severity_text(code) << ": " + << Exception::error_text(code); + if (msg[0] != 0) + stream << ": " << msg; + stream << std::ends; + std::string throwmsg = stream.str(); stream.freeze(false); + ctx.get_hooks().throw_exception(ctx.derived(), + Exception(throwmsg.c_str(), code, pos.get_line(), pos.get_column(), + pos.get_file().c_str())); + } + + template <typename Exception, typename S1, typename Pos, typename S2> + void throw_(typename Exception::error_code code, S1 msg, Pos const& pos, + S2 name) + { + std::strstream stream; + stream << Exception::severity_text(code) << ": " + << Exception::error_text(code); + if (msg[0] != 0) + stream << ": " << msg; + stream << std::ends; + std::string throwmsg = stream.str(); stream.freeze(false); + boost::throw_exception(Exception(throwmsg.c_str(), code, + pos.get_line(), pos.get_column(), pos.get_file().c_str(), name)); + } + + template <typename Exception, typename Context, typename S1, typename Pos, + typename S2> + void throw_(Context& ctx, typename Exception::error_code code, + S1 msg, Pos const& pos, S2 name) + { + std::strstream stream; + stream << Exception::severity_text(code) << ": " + << Exception::error_text(code); + if (msg[0] != 0) + stream << ": " << msg; + stream << std::ends; + std::string throwmsg = stream.str(); stream.freeze(false); + ctx.get_hooks().throw_exception(ctx.derived(), + Exception(throwmsg.c_str(), code, pos.get_line(), pos.get_column(), + pos.get_file().c_str(), name)); + } +#else + template <typename Exception, typename S1, typename Pos> + void throw_(typename Exception::error_code code, S1 msg, Pos const& pos) + { + std::stringstream stream; + stream << Exception::severity_text(code) << ": " + << Exception::error_text(code); + if (msg[0] != 0) + stream << ": " << msg; + stream << std::ends; + std::string throwmsg = stream.str(); + boost::throw_exception(Exception(throwmsg.c_str(), code, + pos.get_line(), pos.get_column(), pos.get_file().c_str())); + } + + template <typename Exception, typename Context, typename S1, typename Pos> + void throw_(Context& ctx, typename Exception::error_code code, + S1 msg, Pos const& pos) + { + std::stringstream stream; + stream << Exception::severity_text(code) << ": " + << Exception::error_text(code); + if (msg[0] != 0) + stream << ": " << msg; + stream << std::ends; + std::string throwmsg = stream.str(); + ctx.get_hooks().throw_exception(ctx.derived(), + Exception(throwmsg.c_str(), code, pos.get_line(), pos.get_column(), + pos.get_file().c_str())); + } + + template <typename Exception, typename S1, typename Pos, typename S2> + void throw_(typename Exception::error_code code, S1 msg, Pos const& pos, + S2 name) + { + std::stringstream stream; + stream << Exception::severity_text(code) << ": " + << Exception::error_text(code); + if (msg[0] != 0) + stream << ": " << msg; + stream << std::ends; + std::string throwmsg = stream.str(); + boost::throw_exception(Exception(throwmsg.c_str(), code, + pos.get_line(), pos.get_column(), pos.get_file().c_str(), name)); + } + + template <typename Exception, typename Context, typename S1, typename Pos1, + typename S2> + void throw_(Context& ctx, typename Exception::error_code code, + S1 msg, Pos1 const& pos, S2 name) + { + std::stringstream stream; + stream << Exception::severity_text(code) << ": " + << Exception::error_text(code); + if (msg[0] != 0) + stream << ": " << msg; + stream << std::ends; + std::string throwmsg = stream.str(); + ctx.get_hooks().throw_exception(ctx.derived(), + Exception(throwmsg.c_str(), code, pos.get_line(), pos.get_column(), + pos.get_file().c_str(), name)); + } +#endif +}}} + +/////////////////////////////////////////////////////////////////////////////// +// helper macro for throwing exceptions +#if !defined(BOOST_WAVE_THROW) +#define BOOST_WAVE_THROW(cls, code, msg, act_pos) \ + boost::wave::util::throw_<cls>(cls::code, msg, act_pos) \ + /**/ + +#define BOOST_WAVE_THROW_CTX(ctx, cls, code, msg, act_pos) \ + boost::wave::util::throw_<cls>(ctx, cls::code, msg, act_pos) \ + /**/ +#endif // BOOST_WAVE_THROW + +/////////////////////////////////////////////////////////////////////////////// +// helper macro for throwing exceptions with additional parameter +#if !defined(BOOST_WAVE_THROW_NAME_CTX) +#define BOOST_WAVE_THROW_NAME_CTX(ctx, cls, code, msg, act_pos, name) \ + boost::wave::util::throw_<cls>(cls::code, msg, act_pos, name) \ + /**/ +#endif // BOOST_WAVE_THROW_NAME_CTX + +/////////////////////////////////////////////////////////////////////////////// +// helper macro for throwing exceptions with additional parameter +#if !defined(BOOST_WAVE_THROW_VAR_CTX) +#define BOOST_WAVE_THROW_VAR_CTX(ctx, cls, code, msg, act_pos) \ + boost::wave::util::throw_<cls>(ctx, code, msg, act_pos) \ + /**/ +#endif // BOOST_WAVE_THROW_VAR_CTX + +#endif // !defined(BOOST_WAVE_CPP_THROW_HPP_INCLUDED) diff --git a/boost/wave/cpplexer/convert_trigraphs.hpp b/boost/wave/cpplexer/convert_trigraphs.hpp new file mode 100644 index 0000000000..8f80cfba49 --- /dev/null +++ b/boost/wave/cpplexer/convert_trigraphs.hpp @@ -0,0 +1,139 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + Grammar for universal character validation (see C++ standard: Annex E) + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(CONVERT_TRIGRAPHS_HK050403_INCLUDED) +#define CONVERT_TRIGRAPHS_HK050403_INCLUDED + +#include <boost/wave/wave_config.hpp> +#include <boost/wave/cpplexer/cpplexer_exceptions.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// +// +// Test, whether the given string represents a valid trigraph sequence +// +/////////////////////////////////////////////////////////////////////////////// +template <typename StringT> +inline bool +is_trigraph(StringT const& trigraph) +{ + if (trigraph.size() < 3 || '?' != trigraph[0] || '?' != trigraph[1]) + return false; + + switch (trigraph[2]) { + case '\'': case '=': case '/': case '(': + case ')': case '<': case '>': case '!': + case '-': + break; + + default: + return false; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// convert_trigraph +// +// The function convert_trigraph() converts a single trigraph character +// sequence into the corresponding character. +// +// If the given character sequence doesn't form a valid trigraph sequence +// no conversion is performed. +// +/////////////////////////////////////////////////////////////////////////////// +template <typename StringT> +inline StringT +convert_trigraph(StringT const &trigraph) +{ +StringT result (trigraph); + + if (is_trigraph(trigraph)) { + switch (trigraph[2]) { + case '\'': result = "^"; break; + case '=': result = "#"; break; + case '/': result = "\\"; break; + case '(': result = "["; break; + case ')': result = "]"; break; + case '<': result = "{"; break; + case '>': result = "}"; break; + case '!': result = "|"; break; + case '-': result = "~"; break; + } + } + return result; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// convert_trigraphs +// +// The function convert_trigraph() converts all trigraphs in the given +// string into the corresponding characters. +// +// If one of the given character sequences doesn't form a valid trigraph +// sequence no conversion is performed. +// +/////////////////////////////////////////////////////////////////////////////// +template <typename StringT> +inline StringT +convert_trigraphs(StringT const &value) +{ + StringT result; + typename StringT::size_type pos = 0; + typename StringT::size_type pos1 = value.find_first_of ("?", 0); + if (StringT::npos != pos1) { + do { + result += value.substr(pos, pos1-pos); + StringT trigraph (value.substr(pos1)); + if (is_trigraph(trigraph)) { + result += convert_trigraph(trigraph); + pos1 = value.find_first_of ("?", pos = pos1+3); + } + else { + result += value[pos1]; + pos1 = value.find_first_of ("?", pos = pos1+1); + } + } while (StringT::npos != pos1); + result += value.substr(pos); + } + else { + result = value; + } + return result; +} + +/////////////////////////////////////////////////////////////////////////////// +} // namespace impl +} // namespace cpplexer +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CONVERT_TRIGRAPHS_HK050403_INCLUDED) + + diff --git a/boost/wave/cpplexer/cpp_lex_interface.hpp b/boost/wave/cpplexer/cpp_lex_interface.hpp new file mode 100644 index 0000000000..c69f8aaa53 --- /dev/null +++ b/boost/wave/cpplexer/cpp_lex_interface.hpp @@ -0,0 +1,73 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + Definition of the abstract lexer interface + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_LEX_INTERFACE_HPP_E83F52A4_90AC_4FBE_A9A7_B65F7F94C497_INCLUDED) +#define CPP_LEX_INTERFACE_HPP_E83F52A4_90AC_4FBE_A9A7_B65F7F94C497_INCLUDED + +#include <boost/wave/wave_config.hpp> +#include <boost/wave/util/file_position.hpp> +#include <boost/wave/language_support.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +// suppress warnings about dependent classes not being exported from the dll +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable : 4251 4231 4660) +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { + +/////////////////////////////////////////////////////////////////////////////// +// +// The lex_input_interface decouples the lex_iterator_shim from the actual +// lexer. This is done to allow compile time reduction. +// Thanks to JCAB for having this idea. +// +/////////////////////////////////////////////////////////////////////////////// + +template <typename TokenT> +struct lex_input_interface +{ + typedef typename TokenT::position_type position_type; + + lex_input_interface() {} + virtual ~lex_input_interface() {} + + virtual TokenT& get(TokenT&) = 0; + virtual void set_position(position_type const &pos) = 0; +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + virtual bool has_include_guards(std::string& guard_name) const = 0; +#endif +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace cpplexer +} // namespace wave +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPP_LEX_INTERFACE_HPP_E83F52A4_90AC_4FBE_A9A7_B65F7F94C497_INCLUDED) diff --git a/boost/wave/cpplexer/cpp_lex_interface_generator.hpp b/boost/wave/cpplexer/cpp_lex_interface_generator.hpp new file mode 100644 index 0000000000..8e1bd7726c --- /dev/null +++ b/boost/wave/cpplexer/cpp_lex_interface_generator.hpp @@ -0,0 +1,110 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + Definition of the abstract lexer interface + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(BOOST_WAVE_LEX_INTERFACE_GENERATOR_HPP_INCLUDED) +#define BOOST_WAVE_LEX_INTERFACE_GENERATOR_HPP_INCLUDED + +#include <boost/wave/wave_config.hpp> +#include <boost/wave/util/file_position.hpp> +#include <boost/wave/language_support.hpp> +#include <boost/wave/cpplexer/cpp_lex_interface.hpp> +#include <boost/wave/cpplexer/cpp_lex_token.hpp> // lex_token + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +// suppress warnings about dependent classes not being exported from the dll +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable : 4251 4231 4660) +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { + +#if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 +#define BOOST_WAVE_NEW_LEXER_DECL BOOST_WAVE_DECL +#else +#define BOOST_WAVE_NEW_LEXER_DECL +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// new_lexer_gen: generates a new instance of the required C++ lexer +// +/////////////////////////////////////////////////////////////////////////////// +template < + typename IteratorT, + typename PositionT = boost::wave::util::file_position_type, + typename TokenT = lex_token<PositionT> +> +struct BOOST_WAVE_NEW_LEXER_DECL new_lexer_gen +{ +// The NewLexer function allows the opaque generation of a new lexer object. +// It is coupled to the token type to allow to decouple the lexer/token +// configurations at compile time. + static lex_input_interface<TokenT> * + new_lexer(IteratorT const &first, IteratorT const &last, + PositionT const &pos, boost::wave::language_support language); +}; + +#undef BOOST_WAVE_NEW_LEXER_DECL + +/////////////////////////////////////////////////////////////////////////////// +// +// The lex_input_interface_generator helps to instantiate a concrete lexer +// to be used by the Wave preprocessor module. +// This is done to allow compile time reduction. +// +/////////////////////////////////////////////////////////////////////////////// + +template <typename TokenT> +struct lex_input_interface_generator +: lex_input_interface<TokenT> +{ + typedef typename lex_input_interface<TokenT>::position_type position_type; + + lex_input_interface_generator() {} + ~lex_input_interface_generator() {} + +// The new_lexer function allows the opaque generation of a new lexer object. +// It is coupled to the token type to allow to distinguish different +// lexer/token configurations at compile time. + template <typename IteratorT> + static lex_input_interface<TokenT> * + new_lexer(IteratorT const &first, IteratorT const &last, + position_type const &pos, boost::wave::language_support language) + { + return new_lexer_gen<IteratorT, position_type, TokenT>::new_lexer ( + first, last, pos, language); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace cpplexer +} // namespace wave +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(BOOST_WAVE_LEX_INTERFACE_GENERATOR_HPP_INCLUDED) diff --git a/boost/wave/cpplexer/cpp_lex_iterator.hpp b/boost/wave/cpplexer/cpp_lex_iterator.hpp new file mode 100644 index 0000000000..fe93888af5 --- /dev/null +++ b/boost/wave/cpplexer/cpp_lex_iterator.hpp @@ -0,0 +1,243 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + Definition of the lexer iterator + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_LEX_ITERATOR_HPP_AF0C37E3_CBD8_4F33_A225_51CF576FA61F_INCLUDED) +#define CPP_LEX_ITERATOR_HPP_AF0C37E3_CBD8_4F33_A225_51CF576FA61F_INCLUDED + +#include <string> + +#include <boost/assert.hpp> +#include <boost/intrusive_ptr.hpp> + +#include <boost/wave/wave_config.hpp> +#include <boost/spirit/include/support_multi_pass.hpp> + +#include <boost/wave/util/file_position.hpp> +#include <boost/wave/util/functor_input.hpp> +#include <boost/wave/cpplexer/cpp_lex_interface_generator.hpp> + +#include <boost/wave/language_support.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +#if 0 != __COMO_VERSION__ || !BOOST_WORKAROUND(BOOST_MSVC, <= 1310) +#define BOOST_WAVE_EOF_PREFIX static +#else +#define BOOST_WAVE_EOF_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// +// +// lex_iterator_functor_shim +// +/////////////////////////////////////////////////////////////////////////////// + +template <typename TokenT> +class lex_iterator_functor_shim +{ + typedef typename TokenT::position_type position_type; + +public: + lex_iterator_functor_shim() +#if /*0 != __DECCXX_VER || */defined(__PGI) + : eof() +#endif + {} + +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1310) + lex_iterator_functor_shim& operator= (lex_iterator_functor_shim const& rhs) + { return *this; } // nothing to do here +#endif + +// interface to the iterator_policies::split_functor_input policy + typedef TokenT result_type; + typedef lex_iterator_functor_shim unique; + typedef lex_input_interface<TokenT>* shared; + + BOOST_WAVE_EOF_PREFIX result_type const eof; + + template <typename MultiPass> + static result_type& get_next(MultiPass& mp, result_type& result) + { + return mp.shared()->ftor->get(result); + } + + // this will be called whenever the last reference to a multi_pass will + // be released + template <typename MultiPass> + static void destroy(MultiPass& mp) + { + delete mp.shared()->ftor; + } + + template <typename MultiPass> + static void set_position(MultiPass& mp, position_type const &pos) + { + mp.shared()->ftor->set_position(pos); + } +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + template <typename MultiPass> + static bool has_include_guards(MultiPass& mp, std::string& guard_name) + { + return mp.shared()->ftor->has_include_guards(guard_name); + } +#endif +}; + +/////////////////////////////////////////////////////////////////////////////// +// eof token +#if 0 != __COMO_VERSION__ || !BOOST_WORKAROUND(BOOST_MSVC, <= 1310) +template <typename TokenT> +typename lex_iterator_functor_shim<TokenT>::result_type const + lex_iterator_functor_shim<TokenT>::eof; +#endif // 0 != __COMO_VERSION__ + +/////////////////////////////////////////////////////////////////////////////// +} // namespace impl + +/////////////////////////////////////////////////////////////////////////////// +// +// lex_iterator +// +// A generic C++ lexer interface class, which allows to plug in different +// lexer implementations. The interface between the lexer type used and +// the preprocessor component depends on the token type only (template +// parameter TokenT). +// Additionally, the following requirements apply: +// +// - the lexer type should have a function implemented, which returnes +// the next lexed token from the input stream: +// typename TokenT get(); +// - at the end of the input stream this function should return the +// eof token equivalent +// - the lexer should implement a constructor taking two iterators +// pointing to the beginning and the end of the input stream, +// a third parameter containing the name of the parsed input file +// and a 4th parameter of the type boost::wave::language_support +// which specifies, which language subset should be supported (C++, +// C99, C++0x etc.). +// +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Divide the given functor type into its components (unique and shared) +// and build a std::pair from these parts +template <typename FunctorData> +struct make_multi_pass +{ + typedef + std::pair<typename FunctorData::unique, typename FunctorData::shared> + functor_data_type; + typedef typename FunctorData::result_type result_type; + + typedef boost::spirit::iterator_policies::split_functor_input input_policy; + typedef boost::spirit::iterator_policies::ref_counted ownership_policy; +#if defined(BOOST_WAVE_DEBUG) + typedef boost::spirit::iterator_policies::buf_id_check check_policy; +#else + typedef boost::spirit::iterator_policies::no_check check_policy; +#endif + typedef boost::spirit::iterator_policies::split_std_deque storage_policy; + + typedef boost::spirit::iterator_policies::default_policy< + ownership_policy, check_policy, input_policy, storage_policy> + policy_type; + typedef boost::spirit::multi_pass<functor_data_type, policy_type> type; +}; + +/////////////////////////////////////////////////////////////////////////////// +template <typename TokenT> +class lex_iterator +: public make_multi_pass<impl::lex_iterator_functor_shim<TokenT> >::type +{ + typedef impl::lex_iterator_functor_shim<TokenT> input_policy_type; + + typedef typename make_multi_pass<input_policy_type>::type base_type; + typedef typename make_multi_pass<input_policy_type>::functor_data_type + functor_data_type; + + typedef typename input_policy_type::unique unique_functor_type; + typedef typename input_policy_type::shared shared_functor_type; + +public: + typedef TokenT token_type; + + lex_iterator() + {} + + template <typename IteratorT> + lex_iterator(IteratorT const &first, IteratorT const &last, + typename TokenT::position_type const &pos, + boost::wave::language_support language) + : base_type( + functor_data_type( + unique_functor_type(), + lex_input_interface_generator<TokenT> + ::new_lexer(first, last, pos, language) + ) + ) + {} + + void set_position(typename TokenT::position_type const &pos) + { + typedef typename TokenT::position_type position_type; + + // set the new position in the current token + token_type const& currtoken = this->base_type::dereference(*this); + position_type currpos = currtoken.get_position(); + + currpos.set_file(pos.get_file()); + currpos.set_line(pos.get_line()); + const_cast<token_type&>(currtoken).set_position(currpos); + + // set the new position for future tokens as well + if (token_type::string_type::npos != + currtoken.get_value().find_first_of('\n')) + { + currpos.set_line(pos.get_line() + 1); + } + unique_functor_type::set_position(*this, currpos); + } + +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + // return, whether the current file has include guards + // this function returns meaningful results only if the file was scanned + // completely + bool has_include_guards(std::string& guard_name) const + { + return unique_functor_type::has_include_guards(*this, guard_name); + } +#endif +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace cpplexer +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#undef BOOST_WAVE_EOF_PREFIX + +#endif // !defined(CPP_LEX_ITERATOR_HPP_AF0C37E3_CBD8_4F33_A225_51CF576FA61F_INCLUDED) diff --git a/boost/wave/cpplexer/cpp_lex_token.hpp b/boost/wave/cpplexer/cpp_lex_token.hpp new file mode 100644 index 0000000000..81e589539f --- /dev/null +++ b/boost/wave/cpplexer/cpp_lex_token.hpp @@ -0,0 +1,335 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + A generic C++ lexer token definition + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_TOKEN_HPP_53A13BD2_FBAA_444B_9B8B_FCB225C2BBA8_INCLUDED) +#define CPP_TOKEN_HPP_53A13BD2_FBAA_444B_9B8B_FCB225C2BBA8_INCLUDED + +#include <boost/wave/wave_config.hpp> +#if BOOST_WAVE_SERIALIZATION != 0 +#include <boost/serialization/serialization.hpp> +#endif +#include <boost/wave/util/file_position.hpp> +#include <boost/wave/token_ids.hpp> +#include <boost/wave/language_support.hpp> + +#include <boost/throw_exception.hpp> +#include <boost/pool/singleton_pool.hpp> +#include <boost/detail/atomic_count.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { + +namespace impl { + +template <typename StringTypeT, typename PositionT> +class token_data +{ +public: + typedef StringTypeT string_type; + typedef PositionT position_type; + + // default constructed tokens correspond to EOI tokens + token_data() + : id(T_EOI), refcnt(1) + {} + + // construct an invalid token + explicit token_data(int) + : id(T_UNKNOWN), refcnt(1) + {} + + token_data(token_id id_, string_type const &value_, position_type const &pos_) + : id(id_), value(value_), pos(pos_), refcnt(1) + {} + + token_data(token_data const& rhs) + : id(rhs.id), value(rhs.value), pos(rhs.pos), refcnt(1) + {} + + ~token_data() + {} + + std::size_t addref() { return ++refcnt; } + std::size_t release() { return --refcnt; } + std::size_t get_refcnt() const { return refcnt; } + +// accessors + operator token_id() const { return id; } + string_type const &get_value() const { return value; } + position_type const &get_position() const { return pos; } + + void set_token_id (token_id id_) { id = id_; } + void set_value (string_type const &value_) { value = value_; } + void set_position (position_type const &pos_) { pos = pos_; } + + friend bool operator== (token_data const& lhs, token_data const& rhs) + { + // two tokens are considered equal even if they refer to different + // positions + return (lhs.id == rhs.id && lhs.value == rhs.value) ? true : false; + } + + void init(token_id id_, string_type const &value_, position_type const &pos_) + { + BOOST_ASSERT(refcnt == 1); + id = id_; + value = value_; + pos = pos_; + } + + void init(token_data const& rhs) + { + BOOST_ASSERT(refcnt == 1); + id = rhs.id; + value = rhs.value; + pos = rhs.pos; + } + + static void *operator new(std::size_t size); + static void operator delete(void *p, std::size_t size); + +#if defined(BOOST_SPIRIT_DEBUG) +// debug support + void print (std::ostream &stream) const + { + stream << get_token_name(id) << "("; + for (std::size_t i = 0; i < value.size(); ++i) { + switch (value[i]) { + case '\r': stream << "\\r"; break; + case '\n': stream << "\\n"; break; + default: + stream << value[i]; + break; + } + } + stream << ")"; + } +#endif // defined(BOOST_SPIRIT_DEBUG) + +#if BOOST_WAVE_SERIALIZATION != 0 + friend class boost::serialization::access; + template<typename Archive> + void serialize(Archive &ar, const unsigned int version) + { + using namespace boost::serialization; + ar & make_nvp("id", id); + ar & make_nvp("value", value); + ar & make_nvp("position", pos); + } +#endif + +private: + token_id id; // the token id + string_type value; // the text, which was parsed into this token + position_type pos; // the original file position + boost::detail::atomic_count refcnt; +}; + +/////////////////////////////////////////////////////////////////////////////// +struct token_data_tag {}; + +template <typename StringTypeT, typename PositionT> +inline void * +token_data<StringTypeT, PositionT>::operator new(std::size_t size) +{ + BOOST_ASSERT(sizeof(token_data<StringTypeT, PositionT>) == size); + typedef boost::singleton_pool< + token_data_tag, sizeof(token_data<StringTypeT, PositionT>) + > pool_type; + + void *ret = pool_type::malloc(); + if (0 == ret) + boost::throw_exception(std::bad_alloc()); + return ret; +} + +template <typename StringTypeT, typename PositionT> +inline void +token_data<StringTypeT, PositionT>::operator delete(void *p, std::size_t size) +{ + BOOST_ASSERT(sizeof(token_data<StringTypeT, PositionT>) == size); + typedef boost::singleton_pool< + token_data_tag, sizeof(token_data<StringTypeT, PositionT>) + > pool_type; + + if (0 != p) + pool_type::free(p); +} + +} // namespace impl + +/////////////////////////////////////////////////////////////////////////////// +// forward declaration of the token type +template <typename PositionT = boost::wave::util::file_position_type> +class lex_token; + +/////////////////////////////////////////////////////////////////////////////// +// +// lex_token +// +/////////////////////////////////////////////////////////////////////////////// + +template <typename PositionT> +class lex_token +{ +public: + typedef BOOST_WAVE_STRINGTYPE string_type; + typedef PositionT position_type; + +private: + typedef impl::token_data<string_type, position_type> data_type; + +public: + // default constructed tokens correspond to EOI tokens + lex_token() + : data(0) + {} + + // construct an invalid token + explicit lex_token(int) + : data(new data_type(0)) + {} + + lex_token(lex_token const& rhs) + : data(rhs.data) + { + if (0 != data) + data->addref(); + } + + lex_token(token_id id_, string_type const &value_, PositionT const &pos_) + : data(new data_type(id_, value_, pos_)) + {} + + ~lex_token() + { + if (0 != data && 0 == data->release()) + delete data; + data = 0; + } + + lex_token& operator=(lex_token const& rhs) + { + if (&rhs != this) { + if (0 != data && 0 == data->release()) + delete data; + + data = rhs.data; + if (0 != data) + data->addref(); + } + return *this; + } + +// accessors + operator token_id() const { return 0 != data ? token_id(*data) : T_EOI; } + string_type const &get_value() const { return data->get_value(); } + position_type const &get_position() const { return data->get_position(); } + bool is_eoi() const { return 0 == data || token_id(*data) == T_EOI; } + bool is_valid() const { return 0 != data && token_id(*data) != T_UNKNOWN; } + + void set_token_id (token_id id_) { make_unique(); data->set_token_id(id_); } + void set_value (string_type const &value_) { make_unique(); data->set_value(value_); } + void set_position (position_type const &pos_) { make_unique(); data->set_position(pos_); } + + friend bool operator== (lex_token const& lhs, lex_token const& rhs) + { + if (0 == rhs.data) + return 0 == lhs.data; + if (0 == lhs.data) + return false; + return *(lhs.data) == *(rhs.data); + } + +// debug support +#if BOOST_WAVE_DUMP_PARSE_TREE != 0 +// access functions for the tree_to_xml functionality + static int get_token_id(lex_token const &t) + { return token_id(t); } + static string_type get_token_value(lex_token const &t) + { return t.get_value(); } +#endif + +#if defined(BOOST_SPIRIT_DEBUG) +// debug support + void print (std::ostream &stream) const + { + data->print(stream); + } +#endif // defined(BOOST_SPIRIT_DEBUG) + +private: +#if BOOST_WAVE_SERIALIZATION != 0 + friend class boost::serialization::access; + template<typename Archive> + void serialize(Archive &ar, const unsigned int version) + { + data->serialize(ar, version); + } +#endif + + // make a unique copy of the current object + void make_unique() + { + if (1 == data->get_refcnt()) + return; + + data_type* newdata = new data_type(*data) ; + + data->release(); // release this reference, can't get zero + data = newdata; + } + + data_type* data; +}; + +/////////////////////////////////////////////////////////////////////////////// +// This overload is needed by the multi_pass/functor_input_policy to +// validate a token instance. It has to be defined in the same namespace +// as the token class itself to allow ADL to find it. +/////////////////////////////////////////////////////////////////////////////// +template <typename Position> +inline bool +token_is_valid(lex_token<Position> const& t) +{ + return t.is_valid(); +} + +/////////////////////////////////////////////////////////////////////////////// +#if defined(BOOST_SPIRIT_DEBUG) +template <typename PositionT> +inline std::ostream & +operator<< (std::ostream &stream, lex_token<PositionT> const &object) +{ + object.print(stream); + return stream; +} +#endif // defined(BOOST_SPIRIT_DEBUG) + +/////////////////////////////////////////////////////////////////////////////// +} // namespace cpplexer +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPP_TOKEN_HPP_53A13BD2_FBAA_444B_9B8B_FCB225C2BBA8_INCLUDED) diff --git a/boost/wave/cpplexer/cpplexer_exceptions.hpp b/boost/wave/cpplexer/cpplexer_exceptions.hpp new file mode 100644 index 0000000000..5ef0ca26e6 --- /dev/null +++ b/boost/wave/cpplexer/cpplexer_exceptions.hpp @@ -0,0 +1,290 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPPLEXER_EXCEPTIONS_HPP_1A09DE1A_6D1F_4091_AF7F_5F13AB0D31AB_INCLUDED) +#define CPPLEXER_EXCEPTIONS_HPP_1A09DE1A_6D1F_4091_AF7F_5F13AB0D31AB_INCLUDED + +#include <exception> +#include <string> + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/throw_exception.hpp> + +#include <boost/wave/wave_config.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +// helper macro for throwing exceptions +#if !defined(BOOST_WAVE_LEXER_THROW) +#ifdef BOOST_NO_STRINGSTREAM +#include <strstream> +#define BOOST_WAVE_LEXER_THROW(cls, code, msg, line, column, name) \ + { \ + using namespace boost::wave; \ + std::strstream stream; \ + stream << cls::severity_text(cls::code) << ": " \ + << cls::error_text(cls::code); \ + if ((msg)[0] != 0) stream << ": " << (msg); \ + stream << std::ends; \ + std::string throwmsg = stream.str(); stream.freeze(false); \ + boost::throw_exception(cls(throwmsg.c_str(), cls::code, line, column, \ + name)); \ + } \ + /**/ +#else +#include <sstream> +#define BOOST_WAVE_LEXER_THROW(cls, code, msg, line, column, name) \ + { \ + using namespace boost::wave; \ + std::stringstream stream; \ + stream << cls::severity_text(cls::code) << ": " \ + << cls::error_text(cls::code); \ + if ((msg)[0] != 0) stream << ": " << (msg); \ + stream << std::ends; \ + boost::throw_exception(cls(stream.str().c_str(), cls::code, line, column, \ + name)); \ + } \ + /**/ +#endif // BOOST_NO_STRINGSTREAM +#endif // BOOST_WAVE_LEXER_THROW + +#if !defined(BOOST_WAVE_LEXER_THROW_VAR) +#ifdef BOOST_NO_STRINGSTREAM +#include <strstream> +#define BOOST_WAVE_LEXER_THROW_VAR(cls, codearg, msg, line, column, name) \ + { \ + using namespace boost::wave; \ + cls::error_code code = static_cast<cls::error_code>(codearg); \ + std::strstream stream; \ + stream << cls::severity_text(code) << ": " \ + << cls::error_text(code); \ + if ((msg)[0] != 0) stream << ": " << (msg); \ + stream << std::ends; \ + std::string throwmsg = stream.str(); stream.freeze(false); \ + boost::throw_exception(cls(throwmsg.c_str(), code, line, column, \ + name)); \ + } \ + /**/ +#else +#include <sstream> +#define BOOST_WAVE_LEXER_THROW_VAR(cls, codearg, msg, line, column, name) \ + { \ + using namespace boost::wave; \ + cls::error_code code = static_cast<cls::error_code>(codearg); \ + std::stringstream stream; \ + stream << cls::severity_text(code) << ": " \ + << cls::error_text(code); \ + if ((msg)[0] != 0) stream << ": " << (msg); \ + stream << std::ends; \ + boost::throw_exception(cls(stream.str().c_str(), code, line, column, \ + name)); \ + } \ + /**/ +#endif // BOOST_NO_STRINGSTREAM +#endif // BOOST_WAVE_LEXER_THROW + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { + +/////////////////////////////////////////////////////////////////////////////// +// exception severity +namespace util { + + enum severity { + severity_remark = 0, + severity_warning, + severity_error, + severity_fatal + }; + + inline char const * + get_severity(severity level) + { + static char const *severity_text[] = + { + "remark", // severity_remark + "warning", // severity_warning + "error", // severity_error + "fatal error" // severity_fatal + }; + BOOST_ASSERT(severity_remark <= level && level <= severity_fatal); + return severity_text[level]; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// cpplexer_exception, the base class for all specific C++ lexer exceptions +class BOOST_SYMBOL_VISIBLE cpplexer_exception +: public std::exception +{ +public: + cpplexer_exception(int line_, int column_, char const *filename_) throw() + : line(line_), column(column_) + { + unsigned int off = 0; + while (off < sizeof(filename)-1 && *filename_) + filename[off++] = *filename_++; + filename[off] = 0; + } + ~cpplexer_exception() throw() {} + + virtual char const *what() const throw() = 0; // to be overloaded + virtual char const *description() const throw() = 0; + virtual int get_errorcode() const throw() = 0; + virtual int get_severity() const throw() = 0; + virtual bool is_recoverable() const throw() = 0; + + int line_no() const throw() { return line; } + int column_no() const throw() { return column; } + char const *file_name() const throw() { return filename; } + +protected: + char filename[512]; + int line; + int column; +}; + +/////////////////////////////////////////////////////////////////////////////// +// lexing_exception error +class BOOST_SYMBOL_VISIBLE lexing_exception : + public cpplexer_exception +{ +public: + enum error_code { + unexpected_error = 0, + universal_char_invalid = 1, + universal_char_base_charset = 2, + universal_char_not_allowed = 3, + invalid_long_long_literal = 4, + generic_lexing_error = 5, + generic_lexing_warning = 6 + }; + + lexing_exception(char const *what_, error_code code, int line_, + int column_, char const *filename_) throw() + : cpplexer_exception(line_, column_, filename_), + level(severity_level(code)), code(code) + { + unsigned int off = 0; + while (off < sizeof(buffer) && *what_) + buffer[off++] = *what_++; + buffer[off] = 0; + } + ~lexing_exception() throw() {} + + virtual char const *what() const throw() + { + return "boost::wave::lexing_exception"; + } + virtual char const *description() const throw() + { + return buffer; + } + virtual int get_severity() const throw() + { + return level; + } + virtual int get_errorcode() const throw() + { + return code; + } + virtual bool is_recoverable() const throw() + { + switch (get_errorcode()) { + case lexing_exception::universal_char_invalid: + case lexing_exception::universal_char_base_charset: + case lexing_exception::universal_char_not_allowed: + case lexing_exception::invalid_long_long_literal: + case lexing_exception::generic_lexing_warning: + case lexing_exception::generic_lexing_error: + return true; // for now allow all exceptions to be recoverable + + case lexing_exception::unexpected_error: + default: + break; + } + return false; + } + + static char const *error_text(int code) + { + // error texts in this array must appear in the same order as the items in + // the error enum above + static char const *preprocess_exception_errors[] = { + "unexpected error (should not happen)", // unexpected_error + "universal character name specifies an invalid character", // universal_char_invalid + "a universal character name cannot designate a character in the " + "basic character set", // universal_char_base_charset + "this universal character is not allowed in an identifier", // universal_char_not_allowed + "long long suffixes are not allowed in pure C++ mode, " + "enable long_long mode to allow these", // invalid_long_long_literal + "generic lexer error", // generic_lexing_error + "generic lexer warning" // generic_lexing_warning + }; + return preprocess_exception_errors[code]; + } + + static util::severity severity_level(int code) + { + static util::severity preprocess_exception_severity[] = { + util::severity_fatal, // unexpected_error + util::severity_error, // universal_char_invalid + util::severity_error, // universal_char_base_charset + util::severity_error, // universal_char_not_allowed + util::severity_warning, // invalid_long_long_literal + util::severity_error, // generic_lexing_error + util::severity_warning // invalid_long_long_literal + }; + return preprocess_exception_severity[code]; + } + static char const *severity_text(int code) + { + return util::get_severity(severity_level(code)); + } + +private: + char buffer[512]; + util::severity level; + error_code code; +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// The is_recoverable() function allows to decide, whether it is possible +// simply to continue after a given exception was thrown by Wave. +// +// This is kind of a hack to allow to recover from certain errors as long as +// Wave doesn't provide better means of error recovery. +// +/////////////////////////////////////////////////////////////////////////////// +inline bool +is_recoverable(lexing_exception const& e) +{ + return e.is_recoverable(); +} + +/////////////////////////////////////////////////////////////////////////////// +} // namespace cpplexer +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPPLEXER_EXCEPTIONS_HPP_1A09DE1A_6D1F_4091_AF7F_5F13AB0D31AB_INCLUDED) diff --git a/boost/wave/cpplexer/detect_include_guards.hpp b/boost/wave/cpplexer/detect_include_guards.hpp new file mode 100644 index 0000000000..09463ff8ea --- /dev/null +++ b/boost/wave/cpplexer/detect_include_guards.hpp @@ -0,0 +1,263 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + State machine detecting include guards in an included file. + This detects two forms of include guards: + + #ifndef INCLUDE_GUARD_MACRO + #define INCLUDE_GUARD_MACRO + ... + #endif + + or + + if !defined(INCLUDE_GUARD_MACRO) + #define INCLUDE_GUARD_MACRO + ... + #endif + + note, that the parenthesis are optional (i.e. !defined INCLUDE_GUARD_MACRO + will work as well). The code allows for any whitespace, newline and single + '#' tokens before the #if/#ifndef and after the final #endif. + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(DETECT_INCLUDE_GUARDS_HK060304_INCLUDED) +#define DETECT_INCLUDE_GUARDS_HK060304_INCLUDED + +#include <boost/wave/wave_config.hpp> +#include <boost/wave/token_ids.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { + +template <typename Token> +class include_guards +{ +public: + include_guards() + : state(&include_guards::state_0), detected_guards(false), + current_state(true), if_depth(0) + {} + + Token& detect_guard(Token& t) + { return current_state ? (this->*state)(t) : t; } + bool detected(std::string& guard_name_) const + { + if (detected_guards) { + guard_name_ = guard_name.c_str(); + return true; + } + return false; + } + +private: + typedef Token& state_type(Token& t); + state_type include_guards::* state; + + bool detected_guards; + bool current_state; + typename Token::string_type guard_name; + int if_depth; + + state_type state_0, state_1, state_2, state_3, state_4, state_5; + state_type state_1a, state_1b, state_1c, state_1d, state_1e; + + bool is_skippable(token_id id) const + { + return (T_POUND == BASE_TOKEN(id) || + IS_CATEGORY(id, WhiteSpaceTokenType) || + IS_CATEGORY(id, EOLTokenType)); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// state 0: beginning of a file, tries to recognize #ifndef or #if tokens +template <typename Token> +inline Token& +include_guards<Token>::state_0(Token& t) +{ + token_id id = token_id(t); + if (T_PP_IFNDEF == id) + state = &include_guards::state_1; + else if (T_PP_IF == id) + state = &include_guards::state_1a; + else if (!is_skippable(id)) + current_state = false; + return t; +} + +/////////////////////////////////////////////////////////////////////////////// +// state 1: found #ifndef, looking for T_IDENTIFIER +template <typename Token> +inline Token& +include_guards<Token>::state_1(Token& t) +{ + token_id id = token_id(t); + if (T_IDENTIFIER == id) { + guard_name = t.get_value(); + state = &include_guards::state_2; + } + else if (!is_skippable(id)) + current_state = false; + return t; +} + +/////////////////////////////////////////////////////////////////////////////// +// state 1a: found T_PP_IF, looking for T_NOT ("!") +template <typename Token> +inline Token& +include_guards<Token>::state_1a(Token& t) +{ + token_id id = token_id(t); + if (T_NOT == BASE_TOKEN(id)) + state = &include_guards::state_1b; + else if (!is_skippable(id)) + current_state = false; + return t; +} + +/////////////////////////////////////////////////////////////////////////////// +// state 1b: found T_NOT, looking for 'defined' +template <typename Token> +inline Token& +include_guards<Token>::state_1b(Token& t) +{ + token_id id = token_id(t); + if (T_IDENTIFIER == id && t.get_value() == "defined") + state = &include_guards::state_1c; + else if (!is_skippable(id)) + current_state = false; + return t; +} + +/////////////////////////////////////////////////////////////////////////////// +// state 1c: found 'defined', looking for (optional) T_LEFTPAREN +template <typename Token> +inline Token& +include_guards<Token>::state_1c(Token& t) +{ + token_id id = token_id(t); + if (T_LEFTPAREN == id) + state = &include_guards::state_1d; + else if (T_IDENTIFIER == id) { + guard_name = t.get_value(); + state = &include_guards::state_2; + } + else if (!is_skippable(id)) + current_state = false; + return t; +} + +/////////////////////////////////////////////////////////////////////////////// +// state 1d: found T_LEFTPAREN, looking for T_IDENTIFIER guard +template <typename Token> +inline Token& +include_guards<Token>::state_1d(Token& t) +{ + token_id id = token_id(t); + if (T_IDENTIFIER == id) { + guard_name = t.get_value(); + state = &include_guards::state_1e; + } + else if (!is_skippable(id)) + current_state = false; + return t; +} + +/////////////////////////////////////////////////////////////////////////////// +// state 1e: found T_IDENTIFIER guard, looking for T_RIGHTPAREN +template <typename Token> +inline Token& +include_guards<Token>::state_1e(Token& t) +{ + token_id id = token_id(t); + if (T_RIGHTPAREN == id) + state = &include_guards::state_2; + else if (!is_skippable(id)) + current_state = false; + return t; +} + +/////////////////////////////////////////////////////////////////////////////// +// state 2: found T_IDENTIFIER, looking for #define +template <typename Token> +inline Token& +include_guards<Token>::state_2(Token& t) +{ + token_id id = token_id(t); + if (T_PP_DEFINE == id) + state = &include_guards::state_3; + else if (!is_skippable(id)) + current_state = false; + return t; +} + +/////////////////////////////////////////////////////////////////////////////// +// state 3: found #define, looking for T_IDENTIFIER as recognized by state 1 +template <typename Token> +inline Token& +include_guards<Token>::state_3(Token& t) +{ + token_id id = token_id(t); + if (T_IDENTIFIER == id && t.get_value() == guard_name) + state = &include_guards::state_4; + else if (!is_skippable(id)) + current_state = false; + return t; +} + +/////////////////////////////////////////////////////////////////////////////// +// state 4: found guard T_IDENTIFIER, looking for #endif +template <typename Token> +inline Token& +include_guards<Token>::state_4(Token& t) +{ + token_id id = token_id(t); + if (T_PP_IF == id || T_PP_IFDEF == id || T_PP_IFNDEF == id) + ++if_depth; + else if (T_PP_ENDIF == id) { + if (if_depth > 0) + --if_depth; + else + state = &include_guards::state_5; + } + return t; +} + +/////////////////////////////////////////////////////////////////////////////// +// state 5: found final #endif, looking for T_EOF +template <typename Token> +inline Token& +include_guards<Token>::state_5(Token& t) +{ + token_id id = token_id(t); + if (T_EOF == id) + detected_guards = current_state; + else if (!is_skippable(id)) + current_state = false; + return t; +} + +/////////////////////////////////////////////////////////////////////////////// +} // namespace cpplexer +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !DETECT_INCLUDE_GUARDS_HK060304_INCLUDED diff --git a/boost/wave/cpplexer/re2clex/aq.hpp b/boost/wave/cpplexer/re2clex/aq.hpp new file mode 100644 index 0000000000..7b24359a48 --- /dev/null +++ b/boost/wave/cpplexer/re2clex/aq.hpp @@ -0,0 +1,64 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001 Daniel C. Nuffer. + Copyright (c) 2001-2011 Hartmut Kaiser. + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(AQ_HPP_A21D9145_B643_44C0_81E7_DB346DD67EE1_INCLUDED) +#define AQ_HPP_A21D9145_B643_44C0_81E7_DB346DD67EE1_INCLUDED + +#include <boost/wave/wave_config.hpp> +#include <cstdlib> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { +namespace re2clex { + +typedef std::size_t aq_stdelement; + +typedef struct tag_aq_queuetype +{ + std::size_t head; + std::size_t tail; + std::size_t size; + std::size_t max_size; + aq_stdelement* queue; +} aq_queuetype; + +typedef aq_queuetype* aq_queue; + +int aq_enqueue(aq_queue q, aq_stdelement e); +int aq_enqueue_front(aq_queue q, aq_stdelement e); +int aq_serve(aq_queue q, aq_stdelement *e); +int aq_pop(aq_queue q); +#define AQ_EMPTY(q) (q->size == 0) +#define AQ_FULL(q) (q->size == q->max_size) +int aq_grow(aq_queue q); + +BOOST_WAVE_DECL aq_queue aq_create(void); +BOOST_WAVE_DECL void aq_terminate(aq_queue q); + +/////////////////////////////////////////////////////////////////////////////// +} // namespace re2clex +} // namespace cpplexer +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(AQ_HPP_A21D9145_B643_44C0_81E7_DB346DD67EE1_INCLUDED) diff --git a/boost/wave/cpplexer/re2clex/cpp_re.hpp b/boost/wave/cpplexer/re2clex/cpp_re.hpp new file mode 100644 index 0000000000..5febbb4a20 --- /dev/null +++ b/boost/wave/cpplexer/re2clex/cpp_re.hpp @@ -0,0 +1,57 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + Re2C based C++ lexer + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_RE_HPP_B76C4F5E_63E9_4B8A_9975_EC32FA6BF027_INCLUDED) +#define CPP_RE_HPP_B76C4F5E_63E9_4B8A_9975_EC32FA6BF027_INCLUDED + +#include <boost/wave/wave_config.hpp> +#include <boost/wave/token_ids.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +// suppress warnings about dependent classes not being exported from the dll +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable : 4251 4231 4660) +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { +namespace re2clex { + +struct Scanner; + +/////////////////////////////////////////////////////////////////////////////// +// The scanner function to call whenever a new token is requested +BOOST_WAVE_DECL boost::wave::token_id scan(Scanner *s); + +/////////////////////////////////////////////////////////////////////////////// +} // namespace re2clex +} // namespace cpplexer +} // namespace wave +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPP_RE_HPP_B76C4F5E_63E9_4B8A_9975_EC32FA6BF027_INCLUDED) diff --git a/boost/wave/cpplexer/re2clex/cpp_re2c_lexer.hpp b/boost/wave/cpplexer/re2clex/cpp_re2c_lexer.hpp new file mode 100644 index 0000000000..748738544b --- /dev/null +++ b/boost/wave/cpplexer/re2clex/cpp_re2c_lexer.hpp @@ -0,0 +1,429 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + Re2C based C++ lexer + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_RE2C_LEXER_HPP_B81A2629_D5B1_4944_A97D_60254182B9A8_INCLUDED) +#define CPP_RE2C_LEXER_HPP_B81A2629_D5B1_4944_A97D_60254182B9A8_INCLUDED + +#include <string> +#include <cstdio> +#include <cstdarg> +#if defined(BOOST_SPIRIT_DEBUG) +#include <iostream> +#endif // defined(BOOST_SPIRIT_DEBUG) + +#include <boost/concept_check.hpp> +#include <boost/assert.hpp> +#include <boost/spirit/include/classic_core.hpp> + +#include <boost/wave/wave_config.hpp> +#include <boost/wave/language_support.hpp> +#include <boost/wave/token_ids.hpp> +#include <boost/wave/util/file_position.hpp> +#include <boost/wave/cpplexer/validate_universal_char.hpp> +#include <boost/wave/cpplexer/cpplexer_exceptions.hpp> +#include <boost/wave/cpplexer/token_cache.hpp> +#include <boost/wave/cpplexer/convert_trigraphs.hpp> + +#include <boost/wave/cpplexer/cpp_lex_interface.hpp> +#include <boost/wave/cpplexer/re2clex/scanner.hpp> +#include <boost/wave/cpplexer/re2clex/cpp_re.hpp> +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 +#include <boost/wave/cpplexer/detect_include_guards.hpp> +#endif + +#include <boost/wave/cpplexer/cpp_lex_interface_generator.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { +namespace re2clex { + +/////////////////////////////////////////////////////////////////////////////// +// +// encapsulation of the re2c based cpp lexer +// +/////////////////////////////////////////////////////////////////////////////// + +template <typename IteratorT, + typename PositionT = boost::wave::util::file_position_type, + typename TokenT = lex_token<PositionT> > +class lexer +{ +public: + typedef TokenT token_type; + typedef typename token_type::string_type string_type; + + lexer(IteratorT const &first, IteratorT const &last, + PositionT const &pos, boost::wave::language_support language_); + ~lexer(); + + token_type& get(token_type&); + void set_position(PositionT const &pos) + { + // set position has to change the file name and line number only + filename = pos.get_file(); + scanner.line = pos.get_line(); +// scanner.column = scanner.curr_column = pos.get_column(); + scanner.file_name = filename.c_str(); + } +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + bool has_include_guards(std::string& guard_name) const + { + return guards.detected(guard_name); + } +#endif + +// error reporting from the re2c generated lexer + static int report_error(Scanner const* s, int code, char const *, ...); + +private: + static char const *tok_names[]; + + Scanner scanner; + string_type filename; + string_type value; + bool at_eof; + boost::wave::language_support language; +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + include_guards<token_type> guards; +#endif + +#if BOOST_WAVE_SUPPORT_THREADING == 0 + static token_cache<string_type> const cache; +#else + token_cache<string_type> const cache; +#endif +}; + +/////////////////////////////////////////////////////////////////////////////// +// initialize cpp lexer +template <typename IteratorT, typename PositionT, typename TokenT> +inline +lexer<IteratorT, PositionT, TokenT>::lexer(IteratorT const &first, + IteratorT const &last, PositionT const &pos, + boost::wave::language_support language_) + : filename(pos.get_file()), at_eof(false), language(language_) +#if BOOST_WAVE_SUPPORT_THREADING != 0 + , cache() +#endif +{ + using namespace std; // some systems have memset in std + memset(&scanner, '\0', sizeof(Scanner)); + scanner.eol_offsets = aq_create(); + if (first != last) { + scanner.first = scanner.act = (uchar *)&(*first); + scanner.last = scanner.first + std::distance(first, last); + } + scanner.line = pos.get_line(); + scanner.column = scanner.curr_column = pos.get_column(); + scanner.error_proc = report_error; + scanner.file_name = filename.c_str(); + +#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 + scanner.enable_ms_extensions = true; +#else + scanner.enable_ms_extensions = false; +#endif + +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + scanner.act_in_c99_mode = boost::wave::need_c99(language_); +#endif + +#if BOOST_WAVE_SUPPORT_IMPORT_KEYWORD != 0 + scanner.enable_import_keyword = !boost::wave::need_c99(language_); +#else + scanner.enable_import_keyword = false; +#endif + + scanner.detect_pp_numbers = boost::wave::need_prefer_pp_numbers(language_); + scanner.single_line_only = boost::wave::need_single_line(language_); + +#if BOOST_WAVE_SUPPORT_CPP0X != 0 + scanner.act_in_cpp0x_mode = boost::wave::need_cpp0x(language_); +#else + scanner.act_in_cpp0x_mode = false; +#endif +} + +template <typename IteratorT, typename PositionT, typename TokenT> +inline +lexer<IteratorT, PositionT, TokenT>::~lexer() +{ + using namespace std; // some systems have free in std + aq_terminate(scanner.eol_offsets); + free(scanner.bot); +} + +/////////////////////////////////////////////////////////////////////////////// +// get the next token from the input stream +template <typename IteratorT, typename PositionT, typename TokenT> +inline TokenT& +lexer<IteratorT, PositionT, TokenT>::get(TokenT& result) +{ + if (at_eof) + return result = token_type(); // return T_EOI + + unsigned int actline = scanner.line; + token_id id = token_id(scan(&scanner)); + + switch (static_cast<unsigned int>(id)) { + case T_IDENTIFIER: + // test identifier characters for validity (throws if invalid chars found) + value = string_type((char const *)scanner.tok, + scanner.cur-scanner.tok); + if (!boost::wave::need_no_character_validation(language)) + impl::validate_identifier_name(value, actline, scanner.column, filename); + break; + + case T_STRINGLIT: + case T_CHARLIT: + case T_RAWSTRINGLIT: + // test literal characters for validity (throws if invalid chars found) + value = string_type((char const *)scanner.tok, + scanner.cur-scanner.tok); + if (boost::wave::need_convert_trigraphs(language)) + value = impl::convert_trigraphs(value); + if (!boost::wave::need_no_character_validation(language)) + impl::validate_literal(value, actline, scanner.column, filename); + break; + +#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 + case T_PP_HHEADER: + case T_PP_QHEADER: + case T_PP_INCLUDE: + // convert to the corresponding ..._next token, if appropriate + { + value = string_type((char const *)scanner.tok, + scanner.cur-scanner.tok); + + // Skip '#' and whitespace and see whether we find an 'include_next' here. + typename string_type::size_type start = value.find("include"); + if (value.compare(start, 12, "include_next", 12) == 0) + id = token_id(id | AltTokenType); + break; + } +#endif + + case T_LONGINTLIT: // supported in C++0x, C99 and long_long mode + value = string_type((char const *)scanner.tok, + scanner.cur-scanner.tok); + if (!boost::wave::need_long_long(language)) { + // syntax error: not allowed in C++ mode + BOOST_WAVE_LEXER_THROW(lexing_exception, invalid_long_long_literal, + value.c_str(), actline, scanner.column, filename.c_str()); + } + break; + + case T_OCTALINT: + case T_DECIMALINT: + case T_HEXAINT: + case T_INTLIT: + case T_FLOATLIT: + case T_FIXEDPOINTLIT: + case T_CCOMMENT: + case T_CPPCOMMENT: + case T_SPACE: + case T_SPACE2: + case T_ANY: + case T_PP_NUMBER: + value = string_type((char const *)scanner.tok, + scanner.cur-scanner.tok); + break; + + case T_EOF: + // T_EOF is returned as a valid token, the next call will return T_EOI, + // i.e. the actual end of input + at_eof = true; + value.clear(); + break; + + case T_OR_TRIGRAPH: + case T_XOR_TRIGRAPH: + case T_LEFTBRACE_TRIGRAPH: + case T_RIGHTBRACE_TRIGRAPH: + case T_LEFTBRACKET_TRIGRAPH: + case T_RIGHTBRACKET_TRIGRAPH: + case T_COMPL_TRIGRAPH: + case T_POUND_TRIGRAPH: + if (boost::wave::need_convert_trigraphs(language)) { + value = cache.get_token_value(BASEID_FROM_TOKEN(id)); + } + else { + value = string_type((char const *)scanner.tok, + scanner.cur-scanner.tok); + } + break; + + case T_ANY_TRIGRAPH: + if (boost::wave::need_convert_trigraphs(language)) { + value = impl::convert_trigraph( + string_type((char const *)scanner.tok)); + } + else { + value = string_type((char const *)scanner.tok, + scanner.cur-scanner.tok); + } + break; + + default: + if (CATEGORY_FROM_TOKEN(id) != EXTCATEGORY_FROM_TOKEN(id) || + IS_CATEGORY(id, UnknownTokenType)) + { + value = string_type((char const *)scanner.tok, + scanner.cur-scanner.tok); + } + else { + value = cache.get_token_value(id); + } + break; + } + +// std::cerr << boost::wave::get_token_name(id) << ": " << value << std::endl; + + // the re2c lexer reports the new line number for newline tokens + result = token_type(id, value, PositionT(filename, actline, scanner.column)); + +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + return guards.detect_guard(result); +#else + return result; +#endif +} + +template <typename IteratorT, typename PositionT, typename TokenT> +inline int +lexer<IteratorT, PositionT, TokenT>::report_error(Scanner const *s, int errcode, + char const *msg, ...) +{ + BOOST_ASSERT(0 != s); + BOOST_ASSERT(0 != msg); + + using namespace std; // some system have vsprintf in namespace std + + char buffer[200]; // should be large enough + va_list params; + va_start(params, msg); + vsprintf(buffer, msg, params); + va_end(params); + + BOOST_WAVE_LEXER_THROW_VAR(lexing_exception, errcode, buffer, s->line, + s->column, s->file_name); +// BOOST_UNREACHABLE_RETURN(0); + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// lex_functor +// +/////////////////////////////////////////////////////////////////////////////// + +template <typename IteratorT, + typename PositionT = boost::wave::util::file_position_type, + typename TokenT = typename lexer<IteratorT, PositionT>::token_type> +class lex_functor +: public lex_input_interface_generator<TokenT> +{ +public: + typedef TokenT token_type; + + lex_functor(IteratorT const &first, IteratorT const &last, + PositionT const &pos, boost::wave::language_support language) + : re2c_lexer(first, last, pos, language) + {} + virtual ~lex_functor() {} + +// get the next token from the input stream + token_type& get(token_type& result) { return re2c_lexer.get(result); } + void set_position(PositionT const &pos) { re2c_lexer.set_position(pos); } +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + bool has_include_guards(std::string& guard_name) const + { return re2c_lexer.has_include_guards(guard_name); } +#endif + +private: + lexer<IteratorT, PositionT, TokenT> re2c_lexer; +}; + +#if BOOST_WAVE_SUPPORT_THREADING == 0 +/////////////////////////////////////////////////////////////////////////////// +template <typename IteratorT, typename PositionT, typename TokenT> +token_cache<typename lexer<IteratorT, PositionT, TokenT>::string_type> const + lexer<IteratorT, PositionT, TokenT>::cache = + token_cache<typename lexer<IteratorT, PositionT, TokenT>::string_type>(); +#endif + +} // namespace re2clex + +/////////////////////////////////////////////////////////////////////////////// +// +// The new_lexer_gen<>::new_lexer function (declared in cpp_lex_interface.hpp) +// should be defined inline, if the lex_functor shouldn't be instantiated +// separately from the lex_iterator. +// +// Separate (explicit) instantiation helps to reduce compilation time. +// +/////////////////////////////////////////////////////////////////////////////// + +#if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 +#define BOOST_WAVE_RE2C_NEW_LEXER_INLINE +#else +#define BOOST_WAVE_RE2C_NEW_LEXER_INLINE inline +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// The 'new_lexer' function allows the opaque generation of a new lexer object. +// It is coupled to the iterator type to allow to decouple the lexer/iterator +// configurations at compile time. +// +// This function is declared inside the cpp_lex_token.hpp file, which is +// referenced by the source file calling the lexer and the source file, which +// instantiates the lex_functor. But is is defined here, so it will be +// instantiated only while compiling the source file, which instantiates the +// lex_functor. While the cpp_re2c_token.hpp file may be included everywhere, +// this file (cpp_re2c_lexer.hpp) should be included only once. This allows +// to decouple the lexer interface from the lexer implementation and reduces +// compilation time. +// +/////////////////////////////////////////////////////////////////////////////// + +template <typename IteratorT, typename PositionT, typename TokenT> +BOOST_WAVE_RE2C_NEW_LEXER_INLINE +lex_input_interface<TokenT> * +new_lexer_gen<IteratorT, PositionT, TokenT>::new_lexer(IteratorT const &first, + IteratorT const &last, PositionT const &pos, + boost::wave::language_support language) +{ + using re2clex::lex_functor; + return new lex_functor<IteratorT, PositionT, TokenT>(first, last, pos, language); +} + +#undef BOOST_WAVE_RE2C_NEW_LEXER_INLINE + +/////////////////////////////////////////////////////////////////////////////// +} // namespace cpplexer +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPP_RE2C_LEXER_HPP_B81A2629_D5B1_4944_A97D_60254182B9A8_INCLUDED) diff --git a/boost/wave/cpplexer/re2clex/scanner.hpp b/boost/wave/cpplexer/re2clex/scanner.hpp new file mode 100644 index 0000000000..e052558e6d --- /dev/null +++ b/boost/wave/cpplexer/re2clex/scanner.hpp @@ -0,0 +1,74 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001 Daniel C. Nuffer. + Copyright (c) 2001-2011 Hartmut Kaiser. + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(SCANNER_HPP_F4FB01EB_E75C_4537_A146_D34B9895EF37_INCLUDED) +#define SCANNER_HPP_F4FB01EB_E75C_4537_A146_D34B9895EF37_INCLUDED + +#include <boost/wave/wave_config.hpp> +#include <boost/wave/cpplexer/re2clex/aq.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { +namespace re2clex { + +struct Scanner; +typedef unsigned char uchar; +typedef int (* ReportErrorProc)(struct Scanner const *, int errorcode, + char const *, ...); + +typedef struct Scanner { + uchar* first; /* start of input buffer */ + uchar* act; /* act position of input buffer */ + uchar* last; /* end (one past last char) of input buffer */ + uchar* bot; /* beginning of the current buffer */ + uchar* top; /* top of the current buffer */ + uchar* eof; /* when we read in the last buffer, will point 1 past the + end of the file, otherwise 0 */ + uchar* tok; /* points to the beginning of the current token */ + uchar* ptr; /* used for YYMARKER - saves backtracking info */ + uchar* cur; /* saves the cursor (maybe is redundant with tok?) */ + uchar* lim; /* used for YYLIMIT - points to the end of the buffer */ + /* (lim == top) except for the last buffer, it points to + the end of the input (lim == eof - 1) */ + unsigned int line; /* current line being lex'ed */ + unsigned int column; /* current token start column position */ + unsigned int curr_column; /* current column position */ + ReportErrorProc error_proc; /* must be != 0, this function is called to + report an error */ + char const *file_name; /* name of the lex'ed file */ + aq_queue eol_offsets; + bool enable_ms_extensions; /* enable MS extensions */ + bool act_in_c99_mode; /* lexer works in C99 mode */ + bool detect_pp_numbers; /* lexer should prefer to detect pp-numbers */ + bool enable_import_keyword; /* recognize import as a keyword */ + bool single_line_only; /* don't report missing eol's in C++ comments */ + bool act_in_cpp0x_mode; /* lexer works in C++0x mode */ +} Scanner; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace re2clex +} // namespace cpplexer +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(SCANNER_HPP_F4FB01EB_E75C_4537_A146_D34B9895EF37_INCLUDED) diff --git a/boost/wave/cpplexer/token_cache.hpp b/boost/wave/cpplexer/token_cache.hpp new file mode 100644 index 0000000000..4dedb48f24 --- /dev/null +++ b/boost/wave/cpplexer/token_cache.hpp @@ -0,0 +1,72 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(TOKEN_CACHE_HPP_4D2320B7_1D56_4113_A114_397E70FA438C_INCLUDED) +#define TOKEN_CACHE_HPP_4D2320B7_1D56_4113_A114_397E70FA438C_INCLUDED + +#include <vector> + +#include <boost/wave/wave_config.hpp> +#include <boost/wave/token_ids.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { + +/////////////////////////////////////////////////////////////////////////////// +// +// The token_cache template is used to cache the tokens corresponding to the +// keywords, operators and other constant language elements. +// +// This avoids repeated construction of these tokens, which is especially +// effective when used in conjunction with a copy on write string +// implementation (COW string). +// +/////////////////////////////////////////////////////////////////////////////// +template <typename StringT> +class token_cache +{ +public: + token_cache() + : cache(T_LAST_TOKEN - T_FIRST_TOKEN) + { + typename std::vector<StringT>::iterator it = cache.begin(); + for (unsigned int i = T_FIRST_TOKEN; i < T_LAST_TOKEN; ++i, ++it) + { + *it = StringT(boost::wave::get_token_value(token_id(i))); + } + } + + StringT const &get_token_value(token_id id) const + { + return cache[BASEID_FROM_TOKEN(id) - T_FIRST_TOKEN]; + } + +private: + std::vector<StringT> cache; +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace cpplexer +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(TOKEN_CACHE_HPP_4D2320B7_1D56_4113_A114_397E70FA438C_INCLUDED) diff --git a/boost/wave/cpplexer/validate_universal_char.hpp b/boost/wave/cpplexer/validate_universal_char.hpp new file mode 100644 index 0000000000..09b0a06c92 --- /dev/null +++ b/boost/wave/cpplexer/validate_universal_char.hpp @@ -0,0 +1,322 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + Grammar for universal character validation (see C++ standard: Annex E) + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(VALIDATE_UNIVERSAL_CHAR_HPP_55F1B811_CD76_4C72_8344_CBC69CF3B339_INCLUDED) +#define VALIDATE_UNIVERSAL_CHAR_HPP_55F1B811_CD76_4C72_8344_CBC69CF3B339_INCLUDED + +#include <boost/assert.hpp> + +#include <boost/wave/wave_config.hpp> +#include <boost/wave/util/file_position.hpp> +#include <boost/wave/cpplexer/cpplexer_exceptions.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { +namespace impl { + +enum universal_char_type { + universal_char_type_valid = 0, + universal_char_type_invalid = 1, + universal_char_type_base_charset = 2, + universal_char_type_not_allowed_for_identifiers = 3 +}; + +/////////////////////////////////////////////////////////////////////////// +// +// is_range is a helper function for the classification by brute force +// below +// +/////////////////////////////////////////////////////////////////////////// +inline bool +in_range(unsigned long ch, unsigned long l, unsigned long u) +{ + return (l <= ch && ch <= u); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// classify_universal_char +// +// This function classifies an universal character value into 4 subranges: +// universal_char_type_valid +// the universal character value is valid for identifiers +// universal_char_type_invalid +// the universal character value is not valid for its usage inside +// identifiers (see C++ Standard: 2.2.2 [lex.charset]) +// universal_char_type_base_charset +// the universal character value designates a character from the base +// character set +// universal_char_type_not_allowed_for_identifiers +// the universal character value is not allowed in an identifier +// +// Implementation note: +// This classification isn't implemented very effectively here. This +// function should be rewritten with some range run matching algorithm. +// +/////////////////////////////////////////////////////////////////////////////// +inline universal_char_type +classify_universal_char (unsigned long ch) +{ +// test for invalid characters + if (ch <= 0x0020 || in_range(ch, 0x007f, 0x009f)) + return universal_char_type_invalid; + +// test for characters in the range of the base character set + if (in_range(ch, 0x0021, 0x005f) || in_range(ch, 0x0061, 0x007e)) + return universal_char_type_base_charset; + +// test for additional valid character values (see C++ Standard: Annex E) + if (in_range(ch, 0x00c0, 0x00d6) || in_range(ch, 0x00d8, 0x00f6) || + in_range(ch, 0x00f8, 0x01f5) || in_range(ch, 0x01fa, 0x0217) || + in_range(ch, 0x0250, 0x02a8) || in_range(ch, 0x1e00, 0x1e9a) || + in_range(ch, 0x1ea0, 0x1ef9)) + { + return universal_char_type_valid; // Latin + } + + if (0x0384 == ch || in_range(ch, 0x0388, 0x038a) || + 0x038c == ch || in_range(ch, 0x038e, 0x03a1) || + in_range(ch, 0x03a3, 0x03ce) || in_range(ch, 0x03d0, 0x03d6) || + 0x03da == ch || 0x03dc == ch || 0x03de == ch || 0x03e0 == ch || + in_range(ch, 0x03e2, 0x03f3) || in_range(ch, 0x1f00, 0x1f15) || + in_range(ch, 0x1f18, 0x1f1d) || in_range(ch, 0x1f20, 0x1f45) || + in_range(ch, 0x1f48, 0x1f4d) || in_range(ch, 0x1f50, 0x1f57) || + 0x1f59 == ch || 0x1f5b == ch || 0x1f5d == ch || + in_range(ch, 0x1f5f, 0x1f7d) || in_range(ch, 0x1f80, 0x1fb4) || + in_range(ch, 0x1fb6, 0x1fbc) || in_range(ch, 0x1fc2, 0x1fc4) || + in_range(ch, 0x1fc6, 0x1fcc) || in_range(ch, 0x1fd0, 0x1fd3) || + in_range(ch, 0x1fd6, 0x1fdb) || in_range(ch, 0x1fe0, 0x1fec) || + in_range(ch, 0x1ff2, 0x1ff4) || in_range(ch, 0x1ff6, 0x1ffc)) + { + return universal_char_type_valid; // Greek + } + + if (in_range(ch, 0x0401, 0x040d) || in_range(ch, 0x040f, 0x044f) || + in_range(ch, 0x0451, 0x045c) || in_range(ch, 0x045e, 0x0481) || + in_range(ch, 0x0490, 0x04c4) || in_range(ch, 0x04c7, 0x04c8) || + in_range(ch, 0x04cb, 0x04cc) || in_range(ch, 0x04d0, 0x04eb) || + in_range(ch, 0x04ee, 0x04f5) || in_range(ch, 0x04f8, 0x04f9)) + { + return universal_char_type_valid; // Cyrillic + } + + if (in_range(ch, 0x0531, 0x0556) || in_range(ch, 0x0561, 0x0587)) + return universal_char_type_valid; // Armenian + + if (in_range(ch, 0x05d0, 0x05ea) || in_range(ch, 0x05f0, 0x05f4)) + return universal_char_type_valid; // Hebrew + + if (in_range(ch, 0x0621, 0x063a) || in_range(ch, 0x0640, 0x0652) || + in_range(ch, 0x0670, 0x06b7) || in_range(ch, 0x06ba, 0x06be) || + in_range(ch, 0x06c0, 0x06ce) || in_range(ch, 0x06e5, 0x06e7)) + { + return universal_char_type_valid; // Arabic + } + + if (in_range(ch, 0x0905, 0x0939) || in_range(ch, 0x0958, 0x0962)) + return universal_char_type_valid; // Devanagari + + if (in_range(ch, 0x0985, 0x098c) || in_range(ch, 0x098f, 0x0990) || + in_range(ch, 0x0993, 0x09a8) || in_range(ch, 0x09aa, 0x09b0) || + 0x09b2 == ch || in_range(ch, 0x09b6, 0x09b9) || + in_range(ch, 0x09dc, 0x09dd) || in_range(ch, 0x09df, 0x09e1) || + in_range(ch, 0x09f0, 0x09f1)) + { + return universal_char_type_valid; // Bengali + } + + if (in_range(ch, 0x0a05, 0x0a0a) || in_range(ch, 0x0a0f, 0x0a10) || + in_range(ch, 0x0a13, 0x0a28) || in_range(ch, 0x0a2a, 0x0a30) || + in_range(ch, 0x0a32, 0x0a33) || in_range(ch, 0x0a35, 0x0a36) || + in_range(ch, 0x0a38, 0x0a39) || in_range(ch, 0x0a59, 0x0a5c) || + 0x0a5e == ch) + { + return universal_char_type_valid; // Gurmukhi + } + + if (in_range(ch, 0x0a85, 0x0a8b) || 0x0a8d == ch || + in_range(ch, 0x0a8f, 0x0a91) || in_range(ch, 0x0a93, 0x0aa8) || + in_range(ch, 0x0aaa, 0x0ab0) || in_range(ch, 0x0ab2, 0x0ab3) || + in_range(ch, 0x0ab5, 0x0ab9) || 0x0ae0 == ch) + { + return universal_char_type_valid; // Gujarati + } + + if (in_range(ch, 0x0b05, 0x0b0c) || in_range(ch, 0x0b0f, 0x0b10) || + in_range(ch, 0x0b13, 0x0b28) || in_range(ch, 0x0b2a, 0x0b30) || + in_range(ch, 0x0b32, 0x0b33) || in_range(ch, 0x0b36, 0x0b39) || + in_range(ch, 0x0b5c, 0x0b5d) || in_range(ch, 0x0b5f, 0x0b61)) + { + return universal_char_type_valid; // Oriya + } + + if (in_range(ch, 0x0b85, 0x0b8a) || in_range(ch, 0x0b8e, 0x0b90) || + in_range(ch, 0x0b92, 0x0b95) || in_range(ch, 0x0b99, 0x0b9a) || + 0x0b9c == ch || in_range(ch, 0x0b9e, 0x0b9f) || + in_range(ch, 0x0ba3, 0x0ba4) || in_range(ch, 0x0ba8, 0x0baa) || + in_range(ch, 0x0bae, 0x0bb5) || in_range(ch, 0x0bb7, 0x0bb9)) + { + return universal_char_type_valid; // Tamil + } + + if (in_range(ch, 0x0c05, 0x0c0c) || in_range(ch, 0x0c0e, 0x0c10) || + in_range(ch, 0x0c12, 0x0c28) || in_range(ch, 0x0c2a, 0x0c33) || + in_range(ch, 0x0c35, 0x0c39) || in_range(ch, 0x0c60, 0x0c61)) + { + return universal_char_type_valid; // Telugu + } + + if (in_range(ch, 0x0c85, 0x0c8c) || in_range(ch, 0x0c8e, 0x0c90) || + in_range(ch, 0x0c92, 0x0ca8) || in_range(ch, 0x0caa, 0x0cb3) || + in_range(ch, 0x0cb5, 0x0cb9) || in_range(ch, 0x0ce0, 0x0ce1)) + { + return universal_char_type_valid; // Kannada + } + + if (in_range(ch, 0x0d05, 0x0d0c) || in_range(ch, 0x0d0e, 0x0d10) || + in_range(ch, 0x0d12, 0x0d28) || in_range(ch, 0x0d2a, 0x0d39) || + in_range(ch, 0x0d60, 0x0d61)) + { + return universal_char_type_valid; // Malayalam + } + + if (in_range(ch, 0x0e01, 0x0e30) || in_range(ch, 0x0e32, 0x0e33) || + in_range(ch, 0x0e40, 0x0e46) || in_range(ch, 0x0e4f, 0x0e5b)) + { + return universal_char_type_valid; // Thai + } + + return universal_char_type_not_allowed_for_identifiers; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// validate_identifier_name +// +// The validate_identifier_name function tests a given identifier name for +// its validity with regard to eventually contained universal characters. +// These should be in valid ranges (see the function +// classify_universal_char above). +// +// If the identifier name contains invalid or not allowed universal +// characters a corresponding lexing_exception is thrown. +// +/////////////////////////////////////////////////////////////////////////////// +template <typename StringT> +inline void +validate_identifier_name (StringT const &name, int line, int column, + StringT const &file_name) +{ + using namespace std; // some systems have strtoul in namespace std:: + +typename StringT::size_type pos = name.find_first_of('\\'); + + while (StringT::npos != pos) { + // the identifier name contains a backslash (must be universal char) + BOOST_ASSERT('u' == name[pos+1] || 'U' == name[pos+1]); + + StringT uchar_val(name.substr(pos+2, ('u' == name[pos+1]) ? 4 : 8)); + universal_char_type type = + classify_universal_char(strtoul(uchar_val.c_str(), 0, 16)); + + if (universal_char_type_valid != type) { + // an invalid char was found, so throw an exception + StringT error_uchar(name.substr(pos, ('u' == name[pos+1]) ? 6 : 10)); + + if (universal_char_type_invalid == type) { + BOOST_WAVE_LEXER_THROW(lexing_exception, universal_char_invalid, + error_uchar, line, column, file_name.c_str()); + } + else if (universal_char_type_base_charset == type) { + BOOST_WAVE_LEXER_THROW(lexing_exception, universal_char_base_charset, + error_uchar, line, column, file_name.c_str()); + } + else { + BOOST_WAVE_LEXER_THROW(lexing_exception, universal_char_not_allowed, + error_uchar, line, column, file_name.c_str()); + } + } + + // find next universal char (if appropriate) + pos = name.find_first_of('\\', pos+2); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// validate_literal +// +// The validate_literal function tests a given string or character literal +// for its validity with regard to eventually contained universal +// characters. These should be in valid ranges (see the function +// classify_universal_char above). +// +// If the string or character literal contains invalid or not allowed +// universal characters a corresponding lexing_exception is thrown. +// +/////////////////////////////////////////////////////////////////////////////// +template <typename StringT> +inline void +validate_literal (StringT const &name, int line, int column, + StringT const &file_name) +{ + using namespace std; // some systems have strtoul in namespace std:: + +typename StringT::size_type pos = name.find_first_of('\\'); + + while (StringT::npos != pos) { + // the literal contains a backslash (may be universal char) + if ('u' == name[pos+1] || 'U' == name[pos+1]) { + StringT uchar_val(name.substr(pos+2, ('u' == name[pos+1]) ? 4 : 8)); + universal_char_type type = + classify_universal_char(strtoul(uchar_val.c_str(), 0, 16)); + + if (universal_char_type_valid != type && + universal_char_type_not_allowed_for_identifiers != type) + { + // an invalid char was found, so throw an exception + StringT error_uchar(name.substr(pos, ('u' == name[pos+1]) ? 6 : 10)); + + if (universal_char_type_invalid == type) { + BOOST_WAVE_LEXER_THROW(lexing_exception, universal_char_invalid, + error_uchar, line, column, file_name.c_str()); + } + else { + BOOST_WAVE_LEXER_THROW(lexing_exception, universal_char_base_charset, + error_uchar, line, column, file_name.c_str()); + } + } + } + + // find next universal char (if appropriate) + pos = name.find_first_of('\\', pos+2); + } +} + +/////////////////////////////////////////////////////////////////////////////// +} // namespace impl +} // namespace cpplexer +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(VALIDATE_UNIVERSAL_CHAR_HPP_55F1B811_CD76_4C72_8344_CBC69CF3B339_INCLUDED) diff --git a/boost/wave/grammars/cpp_chlit_grammar.hpp b/boost/wave/grammars/cpp_chlit_grammar.hpp new file mode 100644 index 0000000000..c494f9f973 --- /dev/null +++ b/boost/wave/grammars/cpp_chlit_grammar.hpp @@ -0,0 +1,354 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_CHLIT_GRAMMAR_HPP_9527D349_6592_449A_A409_42A001E6C64C_INCLUDED) +#define CPP_CHLIT_GRAMMAR_HPP_9527D349_6592_449A_A409_42A001E6C64C_INCLUDED + +#include <limits> // std::numeric_limits +#include <climits> // CHAR_BIT + +#include <boost/wave/wave_config.hpp> + +#include <boost/static_assert.hpp> +#include <boost/cstdint.hpp> + +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_closure.hpp> +#include <boost/spirit/include/classic_if.hpp> +#include <boost/spirit/include/classic_assign_actor.hpp> +#include <boost/spirit/include/classic_push_back_actor.hpp> + +#include <boost/spirit/include/phoenix1_operators.hpp> +#include <boost/spirit/include/phoenix1_primitives.hpp> +#include <boost/spirit/include/phoenix1_statements.hpp> +#include <boost/spirit/include/phoenix1_functions.hpp> + +#include <boost/wave/cpp_exceptions.hpp> +#include <boost/wave/grammars/cpp_literal_grammar_gen.hpp> + +#if !defined(spirit_append_actor) +#define spirit_append_actor(actor) boost::spirit::classic::push_back_a(actor) +#define spirit_assign_actor(actor) boost::spirit::classic::assign_a(actor) +#endif // !defined(spirit_append_actor) + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// Reusable grammar to parse a C++ style character literal +// +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { + +namespace closures { + + struct chlit_closure + : boost::spirit::classic::closure<chlit_closure, boost::uint32_t, bool> + { + member1 value; + member2 long_lit; + }; +} + +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// +// +// compose a multibyte character literal +// +/////////////////////////////////////////////////////////////////////////////// + struct compose_character_literal { + + template <typename A1, typename A2, typename A3, typename A4> + struct result + { + typedef void type; + }; + + void + operator()(boost::uint32_t& value, bool long_lit, bool& overflow, + boost::uint32_t character) const + { + // The following assumes that wchar_t is max. 32 Bit + BOOST_STATIC_ASSERT(sizeof(wchar_t) <= 4); + + static boost::uint32_t masks[] = { + 0x000000ff, 0x0000ffff, 0x00ffffff, 0xffffffff + }; + static boost::uint32_t overflow_masks[] = { + 0xff000000, 0xffff0000, 0xffffff00, 0xffffffff + }; + + if (long_lit) { + // make sure no overflow will occur below + if ((value & overflow_masks[sizeof(wchar_t)-1]) != 0) { + overflow |= true; + } + else { + // calculate the new value (avoiding a warning regarding + // shifting count >= size of the type) + value <<= CHAR_BIT * (sizeof(wchar_t)-1); + value <<= CHAR_BIT; + value |= character & masks[sizeof(wchar_t)-1]; + } + } + else { + // make sure no overflow will occur below + if ((value & overflow_masks[sizeof(char)-1]) != 0) { + overflow |= true; + } + else { + // calculate the new value + value <<= CHAR_BIT * sizeof(char); + value |= character & masks[sizeof(char)-1]; + } + } + } + }; + phoenix::function<compose_character_literal> const compose; + +} // namespace impl + +/////////////////////////////////////////////////////////////////////////////// +// define, whether the rule's should generate some debug output +#define TRACE_CHLIT_GRAMMAR \ + bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_CHLIT_GRAMMAR) \ + /**/ + +struct chlit_grammar : + public boost::spirit::classic::grammar<chlit_grammar, + closures::chlit_closure::context_t> +{ + chlit_grammar() + : overflow(false) + { + BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "chlit_grammar", + TRACE_CHLIT_GRAMMAR); + } + + // no need for copy constructor/assignment operator + chlit_grammar(chlit_grammar const&); + chlit_grammar& operator=(chlit_grammar const&); + + template <typename ScannerT> + struct definition + { + typedef boost::spirit::classic::rule< + ScannerT, closures::chlit_closure::context_t> + rule_t; + + rule_t ch_lit; + + definition(chlit_grammar const &self) + { + using namespace boost::spirit::classic; + namespace phx = phoenix; + + // special parsers for '\x..' and L'\x....' + typedef uint_parser< + unsigned int, 16, 1, 2 * sizeof(char) + > hex_char_parser_type; + typedef uint_parser< + unsigned int, 16, 1, 2 * sizeof(wchar_t) + > hex_wchar_parser_type; + + // the rule for a character literal + ch_lit + = eps_p[self.value = phx::val(0), self.long_lit = phx::val(false)] + >> !ch_p('L')[self.long_lit = phx::val(true)] + >> ch_p('\'') + >> +( ( + ch_p('\\') + >> ( ch_p('a') // BEL + [ + impl::compose(self.value, self.long_lit, + phx::var(self.overflow), phx::val(0x07)) + ] + | ch_p('b') // BS + [ + impl::compose(self.value, self.long_lit, + phx::var(self.overflow), phx::val(0x08)) + ] + | ch_p('t') // HT + [ + impl::compose(self.value, self.long_lit, + phx::var(self.overflow), phx::val(0x09)) + ] + | ch_p('n') // NL + [ + impl::compose(self.value, self.long_lit, + phx::var(self.overflow), phx::val(0x0a)) + ] + | ch_p('v') // VT + [ + impl::compose(self.value, self.long_lit, + phx::var(self.overflow), phx::val(0x0b)) + ] + | ch_p('f') // FF + [ + impl::compose(self.value, self.long_lit, + phx::var(self.overflow), phx::val(0x0c)) + ] + | ch_p('r') // CR + [ + impl::compose(self.value, self.long_lit, + phx::var(self.overflow), phx::val(0x0d)) + ] + | ch_p('?') + [ + impl::compose(self.value, self.long_lit, + phx::var(self.overflow), phx::val('?')) + ] + | ch_p('\'') + [ + impl::compose(self.value, self.long_lit, + phx::var(self.overflow), phx::val('\'')) + ] + | ch_p('\"') + [ + impl::compose(self.value, self.long_lit, + phx::var(self.overflow), phx::val('\"')) + ] + | ch_p('\\') + [ + impl::compose(self.value, self.long_lit, + phx::var(self.overflow), phx::val('\\')) + ] + | ch_p('x') + >> if_p(self.long_lit) + [ + hex_wchar_parser_type() + [ + impl::compose(self.value, self.long_lit, + phx::var(self.overflow), phx::arg1) + ] + ] + .else_p + [ + hex_char_parser_type() + [ + impl::compose(self.value, self.long_lit, + phx::var(self.overflow), phx::arg1) + ] + ] + | ch_p('u') + >> uint_parser<unsigned int, 16, 4, 4>() + [ + impl::compose(self.value, self.long_lit, + phx::var(self.overflow), phx::arg1) + ] + | ch_p('U') + >> uint_parser<unsigned int, 16, 8, 8>() + [ + impl::compose(self.value, self.long_lit, + phx::var(self.overflow), phx::arg1) + ] + | uint_parser<unsigned int, 8, 1, 3>() + [ + impl::compose(self.value, self.long_lit, + phx::var(self.overflow), phx::arg1) + ] + ) + ) + | ~eps_p(ch_p('\'')) >> anychar_p + [ + impl::compose(self.value, self.long_lit, + phx::var(self.overflow), phx::arg1) + ] + ) + >> ch_p('\'') + ; + + BOOST_SPIRIT_DEBUG_TRACE_RULE(ch_lit, TRACE_CHLIT_GRAMMAR); + } + + // start rule of this grammar + rule_t const& start() const + { return ch_lit; } + }; + + // flag signaling integer overflow during value composition + mutable bool overflow; +}; + +#undef TRACE_CHLIT_GRAMMAR + +/////////////////////////////////////////////////////////////////////////////// +// +// The following function is defined here, to allow the separation of +// the compilation of the intlit_grammap from the function using it. +// +/////////////////////////////////////////////////////////////////////////////// + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 +#define BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE +#else +#define BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE inline +#endif + +template <typename IntegralResult, typename TokenT> +BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE +IntegralResult +chlit_grammar_gen<IntegralResult, TokenT>::evaluate(TokenT const &token, value_error &status) +{ + using namespace boost::spirit::classic; + +chlit_grammar g; +IntegralResult result = 0; +typename TokenT::string_type const &token_val = token.get_value(); +parse_info<typename TokenT::string_type::const_iterator> hit = + parse(token_val.begin(), token_val.end(), g[spirit_assign_actor(result)]); + + if (!hit.hit) { + BOOST_WAVE_THROW(preprocess_exception, ill_formed_character_literal, + token_val.c_str(), token.get_position()); + } + else { + // range check + if ('L' == token_val[0]) { + // recognized wide character + if (g.overflow || + result > (IntegralResult)(std::numeric_limits<wchar_t>::max)()) + { + // out of range + status = error_character_overflow; + } + } + else { + // recognized narrow ('normal') character + if (g.overflow || + result > (IntegralResult)(std::numeric_limits<unsigned char>::max)()) + { + // out of range + status = error_character_overflow; + } + } + } + return result; +} + +#undef BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPP_CHLIT_GRAMMAR_HPP_9527D349_6592_449A_A409_42A001E6C64C_INCLUDED) diff --git a/boost/wave/grammars/cpp_defined_grammar.hpp b/boost/wave/grammars/cpp_defined_grammar.hpp new file mode 100644 index 0000000000..d6d3422fe8 --- /dev/null +++ b/boost/wave/grammars/cpp_defined_grammar.hpp @@ -0,0 +1,185 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_DEFINED_GRAMMAR_HPP_F48287B2_DC67_40A8_B4A1_800EFBD67869_INCLUDED) +#define CPP_DEFINED_GRAMMAR_HPP_F48287B2_DC67_40A8_B4A1_800EFBD67869_INCLUDED + +#include <boost/wave/wave_config.hpp> + +#include <boost/assert.hpp> +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_closure.hpp> +#include <boost/spirit/include/classic_assign_actor.hpp> +#include <boost/spirit/include/classic_push_back_actor.hpp> + +#include <boost/wave/token_ids.hpp> +#include <boost/wave/util/pattern_parser.hpp> +#include <boost/wave/grammars/cpp_defined_grammar_gen.hpp> + +#if !defined(spirit_append_actor) +#define spirit_append_actor(actor) boost::spirit::classic::push_back_a(actor) +#define spirit_assign_actor(actor) boost::spirit::classic::assign_a(actor) +#endif // !defined(spirit_append_actor) + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { + +/////////////////////////////////////////////////////////////////////////////// +// define, whether the rule's should generate some debug output +#define TRACE_CPP_DEFINED_GRAMMAR \ + bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_DEFINED_GRAMMAR) \ + /**/ + +template <typename ContainerT> +struct defined_grammar : + public boost::spirit::classic::grammar<defined_grammar<ContainerT> > +{ + defined_grammar(ContainerT &result_seq_) + : result_seq(result_seq_) + { + BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "defined_grammar", + TRACE_CPP_DEFINED_GRAMMAR); + } + + template <typename ScannerT> + struct definition + { + typedef boost::spirit::classic::rule<ScannerT> rule_t; + + rule_t defined_op; + rule_t identifier; + + definition(defined_grammar const &self) + { + using namespace boost::spirit::classic; + using namespace boost::wave; + using namespace boost::wave::util; + + defined_op // parens not required, see C++ standard 16.1.1 + = ch_p(T_IDENTIFIER) // token contains 'defined' + >> ( + ( ch_p(T_LEFTPAREN) + >> identifier + >> ch_p(T_RIGHTPAREN) + ) + | identifier + ) + ; + + identifier + = ch_p(T_IDENTIFIER) + [ + spirit_append_actor(self.result_seq) + ] + | pattern_p(KeywordTokenType, TokenTypeMask|PPTokenFlag) + [ + spirit_append_actor(self.result_seq) + ] + | pattern_p(OperatorTokenType|AltExtTokenType, + ExtTokenTypeMask|PPTokenFlag) + [ + spirit_append_actor(self.result_seq) + ] + | pattern_p(BoolLiteralTokenType, TokenTypeMask|PPTokenFlag) + [ + spirit_append_actor(self.result_seq) + ] + ; + + BOOST_SPIRIT_DEBUG_TRACE_RULE(defined_op, TRACE_CPP_DEFINED_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(identifier, TRACE_CPP_DEFINED_GRAMMAR); + } + + // start rule of this grammar + rule_t const& start() const + { return defined_op; } + }; + + ContainerT &result_seq; +}; + +/////////////////////////////////////////////////////////////////////////////// +#undef TRACE_CPP_DEFINED_GRAMMAR + +/////////////////////////////////////////////////////////////////////////////// +// +// The following parse function is defined here, to allow the separation of +// the compilation of the defined_grammar from the function +// using it. +// +/////////////////////////////////////////////////////////////////////////////// + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 +#define BOOST_WAVE_DEFINED_GRAMMAR_GEN_INLINE +#else +#define BOOST_WAVE_DEFINED_GRAMMAR_GEN_INLINE inline +#endif + +// The parse_operator_define function is instantiated manually twice to +// simplify the explicit specialization of this template. This way the user +// has only to specify one template parameter (the lexer type) to correctly +// formulate the required explicit specialization. +// This results in no code overhead, because otherwise the function would be +// generated by the compiler twice anyway. + +template <typename LexIteratorT> +BOOST_WAVE_DEFINED_GRAMMAR_GEN_INLINE +boost::spirit::classic::parse_info< + typename defined_grammar_gen<LexIteratorT>::iterator1_type +> +defined_grammar_gen<LexIteratorT>::parse_operator_defined ( + iterator1_type const &first, iterator1_type const &last, + token_sequence_type &found_qualified_name) +{ + using namespace boost::spirit::classic; + using namespace boost::wave; + + defined_grammar<token_sequence_type> g(found_qualified_name); + return boost::spirit::classic::parse ( + first, last, g, ch_p(T_SPACE) | ch_p(T_CCOMMENT)); +} + +template <typename LexIteratorT> +BOOST_WAVE_DEFINED_GRAMMAR_GEN_INLINE +boost::spirit::classic::parse_info< + typename defined_grammar_gen<LexIteratorT>::iterator2_type +> +defined_grammar_gen<LexIteratorT>::parse_operator_defined ( + iterator2_type const &first, iterator2_type const &last, + token_sequence_type &found_qualified_name) +{ + using namespace boost::spirit::classic; + using namespace boost::wave; + + defined_grammar<token_sequence_type> g(found_qualified_name); + return boost::spirit::classic::parse ( + first, last, g, ch_p(T_SPACE) | ch_p(T_CCOMMENT)); +} + +#undef BOOST_WAVE_DEFINED_GRAMMAR_GEN_INLINE + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPP_DEFINED_GRAMMAR_HPP_F48287B2_DC67_40A8_B4A1_800EFBD67869_INCLUDED) diff --git a/boost/wave/grammars/cpp_defined_grammar_gen.hpp b/boost/wave/grammars/cpp_defined_grammar_gen.hpp new file mode 100644 index 0000000000..3da519e917 --- /dev/null +++ b/boost/wave/grammars/cpp_defined_grammar_gen.hpp @@ -0,0 +1,85 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_DEFINED_GRAMMAR_GEN_HPP_825BE9F5_98A3_400D_A97C_AD76B3B08632_INCLUDED) +#define CPP_DEFINED_GRAMMAR_GEN_HPP_825BE9F5_98A3_400D_A97C_AD76B3B08632_INCLUDED + +#include <boost/wave/wave_config.hpp> + +#include <list> + +#include <boost/spirit/include/classic_parser.hpp> +#include <boost/pool/pool_alloc.hpp> + +#include <boost/wave/util/unput_queue_iterator.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +// suppress warnings about dependent classes not being exported from the dll +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable : 4251 4231 4660) +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { + +template <typename LexIteratorT> +struct BOOST_WAVE_DECL defined_grammar_gen +{ + typedef typename LexIteratorT::token_type token_type; + typedef std::list<token_type, boost::fast_pool_allocator<token_type> > + token_sequence_type; + +// The parse_operator_defined function is instantiated manually twice to +// simplify the explicit specialization of this template. This way the user +// has only to specify one template parameter (the lexer iterator type) to +// correctly formulate the required explicit specialization. +// This results in no code overhead, because otherwise the function would be +// generated by the compiler twice anyway. + + typedef boost::wave::util::unput_queue_iterator< + typename token_sequence_type::iterator, token_type, token_sequence_type> + iterator1_type; + + typedef boost::wave::util::unput_queue_iterator< + LexIteratorT, token_type, token_sequence_type> + iterator2_type; + +// parse the operator defined and return the found qualified name + static boost::spirit::classic::parse_info<iterator1_type> + parse_operator_defined (iterator1_type const &first, + iterator1_type const &last, token_sequence_type &found_qualified_name); + + static boost::spirit::classic::parse_info<iterator2_type> + parse_operator_defined (iterator2_type const &first, + iterator2_type const &last, token_sequence_type &found_qualified_name); +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPP_DEFINED_GRAMMAR_GEN_HPP_825BE9F5_98A3_400D_A97C_AD76B3B08632_INCLUDED) diff --git a/boost/wave/grammars/cpp_expression_grammar.hpp b/boost/wave/grammars/cpp_expression_grammar.hpp new file mode 100644 index 0000000000..a52d36a5c8 --- /dev/null +++ b/boost/wave/grammars/cpp_expression_grammar.hpp @@ -0,0 +1,870 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_EXPRESSION_GRAMMAR_HPP_099CD1A4_A6C0_44BE_8F24_0B00F5BE5674_INCLUDED) +#define CPP_EXPRESSION_GRAMMAR_HPP_099CD1A4_A6C0_44BE_8F24_0B00F5BE5674_INCLUDED + +#include <boost/wave/wave_config.hpp> + +#include <boost/assert.hpp> +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_closure.hpp> +#include <boost/spirit/include/classic_if.hpp> +#include <boost/spirit/include/classic_assign_actor.hpp> +#include <boost/spirit/include/classic_push_back_actor.hpp> + +#include <boost/spirit/include/phoenix1_functions.hpp> +#include <boost/spirit/include/phoenix1_operators.hpp> +#include <boost/spirit/include/phoenix1_primitives.hpp> +#include <boost/spirit/include/phoenix1_statements.hpp> +#include <boost/spirit/include/phoenix1_casts.hpp> + +#include <boost/wave/token_ids.hpp> + +#include <boost/wave/cpp_exceptions.hpp> +#include <boost/wave/grammars/cpp_expression_grammar_gen.hpp> +#include <boost/wave/grammars/cpp_literal_grammar_gen.hpp> +#include <boost/wave/grammars/cpp_expression_value.hpp> +#include <boost/wave/util/pattern_parser.hpp> +#include <boost/wave/util/macro_helpers.hpp> + +#if !defined(spirit_append_actor) +#define spirit_append_actor(actor) boost::spirit::classic::push_back_a(actor) +#define spirit_assign_actor(actor) boost::spirit::classic::assign_a(actor) +#endif // !defined(spirit_append_actor) + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// Encapsulation of the grammar for evaluation of constant preprocessor +// expressions +// +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { +namespace closures { + +/////////////////////////////////////////////////////////////////////////////// +// +// define the closure type used throughout the C++ expression grammar +// +// Throughout this grammar all literal tokens are stored into a +// closure_value variables, which converts the types appropriately, where +// required. +// +/////////////////////////////////////////////////////////////////////////////// + struct cpp_expr_closure + : boost::spirit::classic::closure<cpp_expr_closure, closure_value> + { + member1 val; + }; + +} // namespace closures + +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// +// +// convert the given token value (integer literal) to a unsigned long +// +/////////////////////////////////////////////////////////////////////////////// + struct convert_intlit { + + template <typename ArgT> + struct result { + + typedef boost::wave::grammars::closures::closure_value type; + }; + + template <typename TokenT> + boost::wave::grammars::closures::closure_value + operator()(TokenT const &token) const + { + typedef boost::wave::grammars::closures::closure_value return_type; + bool is_unsigned = false; + uint_literal_type ul = intlit_grammar_gen<TokenT>::evaluate(token, + is_unsigned); + + return is_unsigned ? + return_type(ul) : return_type(static_cast<int_literal_type>(ul)); + } + }; + phoenix::function<convert_intlit> const as_intlit; + +/////////////////////////////////////////////////////////////////////////////// +// +// Convert the given token value (character literal) to a unsigned int +// +/////////////////////////////////////////////////////////////////////////////// + struct convert_chlit { + + template <typename ArgT> + struct result { + + typedef boost::wave::grammars::closures::closure_value type; + }; + + template <typename TokenT> + boost::wave::grammars::closures::closure_value + operator()(TokenT const &token) const + { + typedef boost::wave::grammars::closures::closure_value return_type; + value_error status = error_noerror; + + // If the literal is a wchar_t and wchar_t is represented by a + // signed integral type, then the created value will be signed as + // well, otherwise we assume unsigned values. +#if BOOST_WAVE_WCHAR_T_SIGNEDNESS == BOOST_WAVE_WCHAR_T_AUTOSELECT + if ('L' == token.get_value()[0] && std::numeric_limits<wchar_t>::is_signed) + { + int value = chlit_grammar_gen<int, TokenT>::evaluate(token, status); + return return_type(value, status); + } +#elif BOOST_WAVE_WCHAR_T_SIGNEDNESS == BOOST_WAVE_WCHAR_T_FORCE_SIGNED + if ('L' == token.get_value()[0]) + { + int value = chlit_grammar_gen<int, TokenT>::evaluate(token, status); + return return_type(value, status); + } +#endif + + unsigned int value = chlit_grammar_gen<unsigned int, TokenT>::evaluate(token, status); + return return_type(value, status); + } + }; + phoenix::function<convert_chlit> const as_chlit; + +//////////////////////////////////////////////////////////////////////////////// +// +// Handle the ?: operator with correct type and error propagation +// +//////////////////////////////////////////////////////////////////////////////// + struct operator_questionmark { + + template <typename CondT, typename Arg1T, typename Arg2T> + struct result { + + typedef boost::wave::grammars::closures::closure_value type; + }; + + template <typename CondT, typename Arg1T, typename Arg2T> + boost::wave::grammars::closures::closure_value + operator()(CondT const &cond, Arg1T &val1, Arg2T const &val2) const + { + return val1.handle_questionmark(cond, val2); + } + }; + phoenix::function<operator_questionmark> const questionmark; + +/////////////////////////////////////////////////////////////////////////////// +// +// Handle type conversion conserving error conditions +// +/////////////////////////////////////////////////////////////////////////////// + struct operator_to_bool { + + template <typename ArgT> + struct result { + + typedef boost::wave::grammars::closures::closure_value type; + }; + + template <typename ArgT> + boost::wave::grammars::closures::closure_value + operator()(ArgT &val) const + { + typedef boost::wave::grammars::closures::closure_value return_type; + return return_type( + boost::wave::grammars::closures::as_bool(val), val.is_valid()); + } + }; + phoenix::function<operator_to_bool> const to_bool; + +/////////////////////////////////////////////////////////////////////////////// +// +// Handle explicit type conversion +// +/////////////////////////////////////////////////////////////////////////////// + struct operator_as_bool { + + template <typename ArgT> + struct result { + + typedef bool type; + }; + + template <typename ArgT> + bool + operator()(ArgT &val) const + { + return boost::wave::grammars::closures::as_bool(val); + } + }; + phoenix::function<operator_as_bool> const as_bool; + +/////////////////////////////////////////////////////////////////////////////// +// +// Handle closure value operators with proper error propagation +// +/////////////////////////////////////////////////////////////////////////////// +#define BOOST_WAVE_BINARYOP(op, optok) \ + struct operator_binary_ ## op { \ + \ + template <typename Arg1T, typename Arg2T> \ + struct result { \ + \ + typedef boost::wave::grammars::closures::closure_value type; \ + }; \ + \ + template <typename Arg1T, typename Arg2T> \ + boost::wave::grammars::closures::closure_value \ + operator()(Arg1T &val1, Arg2T &val2) const \ + { \ + return val1 optok val2; \ + } \ + }; \ + phoenix::function<operator_binary_ ## op> const binary_ ## op \ + /**/ + + BOOST_WAVE_BINARYOP(and, &&); + BOOST_WAVE_BINARYOP(or, ||); + + BOOST_WAVE_BINARYOP(bitand, &); + BOOST_WAVE_BINARYOP(bitor, |); + BOOST_WAVE_BINARYOP(bitxor, ^); + + BOOST_WAVE_BINARYOP(lesseq, <=); + BOOST_WAVE_BINARYOP(less, <); + BOOST_WAVE_BINARYOP(greater, >); + BOOST_WAVE_BINARYOP(greateq, >=); + BOOST_WAVE_BINARYOP(eq, ==); + BOOST_WAVE_BINARYOP(ne, !=); + +#undef BOOST_WAVE_BINARYOP + +/////////////////////////////////////////////////////////////////////////////// +#define BOOST_WAVE_UNARYOP(op, optok) \ + struct operator_unary_ ## op { \ + \ + template <typename ArgT> \ + struct result { \ + \ + typedef boost::wave::grammars::closures::closure_value type; \ + }; \ + \ + template <typename ArgT> \ + boost::wave::grammars::closures::closure_value \ + operator()(ArgT &val) const \ + { \ + return optok val; \ + } \ + }; \ + phoenix::function<operator_unary_ ## op> const unary_ ## op \ + /**/ + + BOOST_WAVE_UNARYOP(neg, !); + +#undef BOOST_WAVE_UNARYOP + +} // namespace impl + +/////////////////////////////////////////////////////////////////////////////// +// define, whether the rule's should generate some debug output +#define TRACE_CPP_EXPR_GRAMMAR \ + bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_CPP_EXPR_GRAMMAR) \ + /**/ + +struct expression_grammar : + public boost::spirit::classic::grammar< + expression_grammar, + closures::cpp_expr_closure::context_t + > +{ + expression_grammar() + { + BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "expression_grammar", + TRACE_CPP_EXPR_GRAMMAR); + } + + // no need for copy constructor/assignment operator + expression_grammar(expression_grammar const&); + expression_grammar& operator= (expression_grammar const&); + + template <typename ScannerT> + struct definition + { + typedef closures::cpp_expr_closure closure_type; + typedef boost::spirit::classic::rule<ScannerT, closure_type::context_t> rule_t; + typedef boost::spirit::classic::rule<ScannerT> simple_rule_t; + + simple_rule_t pp_expression; + + rule_t const_exp; + rule_t logical_or_exp, logical_and_exp; + rule_t inclusive_or_exp, exclusive_or_exp, and_exp; + rule_t cmp_equality, cmp_relational; + rule_t shift_exp; + rule_t add_exp, multiply_exp; + rule_t unary_exp, primary_exp, constant; + + rule_t const_exp_nocalc; + rule_t logical_or_exp_nocalc, logical_and_exp_nocalc; + rule_t inclusive_or_exp_nocalc, exclusive_or_exp_nocalc, and_exp_nocalc; + rule_t cmp_equality_nocalc, cmp_relational_nocalc; + rule_t shift_exp_nocalc; + rule_t add_exp_nocalc, multiply_exp_nocalc; + rule_t unary_exp_nocalc, primary_exp_nocalc, constant_nocalc; + + boost::spirit::classic::subrule<0, closure_type::context_t> const_exp_subrule; + + definition(expression_grammar const &self) + { + using namespace boost::spirit::classic; + using namespace phoenix; + using namespace boost::wave; + using boost::wave::util::pattern_p; + + pp_expression + = const_exp[self.val = arg1] + ; + + const_exp + = logical_or_exp[const_exp.val = arg1] + >> !(const_exp_subrule = + ch_p(T_QUESTION_MARK) + >> const_exp + [ + const_exp_subrule.val = arg1 + ] + >> ch_p(T_COLON) + >> const_exp + [ + const_exp_subrule.val = + impl::questionmark(const_exp.val, + const_exp_subrule.val, arg1) + ] + )[const_exp.val = arg1] + ; + + logical_or_exp + = logical_and_exp[logical_or_exp.val = arg1] + >> *( if_p(impl::as_bool(logical_or_exp.val)) + [ + // if one of the || operators is true, no more + // evaluation is required + pattern_p(T_OROR, MainTokenMask) + >> logical_and_exp_nocalc + [ + logical_or_exp.val = + impl::to_bool(logical_or_exp.val) + ] + ] + .else_p + [ + pattern_p(T_OROR, MainTokenMask) + >> logical_and_exp + [ + logical_or_exp.val = + impl::binary_or(logical_or_exp.val, arg1) + ] + ] + ) + ; + + logical_and_exp + = inclusive_or_exp[logical_and_exp.val = arg1] + >> *( if_p(impl::as_bool(logical_and_exp.val)) + [ + pattern_p(T_ANDAND, MainTokenMask) + >> inclusive_or_exp + [ + logical_and_exp.val = + impl::binary_and(logical_and_exp.val, arg1) + ] + ] + .else_p + [ + // if one of the && operators is false, no more + // evaluation is required + pattern_p(T_ANDAND, MainTokenMask) + >> inclusive_or_exp_nocalc + [ + logical_and_exp.val = + impl::to_bool(logical_and_exp.val) + ] + ] + ) + ; + + inclusive_or_exp + = exclusive_or_exp[inclusive_or_exp.val = arg1] + >> *( pattern_p(T_OR, MainTokenMask) + >> exclusive_or_exp + [ + inclusive_or_exp.val = + impl::binary_bitor(inclusive_or_exp.val, arg1) + ] + ) + ; + + exclusive_or_exp + = and_exp[exclusive_or_exp.val = arg1] + >> *( pattern_p(T_XOR, MainTokenMask) + >> and_exp + [ + exclusive_or_exp.val = + impl::binary_bitxor(exclusive_or_exp.val, arg1) + ] + ) + ; + + and_exp + = cmp_equality[and_exp.val = arg1] + >> *( pattern_p(T_AND, MainTokenMask) + >> cmp_equality + [ + and_exp.val = + impl::binary_bitand(and_exp.val, arg1) + ] + ) + ; + + cmp_equality + = cmp_relational[cmp_equality.val = arg1] + >> *( ch_p(T_EQUAL) + >> cmp_relational + [ + cmp_equality.val = + impl::binary_eq(cmp_equality.val, arg1) + ] + | pattern_p(T_NOTEQUAL, MainTokenMask) + >> cmp_relational + [ + cmp_equality.val = + impl::binary_ne(cmp_equality.val, arg1) + ] + ) + ; + + cmp_relational + = shift_exp[cmp_relational.val = arg1] + >> *( ch_p(T_LESSEQUAL) + >> shift_exp + [ + cmp_relational.val = + impl::binary_lesseq(cmp_relational.val, arg1) + ] + | ch_p(T_GREATEREQUAL) + >> shift_exp + [ + cmp_relational.val = + impl::binary_greateq(cmp_relational.val, arg1) + ] + | ch_p(T_LESS) + >> shift_exp + [ + cmp_relational.val = + impl::binary_less(cmp_relational.val, arg1) + ] + | ch_p(T_GREATER) + >> shift_exp + [ + cmp_relational.val = + impl::binary_greater(cmp_relational.val, arg1) + ] + ) + ; + + shift_exp + = add_exp[shift_exp.val = arg1] + >> *( ch_p(T_SHIFTLEFT) + >> add_exp + [ + shift_exp.val <<= arg1 + ] + | ch_p(T_SHIFTRIGHT) + >> add_exp + [ + shift_exp.val >>= arg1 + ] + ) + ; + + add_exp + = multiply_exp[add_exp.val = arg1] + >> *( ch_p(T_PLUS) + >> multiply_exp + [ + add_exp.val += arg1 + ] + | ch_p(T_MINUS) + >> multiply_exp + [ + add_exp.val -= arg1 + ] + ) + ; + + multiply_exp + = unary_exp[multiply_exp.val = arg1] + >> *( ch_p(T_STAR) + >> unary_exp + [ + multiply_exp.val *= arg1 + ] + | ch_p(T_DIVIDE) + >> unary_exp + [ + multiply_exp.val /= arg1 + ] + | ch_p(T_PERCENT) + >> unary_exp + [ + multiply_exp.val %= arg1 + ] + ) + ; + + unary_exp + = primary_exp[unary_exp.val = arg1] + | ch_p(T_PLUS) >> unary_exp + [ + unary_exp.val = arg1 + ] + | ch_p(T_MINUS) >> unary_exp + [ + unary_exp.val = -arg1 + ] + | pattern_p(T_COMPL, MainTokenMask) >> unary_exp + [ + unary_exp.val = ~arg1 + ] + | pattern_p(T_NOT, MainTokenMask) >> unary_exp + [ + unary_exp.val = impl::unary_neg(arg1) + ] + ; + + primary_exp + = constant[primary_exp.val = arg1] + | ch_p(T_LEFTPAREN) + >> const_exp[primary_exp.val = arg1] + >> ch_p(T_RIGHTPAREN) + ; + + constant + = ch_p(T_PP_NUMBER) + [ + constant.val = impl::as_intlit(arg1) + ] + | ch_p(T_INTLIT) + [ + constant.val = impl::as_intlit(arg1) + ] + | ch_p(T_CHARLIT) + [ + constant.val = impl::as_chlit(arg1) + ] + ; + + // here follows the same grammar, but without any embedded + // calculations + const_exp_nocalc + = logical_or_exp_nocalc + >> !( ch_p(T_QUESTION_MARK) + >> const_exp_nocalc + >> ch_p(T_COLON) + >> const_exp_nocalc + ) + ; + + logical_or_exp_nocalc + = logical_and_exp_nocalc + >> *( pattern_p(T_OROR, MainTokenMask) + >> logical_and_exp_nocalc + ) + ; + + logical_and_exp_nocalc + = inclusive_or_exp_nocalc + >> *( pattern_p(T_ANDAND, MainTokenMask) + >> inclusive_or_exp_nocalc + ) + ; + + inclusive_or_exp_nocalc + = exclusive_or_exp_nocalc + >> *( pattern_p(T_OR, MainTokenMask) + >> exclusive_or_exp_nocalc + ) + ; + + exclusive_or_exp_nocalc + = and_exp_nocalc + >> *( pattern_p(T_XOR, MainTokenMask) + >> and_exp_nocalc + ) + ; + + and_exp_nocalc + = cmp_equality_nocalc + >> *( pattern_p(T_AND, MainTokenMask) + >> cmp_equality_nocalc + ) + ; + + cmp_equality_nocalc + = cmp_relational_nocalc + >> *( ch_p(T_EQUAL) + >> cmp_relational_nocalc + | pattern_p(T_NOTEQUAL, MainTokenMask) + >> cmp_relational_nocalc + ) + ; + + cmp_relational_nocalc + = shift_exp_nocalc + >> *( ch_p(T_LESSEQUAL) + >> shift_exp_nocalc + | ch_p(T_GREATEREQUAL) + >> shift_exp_nocalc + | ch_p(T_LESS) + >> shift_exp_nocalc + | ch_p(T_GREATER) + >> shift_exp_nocalc + ) + ; + + shift_exp_nocalc + = add_exp_nocalc + >> *( ch_p(T_SHIFTLEFT) + >> add_exp_nocalc + | ch_p(T_SHIFTRIGHT) + >> add_exp_nocalc + ) + ; + + add_exp_nocalc + = multiply_exp_nocalc + >> *( ch_p(T_PLUS) + >> multiply_exp_nocalc + | ch_p(T_MINUS) + >> multiply_exp_nocalc + ) + ; + + multiply_exp_nocalc + = unary_exp_nocalc + >> *( ch_p(T_STAR) + >> unary_exp_nocalc + | ch_p(T_DIVIDE) + >> unary_exp_nocalc + | ch_p(T_PERCENT) + >> unary_exp_nocalc + ) + ; + + unary_exp_nocalc + = primary_exp_nocalc + | ch_p(T_PLUS) >> unary_exp_nocalc + | ch_p(T_MINUS) >> unary_exp_nocalc + | pattern_p(T_COMPL, MainTokenMask) >> unary_exp_nocalc + | pattern_p(T_NOT, MainTokenMask) >> unary_exp_nocalc + ; + + primary_exp_nocalc + = constant_nocalc + | ch_p(T_LEFTPAREN) + >> const_exp_nocalc + >> ch_p(T_RIGHTPAREN) + ; + + constant_nocalc + = ch_p(T_PP_NUMBER) + | ch_p(T_INTLIT) + | ch_p(T_CHARLIT) + ; + + BOOST_SPIRIT_DEBUG_TRACE_RULE(pp_expression, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(const_exp, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(logical_or_exp, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(logical_and_exp, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(inclusive_or_exp, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(exclusive_or_exp, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(and_exp, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(cmp_equality, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(cmp_relational, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(shift_exp, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(add_exp, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(multiply_exp, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(unary_exp, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(primary_exp, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(constant, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(const_exp_subrule, TRACE_CPP_EXPR_GRAMMAR); + + BOOST_SPIRIT_DEBUG_TRACE_RULE(const_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(logical_or_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(logical_and_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(inclusive_or_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(exclusive_or_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(and_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(cmp_equality_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(cmp_relational_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(shift_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(add_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(multiply_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(unary_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(primary_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(constant_nocalc, TRACE_CPP_EXPR_GRAMMAR); + } + + // start rule of this grammar + simple_rule_t const& start() const + { return pp_expression; } + }; +}; + +/////////////////////////////////////////////////////////////////////////////// +#undef TRACE_CPP_EXPR_GRAMMAR + +/////////////////////////////////////////////////////////////////////////////// +// +// The following function is defined here, to allow the separation of +// the compilation of the expression_grammar from the function using it. +// +/////////////////////////////////////////////////////////////////////////////// + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 +#define BOOST_WAVE_EXPRGRAMMAR_GEN_INLINE +#else +#define BOOST_WAVE_EXPRGRAMMAR_GEN_INLINE inline +#endif + +template <typename TokenT> +BOOST_WAVE_EXPRGRAMMAR_GEN_INLINE +bool +expression_grammar_gen<TokenT>::evaluate( + typename token_sequence_type::const_iterator const &first, + typename token_sequence_type::const_iterator const &last, + typename token_type::position_type const &act_pos, + bool if_block_status, value_error &status) +{ + using namespace boost::spirit::classic; + using namespace boost::wave; + using namespace boost::wave::grammars::closures; + + using boost::wave::util::impl::as_string; + + typedef typename token_sequence_type::const_iterator iterator_type; + typedef typename token_sequence_type::value_type::string_type string_type; + + parse_info<iterator_type> hit(first); + closure_value result; // expression result + +#if !defined(BOOST_NO_EXCEPTIONS) + try +#endif + { + expression_grammar g; // expression grammar + hit = parse (first, last, g[spirit_assign_actor(result)], + ch_p(T_SPACE) | ch_p(T_CCOMMENT) | ch_p(T_CPPCOMMENT)); + + if (!hit.hit) { + // expression is illformed + if (if_block_status) { + string_type expression = as_string<string_type>(first, last); + if (0 == expression.size()) + expression = "<empty expression>"; + BOOST_WAVE_THROW(preprocess_exception, ill_formed_expression, + expression.c_str(), act_pos); + return false; + } + else { + // as the if_block_status is false no errors will be reported + return false; + } + } + } +#if !defined(BOOST_NO_EXCEPTIONS) + catch (boost::wave::preprocess_exception const& e) { + // expression is illformed + if (if_block_status) { + boost::throw_exception(e); + return false; + } + else { + // as the if_block_status is false no errors will be reported + return false; + } + } +#endif + + if (!hit.full) { + // The token list starts with a valid expression, but there remains + // something. If the remainder consists out of whitespace only, the + // expression is still valid. + iterator_type next = hit.stop; + + while (next != last) { + switch (static_cast<unsigned int>(token_id(*next))) { + case T_SPACE: + case T_SPACE2: + case T_CCOMMENT: + break; // ok continue + + case T_NEWLINE: + case T_EOF: + case T_CPPCOMMENT: // contains newline + return as_bool(result); // expression is valid + + default: + // expression is illformed + if (if_block_status) { + string_type expression = as_string<string_type>(first, last); + if (0 == expression.size()) + expression = "<empty expression>"; + BOOST_WAVE_THROW(preprocess_exception, ill_formed_expression, + expression.c_str(), act_pos); + return false; + } + else { + // as the if_block_status is false no errors will be reported + return false; + } + } + ++next; + } + } + + if (error_noerror != result.is_valid()) // division or other error by zero occurred + status = result.is_valid(); + +// token sequence is a valid expression + return as_bool(result); +} + +#undef BOOST_WAVE_EXPRGRAMMAR_GEN_INLINE + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPP_EXPRESSION_GRAMMAR_HPP_099CD1A4_A6C0_44BE_8F24_0B00F5BE5674_INCLUDED) diff --git a/boost/wave/grammars/cpp_expression_grammar_gen.hpp b/boost/wave/grammars/cpp_expression_grammar_gen.hpp new file mode 100644 index 0000000000..593c97786b --- /dev/null +++ b/boost/wave/grammars/cpp_expression_grammar_gen.hpp @@ -0,0 +1,75 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_EXPRESSION_GRAMMAR_GEN_HPP_42399258_6CDC_4101_863D_5C7D95B5A6CA_INCLUDED) +#define CPP_EXPRESSION_GRAMMAR_GEN_HPP_42399258_6CDC_4101_863D_5C7D95B5A6CA_INCLUDED + +#include <boost/wave/wave_config.hpp> +#include <boost/wave/cpp_iteration_context.hpp> +#include <boost/wave/grammars/cpp_value_error.hpp> + +#include <list> +#include <boost/pool/pool_alloc.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +// suppress warnings about dependent classes not being exported from the dll +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable : 4251 4231 4660) +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { + +/////////////////////////////////////////////////////////////////////////////// +// +// expression_grammar_gen template class +// +// This template helps separating the compilation of the +// expression_grammar class from the compilation of the main +// pp_iterator. This is done to safe compilation time. +// +/////////////////////////////////////////////////////////////////////////////// + +template <typename TokenT> +struct BOOST_WAVE_DECL expression_grammar_gen { + + typedef TokenT token_type; + typedef std::list<token_type, boost::fast_pool_allocator<token_type> > + token_sequence_type; + + static bool evaluate( + typename token_sequence_type::const_iterator const &first, + typename token_sequence_type::const_iterator const &last, + typename token_type::position_type const &tok, + bool if_block_status, value_error &status); +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPP_EXPRESSION_GRAMMAR_GEN_HPP_42399258_6CDC_4101_863D_5C7D95B5A6CA_INCLUDED) diff --git a/boost/wave/grammars/cpp_expression_value.hpp b/boost/wave/grammars/cpp_expression_value.hpp new file mode 100644 index 0000000000..0cd6e13bc1 --- /dev/null +++ b/boost/wave/grammars/cpp_expression_value.hpp @@ -0,0 +1,883 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_EXPRESSION_VALUE_HPP_452FE66D_8754_4107_AF1E_E42255A0C18A_INCLUDED) +#define CPP_EXPRESSION_VALUE_HPP_452FE66D_8754_4107_AF1E_E42255A0C18A_INCLUDED + +#if defined (BOOST_SPIRIT_DEBUG) +#include <iostream> +#endif // defined(BOOST_SPIRIT_DEBUG) + +#include <boost/wave/wave_config.hpp> +#include <boost/wave/grammars/cpp_value_error.hpp> // value_error + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { +namespace closures { + +class closure_value; +inline bool as_bool(closure_value const& v); + +/////////////////////////////////////////////////////////////////////////////// +// +// The closure_value class represents the closure type, which is used for the +// expression grammar. +// +// This class was introduced to allow the expression grammar to respect +// the numeric type of a numeric literal or expression result. +// +/////////////////////////////////////////////////////////////////////////////// +class closure_value { +public: + + enum value_type { + is_int = 1, + is_uint = 2, + is_bool = 3 + }; + + closure_value(value_error valid_ = error_noerror) + : type(is_int), valid(valid_) + { value.i = 0; } + explicit closure_value(int i, value_error valid_ = error_noerror) + : type(is_int), valid(valid_) + { value.i = i; } + explicit closure_value(unsigned int ui, value_error valid_ = error_noerror) + : type(is_uint), valid(valid_) + { value.ui = ui; } + explicit closure_value(int_literal_type i, value_error valid_ = error_noerror) + : type(is_int), valid(valid_) + { value.i = i; } + explicit closure_value(uint_literal_type ui, value_error valid_ = error_noerror) + : type(is_uint), valid(valid_) + { value.ui = ui; } + explicit closure_value(bool b, value_error valid_ = error_noerror) + : type(is_bool), valid(valid_) + { value.b = b; } + + value_type get_type() const { return type; } + value_error is_valid() const { return valid; } + +// explicit conversion + friend int_literal_type as_int(closure_value const& v) + { + switch (v.type) { + case is_uint: return v.value.ui; + case is_bool: return v.value.b ? 1 : 0; + case is_int: break; + } + return v.value.i; + } + friend uint_literal_type as_uint(closure_value const& v) + { + switch (v.type) { + case is_uint: return v.value.ui; + case is_bool: return v.value.b ? 1 : 0; + case is_int: break; + } + return v.value.i; + } + friend int_literal_type as_long(closure_value const& v) + { + switch (v.type) { + case is_uint: return v.value.ui; + case is_bool: return v.value.b ? 1 : 0; + case is_int: break; + } + return v.value.i; + } + friend uint_literal_type as_ulong(closure_value const& v) + { + switch (v.type) { + case is_uint: return v.value.ui; + case is_bool: return v.value.b ? 1 : 0; + case is_int: break; + } + return v.value.i; + } + friend bool as_bool(closure_value const& v) + { + switch (v.type) { + case is_uint: return v.value.ui != 0; + case is_bool: return v.value.b; + case is_int: break; + } + return v.value.i != 0.0; + } + +// assignment + closure_value &operator= (closure_value const &rhs) + { + switch (rhs.get_type()) { + case is_int: + value.i = as_long(rhs); + type = is_int; + break; + + case is_uint: + value.ui = as_ulong(rhs); + type = is_uint; + break; + + case is_bool: + value.b = as_bool(rhs); + type = is_bool; + break; + } + valid = rhs.valid; + return *this; + } + closure_value &operator= (int rhs) + { + type = is_int; + value.i = rhs; + valid = error_noerror; + return *this; + } + closure_value &operator= (unsigned int rhs) + { + type = is_uint; + value.ui = rhs; + valid = error_noerror; + return *this; + } + closure_value &operator= (int_literal_type rhs) + { + type = is_int; + value.i = rhs; + valid = error_noerror; + return *this; + } + closure_value &operator= (uint_literal_type rhs) + { + type = is_uint; + value.ui = rhs; + valid = error_noerror; + return *this; + } + closure_value &operator= (bool rhs) + { + type = is_bool; + value.b = rhs; + valid = error_noerror; + return *this; + } + +// arithmetics + closure_value &operator+= (closure_value const &rhs) + { + switch (type) { + case is_int: + switch(rhs.type) { + case is_bool: + { + int_literal_type result = value.i + as_long(rhs); + if ((rhs.value.i > 0L && value.i > result) || + (rhs.value.i < 0L && value.i < result)) + { + valid = error_integer_overflow; + } + else { + value.i = result; + } + } + break; + + case is_int: + { + int_literal_type result = value.i + rhs.value.i; + if ((rhs.value.i > 0L && value.i > result) || + (rhs.value.i < 0L && value.i < result)) + { + valid = error_integer_overflow; + } + else { + value.i = result; + } + } + break; + + case is_uint: + { + uint_literal_type result = value.ui + rhs.value.ui; + if (result < value.ui) { + valid = error_integer_overflow; + } + else { + value.ui = result; + type = is_uint; + } + } + break; + } + break; + + case is_uint: + { + uint_literal_type result = value.ui + as_ulong(rhs); + if (result < value.ui) { + valid = error_integer_overflow; + } + else { + value.ui = result; + } + } + break; + + case is_bool: + value.i = value.b + as_bool(rhs); + type = is_int; + } + valid = (value_error)(valid | rhs.valid); + return *this; + } + closure_value &operator-= (closure_value const &rhs) + { + switch (type) { + case is_int: + switch(rhs.type) { + case is_bool: + { + int_literal_type result = value.i - as_long(rhs); + if ((rhs.value.i > 0L && result > value.i) || + (rhs.value.i < 0L && result < value.i)) + { + valid = error_integer_overflow; + } + else { + value.i = result; + } + } + break; + + case is_int: + { + int_literal_type result = value.i - rhs.value.i; + if ((rhs.value.i > 0L && result > value.i) || + (rhs.value.i < 0L && result < value.i)) + { + valid = error_integer_overflow; + } + else { + value.i = result; + } + } + break; + + case is_uint: + { + uint_literal_type result = value.ui - rhs.value.ui; + if (result > value.ui) { + valid = error_integer_overflow; + } + else { + value.ui = result; + type = is_uint; + } + } + break; + } + break; + + case is_uint: + switch(rhs.type) { + case is_bool: + { + uint_literal_type result = value.ui - as_ulong(rhs); + if (result > value.ui) + { + valid = error_integer_overflow; + } + else { + value.ui = result; + } + } + break; + + case is_int: + { + uint_literal_type result = value.ui - rhs.value.i; + if ((rhs.value.i > 0L && result > value.ui) || + (rhs.value.i < 0L && result < value.ui)) + { + valid = error_integer_overflow; + } + else { + value.ui = result; + } + } + break; + + case is_uint: + { + uint_literal_type result = value.ui - rhs.value.ui; + if (result > value.ui) { + valid = error_integer_overflow; + } + else { + value.ui = result; + } + } + break; + } + break; + + case is_bool: + value.i = value.b - as_bool(rhs); + type = is_int; + } + valid = (value_error)(valid | rhs.valid); + return *this; + } + closure_value &operator*= (closure_value const &rhs) + { + switch (type) { + case is_int: + switch(rhs.type) { + case is_bool: value.i *= as_long(rhs); break; + case is_int: + { + int_literal_type result = value.i * rhs.value.i; + if (0 != value.i && 0 != rhs.value.i && + (result / value.i != rhs.value.i || + result / rhs.value.i != value.i) + ) + { + valid = error_integer_overflow; + } + else { + value.i = result; + } + } + break; + + case is_uint: + { + uint_literal_type result = value.ui * rhs.value.ui; + if (0 != value.ui && 0 != rhs.value.ui && + (result / value.ui != rhs.value.ui || + result / rhs.value.ui != value.ui) + ) + { + valid = error_integer_overflow; + } + else { + value.ui = result; + type = is_uint; + } + } + break; + } + break; + + case is_uint: + { + uint_literal_type rhs_val = as_ulong(rhs); + uint_literal_type result = value.ui * rhs_val; + if (0 != value.ui && 0 != rhs_val && + (result / value.ui != rhs_val || + result / rhs_val != value.ui) + ) + { + valid = error_integer_overflow; + } + else { + value.ui = result; + type = is_uint; + } + } + break; + + case is_bool: + switch (rhs.type) { + case is_int: + value.i = (value.b ? 1 : 0) * rhs.value.i; + type = is_int; + break; + + case is_uint: + value.ui = (value.b ? 1 : 0) * rhs.value.ui; + type = is_uint; + break; + + case is_bool: + value.b = 0 != ((value.b ? 1 : 0) * (rhs.value.b ? 1 : 0)); + break; + } + } + valid = (value_error)(valid | rhs.valid); + return *this; + } + closure_value &operator/= (closure_value const &rhs) + { + switch (type) { + case is_int: + switch(rhs.type) { + case is_bool: + case is_int: + if (as_long(rhs) != 0) { + if (value.i == -value.i && -1 == rhs.value.i) { + // LONG_MIN / -1 on two's complement + valid = error_integer_overflow; + } + else { + value.i /= as_long(rhs); + } + } + else { + valid = error_division_by_zero; // division by zero + } + break; + + case is_uint: + if (rhs.value.ui != 0) { + value.ui /= rhs.value.ui; + type = is_uint; + } + else { + valid = error_division_by_zero; // division by zero + } + break; + } + break; + + case is_uint: + if (as_ulong(rhs) != 0) + value.ui /= as_ulong(rhs); + else + valid = error_division_by_zero; // division by zero + break; + + case is_bool: + if (as_bool(rhs)) { + switch(rhs.type) { + case is_int: + value.i = (value.b ? 1 : 0) / rhs.value.i; + type = is_int; + break; + + case is_uint: + value.i = (value.b ? 1 : 0) / rhs.value.ui; + type = is_int; + break; + + case is_bool: + break; + } + } + else { + valid = error_division_by_zero; // division by zero + } + } + return *this; + } + closure_value &operator%= (closure_value const &rhs) + { + switch (type) { + case is_int: + switch(rhs.type) { + case is_bool: + case is_int: + if (as_long(rhs) != 0) { + if (value.i == -value.i && -1 == rhs.value.i) { + // LONG_MIN % -1 on two's complement + valid = error_integer_overflow; + } + else { + value.i %= as_long(rhs); + } + } + else { + valid = error_division_by_zero; // division by zero + } + break; + + case is_uint: + if (rhs.value.ui != 0) { + value.ui %= rhs.value.ui; + type = is_uint; + } + else { + valid = error_division_by_zero; // division by zero + } + break; + } + break; + + case is_uint: + if (as_ulong(rhs) != 0) + value.ui %= as_ulong(rhs); + else + valid = error_division_by_zero; // division by zero + break; + + case is_bool: + if (as_bool(rhs)) { + switch(rhs.type) { + case is_int: + value.i = (value.b ? 1 : 0) % rhs.value.i; + type = is_int; + break; + + case is_uint: + value.i = (value.b ? 1 : 0) % rhs.value.ui; + type = is_int; + break; + + case is_bool: + break; + } + } + else { + valid = error_division_by_zero; // division by zero + } + } + return *this; + } + + friend closure_value + operator- (closure_value const &rhs) + { + switch (rhs.type) { + case is_int: + { + int_literal_type value = as_long(rhs); + if (value != 0 && value == -value) + return closure_value(-value, error_integer_overflow); + return closure_value(-value, rhs.valid); + } + + case is_bool: return closure_value(-as_long(rhs), rhs.valid); + case is_uint: break; + } + + int_literal_type value = as_ulong(rhs); + if (value != 0 && value == -value) + return closure_value(-value, error_integer_overflow); + return closure_value(-value, rhs.valid); + } + friend closure_value + operator~ (closure_value const &rhs) + { + return closure_value(~as_ulong(rhs), rhs.valid); + } + friend closure_value + operator! (closure_value const &rhs) + { + switch (rhs.type) { + case is_int: return closure_value(!as_long(rhs), rhs.valid); + case is_bool: return closure_value(!as_bool(rhs), rhs.valid); + case is_uint: break; + } + return closure_value(!as_ulong(rhs), rhs.valid); + } + +// comparison + friend closure_value + operator== (closure_value const &lhs, closure_value const &rhs) + { + bool cmp = false; + switch (lhs.type) { + case is_int: + switch(rhs.type) { + case is_bool: cmp = as_bool(lhs) == rhs.value.b; break; + case is_int: cmp = lhs.value.i == rhs.value.i; break; + case is_uint: cmp = lhs.value.ui == rhs.value.ui; break; + } + break; + + case is_uint: cmp = lhs.value.ui == as_ulong(rhs); break; + case is_bool: cmp = lhs.value.b == as_bool(rhs); break; + } + return closure_value(cmp, (value_error)(lhs.valid | rhs.valid)); + } + friend closure_value + operator!= (closure_value const &lhs, closure_value const &rhs) + { + return closure_value(!as_bool(lhs == rhs), (value_error)(lhs.valid | rhs.valid)); + } + friend closure_value + operator> (closure_value const &lhs, closure_value const &rhs) + { + bool cmp = false; + switch (lhs.type) { + case is_int: + switch(rhs.type) { + case is_bool: cmp = lhs.value.i > as_long(rhs); break; + case is_int: cmp = lhs.value.i > rhs.value.i; break; + case is_uint: cmp = lhs.value.ui > rhs.value.ui; break; + } + break; + + case is_uint: cmp = lhs.value.ui > as_ulong(rhs); break; + case is_bool: cmp = lhs.value.b > as_bool(rhs); break; + } + return closure_value(cmp, (value_error)(lhs.valid | rhs.valid)); + } + friend closure_value + operator< (closure_value const &lhs, closure_value const &rhs) + { + bool cmp = false; + switch (lhs.type) { + case is_int: + switch(rhs.type) { + case is_bool: cmp = lhs.value.i < as_long(rhs); break; + case is_int: cmp = lhs.value.i < rhs.value.i; break; + case is_uint: cmp = lhs.value.ui < rhs.value.ui; break; + } + break; + + case is_uint: cmp = lhs.value.ui < as_ulong(rhs); break; + case is_bool: cmp = as_bool(lhs) < as_bool(rhs); break; + } + return closure_value(cmp, (value_error)(lhs.valid | rhs.valid)); + } + friend closure_value + operator<= (closure_value const &lhs, closure_value const &rhs) + { + return closure_value(!as_bool(lhs > rhs), (value_error)(lhs.valid | rhs.valid)); + } + friend closure_value + operator>= (closure_value const &lhs, closure_value const &rhs) + { + return closure_value(!as_bool(lhs < rhs), (value_error)(lhs.valid | rhs.valid)); + } + + closure_value & + operator<<= (closure_value const &rhs) + { + switch (type) { + case is_bool: + case is_int: + switch (rhs.type) { + case is_bool: + case is_int: + { + int_literal_type shift_by = as_long(rhs); + + if (shift_by > 64) + shift_by = 64; + else if (shift_by < -64) + shift_by = -64; + value.i <<= shift_by; + } + break; + + case is_uint: + { + uint_literal_type shift_by = as_ulong(rhs); + + if (shift_by > 64) + shift_by = 64; + value.ui <<= shift_by; + + // Note: The usual arithmetic conversions are not performed on + // bit shift operations. + } + break; + } + break; + + case is_uint: + switch (rhs.type) { + case is_bool: + case is_int: + { + int_literal_type shift_by = as_long(rhs); + + if (shift_by > 64) + shift_by = 64; + else if (shift_by < -64) + shift_by = -64; + value.ui <<= shift_by; + } + break; + + case is_uint: + { + uint_literal_type shift_by = as_ulong(rhs); + + if (shift_by > 64) + shift_by = 64; + value.ui <<= shift_by; + } + break; + } + } + valid = (value_error)(valid | rhs.valid); + return *this; + } + + closure_value & + operator>>= (closure_value const &rhs) + { + switch (type) { + case is_bool: + case is_int: + switch (rhs.type) { + case is_bool: + case is_int: + { + int_literal_type shift_by = as_long(rhs); + + if (shift_by > 64) + shift_by = 64; + else if (shift_by < -64) + shift_by = -64; + value.i >>= shift_by; + } + break; + + case is_uint: + { + uint_literal_type shift_by = as_ulong(rhs); + + if (shift_by > 64) + shift_by = 64; + value.ui >>= shift_by; + + // Note: The usual arithmetic conversions are not performed on + // bit shift operations. + } + break; + } + break; + + case is_uint: + switch (rhs.type) { + case is_bool: + case is_int: + { + int_literal_type shift_by = as_long(rhs); + + if (shift_by > 64) + shift_by = 64; + else if (shift_by < -64) + shift_by = -64; + value.ui >>= shift_by; + } + break; + + case is_uint: + { + uint_literal_type shift_by = as_ulong(rhs); + + if (shift_by > 64) + shift_by = 64; + value.ui >>= shift_by; + } + break; + } + break; + } + valid = (value_error)(valid | rhs.valid); + return *this; + } + + friend closure_value + operator|| (closure_value const &lhs, closure_value const &rhs) + { + bool result = as_bool(lhs) || as_bool(rhs); + return closure_value(result, (value_error)(lhs.valid | rhs.valid)); + } + + friend closure_value + operator&& (closure_value const &lhs, closure_value const &rhs) + { + bool result = as_bool(lhs) && as_bool(rhs); + return closure_value(result, (value_error)(lhs.valid | rhs.valid)); + } + + friend closure_value + operator| (closure_value const &lhs, closure_value const &rhs) + { + uint_literal_type result = as_ulong(lhs) | as_ulong(rhs); + return closure_value(result, (value_error)(lhs.valid | rhs.valid)); + } + + friend closure_value + operator& (closure_value const &lhs, closure_value const &rhs) + { + uint_literal_type result = as_ulong(lhs) & as_ulong(rhs); + return closure_value(result, (value_error)(lhs.valid | rhs.valid)); + } + + friend closure_value + operator^ (closure_value const &lhs, closure_value const &rhs) + { + uint_literal_type result = as_ulong(lhs) ^ as_ulong(rhs); + return closure_value(result, (value_error)(lhs.valid | rhs.valid)); + } + + // handle the ?: operator + closure_value & + handle_questionmark(closure_value const &cond, closure_value const &val2) + { + switch (type) { + case is_int: + switch (val2.type) { + case is_bool: value.b = as_bool(cond) ? value.b : as_bool(val2); break; + case is_int: value.i = as_bool(cond) ? value.i : as_long(val2); break; + case is_uint: + value.ui = as_bool(cond) ? value.ui : as_ulong(val2); + type = is_uint; // changing type! + break; + } + break; + + case is_uint: value.ui = as_bool(cond) ? value.ui : as_ulong(val2); break; + case is_bool: value.b = as_bool(cond) ? value.b : as_bool(val2); break; + } + valid = as_bool(cond) ? valid : val2.valid; + return *this; + } + +#if defined (BOOST_SPIRIT_DEBUG) + friend std::ostream& + operator<< (std::ostream &o, closure_value const &val) + { + switch (val.type) { + case is_int: o << "int(" << as_long(val) << ")"; break; + case is_uint: o << "unsigned int(" << as_ulong(val) << ")"; break; + case is_bool: o << "bool(" << as_bool(val) << ")"; break; + } + return o; + } +#endif // defined(BOOST_SPIRIT_DEBUG) + +private: + value_type type; + union { + int_literal_type i; + uint_literal_type ui; + bool b; + } value; + value_error valid; +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace closures +} // namespace grammars +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPP_EXPRESSION_VALUE_HPP_452FE66D_8754_4107_AF1E_E42255A0C18A_INCLUDED) diff --git a/boost/wave/grammars/cpp_grammar.hpp b/boost/wave/grammars/cpp_grammar.hpp new file mode 100644 index 0000000000..d309e2e39b --- /dev/null +++ b/boost/wave/grammars/cpp_grammar.hpp @@ -0,0 +1,765 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_GRAMMAR_HPP_FEAEBC2E_2734_428B_A7CA_85E5A415E23E_INCLUDED) +#define CPP_GRAMMAR_HPP_FEAEBC2E_2734_428B_A7CA_85E5A415E23E_INCLUDED + +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_parse_tree.hpp> +#include <boost/spirit/include/classic_parse_tree_utils.hpp> +#include <boost/spirit/include/classic_confix.hpp> +#include <boost/spirit/include/classic_lists.hpp> + +#include <boost/wave/wave_config.hpp> +#include <boost/pool/pool_alloc.hpp> + +#if BOOST_WAVE_DUMP_PARSE_TREE != 0 +#include <map> +#include <boost/spirit/include/classic_tree_to_xml.hpp> +#endif + +#include <boost/wave/token_ids.hpp> +#include <boost/wave/grammars/cpp_grammar_gen.hpp> +#include <boost/wave/util/pattern_parser.hpp> + +#include <boost/wave/cpp_exceptions.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { + +namespace impl { + +/////////////////////////////////////////////////////////////////////////////// +// +// store_found_eof +// +// The store_found_eof functor sets a given flag if the T_EOF token was +// found during the parsing process +// +/////////////////////////////////////////////////////////////////////////////// + + struct store_found_eof { + + store_found_eof(bool &found_eof_) : found_eof(found_eof_) {} + + template <typename TokenT> + void operator()(TokenT const &/*token*/) const + { + found_eof = true; + } + + bool &found_eof; + }; + +/////////////////////////////////////////////////////////////////////////////// +// +// store_found_directive +// +// The store_found_directive functor stores the token_id of the recognized +// pp directive +// +/////////////////////////////////////////////////////////////////////////////// + + template <typename TokenT> + struct store_found_directive { + + store_found_directive(TokenT &found_directive_) + : found_directive(found_directive_) {} + + void operator()(TokenT const &token) const + { + found_directive = token; + } + + TokenT &found_directive; + }; + +/////////////////////////////////////////////////////////////////////////////// +// +// store_found_eoltokens +// +// The store_found_eoltokens functor stores the token sequence of the +// line ending for a particular pp directive +// +/////////////////////////////////////////////////////////////////////////////// + + template <typename ContainerT> + struct store_found_eoltokens { + + store_found_eoltokens(ContainerT &found_eoltokens_) + : found_eoltokens(found_eoltokens_) {} + + template <typename IteratorT> + void operator()(IteratorT const &first, IteratorT const& last) const + { + std::copy(first, last, + std::inserter(found_eoltokens, found_eoltokens.end())); + } + + ContainerT &found_eoltokens; + }; + +/////////////////////////////////////////////////////////////////////////////// +// +// flush_underlying_parser +// +// The flush_underlying_parser flushes the underlying +// multi_pass_iterator during the normal parsing process. This is +// used at certain points during the parsing process, when it is +// clear, that no backtracking is needed anymore and the input +// gathered so far may be discarded. +// +/////////////////////////////////////////////////////////////////////////////// + struct flush_underlying_parser + : public boost::spirit::classic::parser<flush_underlying_parser> + { + typedef flush_underlying_parser this_t; + + template <typename ScannerT> + typename boost::spirit::classic::parser_result<this_t, ScannerT>::type + parse(ScannerT const& scan) const + { + scan.first.clear_queue(); + return scan.empty_match(); + } + }; + + flush_underlying_parser const + flush_underlying_parser_p = flush_underlying_parser(); + +} // anonymous namespace + +/////////////////////////////////////////////////////////////////////////////// +// define, whether the rule's should generate some debug output +#define TRACE_CPP_GRAMMAR \ + bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_CPP_GRAMMAR) \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +// Encapsulation of the C++ preprocessor grammar. +template <typename TokenT, typename ContainerT> +struct cpp_grammar : + public boost::spirit::classic::grammar<cpp_grammar<TokenT, ContainerT> > +{ + typedef typename TokenT::position_type position_type; + typedef cpp_grammar<TokenT, ContainerT> grammar_type; + typedef impl::store_found_eof store_found_eof_type; + typedef impl::store_found_directive<TokenT> store_found_directive_type; + typedef impl::store_found_eoltokens<ContainerT> store_found_eoltokens_type; + + template <typename ScannerT> + struct definition + { + // non-parse_tree generating rule type + typedef typename ScannerT::iteration_policy_t iteration_policy_t; + typedef boost::spirit::classic::match_policy match_policy_t; + typedef typename ScannerT::action_policy_t action_policy_t; + typedef + boost::spirit::classic::scanner_policies< + iteration_policy_t, match_policy_t, action_policy_t> + policies_t; + typedef + boost::spirit::classic::scanner<typename ScannerT::iterator_t, policies_t> + non_tree_scanner_t; + typedef + boost::spirit::classic::rule< + non_tree_scanner_t, boost::spirit::classic::dynamic_parser_tag> + no_tree_rule_type; + + // 'normal' (parse_tree generating) rule type + typedef + boost::spirit::classic::rule< + ScannerT, boost::spirit::classic::dynamic_parser_tag> + rule_type; + + rule_type pp_statement, macro_include_file; +// rule_type include_file, system_include_file; + rule_type plain_define, macro_definition, macro_parameters; + rule_type undefine; + rule_type ppifdef, ppifndef, ppif, ppelif; +// rule_type ppelse, ppendif; + rule_type ppline; + rule_type pperror; + rule_type ppwarning; + rule_type pppragma; + rule_type illformed; + rule_type ppqualifiedname; + rule_type eol_tokens; + no_tree_rule_type ppsp; +#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 + rule_type ppregion; + rule_type ppendregion; +#endif + + definition(cpp_grammar const &self) + { + // import the spirit and cpplexer namespaces here + using namespace boost::spirit::classic; + using namespace boost::wave; + using namespace boost::wave::util; + + // set the rule id's for later use + pp_statement.set_id(BOOST_WAVE_PP_STATEMENT_ID); +// include_file.set_id(BOOST_WAVE_INCLUDE_FILE_ID); +// system_include_file.set_id(BOOST_WAVE_SYSINCLUDE_FILE_ID); + macro_include_file.set_id(BOOST_WAVE_MACROINCLUDE_FILE_ID); + plain_define.set_id(BOOST_WAVE_PLAIN_DEFINE_ID); + macro_parameters.set_id(BOOST_WAVE_MACRO_PARAMETERS_ID); + macro_definition.set_id(BOOST_WAVE_MACRO_DEFINITION_ID); + undefine.set_id(BOOST_WAVE_UNDEFINE_ID); + ppifdef.set_id(BOOST_WAVE_IFDEF_ID); + ppifndef.set_id(BOOST_WAVE_IFNDEF_ID); + ppif.set_id(BOOST_WAVE_IF_ID); + ppelif.set_id(BOOST_WAVE_ELIF_ID); +// ppelse.set_id(BOOST_WAVE_ELSE_ID); +// ppendif.set_id(BOOST_WAVE_ENDIF_ID); + ppline.set_id(BOOST_WAVE_LINE_ID); + pperror.set_id(BOOST_WAVE_ERROR_ID); + ppwarning.set_id(BOOST_WAVE_WARNING_ID); + pppragma.set_id(BOOST_WAVE_PRAGMA_ID); + illformed.set_id(BOOST_WAVE_ILLFORMED_ID); + ppsp.set_id(BOOST_WAVE_PPSPACE_ID); + ppqualifiedname.set_id(BOOST_WAVE_PPQUALIFIEDNAME_ID); +#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 + ppregion.set_id(BOOST_WAVE_REGION_ID); + ppendregion.set_id(BOOST_WAVE_ENDREGION_ID); +#endif + +#if BOOST_WAVE_DUMP_PARSE_TREE != 0 + self.map_rule_id_to_name.init_rule_id_to_name_map(self); +#endif + + // recognizes preprocessor directives only + + // C++ standard 16.1: A preprocessing directive consists of a sequence + // of preprocessing tokens. The first token in the sequence is # + // preprocessing token that is either the first character in the source + // file (optionally after white space containing no new-line + // characters) or that follows white space containing at least one + // new-line character. The last token in the sequence is the first + // new-line character that follows the first token in the sequence. + + pp_statement + = ( plain_define +// | include_file +// | system_include_file + | ppif + | ppelif + | ppifndef + | ppifdef + | undefine +// | ppelse + | macro_include_file + | ppline + | pppragma + | pperror + | ppwarning +// | ppendif +#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 + | ppregion + | ppendregion +#endif + | illformed + ) + >> eol_tokens + [ store_found_eoltokens_type(self.found_eoltokens) ] +// In parser debug mode it is useful not to flush the underlying stream +// to allow its investigation in the debugger and to see the correct +// output in the printed debug log.. +// Note: this may break the parser, though. +#if !(defined(BOOST_SPIRIT_DEBUG) && \ + (BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_CPP_GRAMMAR) \ + ) + >> impl::flush_underlying_parser_p +#endif // !(defined(BOOST_SPIRIT_DEBUG) && + ; + +// // #include ... +// include_file // include "..." +// = ch_p(T_PP_QHEADER) +// [ store_found_directive_type(self.found_directive) ] +// #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 +// | ch_p(T_PP_QHEADER_NEXT) +// [ store_found_directive_type(self.found_directive) ] +// #endif +// ; + +// system_include_file // include <...> +// = ch_p(T_PP_HHEADER) +// [ store_found_directive_type(self.found_directive) ] +// #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 +// | ch_p(T_PP_HHEADER_NEXT) +// [ store_found_directive_type(self.found_directive) ] +// #endif +// ; + + macro_include_file // include ...anything else... + = no_node_d + [ + ch_p(T_PP_INCLUDE) + [ store_found_directive_type(self.found_directive) ] +#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 + | ch_p(T_PP_INCLUDE_NEXT) + [ store_found_directive_type(self.found_directive) ] +#endif + ] + >> *( anychar_p - + (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) + ) + ; + + // #define FOO foo (with optional parameters) + plain_define + = no_node_d + [ + ch_p(T_PP_DEFINE) + [ store_found_directive_type(self.found_directive) ] + >> +ppsp + ] + >> ( ch_p(T_IDENTIFIER) + | pattern_p(KeywordTokenType, + TokenTypeMask|PPTokenFlag) + | pattern_p(OperatorTokenType|AltExtTokenType, + ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc. + | pattern_p(BoolLiteralTokenType, + TokenTypeMask|PPTokenFlag) // true/false + ) + >> ( ( no_node_d[eps_p(ch_p(T_LEFTPAREN))] + >> macro_parameters + >> !macro_definition + ) + | !( no_node_d[+ppsp] + >> macro_definition + ) + ) + ; + + // parameter list + // normal C++ mode + macro_parameters + = confix_p( + no_node_d[ch_p(T_LEFTPAREN) >> *ppsp], + !list_p( + ( ch_p(T_IDENTIFIER) + | pattern_p(KeywordTokenType, + TokenTypeMask|PPTokenFlag) + | pattern_p(OperatorTokenType|AltExtTokenType, + ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc. + | pattern_p(BoolLiteralTokenType, + TokenTypeMask|PPTokenFlag) // true/false +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + | ch_p(T_ELLIPSIS) +#endif + ), + no_node_d[*ppsp >> ch_p(T_COMMA) >> *ppsp] + ), + no_node_d[*ppsp >> ch_p(T_RIGHTPAREN)] + ) + ; + + // macro body (anything left until eol) + macro_definition + = no_node_d[*ppsp] + >> *( anychar_p - + (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) + ) + ; + + // #undef FOO + undefine + = no_node_d + [ + ch_p(T_PP_UNDEF) + [ store_found_directive_type(self.found_directive) ] + >> +ppsp + ] + >> ( ch_p(T_IDENTIFIER) + | pattern_p(KeywordTokenType, + TokenTypeMask|PPTokenFlag) + | pattern_p(OperatorTokenType|AltExtTokenType, + ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc. + | pattern_p(BoolLiteralTokenType, + TokenTypeMask|PPTokenFlag) // true/false + ) + ; + + // #ifdef et.al. + ppifdef + = no_node_d + [ + ch_p(T_PP_IFDEF) + [ store_found_directive_type(self.found_directive) ] + >> +ppsp + ] + >> ppqualifiedname + ; + + ppifndef + = no_node_d + [ + ch_p(T_PP_IFNDEF) + [ store_found_directive_type(self.found_directive) ] + >> +ppsp + ] + >> ppqualifiedname + ; + + ppif + = no_node_d + [ + ch_p(T_PP_IF) + [ store_found_directive_type(self.found_directive) ] +// >> *ppsp + ] + >> +( anychar_p - + (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) + ) + ; + +// ppelse +// = no_node_d +// [ +// ch_p(T_PP_ELSE) +// [ store_found_directive_type(self.found_directive) ] +// ] +// ; + + ppelif + = no_node_d + [ + ch_p(T_PP_ELIF) + [ store_found_directive_type(self.found_directive) ] +// >> *ppsp + ] + >> +( anychar_p - + (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) + ) + ; + +// ppendif +// = no_node_d +// [ +// ch_p(T_PP_ENDIF) +// [ store_found_directive_type(self.found_directive) ] +// ] +// ; + + // #line ... + ppline + = no_node_d + [ + ch_p(T_PP_LINE) + [ store_found_directive_type(self.found_directive) ] + >> *ppsp + ] + >> +( anychar_p - + (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) + ) + ; + +#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 + // #region ... + ppregion + = no_node_d + [ + ch_p(T_MSEXT_PP_REGION) + [ store_found_directive_type(self.found_directive) ] + >> +ppsp + ] + >> ppqualifiedname + ; + + // #endregion + ppendregion + = no_node_d + [ + ch_p(T_MSEXT_PP_ENDREGION) + [ store_found_directive_type(self.found_directive) ] + ] + ; +#endif + + // # something else (ill formed preprocessor directive) + illformed // for error reporting + = no_node_d + [ + pattern_p(T_POUND, MainTokenMask) + >> *ppsp + ] + >> ( anychar_p - + (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) + ) + >> no_node_d + [ + *( anychar_p - + (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) + ) + ] + ; + + // #error + pperror + = no_node_d + [ + ch_p(T_PP_ERROR) + [ store_found_directive_type(self.found_directive) ] + >> *ppsp + ] + >> *( anychar_p - + (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) + ) + ; + + // #warning + ppwarning + = no_node_d + [ + ch_p(T_PP_WARNING) + [ store_found_directive_type(self.found_directive) ] + >> *ppsp + ] + >> *( anychar_p - + (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) + ) + ; + + // #pragma ... + pppragma + = no_node_d + [ + ch_p(T_PP_PRAGMA) + [ store_found_directive_type(self.found_directive) ] + ] + >> *( anychar_p - + (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) + ) + ; + + ppqualifiedname + = no_node_d[*ppsp] + >> ( ch_p(T_IDENTIFIER) + | pattern_p(KeywordTokenType, + TokenTypeMask|PPTokenFlag) + | pattern_p(OperatorTokenType|AltExtTokenType, + ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc. + | pattern_p(BoolLiteralTokenType, + TokenTypeMask|PPTokenFlag) // true/false + ) + ; + + // auxiliary helper rules + ppsp // valid space in a line with a preprocessor directive + = ch_p(T_SPACE) | ch_p(T_CCOMMENT) + ; + + // end of line tokens + eol_tokens + = no_node_d + [ + *( ch_p(T_SPACE) + | ch_p(T_CCOMMENT) + ) + >> ( ch_p(T_NEWLINE) + | ch_p(T_CPPCOMMENT) + | ch_p(T_EOF) + [ store_found_eof_type(self.found_eof) ] + ) + ] + ; + + BOOST_SPIRIT_DEBUG_TRACE_RULE(pp_statement, TRACE_CPP_GRAMMAR); +// BOOST_SPIRIT_DEBUG_TRACE_RULE(include_file, TRACE_CPP_GRAMMAR); +// BOOST_SPIRIT_DEBUG_TRACE_RULE(system_include_file, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_include_file, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(plain_define, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_definition, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_parameters, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(undefine, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(ppifdef, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(ppifndef, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(ppif, TRACE_CPP_GRAMMAR); +// BOOST_SPIRIT_DEBUG_TRACE_RULE(ppelse, TRACE_CPP_GRAMMAR); +// BOOST_SPIRIT_DEBUG_TRACE_RULE(ppelif, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(ppendif, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(ppline, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(pperror, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(ppwarning, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(illformed, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(ppsp, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(ppqualifiedname, TRACE_CPP_GRAMMAR); +#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 + BOOST_SPIRIT_DEBUG_TRACE_RULE(ppregion, TRACE_CPP_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(ppendregion, TRACE_CPP_GRAMMAR); +#endif + } + + // start rule of this grammar + rule_type const& start() const + { return pp_statement; } + }; + + bool &found_eof; + TokenT &found_directive; + ContainerT &found_eoltokens; + + cpp_grammar(bool &found_eof_, TokenT &found_directive_, + ContainerT &found_eoltokens_) + : found_eof(found_eof_), + found_directive(found_directive_), + found_eoltokens(found_eoltokens_) + { + BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "cpp_grammar", + TRACE_CPP_GRAMMAR); + } + +#if BOOST_WAVE_DUMP_PARSE_TREE != 0 +// helper function and data to get readable names of the rules known to us + struct map_ruleid_to_name : + public std::map<boost::spirit::classic::parser_id, std::string> + { + typedef std::map<boost::spirit::classic::parser_id, std::string> base_type; + + void init_rule_id_to_name_map(cpp_grammar const &self) + { + struct { + int parser_id; + char const *rule_name; + } + init_ruleid_name_map[] = { + { BOOST_WAVE_PP_STATEMENT_ID, "pp_statement" }, +// { BOOST_WAVE_INCLUDE_FILE_ID, "include_file" }, +// { BOOST_WAVE_SYSINCLUDE_FILE_ID, "system_include_file" }, + { BOOST_WAVE_MACROINCLUDE_FILE_ID, "macro_include_file" }, + { BOOST_WAVE_PLAIN_DEFINE_ID, "plain_define" }, + { BOOST_WAVE_MACRO_PARAMETERS_ID, "macro_parameters" }, + { BOOST_WAVE_MACRO_DEFINITION_ID, "macro_definition" }, + { BOOST_WAVE_UNDEFINE_ID, "undefine" }, + { BOOST_WAVE_IFDEF_ID, "ppifdef" }, + { BOOST_WAVE_IFNDEF_ID, "ppifndef" }, + { BOOST_WAVE_IF_ID, "ppif" }, + { BOOST_WAVE_ELIF_ID, "ppelif" }, +// { BOOST_WAVE_ELSE_ID, "ppelse" }, +// { BOOST_WAVE_ENDIF_ID, "ppendif" }, + { BOOST_WAVE_LINE_ID, "ppline" }, + { BOOST_WAVE_ERROR_ID, "pperror" }, + { BOOST_WAVE_WARNING_ID, "ppwarning" }, + { BOOST_WAVE_PRAGMA_ID, "pppragma" }, + { BOOST_WAVE_ILLFORMED_ID, "illformed" }, + { BOOST_WAVE_PPSPACE_ID, "ppspace" }, + { BOOST_WAVE_PPQUALIFIEDNAME_ID, "ppqualifiedname" }, +#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 + { BOOST_WAVE_REGION_ID, "ppregion" }, + { BOOST_WAVE_ENDREGION_ID, "ppendregion" }, +#endif + { 0 } + }; + + // initialize parser_id to rule_name map + for (int i = 0; 0 != init_ruleid_name_map[i].parser_id; ++i) + base_type::insert(base_type::value_type( + boost::spirit::classic::parser_id(init_ruleid_name_map[i].parser_id), + std::string(init_ruleid_name_map[i].rule_name)) + ); + } + }; + mutable map_ruleid_to_name map_rule_id_to_name; +#endif // WAVE_DUMP_PARSE_TREE != 0 +}; + +/////////////////////////////////////////////////////////////////////////////// +#undef TRACE_CPP_GRAMMAR + +/////////////////////////////////////////////////////////////////////////////// +// +// Special parse function generating a parse tree using a given node_factory. +// +/////////////////////////////////////////////////////////////////////////////// +template <typename NodeFactoryT, typename IteratorT, typename ParserT> +inline boost::spirit::classic::tree_parse_info<IteratorT, NodeFactoryT> +parsetree_parse(IteratorT const& first_, IteratorT const& last, + boost::spirit::classic::parser<ParserT> const& p) +{ + using namespace boost::spirit::classic; + + typedef pt_match_policy<IteratorT, NodeFactoryT> pt_match_policy_type; + typedef scanner_policies<iteration_policy, pt_match_policy_type> + scanner_policies_type; + typedef scanner<IteratorT, scanner_policies_type> scanner_type; + + scanner_policies_type policies; + IteratorT first = first_; + scanner_type scan(first, last, policies); + tree_match<IteratorT, NodeFactoryT> hit = p.derived().parse(scan); + return tree_parse_info<IteratorT, NodeFactoryT>( + first, hit, hit && (first == last), hit.length(), hit.trees); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// The following parse function is defined here, to allow the separation of +// the compilation of the cpp_grammar from the function using it. +// +/////////////////////////////////////////////////////////////////////////////// + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 +#define BOOST_WAVE_GRAMMAR_GEN_INLINE +#else +#define BOOST_WAVE_GRAMMAR_GEN_INLINE inline +#endif + +template <typename LexIteratorT, typename TokenContainerT> +BOOST_WAVE_GRAMMAR_GEN_INLINE +boost::spirit::classic::tree_parse_info< + LexIteratorT, + typename cpp_grammar_gen<LexIteratorT, TokenContainerT>::node_factory_type +> +cpp_grammar_gen<LexIteratorT, TokenContainerT>::parse_cpp_grammar ( + LexIteratorT const &first, LexIteratorT const &last, + position_type const &act_pos, bool &found_eof, + token_type &found_directive, token_container_type &found_eoltokens) +{ + using namespace boost::spirit::classic; + using namespace boost::wave; + + cpp_grammar<token_type, TokenContainerT> g(found_eof, found_directive, found_eoltokens); + tree_parse_info<LexIteratorT, node_factory_type> hit = + parsetree_parse<node_factory_type>(first, last, g); + +#if BOOST_WAVE_DUMP_PARSE_TREE != 0 + if (hit.match) { + tree_to_xml (BOOST_WAVE_DUMP_PARSE_TREE_OUT, hit.trees, "", + g.map_rule_id_to_name, &token_type::get_token_id, + &token_type::get_token_value); + } +#endif + + return hit; +} + +#undef BOOST_WAVE_GRAMMAR_GEN_INLINE + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPP_GRAMMAR_HPP_FEAEBC2E_2734_428B_A7CA_85E5A415E23E_INCLUDED) diff --git a/boost/wave/grammars/cpp_grammar_gen.hpp b/boost/wave/grammars/cpp_grammar_gen.hpp new file mode 100644 index 0000000000..d582a07144 --- /dev/null +++ b/boost/wave/grammars/cpp_grammar_gen.hpp @@ -0,0 +1,110 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_GRAMMAR_GEN_HPP_80CB8A59_5411_4E45_B406_62531A12FB99_INCLUDED) +#define CPP_GRAMMAR_GEN_HPP_80CB8A59_5411_4E45_B406_62531A12FB99_INCLUDED + +#include <boost/wave/wave_config.hpp> +#include <boost/wave/language_support.hpp> + +#include <boost/spirit/include/classic_nil.hpp> +#include <boost/spirit/include/classic_parse_tree.hpp> + +#include <boost/pool/pool_alloc.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +// suppress warnings about dependent classes not being exported from the dll +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable : 4251 4231 4660) +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { + +/////////////////////////////////////////////////////////////////////////////// +// +// Here are the node id's of the different node of the cpp_grammar +// +/////////////////////////////////////////////////////////////////////////////// +#define BOOST_WAVE_PP_STATEMENT_ID 1 +#define BOOST_WAVE_INCLUDE_FILE_ID 2 +#define BOOST_WAVE_SYSINCLUDE_FILE_ID 3 +#define BOOST_WAVE_MACROINCLUDE_FILE_ID 4 +#define BOOST_WAVE_PLAIN_DEFINE_ID 5 +#define BOOST_WAVE_MACRO_PARAMETERS_ID 6 +#define BOOST_WAVE_MACRO_DEFINITION_ID 7 +#define BOOST_WAVE_UNDEFINE_ID 8 +#define BOOST_WAVE_IFDEF_ID 9 +#define BOOST_WAVE_IFNDEF_ID 10 +#define BOOST_WAVE_IF_ID 11 +#define BOOST_WAVE_ELIF_ID 12 +#define BOOST_WAVE_ELSE_ID 13 +#define BOOST_WAVE_ENDIF_ID 14 +#define BOOST_WAVE_LINE_ID 15 +#define BOOST_WAVE_ERROR_ID 16 +#define BOOST_WAVE_WARNING_ID 17 +#define BOOST_WAVE_PRAGMA_ID 18 +#define BOOST_WAVE_ILLFORMED_ID 19 +#define BOOST_WAVE_PPSPACE_ID 20 +#define BOOST_WAVE_PPQUALIFIEDNAME_ID 21 +#define BOOST_WAVE_REGION_ID 22 +#define BOOST_WAVE_ENDREGION_ID 23 + +/////////////////////////////////////////////////////////////////////////////// +// +// cpp_grammar_gen template class +// +// This template helps separating the compilation of the cpp_grammar +// class from the compilation of the main pp_iterator. This is done to +// safe compilation time. +// +/////////////////////////////////////////////////////////////////////////////// + +template <typename LexIteratorT, typename TokenContainerT> +struct BOOST_WAVE_DECL cpp_grammar_gen +{ + typedef LexIteratorT iterator_type; + typedef typename LexIteratorT::token_type token_type; + typedef TokenContainerT token_container_type; + typedef typename token_type::position_type position_type; + typedef boost::spirit::classic::node_val_data_factory< +// boost::spirit::nil_t, +// boost::pool_allocator<boost::spirit::nil_t> + > node_factory_type; + +// parse the cpp_grammar and return the resulting parse tree + static boost::spirit::classic::tree_parse_info<iterator_type, node_factory_type> + parse_cpp_grammar (iterator_type const &first, iterator_type const &last, + position_type const &act_pos, bool &found_eof, + token_type &found_directive, token_container_type &found_eoltokens); +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPP_GRAMMAR_GEN_HPP_80CB8A59_5411_4E45_B406_62531A12FB99_INCLUDED) diff --git a/boost/wave/grammars/cpp_intlit_grammar.hpp b/boost/wave/grammars/cpp_intlit_grammar.hpp new file mode 100644 index 0000000000..96ac8f62c1 --- /dev/null +++ b/boost/wave/grammars/cpp_intlit_grammar.hpp @@ -0,0 +1,188 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_INTLIT_GRAMMAR_HPP_2E1E70B1_F15C_4132_8554_10A231B0D91C_INCLUDED) +#define CPP_INTLIT_GRAMMAR_HPP_2E1E70B1_F15C_4132_8554_10A231B0D91C_INCLUDED + +#include <boost/wave/wave_config.hpp> + +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_closure.hpp> +#include <boost/spirit/include/classic_assign_actor.hpp> +#include <boost/spirit/include/classic_push_back_actor.hpp> + +#include <boost/spirit/include/phoenix1_operators.hpp> +#include <boost/spirit/include/phoenix1_primitives.hpp> +#include <boost/spirit/include/phoenix1_statements.hpp> + +#include <boost/wave/cpp_exceptions.hpp> +#include <boost/wave/grammars/cpp_literal_grammar_gen.hpp> + +#if !defined(spirit_append_actor) +#define spirit_append_actor(actor) boost::spirit::classic::push_back_a(actor) +#define spirit_assign_actor(actor) boost::spirit::classic::assign_a(actor) +#endif // !defined(spirit_append_actor) + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// Reusable grammar for parsing of C++ style integer literals +// +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { + +/////////////////////////////////////////////////////////////////////////////// +namespace closures { + + struct intlit_closure + : boost::spirit::classic::closure<intlit_closure, uint_literal_type> + { + member1 val; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// define, whether the rule's should generate some debug output +#define TRACE_INTLIT_GRAMMAR \ + bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_INTLIT_GRAMMAR) \ + /**/ + +struct intlit_grammar : + boost::spirit::classic::grammar<intlit_grammar, closures::intlit_closure::context_t> +{ + intlit_grammar(bool &is_unsigned_) : is_unsigned(is_unsigned_) + { + BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "intlit_grammar", + TRACE_INTLIT_GRAMMAR); + } + + template <typename ScannerT> + struct definition + { + typedef boost::spirit::classic::rule<ScannerT> rule_t; + + rule_t int_lit; + boost::spirit::classic::subrule<0> sub_int_lit; + boost::spirit::classic::subrule<1> oct_lit; + boost::spirit::classic::subrule<2> hex_lit; + boost::spirit::classic::subrule<3> dec_lit; + + definition(intlit_grammar const &self) + { + using namespace boost::spirit::classic; + namespace phx = phoenix; + + + int_lit = ( + sub_int_lit = + ( ch_p('0')[self.val = 0] >> (hex_lit | oct_lit) + | dec_lit + ) + >> !as_lower_d[ + (ch_p('u')[phx::var(self.is_unsigned) = true] || ch_p('l')) + | (ch_p('l') || ch_p('u')[phx::var(self.is_unsigned) = true]) + ] + , + + hex_lit = + (ch_p('X') | ch_p('x')) + >> uint_parser<uint_literal_type, 16>() + [ + self.val = phx::arg1, + phx::var(self.is_unsigned) = true + ] + , + + oct_lit = + !uint_parser<uint_literal_type, 8>() + [ + self.val = phx::arg1, + phx::var(self.is_unsigned) = true + ] + , + + dec_lit = + uint_parser<uint_literal_type, 10>() + [ + self.val = phx::arg1 + ] + ) + ; + + BOOST_SPIRIT_DEBUG_TRACE_RULE(int_lit, TRACE_INTLIT_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(sub_int_lit, TRACE_INTLIT_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(hex_lit, TRACE_INTLIT_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(oct_lit, TRACE_INTLIT_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(dec_lit, TRACE_INTLIT_GRAMMAR); + } + + // start rule of this grammar + rule_t const& start() const + { return int_lit; } + }; + + bool &is_unsigned; +}; + +#undef TRACE_INTLIT_GRAMMAR + +/////////////////////////////////////////////////////////////////////////////// +// +// The following function is defined here, to allow the separation of +// the compilation of the intlit_grammar from the function using it. +// +/////////////////////////////////////////////////////////////////////////////// + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 +#define BOOST_WAVE_INTLITGRAMMAR_GEN_INLINE +#else +#define BOOST_WAVE_INTLITGRAMMAR_GEN_INLINE inline +#endif + +template <typename TokenT> +BOOST_WAVE_INTLITGRAMMAR_GEN_INLINE +uint_literal_type +intlit_grammar_gen<TokenT>::evaluate(TokenT const &token, + bool &is_unsigned) +{ + using namespace boost::spirit::classic; + +intlit_grammar g(is_unsigned); +uint_literal_type result = 0; +typename TokenT::string_type const &token_val = token.get_value(); +parse_info<typename TokenT::string_type::const_iterator> hit = + parse(token_val.begin(), token_val.end(), g[spirit_assign_actor(result)]); + + if (!hit.hit) { + BOOST_WAVE_THROW(preprocess_exception, ill_formed_integer_literal, + token_val.c_str(), token.get_position()); + } + return result; +} + +#undef BOOST_WAVE_INTLITGRAMMAR_GEN_INLINE + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPP_INTLIT_GRAMMAR_HPP_2E1E70B1_F15C_4132_8554_10A231B0D91C_INCLUDED) diff --git a/boost/wave/grammars/cpp_literal_grammar_gen.hpp b/boost/wave/grammars/cpp_literal_grammar_gen.hpp new file mode 100644 index 0000000000..f6e24159bd --- /dev/null +++ b/boost/wave/grammars/cpp_literal_grammar_gen.hpp @@ -0,0 +1,77 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_LITERAL_GRAMMAR_GEN_HPP_67794A6C_468A_4AAB_A757_DEDDB182F5A0_INCLUDED) +#define CPP_LITERAL_GRAMMAR_GEN_HPP_67794A6C_468A_4AAB_A757_DEDDB182F5A0_INCLUDED + +#include <boost/wave/wave_config.hpp> +#include <boost/wave/grammars/cpp_value_error.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +// suppress warnings about dependent classes not being exported from the dll +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable : 4251 4231 4660) +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { + +/////////////////////////////////////////////////////////////////////////////// +// +// cpp_intlit_grammar_gen template class +// +// This template helps separating the compilation of the intlit_grammar +// class from the compilation of the expression_grammar. This is done +// to safe compilation time. +// +/////////////////////////////////////////////////////////////////////////////// +template <typename TokenT> +struct BOOST_WAVE_DECL intlit_grammar_gen { + + static uint_literal_type evaluate(TokenT const &tok, bool &is_unsigned); +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// cpp_chlit_grammar_gen template class +// +// This template helps separating the compilation of the chlit_grammar +// class from the compilation of the expression_grammar. This is done +// to safe compilation time. +// +/////////////////////////////////////////////////////////////////////////////// +template <typename IntegralResult, typename TokenT> +struct BOOST_WAVE_DECL chlit_grammar_gen { + + static IntegralResult evaluate(TokenT const &tok, value_error& status); +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPP_LITERAL_GRAMMAR_GEN_HPP_67794A6C_468A_4AAB_A757_DEDDB182F5A0_INCLUDED) diff --git a/boost/wave/grammars/cpp_predef_macros_gen.hpp b/boost/wave/grammars/cpp_predef_macros_gen.hpp new file mode 100644 index 0000000000..4e66a53cbd --- /dev/null +++ b/boost/wave/grammars/cpp_predef_macros_gen.hpp @@ -0,0 +1,80 @@ +/*============================================================================= + A Standard compliant C++ preprocessor + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_PREDEF_MACROS_GEN_HPP_CADB6D2C_76A4_4988_83E1_EFFC6902B9A2_INCLUDED) +#define CPP_PREDEF_MACROS_GEN_HPP_CADB6D2C_76A4_4988_83E1_EFFC6902B9A2_INCLUDED + +#include <boost/spirit/include/classic_parse_tree.hpp> + +#include <boost/wave/wave_config.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +// suppress warnings about dependent classes not being exported from the dll +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable : 4251 4231 4660) +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { + +/////////////////////////////////////////////////////////////////////////////// +// +// Here are the node id's of the different node of the cpp_grammar +// +/////////////////////////////////////////////////////////////////////////////// +#define BOOST_WAVE_PLAIN_DEFINE_ID 5 +#define BOOST_WAVE_MACRO_PARAMETERS_ID 6 +#define BOOST_WAVE_MACRO_DEFINITION_ID 7 + +/////////////////////////////////////////////////////////////////////////////// +// +// predefined_macros_grammar_gen template class +// +// This template helps separating the compilation of the +// predefined_macros_grammar class from the compilation of the +// main pp_iterator. This is done to safe compilation time. +// +// This class helps parsing command line given macro definitions in a +// similar way, as macros are parsed by the cpp_grammar class. +// +/////////////////////////////////////////////////////////////////////////////// + +template <typename LexIteratorT> +struct BOOST_WAVE_DECL predefined_macros_grammar_gen +{ + typedef LexIteratorT iterator_type; + +// parse the cpp_grammar and return the resulting parse tree + static boost::spirit::classic::tree_parse_info<iterator_type> + parse_predefined_macro (iterator_type const &first, iterator_type const &last); +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPP_PREDEF_MACROS_GEN_HPP_CADB6D2C_76A4_4988_83E1_EFFC6902B9A2_INCLUDED) diff --git a/boost/wave/grammars/cpp_predef_macros_grammar.hpp b/boost/wave/grammars/cpp_predef_macros_grammar.hpp new file mode 100644 index 0000000000..9d35a2f461 --- /dev/null +++ b/boost/wave/grammars/cpp_predef_macros_grammar.hpp @@ -0,0 +1,178 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_PREDEF_MACROS_GRAMMAR_HPP_53858C9A_C202_4D60_AD92_DC9CAE4DBB43_INCLUDED) +#define CPP_PREDEF_MACROS_GRAMMAR_HPP_53858C9A_C202_4D60_AD92_DC9CAE4DBB43_INCLUDED + +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_parse_tree.hpp> +#include <boost/spirit/include/classic_confix.hpp> +#include <boost/spirit/include/classic_lists.hpp> + +#include <boost/wave/wave_config.hpp> +#include <boost/wave/token_ids.hpp> +#include <boost/wave/grammars/cpp_predef_macros_gen.hpp> +#include <boost/wave/util/pattern_parser.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { + +/////////////////////////////////////////////////////////////////////////////// +// define, whether the rule's should generate some debug output +#define TRACE_PREDEF_MACROS_GRAMMAR \ + bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_PREDEF_MACROS_GRAMMAR) \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +// Encapsulation of the grammar for command line driven predefined macros. +struct predefined_macros_grammar : + public boost::spirit::classic::grammar<predefined_macros_grammar> +{ + template <typename ScannerT> + struct definition + { + // 'normal' (parse_tree generating) rule type + typedef boost::spirit::classic::rule< + ScannerT, boost::spirit::classic::dynamic_parser_tag> + rule_type; + + rule_type plain_define, macro_definition, macro_parameters; + + definition(predefined_macros_grammar const &/*self*/) + { + // import the spirit and cpplexer namespaces here + using namespace boost::spirit::classic; + using namespace boost::wave; + using namespace boost::wave::util; + + // set the rule id's for later use + plain_define.set_id(BOOST_WAVE_PLAIN_DEFINE_ID); + macro_parameters.set_id(BOOST_WAVE_MACRO_PARAMETERS_ID); + macro_definition.set_id(BOOST_WAVE_MACRO_DEFINITION_ID); + + // recognizes command line defined macro syntax, i.e. + // -DMACRO + // -DMACRO= + // -DMACRO=value + // -DMACRO(x) + // -DMACRO(x)= + // -DMACRO(x)=value + + // This grammar resembles the overall structure of the cpp_grammar to + // make it possible to reuse the parse tree traversal code + plain_define + = ( ch_p(T_IDENTIFIER) + | pattern_p(KeywordTokenType, + TokenTypeMask|PPTokenFlag) + | pattern_p(OperatorTokenType|AltExtTokenType, + ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc. + | pattern_p(BoolLiteralTokenType, + TokenTypeMask|PPTokenFlag) // true/false + ) + >> !macro_parameters + >> !macro_definition + ; + + // parameter list + macro_parameters + = confix_p( + no_node_d[ch_p(T_LEFTPAREN) >> *ch_p(T_SPACE)], + !list_p( + ( ch_p(T_IDENTIFIER) + | pattern_p(KeywordTokenType, + TokenTypeMask|PPTokenFlag) + | pattern_p(OperatorTokenType|AltExtTokenType, + ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc. + | pattern_p(BoolLiteralTokenType, + TokenTypeMask|PPTokenFlag) // true/false +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + | ch_p(T_ELLIPSIS) +#endif + ), + no_node_d + [ + *ch_p(T_SPACE) >> ch_p(T_COMMA) >> *ch_p(T_SPACE) + ] + ), + no_node_d[*ch_p(T_SPACE) >> ch_p(T_RIGHTPAREN)] + ) + ; + + // macro body (anything left until eol) + macro_definition + = no_node_d[ch_p(T_ASSIGN)] + >> *anychar_p + ; + + BOOST_SPIRIT_DEBUG_TRACE_RULE(plain_define, TRACE_PREDEF_MACROS_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_definition, TRACE_PREDEF_MACROS_GRAMMAR); + BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_parameters, TRACE_PREDEF_MACROS_GRAMMAR); + } + + // start rule of this grammar + rule_type const& start() const + { return plain_define; } + }; + + predefined_macros_grammar() + { + BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, + "predefined_macros_grammar", TRACE_PREDEF_MACROS_GRAMMAR); + } + +}; + +/////////////////////////////////////////////////////////////////////////////// +#undef TRACE_PREDEF_MACROS_GRAMMAR + +/////////////////////////////////////////////////////////////////////////////// +// +// The following parse function is defined here, to allow the separation of +// the compilation of the cpp_predefined_macros_grammar from the function +// using it. +// +/////////////////////////////////////////////////////////////////////////////// + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 +#define BOOST_WAVE_PREDEF_MACROS_GRAMMAR_GEN_INLINE +#else +#define BOOST_WAVE_PREDEF_MACROS_GRAMMAR_GEN_INLINE inline +#endif + +template <typename LexIteratorT> +BOOST_WAVE_PREDEF_MACROS_GRAMMAR_GEN_INLINE +boost::spirit::classic::tree_parse_info<LexIteratorT> +predefined_macros_grammar_gen<LexIteratorT>::parse_predefined_macro ( + LexIteratorT const &first, LexIteratorT const &last) +{ + predefined_macros_grammar g; + return boost::spirit::classic::pt_parse (first, last, g); +} + +#undef BOOST_WAVE_PREDEF_MACROS_GRAMMAR_GEN_INLINE + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPP_PREDEF_MACROS_GRAMMAR_HPP_53858C9A_C202_4D60_AD92_DC9CAE4DBB43_INCLUDED) diff --git a/boost/wave/grammars/cpp_value_error.hpp b/boost/wave/grammars/cpp_value_error.hpp new file mode 100644 index 0000000000..9cba99a264 --- /dev/null +++ b/boost/wave/grammars/cpp_value_error.hpp @@ -0,0 +1,51 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(BOOST_WAVE_CPP_VALUE_ERROR_INCLUDED) +#define BOOST_WAVE_CPP_VALUE_ERROR_INCLUDED + +#include <boost/wave/wave_config.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { + +/////////////////////////////////////////////////////////////////////////////// +// +// value_error enum type +// +// This is used to encode any error occurred during the evaluation of a +// conditional preprocessor expression +// +/////////////////////////////////////////////////////////////////////////////// +enum value_error { + error_noerror = 0x0, + error_division_by_zero = 0x1, + error_integer_overflow = 0x2, + error_character_overflow = 0x4 +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace grammars +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(BOOST_WAVE_CPP_VALUE_ERROR_INCLUDED) diff --git a/boost/wave/language_support.hpp b/boost/wave/language_support.hpp new file mode 100644 index 0000000000..f4e599894a --- /dev/null +++ b/boost/wave/language_support.hpp @@ -0,0 +1,215 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + Definition of the various language support constants + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(LANGUAGE_SUPPORT_HPP_93EDD057_2DEF_44BC_BC9F_FDABB9F51AFA_INCLUDED) +#define LANGUAGE_SUPPORT_HPP_93EDD057_2DEF_44BC_BC9F_FDABB9F51AFA_INCLUDED + +#include <boost/wave/wave_config.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { + +enum language_support { +// support flags for C++98 + support_normal = 0x01, + support_cpp = support_normal, + + support_option_long_long = 0x02, + +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 +// support flags for C99 + support_option_variadics = 0x04, + support_c99 = support_option_variadics | support_option_long_long | 0x08, +#endif +#if BOOST_WAVE_SUPPORT_CPP0X != 0 + support_cpp0x = support_option_variadics | support_option_long_long | 0x10, +#endif + + support_option_mask = 0xFFB0, + support_option_emit_contnewlines = 0x0040, + support_option_insert_whitespace = 0x0080, + support_option_preserve_comments = 0x0100, + support_option_no_character_validation = 0x0200, + support_option_convert_trigraphs = 0x0400, + support_option_single_line = 0x0800, + support_option_prefer_pp_numbers = 0x1000, + support_option_emit_line_directives = 0x2000, + support_option_include_guard_detection = 0x4000, + support_option_emit_pragma_directives = 0x8000 +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// need_cpp +// +// Extract, if the language to support is C++98 +// +/////////////////////////////////////////////////////////////////////////////// +inline bool +need_cpp(language_support language) +{ + return (language & ~support_option_mask) == support_cpp; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// need_cpp0x +// +// Extract, if the language to support is C++0x +// +/////////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_SUPPORT_CPP0X != 0 + +inline bool +need_cpp0x(language_support language) +{ + return (language & ~support_option_mask) == support_cpp0x; +} + +#else + +inline bool +need_cpp0x(language_support language) +{ + return false; +} + +#endif + +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 +/////////////////////////////////////////////////////////////////////////////// +// +// need_c99 +// +// Extract, if the language to support is C99 +// +/////////////////////////////////////////////////////////////////////////////// +inline bool +need_c99(language_support language) +{ + return (language & ~support_option_mask) == support_c99; +} + +#else // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + +/////////////////////////////////////////////////////////////////////////////// +inline bool +need_variadics(language_support language) +{ + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +inline language_support +enable_variadics(language_support language, bool enable = true) +{ + return language; +} + +////////////////////////////////////////////////////////////////////////////// +inline bool +need_c99(language_support language) +{ + return false; +} + +#endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 + +/////////////////////////////////////////////////////////////////////////////// +// +// get_support_options +// +// Set preserve comments support in the language to support +// +/////////////////////////////////////////////////////////////////////////////// +inline language_support +get_support_options(language_support language) +{ + return static_cast<language_support>(language & support_option_mask); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// set_support_options +// +// Set language option (for fine tuning of lexer behavior) +// +/////////////////////////////////////////////////////////////////////////////// +inline language_support +set_support_options(language_support language, language_support option) +{ + return static_cast<language_support>( + (language & ~support_option_mask) | (option & support_option_mask)); +} + +/////////////////////////////////////////////////////////////////////////////// +// Get and set different language options +#define BOOST_WAVE_NEED_OPTION(option) \ + inline bool need_ ## option(language_support language) \ + { \ + return (language & support_option_ ## option) ? true : false; \ + } \ + /**/ + +#define BOOST_WAVE_ENABLE_OPTION(option) \ + inline language_support \ + enable_ ## option(language_support language, bool enable = true) \ + { \ + if (enable) \ + return static_cast<language_support>(language | support_option_ ## option); \ + return static_cast<language_support>(language & ~support_option_ ## option); \ + } \ + /**/ + +#define BOOST_WAVE_OPTION(option) \ + BOOST_WAVE_NEED_OPTION(option) \ + BOOST_WAVE_ENABLE_OPTION(option) \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +BOOST_WAVE_OPTION(long_long) // support_option_long_long +BOOST_WAVE_OPTION(no_character_validation) // support_option_no_character_validation +BOOST_WAVE_OPTION(preserve_comments) // support_option_preserve_comments +BOOST_WAVE_OPTION(prefer_pp_numbers) // support_option_prefer_pp_numbers +BOOST_WAVE_OPTION(emit_line_directives) // support_option_emit_line_directives +BOOST_WAVE_OPTION(single_line) // support_option_single_line +BOOST_WAVE_OPTION(convert_trigraphs) // support_option_convert_trigraphs +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 +BOOST_WAVE_OPTION(include_guard_detection) // support_option_include_guard_detection +#endif +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 +BOOST_WAVE_OPTION(variadics) // support_option_variadics +#endif +#if BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES != 0 +BOOST_WAVE_OPTION(emit_pragma_directives) // support_option_emit_pragma_directives +#endif +BOOST_WAVE_OPTION(insert_whitespace) // support_option_insert_whitespace +BOOST_WAVE_OPTION(emit_contnewlines) // support_option_emit_contnewlines + +#undef BOOST_WAVE_NEED_OPTION +#undef BOOST_WAVE_ENABLE_OPTION +#undef BOOST_WAVE_OPTION + +/////////////////////////////////////////////////////////////////////////////// +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(LANGUAGE_SUPPORT_HPP_93EDD057_2DEF_44BC_BC9F_FDABB9F51AFA_INCLUDED) diff --git a/boost/wave/preprocessing_hooks.hpp b/boost/wave/preprocessing_hooks.hpp new file mode 100644 index 0000000000..b57311323b --- /dev/null +++ b/boost/wave/preprocessing_hooks.hpp @@ -0,0 +1,818 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(DEFAULT_PREPROCESSING_HOOKS_HPP_INCLUDED) +#define DEFAULT_PREPROCESSING_HOOKS_HPP_INCLUDED + +#include <boost/wave/wave_config.hpp> +#include <boost/wave/util/cpp_include_paths.hpp> + +#include <vector> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace context_policies { + +/////////////////////////////////////////////////////////////////////////////// +// +// The default_preprocessing_hooks class is a placeholder for all +// preprocessing hooks called from inside the preprocessing engine +// +/////////////////////////////////////////////////////////////////////////////// +struct default_preprocessing_hooks +{ + /////////////////////////////////////////////////////////////////////////// + // + // The function 'expanding_function_like_macro' is called, whenever a + // function-like macro is to be expanded. + // + // The parameter 'macrodef' marks the position, where the macro to expand + // is defined. + // + // The parameter 'formal_args' holds the formal arguments used during the + // definition of the macro. + // + // The parameter 'definition' holds the macro definition for the macro to + // trace. + // + // The parameter 'macro_call' marks the position, where this macro invoked. + // + // The parameter 'arguments' holds the macro arguments used during the + // invocation of the macro + // + // The parameters 'seqstart' and 'seqend' point into the input token + // stream allowing to access the whole token sequence comprising the macro + // invocation (starting with the opening parenthesis and ending after the + // closing one). + // + // The return value defines whether the corresponding macro will be + // expanded (return false) or will be copied to the output (return true). + // Note: the whole argument list is copied unchanged to the output as well + // without any further processing. + // + /////////////////////////////////////////////////////////////////////////// + +#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 + // old signature + template <typename TokenT, typename ContainerT> + void expanding_function_like_macro( + TokenT const& macrodef, std::vector<TokenT> const& formal_args, + ContainerT const& definition, + TokenT const& macrocall, std::vector<ContainerT> const& arguments) + {} +#else + // new signature + template <typename ContextT, typename TokenT, typename ContainerT, typename IteratorT> + bool + expanding_function_like_macro(ContextT const& ctx, + TokenT const& macrodef, std::vector<TokenT> const& formal_args, + ContainerT const& definition, + TokenT const& macrocall, std::vector<ContainerT> const& arguments, + IteratorT const& seqstart, IteratorT const& seqend) + { return false; } // default is to normally expand the macro +#endif + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'expanding_object_like_macro' is called, whenever a + // object-like macro is to be expanded . + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'macro' marks the position, where the macro to expand + // is defined. + // + // The definition 'definition' holds the macro definition for the macro to + // trace. + // + // The parameter 'macrocall' marks the position, where this macro invoked. + // + // The return value defines whether the corresponding macro will be + // expanded (return false) or will be copied to the output (return true). + // + /////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 + // old signature + template <typename TokenT, typename ContainerT> + void expanding_object_like_macro(TokenT const& macro, + ContainerT const& definition, TokenT const& macrocall) + {} +#else + // new signature + template <typename ContextT, typename TokenT, typename ContainerT> + bool + expanding_object_like_macro(ContextT const& ctx, TokenT const& macro, + ContainerT const& definition, TokenT const& macrocall) + { return false; } // default is to normally expand the macro +#endif + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'expanded_macro' is called, whenever the expansion of a + // macro is finished but before the rescanning process starts. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'result' contains the token sequence generated as the + // result of the macro expansion. + // + /////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 + // old signature + template <typename ContainerT> + void expanded_macro(ContainerT const& result) + {} +#else + // new signature + template <typename ContextT, typename ContainerT> + void expanded_macro(ContextT const& ctx, ContainerT const& result) + {} +#endif + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'rescanned_macro' is called, whenever the rescanning of a + // macro is finished. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'result' contains the token sequence generated as the + // result of the rescanning. + // + /////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 + // old signature + template <typename ContainerT> + void rescanned_macro(ContainerT const& result) + {} +#else + // new signature + template <typename ContextT, typename ContainerT> + void rescanned_macro(ContextT const& ctx, ContainerT const& result) + {} +#endif + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'locate_include_file' is called, whenever a #include + // directive was encountered. It is supposed to locate the given file and + // should return the full file name of the located file. This file name + // is expected to uniquely identify the referenced file. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'file_path' contains the (expanded) file name found after + // the #include directive. This parameter holds the string as it is + // specified in the #include directive, i.e. <file> or "file" will result + // in a parameter value 'file'. + // + // The parameter 'is_system' is set to 'true' if this call happens as a + // result of a #include '<file>' directive, it is 'false' otherwise, i.e. + // for #include "file" directives. + // + // The parameter 'current_name' is only used if a #include_next directive + // was encountered (and BOOST_WAVE_SUPPORT_INCLUDE_NEXT was defined to be + // non-zero). In this case it points to unique full name of the current + // include file (if any). Otherwise this parameter is set to NULL. + // + // The parameter 'dir_path' on return is expected to hold the directory + // part of the located file. + // + // The parameter 'native_name' on return is expected to hold the unique + // full file name of the located file. + // + // The return value defines whether the file was located successfully. + // + /////////////////////////////////////////////////////////////////////////// + template <typename ContextT> + bool + locate_include_file(ContextT& ctx, std::string &file_path, + bool is_system, char const *current_name, std::string &dir_path, + std::string &native_name) + { + if (!ctx.find_include_file (file_path, dir_path, is_system, current_name)) + return false; // could not locate file + + namespace fs = boost::filesystem; + + fs::path native_path(wave::util::create_path(file_path)); + if (!fs::exists(native_path)) { + BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_file, + file_path.c_str(), ctx.get_main_pos()); + return false; + } + + // return the unique full file system path of the located file + native_name = wave::util::native_file_string(native_path); + + return true; // include file has been located successfully + } + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'found_include_directive' is called, whenever a #include + // directive was located. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'filename' contains the (expanded) file name found after + // the #include directive. This has the format '<file>', '"file"' or + // 'file'. + // The formats '<file>' or '"file"' are used for #include directives found + // in the preprocessed token stream, the format 'file' is used for files + // specified through the --force_include command line argument. + // + // The parameter 'include_next' is set to true if the found directive was + // a #include_next directive and the BOOST_WAVE_SUPPORT_INCLUDE_NEXT + // preprocessing constant was defined to something != 0. + // + // The return value defines whether the found file will be included + // (return false) or will be skipped (return true). + // + /////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 + // old signature + void + found_include_directive(std::string const& filename, bool include_next) + {} +#else + // new signature + template <typename ContextT> + bool + found_include_directive(ContextT const& ctx, std::string const& filename, + bool include_next) + { + return false; // ok to include this file + } +#endif + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'opened_include_file' is called, whenever a file referred + // by an #include directive was successfully located and opened. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'filename' contains the file system path of the + // opened file (this is relative to the directory of the currently + // processed file or a absolute path depending on the paths given as the + // include search paths). + // + // The include_depth parameter contains the current include file depth. + // + // The is_system_include parameter denotes whether the given file was + // found as a result of a #include <...> directive. + // + /////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 + // old signature + void + opened_include_file(std::string const& relname, std::string const& absname, + std::size_t include_depth, bool is_system_include) + {} +#else + // new signature + template <typename ContextT> + void + opened_include_file(ContextT const& ctx, std::string const& relname, + std::string const& absname, bool is_system_include) + {} +#endif + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'returning_from_include_file' is called, whenever an + // included file is about to be closed after it's processing is complete. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + /////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 + // old signature + void + returning_from_include_file() + {} +#else + // new signature + template <typename ContextT> + void + returning_from_include_file(ContextT const& ctx) + {} +#endif + +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + /////////////////////////////////////////////////////////////////////////// + // + // The function 'detected_include_guard' is called whenever either a + // include file is about to be added to the list of #pragma once headers. + // That means this header file will not be opened and parsed again even + // if it is specified in a later #include directive. + // This function is called as the result of a detected include guard + // scheme. + // + // The implemented heuristics for include guards detects two forms of + // include guards: + // + // #ifndef INCLUDE_GUARD_MACRO + // #define INCLUDE_GUARD_MACRO + // ... + // #endif + // + // or + // + // if !defined(INCLUDE_GUARD_MACRO) + // #define INCLUDE_GUARD_MACRO + // ... + // #endif + // + // note, that the parenthesis are optional (i.e. !defined INCLUDE_GUARD_MACRO + // will work as well). The code allows for any whitespace, newline and single + // '#' tokens before the #if/#ifndef and after the final #endif. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'filename' contains the file system path of the + // opened file (this is relative to the directory of the currently + // processed file or a absolute path depending on the paths given as the + // include search paths). + // + // The parameter contains the name of the detected include guard. + // + /////////////////////////////////////////////////////////////////////////// + template <typename ContextT> + void + detected_include_guard(ContextT const& ctx, std::string const& filename, + std::string const& include_guard) + {} + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'detected_pragma_once' is called whenever either a + // include file is about to be added to the list of #pragma once headers. + // That means this header file will not be opened and parsed again even + // if it is specified in a later #include directive. + // This function is called as the result of a detected directive + // #pragma once. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter pragma_token refers to the token "#pragma" triggering + // this preprocessing hook. + // + // The parameter 'filename' contains the file system path of the + // opened file (this is relative to the directory of the currently + // processed file or a absolute path depending on the paths given as the + // include search paths). + // + /////////////////////////////////////////////////////////////////////////// + template <typename ContextT, typename TokenT> + void + detected_pragma_once(ContextT const& ctx, TokenT const& pragma_token, + std::string const& filename) + {} +#endif + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'interpret_pragma' is called, whenever a '#pragma command' + // directive is found which isn't known to the core Wave library, where + // 'command' is the value defined as the BOOST_WAVE_PRAGMA_KEYWORD constant + // which defaults to "wave". + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'pending' may be used to push tokens back into the input + // stream, which are to be used as the replacement text for the whole + // #pragma directive. + // + // The parameter 'option' contains the name of the interpreted pragma. + // + // The parameter 'values' holds the values of the parameter provided to + // the pragma operator. + // + // The parameter 'act_token' contains the actual #pragma token, which may + // be used for error output. + // + // If the return value is 'false', the whole #pragma directive is + // interpreted as unknown and a corresponding error message is issued. A + // return value of 'true' signs a successful interpretation of the given + // #pragma. + // + /////////////////////////////////////////////////////////////////////////// + template <typename ContextT, typename ContainerT> + bool + interpret_pragma(ContextT const& ctx, ContainerT &pending, + typename ContextT::token_type const& option, ContainerT const& values, + typename ContextT::token_type const& act_token) + { + return false; + } + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'emit_line_directive' is called whenever a #line directive + // has to be emitted into the generated output. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'pending' may be used to push tokens back into the input + // stream, which are to be used instead of the default output generated + // for the #line directive. + // + // The parameter 'act_token' contains the actual #pragma token, which may + // be used for error output. The line number stored in this token can be + // used as the line number emitted as part of the #line directive. + // + // If the return value is 'false', a default #line directive is emitted + // by the library. A return value of 'true' will inhibit any further + // actions, the tokens contained in 'pending' will be copied verbatim + // to the output. + // + /////////////////////////////////////////////////////////////////////////// + template <typename ContextT, typename ContainerT> + bool + emit_line_directive(ContextT const& ctx, ContainerT &pending, + typename ContextT::token_type const& act_token) + { + return false; + } + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'defined_macro' is called, whenever a macro was defined + // successfully. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'name' is a reference to the token holding the macro name. + // + // The parameter 'is_functionlike' is set to true, whenever the newly + // defined macro is defined as a function like macro. + // + // The parameter 'parameters' holds the parameter tokens for the macro + // definition. If the macro has no parameters or if it is a object like + // macro, then this container is empty. + // + // The parameter 'definition' contains the token sequence given as the + // replacement sequence (definition part) of the newly defined macro. + // + // The parameter 'is_predefined' is set to true for all macros predefined + // during the initialization phase of the library. + // + /////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 + // old signature + template <typename TokenT, typename ParametersT, typename DefinitionT> + void + defined_macro(TokenT const& macro_name, bool is_functionlike, + ParametersT const& parameters, DefinitionT const& definition, + bool is_predefined) + {} +#else + // new signature + template < + typename ContextT, typename TokenT, typename ParametersT, + typename DefinitionT + > + void + defined_macro(ContextT const& ctx, TokenT const& macro_name, + bool is_functionlike, ParametersT const& parameters, + DefinitionT const& definition, bool is_predefined) + {} +#endif + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'undefined_macro' is called, whenever a macro definition + // was removed successfully. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'name' holds the name of the macro, which definition was + // removed. + // + /////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 + // old signature + template <typename TokenT> + void + undefined_macro(TokenT const& macro_name) + {} +#else + // new signature + template <typename ContextT, typename TokenT> + void + undefined_macro(ContextT const& ctx, TokenT const& macro_name) + {} +#endif + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'found_directive' is called, whenever a preprocessor + // directive was encountered, but before the corresponding action is + // executed. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'directive' is a reference to the token holding the + // preprocessing directive. + // + // The return value defines whether the given expression has to be + // to be executed in a normal way (return 'false'), or if it has to be + // skipped altogether (return 'true'), which means it gets replaced in the + // output by a single newline. + // + /////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 + // old signature + template <typename TokenT> + void + found_directive(TokenT const& directive) + {} +#else + // new signature + template <typename ContextT, typename TokenT> + bool + found_directive(ContextT const& ctx, TokenT const& directive) + { return false; } // by default we never skip any directives +#endif + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'found_unknown_directive' is called, whenever an unknown + // preprocessor directive was encountered. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'line' holds the tokens of the entire source line + // containing the unknown directive. + // + // The parameter 'pending' may be used to push tokens back into the input + // stream, which are to be used as the replacement text for the whole + // line containing the unknown directive. + // + // The return value defines whether the given expression has been + // properly interpreted by the hook function or not. If this function + // returns 'false', the library will raise an 'ill_formed_directive' + // preprocess_exception. Otherwise the tokens pushed back into 'pending' + // are passed on to the user program. + // + /////////////////////////////////////////////////////////////////////////// + template <typename ContextT, typename ContainerT> + bool + found_unknown_directive(ContextT const& ctx, ContainerT const& line, + ContainerT& pending) + { return false; } // by default we never interpret unknown directives + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'evaluated_conditional_expression' is called, whenever a + // conditional preprocessing expression was evaluated (the expression + // given to a #if, #elif, #ifdef or #ifndef directive) + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'directive' is a reference to the token holding the + // corresponding preprocessing directive. + // + // The parameter 'expression' holds the non-expanded token sequence + // comprising the evaluated expression. + // + // The parameter expression_value contains the result of the evaluation of + // the expression in the current preprocessing context. + // + // The return value defines whether the given expression has to be + // evaluated again, allowing to decide which of the conditional branches + // should be expanded. You need to return 'true' from this hook function + // to force the expression to be re-evaluated. + // + /////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 + // old signature + template <typename ContainerT> + void + evaluated_conditional_expression(ContainerT const& expression, + bool expression_value) + {} +#else + // new signature + template <typename ContextT, typename TokenT, typename ContainerT> + bool + evaluated_conditional_expression(ContextT const& ctx, + TokenT const& directive, ContainerT const& expression, + bool expression_value) + { return false; } // ok to continue, do not re-evaluate expression +#endif + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'skipped_token' is called, whenever a token is about to be + // skipped due to a false preprocessor condition (code fragments to be + // skipped inside the not evaluated conditional #if/#else/#endif branches). + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'token' refers to the token to be skipped. + // + /////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 + // old signature + template <typename TokenT> + void + skipped_token(TokenT const& token) + {} +#else + // new signature + template <typename ContextT, typename TokenT> + void + skipped_token(ContextT const& ctx, TokenT const& token) + {} +#endif + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'generated_token' will be called by the library whenever a + // token is about to be returned from the library. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 't' is the token about to be returned from the library. + // This function may alter the token, but in this case it must be + // implemented with a corresponding signature: + // + // TokenT const& + // generated_token(ContextT const& ctx, TokenT& t); + // + // which makes it possible to modify the token in place. + // + // The default behavior is to return the token passed as the parameter + // without modification. + // + /////////////////////////////////////////////////////////////////////////// + template <typename ContextT, typename TokenT> + TokenT const& + generated_token(ContextT const& ctx, TokenT const& t) + { return t; } + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'may_skip_whitespace' will be called by the + // library, whenever it must be tested whether a specific token refers to + // whitespace and this whitespace has to be skipped. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The 'token' parameter holds a reference to the current token. The policy + // is free to change this token if needed. + // + // The 'skipped_newline' parameter holds a reference to a boolean value + // which should be set to true by the policy function whenever a newline + // is going to be skipped. + // + // If the return value is true, the given token is skipped and the + // preprocessing continues to the next token. If the return value is + // false, the given token is returned to the calling application. + // + // ATTENTION! + // Caution has to be used, because by returning true the policy function + // is able to force skipping even significant tokens, not only whitespace. + // + /////////////////////////////////////////////////////////////////////////// + template <typename ContextT, typename TokenT> + bool + may_skip_whitespace(ContextT const& ctx, TokenT& token, bool& skipped_newline) + { return false; } + +#if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0 + /////////////////////////////////////////////////////////////////////////// + // + // The function 'found_warning_directive' will be called by the library + // whenever a #warning directive is found. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'message' references the argument token sequence of the + // encountered #warning directive. + // + // If the return value is false, the library throws a preprocessor + // exception of the type 'warning_directive', if the return value is true + // the execution continues as if no #warning directive has been found. + // + /////////////////////////////////////////////////////////////////////////// + template <typename ContextT, typename ContainerT> + bool + found_warning_directive(ContextT const& ctx, ContainerT const& message) + { return false; } +#endif + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'found_error_directive' will be called by the library + // whenever a #error directive is found. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'message' references the argument token sequence of the + // encountered #error directive. + // + // If the return value is false, the library throws a preprocessor + // exception of the type 'error_directive', if the return value is true + // the execution continues as if no #error directive has been found. + // + /////////////////////////////////////////////////////////////////////////// + template <typename ContextT, typename ContainerT> + bool + found_error_directive(ContextT const& ctx, ContainerT const& message) + { return false; } + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'found_line_directive' will be called by the library + // whenever a #line directive is found. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'arguments' references the argument token sequence of the + // encountered #line directive. + // + // The parameter 'line' contains the recognized line number from the #line + // directive. + // + // The parameter 'filename' references the recognized file name from the + // #line directive (if there was one given). + // + /////////////////////////////////////////////////////////////////////////// + template <typename ContextT, typename ContainerT> + void + found_line_directive(ContextT const& ctx, ContainerT const& arguments, + unsigned int line, std::string const& filename) + {} + + /////////////////////////////////////////////////////////////////////////// + // + // The function 'throw_exception' will be called by the library whenever a + // preprocessing exception occurs. + // + // The parameter 'ctx' is a reference to the context object used for + // instantiating the preprocessing iterators by the user. + // + // The parameter 'e' is the exception object containing detailed error + // information. + // + // The default behavior is to call the function boost::throw_exception. + // + /////////////////////////////////////////////////////////////////////////// + template <typename ContextT, typename ExceptionT> + void + throw_exception(ContextT const& ctx, ExceptionT const& e) + { + boost::throw_exception(e); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace context_policies +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(DEFAULT_PREPROCESSING_HOOKS_HPP_INCLUDED) diff --git a/boost/wave/token_ids.hpp b/boost/wave/token_ids.hpp new file mode 100644 index 0000000000..a2edba7e08 --- /dev/null +++ b/boost/wave/token_ids.hpp @@ -0,0 +1,378 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + The definition of a default set of token identifiers and related + functions. + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(TOKEN_IDS_HPP_414E9A58_F079_4789_8AFF_513815CE475B_INCLUDED) +#define TOKEN_IDS_HPP_414E9A58_F079_4789_8AFF_513815CE475B_INCLUDED + +#include <string> + +#include <boost/wave/wave_config.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Allow external redefinition of the token identifiers to use +#if !defined(BOOST_WAVE_TOKEN_IDS_DEFINED) +#define BOOST_WAVE_TOKEN_IDS_DEFINED + +#if (defined (__FreeBSD__) || defined (__DragonFly__) || defined (__OpenBSD__)) && defined (T_DIVIDE) +#undef T_DIVIDE +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { + +/////////////////////////////////////////////////////////////////////////////// +// assemble tokenids +#define TOKEN_FROM_ID(id, cat) ((id) | (cat)) +#define ID_FROM_TOKEN(tok) ((tok) & ~TokenTypeMask) +#define BASEID_FROM_TOKEN(tok) ((tok) & ~ExtTokenTypeMask) + +/////////////////////////////////////////////////////////////////////////////// +// the token_category helps to classify the different token types +enum token_category { + IdentifierTokenType = 0x10080000, + ParameterTokenType = 0x11080000, + ExtParameterTokenType = 0x11180000, + KeywordTokenType = 0x20080000, + OperatorTokenType = 0x30080000, + LiteralTokenType = 0x40080000, + IntegerLiteralTokenType = 0x41080000, + FloatingLiteralTokenType = 0x42080000, + StringLiteralTokenType = 0x43080000, + CharacterLiteralTokenType = 0x44080000, + BoolLiteralTokenType = 0x45080000, + PPTokenType = 0x50080000, + PPConditionalTokenType = 0x50880000, + + UnknownTokenType = 0xA0000000, + EOLTokenType = 0xB0000000, + EOFTokenType = 0xC0000000, + WhiteSpaceTokenType = 0xD0000000, + InternalTokenType = 0xE0080000, + + TokenTypeMask = 0xFF000000, + AltTokenType = 0x00100000, + TriGraphTokenType = 0x00200000, + AltExtTokenType = 0x00500000, // and, bit_and etc. + PPTokenFlag = 0x00080000, // these are 'real' pp-tokens + ExtTokenTypeMask = 0xFFF00000, + ExtTokenOnlyMask = 0x00F00000, + TokenValueMask = 0x000FFFFF, + MainTokenMask = 0xFF0FFFFF // TokenTypeMask|TokenValueMask +}; + +/////////////////////////////////////////////////////////////////////////////// +// the token_id assigns unique numbers to the different C++ lexemes +enum token_id { + T_UNKNOWN = 0, + T_FIRST_TOKEN = 256, + T_AND = TOKEN_FROM_ID(T_FIRST_TOKEN, OperatorTokenType), + T_AND_ALT = TOKEN_FROM_ID(T_FIRST_TOKEN, OperatorTokenType|AltExtTokenType), + T_ANDAND = TOKEN_FROM_ID(257, OperatorTokenType), + T_ANDAND_ALT = TOKEN_FROM_ID(257, OperatorTokenType|AltExtTokenType), + T_ASSIGN = TOKEN_FROM_ID(258, OperatorTokenType), + T_ANDASSIGN = TOKEN_FROM_ID(259, OperatorTokenType), + T_ANDASSIGN_ALT = TOKEN_FROM_ID(259, OperatorTokenType|AltExtTokenType), + T_OR = TOKEN_FROM_ID(260, OperatorTokenType), + T_OR_ALT = TOKEN_FROM_ID(260, OperatorTokenType|AltExtTokenType), + T_OR_TRIGRAPH = TOKEN_FROM_ID(260, OperatorTokenType|TriGraphTokenType), + T_ORASSIGN = TOKEN_FROM_ID(261, OperatorTokenType), + T_ORASSIGN_ALT = TOKEN_FROM_ID(261, OperatorTokenType|AltExtTokenType), + T_ORASSIGN_TRIGRAPH = TOKEN_FROM_ID(261, OperatorTokenType|TriGraphTokenType), + T_XOR = TOKEN_FROM_ID(262, OperatorTokenType), + T_XOR_ALT = TOKEN_FROM_ID(262, OperatorTokenType|AltExtTokenType), + T_XOR_TRIGRAPH = TOKEN_FROM_ID(262, OperatorTokenType|TriGraphTokenType), + T_XORASSIGN = TOKEN_FROM_ID(263, OperatorTokenType), + T_XORASSIGN_ALT = TOKEN_FROM_ID(263, OperatorTokenType|AltExtTokenType), + T_XORASSIGN_TRIGRAPH = TOKEN_FROM_ID(263, OperatorTokenType|TriGraphTokenType), + T_COMMA = TOKEN_FROM_ID(264, OperatorTokenType), + T_COLON = TOKEN_FROM_ID(265, OperatorTokenType), + T_DIVIDE = TOKEN_FROM_ID(266, OperatorTokenType), + T_DIVIDEASSIGN = TOKEN_FROM_ID(267, OperatorTokenType), + T_DOT = TOKEN_FROM_ID(268, OperatorTokenType), + T_DOTSTAR = TOKEN_FROM_ID(269, OperatorTokenType), + T_ELLIPSIS = TOKEN_FROM_ID(270, OperatorTokenType), + T_EQUAL = TOKEN_FROM_ID(271, OperatorTokenType), + T_GREATER = TOKEN_FROM_ID(272, OperatorTokenType), + T_GREATEREQUAL = TOKEN_FROM_ID(273, OperatorTokenType), + T_LEFTBRACE = TOKEN_FROM_ID(274, OperatorTokenType), + T_LEFTBRACE_ALT = TOKEN_FROM_ID(274, OperatorTokenType|AltTokenType), + T_LEFTBRACE_TRIGRAPH = TOKEN_FROM_ID(274, OperatorTokenType|TriGraphTokenType), + T_LESS = TOKEN_FROM_ID(275, OperatorTokenType), + T_LESSEQUAL = TOKEN_FROM_ID(276, OperatorTokenType), + T_LEFTPAREN = TOKEN_FROM_ID(277, OperatorTokenType), + T_LEFTBRACKET = TOKEN_FROM_ID(278, OperatorTokenType), + T_LEFTBRACKET_ALT = TOKEN_FROM_ID(278, OperatorTokenType|AltTokenType), + T_LEFTBRACKET_TRIGRAPH = TOKEN_FROM_ID(278, OperatorTokenType|TriGraphTokenType), + T_MINUS = TOKEN_FROM_ID(279, OperatorTokenType), + T_MINUSASSIGN = TOKEN_FROM_ID(280, OperatorTokenType), + T_MINUSMINUS = TOKEN_FROM_ID(281, OperatorTokenType), + T_PERCENT = TOKEN_FROM_ID(282, OperatorTokenType), + T_PERCENTASSIGN = TOKEN_FROM_ID(283, OperatorTokenType), + T_NOT = TOKEN_FROM_ID(284, OperatorTokenType), + T_NOT_ALT = TOKEN_FROM_ID(284, OperatorTokenType|AltExtTokenType), + T_NOTEQUAL = TOKEN_FROM_ID(285, OperatorTokenType), + T_NOTEQUAL_ALT = TOKEN_FROM_ID(285, OperatorTokenType|AltExtTokenType), + T_OROR = TOKEN_FROM_ID(286, OperatorTokenType), + T_OROR_ALT = TOKEN_FROM_ID(286, OperatorTokenType|AltExtTokenType), + T_OROR_TRIGRAPH = TOKEN_FROM_ID(286, OperatorTokenType|TriGraphTokenType), + T_PLUS = TOKEN_FROM_ID(287, OperatorTokenType), + T_PLUSASSIGN = TOKEN_FROM_ID(288, OperatorTokenType), + T_PLUSPLUS = TOKEN_FROM_ID(289, OperatorTokenType), + T_ARROW = TOKEN_FROM_ID(290, OperatorTokenType), + T_ARROWSTAR = TOKEN_FROM_ID(291, OperatorTokenType), + T_QUESTION_MARK = TOKEN_FROM_ID(292, OperatorTokenType), + T_RIGHTBRACE = TOKEN_FROM_ID(293, OperatorTokenType), + T_RIGHTBRACE_ALT = TOKEN_FROM_ID(293, OperatorTokenType|AltTokenType), + T_RIGHTBRACE_TRIGRAPH = TOKEN_FROM_ID(293, OperatorTokenType|TriGraphTokenType), + T_RIGHTPAREN = TOKEN_FROM_ID(294, OperatorTokenType), + T_RIGHTBRACKET = TOKEN_FROM_ID(295, OperatorTokenType), + T_RIGHTBRACKET_ALT = TOKEN_FROM_ID(295, OperatorTokenType|AltTokenType), + T_RIGHTBRACKET_TRIGRAPH = TOKEN_FROM_ID(295, OperatorTokenType|TriGraphTokenType), + T_COLON_COLON = TOKEN_FROM_ID(296, OperatorTokenType), + T_SEMICOLON = TOKEN_FROM_ID(297, OperatorTokenType), + T_SHIFTLEFT = TOKEN_FROM_ID(298, OperatorTokenType), + T_SHIFTLEFTASSIGN = TOKEN_FROM_ID(299, OperatorTokenType), + T_SHIFTRIGHT = TOKEN_FROM_ID(300, OperatorTokenType), + T_SHIFTRIGHTASSIGN = TOKEN_FROM_ID(301, OperatorTokenType), + T_STAR = TOKEN_FROM_ID(302, OperatorTokenType), + T_COMPL = TOKEN_FROM_ID(303, OperatorTokenType), + T_COMPL_ALT = TOKEN_FROM_ID(303, OperatorTokenType|AltExtTokenType), + T_COMPL_TRIGRAPH = TOKEN_FROM_ID(303, OperatorTokenType|TriGraphTokenType), + T_STARASSIGN = TOKEN_FROM_ID(304, OperatorTokenType), + T_ASM = TOKEN_FROM_ID(305, KeywordTokenType), + T_AUTO = TOKEN_FROM_ID(306, KeywordTokenType), + T_BOOL = TOKEN_FROM_ID(307, KeywordTokenType), + T_FALSE = TOKEN_FROM_ID(308, BoolLiteralTokenType), + T_TRUE = TOKEN_FROM_ID(309, BoolLiteralTokenType), + T_BREAK = TOKEN_FROM_ID(310, KeywordTokenType), + T_CASE = TOKEN_FROM_ID(311, KeywordTokenType), + T_CATCH = TOKEN_FROM_ID(312, KeywordTokenType), + T_CHAR = TOKEN_FROM_ID(313, KeywordTokenType), + T_CLASS = TOKEN_FROM_ID(314, KeywordTokenType), + T_CONST = TOKEN_FROM_ID(315, KeywordTokenType), + T_CONSTCAST = TOKEN_FROM_ID(316, KeywordTokenType), + T_CONTINUE = TOKEN_FROM_ID(317, KeywordTokenType), + T_DEFAULT = TOKEN_FROM_ID(318, KeywordTokenType), + T_DELETE = TOKEN_FROM_ID(319, KeywordTokenType), + T_DO = TOKEN_FROM_ID(320, KeywordTokenType), + T_DOUBLE = TOKEN_FROM_ID(321, KeywordTokenType), + T_DYNAMICCAST = TOKEN_FROM_ID(322, KeywordTokenType), + T_ELSE = TOKEN_FROM_ID(323, KeywordTokenType), + T_ENUM = TOKEN_FROM_ID(324, KeywordTokenType), + T_EXPLICIT = TOKEN_FROM_ID(325, KeywordTokenType), + T_EXPORT = TOKEN_FROM_ID(326, KeywordTokenType), + T_EXTERN = TOKEN_FROM_ID(327, KeywordTokenType), + T_FLOAT = TOKEN_FROM_ID(328, KeywordTokenType), + T_FOR = TOKEN_FROM_ID(329, KeywordTokenType), + T_FRIEND = TOKEN_FROM_ID(330, KeywordTokenType), + T_GOTO = TOKEN_FROM_ID(331, KeywordTokenType), + T_IF = TOKEN_FROM_ID(332, KeywordTokenType), + T_INLINE = TOKEN_FROM_ID(333, KeywordTokenType), + T_INT = TOKEN_FROM_ID(334, KeywordTokenType), + T_LONG = TOKEN_FROM_ID(335, KeywordTokenType), + T_MUTABLE = TOKEN_FROM_ID(336, KeywordTokenType), + T_NAMESPACE = TOKEN_FROM_ID(337, KeywordTokenType), + T_NEW = TOKEN_FROM_ID(338, KeywordTokenType), + T_OPERATOR = TOKEN_FROM_ID(339, KeywordTokenType), + T_PRIVATE = TOKEN_FROM_ID(340, KeywordTokenType), + T_PROTECTED = TOKEN_FROM_ID(341, KeywordTokenType), + T_PUBLIC = TOKEN_FROM_ID(342, KeywordTokenType), + T_REGISTER = TOKEN_FROM_ID(343, KeywordTokenType), + T_REINTERPRETCAST = TOKEN_FROM_ID(344, KeywordTokenType), + T_RETURN = TOKEN_FROM_ID(345, KeywordTokenType), + T_SHORT = TOKEN_FROM_ID(346, KeywordTokenType), + T_SIGNED = TOKEN_FROM_ID(347, KeywordTokenType), + T_SIZEOF = TOKEN_FROM_ID(348, KeywordTokenType), + T_STATIC = TOKEN_FROM_ID(349, KeywordTokenType), + T_STATICCAST = TOKEN_FROM_ID(350, KeywordTokenType), + T_STRUCT = TOKEN_FROM_ID(351, KeywordTokenType), + T_SWITCH = TOKEN_FROM_ID(352, KeywordTokenType), + T_TEMPLATE = TOKEN_FROM_ID(353, KeywordTokenType), + T_THIS = TOKEN_FROM_ID(354, KeywordTokenType), + T_THROW = TOKEN_FROM_ID(355, KeywordTokenType), + T_TRY = TOKEN_FROM_ID(356, KeywordTokenType), + T_TYPEDEF = TOKEN_FROM_ID(357, KeywordTokenType), + T_TYPEID = TOKEN_FROM_ID(358, KeywordTokenType), + T_TYPENAME = TOKEN_FROM_ID(359, KeywordTokenType), + T_UNION = TOKEN_FROM_ID(360, KeywordTokenType), + T_UNSIGNED = TOKEN_FROM_ID(361, KeywordTokenType), + T_USING = TOKEN_FROM_ID(362, KeywordTokenType), + T_VIRTUAL = TOKEN_FROM_ID(363, KeywordTokenType), + T_VOID = TOKEN_FROM_ID(364, KeywordTokenType), + T_VOLATILE = TOKEN_FROM_ID(365, KeywordTokenType), + T_WCHART = TOKEN_FROM_ID(366, KeywordTokenType), + T_WHILE = TOKEN_FROM_ID(367, KeywordTokenType), + T_PP_DEFINE = TOKEN_FROM_ID(368, PPTokenType), + T_PP_IF = TOKEN_FROM_ID(369, PPConditionalTokenType), + T_PP_IFDEF = TOKEN_FROM_ID(370, PPConditionalTokenType), + T_PP_IFNDEF = TOKEN_FROM_ID(371, PPConditionalTokenType), + T_PP_ELSE = TOKEN_FROM_ID(372, PPConditionalTokenType), + T_PP_ELIF = TOKEN_FROM_ID(373, PPConditionalTokenType), + T_PP_ENDIF = TOKEN_FROM_ID(374, PPConditionalTokenType), + T_PP_ERROR = TOKEN_FROM_ID(375, PPTokenType), + T_PP_LINE = TOKEN_FROM_ID(376, PPTokenType), + T_PP_PRAGMA = TOKEN_FROM_ID(377, PPTokenType), + T_PP_UNDEF = TOKEN_FROM_ID(378, PPTokenType), + T_PP_WARNING = TOKEN_FROM_ID(379, PPTokenType), + T_IDENTIFIER = TOKEN_FROM_ID(380, IdentifierTokenType), + T_OCTALINT = TOKEN_FROM_ID(381, IntegerLiteralTokenType), + T_DECIMALINT = TOKEN_FROM_ID(382, IntegerLiteralTokenType), + T_HEXAINT = TOKEN_FROM_ID(383, IntegerLiteralTokenType), + T_INTLIT = TOKEN_FROM_ID(384, IntegerLiteralTokenType), + T_LONGINTLIT = TOKEN_FROM_ID(385, IntegerLiteralTokenType), + T_FLOATLIT = TOKEN_FROM_ID(386, FloatingLiteralTokenType), + T_FIXEDPOINTLIT = TOKEN_FROM_ID(386, FloatingLiteralTokenType|AltTokenType), // IDL specific + T_CCOMMENT = TOKEN_FROM_ID(387, WhiteSpaceTokenType|AltTokenType), + T_CPPCOMMENT = TOKEN_FROM_ID(388, WhiteSpaceTokenType|AltTokenType), + T_CHARLIT = TOKEN_FROM_ID(389, CharacterLiteralTokenType), + T_STRINGLIT = TOKEN_FROM_ID(390, StringLiteralTokenType), + T_CONTLINE = TOKEN_FROM_ID(391, EOLTokenType), + T_SPACE = TOKEN_FROM_ID(392, WhiteSpaceTokenType), + T_SPACE2 = TOKEN_FROM_ID(393, WhiteSpaceTokenType), + T_NEWLINE = TOKEN_FROM_ID(394, EOLTokenType), + T_GENERATEDNEWLINE = TOKEN_FROM_ID(394, EOLTokenType|AltTokenType), + T_POUND_POUND = TOKEN_FROM_ID(395, OperatorTokenType), + T_POUND_POUND_ALT = TOKEN_FROM_ID(395, OperatorTokenType|AltTokenType), + T_POUND_POUND_TRIGRAPH = TOKEN_FROM_ID(395, OperatorTokenType|TriGraphTokenType), + T_POUND = TOKEN_FROM_ID(396, OperatorTokenType), + T_POUND_ALT = TOKEN_FROM_ID(396, OperatorTokenType|AltTokenType), + T_POUND_TRIGRAPH = TOKEN_FROM_ID(396, OperatorTokenType|TriGraphTokenType), + T_ANY = TOKEN_FROM_ID(397, UnknownTokenType), + T_ANY_TRIGRAPH = TOKEN_FROM_ID(397, UnknownTokenType|TriGraphTokenType), + T_PP_INCLUDE = TOKEN_FROM_ID(398, PPTokenType), + T_PP_QHEADER = TOKEN_FROM_ID(399, PPTokenType), + T_PP_HHEADER = TOKEN_FROM_ID(400, PPTokenType), + T_PP_INCLUDE_NEXT = TOKEN_FROM_ID(398, PPTokenType|AltTokenType), + T_PP_QHEADER_NEXT = TOKEN_FROM_ID(399, PPTokenType|AltTokenType), + T_PP_HHEADER_NEXT = TOKEN_FROM_ID(400, PPTokenType|AltTokenType), + T_EOF = TOKEN_FROM_ID(401, EOFTokenType), // end of file reached + T_EOI = TOKEN_FROM_ID(402, EOFTokenType), // end of input reached + T_PP_NUMBER = TOKEN_FROM_ID(403, InternalTokenType), + +// MS extensions + T_MSEXT_INT8 = TOKEN_FROM_ID(404, KeywordTokenType), + T_MSEXT_INT16 = TOKEN_FROM_ID(405, KeywordTokenType), + T_MSEXT_INT32 = TOKEN_FROM_ID(406, KeywordTokenType), + T_MSEXT_INT64 = TOKEN_FROM_ID(407, KeywordTokenType), + T_MSEXT_BASED = TOKEN_FROM_ID(408, KeywordTokenType), + T_MSEXT_DECLSPEC = TOKEN_FROM_ID(409, KeywordTokenType), + T_MSEXT_CDECL = TOKEN_FROM_ID(410, KeywordTokenType), + T_MSEXT_FASTCALL = TOKEN_FROM_ID(411, KeywordTokenType), + T_MSEXT_STDCALL = TOKEN_FROM_ID(412, KeywordTokenType), + T_MSEXT_TRY = TOKEN_FROM_ID(413, KeywordTokenType), + T_MSEXT_EXCEPT = TOKEN_FROM_ID(414, KeywordTokenType), + T_MSEXT_FINALLY = TOKEN_FROM_ID(415, KeywordTokenType), + T_MSEXT_LEAVE = TOKEN_FROM_ID(416, KeywordTokenType), + T_MSEXT_INLINE = TOKEN_FROM_ID(417, KeywordTokenType), + T_MSEXT_ASM = TOKEN_FROM_ID(418, KeywordTokenType), + + T_MSEXT_PP_REGION = TOKEN_FROM_ID(419, PPTokenType), + T_MSEXT_PP_ENDREGION = TOKEN_FROM_ID(420, PPTokenType), + +// import is needed to be a keyword for the C++ module Standards proposal + T_IMPORT = TOKEN_FROM_ID(421, KeywordTokenType), + +// C++0x keywords + T_ALIGNAS = TOKEN_FROM_ID(422, KeywordTokenType), + T_ALIGNOF = TOKEN_FROM_ID(423, KeywordTokenType), + T_CHAR16_T = TOKEN_FROM_ID(424, KeywordTokenType), + T_CHAR32_T = TOKEN_FROM_ID(425, KeywordTokenType), + T_CONSTEXPR = TOKEN_FROM_ID(426, KeywordTokenType), + T_DECLTYPE = TOKEN_FROM_ID(427, KeywordTokenType), + T_NOEXCEPT = TOKEN_FROM_ID(428, KeywordTokenType), + T_NULLPTR = TOKEN_FROM_ID(429, KeywordTokenType), + T_STATICASSERT = TOKEN_FROM_ID(430, KeywordTokenType), + T_THREADLOCAL = TOKEN_FROM_ID(431, KeywordTokenType), + T_RAWSTRINGLIT = TOKEN_FROM_ID(432, StringLiteralTokenType), + + T_LAST_TOKEN_ID, + T_LAST_TOKEN = ID_FROM_TOKEN(T_LAST_TOKEN_ID & ~PPTokenFlag), + +// pseudo tokens to help streamlining macro replacement, these should not +// returned from the lexer nor should these be returned from the pp-iterator + T_NONREPLACABLE_IDENTIFIER = TOKEN_FROM_ID(T_LAST_TOKEN+1, IdentifierTokenType), + T_PLACEHOLDER = TOKEN_FROM_ID(T_LAST_TOKEN+2, WhiteSpaceTokenType), + T_PLACEMARKER = TOKEN_FROM_ID(T_LAST_TOKEN+3, InternalTokenType), + T_PARAMETERBASE = TOKEN_FROM_ID(T_LAST_TOKEN+4, ParameterTokenType), + T_EXTPARAMETERBASE = TOKEN_FROM_ID(T_LAST_TOKEN+4, ExtParameterTokenType) +}; + +/////////////////////////////////////////////////////////////////////////////// +// redefine the TOKEN_FROM_ID macro to be more type safe +#undef TOKEN_FROM_ID +#define TOKEN_FROM_ID(id, cat) boost::wave::token_id((id) | (cat)) + +#undef ID_FROM_TOKEN +#define ID_FROM_TOKEN(tok) \ + boost::wave::token_id((tok) & \ + ~(boost::wave::TokenTypeMask|boost::wave::PPTokenFlag)) \ + /**/ + +#undef BASEID_FROM_TOKEN +#define BASEID_FROM_TOKEN(tok) \ + boost::wave::token_id((tok) & \ + ~(boost::wave::ExtTokenTypeMask|boost::wave::PPTokenFlag)) \ + /**/ +#define BASE_TOKEN(tok) \ + boost::wave::token_id((tok) & boost::wave::MainTokenMask) \ + /**/ +#define CATEGORY_FROM_TOKEN(tok) ((tok) & boost::wave::TokenTypeMask) +#define EXTCATEGORY_FROM_TOKEN(tok) ((tok) & boost::wave::ExtTokenTypeMask) +#define IS_CATEGORY(tok, cat) \ + ((CATEGORY_FROM_TOKEN(tok) == CATEGORY_FROM_TOKEN(cat)) ? true : false) \ + /**/ +#define IS_EXTCATEGORY(tok, cat) \ + ((EXTCATEGORY_FROM_TOKEN(tok) == EXTCATEGORY_FROM_TOKEN(cat)) ? true : false) \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +// verify whether the given token(-id) represents a valid pp_token +inline bool is_pp_token(boost::wave::token_id id) +{ + return (id & boost::wave::PPTokenFlag) ? true : false; +} + +template <typename TokenT> +inline bool is_pp_token(TokenT const& tok) +{ + return is_pp_token(boost::wave::token_id(tok)); +} + +/////////////////////////////////////////////////////////////////////////////// +// return a token name +BOOST_WAVE_DECL +BOOST_WAVE_STRINGTYPE get_token_name(token_id tokid); + +/////////////////////////////////////////////////////////////////////////////// +// return a token name +BOOST_WAVE_DECL +char const *get_token_value(token_id tokid); + +/////////////////////////////////////////////////////////////////////////////// +} // namespace wave +} // namespace boost + +#endif // #if !defined(BOOST_WAVE_TOKEN_IDS_DEFINED) + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(TOKEN_IDS_HPP_414E9A58_F079_4789_8AFF_513815CE475B_INCLUDED) + diff --git a/boost/wave/util/cpp_ifblock.hpp b/boost/wave/util/cpp_ifblock.hpp new file mode 100644 index 0000000000..f89f9eaf66 --- /dev/null +++ b/boost/wave/util/cpp_ifblock.hpp @@ -0,0 +1,161 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_IFBLOCK_HPP_D4676B36_00C5_41F4_BC9F_9CBBAE3B8006_INCLUDED) +#define CPP_IFBLOCK_HPP_D4676B36_00C5_41F4_BC9F_9CBBAE3B8006_INCLUDED + +#include <stack> +#include <boost/wave/wave_config.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace util { + +/////////////////////////////////////////////////////////////////////////////// +// the class if_blocks handles recursive conditional compilation contexts +class if_block +{ +public: + if_block() : + status(true), some_part_status(true), + enclosing_status(true), is_in_else(false) + { + } + if_block(bool status_, bool enclosing_status_) : + status(status_), + some_part_status(status_), + enclosing_status(enclosing_status_), + is_in_else(false) + { + } + + void set_status(bool status_) + { + status = status_; + if (status_) + some_part_status = true; + } + bool get_status() const { return status; } + bool get_some_part_status() const { return some_part_status; } + bool get_enclosing_status() const { return enclosing_status; } + bool get_in_else() const { return is_in_else; } + void set_in_else() { is_in_else = true; } + +private: + bool status; // Current block is true + bool some_part_status; // One of the preceding or current #if/#elif was true + bool enclosing_status; // Enclosing #if block is true + bool is_in_else; // Inside the #else part +}; + +/////////////////////////////////////////////////////////////////////////////// +// stack of conditional compilation contexts +class if_block_stack +: private std::stack<if_block> +{ +public: + typedef std::stack<if_block>::size_type size_type; + + void enter_if_block(bool new_status) + { + // If enclosing block is false, then this block is also false + bool enclosing_status = get_status(); + this->push (value_type (new_status && enclosing_status, enclosing_status)); + } + bool enter_elif_block(bool new_status) + { + if (!is_inside_ifpart()) + return false; // #elif without matching #if + + if (get_enclosing_status()) { + if (get_status()) { + // entered a (false) #elif block from a true block + this->top().set_status(false); + } + else if (new_status && !this->top().get_some_part_status()) { + // Entered true #elif block and no previous block was true + this->top().set_status(new_status); + } + } + return true; + } + bool enter_else_block() + { + if (!is_inside_ifpart()) + return false; // #else without matching #if + + if (get_enclosing_status()) { + if (!this->top().get_some_part_status()) { + // Entered (true) #else block and no previous block was true + this->top().set_status(true); + } + else if (get_status()) { + // Entered (false) #else block from true block + this->top().set_status(false); + } + + // Set else flag + this->top().set_in_else(); + } + return true; + } + bool exit_if_block() + { + if (0 == this->size()) + return false; // #endif without matching #if + + this->pop(); + return true; + } + +// return, whether the top (innermost) condition is true or false + bool get_status() const + { + return 0 == this->size() || this->top().get_status(); + } + bool get_some_part_status() const + { + return 0 == this->size() || this->top().get_some_part_status(); + } + bool get_enclosing_status() const + { + return 0 == this->size() || this->top().get_enclosing_status(); + } + + size_type get_if_block_depth() const { return this->size(); } + +protected: + bool is_inside_ifpart() const + { + return 0 != this->size() && !this->top().get_in_else(); + } + bool is_inside_elsepart() const + { + return 0 != this->size() && this->top().get_in_else(); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace util +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPP_IFBLOCK_HPP_D4676B36_00C5_41F4_BC9F_9CBBAE3B8006_INCLUDED) diff --git a/boost/wave/util/cpp_include_paths.hpp b/boost/wave/util/cpp_include_paths.hpp new file mode 100644 index 0000000000..29c2bec3c9 --- /dev/null +++ b/boost/wave/util/cpp_include_paths.hpp @@ -0,0 +1,553 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_INCLUDE_PATHS_HPP_AF620DA4_B3D2_4221_AD91_8A1ABFFB6944_INCLUDED) +#define CPP_INCLUDE_PATHS_HPP_AF620DA4_B3D2_4221_AD91_8A1ABFFB6944_INCLUDED + +#include <string> +#include <list> +#include <utility> + +#include <boost/wave/wave_config.hpp> +#include <boost/wave/util/filesystem_compatibility.hpp> + +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 +#include <boost/multi_index_container.hpp> +#include <boost/multi_index/member.hpp> +#include <boost/multi_index/ordered_index.hpp> +#endif + +#if BOOST_WAVE_SERIALIZATION != 0 +#include <boost/serialization/serialization.hpp> +#include <boost/serialization/utility.hpp> +#include <boost/serialization/collections_save_imp.hpp> +#include <boost/serialization/collections_load_imp.hpp> +#include <boost/serialization/split_free.hpp> +#endif + +#include <boost/filesystem/path.hpp> +#include <boost/filesystem/operations.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { namespace wave { namespace util { + +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 +/////////////////////////////////////////////////////////////////////////////// +// Tags for accessing both sides of a bidirectional map +struct from {}; +struct to {}; + +/////////////////////////////////////////////////////////////////////////////// +// The class template bidirectional_map wraps the specification +// of a bidirectional map based on multi_index_container. +template<typename FromType, typename ToType> +struct bidirectional_map +{ + typedef std::pair<FromType, ToType> value_type; + +#if defined(BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS) || \ + (defined(BOOST_MSVC) && \ + ( (BOOST_MSVC < 1300) || (BOOST_MSVC == 1600) )) || \ + (defined(BOOST_INTEL_CXX_VERSION) && \ + (defined(_MSC_VER) && (BOOST_INTEL_CXX_VERSION <= 700))) + + BOOST_STATIC_CONSTANT(unsigned, from_offset = offsetof(value_type, first)); + BOOST_STATIC_CONSTANT(unsigned, to_offset = offsetof(value_type, second)); + + typedef boost::multi_index::multi_index_container< + value_type, + boost::multi_index::indexed_by< + boost::multi_index::ordered_unique< + boost::multi_index::tag<from>, + boost::multi_index::member_offset<value_type, FromType, from_offset> + >, + boost::multi_index::ordered_non_unique< + boost::multi_index::tag<to>, + boost::multi_index::member_offset<value_type, ToType, to_offset> + > + > + > type; + +#else + + typedef boost::multi_index::multi_index_container< + value_type, + boost::multi_index::indexed_by< + boost::multi_index::ordered_unique< + boost::multi_index::tag<from>, + boost::multi_index::member<value_type, FromType, &value_type::first> + >, + boost::multi_index::ordered_non_unique< + boost::multi_index::tag<to>, + boost::multi_index::member<value_type, ToType, &value_type::second> + > + > + > type; + +#endif +}; +#endif // BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + +#if BOOST_WAVE_SERIALIZATION != 0 +struct load_filepos +{ + static unsigned int get_line() { return 0; } + static unsigned int get_column() { return 0; } + static std::string get_file() { return "<loading-state>"; } +}; +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// include_paths - controlling the include path search order +// +// General notes: +// +// Any directories specified with the 'add_include_path()' function before +// the function 'set_sys_include_delimiter()' is called are searched only +// for the case of '#include "file"' directives, they are not searched for +// '#include <file>' directives. If additional directories are specified +// with the 'add_include_path()' function after a call to the function +// 'set_sys_include_delimiter()', these directories are searched for all +// '#include' directives. +// +// In addition, a call to the function 'set_sys_include_delimiter()' +// inhibits the use of the current directory as the first search directory +// for '#include "file"' directives. Therefore, the current directory is +// searched only if it is requested explicitly with a call to the function +// 'add_include_path(".")'. +// +// Calling both functions, the 'set_sys_include_delimiter()' and +// 'add_include_path(".")' allows you to control precisely which +// directories are searched before the current one and which are searched +// after. +// +/////////////////////////////////////////////////////////////////////////////// +class include_paths +{ +private: + typedef std::list<std::pair<boost::filesystem::path, std::string> > + include_list_type; + typedef include_list_type::value_type include_value_type; + +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + typedef bidirectional_map<std::string, std::string>::type + pragma_once_set_type; +#endif + +public: + include_paths() + : was_sys_include_path(false), + current_dir(initial_path()), + current_rel_dir(initial_path()) + {} + + bool add_include_path(char const *path_, bool is_system = false) + { + return add_include_path(path_, (is_system || was_sys_include_path) ? + system_include_paths : user_include_paths); + } + void set_sys_include_delimiter() { was_sys_include_path = true; } + bool find_include_file (std::string &s, std::string &dir, bool is_system, + char const *current_file) const; + void set_current_directory(char const *path_); + boost::filesystem::path get_current_directory() const + { return current_dir; } + +protected: + bool find_include_file (std::string &s, std::string &dir, + include_list_type const &pathes, char const *) const; + bool add_include_path(char const *path_, include_list_type &pathes_); + +private: + include_list_type user_include_paths; + include_list_type system_include_paths; + bool was_sys_include_path; // saw a set_sys_include_delimiter() + boost::filesystem::path current_dir; + boost::filesystem::path current_rel_dir; + +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 +public: + bool has_pragma_once(std::string const &filename) + { + using boost::multi_index::get; + return get<from>(pragma_once_files).find(filename) != pragma_once_files.end(); + } + bool add_pragma_once_header(std::string const &filename, + std::string const& guard_name) + { + typedef pragma_once_set_type::value_type value_type; + return pragma_once_files.insert(value_type(filename, guard_name)).second; + } + bool remove_pragma_once_header(std::string const& guard_name) + { + typedef pragma_once_set_type::index_iterator<to>::type to_iterator; + typedef std::pair<to_iterator, to_iterator> range_type; + + range_type r = pragma_once_files.get<to>().equal_range(guard_name); + if (r.first != r.second) { + using boost::multi_index::get; + get<to>(pragma_once_files).erase(r.first, r.second); + return true; + } + return false; + } + +private: + pragma_once_set_type pragma_once_files; +#endif + +#if BOOST_WAVE_SERIALIZATION != 0 +public: + BOOST_STATIC_CONSTANT(unsigned int, version = 0x10); + BOOST_STATIC_CONSTANT(unsigned int, version_mask = 0x0f); + +private: + friend class boost::serialization::access; + template<typename Archive> + void save(Archive & ar, const unsigned int version) const + { + using namespace boost::serialization; +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + ar & make_nvp("pragma_once_files", pragma_once_files); +#endif + ar & make_nvp("user_include_paths", user_include_paths); + ar & make_nvp("system_include_paths", system_include_paths); + ar & make_nvp("was_sys_include_path", was_sys_include_path); + } + template<typename Archive> + void load(Archive & ar, const unsigned int loaded_version) + { + using namespace boost::serialization; + if (version != (loaded_version & ~version_mask)) { + BOOST_WAVE_THROW(preprocess_exception, incompatible_config, + "cpp_include_path state version", load_filepos()); + return; + } + +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 + ar & make_nvp("pragma_once_files", pragma_once_files); +#endif + // verify that the old include paths match the current ones + include_list_type user_paths, system_paths; + ar & make_nvp("user_include_paths", user_paths); + ar & make_nvp("system_include_paths", system_paths); + + if (user_paths != user_include_paths) + { + BOOST_WAVE_THROW(preprocess_exception, incompatible_config, + "user include paths", load_filepos()); + return; + } + if (system_paths != system_include_paths) + { + BOOST_WAVE_THROW(preprocess_exception, incompatible_config, + "system include paths", load_filepos()); + return; + } + + ar & make_nvp("was_sys_include_path", was_sys_include_path); + } + BOOST_SERIALIZATION_SPLIT_MEMBER() +#endif +}; + +/////////////////////////////////////////////////////////////////////////////// +// Add an include path to one of the search lists (user include path or system +// include path). +inline +bool include_paths::add_include_path ( + char const *path_, include_list_type &pathes_) +{ + namespace fs = boost::filesystem; + if (path_) { + fs::path newpath = util::complete_path(create_path(path_), current_dir); + + if (!fs::exists(newpath) || !fs::is_directory(newpath)) { + // the given path does not form a name of a valid file system directory + // item + return false; + } + + pathes_.push_back (include_value_type(newpath, path_)); + return true; + } + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// Find an include file by traversing the list of include directories +inline +bool include_paths::find_include_file (std::string &s, std::string &dir, + include_list_type const &pathes, char const *current_file) const +{ + namespace fs = boost::filesystem; + typedef include_list_type::const_iterator const_include_list_iter_t; + + const_include_list_iter_t it = pathes.begin(); + const_include_list_iter_t include_paths_end = pathes.end(); + +#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 + if (0 != current_file) { + // re-locate the directory of the current file (#include_next handling) + + // #include_next does not distinguish between <file> and "file" + // inclusion, nor does it check that the file you specify has the same + // name as the current file. It simply looks for the file named, starting + // with the directory in the search path after the one where the current + // file was found. + + fs::path file_path (create_path(current_file)); + for (/**/; it != include_paths_end; ++it) { + fs::path currpath (create_path((*it).first.string())); + if (std::equal(currpath.begin(), currpath.end(), file_path.begin())) + { + ++it; // start searching with the next directory + break; + } + } + } +#endif + + for (/**/; it != include_paths_end; ++it) { + fs::path currpath (create_path(s)); + if (!currpath.has_root_directory()) { + currpath = create_path((*it).first.string()); + currpath /= create_path(s); // append filename + } + + if (fs::exists(currpath)) { + fs::path dirpath (create_path(s)); + if (!dirpath.has_root_directory()) { + dirpath = create_path((*it).second); + dirpath /= create_path(s); + } + + dir = dirpath.string(); + s = normalize(currpath).string(); // found the required file + return true; + } + } + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// Find an include file by searching the user and system includes in the +// correct sequence (as it was configured by the user of the driver program) +inline bool +include_paths::find_include_file (std::string &s, std::string &dir, + bool is_system, char const *current_file) const +{ + namespace fs = boost::filesystem; + +// if not system include (<...>), then search current directory first + if (!is_system) { + if (!was_sys_include_path) { // set_sys_include_delimiter() not called + // first have a look at the current directory + fs::path currpath (create_path(s)); + if (!currpath.has_root_directory()) { + currpath = create_path(current_dir.string()); + currpath /= create_path(s); + } + + if (fs::exists(currpath) && 0 == current_file) { + // if 0 != current_path (#include_next handling) it can't be + // the file in the current directory + fs::path dirpath (create_path(s)); + if (!dirpath.has_root_directory()) { + dirpath = create_path(current_rel_dir.string()); + dirpath /= create_path(s); + } + + dir = dirpath.string(); + s = normalize(currpath).string(); // found in local directory + return true; + } + + // iterate all user include file directories to find the file + if (find_include_file(s, dir, user_include_paths, current_file)) + return true; + + // ... fall through + } + else { + // if set_sys_include_delimiter() was called, then user include files + // are searched in the user search path only + return find_include_file(s, dir, user_include_paths, current_file); + } + + // if nothing found, fall through + // ... + } + +// iterate all system include file directories to find the file + return find_include_file (s, dir, system_include_paths, current_file); +} + +/////////////////////////////////////////////////////////////////////////////// +// Set current directory from a given file name + +inline bool +as_relative_to(boost::filesystem::path const& path, + boost::filesystem::path const& base, boost::filesystem::path& result) +{ + if (path.has_root_path()) { + if (path.root_path() == base.root_path()) + return as_relative_to(path.relative_path(), base.relative_path(), result); + + result = path; // that's our result + } + else { + if (base.has_root_path()) { + // cannot find relative path from a relative path and a rooted base + return false; + } + else { + typedef boost::filesystem::path::const_iterator path_iterator; + path_iterator path_it = path.begin(); + path_iterator base_it = base.begin(); + while (path_it != path.end() && base_it != base.end() ) { + if (*path_it != *base_it) + break; + ++path_it; ++base_it; + } + + for (/**/; base_it != base.end(); ++base_it) + result /= ".."; + + for (/**/; path_it != path.end(); ++path_it) + result /= *path_it; + } + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +inline +void include_paths::set_current_directory(char const *path_) +{ + namespace fs = boost::filesystem; + + fs::path filepath (create_path(path_)); + fs::path filename = util::complete_path(filepath, current_dir); + if (fs::exists(filename) && fs::is_directory(filename)) { + current_rel_dir.clear(); + if (!as_relative_to(filepath, current_dir, current_rel_dir)) + current_rel_dir = filepath; + current_dir = filename; + } + else { + current_rel_dir.clear(); + if (!as_relative_to(branch_path(filepath), current_dir, current_rel_dir)) + current_rel_dir = branch_path(filepath); + current_dir = branch_path(filename); + } +} + +/////////////////////////////////////////////////////////////////////////////// +}}} // namespace boost::wave::util + +#if BOOST_WAVE_SERIALIZATION != 0 +/////////////////////////////////////////////////////////////////////////////// +namespace boost { namespace serialization { + +/////////////////////////////////////////////////////////////////////////////// +// Serialization support for boost::filesystem::path +template<class Archive> +inline void save (Archive & ar, boost::filesystem::path const& p, + const unsigned int /* file_version */) +{ + using namespace boost::serialization; + std::string path_str(p.native_file_string()); + ar & make_nvp("filepath", path_str); +} + +template<class Archive> +inline void load (Archive & ar, boost::filesystem::path &p, + const unsigned int /* file_version */) +{ + using namespace boost::serialization; + std::string path_str; + ar & make_nvp("filepath", path_str); + p = wave::util::create_path(path_str); +} + +// split non-intrusive serialization function member into separate +// non intrusive save/load member functions +template<class Archive> +inline void serialize (Archive & ar, boost::filesystem::path &p, + const unsigned int file_version) +{ + boost::serialization::split_free(ar, p, file_version); +} + +/////////////////////////////////////////////////////////////////////////////// +// Serialization support for the used multi_index +template<class Archive> +inline void save (Archive & ar, + const typename boost::wave::util::bidirectional_map< + std::string, std::string + >::type &t, + const unsigned int /* file_version */) +{ + boost::serialization::stl::save_collection< + Archive, + typename boost::wave::util::bidirectional_map< + std::string, std::string + >::type + >(ar, t); +} + +template<class Archive> +inline void load (Archive & ar, + typename boost::wave::util::bidirectional_map<std::string, std::string>::type &t, + const unsigned int /* file_version */) +{ + typedef typename boost::wave::util::bidirectional_map< + std::string, std::string + >::type map_type; + boost::serialization::stl::load_collection< + Archive, map_type, + boost::serialization::stl::archive_input_unique<Archive, map_type>, + boost::serialization::stl::no_reserve_imp<map_type> + >(ar, t); +} + +// split non-intrusive serialization function member into separate +// non intrusive save/load member functions +template<class Archive> +inline void serialize (Archive & ar, + typename boost::wave::util::bidirectional_map< + std::string, std::string + >::type &t, + const unsigned int file_version) +{ + boost::serialization::split_free(ar, t, file_version); +} + +/////////////////////////////////////////////////////////////////////////////// +}} // namespace boost::serialization + +BOOST_CLASS_VERSION(boost::wave::util::include_paths, + boost::wave::util::include_paths::version); + +#endif // BOOST_WAVE_SERIALIZATION != 0 + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPP_INCLUDE_PATHS_HPP_AF620DA4_B3D2_4221_AD91_8A1ABFFB6944_INCLUDED) diff --git a/boost/wave/util/cpp_iterator.hpp b/boost/wave/util/cpp_iterator.hpp new file mode 100644 index 0000000000..8441b41faa --- /dev/null +++ b/boost/wave/util/cpp_iterator.hpp @@ -0,0 +1,2571 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + Definition of the preprocessor iterator + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_ITERATOR_HPP_175CA88F_7273_43FA_9039_BCF7459E1F29_INCLUDED) +#define CPP_ITERATOR_HPP_175CA88F_7273_43FA_9039_BCF7459E1F29_INCLUDED + +#include <string> +#include <vector> +#include <list> +#include <cstdlib> +#include <cctype> + +#include <boost/assert.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/filesystem/path.hpp> +#include <boost/filesystem/operations.hpp> +#include <boost/spirit/include/classic_multi_pass.hpp> +#include <boost/spirit/include/classic_parse_tree_utils.hpp> + +#include <boost/wave/wave_config.hpp> +#include <boost/pool/pool_alloc.hpp> + +#include <boost/wave/util/insert_whitespace_detection.hpp> +#include <boost/wave/util/macro_helpers.hpp> +#include <boost/wave/util/cpp_macromap_utils.hpp> +#include <boost/wave/util/interpret_pragma.hpp> +#include <boost/wave/util/transform_iterator.hpp> +#include <boost/wave/util/functor_input.hpp> +#include <boost/wave/util/filesystem_compatibility.hpp> + +#include <boost/wave/grammars/cpp_grammar_gen.hpp> +#include <boost/wave/grammars/cpp_expression_grammar_gen.hpp> +#if BOOST_WAVE_ENABLE_COMMANDLINE_MACROS != 0 +#include <boost/wave/grammars/cpp_predef_macros_gen.hpp> +#endif + +#include <boost/wave/whitespace_handling.hpp> +#include <boost/wave/cpp_iteration_context.hpp> +#include <boost/wave/cpp_exceptions.hpp> +#include <boost/wave/language_support.hpp> + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace util { + +/////////////////////////////////////////////////////////////////////////////// +// retrieve the macro name from the parse tree +template < + typename ContextT, typename ParseNodeT, typename TokenT, + typename PositionT +> +inline bool +retrieve_macroname(ContextT& ctx, ParseNodeT const &node, + boost::spirit::classic::parser_id id, TokenT ¯oname, 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 ¯odefinition, 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 ¤t_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 ¶meters, + 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 ¶meters, + 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 ¶meter_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 ¶meter_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 ¯odefinition, + 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 ¯odef, 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 ¶meters, 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 ¶meters, + 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 ¯o_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 ¶meter_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 ¶meter_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 ¯odef, + 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 ¯o_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 ¯o_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 ⁢ + 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 ⁢ + 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 ¶meters, 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) diff --git a/boost/wave/wave_config.hpp b/boost/wave/wave_config.hpp new file mode 100644 index 0000000000..fa537a6891 --- /dev/null +++ b/boost/wave/wave_config.hpp @@ -0,0 +1,491 @@ +/*============================================================================= + 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(WAVE_CONFIG_HPP_F143F90A_A63F_4B27_AC41_9CA4F14F538D_INCLUDED) +#define WAVE_CONFIG_HPP_F143F90A_A63F_4B27_AC41_9CA4F14F538D_INCLUDED + +#include <boost/config.hpp> +#include <boost/detail/workaround.hpp> +#include <boost/version.hpp> +#include <boost/spirit/include/classic_version.hpp> +#include <boost/wave/wave_version.hpp> + +/////////////////////////////////////////////////////////////////////////////// +// Define the maximal include nesting depth allowed. If this value isn't +// defined it defaults to 1024 +// +// To define a new initial include nesting define the following constant +// before including this file. +// +#if !defined(BOOST_WAVE_MAX_INCLUDE_LEVEL_DEPTH) +#define BOOST_WAVE_MAX_INCLUDE_LEVEL_DEPTH 1024 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Decide, whether to support variadics and placemarkers +// +// To implement support variadics and placemarkers define the following to +// something not equal to zero. +// +#if !defined(BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS) +#define BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Decide, whether to implement a #warning directive as an extension to the +// C++ Standard (same as #error, but emits a warning, not an error) +// +// To disable the implementation of #warning directives, define the following +// constant as zero before including this file. +// +#if !defined(BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE) +#define BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Decide, whether to implement #pragma once +// +// To disable the implementation of #pragma once, define the following +// constant as zero before including this file. +// +#if !defined(BOOST_WAVE_SUPPORT_PRAGMA_ONCE) +#define BOOST_WAVE_SUPPORT_PRAGMA_ONCE 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Decide, whether to implement #pragma message("") +// +// To disable the implementation of #pragma message(""), define the following +// constant as zero before including this file. +// +#if !defined(BOOST_WAVE_SUPPORT_PRAGMA_MESSAGE) +#define BOOST_WAVE_SUPPORT_PRAGMA_MESSAGE 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Decide, whether to implement #include_next +// Please note, that this is an extension to the C++ Standard. +// +// To disable the implementation of #include_next, define the following +// constant as zero before including this file. +// +#if !defined(BOOST_WAVE_SUPPORT_INCLUDE_NEXT) +#define BOOST_WAVE_SUPPORT_INCLUDE_NEXT 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Decide, whether to support C++0x +// +// To implement C++0x keywords and preprocessor semantics define the following +// to something not equal to zero. +// +#if !defined(BOOST_WAVE_SUPPORT_CPP0X) +#define BOOST_WAVE_SUPPORT_CPP0X 1 +#undef BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS +#define BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Undefine the following, to enable some MS specific language extensions: +// __int8, __int16, __int32, __int64, __based, __declspec, __cdecl, +// __fastcall, __stdcall, __try, __except, __finally, __leave, __inline, +// __asm, #region, #endregion +// +// Note: By default this is enabled for Windows based systems, otherwise it's +// disabled. +#if !defined(BOOST_WAVE_SUPPORT_MS_EXTENSIONS) +#if defined(BOOST_WINDOWS) +#define BOOST_WAVE_SUPPORT_MS_EXTENSIONS 1 +#else +#define BOOST_WAVE_SUPPORT_MS_EXTENSIONS 0 +#endif +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Allow the message body of the #error and #warning directives to be +// preprocessed before the diagnostic is issued. +// +// To disable preprocessing of the body of #error and #warning directives, +// define the following constant as zero before including this file. +// +#if !defined(BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY) +#define BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Allow the #pragma directives to be returned to the caller (optionally after +// preprocessing the body) +// +// To disable the library to emit unknown #pragma directives, define the +// following constant as zero before including this file. +// +#if !defined(BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES) +#define BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Allow the body of a #pragma directive to be preprocessed before the +// directive is returned to the caller. +// +// To disable the preprocessing of the body of #pragma directives, define the +// following constant as zero before including this file. +// +#if !defined(BOOST_WAVE_PREPROCESS_PRAGMA_BODY) +#define BOOST_WAVE_PREPROCESS_PRAGMA_BODY 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Allow to define macros with the command line syntax (-DMACRO(x)=definition) +// +// To disable the possibility to define macros based on the command line +// syntax, define the following constant as zero before including this file. +// +#if !defined(BOOST_WAVE_ENABLE_COMMANDLINE_MACROS) +#define BOOST_WAVE_ENABLE_COMMANDLINE_MACROS 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Define the pragma keyword to be used by the library to recognize its own +// pragma's. If nothing else is defined, then 'wave' will be used as the +// default keyword, i.e. the library recognizes all +// +// #pragma wave option [(argument)] +// +// and dispatches the handling to the interpret_pragma() preprocessing hook +// function (see file: preprocessing_hooks.hpp). The arguments part of the +// pragma is optional. +// The BOOST_WAVE_PRAGMA_KEYWORD constant needs to be defined to +// resolve as a string literal value. +#if !defined(BOOST_WAVE_PRAGMA_KEYWORD) +#define BOOST_WAVE_PRAGMA_KEYWORD "wave" +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Configure Wave thread support, Boost.Spirit and Boost.Pool are configured +// based on these settings automatically +// +// If BOOST_WAVE_SUPPORT_THREADING is not defined, Wave will use the global +// Boost build settings (BOOST_HAS_THREADS), if it is defined its value +// defines, whether threading will be enabled or not (should be set to '0' +// or '1'). +#if !defined(BOOST_WAVE_SUPPORT_THREADING) +#if defined(BOOST_HAS_THREADS) +#define BOOST_WAVE_SUPPORT_THREADING 1 +#else +#define BOOST_WAVE_SUPPORT_THREADING 0 +#endif +#endif + +#if BOOST_WAVE_SUPPORT_THREADING != 0 +#define BOOST_SPIRIT_THREADSAFE 1 +#define PHOENIX_THREADSAFE 1 +#else +// disable thread support in Boost.Pool +#define BOOST_NO_MT 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Define the string type to be used to store the token values and the file +// names inside a file_position template class +// +#if !defined(BOOST_WAVE_STRINGTYPE) + +// VC7 isn't able to compile the flex_string class, fall back to std::string +// CW up to 8.3 chokes as well *sigh* +// Tru64/CXX has linker problems when using flex_string +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) || \ + BOOST_WORKAROUND(__MWERKS__, < 0x3200) || \ + (defined(__DECCXX) && defined(__alpha)) || \ + defined(BOOST_WAVE_STRINGTYPE_USE_STDSTRING) + +#define BOOST_WAVE_STRINGTYPE std::string + +#if !defined(BOOST_WAVE_STRINGTYPE_USE_STDSTRING) +#define BOOST_WAVE_STRINGTYPE_USE_STDSTRING 1 +#endif + +#else + +// use the following, if you have a fast std::allocator<char> +#define BOOST_WAVE_STRINGTYPE boost::wave::util::flex_string< \ + char, std::char_traits<char>, std::allocator<char>, \ + boost::wave::util::CowString< \ + boost::wave::util::AllocatorStringStorage<char> \ + > \ + > \ + /**/ + +// This include is needed for the flex_string class used in the +// BOOST_WAVE_STRINGTYPE above. +#include <boost/wave/util/flex_string.hpp> + +#endif // BOOST_WORKAROUND(_MSC_VER, <= 1300) et.al. +#endif // !defined(BOOST_WAVE_STRINGTYPE) + +/////////////////////////////////////////////////////////////////////////////// +// The following definition forces the Spirit tree code to use list's instead +// of vectors, which may be more efficient on some platforms +// #define BOOST_SPIRIT_USE_LIST_FOR_TREES + +/////////////////////////////////////////////////////////////////////////////// +// The following definition forces the Spirit tree code to use boost pool +// allocators instead of the std::allocator for the vector/list's. +// #define BOOST_SPIRIT_USE_BOOST_ALLOCATOR_FOR_TREES + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment the following, if you need debug output, the +// BOOST_SPIRIT_DEBUG_FLAGS_CPP constants below help to fine control the +// amount of the generated debug output. +//#define BOOST_SPIRIT_DEBUG + +/////////////////////////////////////////////////////////////////////////////// +// Debug flags for the Wave library, possible flags specified below. +// +// Note: These flags take effect only if the BOOST_SPIRIT_DEBUG constant +// above is defined as well. +#define BOOST_SPIRIT_DEBUG_FLAGS_CPP_GRAMMAR 0x0001 +#define BOOST_SPIRIT_DEBUG_FLAGS_TIME_CONVERSION 0x0002 +#define BOOST_SPIRIT_DEBUG_FLAGS_CPP_EXPR_GRAMMAR 0x0004 +#define BOOST_SPIRIT_DEBUG_FLAGS_INTLIT_GRAMMAR 0x0008 +#define BOOST_SPIRIT_DEBUG_FLAGS_CHLIT_GRAMMAR 0x0010 +#define BOOST_SPIRIT_DEBUG_FLAGS_DEFINED_GRAMMAR 0x0020 +#define BOOST_SPIRIT_DEBUG_FLAGS_PREDEF_MACROS_GRAMMAR 0x0040 + +#if !defined(BOOST_SPIRIT_DEBUG_FLAGS_CPP) +#define BOOST_SPIRIT_DEBUG_FLAGS_CPP 0 // default is no debugging +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// For all recognized preprocessor statements the output parse trees +// formatted as xml are printed. The formatted parse trees are streamed to the +// std::ostream defined by the WAVE_DUMP_PARSE_TREE_OUT constant. +// +// To enable the output of these parse trees, define the following constant +// as zero something not equal to zero before including this file. +// +#if !defined(BOOST_WAVE_DUMP_PARSE_TREE) +#define BOOST_WAVE_DUMP_PARSE_TREE 0 +#endif +#if BOOST_WAVE_DUMP_PARSE_TREE != 0 && !defined(BOOST_WAVE_DUMP_PARSE_TREE_OUT) +#define BOOST_WAVE_DUMP_PARSE_TREE_OUT std::cerr +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// For all #if and #elif directives the preprocessed expressions are printed. +// These expressions are streamed to the std::ostream defined by the +// BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS_OUT constant. +// +// To enable the output of the preprocessed expressions, define the following +// constant as something not equal to zero before including this file. +// +#if !defined(BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS) +#define BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS 0 +#endif +#if BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS != 0 && \ + !defined(BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS_OUT) +#define BOOST_WAVE_DUMP_CONDITIONAL_EXPRESSIONS_OUT std::cerr +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Decide, whether to use the separate compilation model for the instantiation +// of the C++ lexer objects. +// +// If this is defined, you should explicitly instantiate the C++ lexer +// template with the correct parameters in a separate compilation unit of +// your program (see the file instantiate_re2c_lexer.cpp). +// +// To use the lexer inclusion model, define the following constant as +// something not equal to zero before including this file. +// +#if !defined(BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION) +#define BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Decide, whether to use the separate compilation model for the instantiation +// of the grammar objects. +// +// If this is defined, you should explicitly instantiate the grammar +// templates with the correct parameters in a separate compilation unit of +// your program (see the files instantiate_cpp_grammar.cpp et.al.). +// +// To use the grammar inclusion model, define the following constant as +// something not equal to zero before including this file. +// +#if !defined(BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION) +#define BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Decide whether to use a strict C++ lexer. +// +// If this is defined to something != 0, then the C++ lexers recognize the +// strict C99/C++ basic source character set. If it is not defined or defined +// to zero, the C++ lexers recognize the '$' character as part of identifiers. +// +// The default is to recognize the '$' character as part of identifiers. +// +#if !defined(BOOST_WAVE_USE_STRICT_LEXER) +#define BOOST_WAVE_USE_STRICT_LEXER 0 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Decide, whether the serialization of the wave::context class should be +// supported +// +// If this is defined to something not equal to zero the generated code will +// expose routines allowing to store and reload the internal state of the +// wave::context object. +// +// To enable the availability of the serialization functionality, define the +// following constant as something not equal to zero before including this file. +// +#if !defined(BOOST_WAVE_SERIALIZATION) +#define BOOST_WAVE_SERIALIZATION 0 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Decide, whether the import keyword is recognized as such +// +// If this is defined to something not equal to zero the Wave will recognize +// import as a keyword (T_IMPORT token id) +// +#if !defined(BOOST_WAVE_SUPPORT_IMPORT_KEYWORD) +#define BOOST_WAVE_SUPPORT_IMPORT_KEYWORD 0 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Decide, whether to support long long integers in the preprocessor. +// +// The C++ standard requires the preprocessor to use one of the following +// types for integer literals: long or unsigned long depending on an optional +// suffix ('u', 'l', 'ul', or 'lu') +// +// Sometimes it's required to preprocess integer literals bigger than that +// (i.e. long long or unsigned long long). In this case you need to define the +// BOOST_WAVE_SUPPORT_LONGLONG_INTEGER_LITERALS to something not equal to zero. +// +// This pp constant is effective only, if your target platform supports +// long long integers (BOOST_HAS_LONG_LONG is defined). +// +// Please note, that this setting doesn't relate to the Wave support option +// support_option_long_long, which enables the recognition of 'll' suffixes +// only. +// +// Defining this pp constant enables the recognition of long long integers +// even if these do not have the 'll' suffix. +// +#if !defined(BOOST_WAVE_SUPPORT_LONGLONG_INTEGER_LITERALS) +#define BOOST_WAVE_SUPPORT_LONGLONG_INTEGER_LITERALS 0 +#endif + +namespace boost { namespace wave +{ +#if defined(BOOST_HAS_LONG_LONG) && \ + BOOST_WAVE_SUPPORT_LONGLONG_INTEGER_LITERALS != 0 + typedef boost::long_long_type int_literal_type; + typedef boost::ulong_long_type uint_literal_type; +#else + typedef long int_literal_type; + typedef unsigned long uint_literal_type; +#endif +}} + +/////////////////////////////////////////////////////////////////////////////// +// On some platforms Wave will not be able to properly detect whether wchar_t +// is representing a signed or unsigned integral data type. Use the +// configuration constants below to force wchar_t being signed or unsigned, as +// appropriate. +// +// The default is to use std::numeric_limits<wchar_t>::is_signed. + +#define BOOST_WAVE_WCHAR_T_AUTOSELECT 1 +#define BOOST_WAVE_WCHAR_T_FORCE_SIGNED 2 +#define BOOST_WAVE_WCHAR_T_FORCE_UNSIGNED 3 + +#if !defined(BOOST_WAVE_WCHAR_T_SIGNEDNESS) +#define BOOST_WAVE_WCHAR_T_SIGNEDNESS BOOST_WAVE_WCHAR_T_AUTOSELECT +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Wave needs at least 4 parameters for phoenix actors +#if !defined(PHOENIX_LIMIT) +#define PHOENIX_LIMIT 6 +#endif +#if PHOENIX_LIMIT < 6 +// boost/home/classic/spirit/classic_attribute.hpp sets PHOENIX_LIMIT to 3! +#error "Boost.Wave: the constant PHOENIX_LIMIT must be at least defined to 6" \ +" to compile the library." +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Set up dll import/export options +#if (defined(BOOST_WAVE_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)) && \ + !defined(BOOST_WAVE_STATIC_LINK) + +#if defined(BOOST_WAVE_SOURCE) +#define BOOST_WAVE_DECL BOOST_SYMBOL_EXPORT +#define BOOST_WAVE_BUILD_DLL +#else +#define BOOST_WAVE_DECL BOOST_SYMBOL_IMPORT +#endif + +#endif // building a shared library + +#ifndef BOOST_WAVE_DECL +#define BOOST_WAVE_DECL +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Auto library naming +#if BOOST_VERSION >= 103100 +// auto link features work beginning from Boost V1.31.0 +#if !defined(BOOST_WAVE_SOURCE) && !defined(BOOST_ALL_NO_LIB) && \ + !defined(BOOST_WAVE_NO_LIB) + +#define BOOST_LIB_NAME boost_wave + +// tell the auto-link code to select a dll when required: +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_WAVE_DYN_LINK) +#define BOOST_DYN_LINK +#endif + +#include <boost/config/auto_link.hpp> + +#endif // auto-linking disabled +#endif // BOOST_VERSION + +/////////////////////////////////////////////////////////////////////////////// +// Compatibility macros +// (ensure interface compatibility to older Wave versions) +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// The preprocessing hook signatures changed after the Boost V1.34.0 release +// +// To use the preprocessing hook signatures as released with Boost V1.34.0 +// you need to define the BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS +// constant to something not equal zero. +// +// To force using the new interface define this constant to zero. +// +#if !defined(BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS) +#if BOOST_VERSION < 103500 // before Boost V1.35.0 +#define BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS 1 +#else +#define BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS 0 +#endif +#endif + +#endif // !defined(WAVE_CONFIG_HPP_F143F90A_A63F_4B27_AC41_9CA4F14F538D_INCLUDED) diff --git a/boost/wave/wave_config_constant.hpp b/boost/wave/wave_config_constant.hpp new file mode 100644 index 0000000000..68bdf74c42 --- /dev/null +++ b/boost/wave/wave_config_constant.hpp @@ -0,0 +1,91 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + Persistent 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_WAVE_CONFIG_CONSTANT_HPP) +#define BOOST_WAVE_CONFIG_CONSTANT_HPP + +#include <boost/preprocessor/stringize.hpp> +#include <boost/wave/wave_config.hpp> + +/////////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 +#define BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS_CONFIG 0x00000001 +#else +#define BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS_CONFIG 0x00000000 +#endif + +/////////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 +#define BOOST_WAVE_SUPPORT_PRAGMA_ONCE_CONFIG 0x00000002 +#else +#define BOOST_WAVE_SUPPORT_PRAGMA_ONCE_CONFIG 0x00000000 +#endif + +/////////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 +#define BOOST_WAVE_SUPPORT_MS_EXTENSIONS_CONFIG 0x00000004 +#else +#define BOOST_WAVE_SUPPORT_MS_EXTENSIONS_CONFIG 0x00000000 +#endif + +/////////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_PREPROCESS_PRAGMA_BODY != 0 +#define BOOST_WAVE_PREPROCESS_PRAGMA_BODY_CONFIG 0x00000008 +#else +#define BOOST_WAVE_PREPROCESS_PRAGMA_BODY_CONFIG 0x00000000 +#endif + +/////////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_USE_STRICT_LEXER != 0 +#define BOOST_WAVE_USE_STRICT_LEXER_CONFIG 0x00000010 +#else +#define BOOST_WAVE_USE_STRICT_LEXER_CONFIG 0x00000000 +#endif + +/////////////////////////////////////////////////////////////////////////////// +#if BOOST_WAVE_SUPPORT_IMPORT_KEYWORD != 0 +#define BOOST_WAVE_SUPPORT_IMPORT_KEYWORD_CONFIG 0x00000020 +#else +#define BOOST_WAVE_SUPPORT_IMPORT_KEYWORD_CONFIG 0x00000000 +#endif + +/////////////////////////////////////////////////////////////////////////////// +#define BOOST_WAVE_CONFIG ( \ + BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS_CONFIG | \ + BOOST_WAVE_SUPPORT_PRAGMA_ONCE_CONFIG | \ + BOOST_WAVE_SUPPORT_MS_EXTENSIONS_CONFIG | \ + BOOST_WAVE_PREPROCESS_PRAGMA_BODY_CONFIG | \ + BOOST_WAVE_USE_STRICT_LEXER_CONFIG | \ + BOOST_WAVE_SUPPORT_IMPORT_KEYWORD_CONFIG \ + ) \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { namespace wave { + + /////////////////////////////////////////////////////////////////////////// + // Call this function to test the configuration of the calling application + // against the configuration of the linked library. + BOOST_WAVE_DECL bool test_configuration(unsigned int config, + char const* pragma_keyword, char const* string_type); + +/////////////////////////////////////////////////////////////////////////////// +}} // namespace boost::wave + +#define BOOST_WAVE_TEST_CONFIGURATION() \ + boost::wave::test_configuration( \ + BOOST_WAVE_CONFIG, \ + BOOST_WAVE_PRAGMA_KEYWORD, \ + BOOST_PP_STRINGIZE((BOOST_WAVE_STRINGTYPE)) \ + ) \ + /**/ + +#endif // !BOOST_WAVE_CONFIG_CONSTANT_HPP diff --git a/boost/wave/wave_version.hpp b/boost/wave/wave_version.hpp new file mode 100644 index 0000000000..3512e0da10 --- /dev/null +++ b/boost/wave/wave_version.hpp @@ -0,0 +1,26 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + This is the current version of the Wave 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(WAVE_VERSION_H_9D79ABDB_AC54_4C0A_89B1_F70A2DCFE21E_INCLUDED) +#define WAVE_VERSION_H_9D79ABDB_AC54_4C0A_89B1_F70A2DCFE21E_INCLUDED + +// BOOST_WAVE_VERSION & 0x0000FF is the sub-minor version +// BOOST_WAVE_VERSION & 0x00FF00 is the minor version +// BOOST_WAVE_VERSION & 0xFF0000 is the major version +#define BOOST_WAVE_VERSION 0x020300 + +// The following defines contain the same information as above +#define BOOST_WAVE_VERSION_MAJOR 2 +#define BOOST_WAVE_VERSION_MINOR 3 +#define BOOST_WAVE_VERSION_SUBMINOR 0 + +#endif // !defined(WAVE_VERSION_H_9D79ABDB_AC54_4C0A_89B1_F70A2DCFE21E_INCLUDED) diff --git a/boost/wave/whitespace_handling.hpp b/boost/wave/whitespace_handling.hpp new file mode 100644 index 0000000000..be9725fd8d --- /dev/null +++ b/boost/wave/whitespace_handling.hpp @@ -0,0 +1,296 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + Whitespace eater + + http://www.boost.org/ + + Copyright (c) 2003 Paul Mensonides + 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(WHITESPACE_HANDLING_HPP_INCLUDED) +#define WHITESPACE_HANDLING_HPP_INCLUDED + +#include <boost/wave/wave_config.hpp> +#include <boost/wave/token_ids.hpp> +#include <boost/wave/preprocessing_hooks.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 context_policies { + +namespace util { + /////////////////////////////////////////////////////////////////////////// + // This function returns true if the given C style comment contains at + // least one newline + template <typename TokenT> + bool ccomment_has_newline(TokenT const& token) + { + using namespace boost::wave; + + if (T_CCOMMENT == token_id(token) && + TokenT::string_type::npos != token.get_value().find_first_of("\n")) + { + return true; + } + return false; + } + + /////////////////////////////////////////////////////////////////////////// + // This function returns the number of newlines in the given C style + // comment + template <typename TokenT> + int ccomment_count_newlines(TokenT const& token) + { + using namespace boost::wave; + int newlines = 0; + if (T_CCOMMENT == token_id(token)) { + typename TokenT::string_type const& value = token.get_value(); + typename TokenT::string_type::size_type p = value.find_first_of("\n"); + + while (TokenT::string_type::npos != p) { + ++newlines; + p = value.find_first_of("\n", p+1); + } + } + return newlines; + } + +#if BOOST_WAVE_SUPPORT_CPP0X != 0 + /////////////////////////////////////////////////////////////////////////// + // This function returns the number of newlines in the given C++0x style + // raw string + template <typename TokenT> + int rawstring_count_newlines(TokenT const& token) + { + using namespace boost::wave; + int newlines = 0; + if (T_RAWSTRINGLIT == token_id(token)) { + typename TokenT::string_type const& value = token.get_value(); + typename TokenT::string_type::size_type p = value.find_first_of("\n"); + + while (TokenT::string_type::npos != p) { + ++newlines; + p = value.find_first_of("\n", p+1); + } + } + return newlines; + } +#endif +} + +/////////////////////////////////////////////////////////////////////////////// +template <typename TokenT> +class eat_whitespace +: public default_preprocessing_hooks +{ +public: + eat_whitespace(); + + template <typename ContextT> + bool may_skip_whitespace(ContextT const& ctx, TokenT &token, + bool &skipped_newline); + template <typename ContextT> + bool may_skip_whitespace(ContextT const& ctx, TokenT &token, + bool preserve_comments_, bool preserve_bol_whitespace_, + bool &skipped_newline); + +protected: + bool skip_cppcomment(boost::wave::token_id id) + { + return !preserve_comments && T_CPPCOMMENT == id; + } + +private: + typedef bool state_t(TokenT &token, bool &skipped_newline); + state_t eat_whitespace::* state; + state_t general, newline, newline_2nd, whitespace, bol_whitespace; + bool preserve_comments; + bool preserve_bol_whitespace; +}; + +template <typename TokenT> +inline +eat_whitespace<TokenT>::eat_whitespace() +: state(&eat_whitespace::newline), preserve_comments(false), + preserve_bol_whitespace(false) +{ +} + +template <typename TokenT> +template <typename ContextT> +inline bool +eat_whitespace<TokenT>::may_skip_whitespace(ContextT const& ctx, TokenT &token, + bool &skipped_newline) +{ + // re-initialize the preserve comments state + preserve_comments = boost::wave::need_preserve_comments(ctx.get_language()); + return (this->*state)(token, skipped_newline); +} + +template <typename TokenT> +template <typename ContextT> +inline bool +eat_whitespace<TokenT>::may_skip_whitespace(ContextT const& ctx, TokenT &token, + bool preserve_comments_, bool preserve_bol_whitespace_, + bool &skipped_newline) +{ + // re-initialize the preserve comments state + preserve_comments = preserve_comments_; + preserve_bol_whitespace = preserve_bol_whitespace_; + return (this->*state)(token, skipped_newline); +} + +template <typename TokenT> +inline bool +eat_whitespace<TokenT>::general(TokenT &token, bool &skipped_newline) +{ + using namespace boost::wave; + + token_id id = token_id(token); + if (T_NEWLINE == id || T_CPPCOMMENT == id) { + state = &eat_whitespace::newline; + } + else if (T_SPACE == id || T_SPACE2 == id || T_CCOMMENT == id) { + state = &eat_whitespace::whitespace; + + if (util::ccomment_has_newline(token)) + skipped_newline = true; + + if ((!preserve_comments || T_CCOMMENT != id) && + token.get_value().size() > 1) + { + token.set_value(" "); // replace with a single space + } + } + else { + state = &eat_whitespace::general; + } + return false; +} + +template <typename TokenT> +inline bool +eat_whitespace<TokenT>::newline(TokenT &token, bool &skipped_newline) +{ + using namespace boost::wave; + + token_id id = token_id(token); + if (T_NEWLINE == id || T_CPPCOMMENT == id) { + skipped_newline = true; + state = &eat_whitespace::newline_2nd; + return T_NEWLINE == id || skip_cppcomment(id); + } + + if (T_SPACE != id && T_SPACE2 != id && T_CCOMMENT != id) + return general(token, skipped_newline); + + if (T_CCOMMENT == id) { + if (util::ccomment_has_newline(token)) { + skipped_newline = true; + state = &eat_whitespace::newline_2nd; + } + if (preserve_comments) { + state = &eat_whitespace::general; + return false; + } + return true; + } + + if (preserve_bol_whitespace) { + state = &eat_whitespace::bol_whitespace; + return false; + } + + return true; +} + +template <typename TokenT> +inline bool +eat_whitespace<TokenT>::newline_2nd(TokenT &token, bool &skipped_newline) +{ + using namespace boost::wave; + + token_id id = token_id(token); + if (T_SPACE == id || T_SPACE2 == id) { + if (preserve_bol_whitespace) { + state = &eat_whitespace::bol_whitespace; + return false; + } + return true; + } + + if (T_CCOMMENT == id) { + if (util::ccomment_has_newline(token)) + skipped_newline = true; + + if (preserve_comments) { + state = &eat_whitespace::general; + return false; + } + return true; + } + + if (T_NEWLINE != id && T_CPPCOMMENT != id) + return general(token, skipped_newline); + + skipped_newline = true; + return T_NEWLINE == id || skip_cppcomment(id); +} + +template <typename TokenT> +inline bool +eat_whitespace<TokenT>::bol_whitespace(TokenT &token, bool &skipped_newline) +{ + using namespace boost::wave; + + token_id id = token_id(token); + if (T_SPACE == id || T_SPACE2 == id) + return !preserve_bol_whitespace; + + return general(token, skipped_newline); +} + +template <typename TokenT> +inline bool +eat_whitespace<TokenT>::whitespace(TokenT &token, bool &skipped_newline) +{ + using namespace boost::wave; + + token_id id = token_id(token); + if (T_SPACE != id && T_SPACE2 != id && + T_CCOMMENT != id && T_CPPCOMMENT != id) + { + return general(token, skipped_newline); + } + + if (T_CCOMMENT == id) { + if (util::ccomment_has_newline(token)) + skipped_newline = true; + return !preserve_comments; + } + + return T_SPACE == id || T_SPACE2 == id || skip_cppcomment(id); +} + +/////////////////////////////////////////////////////////////////////////////// +} // namespace context_policies +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(WHITESPACE_HANDLING_HPP_INCLUDED) + |