Line data Source code
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(INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED) 12 : #define 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 56 0 : 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 0 : if (T_IDENTIFIER == token_id(*it)) { 64 : // check for pragma wave ... 65 0 : 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 0 : token_type option; 81 0 : ContainerT values; 82 : 83 0 : if (!parse (++it, end, 84 0 : ( ch_p(T_IDENTIFIER) 85 0 : [ 86 0 : spirit_assign_actor(option) 87 : ] 88 0 : | pattern_p(KeywordTokenType, 89 : TokenTypeMask|PPTokenFlag) 90 0 : [ 91 0 : spirit_assign_actor(option) 92 : ] 93 0 : | pattern_p(OperatorTokenType|AltExtTokenType, 94 : ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc. 95 0 : [ 96 0 : spirit_assign_actor(option) 97 : ] 98 0 : | pattern_p(BoolLiteralTokenType, 99 : TokenTypeMask|PPTokenFlag) 100 0 : [ 101 0 : spirit_assign_actor(option) 102 : ] 103 : ) 104 0 : >> !comment_nest_p( 105 0 : ch_p(T_LEFTPAREN), 106 0 : ch_p(T_RIGHTPAREN) 107 0 : )[spirit_assign_actor(values)], 108 0 : pattern_p(WhiteSpaceTokenType, TokenTypeMask|PPTokenFlag)).hit) 109 : { 110 0 : typename ContextT::string_type msg( 111 : impl::as_string<string_type>(it, end)); 112 0 : BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, 113 : ill_formed_pragma_option, 114 : msg.c_str(), act_token.get_position()); 115 0 : return false; 116 : } 117 : 118 : // remove the falsely matched surrounding parenthesis's 119 0 : if (values.size() >= 2) { 120 0 : BOOST_ASSERT(T_LEFTPAREN == values.front() && T_RIGHTPAREN == values.back()); 121 0 : values.erase(values.begin()); 122 0 : typename ContainerT::reverse_iterator rit = values.rbegin(); 123 0 : values.erase((++rit).base()); 124 : } 125 : 126 : // decode the option (call the context_policy hook) 127 0 : if (!ctx.get_hooks().interpret_pragma( 128 : ctx.derived(), pending, option, values, act_token)) 129 : { 130 : // unknown #pragma option 131 0 : string_type option_str ((*it).get_value()); 132 : 133 0 : option_str += option.get_value(); 134 0 : if (values.size() > 0) { 135 0 : option_str += "("; 136 0 : option_str += impl::as_string(values); 137 0 : option_str += ")"; 138 : } 139 0 : BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, 140 : ill_formed_pragma_option, 141 : option_str.c_str(), act_token.get_position()); 142 0 : return false; 143 : } 144 : return true; 145 : } 146 : #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 147 0 : else if ((*it).get_value() == "once") { 148 : // #pragma once 149 0 : return ctx.add_pragma_once_header(act_token, ctx.get_current_filename()); 150 : } 151 : #endif 152 : #if BOOST_WAVE_SUPPORT_PRAGMA_MESSAGE != 0 153 0 : else if ((*it).get_value() == "message") { 154 : // #pragma message(...) or #pragma message ... 155 : using namespace boost::spirit::classic; 156 0 : ContainerT values; 157 : 158 0 : if (!parse (++it, end, 159 0 : ( ( ch_p(T_LEFTPAREN) 160 0 : >> lexeme_d[ 161 0 : *(anychar_p[spirit_append_actor(values)] - ch_p(T_RIGHTPAREN)) 162 : ] 163 0 : >> ch_p(T_RIGHTPAREN) 164 : ) 165 0 : | lexeme_d[ 166 0 : *(anychar_p[spirit_append_actor(values)] - ch_p(T_NEWLINE)) 167 : ] 168 : ), 169 0 : pattern_p(WhiteSpaceTokenType, TokenTypeMask|PPTokenFlag) 170 0 : ).hit 171 : ) 172 : { 173 0 : typename ContextT::string_type msg( 174 : impl::as_string<string_type>(it, end)); 175 0 : BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, 176 : ill_formed_pragma_message, 177 : msg.c_str(), act_token.get_position()); 178 0 : return false; 179 : } 180 : 181 : // remove the falsely matched closing parenthesis/newline 182 0 : if (values.size() > 0) { 183 0 : BOOST_ASSERT(T_RIGHTPAREN == values.back() || T_NEWLINE == values.back()); 184 0 : typename ContainerT::reverse_iterator rit = values.rbegin(); 185 0 : values.erase((++rit).base()); 186 : } 187 : 188 : // output the message itself 189 0 : typename ContextT::string_type msg(impl::as_string(values)); 190 0 : BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, 191 : pragma_message_directive, 192 : msg.c_str(), act_token.get_position()); 193 0 : 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(INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED)