• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Boost.Wave: A Standard compliant C++ preprocessor library
3 
4     http://www.boost.org/
5 
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 =============================================================================*/
10 
11 #if !defined(BOOST_INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED)
12 #define BOOST_INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED
13 
14 #include <string>
15 #include <list>
16 
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>
21 
22 #include <boost/wave/wave_config.hpp>
23 
24 #include <boost/wave/util/pattern_parser.hpp>
25 #include <boost/wave/util/macro_helpers.hpp>
26 
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>
31 
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)
36 
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
40 #endif
41 
42 ///////////////////////////////////////////////////////////////////////////////
43 namespace boost {
44 namespace wave {
45 namespace util {
46 
47 ///////////////////////////////////////////////////////////////////////////////
48 //
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.
52 //
53 ///////////////////////////////////////////////////////////////////////////////
54 template <typename ContextT, typename IteratorT, typename ContainerT>
55 inline bool
interpret_pragma(ContextT & ctx,typename ContextT::token_type const & act_token,IteratorT it,IteratorT const & end,ContainerT & pending)56 interpret_pragma(ContextT &ctx, typename ContextT::token_type const &act_token,
57     IteratorT it, IteratorT const &end, ContainerT &pending)
58 {
59     typedef typename ContextT::token_type token_type;
60     typedef typename token_type::string_type string_type;
61 
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)
66         {
67         //  this is a wave specific option, it should have the form:
68         //
69         //      #pragma command option(value)
70         //
71         //  where
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
75         //                optional)
76         //
77         //  All recognized #pragma operators are forwarded to the supplied
78         //  preprocessing hook.
79             using namespace boost::spirit::classic;
80             token_type option;
81             ContainerT values;
82 
83             if (!parse (++it, end,
84                             (   ch_p(T_IDENTIFIER)
85                                 [
86                                     spirit_assign_actor(option)
87                                 ]
88                             |   pattern_p(KeywordTokenType,
89                                     TokenTypeMask|PPTokenFlag)
90                                 [
91                                     spirit_assign_actor(option)
92                                 ]
93                             |   pattern_p(OperatorTokenType|AltExtTokenType,
94                                     ExtTokenTypeMask|PPTokenFlag)   // and, bit_and etc.
95                                 [
96                                     spirit_assign_actor(option)
97                                 ]
98                             |   pattern_p(BoolLiteralTokenType,
99                                     TokenTypeMask|PPTokenFlag)
100                                 [
101                                     spirit_assign_actor(option)
102                                 ]
103                             )
104                         >> !comment_nest_p(
105                                 ch_p(T_LEFTPAREN),
106                                 ch_p(T_RIGHTPAREN)
107                             )[spirit_assign_actor(values)],
108                     pattern_p(WhiteSpaceTokenType, TokenTypeMask|PPTokenFlag)).hit)
109             {
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());
115                 return false;
116             }
117 
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());
124             }
125 
126         // decode the option (call the context_policy hook)
127             if (!ctx.get_hooks().interpret_pragma(
128                   ctx.derived(), pending, option, values, act_token))
129             {
130             // unknown #pragma option
131             string_type option_str ((*it).get_value());
132 
133                 option_str += option.get_value();
134                 if (values.size() > 0) {
135                     option_str += "(";
136                     option_str += impl::as_string(values);
137                     option_str += ")";
138                 }
139                 BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
140                     ill_formed_pragma_option,
141                     option_str.c_str(), act_token.get_position());
142                 return false;
143             }
144             return true;
145         }
146 #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
147         else if ((*it).get_value() == "once") {
148         // #pragma once
149             return ctx.add_pragma_once_header(act_token, ctx.get_current_filename());
150         }
151 #endif
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;
156             ContainerT values;
157 
158             if (!parse (++it, end,
159                             (   (   ch_p(T_LEFTPAREN)
160                                 >>  lexeme_d[
161                                         *(anychar_p[spirit_append_actor(values)] - ch_p(T_RIGHTPAREN))
162                                     ]
163                                 >>  ch_p(T_RIGHTPAREN)
164                                 )
165                             |   lexeme_d[
166                                     *(anychar_p[spirit_append_actor(values)] - ch_p(T_NEWLINE))
167                                 ]
168                             ),
169                             pattern_p(WhiteSpaceTokenType, TokenTypeMask|PPTokenFlag)
170                        ).hit
171                )
172             {
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());
178                 return false;
179             }
180 
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());
186             }
187 
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());
193             return false;
194         }
195 #endif
196     }
197     return false;
198 }
199 
200 ///////////////////////////////////////////////////////////////////////////////
201 }   // namespace util
202 }   // namespace wave
203 }   // namespace boost
204 
205 // the suffix header occurs after all of the code
206 #ifdef BOOST_HAS_ABI_HEADERS
207 #include BOOST_ABI_SUFFIX
208 #endif
209 
210 #endif // !defined(BOOST_INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED)
211