1 /*=============================================================================
2 Boost.Wave: A Standard compliant C++ preprocessor library
6 Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
7 Software License, Version 1.0. (See accompanying file
8 LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 =============================================================================*/
11 #if !defined(INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED)
12 #define INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED
17 #include <boost/spirit/include/classic_core.hpp>
18 #include <boost/spirit/include/classic_assign_actor.hpp>
19 #include <boost/spirit/include/classic_push_back_actor.hpp>
20 #include <boost/spirit/include/classic_confix.hpp>
22 #include <boost/wave/wave_config.hpp>
24 #include <boost/wave/util/pattern_parser.hpp>
25 #include <boost/wave/util/macro_helpers.hpp>
27 #include <boost/wave/token_ids.hpp>
28 #include <boost/wave/cpp_exceptions.hpp>
29 #include <boost/wave/cpp_iteration_context.hpp>
30 #include <boost/wave/language_support.hpp>
32 #if !defined(spirit_append_actor)
33 #define spirit_append_actor(actor) boost::spirit::classic::push_back_a(actor)
34 #define spirit_assign_actor(actor) boost::spirit::classic::assign_a(actor)
35 #endif // !defined(spirit_append_actor)
37 // this must occur after all of the includes and before any code appears
38 #ifdef BOOST_HAS_ABI_HEADERS
39 #include BOOST_ABI_PREFIX
42 ///////////////////////////////////////////////////////////////////////////////
47 ///////////////////////////////////////////////////////////////////////////////
49 // The function interpret_pragma interprets the given token sequence as the
50 // body of a #pragma directive (or parameter to the _Pragma operator) and
51 // executes the actions associated with recognized Wave specific options.
53 ///////////////////////////////////////////////////////////////////////////////
54 template <typename ContextT, typename IteratorT, typename ContainerT>
56 interpret_pragma(ContextT &ctx, typename ContextT::token_type const &act_token,
57 IteratorT it, IteratorT const &end, ContainerT &pending)
59 typedef typename ContextT::token_type token_type;
60 typedef typename token_type::string_type string_type;
62 using namespace cpplexer;
63 if (T_IDENTIFIER == token_id(*it)) {
64 // check for pragma wave ...
65 if ((*it).get_value() == BOOST_WAVE_PRAGMA_KEYWORD)
67 // this is a wave specific option, it should have the form:
69 // #pragma command option(value)
72 // 'command' is the value of the preprocessor constant
73 // BOOST_WAVE_PRAGMA_KEYWORD (defaults to "wave") and
74 // '(value)' is required only for some pragma directives (this is
77 // All recognized #pragma operators are forwarded to the supplied
78 // preprocessing hook.
79 using namespace boost::spirit::classic;
83 if (!parse (++it, end,
86 spirit_assign_actor(option)
88 | pattern_p(KeywordTokenType,
89 TokenTypeMask|PPTokenFlag)
91 spirit_assign_actor(option)
93 | pattern_p(OperatorTokenType|AltExtTokenType,
94 ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc.
96 spirit_assign_actor(option)
98 | pattern_p(BoolLiteralTokenType,
99 TokenTypeMask|PPTokenFlag)
101 spirit_assign_actor(option)
107 )[spirit_assign_actor(values)],
108 pattern_p(WhiteSpaceTokenType, TokenTypeMask|PPTokenFlag)).hit)
110 typename ContextT::string_type msg(
111 impl::as_string<string_type>(it, end));
112 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
113 ill_formed_pragma_option,
114 msg.c_str(), act_token.get_position());
118 // remove the falsely matched surrounding parenthesis's
119 if (values.size() >= 2) {
120 BOOST_ASSERT(T_LEFTPAREN == values.front() && T_RIGHTPAREN == values.back());
121 values.erase(values.begin());
122 typename ContainerT::reverse_iterator rit = values.rbegin();
123 values.erase((++rit).base());
126 // decode the option (call the context_policy hook)
127 if (!ctx.get_hooks().interpret_pragma(
128 ctx.derived(), pending, option, values, act_token))
130 // unknown #pragma option
131 string_type option_str ((*it).get_value());
133 option_str += option.get_value();
134 if (values.size() > 0) {
136 option_str += impl::as_string(values);
139 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
140 ill_formed_pragma_option,
141 option_str.c_str(), act_token.get_position());
146 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
147 else if ((*it).get_value() == "once") {
149 return ctx.add_pragma_once_header(act_token, ctx.get_current_filename());
152 #if BOOST_WAVE_SUPPORT_PRAGMA_MESSAGE != 0
153 else if ((*it).get_value() == "message") {
154 // #pragma message(...) or #pragma message ...
155 using namespace boost::spirit::classic;
158 if (!parse (++it, end,
159 ( ( ch_p(T_LEFTPAREN)
161 *(anychar_p[spirit_append_actor(values)] - ch_p(T_RIGHTPAREN))
163 >> ch_p(T_RIGHTPAREN)
166 *(anychar_p[spirit_append_actor(values)] - ch_p(T_NEWLINE))
169 pattern_p(WhiteSpaceTokenType, TokenTypeMask|PPTokenFlag)
173 typename ContextT::string_type msg(
174 impl::as_string<string_type>(it, end));
175 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
176 ill_formed_pragma_message,
177 msg.c_str(), act_token.get_position());
181 // remove the falsely matched closing parenthesis/newline
182 if (values.size() > 0) {
183 BOOST_ASSERT(T_RIGHTPAREN == values.back() || T_NEWLINE == values.back());
184 typename ContainerT::reverse_iterator rit = values.rbegin();
185 values.erase((++rit).base());
188 // output the message itself
189 typename ContextT::string_type msg(impl::as_string(values));
190 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
191 pragma_message_directive,
192 msg.c_str(), act_token.get_position());
200 ///////////////////////////////////////////////////////////////////////////////
205 // the suffix header occurs after all of the code
206 #ifdef BOOST_HAS_ABI_HEADERS
207 #include BOOST_ABI_SUFFIX
210 #endif // !defined(INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED)