You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
210 lines
8.4 KiB
210 lines
8.4 KiB
/*============================================================================= |
|
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)
|
|
|