cpp_context.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. /*=============================================================================
  2. Boost.Wave: A Standard compliant C++ preprocessor library
  3. Definition of the preprocessor context
  4. http://www.boost.org/
  5. Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
  6. Software License, Version 1.0. (See accompanying file
  7. LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  8. =============================================================================*/
  9. #if !defined(BOOST_CPP_CONTEXT_HPP_907485E2_6649_4A87_911B_7F7225F3E5B8_INCLUDED)
  10. #define BOOST_CPP_CONTEXT_HPP_907485E2_6649_4A87_911B_7F7225F3E5B8_INCLUDED
  11. #include <string>
  12. #include <vector>
  13. #include <stack>
  14. #include <boost/concept_check.hpp>
  15. #include <boost/noncopyable.hpp>
  16. #include <boost/filesystem/path.hpp>
  17. #include <boost/mpl/if.hpp>
  18. #include <boost/type_traits/is_same.hpp>
  19. #include <boost/pool/pool_alloc.hpp>
  20. #include <boost/wave/wave_config.hpp>
  21. #if BOOST_WAVE_SERIALIZATION != 0
  22. #include <boost/serialization/serialization.hpp>
  23. #include <boost/wave/wave_config_constant.hpp>
  24. #endif
  25. #include <boost/wave/token_ids.hpp>
  26. #include <boost/wave/util/unput_queue_iterator.hpp>
  27. #include <boost/wave/util/cpp_ifblock.hpp>
  28. #include <boost/wave/util/cpp_include_paths.hpp>
  29. #include <boost/wave/util/iteration_context.hpp>
  30. #include <boost/wave/util/cpp_iterator.hpp>
  31. #include <boost/wave/util/cpp_macromap.hpp>
  32. #include <boost/wave/preprocessing_hooks.hpp>
  33. #include <boost/wave/whitespace_handling.hpp>
  34. #include <boost/wave/cpp_iteration_context.hpp>
  35. #include <boost/wave/language_support.hpp>
  36. // this must occur after all of the includes and before any code appears
  37. #ifdef BOOST_HAS_ABI_HEADERS
  38. #include BOOST_ABI_PREFIX
  39. #endif
  40. ///////////////////////////////////////////////////////////////////////////////
  41. namespace boost {
  42. namespace wave {
  43. ///////////////////////////////////////////////////////////////////////////////
  44. //
  45. // The C/C++ preprocessor context template class
  46. //
  47. // The boost::wave::context template is the main interface class to
  48. // control the behavior of the preprocessing engine.
  49. //
  50. // The following template parameters has to be supplied:
  51. //
  52. // IteratorT The iterator type of the underlying input stream
  53. // LexIteratorT The lexer iterator type to use as the token factory
  54. // InputPolicyT The input policy type to use for loading the files
  55. // to be included. This template parameter is optional and
  56. // defaults to the
  57. // iteration_context_policies::load_file_to_string
  58. // type.
  59. // HooksT The hooks policy to use for different notification
  60. // callbacks. This template parameter is optional and
  61. // defaults to the
  62. // context_policies::default_preprocessing_hooks
  63. // type.
  64. // DerivedT The type of the type being derived from the context
  65. // type (if any). This template parameter is optional and
  66. // defaults to 'this_type', which means that the context
  67. // type will be used assuming no derived type exists.
  68. //
  69. ///////////////////////////////////////////////////////////////////////////////
  70. struct this_type {};
  71. template <
  72. typename IteratorT,
  73. typename LexIteratorT,
  74. typename InputPolicyT = iteration_context_policies::load_file_to_string,
  75. typename HooksT = context_policies::eat_whitespace<typename LexIteratorT::token_type>,
  76. typename DerivedT = this_type
  77. >
  78. class context : private boost::noncopyable
  79. {
  80. private:
  81. typedef typename mpl::if_<
  82. is_same<DerivedT, this_type>, context, DerivedT
  83. >::type actual_context_type;
  84. public:
  85. // concept checks
  86. // the given iterator should be at least a forward iterator type
  87. BOOST_CLASS_REQUIRE(IteratorT, boost, ForwardIteratorConcept);
  88. // public typedefs
  89. typedef typename LexIteratorT::token_type token_type;
  90. typedef typename token_type::string_type string_type;
  91. typedef IteratorT target_iterator_type;
  92. typedef LexIteratorT lexer_type;
  93. typedef pp_iterator<context> iterator_type;
  94. typedef InputPolicyT input_policy_type;
  95. typedef typename token_type::position_type position_type;
  96. // type of a token sequence
  97. typedef std::list<token_type, boost::fast_pool_allocator<token_type> >
  98. token_sequence_type;
  99. // type of the policies
  100. typedef HooksT hook_policy_type;
  101. private:
  102. // stack of shared_ptr's to the pending iteration contexts
  103. typedef boost::shared_ptr<base_iteration_context<context, lexer_type> >
  104. iteration_ptr_type;
  105. typedef boost::wave::util::iteration_context_stack<iteration_ptr_type>
  106. iteration_context_stack_type;
  107. typedef typename iteration_context_stack_type::size_type iter_size_type;
  108. context *this_() { return this; } // avoid warning in constructor
  109. public:
  110. context(target_iterator_type const &first_, target_iterator_type const &last_,
  111. char const *fname = "<Unknown>", HooksT const &hooks_ = HooksT())
  112. : first(first_), last(last_), filename(fname)
  113. , has_been_initialized(false)
  114. #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
  115. , current_filename(fname)
  116. #endif
  117. , current_relative_filename(fname)
  118. , macros(*this_())
  119. , language(language_support(
  120. support_cpp
  121. | support_option_convert_trigraphs
  122. | support_option_emit_line_directives
  123. #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
  124. | support_option_include_guard_detection
  125. #endif
  126. #if BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES != 0
  127. | support_option_emit_pragma_directives
  128. #endif
  129. | support_option_insert_whitespace
  130. ))
  131. , hooks(hooks_)
  132. {
  133. macros.init_predefined_macros(fname);
  134. }
  135. // default copy constructor
  136. // default assignment operator
  137. // default destructor
  138. // iterator interface
  139. iterator_type begin()
  140. {
  141. std::string fname(filename);
  142. if (filename != "<Unknown>" && filename != "<stdin>") {
  143. using namespace boost::filesystem;
  144. path fpath(util::complete_path(path(filename)));
  145. fname = fpath.string();
  146. }
  147. return iterator_type(*this, first, last, position_type(fname.c_str()));
  148. }
  149. iterator_type begin(
  150. target_iterator_type const &first_,
  151. target_iterator_type const &last_)
  152. {
  153. std::string fname(filename);
  154. if (filename != "<Unknown>" && filename != "<stdin>") {
  155. using namespace boost::filesystem;
  156. path fpath(util::complete_path(path(filename)));
  157. fname = fpath.string();
  158. }
  159. return iterator_type(*this, first_, last_, position_type(fname.c_str()));
  160. }
  161. iterator_type end() const
  162. { return iterator_type(); }
  163. // maintain include paths
  164. bool add_include_path(char const *path_)
  165. { return includes.add_include_path(path_, false);}
  166. bool add_sysinclude_path(char const *path_)
  167. { return includes.add_include_path(path_, true);}
  168. void set_sysinclude_delimiter() { includes.set_sys_include_delimiter(); }
  169. typename iteration_context_stack_type::size_type get_iteration_depth() const
  170. { return iter_ctxs.size(); }
  171. // maintain defined macros
  172. #if BOOST_WAVE_ENABLE_COMMANDLINE_MACROS != 0
  173. template <typename StringT>
  174. bool add_macro_definition(StringT macrostring, bool is_predefined = false)
  175. {
  176. return boost::wave::util::add_macro_definition(*this,
  177. util::to_string<std::string>(macrostring), is_predefined,
  178. get_language());
  179. }
  180. #endif
  181. // Define and undefine macros, macro introspection
  182. template <typename StringT>
  183. bool add_macro_definition(StringT const &name, position_type const& pos,
  184. bool has_params, std::vector<token_type> &parameters,
  185. token_sequence_type &definition, bool is_predefined = false)
  186. {
  187. return macros.add_macro(
  188. token_type(T_IDENTIFIER, util::to_string<string_type>(name), pos),
  189. has_params, parameters, definition, is_predefined);
  190. }
  191. template <typename StringT>
  192. bool is_defined_macro(StringT const &str) const
  193. {
  194. return macros.is_defined(util::to_string<string_type>(str));
  195. }
  196. template <typename StringT>
  197. bool get_macro_definition(StringT const &name,
  198. bool &has_params, bool &is_predefined, position_type &pos,
  199. std::vector<token_type> &parameters,
  200. token_sequence_type &definition) const
  201. {
  202. return macros.get_macro(util::to_string<string_type>(name),
  203. has_params, is_predefined, pos, parameters, definition);
  204. }
  205. template <typename StringT>
  206. bool remove_macro_definition(StringT const& undefname, bool even_predefined = false)
  207. {
  208. // strip leading and trailing whitespace
  209. string_type name = util::to_string<string_type>(undefname);
  210. typename string_type::size_type pos = name.find_first_not_of(" \t");
  211. if (pos != string_type::npos) {
  212. typename string_type::size_type endpos = name.find_last_not_of(" \t");
  213. name = name.substr(pos, endpos-pos+1);
  214. }
  215. #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
  216. // ensure this gets removed from the list of include guards as well
  217. includes.remove_pragma_once_header(
  218. util::to_string<std::string>(name));
  219. #endif
  220. return macros.remove_macro(name, macros.get_main_pos(), even_predefined);
  221. }
  222. void reset_macro_definitions()
  223. { macros.reset_macromap(); macros.init_predefined_macros(); }
  224. // Iterate over names of defined macros
  225. typedef boost::wave::util::macromap<context> macromap_type;
  226. typedef typename macromap_type::name_iterator name_iterator;
  227. typedef typename macromap_type::const_name_iterator const_name_iterator;
  228. name_iterator macro_names_begin() { return macros.begin(); }
  229. name_iterator macro_names_end() { return macros.end(); }
  230. const_name_iterator macro_names_begin() const { return macros.begin(); }
  231. const_name_iterator macro_names_end() const { return macros.end(); }
  232. // This version now is used internally mainly, but since it was a documented
  233. // API function we leave it in the public interface.
  234. bool add_macro_definition(token_type const &name, bool has_params,
  235. std::vector<token_type> &parameters, token_sequence_type &definition,
  236. bool is_predefined = false)
  237. {
  238. return macros.add_macro(name, has_params, parameters, definition,
  239. is_predefined);
  240. }
  241. // get the Wave version information
  242. static std::string get_version()
  243. {
  244. boost::wave::util::predefined_macros p;
  245. return util::to_string<std::string>(p.get_fullversion());
  246. }
  247. static std::string get_version_string()
  248. {
  249. boost::wave::util::predefined_macros p;
  250. return util::to_string<std::string>(p.get_versionstr());
  251. }
  252. // access current language options
  253. void set_language(boost::wave::language_support language_,
  254. bool reset_macros = true)
  255. {
  256. language = language_;
  257. if (reset_macros)
  258. reset_macro_definitions();
  259. }
  260. boost::wave::language_support get_language() const { return language; }
  261. position_type &get_main_pos() { return macros.get_main_pos(); }
  262. position_type const& get_main_pos() const { return macros.get_main_pos(); }
  263. // change and ask for maximal possible include nesting depth
  264. void set_max_include_nesting_depth(iter_size_type new_depth)
  265. { iter_ctxs.set_max_include_nesting_depth(new_depth); }
  266. iter_size_type get_max_include_nesting_depth() const
  267. { return iter_ctxs.get_max_include_nesting_depth(); }
  268. // access the policies
  269. hook_policy_type &get_hooks() { return hooks; }
  270. hook_policy_type const &get_hooks() const { return hooks; }
  271. // return type of actually used context type (might be the derived type)
  272. actual_context_type& derived()
  273. { return *static_cast<actual_context_type*>(this); }
  274. actual_context_type const& derived() const
  275. { return *static_cast<actual_context_type const*>(this); }
  276. // return the directory of the currently preprocessed file
  277. boost::filesystem::path get_current_directory() const
  278. { return includes.get_current_directory(); }
  279. #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
  280. protected:
  281. friend class boost::wave::pp_iterator<context>;
  282. friend class boost::wave::impl::pp_iterator_functor<context>;
  283. friend class boost::wave::util::macromap<context>;
  284. #endif
  285. // make sure the context has been initialized
  286. void init_context()
  287. {
  288. if (!has_been_initialized) {
  289. std::string fname(filename);
  290. if (filename != "<Unknown>" && filename != "<stdin>") {
  291. using namespace boost::filesystem;
  292. path fpath(util::complete_path(path(filename)));
  293. fname = fpath.string();
  294. includes.set_current_directory(fname.c_str());
  295. }
  296. has_been_initialized = true; // execute once
  297. }
  298. }
  299. template <typename IteratorT2>
  300. bool is_defined_macro(IteratorT2 const &begin, IteratorT2 const &end) const
  301. { return macros.is_defined(begin, end); }
  302. // maintain include paths (helper functions)
  303. void set_current_directory(char const *path_)
  304. { includes.set_current_directory(path_); }
  305. // conditional compilation contexts
  306. bool get_if_block_status() const { return ifblocks.get_status(); }
  307. bool get_if_block_some_part_status() const
  308. { return ifblocks.get_some_part_status(); }
  309. bool get_enclosing_if_block_status() const
  310. { return ifblocks.get_enclosing_status(); }
  311. void enter_if_block(bool new_status)
  312. { ifblocks.enter_if_block(new_status); }
  313. bool enter_elif_block(bool new_status)
  314. { return ifblocks.enter_elif_block(new_status); }
  315. bool enter_else_block() { return ifblocks.enter_else_block(); }
  316. bool exit_if_block() { return ifblocks.exit_if_block(); }
  317. typename boost::wave::util::if_block_stack::size_type get_if_block_depth() const
  318. { return ifblocks.get_if_block_depth(); }
  319. // stack of iteration contexts
  320. iteration_ptr_type pop_iteration_context()
  321. { iteration_ptr_type top = iter_ctxs.top(); iter_ctxs.pop(); return top; }
  322. void push_iteration_context(position_type const &act_pos, iteration_ptr_type iter_ctx)
  323. { iter_ctxs.push(*this, act_pos, iter_ctx); }
  324. ///////////////////////////////////////////////////////////////////////////////
  325. //
  326. // expand_tokensequence():
  327. // expands all macros contained in a given token sequence, handles '##'
  328. // and '#' pp operators and re-scans the resulting sequence
  329. // (essentially pre-processes the token sequence).
  330. //
  331. // The expand_defined parameter is true during macro expansion inside
  332. // a C++ expression given for a #if or #elif statement.
  333. //
  334. ///////////////////////////////////////////////////////////////////////////////
  335. template <typename IteratorT2>
  336. token_type expand_tokensequence(IteratorT2 &first_, IteratorT2 const &last_,
  337. token_sequence_type &pending, token_sequence_type &expanded,
  338. bool& seen_newline, bool expand_defined = false,
  339. bool expand_has_include = false)
  340. {
  341. return macros.expand_tokensequence(first_, last_, pending, expanded,
  342. seen_newline, expand_defined, expand_has_include);
  343. }
  344. template <typename IteratorT2>
  345. void expand_whole_tokensequence(IteratorT2 &first_, IteratorT2 const &last_,
  346. token_sequence_type &expanded, bool expand_defined = true,
  347. bool expand_has_include = true)
  348. {
  349. macros.expand_whole_tokensequence(
  350. expanded, first_, last_,
  351. expand_defined, expand_has_include);
  352. // remove any contained placeholder
  353. boost::wave::util::impl::remove_placeholders(expanded);
  354. }
  355. public:
  356. #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
  357. // support for #pragma once
  358. // maintain the real name of the current preprocessed file
  359. void set_current_filename(char const *real_name)
  360. { current_filename = real_name; }
  361. std::string const &get_current_filename() const
  362. { return current_filename; }
  363. // maintain the list of known headers containing #pragma once
  364. bool has_pragma_once(std::string const &filename_)
  365. { return includes.has_pragma_once(filename_); }
  366. bool add_pragma_once_header(std::string const &filename_,
  367. std::string const& guard_name)
  368. {
  369. get_hooks().detected_include_guard(derived(), filename_, guard_name);
  370. return includes.add_pragma_once_header(filename_, guard_name);
  371. }
  372. bool add_pragma_once_header(token_type const &pragma_,
  373. std::string const &filename_)
  374. {
  375. get_hooks().detected_pragma_once(derived(), pragma_, filename_);
  376. return includes.add_pragma_once_header(filename_,
  377. "__BOOST_WAVE_PRAGMA_ONCE__");
  378. }
  379. #endif
  380. void set_current_relative_filename(char const *real_name)
  381. { current_relative_filename = real_name; }
  382. std::string const &get_current_relative_filename() const
  383. { return current_relative_filename; }
  384. bool find_include_file (std::string &s, std::string &d, bool is_system,
  385. char const *current_file) const
  386. { return includes.find_include_file(s, d, is_system, current_file); }
  387. #if BOOST_WAVE_SERIALIZATION != 0
  388. public:
  389. BOOST_STATIC_CONSTANT(unsigned int, version = 0x10);
  390. BOOST_STATIC_CONSTANT(unsigned int, version_mask = 0x0f);
  391. private:
  392. friend class boost::serialization::access;
  393. template<class Archive>
  394. void save(Archive & ar, const unsigned int version) const
  395. {
  396. using namespace boost::serialization;
  397. string_type cfg(BOOST_PP_STRINGIZE(BOOST_WAVE_CONFIG));
  398. string_type kwd(BOOST_WAVE_PRAGMA_KEYWORD);
  399. string_type strtype(BOOST_PP_STRINGIZE((BOOST_WAVE_STRINGTYPE)));
  400. ar & make_nvp("config", cfg);
  401. ar & make_nvp("pragma_keyword", kwd);
  402. ar & make_nvp("string_type", strtype);
  403. ar & make_nvp("language_options", language);
  404. ar & make_nvp("macro_definitions", macros);
  405. ar & make_nvp("include_settings", includes);
  406. }
  407. template<class Archive>
  408. void load(Archive & ar, const unsigned int loaded_version)
  409. {
  410. using namespace boost::serialization;
  411. if (version != (loaded_version & ~version_mask)) {
  412. BOOST_WAVE_THROW_CTX((*this), preprocess_exception,
  413. incompatible_config, "cpp_context state version",
  414. get_main_pos());
  415. return;
  416. }
  417. // check compatibility of the stored information
  418. string_type config, pragma_keyword, string_type_str;
  419. // BOOST_PP_STRINGIZE(BOOST_WAVE_CONFIG)
  420. ar & make_nvp("config", config);
  421. if (config != BOOST_PP_STRINGIZE(BOOST_WAVE_CONFIG)) {
  422. BOOST_WAVE_THROW_CTX((*this), preprocess_exception,
  423. incompatible_config, "BOOST_WAVE_CONFIG", get_main_pos());
  424. return;
  425. }
  426. // BOOST_WAVE_PRAGMA_KEYWORD
  427. ar & make_nvp("pragma_keyword", pragma_keyword);
  428. if (pragma_keyword != BOOST_WAVE_PRAGMA_KEYWORD) {
  429. BOOST_WAVE_THROW_CTX((*this), preprocess_exception,
  430. incompatible_config, "BOOST_WAVE_PRAGMA_KEYWORD",
  431. get_main_pos());
  432. return;
  433. }
  434. // BOOST_PP_STRINGIZE((BOOST_WAVE_STRINGTYPE))
  435. ar & make_nvp("string_type", string_type_str);
  436. if (string_type_str != BOOST_PP_STRINGIZE((BOOST_WAVE_STRINGTYPE))) {
  437. BOOST_WAVE_THROW_CTX((*this), preprocess_exception,
  438. incompatible_config, "BOOST_WAVE_STRINGTYPE", get_main_pos());
  439. return;
  440. }
  441. try {
  442. // read in the useful bits
  443. ar & make_nvp("language_options", language);
  444. ar & make_nvp("macro_definitions", macros);
  445. ar & make_nvp("include_settings", includes);
  446. }
  447. catch (boost::wave::preprocess_exception const& e) {
  448. // catch version mismatch exceptions and call error handler
  449. get_hooks().throw_exception(derived(), e);
  450. }
  451. }
  452. BOOST_SERIALIZATION_SPLIT_MEMBER()
  453. #endif
  454. private:
  455. // the main input stream
  456. target_iterator_type first; // underlying input stream
  457. target_iterator_type last;
  458. std::string filename; // associated main filename
  459. bool has_been_initialized; // set cwd once
  460. #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
  461. std::string current_filename; // real name of current preprocessed file
  462. #endif
  463. std::string current_relative_filename; // real relative name of current preprocessed file
  464. boost::wave::util::if_block_stack ifblocks; // conditional compilation contexts
  465. boost::wave::util::include_paths includes; // lists of include directories to search
  466. iteration_context_stack_type iter_ctxs; // iteration contexts
  467. macromap_type macros; // map of defined macros
  468. boost::wave::language_support language; // supported language/extensions
  469. hook_policy_type hooks; // hook policy instance
  470. };
  471. ///////////////////////////////////////////////////////////////////////////////
  472. } // namespace wave
  473. } // namespace boost
  474. #if BOOST_WAVE_SERIALIZATION != 0
  475. namespace boost { namespace serialization {
  476. template<
  477. typename Iterator, typename LexIterator,
  478. typename InputPolicy, typename Hooks
  479. >
  480. struct tracking_level<boost::wave::context<Iterator, LexIterator, InputPolicy, Hooks> >
  481. {
  482. typedef mpl::integral_c_tag tag;
  483. typedef mpl::int_<track_never> type;
  484. BOOST_STATIC_CONSTANT(
  485. int,
  486. value = tracking_level::type::value
  487. );
  488. };
  489. template<
  490. typename Iterator, typename LexIterator,
  491. typename InputPolicy, typename Hooks
  492. >
  493. struct version<boost::wave::context<Iterator, LexIterator, InputPolicy, Hooks> >
  494. {
  495. typedef boost::wave::context<Iterator, LexIterator, InputPolicy, Hooks>
  496. target_type;
  497. typedef mpl::int_<target_type::version> type;
  498. typedef mpl::integral_c_tag tag;
  499. BOOST_STATIC_CONSTANT(unsigned int, value = version::type::value);
  500. };
  501. }} // namespace boost::serialization
  502. #endif
  503. // the suffix header occurs after all of the code
  504. #ifdef BOOST_HAS_ABI_HEADERS
  505. #include BOOST_ABI_SUFFIX
  506. #endif
  507. #endif // !defined(BOOST_CPP_CONTEXT_HPP_907485E2_6649_4A87_911B_7F7225F3E5B8_INCLUDED)