/*============================================================================= | |
Boost.Wave: A Standard compliant C++ preprocessor library | |
http://www.boost.org/ | |
Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost | |
Software License, Version 1.0. (See accompanying file | |
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
=============================================================================*/ | |
#if !defined(INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED) | |
#define INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED | |
#include <string> | |
#include <list> | |
#include <boost/spirit/include/classic_core.hpp> | |
#include <boost/spirit/include/classic_assign_actor.hpp> | |
#include <boost/spirit/include/classic_push_back_actor.hpp> | |
#include <boost/spirit/include/classic_confix.hpp> | |
#include <boost/wave/wave_config.hpp> | |
#include <boost/wave/util/pattern_parser.hpp> | |
#include <boost/wave/util/macro_helpers.hpp> | |
#include <boost/wave/token_ids.hpp> | |
#include <boost/wave/cpp_exceptions.hpp> | |
#include <boost/wave/cpp_iteration_context.hpp> | |
#include <boost/wave/language_support.hpp> | |
#if !defined(spirit_append_actor) | |
#define spirit_append_actor(actor) boost::spirit::classic::push_back_a(actor) | |
#define spirit_assign_actor(actor) boost::spirit::classic::assign_a(actor) | |
#endif // !defined(spirit_append_actor) | |
// this must occur after all of the includes and before any code appears | |
#ifdef BOOST_HAS_ABI_HEADERS | |
#include BOOST_ABI_PREFIX | |
#endif | |
/////////////////////////////////////////////////////////////////////////////// | |
namespace boost { | |
namespace wave { | |
namespace util { | |
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// The function interpret_pragma interprets the given token sequence as the | |
// body of a #pragma directive (or parameter to the _Pragma operator) and | |
// executes the actions associated with recognized Wave specific options. | |
// | |
/////////////////////////////////////////////////////////////////////////////// | |
template <typename ContextT, typename IteratorT, typename ContainerT> | |
inline bool | |
interpret_pragma(ContextT &ctx, typename ContextT::token_type const &act_token, | |
IteratorT it, IteratorT const &end, ContainerT &pending) | |
{ | |
typedef typename ContextT::token_type token_type; | |
typedef typename token_type::string_type string_type; | |
using namespace cpplexer; | |
if (T_IDENTIFIER == token_id(*it)) { | |
// check for pragma wave ... | |
if ((*it).get_value() == BOOST_WAVE_PRAGMA_KEYWORD) | |
{ | |
// this is a wave specific option, it should have the form: | |
// | |
// #pragma command option(value) | |
// | |
// where | |
// 'command' is the value of the preprocessor constant | |
// BOOST_WAVE_PRAGMA_KEYWORD (defaults to "wave") and | |
// '(value)' is required only for some pragma directives (this is | |
// optional) | |
// | |
// All recognized #pragma operators are forwarded to the supplied | |
// preprocessing hook. | |
using namespace boost::spirit::classic; | |
token_type option; | |
ContainerT values; | |
if (!parse (++it, end, | |
( ch_p(T_IDENTIFIER) | |
[ | |
spirit_assign_actor(option) | |
] | |
| pattern_p(KeywordTokenType, | |
TokenTypeMask|PPTokenFlag) | |
[ | |
spirit_assign_actor(option) | |
] | |
| pattern_p(OperatorTokenType|AltExtTokenType, | |
ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc. | |
[ | |
spirit_assign_actor(option) | |
] | |
| pattern_p(BoolLiteralTokenType, | |
TokenTypeMask|PPTokenFlag) | |
[ | |
spirit_assign_actor(option) | |
] | |
) | |
>> !comment_nest_p( | |
ch_p(T_LEFTPAREN), | |
ch_p(T_RIGHTPAREN) | |
)[spirit_assign_actor(values)], | |
pattern_p(WhiteSpaceTokenType, TokenTypeMask|PPTokenFlag)).hit) | |
{ | |
typename ContextT::string_type msg( | |
impl::as_string<string_type>(it, end)); | |
BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, | |
ill_formed_pragma_option, | |
msg.c_str(), act_token.get_position()); | |
return false; | |
} | |
// remove the falsely matched surrounding parenthesis's | |
if (values.size() >= 2) { | |
BOOST_ASSERT(T_LEFTPAREN == values.front() && T_RIGHTPAREN == values.back()); | |
values.erase(values.begin()); | |
typename ContainerT::reverse_iterator rit = values.rbegin(); | |
values.erase((++rit).base()); | |
} | |
// decode the option (call the context_policy hook) | |
if (!ctx.get_hooks().interpret_pragma( | |
ctx.derived(), pending, option, values, act_token)) | |
{ | |
// unknown #pragma option | |
string_type option_str ((*it).get_value()); | |
option_str += option.get_value(); | |
if (values.size() > 0) { | |
option_str += "("; | |
option_str += impl::as_string(values); | |
option_str += ")"; | |
} | |
BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, | |
ill_formed_pragma_option, | |
option_str.c_str(), act_token.get_position()); | |
return false; | |
} | |
return true; | |
} | |
#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 | |
else if ((*it).get_value() == "once") { | |
// #pragma once | |
return ctx.add_pragma_once_header(act_token, ctx.get_current_filename()); | |
} | |
#endif | |
#if BOOST_WAVE_SUPPORT_PRAGMA_MESSAGE != 0 | |
else if ((*it).get_value() == "message") { | |
// #pragma message(...) or #pragma message ... | |
using namespace boost::spirit::classic; | |
ContainerT values; | |
if (!parse (++it, end, | |
( ( ch_p(T_LEFTPAREN) | |
>> lexeme_d[ | |
*(anychar_p[spirit_append_actor(values)] - ch_p(T_RIGHTPAREN)) | |
] | |
>> ch_p(T_RIGHTPAREN) | |
) | |
| lexeme_d[ | |
*(anychar_p[spirit_append_actor(values)] - ch_p(T_NEWLINE)) | |
] | |
), | |
pattern_p(WhiteSpaceTokenType, TokenTypeMask|PPTokenFlag) | |
).hit | |
) | |
{ | |
typename ContextT::string_type msg( | |
impl::as_string<string_type>(it, end)); | |
BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, | |
ill_formed_pragma_message, | |
msg.c_str(), act_token.get_position()); | |
return false; | |
} | |
// remove the falsely matched closing parenthesis/newline | |
if (values.size() > 0) { | |
BOOST_ASSERT(T_RIGHTPAREN == values.back() || T_NEWLINE == values.back()); | |
typename ContainerT::reverse_iterator rit = values.rbegin(); | |
values.erase((++rit).base()); | |
} | |
// output the message itself | |
typename ContextT::string_type msg(impl::as_string(values)); | |
BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, | |
pragma_message_directive, | |
msg.c_str(), act_token.get_position()); | |
return false; | |
} | |
#endif | |
} | |
return false; | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
} // namespace util | |
} // namespace wave | |
} // namespace boost | |
// the suffix header occurs after all of the code | |
#ifdef BOOST_HAS_ABI_HEADERS | |
#include BOOST_ABI_SUFFIX | |
#endif | |
#endif // !defined(INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED) |