cpp_context.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  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(CPP_CONTEXT_HPP_907485E2_6649_4A87_911B_7F7225F3E5B8_INCLUDED)
  10. #define 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. #endif
  284. // make sure the context has been initialized
  285. void init_context()
  286. {
  287. if (!has_been_initialized) {
  288. std::string fname(filename);
  289. if (filename != "<Unknown>" && filename != "<stdin>") {
  290. using namespace boost::filesystem;
  291. path fpath(util::complete_path(path(filename)));
  292. fname = fpath.string();
  293. includes.set_current_directory(fname.c_str());
  294. }
  295. has_been_initialized = true; // execute once
  296. }
  297. }
  298. template <typename IteratorT2>
  299. bool is_defined_macro(IteratorT2 const &begin, IteratorT2 const &end) const
  300. { return macros.is_defined(begin, end); }
  301. // maintain include paths (helper functions)
  302. void set_current_directory(char const *path_)
  303. { includes.set_current_directory(path_); }
  304. // conditional compilation contexts
  305. bool get_if_block_status() const { return ifblocks.get_status(); }
  306. bool get_if_block_some_part_status() const
  307. { return ifblocks.get_some_part_status(); }
  308. bool get_enclosing_if_block_status() const
  309. { return ifblocks.get_enclosing_status(); }
  310. void enter_if_block(bool new_status)
  311. { ifblocks.enter_if_block(new_status); }
  312. bool enter_elif_block(bool new_status)
  313. { return ifblocks.enter_elif_block(new_status); }
  314. bool enter_else_block() { return ifblocks.enter_else_block(); }
  315. bool exit_if_block() { return ifblocks.exit_if_block(); }
  316. typename boost::wave::util::if_block_stack::size_type get_if_block_depth() const
  317. { return ifblocks.get_if_block_depth(); }
  318. // stack of iteration contexts
  319. iteration_ptr_type pop_iteration_context()
  320. { iteration_ptr_type top = iter_ctxs.top(); iter_ctxs.pop(); return top; }
  321. void push_iteration_context(position_type const &act_pos, iteration_ptr_type iter_ctx)
  322. { iter_ctxs.push(*this, act_pos, iter_ctx); }
  323. ///////////////////////////////////////////////////////////////////////////////
  324. //
  325. // expand_tokensequence():
  326. // expands all macros contained in a given token sequence, handles '##'
  327. // and '#' pp operators and re-scans the resulting sequence
  328. // (essentially pre-processes the token sequence).
  329. //
  330. // The expand_undefined parameter is true during macro expansion inside
  331. // a C++ expression given for a #if or #elif statement.
  332. //
  333. ///////////////////////////////////////////////////////////////////////////////
  334. template <typename IteratorT2>
  335. token_type expand_tokensequence(IteratorT2 &first_, IteratorT2 const &last_,
  336. token_sequence_type &pending, token_sequence_type &expanded,
  337. bool& seen_newline, bool expand_undefined = false)
  338. {
  339. return macros.expand_tokensequence(first_, last_, pending, expanded,
  340. seen_newline, expand_undefined);
  341. }
  342. template <typename IteratorT2>
  343. void expand_whole_tokensequence(IteratorT2 &first_, IteratorT2 const &last_,
  344. token_sequence_type &expanded, bool expand_undefined = true)
  345. {
  346. macros.expand_whole_tokensequence(expanded, first_, last_,
  347. expand_undefined);
  348. // remove any contained placeholder
  349. boost::wave::util::impl::remove_placeholders(expanded);
  350. }
  351. public:
  352. #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
  353. // support for #pragma once
  354. // maintain the real name of the current preprocessed file
  355. void set_current_filename(char const *real_name)
  356. { current_filename = real_name; }
  357. std::string const &get_current_filename() const
  358. { return current_filename; }
  359. // maintain the list of known headers containing #pragma once
  360. bool has_pragma_once(std::string const &filename_)
  361. { return includes.has_pragma_once(filename_); }
  362. bool add_pragma_once_header(std::string const &filename_,
  363. std::string const& guard_name)
  364. {
  365. get_hooks().detected_include_guard(derived(), filename_, guard_name);
  366. return includes.add_pragma_once_header(filename_, guard_name);
  367. }
  368. bool add_pragma_once_header(token_type const &pragma_,
  369. std::string const &filename_)
  370. {
  371. get_hooks().detected_pragma_once(derived(), pragma_, filename_);
  372. return includes.add_pragma_once_header(filename_,
  373. "__BOOST_WAVE_PRAGMA_ONCE__");
  374. }
  375. #endif
  376. void set_current_relative_filename(char const *real_name)
  377. { current_relative_filename = real_name; }
  378. std::string const &get_current_relative_filename() const
  379. { return current_relative_filename; }
  380. bool find_include_file (std::string &s, std::string &d, bool is_system,
  381. char const *current_file) const
  382. { return includes.find_include_file(s, d, is_system, current_file); }
  383. #if BOOST_WAVE_SERIALIZATION != 0
  384. public:
  385. BOOST_STATIC_CONSTANT(unsigned int, version = 0x10);
  386. BOOST_STATIC_CONSTANT(unsigned int, version_mask = 0x0f);
  387. private:
  388. friend class boost::serialization::access;
  389. template<class Archive>
  390. void save(Archive & ar, const unsigned int version) const
  391. {
  392. using namespace boost::serialization;
  393. string_type cfg(BOOST_PP_STRINGIZE(BOOST_WAVE_CONFIG));
  394. string_type kwd(BOOST_WAVE_PRAGMA_KEYWORD);
  395. string_type strtype(BOOST_PP_STRINGIZE((BOOST_WAVE_STRINGTYPE)));
  396. ar & make_nvp("config", cfg);
  397. ar & make_nvp("pragma_keyword", kwd);
  398. ar & make_nvp("string_type", strtype);
  399. ar & make_nvp("language_options", language);
  400. ar & make_nvp("macro_definitions", macros);
  401. ar & make_nvp("include_settings", includes);
  402. }
  403. template<class Archive>
  404. void load(Archive & ar, const unsigned int loaded_version)
  405. {
  406. using namespace boost::serialization;
  407. if (version != (loaded_version & ~version_mask)) {
  408. BOOST_WAVE_THROW_CTX((*this), preprocess_exception,
  409. incompatible_config, "cpp_context state version",
  410. get_main_pos());
  411. return;
  412. }
  413. // check compatibility of the stored information
  414. string_type config, pragma_keyword, string_type_str;
  415. // BOOST_PP_STRINGIZE(BOOST_WAVE_CONFIG)
  416. ar & make_nvp("config", config);
  417. if (config != BOOST_PP_STRINGIZE(BOOST_WAVE_CONFIG)) {
  418. BOOST_WAVE_THROW_CTX((*this), preprocess_exception,
  419. incompatible_config, "BOOST_WAVE_CONFIG", get_main_pos());
  420. return;
  421. }
  422. // BOOST_WAVE_PRAGMA_KEYWORD
  423. ar & make_nvp("pragma_keyword", pragma_keyword);
  424. if (pragma_keyword != BOOST_WAVE_PRAGMA_KEYWORD) {
  425. BOOST_WAVE_THROW_CTX((*this), preprocess_exception,
  426. incompatible_config, "BOOST_WAVE_PRAGMA_KEYWORD",
  427. get_main_pos());
  428. return;
  429. }
  430. // BOOST_PP_STRINGIZE((BOOST_WAVE_STRINGTYPE))
  431. ar & make_nvp("string_type", string_type_str);
  432. if (string_type_str != BOOST_PP_STRINGIZE((BOOST_WAVE_STRINGTYPE))) {
  433. BOOST_WAVE_THROW_CTX((*this), preprocess_exception,
  434. incompatible_config, "BOOST_WAVE_STRINGTYPE", get_main_pos());
  435. return;
  436. }
  437. try {
  438. // read in the useful bits
  439. ar & make_nvp("language_options", language);
  440. ar & make_nvp("macro_definitions", macros);
  441. ar & make_nvp("include_settings", includes);
  442. }
  443. catch (boost::wave::preprocess_exception const& e) {
  444. // catch version mismatch exceptions and call error handler
  445. get_hooks().throw_exception(derived(), e);
  446. }
  447. }
  448. BOOST_SERIALIZATION_SPLIT_MEMBER()
  449. #endif
  450. private:
  451. // the main input stream
  452. target_iterator_type first; // underlying input stream
  453. target_iterator_type last;
  454. std::string filename; // associated main filename
  455. bool has_been_initialized; // set cwd once
  456. #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
  457. std::string current_filename; // real name of current preprocessed file
  458. #endif
  459. std::string current_relative_filename; // real relative name of current preprocessed file
  460. boost::wave::util::if_block_stack ifblocks; // conditional compilation contexts
  461. boost::wave::util::include_paths includes; // lists of include directories to search
  462. iteration_context_stack_type iter_ctxs; // iteration contexts
  463. macromap_type macros; // map of defined macros
  464. boost::wave::language_support language; // supported language/extensions
  465. hook_policy_type hooks; // hook policy instance
  466. };
  467. ///////////////////////////////////////////////////////////////////////////////
  468. } // namespace wave
  469. } // namespace boost
  470. #if BOOST_WAVE_SERIALIZATION != 0
  471. namespace boost { namespace serialization {
  472. template<
  473. typename Iterator, typename LexIterator,
  474. typename InputPolicy, typename Hooks
  475. >
  476. struct tracking_level<boost::wave::context<Iterator, LexIterator, InputPolicy, Hooks> >
  477. {
  478. typedef mpl::integral_c_tag tag;
  479. typedef mpl::int_<track_never> type;
  480. BOOST_STATIC_CONSTANT(
  481. int,
  482. value = tracking_level::type::value
  483. );
  484. };
  485. template<
  486. typename Iterator, typename LexIterator,
  487. typename InputPolicy, typename Hooks
  488. >
  489. struct version<boost::wave::context<Iterator, LexIterator, InputPolicy, Hooks> >
  490. {
  491. typedef boost::wave::context<Iterator, LexIterator, InputPolicy, Hooks>
  492. target_type;
  493. typedef mpl::int_<target_type::version> type;
  494. typedef mpl::integral_c_tag tag;
  495. BOOST_STATIC_CONSTANT(unsigned int, value = version::type::value);
  496. };
  497. }} // namespace boost::serialization
  498. #endif
  499. // the suffix header occurs after all of the code
  500. #ifdef BOOST_HAS_ABI_HEADERS
  501. #include BOOST_ABI_SUFFIX
  502. #endif
  503. #endif // !defined(CPP_CONTEXT_HPP_907485E2_6649_4A87_911B_7F7225F3E5B8_INCLUDED)