📄 cpp_macromap.hpp
字号:
if (name.size() < 8 || '_' != name[0] || '_' != name[1])
return false; // quick check failed
return name == "__LINE__" || name == "__FILE__" ||
name == "__INCLUDE_LEVEL__";
}
template <typename ContextT>
template <typename IteratorT>
inline bool
macromap<ContextT>::is_defined(IteratorT const &begin,
IteratorT const &end)
{
// in normal mode the name under inspection should consist of an identifier
// only
token_id id = token_id(*begin);
if (T_IDENTIFIER != id &&
!IS_CATEGORY(id, KeywordTokenType) &&
!IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType))
{
BOOST_WAVE_THROW(preprocess_exception, invalid_macroname,
impl::get_full_name(begin, end).c_str(), main_pos);
}
IteratorT it = begin;
string_type name ((*it).get_value());
typename defined_macros_type::iterator cit(current_macros -> find(name));
if (++it != end) {
// there should be only one token as the inspected name
BOOST_WAVE_THROW(preprocess_exception, invalid_macroname,
impl::get_full_name(begin, end).c_str(), main_pos);
}
return cit != current_macros -> end();
}
///////////////////////////////////////////////////////////////////////////////
//
// remove_macro(): remove a macro from the macromap
//
///////////////////////////////////////////////////////////////////////////////
template <typename ContextT>
inline bool
macromap<ContextT>::remove_macro(token_type const &token,
bool even_predefined)
{
string_type name (token.get_value());
typename defined_macros_type::iterator it = current_macros->find(name);
if (it != current_macros->end()) {
if ((*it).second->is_predefined) {
if (!even_predefined || impl::is_special_macroname(name)) {
BOOST_WAVE_THROW(preprocess_exception, bad_undefine_statement,
name.c_str(), main_pos);
}
}
current_macros->erase(it);
// call the context supplied preprocessing hook function
ctx.undefined_macro(token);
return true;
}
else if (impl::is_special_macroname(name)) {
BOOST_WAVE_THROW(preprocess_exception, bad_undefine_statement,
name.c_str(), main_pos);
}
return false; // macro was not defined
}
///////////////////////////////////////////////////////////////////////////////
//
// expand_tokensequence
//
// This function is a helper function which wraps the given iterator
// range into corresponding unput_iterator's and calls the main workhorse
// of the macro expansion engine (the function expand_tokensequence_worker)
//
// This is the top level macro expansion function called from the
// preprocessing iterator component only.
//
///////////////////////////////////////////////////////////////////////////////
template <typename ContextT>
template <typename IteratorT, typename ContainerT>
inline typename ContextT::token_type const &
macromap<ContextT>::expand_tokensequence(IteratorT &first,
IteratorT const &last, ContainerT &pending, ContainerT &expanded,
bool expand_operator_defined)
{
typedef impl::gen_unput_queue_iterator<IteratorT, token_type, ContainerT>
gen_type;
typedef typename gen_type::return_type iterator_type;
iterator_type first_it = gen_type::generate(expanded, first);
iterator_type last_it = gen_type::generate(last);
on_exit::assign<IteratorT, iterator_type> on_exit(first, first_it);
return expand_tokensequence_worker(pending, first_it, last_it,
expand_operator_defined);
}
///////////////////////////////////////////////////////////////////////////////
//
// expand_tokensequence_worker
//
// This function is the main workhorse of the macro expansion engine. It
// expands as much tokens as needed to identify the next preprocessed
// token to return to the caller.
// It returns the next preprocessed token.
//
// The iterator 'first' is adjusted accordingly.
//
///////////////////////////////////////////////////////////////////////////////
template <typename ContextT>
template <typename IteratorT, typename ContainerT>
inline typename ContextT::token_type const &
macromap<ContextT>::expand_tokensequence_worker(
ContainerT &pending,
unput_queue_iterator<IteratorT, token_type, ContainerT> &first,
unput_queue_iterator<IteratorT, token_type, ContainerT> const &last,
bool expand_operator_defined)
{
// if there exist pending tokens (tokens, which are already preprocessed), then
// return the next one from there
if (!pending.empty()) {
on_exit::pop_front<definition_container_type> pop_front_token(pending);
return act_token = pending.front();
}
// analyze the next element of the given sequence, if it is an
// T_IDENTIFIER token, try to replace this as a macro etc.
using namespace boost::wave;
typedef unput_queue_iterator<IteratorT, token_type, ContainerT> iterator_type;
if (first != last) {
token_id id = token_id(*first);
// ignore placeholder tokens
if (T_PLACEHOLDER == id) {
token_type placeholder = *first;
++first;
if (first == last)
return act_token = placeholder;
id = token_id(*first);
}
if (T_IDENTIFIER == id || IS_CATEGORY(id, KeywordTokenType) ||
IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType))
{
// try to replace this identifier as a macro
if (expand_operator_defined && (*first).get_value() == "defined") {
// resolve operator defined()
return resolve_defined(first, last, pending);
}
else if (boost::wave::need_variadics(ctx.get_language()) &&
(*first).get_value() == "_Pragma")
{
// in C99 mode only: resolve the operator _Pragma
token_type curr_token = *first;
if (!resolve_operator_pragma(first, last, pending) ||
pending.size() > 0)
{
// unknown to us pragma or supplied replacement, return the
// next token
on_exit::pop_front<definition_container_type> pop_token(pending);
return act_token = pending.front();
}
// the operator _Pragma() was eaten completely, continue
return act_token = token_type(T_PLACEHOLDER, "_",
curr_token.get_position());
}
token_type name_token (*first);
typename defined_macros_type::iterator it;
if (is_defined(name_token.get_value(), it)) {
// the current token contains an identifier, which is currently
// defined as a macro
if (expand_macro(pending, name_token, it, first, last,
expand_operator_defined))
{
// the tokens returned by expand_macro should be rescanned
// beginning at the last token of the returned replacement list
if (first != last) {
// splice the last token back into the input queue
typename ContainerT::reverse_iterator rit = pending.rbegin();
first.get_unput_queue().splice(
first.get_unput_queue().begin(), pending,
(++rit).base(), pending.end());
}
// fall through ...
}
else if (!pending.empty()) {
// return the first token from the pending queue
on_exit::pop_front<definition_container_type> pop_queue (pending);
return act_token = pending.front();
}
else {
// macro expansion reached the eoi
return act_token = token_type();
}
// return the next preprocessed token
return expand_tokensequence_worker(pending, first, last,
expand_operator_defined);
}
// else if (expand_operator_defined) {
// // in preprocessing conditionals undefined identifiers and keywords
// // are to be replaced with '0' (see. C++ standard 16.1.4, [cpp.cond])
// return act_token =
// token_type(T_INTLIT, "0", (*first++).get_position());
// }
else {
act_token = name_token;
++first;
return act_token;
}
}
else if (expand_operator_defined && IS_CATEGORY(*first, BoolLiteralTokenType)) {
// expanding a constant expression inside #if/#elif, special handling
// of 'true' and 'false'
// all remaining identifiers and keywords, except for true and false,
// are replaced with the pp-number 0 (C++ standard 16.1.4, [cpp.cond])
return act_token = token_type(T_INTLIT, T_TRUE != id ? "0" : "1",
(*first++).get_position());
}
else {
act_token = *first;
++first;
return act_token;
}
}
return act_token = token_type(); // eoi
}
///////////////////////////////////////////////////////////////////////////////
//
// collect_arguments(): collect the actual arguments of a macro invocation
//
// return the number of successfully detected non-empty arguments
//
///////////////////////////////////////////////////////////////////////////////
template <typename ContextT>
template <typename IteratorT, typename ContainerT, typename SizeT>
inline typename std::vector<ContainerT>::size_type
macromap<ContextT>::collect_arguments (token_type const curr_token,
std::vector<ContainerT> &arguments, IteratorT &next, IteratorT const &end,
SizeT const ¶meter_count)
{
using namespace boost::wave;
arguments.push_back(ContainerT());
// collect the actual arguments
typename std::vector<ContainerT>::size_type count_arguments = 0;
int nested_parenthesis_level = 1;
ContainerT *argument = &arguments[0];
bool was_whitespace = false;
token_type startof_argument_list = *next;
while (++next != end && nested_parenthesis_level) {
token_id id = token_id(*next);
if (0 == parameter_count &&
!IS_CATEGORY((*next), WhiteSpaceTokenType) && id != T_NEWLINE &&
id != T_RIGHTPAREN && id != T_LEFTPAREN)
{
// there shouldn't be any arguments
BOOST_WAVE_THROW(preprocess_exception, too_many_macroarguments,
curr_token.get_value().c_str(), main_pos);
}
switch (static_cast<unsigned int>(id)) {
case T_LEFTPAREN:
++nested_parenthesis_level;
argument->push_back(*next);
was_whitespace = false;
break;
case T_RIGHTPAREN:
{
if (--nested_parenthesis_level >= 1)
argument->push_back(*next);
else {
// found closing parenthesis
// trim_argument(argument);
if (parameter_count > 0) {
if (argument->empty() ||
impl::is_whitespace_only(*argument))
{
#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
if (boost::wave::need_variadics(ctx.get_language())) {
// store a placemarker as the argument
argument->push_back(token_type(T_PLACEMARKER, "
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -