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