annotate DEPENDENCIES/generic/include/boost/wave/util/cpp_macromap.hpp @ 125:34e428693f5d vext

Vext -> Repoint
author Chris Cannam
date Thu, 14 Jun 2018 11:15:39 +0100
parents 2665513ce2d3
children
rev   line source
Chris@16 1 /*=============================================================================
Chris@16 2 Boost.Wave: A Standard compliant C++ preprocessor library
Chris@16 3
Chris@16 4 Macro expansion engine
Chris@16 5
Chris@16 6 http://www.boost.org/
Chris@16 7
Chris@16 8 Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
Chris@16 9 Software License, Version 1.0. (See accompanying file
Chris@16 10 LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Chris@16 11 =============================================================================*/
Chris@16 12
Chris@16 13 #if !defined(CPP_MACROMAP_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED)
Chris@16 14 #define CPP_MACROMAP_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED
Chris@16 15
Chris@16 16 #include <cstdlib>
Chris@16 17 #include <cstdio>
Chris@16 18 #include <ctime>
Chris@16 19
Chris@16 20 #include <list>
Chris@16 21 #include <map>
Chris@16 22 #include <set>
Chris@16 23 #include <vector>
Chris@16 24 #include <iterator>
Chris@16 25 #include <algorithm>
Chris@16 26
Chris@16 27 #include <boost/assert.hpp>
Chris@16 28 #include <boost/wave/wave_config.hpp>
Chris@16 29 #if BOOST_WAVE_SERIALIZATION != 0
Chris@16 30 #include <boost/serialization/serialization.hpp>
Chris@16 31 #include <boost/serialization/shared_ptr.hpp>
Chris@16 32 #endif
Chris@16 33
Chris@16 34 #include <boost/filesystem/path.hpp>
Chris@16 35
Chris@16 36 #include <boost/wave/util/time_conversion_helper.hpp>
Chris@16 37 #include <boost/wave/util/unput_queue_iterator.hpp>
Chris@16 38 #include <boost/wave/util/macro_helpers.hpp>
Chris@16 39 #include <boost/wave/util/macro_definition.hpp>
Chris@16 40 #include <boost/wave/util/symbol_table.hpp>
Chris@16 41 #include <boost/wave/util/cpp_macromap_utils.hpp>
Chris@16 42 #include <boost/wave/util/cpp_macromap_predef.hpp>
Chris@16 43 #include <boost/wave/util/filesystem_compatibility.hpp>
Chris@16 44 #include <boost/wave/grammars/cpp_defined_grammar_gen.hpp>
Chris@16 45
Chris@16 46 #include <boost/wave/wave_version.hpp>
Chris@16 47 #include <boost/wave/cpp_exceptions.hpp>
Chris@16 48 #include <boost/wave/language_support.hpp>
Chris@16 49
Chris@16 50 // this must occur after all of the includes and before any code appears
Chris@16 51 #ifdef BOOST_HAS_ABI_HEADERS
Chris@16 52 #include BOOST_ABI_PREFIX
Chris@16 53 #endif
Chris@16 54
Chris@16 55 ///////////////////////////////////////////////////////////////////////////////
Chris@16 56 namespace boost { namespace wave { namespace util {
Chris@16 57
Chris@16 58 ///////////////////////////////////////////////////////////////////////////////
Chris@16 59 //
Chris@16 60 // macromap
Chris@16 61 //
Chris@16 62 // This class holds all currently defined macros and on demand expands
Chris@16 63 // those macro definitions
Chris@16 64 //
Chris@16 65 ///////////////////////////////////////////////////////////////////////////////
Chris@16 66 template <typename ContextT>
Chris@16 67 class macromap {
Chris@16 68
Chris@16 69 typedef macromap<ContextT> self_type;
Chris@16 70 typedef typename ContextT::token_type token_type;
Chris@16 71 typedef typename token_type::string_type string_type;
Chris@16 72 typedef typename token_type::position_type position_type;
Chris@16 73
Chris@16 74 typedef typename ContextT::token_sequence_type definition_container_type;
Chris@16 75 typedef std::vector<token_type> parameter_container_type;
Chris@16 76
Chris@16 77 typedef macro_definition<token_type, definition_container_type>
Chris@16 78 macro_definition_type;
Chris@16 79 typedef symbol_table<string_type, macro_definition_type>
Chris@16 80 defined_macros_type;
Chris@16 81 typedef typename defined_macros_type::value_type::second_type
Chris@16 82 macro_ref_type;
Chris@16 83
Chris@16 84 public:
Chris@16 85 macromap(ContextT &ctx_)
Chris@16 86 : current_macros(0), defined_macros(new defined_macros_type(1)),
Chris@16 87 main_pos("", 0), ctx(ctx_), macro_uid(1)
Chris@16 88 {
Chris@16 89 current_macros = defined_macros.get();
Chris@16 90 }
Chris@16 91 ~macromap() {}
Chris@16 92
Chris@16 93 // Add a new macro to the given macro scope
Chris@16 94 bool add_macro(token_type const &name, bool has_parameters,
Chris@16 95 parameter_container_type &parameters,
Chris@16 96 definition_container_type &definition, bool is_predefined = false,
Chris@16 97 defined_macros_type *scope = 0);
Chris@16 98
Chris@16 99 // Tests, whether the given macro name is defined in the given macro scope
Chris@16 100 bool is_defined(string_type const &name,
Chris@16 101 typename defined_macros_type::iterator &it,
Chris@16 102 defined_macros_type *scope = 0) const;
Chris@16 103
Chris@16 104 // expects a token sequence as its parameters
Chris@16 105 template <typename IteratorT>
Chris@16 106 bool is_defined(IteratorT const &begin, IteratorT const &end) const;
Chris@16 107
Chris@16 108 // expects an arbitrary string as its parameter
Chris@16 109 bool is_defined(string_type const &str) const;
Chris@16 110
Chris@16 111 // Get the macro definition for the given macro scope
Chris@16 112 bool get_macro(string_type const &name, bool &has_parameters,
Chris@16 113 bool &is_predefined, position_type &pos,
Chris@16 114 parameter_container_type &parameters,
Chris@16 115 definition_container_type &definition,
Chris@16 116 defined_macros_type *scope = 0) const;
Chris@16 117
Chris@16 118 // Remove a macro name from the given macro scope
Chris@16 119 bool remove_macro(string_type const &name, position_type const& pos,
Chris@16 120 bool even_predefined = false);
Chris@16 121
Chris@16 122 template <typename IteratorT, typename ContainerT>
Chris@16 123 token_type const &expand_tokensequence(IteratorT &first,
Chris@16 124 IteratorT const &last, ContainerT &pending, ContainerT &expanded,
Chris@16 125 bool& seen_newline, bool expand_operator_defined);
Chris@16 126
Chris@16 127 // Expand all macros inside the given token sequence
Chris@16 128 template <typename IteratorT, typename ContainerT>
Chris@16 129 void expand_whole_tokensequence(ContainerT &expanded,
Chris@16 130 IteratorT &first, IteratorT const &last,
Chris@16 131 bool expand_operator_defined);
Chris@16 132
Chris@16 133 // Init the predefined macros (add them to the given scope)
Chris@16 134 void init_predefined_macros(char const *fname = "<Unknown>",
Chris@16 135 defined_macros_type *scope = 0, bool at_global_scope = true);
Chris@16 136 void predefine_macro(defined_macros_type *scope, string_type const &name,
Chris@16 137 token_type const &t);
Chris@16 138
Chris@16 139 // Init the internal macro symbol namespace
Chris@16 140 void reset_macromap();
Chris@16 141
Chris@16 142 position_type &get_main_pos() { return main_pos; }
Chris@16 143 position_type const& get_main_pos() const { return main_pos; }
Chris@16 144
Chris@16 145 // interface for macro name introspection
Chris@16 146 typedef typename defined_macros_type::name_iterator name_iterator;
Chris@16 147 typedef typename defined_macros_type::const_name_iterator const_name_iterator;
Chris@16 148
Chris@16 149 name_iterator begin()
Chris@16 150 { return defined_macros_type::make_iterator(current_macros->begin()); }
Chris@16 151 name_iterator end()
Chris@16 152 { return defined_macros_type::make_iterator(current_macros->end()); }
Chris@16 153 const_name_iterator begin() const
Chris@16 154 { return defined_macros_type::make_iterator(current_macros->begin()); }
Chris@16 155 const_name_iterator end() const
Chris@16 156 { return defined_macros_type::make_iterator(current_macros->end()); }
Chris@16 157
Chris@16 158 protected:
Chris@16 159 // Helper functions for expanding all macros in token sequences
Chris@16 160 template <typename IteratorT, typename ContainerT>
Chris@16 161 token_type const &expand_tokensequence_worker(ContainerT &pending,
Chris@16 162 unput_queue_iterator<IteratorT, token_type, ContainerT> &first,
Chris@16 163 unput_queue_iterator<IteratorT, token_type, ContainerT> const &last,
Chris@16 164 bool& seen_newline, bool expand_operator_defined);
Chris@16 165
Chris@16 166 // Collect all arguments supplied to a macro invocation
Chris@16 167 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
Chris@16 168 template <typename IteratorT, typename ContainerT, typename SizeT>
Chris@16 169 typename std::vector<ContainerT>::size_type collect_arguments (
Chris@16 170 token_type const curr_token, std::vector<ContainerT> &arguments,
Chris@16 171 IteratorT &next, IteratorT const &end, SizeT const &parameter_count,
Chris@16 172 bool& seen_newline);
Chris@16 173 #else
Chris@16 174 template <typename IteratorT, typename ContainerT, typename SizeT>
Chris@16 175 typename std::vector<ContainerT>::size_type collect_arguments (
Chris@16 176 token_type const curr_token, std::vector<ContainerT> &arguments,
Chris@16 177 IteratorT &next, IteratorT &endparen, IteratorT const &end,
Chris@16 178 SizeT const &parameter_count, bool& seen_newline);
Chris@16 179 #endif
Chris@16 180
Chris@16 181 // Expand a single macro name
Chris@16 182 template <typename IteratorT, typename ContainerT>
Chris@16 183 bool expand_macro(ContainerT &pending, token_type const &name,
Chris@16 184 typename defined_macros_type::iterator it,
Chris@16 185 IteratorT &first, IteratorT const &last,
Chris@16 186 bool& seen_newline, bool expand_operator_defined,
Chris@16 187 defined_macros_type *scope = 0, ContainerT *queue_symbol = 0);
Chris@16 188
Chris@16 189 // Expand a predefined macro (__LINE__, __FILE__ and __INCLUDE_LEVEL__)
Chris@16 190 template <typename ContainerT>
Chris@16 191 bool expand_predefined_macro(token_type const &curr_token,
Chris@16 192 ContainerT &expanded);
Chris@16 193
Chris@16 194 // Expand a single macro argument
Chris@16 195 template <typename ContainerT>
Chris@16 196 void expand_argument (typename std::vector<ContainerT>::size_type arg,
Chris@16 197 std::vector<ContainerT> &arguments,
Chris@16 198 std::vector<ContainerT> &expanded_args, bool expand_operator_defined,
Chris@16 199 std::vector<bool> &has_expanded_args);
Chris@16 200
Chris@16 201 // Expand the replacement list (replaces parameters with arguments)
Chris@16 202 template <typename ContainerT>
Chris@16 203 void expand_replacement_list(
Chris@16 204 macro_definition_type const &macrodefinition,
Chris@16 205 std::vector<ContainerT> &arguments,
Chris@16 206 bool expand_operator_defined, ContainerT &expanded);
Chris@16 207
Chris@16 208 // Rescans the replacement list for macro expansion
Chris@16 209 template <typename IteratorT, typename ContainerT>
Chris@16 210 void rescan_replacement_list(token_type const &curr_token,
Chris@16 211 macro_definition_type &macrodef, ContainerT &replacement_list,
Chris@16 212 ContainerT &expanded, bool expand_operator_defined,
Chris@16 213 IteratorT &nfirst, IteratorT const &nlast);
Chris@16 214
Chris@16 215 // Resolves the operator defined() and replces the token with "0" or "1"
Chris@16 216 template <typename IteratorT, typename ContainerT>
Chris@16 217 token_type const &resolve_defined(IteratorT &first, IteratorT const &last,
Chris@16 218 ContainerT &expanded);
Chris@16 219
Chris@16 220 // Resolve operator _Pragma or the #pragma directive
Chris@16 221 template <typename IteratorT, typename ContainerT>
Chris@16 222 bool resolve_operator_pragma(IteratorT &first,
Chris@16 223 IteratorT const &last, ContainerT &expanded, bool& seen_newline);
Chris@16 224
Chris@16 225 // Handle the concatenation operator '##'
Chris@16 226 template <typename ContainerT>
Chris@16 227 bool concat_tokensequence(ContainerT &expanded);
Chris@16 228
Chris@16 229 template <typename ContainerT>
Chris@16 230 bool is_valid_concat(string_type new_value,
Chris@16 231 position_type const &pos, ContainerT &rescanned);
Chris@16 232
Chris@16 233 #if BOOST_WAVE_SERIALIZATION != 0
Chris@16 234 public:
Chris@16 235 BOOST_STATIC_CONSTANT(unsigned int, version = 0x10);
Chris@16 236 BOOST_STATIC_CONSTANT(unsigned int, version_mask = 0x0f);
Chris@16 237
Chris@16 238 private:
Chris@16 239 friend class boost::serialization::access;
Chris@16 240 template<typename Archive>
Chris@16 241 void save(Archive &ar, const unsigned int version) const
Chris@16 242 {
Chris@16 243 using namespace boost::serialization;
Chris@16 244 ar & make_nvp("defined_macros", defined_macros);
Chris@16 245 }
Chris@16 246 template<typename Archive>
Chris@16 247 void load(Archive &ar, const unsigned int loaded_version)
Chris@16 248 {
Chris@16 249 using namespace boost::serialization;
Chris@16 250 if (version != (loaded_version & ~version_mask)) {
Chris@16 251 BOOST_WAVE_THROW(preprocess_exception, incompatible_config,
Chris@16 252 "cpp_context state version", get_main_pos());
Chris@16 253 }
Chris@16 254 ar & make_nvp("defined_macros", defined_macros);
Chris@16 255 current_macros = defined_macros.get();
Chris@16 256 }
Chris@16 257 BOOST_SERIALIZATION_SPLIT_MEMBER()
Chris@16 258 #endif
Chris@16 259
Chris@16 260 private:
Chris@16 261 defined_macros_type *current_macros; // current symbol table
Chris@16 262 boost::shared_ptr<defined_macros_type> defined_macros; // global symbol table
Chris@16 263
Chris@16 264 token_type act_token; // current token
Chris@16 265 position_type main_pos; // last token position in the pp_iterator
Chris@16 266 string_type base_name; // the name to be expanded by __BASE_FILE__
Chris@16 267 ContextT &ctx; // context object associated with the macromap
Chris@16 268 long macro_uid;
Chris@16 269 predefined_macros predef; // predefined macro support
Chris@16 270 };
Chris@16 271 ///////////////////////////////////////////////////////////////////////////////
Chris@16 272
Chris@16 273 ///////////////////////////////////////////////////////////////////////////////
Chris@16 274 //
Chris@16 275 // add_macro(): adds a new macro to the macromap
Chris@16 276 //
Chris@16 277 ///////////////////////////////////////////////////////////////////////////////
Chris@16 278 template <typename ContextT>
Chris@16 279 inline bool
Chris@16 280 macromap<ContextT>::add_macro(token_type const &name, bool has_parameters,
Chris@16 281 parameter_container_type &parameters, definition_container_type &definition,
Chris@16 282 bool is_predefined, defined_macros_type *scope)
Chris@16 283 {
Chris@16 284 if (!is_predefined && impl::is_special_macroname (name.get_value())) {
Chris@16 285 // exclude special macro names
Chris@16 286 BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
Chris@16 287 illegal_redefinition, name.get_value().c_str(), main_pos,
Chris@16 288 name.get_value().c_str());
Chris@16 289 return false;
Chris@16 290 }
Chris@16 291 if (boost::wave::need_variadics(ctx.get_language()) &&
Chris@16 292 "__VA_ARGS__" == name.get_value())
Chris@16 293 {
Chris@16 294 // can't use __VA_ARGS__ as a macro name
Chris@16 295 BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
Chris@16 296 bad_define_statement_va_args, name.get_value().c_str(), main_pos,
Chris@16 297 name.get_value().c_str());
Chris@16 298 return false;
Chris@16 299 }
Chris@16 300 if (AltExtTokenType == (token_id(name) & ExtTokenOnlyMask)) {
Chris@16 301 // exclude special operator names
Chris@16 302 BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
Chris@16 303 illegal_operator_redefinition, name.get_value().c_str(), main_pos,
Chris@16 304 name.get_value().c_str());
Chris@16 305 return false;
Chris@16 306 }
Chris@16 307
Chris@16 308 // try to define the new macro
Chris@16 309 defined_macros_type *current_scope = scope ? scope : current_macros;
Chris@16 310 typename defined_macros_type::iterator it = current_scope->find(name.get_value());
Chris@16 311
Chris@16 312 if (it != current_scope->end()) {
Chris@16 313 // redefinition, should not be different
Chris@16 314 macro_definition_type* macrodef = (*it).second.get();
Chris@16 315 if (macrodef->is_functionlike != has_parameters ||
Chris@16 316 !impl::parameters_equal(macrodef->macroparameters, parameters) ||
Chris@16 317 !impl::definition_equals(macrodef->macrodefinition, definition))
Chris@16 318 {
Chris@16 319 BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
Chris@16 320 macro_redefinition, name.get_value().c_str(), main_pos,
Chris@16 321 name.get_value().c_str());
Chris@16 322 }
Chris@16 323 return false;
Chris@16 324 }
Chris@16 325
Chris@16 326 // test the validity of the parameter names
Chris@16 327 if (has_parameters) {
Chris@16 328 std::set<typename token_type::string_type> names;
Chris@16 329
Chris@16 330 typedef typename parameter_container_type::iterator
Chris@16 331 parameter_iterator_type;
Chris@16 332 typedef typename std::set<typename token_type::string_type>::iterator
Chris@16 333 name_iterator_type;
Chris@16 334
Chris@16 335 parameter_iterator_type end = parameters.end();
Chris@16 336 for (parameter_iterator_type itp = parameters.begin(); itp != end; ++itp)
Chris@16 337 {
Chris@16 338 name_iterator_type pit = names.find((*itp).get_value());
Chris@16 339
Chris@16 340 if (pit != names.end()) {
Chris@16 341 // duplicate parameter name
Chris@16 342 BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
Chris@16 343 duplicate_parameter_name, (*pit).c_str(), main_pos,
Chris@16 344 name.get_value().c_str());
Chris@16 345 return false;
Chris@16 346 }
Chris@16 347 names.insert((*itp).get_value());
Chris@16 348 }
Chris@16 349 }
Chris@16 350
Chris@16 351 // insert a new macro node
Chris@16 352 std::pair<typename defined_macros_type::iterator, bool> p =
Chris@16 353 current_scope->insert(
Chris@16 354 typename defined_macros_type::value_type(
Chris@16 355 name.get_value(),
Chris@16 356 macro_ref_type(new macro_definition_type(name,
Chris@16 357 has_parameters, is_predefined, ++macro_uid)
Chris@16 358 )
Chris@16 359 )
Chris@16 360 );
Chris@16 361
Chris@16 362 if (!p.second) {
Chris@16 363 BOOST_WAVE_THROW_NAME_CTX(ctx, macro_handling_exception,
Chris@16 364 macro_insertion_error, name.get_value().c_str(), main_pos,
Chris@16 365 name.get_value().c_str());
Chris@16 366 return false;
Chris@16 367 }
Chris@16 368
Chris@16 369 // add the parameters and the definition
Chris@16 370 std::swap((*p.first).second->macroparameters, parameters);
Chris@16 371 std::swap((*p.first).second->macrodefinition, definition);
Chris@16 372
Chris@16 373 // call the context supplied preprocessing hook
Chris@16 374 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
Chris@16 375 ctx.get_hooks().defined_macro(name, has_parameters,
Chris@16 376 (*p.first).second->macroparameters,
Chris@16 377 (*p.first).second->macrodefinition, is_predefined);
Chris@16 378 #else
Chris@16 379 ctx.get_hooks().defined_macro(ctx.derived(), name, has_parameters,
Chris@16 380 (*p.first).second->macroparameters,
Chris@16 381 (*p.first).second->macrodefinition, is_predefined);
Chris@16 382 #endif
Chris@16 383 return true;
Chris@16 384 }
Chris@16 385
Chris@16 386 ///////////////////////////////////////////////////////////////////////////////
Chris@16 387 //
Chris@16 388 // is_defined(): returns, whether a given macro is already defined
Chris@16 389 //
Chris@16 390 ///////////////////////////////////////////////////////////////////////////////
Chris@16 391 template <typename ContextT>
Chris@16 392 inline bool
Chris@16 393 macromap<ContextT>::is_defined(typename token_type::string_type const &name,
Chris@16 394 typename defined_macros_type::iterator &it,
Chris@16 395 defined_macros_type *scope) const
Chris@16 396 {
Chris@16 397 if (0 == scope) scope = current_macros;
Chris@16 398
Chris@16 399 if ((it = scope->find(name)) != scope->end())
Chris@16 400 return true; // found in symbol table
Chris@16 401
Chris@16 402 // quick pre-check
Chris@16 403 if (name.size() < 8 || '_' != name[0] || '_' != name[1])
Chris@16 404 return false; // quick check failed
Chris@16 405
Chris@16 406 return name == "__LINE__" || name == "__FILE__" ||
Chris@16 407 name == "__INCLUDE_LEVEL__";
Chris@16 408 }
Chris@16 409
Chris@16 410 template <typename ContextT>
Chris@16 411 template <typename IteratorT>
Chris@16 412 inline bool
Chris@16 413 macromap<ContextT>::is_defined(IteratorT const &begin,
Chris@16 414 IteratorT const &end) const
Chris@16 415 {
Chris@16 416 // in normal mode the name under inspection should consist of an identifier
Chris@16 417 // only
Chris@16 418 token_id id = token_id(*begin);
Chris@16 419
Chris@16 420 if (T_IDENTIFIER != id &&
Chris@16 421 !IS_CATEGORY(id, KeywordTokenType) &&
Chris@16 422 !IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) &&
Chris@16 423 !IS_CATEGORY(id, BoolLiteralTokenType))
Chris@16 424 {
Chris@16 425 std::string msg(impl::get_full_name(begin, end));
Chris@16 426 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, invalid_macroname,
Chris@16 427 msg.c_str(), main_pos);
Chris@16 428 return false;
Chris@16 429 }
Chris@16 430
Chris@16 431 IteratorT it = begin;
Chris@16 432 string_type name ((*it).get_value());
Chris@16 433 typename defined_macros_type::iterator cit;
Chris@16 434
Chris@16 435 if (++it != end) {
Chris@16 436 // there should be only one token as the inspected name
Chris@16 437 std::string msg(impl::get_full_name(begin, end));
Chris@16 438 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, invalid_macroname,
Chris@16 439 msg.c_str(), main_pos);
Chris@16 440 return false;
Chris@16 441 }
Chris@16 442 return is_defined(name, cit, 0);
Chris@16 443 }
Chris@16 444
Chris@16 445 ///////////////////////////////////////////////////////////////////////////////
Chris@16 446 // same as above, only takes an arbitrary string type as its parameter
Chris@16 447 template <typename ContextT>
Chris@16 448 inline bool
Chris@16 449 macromap<ContextT>::is_defined(string_type const &str) const
Chris@16 450 {
Chris@16 451 typename defined_macros_type::iterator cit;
Chris@16 452 return is_defined(str, cit, 0);
Chris@16 453 }
Chris@16 454
Chris@16 455 ///////////////////////////////////////////////////////////////////////////////
Chris@16 456 //
Chris@16 457 // Get the macro definition for the given macro scope
Chris@16 458 //
Chris@16 459 ///////////////////////////////////////////////////////////////////////////////
Chris@16 460 template <typename ContextT>
Chris@16 461 inline bool
Chris@16 462 macromap<ContextT>::get_macro(string_type const &name, bool &has_parameters,
Chris@16 463 bool &is_predefined, position_type &pos,
Chris@16 464 parameter_container_type &parameters,
Chris@16 465 definition_container_type &definition,
Chris@16 466 defined_macros_type *scope) const
Chris@16 467 {
Chris@16 468 typename defined_macros_type::iterator it;
Chris@16 469 if (!is_defined(name, it, scope))
Chris@16 470 return false;
Chris@16 471
Chris@16 472 macro_definition_type &macro_def = *(*it).second.get();
Chris@16 473
Chris@16 474 has_parameters = macro_def.is_functionlike;
Chris@16 475 is_predefined = macro_def.is_predefined;
Chris@16 476 pos = macro_def.macroname.get_position();
Chris@16 477 parameters = macro_def.macroparameters;
Chris@16 478 definition = macro_def.macrodefinition;
Chris@16 479 return true;
Chris@16 480 }
Chris@16 481
Chris@16 482 ///////////////////////////////////////////////////////////////////////////////
Chris@16 483 //
Chris@16 484 // remove_macro(): remove a macro from the macromap
Chris@16 485 //
Chris@16 486 ///////////////////////////////////////////////////////////////////////////////
Chris@16 487 template <typename ContextT>
Chris@16 488 inline bool
Chris@16 489 macromap<ContextT>::remove_macro(string_type const &name,
Chris@16 490 position_type const& pos, bool even_predefined)
Chris@16 491 {
Chris@16 492 typename defined_macros_type::iterator it = current_macros->find(name);
Chris@16 493
Chris@16 494 if (it != current_macros->end()) {
Chris@16 495 if ((*it).second->is_predefined) {
Chris@16 496 if (!even_predefined || impl::is_special_macroname(name)) {
Chris@16 497 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
Chris@16 498 bad_undefine_statement, name.c_str(), main_pos);
Chris@16 499 return false;
Chris@16 500 }
Chris@16 501 }
Chris@16 502 current_macros->erase(it);
Chris@16 503
Chris@16 504 // call the context supplied preprocessing hook function
Chris@16 505 token_type tok(T_IDENTIFIER, name, pos);
Chris@16 506
Chris@16 507 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
Chris@16 508 ctx.get_hooks().undefined_macro(tok);
Chris@16 509 #else
Chris@16 510 ctx.get_hooks().undefined_macro(ctx.derived(), tok);
Chris@16 511 #endif
Chris@16 512 return true;
Chris@16 513 }
Chris@16 514 else if (impl::is_special_macroname(name)) {
Chris@16 515 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_undefine_statement,
Chris@16 516 name.c_str(), pos);
Chris@16 517 }
Chris@16 518 return false; // macro was not defined
Chris@16 519 }
Chris@16 520
Chris@16 521 ///////////////////////////////////////////////////////////////////////////////
Chris@16 522 //
Chris@16 523 // expand_tokensequence
Chris@16 524 //
Chris@16 525 // This function is a helper function which wraps the given iterator
Chris@16 526 // range into corresponding unput_iterator's and calls the main workhorse
Chris@16 527 // of the macro expansion engine (the function expand_tokensequence_worker)
Chris@16 528 //
Chris@16 529 // This is the top level macro expansion function called from the
Chris@16 530 // preprocessing iterator component only.
Chris@16 531 //
Chris@16 532 ///////////////////////////////////////////////////////////////////////////////
Chris@16 533 template <typename ContextT>
Chris@16 534 template <typename IteratorT, typename ContainerT>
Chris@16 535 inline typename ContextT::token_type const &
Chris@16 536 macromap<ContextT>::expand_tokensequence(IteratorT &first,
Chris@16 537 IteratorT const &last, ContainerT &pending, ContainerT &expanded,
Chris@16 538 bool& seen_newline, bool expand_operator_defined)
Chris@16 539 {
Chris@16 540 typedef impl::gen_unput_queue_iterator<IteratorT, token_type, ContainerT>
Chris@16 541 gen_type;
Chris@16 542 typedef typename gen_type::return_type iterator_type;
Chris@16 543
Chris@16 544 iterator_type first_it = gen_type::generate(expanded, first);
Chris@16 545 iterator_type last_it = gen_type::generate(last);
Chris@16 546
Chris@16 547 on_exit::assign<IteratorT, iterator_type> on_exit(first, first_it);
Chris@16 548
Chris@16 549 return expand_tokensequence_worker(pending, first_it, last_it,
Chris@16 550 seen_newline, expand_operator_defined);
Chris@16 551 }
Chris@16 552
Chris@16 553 ///////////////////////////////////////////////////////////////////////////////
Chris@16 554 //
Chris@16 555 // expand_tokensequence_worker
Chris@16 556 //
Chris@16 557 // This function is the main workhorse of the macro expansion engine. It
Chris@16 558 // expands as much tokens as needed to identify the next preprocessed
Chris@16 559 // token to return to the caller.
Chris@16 560 // It returns the next preprocessed token.
Chris@16 561 //
Chris@16 562 // The iterator 'first' is adjusted accordingly.
Chris@16 563 //
Chris@16 564 ///////////////////////////////////////////////////////////////////////////////
Chris@16 565 template <typename ContextT>
Chris@16 566 template <typename IteratorT, typename ContainerT>
Chris@16 567 inline typename ContextT::token_type const &
Chris@16 568 macromap<ContextT>::expand_tokensequence_worker(
Chris@16 569 ContainerT &pending,
Chris@16 570 unput_queue_iterator<IteratorT, token_type, ContainerT> &first,
Chris@16 571 unput_queue_iterator<IteratorT, token_type, ContainerT> const &last,
Chris@16 572 bool& seen_newline, bool expand_operator_defined)
Chris@16 573 {
Chris@16 574 // if there exist pending tokens (tokens, which are already preprocessed), then
Chris@16 575 // return the next one from there
Chris@16 576 if (!pending.empty()) {
Chris@16 577 on_exit::pop_front<definition_container_type> pop_front_token(pending);
Chris@16 578
Chris@16 579 return act_token = pending.front();
Chris@16 580 }
Chris@16 581
Chris@16 582 // analyze the next element of the given sequence, if it is an
Chris@16 583 // T_IDENTIFIER token, try to replace this as a macro etc.
Chris@16 584 using namespace boost::wave;
Chris@16 585 typedef unput_queue_iterator<IteratorT, token_type, ContainerT> iterator_type;
Chris@16 586
Chris@16 587 if (first != last) {
Chris@16 588 token_id id = token_id(*first);
Chris@16 589
Chris@16 590 // ignore placeholder tokens
Chris@16 591 if (T_PLACEHOLDER == id) {
Chris@16 592 token_type placeholder = *first;
Chris@16 593
Chris@16 594 ++first;
Chris@16 595 if (first == last)
Chris@16 596 return act_token = placeholder;
Chris@16 597 id = token_id(*first);
Chris@16 598 }
Chris@16 599
Chris@16 600 if (T_IDENTIFIER == id || IS_CATEGORY(id, KeywordTokenType) ||
Chris@16 601 IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) ||
Chris@16 602 IS_CATEGORY(id, BoolLiteralTokenType))
Chris@16 603 {
Chris@16 604 // try to replace this identifier as a macro
Chris@16 605 if (expand_operator_defined && (*first).get_value() == "defined") {
Chris@16 606 // resolve operator defined()
Chris@16 607 return resolve_defined(first, last, pending);
Chris@16 608 }
Chris@16 609 else if (boost::wave::need_variadics(ctx.get_language()) &&
Chris@16 610 (*first).get_value() == "_Pragma")
Chris@16 611 {
Chris@16 612 // in C99 mode only: resolve the operator _Pragma
Chris@16 613 token_type curr_token = *first;
Chris@16 614
Chris@16 615 if (!resolve_operator_pragma(first, last, pending, seen_newline) ||
Chris@16 616 pending.size() > 0)
Chris@16 617 {
Chris@16 618 // unknown to us pragma or supplied replacement, return the
Chris@16 619 // next token
Chris@16 620 on_exit::pop_front<definition_container_type> pop_token(pending);
Chris@16 621
Chris@16 622 return act_token = pending.front();
Chris@16 623 }
Chris@16 624
Chris@16 625 // the operator _Pragma() was eaten completely, continue
Chris@16 626 return act_token = token_type(T_PLACEHOLDER, "_",
Chris@16 627 curr_token.get_position());
Chris@16 628 }
Chris@16 629
Chris@16 630 token_type name_token (*first);
Chris@16 631 typename defined_macros_type::iterator it;
Chris@16 632
Chris@16 633 if (is_defined(name_token.get_value(), it)) {
Chris@16 634 // the current token contains an identifier, which is currently
Chris@16 635 // defined as a macro
Chris@16 636 if (expand_macro(pending, name_token, it, first, last,
Chris@16 637 seen_newline, expand_operator_defined))
Chris@16 638 {
Chris@16 639 // the tokens returned by expand_macro should be rescanned
Chris@16 640 // beginning at the last token of the returned replacement list
Chris@16 641 if (first != last) {
Chris@16 642 // splice the last token back into the input queue
Chris@16 643 typename ContainerT::reverse_iterator rit = pending.rbegin();
Chris@16 644
Chris@16 645 first.get_unput_queue().splice(
Chris@16 646 first.get_unput_queue().begin(), pending,
Chris@16 647 (++rit).base(), pending.end());
Chris@16 648 }
Chris@16 649
Chris@16 650 // fall through ...
Chris@16 651 }
Chris@16 652 else if (!pending.empty()) {
Chris@16 653 // return the first token from the pending queue
Chris@16 654 on_exit::pop_front<definition_container_type> pop_queue (pending);
Chris@16 655
Chris@16 656 return act_token = pending.front();
Chris@16 657 }
Chris@16 658 else {
Chris@16 659 // macro expansion reached the eoi
Chris@16 660 return act_token = token_type();
Chris@16 661 }
Chris@16 662
Chris@16 663 // return the next preprocessed token
Chris@16 664 return expand_tokensequence_worker(pending, first, last,
Chris@16 665 seen_newline, expand_operator_defined);
Chris@16 666 }
Chris@16 667 // else if (expand_operator_defined) {
Chris@16 668 // // in preprocessing conditionals undefined identifiers and keywords
Chris@16 669 // // are to be replaced with '0' (see. C++ standard 16.1.4, [cpp.cond])
Chris@16 670 // return act_token =
Chris@16 671 // token_type(T_INTLIT, "0", (*first++).get_position());
Chris@16 672 // }
Chris@16 673 else {
Chris@16 674 act_token = name_token;
Chris@16 675 ++first;
Chris@16 676 return act_token;
Chris@16 677 }
Chris@16 678 }
Chris@16 679 else if (expand_operator_defined && IS_CATEGORY(*first, BoolLiteralTokenType)) {
Chris@16 680 // expanding a constant expression inside #if/#elif, special handling
Chris@16 681 // of 'true' and 'false'
Chris@16 682
Chris@16 683 // all remaining identifiers and keywords, except for true and false,
Chris@16 684 // are replaced with the pp-number 0 (C++ standard 16.1.4, [cpp.cond])
Chris@16 685 return act_token = token_type(T_INTLIT, T_TRUE != id ? "0" : "1",
Chris@16 686 (*first++).get_position());
Chris@16 687 }
Chris@16 688 else {
Chris@16 689 act_token = *first;
Chris@16 690 ++first;
Chris@16 691 return act_token;
Chris@16 692 }
Chris@16 693 }
Chris@16 694 return act_token = token_type(); // eoi
Chris@16 695 }
Chris@16 696
Chris@16 697 ///////////////////////////////////////////////////////////////////////////////
Chris@16 698 //
Chris@16 699 // collect_arguments(): collect the actual arguments of a macro invocation
Chris@16 700 //
Chris@16 701 // return the number of successfully detected non-empty arguments
Chris@16 702 //
Chris@16 703 ///////////////////////////////////////////////////////////////////////////////
Chris@16 704 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
Chris@16 705 template <typename ContextT>
Chris@16 706 template <typename IteratorT, typename ContainerT, typename SizeT>
Chris@16 707 inline typename std::vector<ContainerT>::size_type
Chris@16 708 macromap<ContextT>::collect_arguments (token_type const curr_token,
Chris@16 709 std::vector<ContainerT> &arguments, IteratorT &next,
Chris@16 710 IteratorT const &end, SizeT const &parameter_count, bool& seen_newline)
Chris@16 711 #else
Chris@16 712 template <typename ContextT>
Chris@16 713 template <typename IteratorT, typename ContainerT, typename SizeT>
Chris@16 714 inline typename std::vector<ContainerT>::size_type
Chris@16 715 macromap<ContextT>::collect_arguments (token_type const curr_token,
Chris@16 716 std::vector<ContainerT> &arguments, IteratorT &next, IteratorT &endparen,
Chris@16 717 IteratorT const &end, SizeT const &parameter_count, bool& seen_newline)
Chris@16 718 #endif
Chris@16 719 {
Chris@16 720 using namespace boost::wave;
Chris@16 721
Chris@16 722 arguments.push_back(ContainerT());
Chris@16 723
Chris@16 724 // collect the actual arguments
Chris@16 725 typename std::vector<ContainerT>::size_type count_arguments = 0;
Chris@16 726 int nested_parenthesis_level = 1;
Chris@16 727 ContainerT *argument = &arguments[0];
Chris@16 728 bool was_whitespace = false;
Chris@16 729 token_type startof_argument_list = *next;
Chris@16 730
Chris@16 731 while (++next != end && nested_parenthesis_level) {
Chris@16 732 token_id id = token_id(*next);
Chris@16 733
Chris@16 734 if (0 == parameter_count &&
Chris@16 735 !IS_CATEGORY((*next), WhiteSpaceTokenType) && id != T_NEWLINE &&
Chris@16 736 id != T_RIGHTPAREN && id != T_LEFTPAREN)
Chris@16 737 {
Chris@16 738 // there shouldn't be any arguments
Chris@16 739 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
Chris@16 740 too_many_macroarguments, curr_token.get_value().c_str(),
Chris@16 741 main_pos);
Chris@16 742 return 0;
Chris@16 743 }
Chris@16 744
Chris@16 745 switch (static_cast<unsigned int>(id)) {
Chris@16 746 case T_LEFTPAREN:
Chris@16 747 ++nested_parenthesis_level;
Chris@16 748 argument->push_back(*next);
Chris@16 749 was_whitespace = false;
Chris@16 750 break;
Chris@16 751
Chris@16 752 case T_RIGHTPAREN:
Chris@16 753 {
Chris@16 754 if (--nested_parenthesis_level >= 1)
Chris@16 755 argument->push_back(*next);
Chris@16 756 else {
Chris@16 757 // found closing parenthesis
Chris@16 758 // trim_sequence(argument);
Chris@16 759 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS == 0
Chris@16 760 endparen = next;
Chris@16 761 #endif
Chris@16 762 if (parameter_count > 0) {
Chris@16 763 if (argument->empty() ||
Chris@16 764 impl::is_whitespace_only(*argument))
Chris@16 765 {
Chris@16 766 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
Chris@16 767 if (boost::wave::need_variadics(ctx.get_language())) {
Chris@16 768 // store a placemarker as the argument
Chris@16 769 argument->push_back(token_type(T_PLACEMARKER, "\xA7",
Chris@16 770 (*next).get_position()));
Chris@16 771 ++count_arguments;
Chris@16 772 }
Chris@16 773 #endif
Chris@16 774 }
Chris@16 775 else {
Chris@16 776 ++count_arguments;
Chris@16 777 }
Chris@16 778 }
Chris@16 779 }
Chris@16 780 was_whitespace = false;
Chris@16 781 }
Chris@16 782 break;
Chris@16 783
Chris@16 784 case T_COMMA:
Chris@16 785 if (1 == nested_parenthesis_level) {
Chris@16 786 // next parameter
Chris@16 787 // trim_sequence(argument);
Chris@16 788 if (argument->empty() ||
Chris@16 789 impl::is_whitespace_only(*argument))
Chris@16 790 {
Chris@16 791 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
Chris@16 792 if (boost::wave::need_variadics(ctx.get_language())) {
Chris@16 793 // store a placemarker as the argument
Chris@16 794 argument->push_back(token_type(T_PLACEMARKER, "\xA7",
Chris@16 795 (*next).get_position()));
Chris@16 796 ++count_arguments;
Chris@16 797 }
Chris@16 798 #endif
Chris@16 799 }
Chris@16 800 else {
Chris@16 801 ++count_arguments;
Chris@16 802 }
Chris@16 803 arguments.push_back(ContainerT()); // add new arg
Chris@16 804 argument = &arguments[arguments.size()-1];
Chris@16 805 }
Chris@16 806 else {
Chris@16 807 // surrounded by parenthesises, so store to current argument
Chris@16 808 argument->push_back(*next);
Chris@16 809 }
Chris@16 810 was_whitespace = false;
Chris@16 811 break;
Chris@16 812
Chris@16 813 case T_NEWLINE:
Chris@16 814 seen_newline = true;
Chris@16 815 /* fall through */
Chris@16 816 case T_SPACE:
Chris@16 817 case T_SPACE2:
Chris@16 818 case T_CCOMMENT:
Chris@16 819 if (!was_whitespace)
Chris@16 820 argument->push_back(token_type(T_SPACE, " ", (*next).get_position()));
Chris@16 821 was_whitespace = true;
Chris@16 822 break; // skip whitespace
Chris@16 823
Chris@16 824 case T_PLACEHOLDER:
Chris@16 825 break; // ignore placeholder
Chris@16 826
Chris@16 827 default:
Chris@16 828 argument->push_back(*next);
Chris@16 829 was_whitespace = false;
Chris@16 830 break;
Chris@16 831 }
Chris@16 832 }
Chris@16 833
Chris@16 834 if (nested_parenthesis_level >= 1) {
Chris@16 835 // missing ')': improperly terminated macro invocation
Chris@16 836 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
Chris@16 837 improperly_terminated_macro, "missing ')'", main_pos);
Chris@16 838 return 0;
Chris@16 839 }
Chris@16 840
Chris@16 841 // if no argument was expected and we didn't find any, than remove the empty
Chris@16 842 // element
Chris@16 843 if (0 == parameter_count && 0 == count_arguments) {
Chris@16 844 BOOST_ASSERT(1 == arguments.size());
Chris@16 845 arguments.clear();
Chris@16 846 }
Chris@16 847 return count_arguments;
Chris@16 848 }
Chris@16 849
Chris@16 850 ///////////////////////////////////////////////////////////////////////////////
Chris@16 851 //
Chris@16 852 // expand_whole_tokensequence
Chris@16 853 //
Chris@16 854 // fully expands a given token sequence
Chris@16 855 //
Chris@16 856 ///////////////////////////////////////////////////////////////////////////////
Chris@16 857 template <typename ContextT>
Chris@16 858 template <typename IteratorT, typename ContainerT>
Chris@16 859 inline void
Chris@16 860 macromap<ContextT>::expand_whole_tokensequence(ContainerT &expanded,
Chris@16 861 IteratorT &first, IteratorT const &last,
Chris@16 862 bool expand_operator_defined)
Chris@16 863 {
Chris@16 864 typedef impl::gen_unput_queue_iterator<IteratorT, token_type, ContainerT>
Chris@16 865 gen_type;
Chris@16 866 typedef typename gen_type::return_type iterator_type;
Chris@16 867
Chris@16 868 ContainerT empty;
Chris@16 869 iterator_type first_it = gen_type::generate(empty, first);
Chris@16 870 iterator_type last_it = gen_type::generate(last);
Chris@16 871
Chris@16 872 on_exit::assign<IteratorT, iterator_type> on_exit(first, first_it);
Chris@16 873 ContainerT pending_queue;
Chris@16 874 bool seen_newline;
Chris@16 875
Chris@16 876 while (!pending_queue.empty() || first_it != last_it) {
Chris@16 877 expanded.push_back(
Chris@16 878 expand_tokensequence_worker(pending_queue, first_it,
Chris@16 879 last_it, seen_newline, expand_operator_defined)
Chris@16 880 );
Chris@16 881 }
Chris@16 882
Chris@16 883 // should have returned all expanded tokens
Chris@16 884 BOOST_ASSERT(pending_queue.empty()/* && unput_queue.empty()*/);
Chris@16 885 }
Chris@16 886
Chris@16 887 ///////////////////////////////////////////////////////////////////////////////
Chris@16 888 //
Chris@16 889 // expand_argument
Chris@16 890 //
Chris@16 891 // fully expands the given argument of a macro call
Chris@16 892 //
Chris@16 893 ///////////////////////////////////////////////////////////////////////////////
Chris@16 894 template <typename ContextT>
Chris@16 895 template <typename ContainerT>
Chris@16 896 inline void
Chris@16 897 macromap<ContextT>::expand_argument (
Chris@16 898 typename std::vector<ContainerT>::size_type arg,
Chris@16 899 std::vector<ContainerT> &arguments, std::vector<ContainerT> &expanded_args,
Chris@16 900 bool expand_operator_defined, std::vector<bool> &has_expanded_args)
Chris@16 901 {
Chris@16 902 if (!has_expanded_args[arg]) {
Chris@16 903 // expand the argument only once
Chris@16 904 typedef typename std::vector<ContainerT>::value_type::iterator
Chris@16 905 argument_iterator_type;
Chris@16 906
Chris@16 907 argument_iterator_type begin_it = arguments[arg].begin();
Chris@16 908 argument_iterator_type end_it = arguments[arg].end();
Chris@16 909
Chris@16 910 expand_whole_tokensequence(expanded_args[arg], begin_it, end_it,
Chris@16 911 expand_operator_defined);
Chris@16 912 impl::remove_placeholders(expanded_args[arg]);
Chris@16 913 has_expanded_args[arg] = true;
Chris@16 914 }
Chris@16 915 }
Chris@16 916
Chris@16 917 ///////////////////////////////////////////////////////////////////////////////
Chris@16 918 //
Chris@16 919 // expand_replacement_list
Chris@16 920 //
Chris@16 921 // fully expands the replacement list of a given macro with the
Chris@16 922 // actual arguments/expanded arguments
Chris@16 923 // handles the '#' [cpp.stringize] and the '##' [cpp.concat] operator
Chris@16 924 //
Chris@16 925 ///////////////////////////////////////////////////////////////////////////////
Chris@16 926 template <typename ContextT>
Chris@16 927 template <typename ContainerT>
Chris@16 928 inline void
Chris@16 929 macromap<ContextT>::expand_replacement_list(
Chris@16 930 macro_definition_type const &macrodef,
Chris@16 931 std::vector<ContainerT> &arguments, bool expand_operator_defined,
Chris@16 932 ContainerT &expanded)
Chris@16 933 {
Chris@16 934 using namespace boost::wave;
Chris@16 935 typedef typename macro_definition_type::const_definition_iterator_t
Chris@16 936 macro_definition_iter_t;
Chris@16 937
Chris@16 938 std::vector<ContainerT> expanded_args(arguments.size());
Chris@16 939 std::vector<bool> has_expanded_args(arguments.size());
Chris@16 940 bool seen_concat = false;
Chris@16 941 bool adjacent_concat = false;
Chris@16 942 bool adjacent_stringize = false;
Chris@16 943
Chris@16 944 macro_definition_iter_t cend = macrodef.macrodefinition.end();
Chris@16 945 for (macro_definition_iter_t cit = macrodef.macrodefinition.begin();
Chris@16 946 cit != cend; ++cit)
Chris@16 947 {
Chris@16 948 bool use_replaced_arg = true;
Chris@16 949 token_id base_id = BASE_TOKEN(token_id(*cit));
Chris@16 950
Chris@16 951 if (T_POUND_POUND == base_id) {
Chris@16 952 // concatenation operator
Chris@16 953 adjacent_concat = true;
Chris@16 954 seen_concat = true;
Chris@16 955 }
Chris@16 956 else if (T_POUND == base_id) {
Chris@16 957 // stringize operator
Chris@16 958 adjacent_stringize = true;
Chris@16 959 }
Chris@16 960 else {
Chris@16 961 if (adjacent_stringize || adjacent_concat ||
Chris@16 962 T_POUND_POUND == impl::next_token<macro_definition_iter_t>
Chris@16 963 ::peek(cit, cend))
Chris@16 964 {
Chris@16 965 use_replaced_arg = false;
Chris@16 966 }
Chris@16 967 if (adjacent_concat) // spaces after '##' ?
Chris@16 968 adjacent_concat = IS_CATEGORY(*cit, WhiteSpaceTokenType);
Chris@16 969 }
Chris@16 970
Chris@16 971 if (IS_CATEGORY((*cit), ParameterTokenType)) {
Chris@16 972 // copy argument 'i' instead of the parameter token i
Chris@16 973 typename ContainerT::size_type i;
Chris@16 974 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
Chris@16 975 bool is_ellipsis = false;
Chris@16 976
Chris@16 977 if (IS_EXTCATEGORY((*cit), ExtParameterTokenType)) {
Chris@16 978 BOOST_ASSERT(boost::wave::need_variadics(ctx.get_language()));
Chris@16 979 i = token_id(*cit) - T_EXTPARAMETERBASE;
Chris@16 980 is_ellipsis = true;
Chris@16 981 }
Chris@16 982 else
Chris@16 983 #endif
Chris@16 984 {
Chris@16 985 i = token_id(*cit) - T_PARAMETERBASE;
Chris@16 986 }
Chris@16 987
Chris@16 988 BOOST_ASSERT(i < arguments.size());
Chris@16 989 if (use_replaced_arg) {
Chris@16 990
Chris@16 991 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
Chris@16 992 if (is_ellipsis) {
Chris@16 993 position_type const &pos = (*cit).get_position();
Chris@16 994
Chris@16 995 BOOST_ASSERT(boost::wave::need_variadics(ctx.get_language()));
Chris@16 996
Chris@16 997 // ensure all variadic arguments to be expanded
Chris@16 998 for (typename vector<ContainerT>::size_type arg = i;
Chris@16 999 arg < expanded_args.size(); ++arg)
Chris@16 1000 {
Chris@16 1001 expand_argument(arg, arguments, expanded_args,
Chris@16 1002 expand_operator_defined, has_expanded_args);
Chris@16 1003 }
Chris@16 1004 impl::replace_ellipsis(expanded_args, i, expanded, pos);
Chris@16 1005 }
Chris@16 1006 else
Chris@16 1007 #endif
Chris@16 1008 {
Chris@16 1009 // ensure argument i to be expanded
Chris@16 1010 expand_argument(i, arguments, expanded_args,
Chris@16 1011 expand_operator_defined, has_expanded_args);
Chris@16 1012
Chris@16 1013 // replace argument
Chris@16 1014 ContainerT const &arg = expanded_args[i];
Chris@16 1015
Chris@16 1016 std::copy(arg.begin(), arg.end(),
Chris@16 1017 std::inserter(expanded, expanded.end()));
Chris@16 1018 }
Chris@16 1019 }
Chris@16 1020 else if (adjacent_stringize &&
Chris@16 1021 !IS_CATEGORY(*cit, WhiteSpaceTokenType))
Chris@16 1022 {
Chris@16 1023 // stringize the current argument
Chris@16 1024 BOOST_ASSERT(!arguments[i].empty());
Chris@16 1025
Chris@16 1026 // safe a copy of the first tokens position (not a reference!)
Chris@16 1027 position_type pos ((*arguments[i].begin()).get_position());
Chris@16 1028
Chris@16 1029 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
Chris@16 1030 if (is_ellipsis && boost::wave::need_variadics(ctx.get_language())) {
Chris@16 1031 impl::trim_sequence_left(arguments[i]);
Chris@16 1032 impl::trim_sequence_right(arguments.back());
Chris@16 1033 expanded.push_back(token_type(T_STRINGLIT,
Chris@16 1034 impl::as_stringlit(arguments, i, pos), pos));
Chris@16 1035 }
Chris@16 1036 else
Chris@16 1037 #endif
Chris@16 1038 {
Chris@16 1039 impl::trim_sequence(arguments[i]);
Chris@16 1040 expanded.push_back(token_type(T_STRINGLIT,
Chris@16 1041 impl::as_stringlit(arguments[i], pos), pos));
Chris@16 1042 }
Chris@16 1043 adjacent_stringize = false;
Chris@16 1044 }
Chris@16 1045 else {
Chris@16 1046 // simply copy the original argument (adjacent '##' or '#')
Chris@16 1047 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
Chris@16 1048 if (is_ellipsis) {
Chris@16 1049 position_type const &pos = (*cit).get_position();
Chris@16 1050
Chris@16 1051 impl::trim_sequence_left(arguments[i]);
Chris@16 1052 impl::trim_sequence_right(arguments.back());
Chris@16 1053 BOOST_ASSERT(boost::wave::need_variadics(ctx.get_language()));
Chris@16 1054 impl::replace_ellipsis(arguments, i, expanded, pos);
Chris@16 1055 }
Chris@16 1056 else
Chris@16 1057 #endif
Chris@16 1058 {
Chris@16 1059 ContainerT &arg = arguments[i];
Chris@16 1060
Chris@16 1061 impl::trim_sequence(arg);
Chris@16 1062 std::copy(arg.begin(), arg.end(),
Chris@16 1063 std::inserter(expanded, expanded.end()));
Chris@16 1064 }
Chris@16 1065 }
Chris@16 1066 }
Chris@16 1067 else if (!adjacent_stringize || T_POUND != base_id) {
Chris@16 1068 // insert the actual replacement token (if it is not the '#' operator)
Chris@16 1069 expanded.push_back(*cit);
Chris@16 1070 }
Chris@16 1071 }
Chris@16 1072
Chris@16 1073 if (adjacent_stringize) {
Chris@16 1074 // error, '#' should not be the last token
Chris@16 1075 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, ill_formed_operator,
Chris@16 1076 "stringize ('#')", main_pos);
Chris@16 1077 return;
Chris@16 1078 }
Chris@16 1079
Chris@16 1080 // handle the cpp.concat operator
Chris@16 1081 if (seen_concat)
Chris@16 1082 concat_tokensequence(expanded);
Chris@16 1083 }
Chris@16 1084
Chris@16 1085 ///////////////////////////////////////////////////////////////////////////////
Chris@16 1086 //
Chris@16 1087 // rescan_replacement_list
Chris@16 1088 //
Chris@16 1089 // As the name implies, this function is used to rescan the replacement list
Chris@16 1090 // after the first macro substitution phase.
Chris@16 1091 //
Chris@16 1092 ///////////////////////////////////////////////////////////////////////////////
Chris@16 1093 template <typename ContextT>
Chris@16 1094 template <typename IteratorT, typename ContainerT>
Chris@16 1095 inline void
Chris@16 1096 macromap<ContextT>::rescan_replacement_list(token_type const &curr_token,
Chris@16 1097 macro_definition_type &macro_def, ContainerT &replacement_list,
Chris@16 1098 ContainerT &expanded, bool expand_operator_defined,
Chris@16 1099 IteratorT &nfirst, IteratorT const &nlast)
Chris@16 1100 {
Chris@16 1101 if (!replacement_list.empty()) {
Chris@16 1102 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
Chris@16 1103 // remove the placemarkers
Chris@16 1104 if (boost::wave::need_variadics(ctx.get_language())) {
Chris@16 1105 typename ContainerT::iterator end = replacement_list.end();
Chris@16 1106 typename ContainerT::iterator it = replacement_list.begin();
Chris@16 1107
Chris@16 1108 while (it != end) {
Chris@16 1109 using namespace boost::wave;
Chris@16 1110 if (T_PLACEMARKER == token_id(*it)) {
Chris@16 1111 typename ContainerT::iterator placemarker = it;
Chris@16 1112
Chris@16 1113 ++it;
Chris@16 1114 replacement_list.erase(placemarker);
Chris@16 1115 }
Chris@16 1116 else {
Chris@16 1117 ++it;
Chris@16 1118 }
Chris@16 1119 }
Chris@16 1120 }
Chris@16 1121 #endif
Chris@16 1122
Chris@16 1123 // rescan the replacement list, during this rescan the current macro under
Chris@16 1124 // expansion isn't available as an expandable macro
Chris@16 1125 on_exit::reset<bool> on_exit(macro_def.is_available_for_replacement, false);
Chris@16 1126 typename ContainerT::iterator begin_it = replacement_list.begin();
Chris@16 1127 typename ContainerT::iterator end_it = replacement_list.end();
Chris@16 1128
Chris@16 1129 expand_whole_tokensequence(expanded, begin_it, end_it,
Chris@16 1130 expand_operator_defined);
Chris@16 1131
Chris@16 1132 // trim replacement list, leave placeholder tokens untouched
Chris@16 1133 impl::trim_replacement_list(expanded);
Chris@16 1134 }
Chris@16 1135
Chris@16 1136 if (expanded.empty()) {
Chris@16 1137 // the resulting replacement list should contain at least a placeholder
Chris@16 1138 // token
Chris@16 1139 expanded.push_back(token_type(T_PLACEHOLDER, "_", curr_token.get_position()));
Chris@16 1140 }
Chris@16 1141 }
Chris@16 1142
Chris@16 1143 ///////////////////////////////////////////////////////////////////////////////
Chris@16 1144 //
Chris@16 1145 // expand_macro(): expands a defined macro
Chris@16 1146 //
Chris@16 1147 // This functions tries to expand the macro, to which points the 'first'
Chris@16 1148 // iterator. The functions eats up more tokens, if the macro to expand is
Chris@16 1149 // a function-like macro.
Chris@16 1150 //
Chris@16 1151 ///////////////////////////////////////////////////////////////////////////////
Chris@16 1152 template <typename ContextT>
Chris@16 1153 template <typename IteratorT, typename ContainerT>
Chris@16 1154 inline bool
Chris@16 1155 macromap<ContextT>::expand_macro(ContainerT &expanded,
Chris@16 1156 token_type const &curr_token, typename defined_macros_type::iterator it,
Chris@16 1157 IteratorT &first, IteratorT const &last,
Chris@16 1158 bool& seen_newline, bool expand_operator_defined,
Chris@16 1159 defined_macros_type *scope, ContainerT *queue_symbol)
Chris@16 1160 {
Chris@16 1161 using namespace boost::wave;
Chris@16 1162
Chris@16 1163 if (0 == scope) scope = current_macros;
Chris@16 1164
Chris@16 1165 BOOST_ASSERT(T_IDENTIFIER == token_id(curr_token) ||
Chris@16 1166 IS_CATEGORY(token_id(curr_token), KeywordTokenType) ||
Chris@16 1167 IS_EXTCATEGORY(token_id(curr_token), OperatorTokenType|AltExtTokenType) ||
Chris@16 1168 IS_CATEGORY(token_id(curr_token), BoolLiteralTokenType));
Chris@16 1169
Chris@16 1170 if (it == scope->end()) {
Chris@16 1171 ++first; // advance
Chris@16 1172
Chris@16 1173 // try to expand a predefined macro (__FILE__, __LINE__ or __INCLUDE_LEVEL__)
Chris@16 1174 if (expand_predefined_macro(curr_token, expanded))
Chris@16 1175 return false;
Chris@16 1176
Chris@16 1177 // not defined as a macro
Chris@16 1178 if (0 != queue_symbol) {
Chris@16 1179 expanded.splice(expanded.end(), *queue_symbol);
Chris@16 1180 }
Chris@16 1181 else {
Chris@16 1182 expanded.push_back(curr_token);
Chris@16 1183 }
Chris@16 1184 return false;
Chris@16 1185 }
Chris@16 1186
Chris@16 1187 // ensure the parameters to be replaced with special parameter tokens
Chris@16 1188 macro_definition_type &macro_def = *(*it).second.get();
Chris@16 1189
Chris@16 1190 macro_def.replace_parameters();
Chris@16 1191
Chris@16 1192 // test if this macro is currently available for replacement
Chris@16 1193 if (!macro_def.is_available_for_replacement) {
Chris@16 1194 // this macro is marked as non-replaceable
Chris@16 1195 // copy the macro name itself
Chris@16 1196 if (0 != queue_symbol) {
Chris@16 1197 queue_symbol->push_back(token_type(T_NONREPLACABLE_IDENTIFIER,
Chris@16 1198 curr_token.get_value(), curr_token.get_position()));
Chris@16 1199 expanded.splice(expanded.end(), *queue_symbol);
Chris@16 1200 }
Chris@16 1201 else {
Chris@16 1202 expanded.push_back(token_type(T_NONREPLACABLE_IDENTIFIER,
Chris@16 1203 curr_token.get_value(), curr_token.get_position()));
Chris@16 1204 }
Chris@16 1205 ++first;
Chris@16 1206 return false;
Chris@16 1207 }
Chris@16 1208
Chris@16 1209 // try to replace the current identifier as a function-like macro
Chris@16 1210 ContainerT replacement_list;
Chris@16 1211
Chris@16 1212 if (T_LEFTPAREN == impl::next_token<IteratorT>::peek(first, last)) {
Chris@16 1213 // called as a function-like macro
Chris@16 1214 impl::skip_to_token(ctx, first, last, T_LEFTPAREN, seen_newline);
Chris@16 1215
Chris@16 1216 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS == 0
Chris@16 1217 IteratorT seqstart = first;
Chris@16 1218 IteratorT seqend = first;
Chris@16 1219 #endif
Chris@16 1220
Chris@16 1221 if (macro_def.is_functionlike) {
Chris@16 1222 // defined as a function-like macro
Chris@16 1223
Chris@16 1224 // collect the arguments
Chris@16 1225 std::vector<ContainerT> arguments;
Chris@16 1226 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
Chris@16 1227 typename std::vector<ContainerT>::size_type count_args =
Chris@16 1228 collect_arguments (curr_token, arguments, first, last,
Chris@16 1229 macro_def.macroparameters.size(), seen_newline);
Chris@16 1230 #else
Chris@16 1231 typename std::vector<ContainerT>::size_type count_args =
Chris@16 1232 collect_arguments (curr_token, arguments, first, seqend, last,
Chris@16 1233 macro_def.macroparameters.size(), seen_newline);
Chris@16 1234 #endif
Chris@16 1235
Chris@16 1236 // verify the parameter count
Chris@16 1237 if (count_args < macro_def.macroparameters.size() ||
Chris@16 1238 arguments.size() < macro_def.macroparameters.size())
Chris@16 1239 {
Chris@16 1240 if (count_args != arguments.size()) {
Chris@16 1241 // must been at least one empty argument in C++ mode
Chris@16 1242 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
Chris@16 1243 empty_macroarguments, curr_token.get_value().c_str(),
Chris@16 1244 main_pos);
Chris@16 1245 }
Chris@16 1246 else {
Chris@16 1247 // too few macro arguments
Chris@16 1248 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
Chris@16 1249 too_few_macroarguments, curr_token.get_value().c_str(),
Chris@16 1250 main_pos);
Chris@16 1251 }
Chris@16 1252 return false;
Chris@16 1253 }
Chris@16 1254
Chris@16 1255 if (count_args > macro_def.macroparameters.size() ||
Chris@16 1256 arguments.size() > macro_def.macroparameters.size())
Chris@16 1257 {
Chris@16 1258 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
Chris@16 1259 if (!macro_def.has_ellipsis)
Chris@16 1260 #endif
Chris@16 1261 {
Chris@16 1262 // too many macro arguments
Chris@16 1263 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
Chris@16 1264 too_many_macroarguments,
Chris@16 1265 curr_token.get_value().c_str(), main_pos);
Chris@16 1266 return false;
Chris@16 1267 }
Chris@16 1268 }
Chris@16 1269
Chris@16 1270 // inject tracing support
Chris@16 1271 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
Chris@16 1272 ctx.get_hooks().expanding_function_like_macro(
Chris@16 1273 macro_def.macroname, macro_def.macroparameters,
Chris@16 1274 macro_def.macrodefinition, curr_token, arguments);
Chris@16 1275 #else
Chris@16 1276 if (ctx.get_hooks().expanding_function_like_macro(ctx.derived(),
Chris@16 1277 macro_def.macroname, macro_def.macroparameters,
Chris@16 1278 macro_def.macrodefinition, curr_token, arguments,
Chris@16 1279 seqstart, seqend))
Chris@16 1280 {
Chris@16 1281 // // do not expand this macro, just copy the whole sequence
Chris@16 1282 // expanded.push_back(curr_token);
Chris@16 1283 // std::copy(seqstart, first,
Chris@16 1284 // std::inserter(expanded, expanded.end()));
Chris@16 1285 // do not expand macro, just copy macro name and parenthesis
Chris@16 1286 expanded.push_back(curr_token);
Chris@16 1287 expanded.push_back(*seqstart);
Chris@16 1288 first = ++seqstart;
Chris@16 1289 return false; // no further preprocessing required
Chris@16 1290 }
Chris@16 1291 #endif
Chris@16 1292
Chris@16 1293 // expand the replacement list of this macro
Chris@16 1294 expand_replacement_list(macro_def, arguments, expand_operator_defined,
Chris@16 1295 replacement_list);
Chris@16 1296 }
Chris@16 1297 else {
Chris@16 1298 // defined as an object-like macro
Chris@16 1299 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
Chris@16 1300 ctx.get_hooks().expanding_object_like_macro(
Chris@16 1301 macro_def.macroname, macro_def.macrodefinition, curr_token);
Chris@16 1302 #else
Chris@16 1303 if (ctx.get_hooks().expanding_object_like_macro(ctx.derived(),
Chris@16 1304 macro_def.macroname, macro_def.macrodefinition, curr_token))
Chris@16 1305 {
Chris@16 1306 // do not expand this macro, just copy the whole sequence
Chris@16 1307 expanded.push_back(curr_token);
Chris@16 1308 return false; // no further preprocessing required
Chris@16 1309 }
Chris@16 1310 #endif
Chris@16 1311
Chris@16 1312 bool found = false;
Chris@16 1313 impl::find_concat_operator concat_tag(found);
Chris@16 1314
Chris@16 1315 std::remove_copy_if(macro_def.macrodefinition.begin(),
Chris@16 1316 macro_def.macrodefinition.end(),
Chris@16 1317 std::inserter(replacement_list, replacement_list.end()),
Chris@16 1318 concat_tag);
Chris@16 1319
Chris@16 1320 // handle concatenation operators
Chris@16 1321 if (found && !concat_tokensequence(replacement_list))
Chris@16 1322 return false;
Chris@16 1323 }
Chris@16 1324 }
Chris@16 1325 else {
Chris@16 1326 // called as an object like macro
Chris@16 1327 if ((*it).second->is_functionlike) {
Chris@16 1328 // defined as a function-like macro
Chris@16 1329 if (0 != queue_symbol) {
Chris@16 1330 queue_symbol->push_back(curr_token);
Chris@16 1331 expanded.splice(expanded.end(), *queue_symbol);
Chris@16 1332 }
Chris@16 1333 else {
Chris@16 1334 expanded.push_back(curr_token);
Chris@16 1335 }
Chris@16 1336 ++first; // skip macro name
Chris@16 1337 return false; // no further preprocessing required
Chris@16 1338 }
Chris@16 1339 else {
Chris@16 1340 // defined as an object-like macro (expand it)
Chris@16 1341 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
Chris@16 1342 ctx.get_hooks().expanding_object_like_macro(
Chris@16 1343 macro_def.macroname, macro_def.macrodefinition, curr_token);
Chris@16 1344 #else
Chris@16 1345 if (ctx.get_hooks().expanding_object_like_macro(ctx.derived(),
Chris@16 1346 macro_def.macroname, macro_def.macrodefinition, curr_token))
Chris@16 1347 {
Chris@16 1348 // do not expand this macro, just copy the whole sequence
Chris@16 1349 expanded.push_back(curr_token);
Chris@16 1350 ++first; // skip macro name
Chris@16 1351 return false; // no further preprocessing required
Chris@16 1352 }
Chris@16 1353 #endif
Chris@16 1354
Chris@16 1355 bool found = false;
Chris@16 1356 impl::find_concat_operator concat_tag(found);
Chris@16 1357
Chris@16 1358 std::remove_copy_if(macro_def.macrodefinition.begin(),
Chris@16 1359 macro_def.macrodefinition.end(),
Chris@16 1360 std::inserter(replacement_list, replacement_list.end()),
Chris@16 1361 concat_tag);
Chris@16 1362
Chris@16 1363 // handle concatenation operators
Chris@16 1364 if (found && !concat_tokensequence(replacement_list))
Chris@16 1365 return false;
Chris@16 1366
Chris@16 1367 ++first; // skip macro name
Chris@16 1368 }
Chris@16 1369 }
Chris@16 1370
Chris@16 1371 // rescan the replacement list
Chris@16 1372 ContainerT expanded_list;
Chris@16 1373
Chris@16 1374 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
Chris@16 1375 ctx.get_hooks().expanded_macro(replacement_list);
Chris@16 1376 #else
Chris@16 1377 ctx.get_hooks().expanded_macro(ctx.derived(), replacement_list);
Chris@16 1378 #endif
Chris@16 1379
Chris@16 1380 rescan_replacement_list(curr_token, macro_def, replacement_list,
Chris@16 1381 expanded_list, expand_operator_defined, first, last);
Chris@16 1382
Chris@16 1383 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
Chris@16 1384 ctx.get_hooks().rescanned_macro(expanded_list);
Chris@16 1385 #else
Chris@16 1386 ctx.get_hooks().rescanned_macro(ctx.derived(), expanded_list);
Chris@16 1387 #endif
Chris@16 1388 expanded.splice(expanded.end(), expanded_list);
Chris@16 1389 return true; // rescan is required
Chris@16 1390 }
Chris@16 1391
Chris@16 1392 ///////////////////////////////////////////////////////////////////////////////
Chris@16 1393 //
Chris@16 1394 // If the token under inspection points to a certain predefined macro it will
Chris@16 1395 // be expanded, otherwise false is returned.
Chris@16 1396 // (only __FILE__, __LINE__ and __INCLUDE_LEVEL__ macros are expanded here)
Chris@16 1397 //
Chris@16 1398 ///////////////////////////////////////////////////////////////////////////////
Chris@16 1399 template <typename ContextT>
Chris@16 1400 template <typename ContainerT>
Chris@16 1401 inline bool
Chris@16 1402 macromap<ContextT>::expand_predefined_macro(token_type const &curr_token,
Chris@16 1403 ContainerT &expanded)
Chris@16 1404 {
Chris@16 1405 using namespace boost::wave;
Chris@16 1406
Chris@16 1407 string_type const &value = curr_token.get_value();
Chris@16 1408
Chris@16 1409 if (value.size() < 8 || '_' != value[0] || '_' != value[1])
Chris@16 1410 return false; // quick check failed
Chris@16 1411
Chris@16 1412 if (value == "__LINE__") {
Chris@16 1413 // expand the __LINE__ macro
Chris@16 1414 char buffer[22]; // 21 bytes holds all NUL-terminated unsigned 64-bit numbers
Chris@16 1415
Chris@16 1416 using namespace std; // for some systems sprintf is in namespace std
Chris@16 1417 sprintf(buffer, "%ld", main_pos.get_line());
Chris@16 1418 expanded.push_back(token_type(T_INTLIT, buffer, curr_token.get_position()));
Chris@16 1419 return true;
Chris@16 1420 }
Chris@16 1421 else if (value == "__FILE__") {
Chris@16 1422 // expand the __FILE__ macro
Chris@16 1423 namespace fs = boost::filesystem;
Chris@16 1424
Chris@16 1425 std::string file("\"");
Chris@16 1426 fs::path filename(wave::util::create_path(main_pos.get_file().c_str()));
Chris@16 1427
Chris@16 1428 using boost::wave::util::impl::escape_lit;
Chris@16 1429 file += escape_lit(wave::util::native_file_string(filename)) + "\"";
Chris@16 1430 expanded.push_back(token_type(T_STRINGLIT, file.c_str(),
Chris@16 1431 curr_token.get_position()));
Chris@16 1432 return true;
Chris@16 1433 }
Chris@16 1434 else if (value == "__INCLUDE_LEVEL__") {
Chris@16 1435 // expand the __INCLUDE_LEVEL__ macro
Chris@16 1436 char buffer[22]; // 21 bytes holds all NUL-terminated unsigned 64-bit numbers
Chris@16 1437
Chris@16 1438 using namespace std; // for some systems sprintf is in namespace std
Chris@16 1439 sprintf(buffer, "%d", (int)ctx.get_iteration_depth());
Chris@16 1440 expanded.push_back(token_type(T_INTLIT, buffer, curr_token.get_position()));
Chris@16 1441 return true;
Chris@16 1442 }
Chris@16 1443 return false; // no predefined token
Chris@16 1444 }
Chris@16 1445
Chris@16 1446 ///////////////////////////////////////////////////////////////////////////////
Chris@16 1447 //
Chris@16 1448 // resolve_defined(): resolve the operator defined() and replace it with the
Chris@16 1449 // correct T_INTLIT token
Chris@16 1450 //
Chris@16 1451 ///////////////////////////////////////////////////////////////////////////////
Chris@16 1452 template <typename ContextT>
Chris@16 1453 template <typename IteratorT, typename ContainerT>
Chris@16 1454 inline typename ContextT::token_type const &
Chris@16 1455 macromap<ContextT>::resolve_defined(IteratorT &first,
Chris@16 1456 IteratorT const &last, ContainerT &pending)
Chris@16 1457 {
Chris@16 1458 using namespace boost::wave;
Chris@16 1459 using namespace boost::wave::grammars;
Chris@16 1460
Chris@16 1461 ContainerT result;
Chris@16 1462 IteratorT start = first;
Chris@16 1463 boost::spirit::classic::parse_info<IteratorT> hit =
Chris@16 1464 defined_grammar_gen<typename ContextT::lexer_type>::
Chris@16 1465 parse_operator_defined(start, last, result);
Chris@16 1466
Chris@16 1467 if (!hit.hit) {
Chris@16 1468 string_type msg ("defined(): ");
Chris@16 1469 msg = msg + util::impl::as_string<string_type>(first, last);
Chris@16 1470 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, ill_formed_expression,
Chris@16 1471 msg.c_str(), main_pos);
Chris@16 1472
Chris@16 1473 // insert a dummy token
Chris@16 1474 pending.push_back(token_type(T_INTLIT, "0", main_pos));
Chris@16 1475 }
Chris@16 1476 else {
Chris@16 1477 impl::assign_iterator<IteratorT>::do_(first, hit.stop);
Chris@16 1478
Chris@16 1479 // insert a token, which reflects the outcome
Chris@16 1480 pending.push_back(token_type(T_INTLIT,
Chris@16 1481 is_defined(result.begin(), result.end()) ? "1" : "0",
Chris@16 1482 main_pos));
Chris@16 1483 }
Chris@16 1484
Chris@16 1485 on_exit::pop_front<definition_container_type> pop_front_token(pending);
Chris@16 1486
Chris@16 1487 return act_token = pending.front();
Chris@16 1488 }
Chris@16 1489
Chris@16 1490 ///////////////////////////////////////////////////////////////////////////////
Chris@16 1491 //
Chris@16 1492 // resolve_operator_pragma(): resolve the operator _Pragma() and dispatch to
Chris@16 1493 // the associated action
Chris@16 1494 //
Chris@16 1495 // This function returns true, if the pragma was correctly interpreted.
Chris@16 1496 // The iterator 'first' is positioned behind the closing ')'.
Chris@16 1497 // This function returns false, if the _Pragma was not known, the
Chris@16 1498 // preprocessed token sequence is pushed back to the 'pending' sequence.
Chris@16 1499 //
Chris@16 1500 ///////////////////////////////////////////////////////////////////////////////
Chris@16 1501 template <typename ContextT>
Chris@16 1502 template <typename IteratorT, typename ContainerT>
Chris@16 1503 inline bool
Chris@16 1504 macromap<ContextT>::resolve_operator_pragma(IteratorT &first,
Chris@16 1505 IteratorT const &last, ContainerT &pending, bool& seen_newline)
Chris@16 1506 {
Chris@16 1507 // isolate the parameter of the operator _Pragma
Chris@16 1508 token_type pragma_token = *first;
Chris@16 1509
Chris@16 1510 if (!impl::skip_to_token(ctx, first, last, T_LEFTPAREN, seen_newline)) {
Chris@16 1511 // illformed operator _Pragma
Chris@16 1512 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, ill_formed_expression,
Chris@16 1513 "operator _Pragma()", pragma_token.get_position());
Chris@16 1514 return false;
Chris@16 1515 }
Chris@16 1516
Chris@16 1517 std::vector<ContainerT> arguments;
Chris@16 1518 #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
Chris@16 1519 typename std::vector<ContainerT>::size_type count_args =
Chris@16 1520 collect_arguments (pragma_token, arguments, first, last, 1, seen_newline);
Chris@16 1521 #else
Chris@16 1522 IteratorT endparen = first;
Chris@16 1523 typename std::vector<ContainerT>::size_type count_args =
Chris@16 1524 collect_arguments (pragma_token, arguments, first, endparen, last, 1,
Chris@16 1525 seen_newline);
Chris@16 1526 #endif
Chris@16 1527
Chris@16 1528 // verify the parameter count
Chris@16 1529 if (pragma_token.get_position().get_file().empty())
Chris@16 1530 pragma_token.set_position(act_token.get_position());
Chris@16 1531
Chris@16 1532 if (count_args < 1 || arguments.size() < 1) {
Chris@16 1533 // too few macro arguments
Chris@16 1534 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, too_few_macroarguments,
Chris@16 1535 pragma_token.get_value().c_str(), pragma_token.get_position());
Chris@16 1536 return false;
Chris@16 1537 }
Chris@16 1538 if (count_args > 1 || arguments.size() > 1) {
Chris@16 1539 // too many macro arguments
Chris@16 1540 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, too_many_macroarguments,
Chris@16 1541 pragma_token.get_value().c_str(), pragma_token.get_position());
Chris@16 1542 return false;
Chris@16 1543 }
Chris@16 1544
Chris@16 1545 // preprocess the pragma token body
Chris@16 1546 typedef typename std::vector<ContainerT>::value_type::iterator
Chris@16 1547 argument_iterator_type;
Chris@16 1548
Chris@16 1549 ContainerT expanded;
Chris@16 1550 argument_iterator_type begin_it = arguments[0].begin();
Chris@16 1551 argument_iterator_type end_it = arguments[0].end();
Chris@16 1552 expand_whole_tokensequence(expanded, begin_it, end_it, false);
Chris@16 1553
Chris@16 1554 // un-escape the parameter of the operator _Pragma
Chris@16 1555 typedef typename token_type::string_type string_type;
Chris@16 1556
Chris@16 1557 string_type pragma_cmd;
Chris@16 1558 typename ContainerT::const_iterator end_exp = expanded.end();
Chris@16 1559 for (typename ContainerT::const_iterator it_exp = expanded.begin();
Chris@16 1560 it_exp != end_exp; ++it_exp)
Chris@16 1561 {
Chris@16 1562 if (T_EOF == token_id(*it_exp))
Chris@16 1563 break;
Chris@16 1564 if (IS_CATEGORY(*it_exp, WhiteSpaceTokenType))
Chris@16 1565 continue;
Chris@16 1566
Chris@16 1567 if (T_STRINGLIT != token_id(*it_exp)) {
Chris@16 1568 // ill formed operator _Pragma
Chris@16 1569 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
Chris@16 1570 ill_formed_pragma_option, "_Pragma",
Chris@16 1571 pragma_token.get_position());
Chris@16 1572 return false;
Chris@16 1573 }
Chris@16 1574 if (pragma_cmd.size() > 0) {
Chris@16 1575 // there should be exactly one string literal (string literals are to
Chris@16 1576 // be concatenated at translation phase 6, but _Pragma operators are
Chris@16 1577 // to be executed at translation phase 4)
Chris@16 1578 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
Chris@16 1579 ill_formed_pragma_option, "_Pragma",
Chris@16 1580 pragma_token.get_position());
Chris@16 1581 return false;
Chris@16 1582 }
Chris@16 1583
Chris@16 1584 // remove the '\"' and concat all given string literal-values
Chris@16 1585 string_type token_str = (*it_exp).get_value();
Chris@16 1586 pragma_cmd += token_str.substr(1, token_str.size() - 2);
Chris@16 1587 }
Chris@16 1588 string_type pragma_cmd_unesc = impl::unescape_lit(pragma_cmd);
Chris@16 1589
Chris@16 1590 // tokenize the pragma body
Chris@16 1591 typedef typename ContextT::lexer_type lexer_type;
Chris@16 1592
Chris@16 1593 ContainerT pragma;
Chris@16 1594 std::string pragma_cmd_str(pragma_cmd_unesc.c_str());
Chris@16 1595 lexer_type it = lexer_type(pragma_cmd_str.begin(), pragma_cmd_str.end(),
Chris@16 1596 pragma_token.get_position(), ctx.get_language());
Chris@16 1597 lexer_type end = lexer_type();
Chris@16 1598 for (/**/; it != end; ++it)
Chris@16 1599 pragma.push_back(*it);
Chris@16 1600
Chris@16 1601 // analyze the preprocessed token sequence and eventually dispatch to the
Chris@16 1602 // associated action
Chris@16 1603 if (interpret_pragma(ctx, pragma_token, pragma.begin(), pragma.end(),
Chris@16 1604 pending))
Chris@16 1605 {
Chris@16 1606 return true; // successfully recognized a wave specific pragma
Chris@16 1607 }
Chris@16 1608
Chris@16 1609 // unknown pragma token sequence, push it back and return to the caller
Chris@16 1610 pending.push_front(token_type(T_SPACE, " ", pragma_token.get_position()));
Chris@16 1611 pending.push_front(token_type(T_RIGHTPAREN, ")", pragma_token.get_position()));
Chris@16 1612 pending.push_front(token_type(T_STRINGLIT, string_type("\"") + pragma_cmd + "\"",
Chris@16 1613 pragma_token.get_position()));
Chris@16 1614 pending.push_front(token_type(T_LEFTPAREN, "(", pragma_token.get_position()));
Chris@16 1615 pending.push_front(pragma_token);
Chris@16 1616 return false;
Chris@16 1617 }
Chris@16 1618
Chris@16 1619 ///////////////////////////////////////////////////////////////////////////////
Chris@16 1620 //
Chris@16 1621 // Test, whether the result of a concat operator is well formed or not.
Chris@16 1622 //
Chris@16 1623 // This is done by re-scanning (re-tokenizing) the resulting token sequence,
Chris@16 1624 // which should give back exactly one token.
Chris@16 1625 //
Chris@16 1626 ///////////////////////////////////////////////////////////////////////////////
Chris@16 1627 template <typename ContextT>
Chris@16 1628 template <typename ContainerT>
Chris@16 1629 inline bool
Chris@16 1630 macromap<ContextT>::is_valid_concat(string_type new_value,
Chris@16 1631 position_type const &pos, ContainerT &rescanned)
Chris@16 1632 {
Chris@16 1633 // re-tokenize the newly generated string
Chris@16 1634 typedef typename ContextT::lexer_type lexer_type;
Chris@16 1635
Chris@16 1636 std::string value_to_test(new_value.c_str());
Chris@16 1637
Chris@16 1638 boost::wave::language_support lang =
Chris@16 1639 boost::wave::enable_prefer_pp_numbers(ctx.get_language());
Chris@16 1640 lang = boost::wave::enable_single_line(lang);
Chris@16 1641
Chris@16 1642 lexer_type it = lexer_type(value_to_test.begin(), value_to_test.end(), pos,
Chris@16 1643 lang);
Chris@16 1644 lexer_type end = lexer_type();
Chris@16 1645 for (/**/; it != end && T_EOF != token_id(*it); ++it)
Chris@16 1646 {
Chris@16 1647 // as of Wave V2.0.7 pasting of tokens is valid only if the resulting
Chris@16 1648 // tokens are pp_tokens (as mandated by C++11)
Chris@16 1649 if (!is_pp_token(*it))
Chris@16 1650 return false;
Chris@16 1651 rescanned.push_back(*it);
Chris@16 1652 }
Chris@16 1653
Chris@16 1654 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
Chris@16 1655 if (boost::wave::need_variadics(ctx.get_language()))
Chris@16 1656 return true; // in variadics mode token pasting is well defined
Chris@16 1657 #endif
Chris@16 1658
Chris@16 1659 // test if the newly generated token sequence contains more than 1 token
Chris@16 1660 return 1 == rescanned.size();
Chris@16 1661 }
Chris@16 1662
Chris@16 1663 ///////////////////////////////////////////////////////////////////////////////
Chris@16 1664 //
Chris@16 1665 // Handle all occurrences of the concatenation operator '##' inside the given
Chris@16 1666 // token sequence.
Chris@16 1667 //
Chris@16 1668 ///////////////////////////////////////////////////////////////////////////////
Chris@16 1669 template <typename Context>
Chris@16 1670 inline void report_invalid_concatenation(Context& ctx,
Chris@16 1671 typename Context::token_type const& prev,
Chris@16 1672 typename Context::token_type const& next,
Chris@16 1673 typename Context::position_type const& main_pos)
Chris@16 1674 {
Chris@16 1675 typename Context::string_type error_string("\"");
Chris@16 1676
Chris@16 1677 error_string += prev.get_value();
Chris@16 1678 error_string += "\" and \"";
Chris@16 1679 error_string += next.get_value();
Chris@16 1680 error_string += "\"";
Chris@16 1681 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, invalid_concat,
Chris@16 1682 error_string.c_str(), main_pos);
Chris@16 1683 }
Chris@16 1684
Chris@16 1685 template <typename ContextT>
Chris@16 1686 template <typename ContainerT>
Chris@16 1687 inline bool
Chris@16 1688 macromap<ContextT>::concat_tokensequence(ContainerT &expanded)
Chris@16 1689 {
Chris@16 1690 using namespace boost::wave;
Chris@16 1691 typedef typename ContainerT::iterator iterator_type;
Chris@16 1692
Chris@16 1693 iterator_type end = expanded.end();
Chris@16 1694 iterator_type prev = end;
Chris@16 1695 for (iterator_type it = expanded.begin(); it != end; /**/)
Chris@16 1696 {
Chris@16 1697 if (T_POUND_POUND == BASE_TOKEN(token_id(*it))) {
Chris@16 1698 iterator_type next = it;
Chris@16 1699
Chris@16 1700 ++next;
Chris@16 1701 if (prev == end || next == end) {
Chris@16 1702 // error, '##' should be in between two tokens
Chris@16 1703 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
Chris@16 1704 ill_formed_operator, "concat ('##')", main_pos);
Chris@16 1705 return false;
Chris@16 1706 }
Chris@16 1707
Chris@16 1708 // replace prev##next with the concatenated value, skip whitespace
Chris@16 1709 // before and after the '##' operator
Chris@16 1710 while (IS_CATEGORY(*next, WhiteSpaceTokenType)) {
Chris@16 1711 ++next;
Chris@16 1712 if (next == end) {
Chris@16 1713 // error, '##' should be in between two tokens
Chris@16 1714 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
Chris@16 1715 ill_formed_operator, "concat ('##')", main_pos);
Chris@16 1716 return false;
Chris@16 1717 }
Chris@16 1718 }
Chris@16 1719
Chris@16 1720 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
Chris@16 1721 if (boost::wave::need_variadics(ctx.get_language())) {
Chris@16 1722 if (T_PLACEMARKER == token_id(*next)) {
Chris@16 1723 // remove the '##' and the next tokens from the sequence
Chris@16 1724 iterator_type first_to_delete = prev;
Chris@16 1725
Chris@16 1726 expanded.erase(++first_to_delete, ++next);
Chris@16 1727 it = next;
Chris@16 1728 continue;
Chris@16 1729 }
Chris@16 1730 else if (T_PLACEMARKER == token_id(*prev)) {
Chris@16 1731 // remove the '##' and the next tokens from the sequence
Chris@16 1732 iterator_type first_to_delete = prev;
Chris@16 1733
Chris@16 1734 *prev = *next;
Chris@16 1735 expanded.erase(++first_to_delete, ++next);
Chris@16 1736 it = next;
Chris@16 1737 continue;
Chris@16 1738 }
Chris@16 1739 }
Chris@16 1740 #endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
Chris@16 1741
Chris@16 1742 // test if the concat operator has to concatenate two unrelated
Chris@16 1743 // tokens i.e. the result yields more then one token
Chris@16 1744 string_type concat_result;
Chris@16 1745 ContainerT rescanned;
Chris@16 1746
Chris@16 1747 concat_result = ((*prev).get_value() + (*next).get_value());
Chris@16 1748
Chris@16 1749 // analyze the validity of the concatenation result
Chris@16 1750 if (!is_valid_concat(concat_result, (*prev).get_position(),
Chris@16 1751 rescanned) &&
Chris@16 1752 !IS_CATEGORY(*prev, WhiteSpaceTokenType) &&
Chris@16 1753 !IS_CATEGORY(*next, WhiteSpaceTokenType))
Chris@16 1754 {
Chris@16 1755 report_invalid_concatenation(ctx, *prev, *next, main_pos);
Chris@16 1756 return false;
Chris@16 1757 }
Chris@16 1758
Chris@16 1759 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
Chris@16 1760 if (boost::wave::need_variadics(ctx.get_language())) {
Chris@16 1761 // remove the prev, '##' and the next tokens from the sequence
Chris@16 1762 expanded.erase(prev, ++next); // remove not needed tokens
Chris@16 1763
Chris@16 1764 // some stl implementations clear() the container if we erased all
Chris@16 1765 // the elements, which orphans all iterators. we re-initialize these
Chris@16 1766 // here
Chris@16 1767 if (expanded.empty())
Chris@16 1768 end = next = expanded.end();
Chris@16 1769
Chris@16 1770 // replace the old token (pointed to by *prev) with the re-tokenized
Chris@16 1771 // sequence
Chris@16 1772 expanded.splice(next, rescanned);
Chris@16 1773
Chris@16 1774 // the last token of the inserted sequence is the new previous
Chris@16 1775 prev = next;
Chris@16 1776 if (next != expanded.end())
Chris@16 1777 --prev;
Chris@16 1778 }
Chris@16 1779 else
Chris@16 1780 #endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
Chris@16 1781 {
Chris@16 1782 // we leave the token_id unchanged, but unmark the token as
Chris@16 1783 // disabled, if appropriate
Chris@16 1784 (*prev).set_value(concat_result);
Chris@16 1785 if (T_NONREPLACABLE_IDENTIFIER == token_id(*prev))
Chris@16 1786 (*prev).set_token_id(T_IDENTIFIER);
Chris@16 1787
Chris@16 1788 // remove the '##' and the next tokens from the sequence
Chris@16 1789 iterator_type first_to_delete = prev;
Chris@16 1790
Chris@16 1791 expanded.erase(++first_to_delete, ++next);
Chris@16 1792 }
Chris@16 1793 it = next;
Chris@16 1794 continue;
Chris@16 1795 }
Chris@16 1796
Chris@16 1797 // save last non-whitespace token position
Chris@16 1798 if (!IS_CATEGORY(*it, WhiteSpaceTokenType))
Chris@16 1799 prev = it;
Chris@16 1800
Chris@16 1801 ++it; // next token, please
Chris@16 1802 }
Chris@16 1803 return true;
Chris@16 1804 }
Chris@16 1805
Chris@16 1806 ///////////////////////////////////////////////////////////////////////////////
Chris@16 1807 //
Chris@16 1808 // predefine_macro(): predefine a single macro
Chris@16 1809 //
Chris@16 1810 ///////////////////////////////////////////////////////////////////////////////
Chris@16 1811 template <typename ContextT>
Chris@16 1812 inline void
Chris@16 1813 macromap<ContextT>::predefine_macro(defined_macros_type *scope,
Chris@16 1814 string_type const &name, token_type const &t)
Chris@16 1815 {
Chris@16 1816 definition_container_type macrodefinition;
Chris@16 1817 std::vector<token_type> param;
Chris@16 1818
Chris@16 1819 macrodefinition.push_back(t);
Chris@16 1820 add_macro(token_type(T_IDENTIFIER, name, t.get_position()),
Chris@16 1821 false, param, macrodefinition, true, scope);
Chris@16 1822 }
Chris@16 1823
Chris@16 1824 ///////////////////////////////////////////////////////////////////////////////
Chris@16 1825 //
Chris@16 1826 // init_predefined_macros(): init the predefined macros
Chris@16 1827 //
Chris@16 1828 ///////////////////////////////////////////////////////////////////////////////
Chris@16 1829 template <typename ContextT>
Chris@16 1830 inline void
Chris@16 1831 macromap<ContextT>::init_predefined_macros(char const *fname,
Chris@16 1832 defined_macros_type *scope, bool at_global_scope)
Chris@16 1833 {
Chris@16 1834 // if no scope is given, use the current one
Chris@16 1835 defined_macros_type *current_scope = scope ? scope : current_macros;
Chris@16 1836
Chris@16 1837 // first, add the static macros
Chris@16 1838 position_type pos("<built-in>");
Chris@16 1839
Chris@16 1840 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
Chris@16 1841 if (boost::wave::need_c99(ctx.get_language())) {
Chris@16 1842 // define C99 specifics
Chris@16 1843 for (int i = 0; 0 != predef.static_data_c99(i).name; ++i) {
Chris@16 1844 predefined_macros::static_macros const& m = predef.static_data_c99(i);
Chris@16 1845 predefine_macro(current_scope, m.name,
Chris@16 1846 token_type(m.token_id, m.value, pos));
Chris@16 1847 }
Chris@16 1848 }
Chris@16 1849 else
Chris@16 1850 #endif
Chris@16 1851 {
Chris@16 1852 #if BOOST_WAVE_SUPPORT_CPP0X != 0
Chris@16 1853 if (boost::wave::need_cpp0x(ctx.get_language())) {
Chris@16 1854 // define C++11 specifics
Chris@16 1855 for (int i = 0; 0 != predef.static_data_cpp0x(i).name; ++i) {
Chris@16 1856 predefined_macros::static_macros const& m = predef.static_data_cpp0x(i);
Chris@16 1857 predefine_macro(current_scope, m.name,
Chris@16 1858 token_type(m.token_id, m.value, pos));
Chris@16 1859 }
Chris@16 1860 }
Chris@16 1861 else
Chris@16 1862 #endif
Chris@16 1863 {
Chris@16 1864 // define C++ specifics
Chris@16 1865 for (int i = 0; 0 != predef.static_data_cpp(i).name; ++i) {
Chris@16 1866 predefined_macros::static_macros const& m = predef.static_data_cpp(i);
Chris@16 1867 predefine_macro(current_scope, m.name,
Chris@16 1868 token_type(m.token_id, m.value, pos));
Chris@16 1869 }
Chris@16 1870
Chris@16 1871 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
Chris@16 1872 // define __WAVE_HAS_VARIADICS__, if appropriate
Chris@16 1873 if (boost::wave::need_variadics(ctx.get_language())) {
Chris@16 1874 predefine_macro(current_scope, "__WAVE_HAS_VARIADICS__",
Chris@16 1875 token_type(T_INTLIT, "1", pos));
Chris@16 1876 }
Chris@16 1877 #endif
Chris@16 1878 }
Chris@16 1879 }
Chris@16 1880
Chris@16 1881 // predefine the __BASE_FILE__ macro which contains the main file name
Chris@16 1882 namespace fs = boost::filesystem;
Chris@16 1883 if (string_type(fname) != "<Unknown>") {
Chris@16 1884 fs::path filename(create_path(fname));
Chris@16 1885
Chris@16 1886 using boost::wave::util::impl::escape_lit;
Chris@16 1887 predefine_macro(current_scope, "__BASE_FILE__",
Chris@16 1888 token_type(T_STRINGLIT, string_type("\"") +
Chris@16 1889 escape_lit(native_file_string(filename)).c_str() + "\"", pos));
Chris@16 1890 base_name = fname;
Chris@16 1891 }
Chris@16 1892 else if (!base_name.empty()) {
Chris@16 1893 fs::path filename(create_path(base_name.c_str()));
Chris@16 1894
Chris@16 1895 using boost::wave::util::impl::escape_lit;
Chris@16 1896 predefine_macro(current_scope, "__BASE_FILE__",
Chris@16 1897 token_type(T_STRINGLIT, string_type("\"") +
Chris@16 1898 escape_lit(native_file_string(filename)).c_str() + "\"", pos));
Chris@16 1899 }
Chris@16 1900
Chris@16 1901 // now add the dynamic macros
Chris@16 1902 for (int j = 0; 0 != predef.dynamic_data(j).name; ++j) {
Chris@16 1903 predefined_macros::dynamic_macros const& m = predef.dynamic_data(j);
Chris@16 1904 predefine_macro(current_scope, m.name,
Chris@16 1905 token_type(m.token_id, (predef.* m.generator)(), pos));
Chris@16 1906 }
Chris@16 1907 }
Chris@16 1908
Chris@16 1909 ///////////////////////////////////////////////////////////////////////////////
Chris@16 1910 //
Chris@16 1911 // reset_macromap(): initialize the internal macro symbol namespace
Chris@16 1912 //
Chris@16 1913 ///////////////////////////////////////////////////////////////////////////////
Chris@16 1914 template <typename ContextT>
Chris@16 1915 inline void
Chris@16 1916 macromap<ContextT>::reset_macromap()
Chris@16 1917 {
Chris@16 1918 current_macros->clear();
Chris@16 1919 predef.reset();
Chris@16 1920 act_token = token_type();
Chris@16 1921 }
Chris@16 1922
Chris@16 1923 ///////////////////////////////////////////////////////////////////////////////
Chris@16 1924 }}} // namespace boost::wave::util
Chris@16 1925
Chris@16 1926 #if BOOST_WAVE_SERIALIZATION != 0
Chris@16 1927 namespace boost { namespace serialization {
Chris@16 1928
Chris@16 1929 template<typename ContextT>
Chris@16 1930 struct version<boost::wave::util::macromap<ContextT> >
Chris@16 1931 {
Chris@16 1932 typedef boost::wave::util::macromap<ContextT> target_type;
Chris@16 1933 typedef mpl::int_<target_type::version> type;
Chris@16 1934 typedef mpl::integral_c_tag tag;
Chris@16 1935 BOOST_STATIC_CONSTANT(unsigned int, value = version::type::value);
Chris@16 1936 };
Chris@16 1937
Chris@16 1938 }} // namespace boost::serialization
Chris@16 1939 #endif
Chris@16 1940
Chris@16 1941 // the suffix header occurs after all of the code
Chris@16 1942 #ifdef BOOST_HAS_ABI_HEADERS
Chris@16 1943 #include BOOST_ABI_SUFFIX
Chris@16 1944 #endif
Chris@16 1945
Chris@16 1946 #endif // !defined(CPP_MACROMAP_HPP_CB8F51B0_A3F0_411C_AEF4_6FF631B8B414_INCLUDED)