/*============================================================================= | |
Boost.Wave: A Standard compliant C++ preprocessor library | |
http://www.boost.org/ | |
State machine detecting include guards in an included file. | |
This detects two forms of include guards: | |
#ifndef INCLUDE_GUARD_MACRO | |
#define INCLUDE_GUARD_MACRO | |
... | |
#endif | |
or | |
if !defined(INCLUDE_GUARD_MACRO) | |
#define INCLUDE_GUARD_MACRO | |
... | |
#endif | |
note, that the parenthesis are optional (i.e. !defined INCLUDE_GUARD_MACRO | |
will work as well). The code allows for any whitespace, newline and single | |
'#' tokens before the #if/#ifndef and after the final #endif. | |
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(DETECT_INCLUDE_GUARDS_HK060304_INCLUDED) | |
#define DETECT_INCLUDE_GUARDS_HK060304_INCLUDED | |
#include <boost/wave/wave_config.hpp> | |
#include <boost/wave/token_ids.hpp> | |
// 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 cpplexer { | |
template <typename Token> | |
class include_guards | |
{ | |
public: | |
include_guards() | |
: state(&include_guards::state_0), detected_guards(false), | |
current_state(true), if_depth(0) | |
{} | |
Token& detect_guard(Token& t) | |
{ return current_state ? (this->*state)(t) : t; } | |
bool detected(std::string& guard_name_) const | |
{ | |
if (detected_guards) { | |
guard_name_ = guard_name.c_str(); | |
return true; | |
} | |
return false; | |
} | |
private: | |
typedef Token& state_type(Token& t); | |
state_type include_guards::* state; | |
bool detected_guards; | |
bool current_state; | |
typename Token::string_type guard_name; | |
int if_depth; | |
state_type state_0, state_1, state_2, state_3, state_4, state_5; | |
state_type state_1a, state_1b, state_1c, state_1d, state_1e; | |
bool is_skippable(token_id id) const | |
{ | |
return (T_POUND == BASE_TOKEN(id) || | |
IS_CATEGORY(id, WhiteSpaceTokenType) || | |
IS_CATEGORY(id, EOLTokenType)); | |
} | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// state 0: beginning of a file, tries to recognize #ifndef or #if tokens | |
template <typename Token> | |
inline Token& | |
include_guards<Token>::state_0(Token& t) | |
{ | |
token_id id = token_id(t); | |
if (T_PP_IFNDEF == id) | |
state = &include_guards::state_1; | |
else if (T_PP_IF == id) | |
state = &include_guards::state_1a; | |
else if (!is_skippable(id)) | |
current_state = false; | |
return t; | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
// state 1: found #ifndef, looking for T_IDENTIFIER | |
template <typename Token> | |
inline Token& | |
include_guards<Token>::state_1(Token& t) | |
{ | |
token_id id = token_id(t); | |
if (T_IDENTIFIER == id) { | |
guard_name = t.get_value(); | |
state = &include_guards::state_2; | |
} | |
else if (!is_skippable(id)) | |
current_state = false; | |
return t; | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
// state 1a: found T_PP_IF, looking for T_NOT ("!") | |
template <typename Token> | |
inline Token& | |
include_guards<Token>::state_1a(Token& t) | |
{ | |
token_id id = token_id(t); | |
if (T_NOT == BASE_TOKEN(id)) | |
state = &include_guards::state_1b; | |
else if (!is_skippable(id)) | |
current_state = false; | |
return t; | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
// state 1b: found T_NOT, looking for 'defined' | |
template <typename Token> | |
inline Token& | |
include_guards<Token>::state_1b(Token& t) | |
{ | |
token_id id = token_id(t); | |
if (T_IDENTIFIER == id && t.get_value() == "defined") | |
state = &include_guards::state_1c; | |
else if (!is_skippable(id)) | |
current_state = false; | |
return t; | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
// state 1c: found 'defined', looking for (optional) T_LEFTPAREN | |
template <typename Token> | |
inline Token& | |
include_guards<Token>::state_1c(Token& t) | |
{ | |
token_id id = token_id(t); | |
if (T_LEFTPAREN == id) | |
state = &include_guards::state_1d; | |
else if (T_IDENTIFIER == id) { | |
guard_name = t.get_value(); | |
state = &include_guards::state_2; | |
} | |
else if (!is_skippable(id)) | |
current_state = false; | |
return t; | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
// state 1d: found T_LEFTPAREN, looking for T_IDENTIFIER guard | |
template <typename Token> | |
inline Token& | |
include_guards<Token>::state_1d(Token& t) | |
{ | |
token_id id = token_id(t); | |
if (T_IDENTIFIER == id) { | |
guard_name = t.get_value(); | |
state = &include_guards::state_1e; | |
} | |
else if (!is_skippable(id)) | |
current_state = false; | |
return t; | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
// state 1e: found T_IDENTIFIER guard, looking for T_RIGHTPAREN | |
template <typename Token> | |
inline Token& | |
include_guards<Token>::state_1e(Token& t) | |
{ | |
token_id id = token_id(t); | |
if (T_RIGHTPAREN == id) | |
state = &include_guards::state_2; | |
else if (!is_skippable(id)) | |
current_state = false; | |
return t; | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
// state 2: found T_IDENTIFIER, looking for #define | |
template <typename Token> | |
inline Token& | |
include_guards<Token>::state_2(Token& t) | |
{ | |
token_id id = token_id(t); | |
if (T_PP_DEFINE == id) | |
state = &include_guards::state_3; | |
else if (!is_skippable(id)) | |
current_state = false; | |
return t; | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
// state 3: found #define, looking for T_IDENTIFIER as recognized by state 1 | |
template <typename Token> | |
inline Token& | |
include_guards<Token>::state_3(Token& t) | |
{ | |
token_id id = token_id(t); | |
if (T_IDENTIFIER == id && t.get_value() == guard_name) | |
state = &include_guards::state_4; | |
else if (!is_skippable(id)) | |
current_state = false; | |
return t; | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
// state 4: found guard T_IDENTIFIER, looking for #endif | |
template <typename Token> | |
inline Token& | |
include_guards<Token>::state_4(Token& t) | |
{ | |
token_id id = token_id(t); | |
if (T_PP_IF == id || T_PP_IFDEF == id || T_PP_IFNDEF == id) | |
++if_depth; | |
else if (T_PP_ENDIF == id) { | |
if (if_depth > 0) | |
--if_depth; | |
else | |
state = &include_guards::state_5; | |
} | |
return t; | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
// state 5: found final #endif, looking for T_EOF | |
template <typename Token> | |
inline Token& | |
include_guards<Token>::state_5(Token& t) | |
{ | |
token_id id = token_id(t); | |
if (T_EOF == id) | |
detected_guards = current_state; | |
else if (!is_skippable(id)) | |
current_state = false; | |
return t; | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
} // namespace cpplexer | |
} // namespace wave | |
} // namespace boost | |
// the suffix header occurs after all of the code | |
#ifdef BOOST_HAS_ABI_HEADERS | |
#include BOOST_ABI_SUFFIX | |
#endif | |
#endif // !DETECT_INCLUDE_GUARDS_HK060304_INCLUDED |