Update contrib.
1 /*=============================================================================
2 Boost.Wave: A Standard compliant C++ preprocessor library
3 Definition of the preprocessor context
7 Copyright (c) 2001-2007 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 =============================================================================*/
12 #if !defined(CPP_CONTEXT_HPP_907485E2_6649_4A87_911B_7F7225F3E5B8_INCLUDED)
13 #define CPP_CONTEXT_HPP_907485E2_6649_4A87_911B_7F7225F3E5B8_INCLUDED
19 #include <boost/concept_check.hpp>
20 #include <boost/noncopyable.hpp>
21 #include <boost/filesystem/path.hpp>
23 #include <boost/wave/wave_config.hpp>
24 #if BOOST_WAVE_SERIALIZATION != 0
25 #include <boost/serialization/serialization.hpp>
26 #include <boost/wave/wave_config_constant.hpp>
28 #include <boost/wave/token_ids.hpp>
30 #include <boost/wave/util/unput_queue_iterator.hpp>
31 #include <boost/wave/util/cpp_ifblock.hpp>
32 #include <boost/wave/util/cpp_include_paths.hpp>
33 #include <boost/wave/util/iteration_context.hpp>
34 #include <boost/wave/util/cpp_iterator.hpp>
35 #include <boost/wave/util/cpp_macromap.hpp>
37 #include <boost/wave/preprocessing_hooks.hpp>
38 #include <boost/wave/whitespace_handling.hpp>
39 #include <boost/wave/cpp_iteration_context.hpp>
40 #include <boost/wave/language_support.hpp>
42 // this must occur after all of the includes and before any code appears
43 #ifdef BOOST_HAS_ABI_HEADERS
44 #include BOOST_ABI_PREFIX
47 ///////////////////////////////////////////////////////////////////////////////
51 ///////////////////////////////////////////////////////////////////////////////
53 // The C preprocessor context template class
55 // The boost::wave::context template is the main interface class to
56 // control the behaviour of the preprocessing engine.
58 // The following template parameters has to be supplied:
60 // IteratorT The iterator type of the underlying input stream
61 // LexIteratorT The lexer iterator type to use as the token factory
62 // InputPolicyT The input policy type to use for loading the files
63 // to be included. This template parameter is optional and
65 // iteration_context_policies::load_file_to_string
67 // HooksT The hooks policy to use for different notification
68 // callbacks. This template parameter is optional and
70 // context_policies::default_preprocessing_hooks
73 ///////////////////////////////////////////////////////////////////////////////
77 typename LexIteratorT,
78 typename InputPolicyT = iteration_context_policies::load_file_to_string,
79 typename HooksT = context_policies::eat_whitespace<typename LexIteratorT::token_type>
81 class context : private boost::noncopyable
86 // the given iterator shall be at least a forward iterator type
87 BOOST_CLASS_REQUIRE(IteratorT, boost, ForwardIteratorConcept);
90 typedef typename LexIteratorT::token_type token_type;
91 typedef context<IteratorT, LexIteratorT, InputPolicyT, HooksT>
94 typedef IteratorT target_iterator_type;
95 typedef LexIteratorT lexer_type;
96 typedef pp_iterator<self_type> iterator_type;
98 typedef InputPolicyT input_policy_type;
99 typedef typename token_type::position_type position_type;
102 // type of a token sequence
103 typedef std::list<token_type, boost::fast_pool_allocator<token_type> >
105 // types of the policies
106 typedef HooksT hook_policy_type;
109 // stack of shared_ptr's to the pending iteration contexts
110 typedef boost::shared_ptr<base_iteration_context<lexer_type> >
112 typedef boost::wave::util::iteration_context_stack<iteration_ptr_type>
113 iteration_context_stack_type;
114 typedef typename iteration_context_stack_type::size_type iter_size_type;
116 context *this_() { return this; } // avoid warning in constructor
119 context(target_iterator_type const &first_, target_iterator_type const &last_,
120 char const *fname = "<Unknown>", HooksT const &hooks_ = HooksT())
121 : first(first_), last(last_), filename(fname)
122 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
123 , current_filename(fname)
126 , language(language_support(
128 | support_option_convert_trigraphs
129 | support_option_emit_line_directives
130 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
131 | support_option_include_guard_detection
136 macros.init_predefined_macros(fname);
137 includes.init_initial_path();
140 // default copy constructor
141 // default assignment operator
142 // default destructor
144 // iterator interface
145 iterator_type begin()
147 std::string fname(filename);
148 if (filename != "<Unknown>" && filename != "<stdin>") {
149 using namespace boost::filesystem;
150 path fpath(complete(path(filename)));
151 fname = fpath.string();
152 includes.set_current_directory(fname.c_str());
154 return iterator_type(*this, first, last, position_type(fname.c_str()));
157 target_iterator_type const &first_,
158 target_iterator_type const &last_)
160 std::string fname(filename);
161 if (filename != "<Unknown>" && filename != "<stdin>") {
162 using namespace boost::filesystem;
163 path fpath(complete(path(filename)));
164 fname = fpath.string();
165 includes.set_current_directory(fname.c_str());
167 return iterator_type(*this, first_, last_, position_type(fname.c_str()));
169 iterator_type end() const
170 { return iterator_type(); }
172 // maintain include paths
173 bool add_include_path(char const *path_)
174 { return includes.add_include_path(path_, false);}
175 bool add_sysinclude_path(char const *path_)
176 { return includes.add_include_path(path_, true);}
177 void set_sysinclude_delimiter() { includes.set_sys_include_delimiter(); }
178 typename iteration_context_stack_type::size_type get_iteration_depth() const
179 { return iter_ctxs.size(); }
181 // maintain defined macros
182 #if BOOST_WAVE_ENABLE_COMMANDLINE_MACROS != 0
183 bool add_macro_definition(std::string macrostring,
184 bool is_predefined = false)
185 { return boost::wave::util::add_macro_definition(*this, macrostring,
186 is_predefined, get_language()); }
188 bool add_macro_definition(token_type const &name, bool has_params,
189 std::vector<token_type> ¶meters, token_sequence_type &definition,
190 bool is_predefined = false)
191 { return macros.add_macro(name, has_params, parameters, definition,
193 template <typename IteratorT2>
194 bool is_defined_macro(IteratorT2 const &begin, IteratorT2 const &end)
195 { return macros.is_defined(begin, end); }
196 bool get_macro_definition(typename token_type::string_type const &name,
197 bool &has_params, bool &is_predefined, position_type &pos,
198 std::vector<token_type> ¶meters, token_sequence_type &definition)
200 return macros.get_macro(name, has_params, is_predefined, pos,
201 parameters, definition);
203 bool remove_macro_definition(typename token_type::string_type const &name,
204 bool even_predefined = false)
206 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
207 // ensure this gets remove from the list of include guards as well
208 includes.remove_pragma_once_header(std::string(name.c_str()));
210 return macros.remove_macro(
211 token_type(T_IDENTIFIER, name, macros.get_main_pos()),
214 void reset_macro_definitions()
215 { macros.reset_macromap(); macros.init_predefined_macros(); }
217 // get the Wave version information
218 static std::string get_version()
219 { return boost::wave::util::predefined_macros::get_fullversion(false); }
220 static std::string get_version_string()
221 { return boost::wave::util::predefined_macros::get_versionstr(false); }
223 // access current language options
224 void set_language(boost::wave::language_support language_,
225 bool reset_macros = true)
227 language = language_;
229 reset_macro_definitions();
231 boost::wave::language_support get_language() const { return language; }
233 // change and ask for maximal possible include nesting depth
234 void set_max_include_nesting_depth(iter_size_type new_depth)
235 { iter_ctxs.set_max_include_nesting_depth(new_depth); }
236 iter_size_type get_max_include_nesting_depth() const
237 { return iter_ctxs.get_max_include_nesting_depth(); }
239 // access the policies
240 hook_policy_type &get_hooks() { return hooks; }
242 // return the directory of the currently preprocessed file
243 boost::filesystem::path get_current_directory() const
244 { return includes.get_current_directory(); }
246 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
248 friend class boost::wave::pp_iterator<
249 boost::wave::context<IteratorT, lexer_type, InputPolicyT, HooksT> >;
250 friend class boost::wave::impl::pp_iterator_functor<
251 boost::wave::context<IteratorT, lexer_type, InputPolicyT, HooksT> >;
254 // maintain include paths (helper functions)
255 bool find_include_file (std::string &s, std::string &d, bool is_system,
256 char const *current_file) const
257 { return includes.find_include_file(s, d, is_system, current_file); }
258 void set_current_directory(char const *path_)
259 { includes.set_current_directory(path_); }
261 // conditional compilation contexts
262 bool get_if_block_status() const { return ifblocks.get_status(); }
263 bool get_if_block_some_part_status() const
264 { return ifblocks.get_some_part_status(); }
265 bool get_enclosing_if_block_status() const
266 { return ifblocks.get_enclosing_status(); }
267 void enter_if_block(bool new_status)
268 { ifblocks.enter_if_block(new_status); }
269 bool enter_elif_block(bool new_status)
270 { return ifblocks.enter_elif_block(new_status); }
271 bool enter_else_block() { return ifblocks.enter_else_block(); }
272 bool exit_if_block() { return ifblocks.exit_if_block(); }
273 typename boost::wave::util::if_block_stack::size_type get_if_block_depth() const
274 { return ifblocks.get_if_block_depth(); }
276 // stack of iteration contexts
277 iteration_ptr_type pop_iteration_context()
278 { iteration_ptr_type top = iter_ctxs.top(); iter_ctxs.pop(); return top; }
279 void push_iteration_context(position_type const &act_pos, iteration_ptr_type iter_ctx)
280 { iter_ctxs.push(act_pos, iter_ctx); }
282 position_type &get_main_pos() { return macros.get_main_pos(); }
284 ///////////////////////////////////////////////////////////////////////////////
286 // expand_tokensequence():
287 // expands all macros contained in a given token sequence, handles '##'
288 // and '#' pp operators and re-scans the resulting sequence
289 // (essentially pre-processes the token sequence).
291 // The expand_undefined parameter is true during macro expansion inside
292 // a C++ expression given for a #if or #elif statement.
294 ///////////////////////////////////////////////////////////////////////////////
295 template <typename IteratorT2>
296 token_type expand_tokensequence(IteratorT2 &first_, IteratorT2 const &last_,
297 token_sequence_type &pending, token_sequence_type &expanded,
298 bool expand_undefined = false)
300 return macros.expand_tokensequence(first_, last_, pending, expanded,
304 template <typename IteratorT2>
305 void expand_whole_tokensequence(IteratorT2 &first_, IteratorT2 const &last_,
306 token_sequence_type &expanded, bool expand_undefined = true)
308 macros.expand_whole_tokensequence(expanded, first_, last_,
311 // remove any contained placeholder
312 boost::wave::util::impl::remove_placeholders(expanded);
316 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
317 // support for #pragma once
318 // maintain the real name of the current preprocessed file
319 void set_current_filename(char const *real_name)
320 { current_filename = real_name; }
321 std::string const &get_current_filename() const
322 { return current_filename; }
324 // maintain the list of known headers containing #pragma once
325 bool has_pragma_once(std::string const &filename_)
326 { return includes.has_pragma_once(filename_); }
327 bool add_pragma_once_header(std::string const &filename_,
328 std::string const& guard_name = "__BOOST_WAVE_PRAGMA_ONCE__")
329 { return includes.add_pragma_once_header(filename_, guard_name); }
332 // forwarding functions for the context policy hooks
333 template <typename ContainerT>
334 bool interpret_pragma(ContainerT &pending, token_type const &option,
335 ContainerT const &values, token_type const &act_token)
337 return hooks.interpret_pragma(*this, pending, option, values, act_token);
340 #if BOOST_WAVE_SERIALIZATION != 0
342 BOOST_STATIC_CONSTANT(unsigned int, version = 0x10);
343 BOOST_STATIC_CONSTANT(unsigned int, version_mask = 0x0f);
346 friend class boost::serialization::access;
347 template<class Archive>
348 void save(Archive & ar, const unsigned int version) const
350 typedef typename token_type::string_type string_type;
352 string_type cfg(BOOST_PP_STRINGIZE(BOOST_WAVE_CONFIG));
353 string_type kwd(BOOST_WAVE_PRAGMA_KEYWORD);
354 string_type strtype(BOOST_PP_STRINGIZE((BOOST_WAVE_STRINGTYPE)));
363 template<class Archive>
364 void load(Archive & ar, const unsigned int loaded_version)
366 if (version != (loaded_version & ~version_mask)) {
367 BOOST_WAVE_THROW(preprocess_exception, incompatible_config,
368 "cpp_context state version", get_main_pos());
371 // check compatibility of the stored information
372 typedef typename token_type::string_type string_type;
373 string_type config, pragma_keyword, string_type_str;
375 ar & config; // BOOST_WAVE_CONFIG
376 if (config != BOOST_PP_STRINGIZE(BOOST_WAVE_CONFIG)) {
377 BOOST_WAVE_THROW(preprocess_exception, incompatible_config,
378 "BOOST_WAVE_CONFIG", get_main_pos());
381 ar & pragma_keyword; // BOOST_WAVE_PRAGMA_KEYWORD
382 if (pragma_keyword != BOOST_WAVE_PRAGMA_KEYWORD) {
383 BOOST_WAVE_THROW(preprocess_exception, incompatible_config,
384 "BOOST_WAVE_PRAGMA_KEYWORD", get_main_pos());
387 ar & string_type_str; // BOOST_PP_STRINGIZE((BOOST_WAVE_STRINGTYPE))
388 if (string_type_str != BOOST_PP_STRINGIZE((BOOST_WAVE_STRINGTYPE))) {
389 BOOST_WAVE_THROW(preprocess_exception, incompatible_config,
390 "BOOST_WAVE_STRINGTYPE", get_main_pos());
393 // read in the useful bits
398 BOOST_SERIALIZATION_SPLIT_MEMBER()
402 // the main input stream
403 target_iterator_type first; // underlying input stream
404 target_iterator_type last;
405 std::string filename; // associated main filename
406 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
407 std::string current_filename; // real name of current preprocessed file
410 boost::wave::util::if_block_stack ifblocks; // conditional compilation contexts
411 boost::wave::util::include_paths includes; // lists of include directories to search
412 iteration_context_stack_type iter_ctxs; // iteration contexts
413 boost::wave::util::macromap<self_type> macros; // map of defined macros
414 boost::wave::language_support language; // supported language/extensions
415 hook_policy_type hooks; // hook policy instance
418 ///////////////////////////////////////////////////////////////////////////////
422 #if BOOST_WAVE_SERIALIZATION != 0
423 namespace boost { namespace serialization {
426 typename Iterator, typename LexIterator,
427 typename InputPolicy, typename Hooks
429 struct tracking_level<boost::wave::context<Iterator, LexIterator, InputPolicy, Hooks> >
431 typedef mpl::integral_c_tag tag;
432 typedef mpl::int_<track_never> type;
433 BOOST_STATIC_CONSTANT(
435 value = tracking_level::type::value
440 typename Iterator, typename LexIterator,
441 typename InputPolicy, typename Hooks
443 struct version<boost::wave::context<Iterator, LexIterator, InputPolicy, Hooks> >
445 typedef boost::wave::context<Iterator, LexIterator, InputPolicy, Hooks>
447 typedef mpl::int_<target_type::version> type;
448 typedef mpl::integral_c_tag tag;
449 BOOST_STATIC_CONSTANT(unsigned int, value = version::type::value);
452 }} // namespace boost::serialization
455 // the suffix header occurs after all of the code
456 #ifdef BOOST_HAS_ABI_HEADERS
457 #include BOOST_ABI_SUFFIX
460 #endif // !defined(CPP_CONTEXT_HPP_907485E2_6649_4A87_911B_7F7225F3E5B8_INCLUDED)