Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include __LINE__, __FILE__, __INCLUDE_LEVEL__, and __VA_OPT__ in hooks #87

Merged
merged 5 commits into from Apr 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
121 changes: 99 additions & 22 deletions include/boost/wave/util/cpp_macromap.hpp
Expand Up @@ -1085,7 +1085,7 @@ bool adjacent_stringize = false;
expand_operator_defined, has_expanded_args);
}

// locate the __VA_OPT__ arguments
// locate the end of the __VA_OPT__ call
typename macro_definition_type::const_definition_iterator_t cstart = cit;
if (!impl::find_va_opt_args(cit, cend)) {
BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
Expand All @@ -1094,17 +1094,59 @@ bool adjacent_stringize = false;
}
// cstart still points to __VA_OPT__; cit now points to the last rparen

if ((i == arguments.size()) || // no variadic argument
impl::is_whitespace_only(arguments[i])) { // no visible tokens
// no args; insert placemarker if one is not already present
expanded.push_back(
typename ContainerT::value_type(T_PLACEMARKER, "\xA7", pos));
} else if (!impl::is_blank_only(arguments[i])) {
++cstart; ++cstart;
// [cstart, cit) is now the args to va_opt
// recursively process them
expand_replacement_list(cstart, cit, arguments,
expand_operator_defined, expanded);
// locate the __VA_OPT__ arguments
typename macro_definition_type::const_definition_iterator_t arg_start = cstart;
++arg_start; // skip __VA_OPT__
++arg_start; // skip lparen

// create a synthetic macro definition for use with hooks
token_type macroname(T_IDENTIFIER, "__VA_OPT__", position_type("<built-in>"));
parameter_container_type macroparameters;
macroparameters.push_back(token_type(T_ELLIPSIS, "...", position_type("<built-in>")));
definition_container_type macrodefinition;

bool suppress_expand = false;
// __VA_OPT__ treats its arguments as an undifferentiated stream of tokens
// for our purposes we can consider it as a single argument
typename std::vector<ContainerT> va_opt_args(1, ContainerT(arg_start, cit));
#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
ctx.get_hooks().expanding_function_like_macro(
macroname, macroparameters, macrodefinitions,
*cstart, va_opt_args);
#else
suppress_expand = ctx.get_hooks().expanding_function_like_macro(
ctx.derived(),
macroname, macroparameters, macrodefinition,
*cstart, va_opt_args,
cstart, cit);
#endif

if (suppress_expand) {
// leave the whole expression in place
std::copy(cstart, cit, std::back_inserter(expanded));
expanded.push_back(*cit); // include the rparen
} else {
ContainerT va_expanded;
if ((i == arguments.size()) || // no variadic argument
impl::is_whitespace_only(arguments[i])) { // no visible tokens
// no args; insert placemarker
va_expanded.push_back(
typename ContainerT::value_type(T_PLACEMARKER, "\xA7", pos));
} else if (!impl::is_blank_only(arguments[i])) {
// [cstart, cit) is now the args to va_opt
// recursively process them
expand_replacement_list(arg_start, cit, arguments,
expand_operator_defined, va_expanded);
}
// run final hooks
#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
ctx.get_hooks().expanded_macro(va_expanded);
#else
ctx.get_hooks().expanded_macro(ctx.derived(), va_expanded);
#endif

// updated overall expansion with va_opt results
expanded.splice(expanded.end(), va_expanded);
}
// continue from rparen
}
Expand Down Expand Up @@ -1543,15 +1585,32 @@ macromap<ContextT>::expand_predefined_macro(token_type const &curr_token,

string_type const &value = curr_token.get_value();

if (value.size() < 8 || '_' != value[0] || '_' != value[1])
return false; // quick check failed
if ((value != "__LINE__") && (value != "__FILE__") && (value != "__INCLUDE_LEVEL__"))
return false;

// construct a fake token for the macro's definition point
token_type deftoken(T_IDENTIFIER, value, position_type("<built-in>"));

#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
ctx.get_hooks().expanding_object_like_macro(
deftoken, Container(), curr_token); // BOZO check params
#else
if (ctx.get_hooks().expanding_object_like_macro(ctx.derived(),
deftoken, ContainerT(), curr_token))
{
// do not expand this macro, just copy the whole sequence
expanded.push_back(curr_token);
return false; // no further preprocessing required
}
#endif

token_type replacement;

if (value == "__LINE__") {
// expand the __LINE__ macro
std::string buffer = lexical_cast<std::string>(main_pos.get_line());

expanded.push_back(token_type(T_INTLIT, buffer.c_str(), curr_token.get_position()));
return true;
replacement = token_type(T_INTLIT, buffer.c_str(), curr_token.get_position());
}
else if (value == "__FILE__") {
// expand the __FILE__ macro
Expand All @@ -1562,20 +1621,38 @@ string_type const &value = curr_token.get_value();

using boost::wave::util::impl::escape_lit;
file += escape_lit(wave::util::native_file_string(filename)) + "\"";
expanded.push_back(token_type(T_STRINGLIT, file.c_str(),
curr_token.get_position()));
return true;
replacement = token_type(T_STRINGLIT, file.c_str(),
curr_token.get_position());
}
else if (value == "__INCLUDE_LEVEL__") {
// expand the __INCLUDE_LEVEL__ macro
char buffer[22]; // 21 bytes holds all NUL-terminated unsigned 64-bit numbers

using namespace std; // for some systems sprintf is in namespace std
sprintf(buffer, "%d", (int)ctx.get_iteration_depth());
expanded.push_back(token_type(T_INTLIT, buffer, curr_token.get_position()));
return true;
replacement = token_type(T_INTLIT, buffer, curr_token.get_position());
}
return false; // no predefined token

// post-expansion hooks
ContainerT replacement_list;
replacement_list.push_back(replacement);

#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
ctx.get_hooks().expanded_macro(replacement_list);
#else
ctx.get_hooks().expanded_macro(ctx.derived(), replacement_list);
#endif

expanded.push_back(replacement);

#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
ctx.get_hooks().rescanned_macro(expanded);
#else
ctx.get_hooks().rescanned_macro(ctx.derived(), expanded);
#endif

return true;

}

///////////////////////////////////////////////////////////////////////////////
Expand Down
3 changes: 3 additions & 0 deletions test/testwave/testfiles/t_2_017.cpp
Expand Up @@ -28,6 +28,9 @@ file t_2_017.cpp
//H 10: t_2_017.cpp(14): #define
//H 08: t_2_017.cpp(14): FILE_002_017_CPP=
//H 10: t_2_017.cpp(16): #include
//H 01: <built-in>(1): __FILE__
//H 02: "$P(t_2_017.cpp)"
//H 03: "$P(t_2_017.cpp)"
//H 04: "$P(t_2_017.cpp)"
//H 05: $B(t_2_017.cpp) ($B(t_2_017.cpp))
//H 10: t_2_017.cpp(13): #if
Expand Down
21 changes: 21 additions & 0 deletions test/testwave/testfiles/t_3_002.cpp
Expand Up @@ -37,14 +37,35 @@ __BASE_FILE__ //R "$F"
//H 01: <built-in>(1): __cplusplus
//H 02: 199711L
//H 03: 199711L
//H 01: <built-in>(1): __LINE__
//H 02: 17
//H 03: 17
//H 01: <built-in>(1): __FILE__
//H 02: "$P(t_3_002.cpp)"
//H 03: "$P(t_3_002.cpp)"
//H 01: <built-in>(1): __BASE_FILE__
//H 02: "$F"
//H 03: "$F"
//H 01: <built-in>(1): __INCLUDE_LEVEL__
//H 02: 0
//H 03: 0
//H 10: t_3_002.cpp(23): #line
//H 17: 50 "test.cpp" (50, "test.cpp")
//H 01: <built-in>(1): __LINE__
//H 02: 50
//H 03: 50
//H 01: <built-in>(1): __FILE__
//H 02: "test.cpp"
//H 03: "test.cpp"
//H 01: <built-in>(1): __BASE_FILE__
//H 02: "$F"
//H 03: "$F"
//H 01: <built-in>(1): __LINE__
//H 02: 56
//H 03: 56
//H 01: <built-in>(1): __FILE__
//H 02: "test.cpp"
//H 03: "test.cpp"
//H 01: <built-in>(1): __BASE_FILE__
//H 02: "$F"
//H 03: "$F"
21 changes: 21 additions & 0 deletions test/testwave/testfiles/t_3_003.cpp
Expand Up @@ -39,17 +39,38 @@ __BASE_FILE__ //R "$F"
//H 01: <built-in>(1): __cplusplus
//H 02: 199711L
//H 03: 199711L
//H 01: <built-in>(1): __LINE__
//H 02: 19
//H 03: 19
//H 01: <built-in>(1): __FILE__
//H 02: "$P(t_3_003.cpp)"
//H 03: "$P(t_3_003.cpp)"
//H 01: <built-in>(1): __BASE_FILE__
//H 02: "$F"
//H 03: "$F"
//H 01: <built-in>(1): __WAVE_HAS_VARIADICS__
//H 02: 1
//H 03: 1
//H 01: <built-in>(1): __INCLUDE_LEVEL__
//H 02: 0
//H 03: 0
//H 10: t_3_003.cpp(25): #line
//H 17: 50 "test.cpp" (50, "test.cpp")
//H 01: <built-in>(1): __LINE__
//H 02: 50
//H 03: 50
//H 01: <built-in>(1): __FILE__
//H 02: "test.cpp"
//H 03: "test.cpp"
//H 01: <built-in>(1): __BASE_FILE__
//H 02: "$F"
//H 03: "$F"
//H 01: <built-in>(1): __LINE__
//H 02: 56
//H 03: 56
//H 01: <built-in>(1): __FILE__
//H 02: "test.cpp"
//H 03: "test.cpp"
//H 01: <built-in>(1): __BASE_FILE__
//H 02: "$F"
//H 03: "$F"
21 changes: 21 additions & 0 deletions test/testwave/testfiles/t_3_004.cpp
Expand Up @@ -42,17 +42,38 @@ __BASE_FILE__ //R "$F"
//H 01: <built-in>(1): __STDC_HOSTED__
//H 02: 0
//H 03: 0
//H 01: <built-in>(1): __LINE__
//H 02: 19
//H 03: 19
//H 01: <built-in>(1): __FILE__
//H 02: "$P(t_3_004.cpp)"
//H 03: "$P(t_3_004.cpp)"
//H 01: <built-in>(1): __BASE_FILE__
//H 02: "$F"
//H 03: "$F"
//H 01: <built-in>(1): __WAVE_HAS_VARIADICS__
//H 02: 1
//H 03: 1
//H 01: <built-in>(1): __INCLUDE_LEVEL__
//H 02: 0
//H 03: 0
//H 10: t_3_004.cpp(25): #line
//H 17: 50 "test.cpp" (50, "test.cpp")
//H 01: <built-in>(1): __LINE__
//H 02: 50
//H 03: 50
//H 01: <built-in>(1): __FILE__
//H 02: "test.cpp"
//H 03: "test.cpp"
//H 01: <built-in>(1): __BASE_FILE__
//H 02: "$F"
//H 03: "$F"
//H 01: <built-in>(1): __LINE__
//H 02: 56
//H 03: 56
//H 01: <built-in>(1): __FILE__
//H 02: "test.cpp"
//H 03: "test.cpp"
//H 01: <built-in>(1): __BASE_FILE__
//H 02: "$F"
//H 03: "$F"
29 changes: 29 additions & 0 deletions test/testwave/testfiles/t_8_001.cpp
Expand Up @@ -50,23 +50,52 @@ LOG2("All well in zone %d", n);
//H 10: t_8_001.cpp(19): #define
//H 08: t_8_001.cpp(19): LOG2(...)=printf("at line=%d" __VA_OPT__(": "), __LINE__); __VA_OPT__(printf(__VA_ARGS__);) printf("\n")
//H 00: t_8_001.cpp(28): LOG("hello world\n"), [t_8_001.cpp(17): LOG(msg, ...)=printf(msg __VA_OPT__(,) __VA_ARGS__)]
//H 00: t_8_001.cpp(17): __VA_OPT__(,), [<built-in>(1): __VA_OPT__(...)=]
// no variadic args supplied, placemarker produced:
//H 02: �
//H 02: printf("hello world\n" � )
//H 03: printf("hello world\n" )
//H 00: t_8_001.cpp(29): LOG("hello world\n", �), [t_8_001.cpp(17): LOG(msg, ...)=printf(msg __VA_OPT__(,) __VA_ARGS__)]
//H 00: t_8_001.cpp(17): __VA_OPT__(,), [<built-in>(1): __VA_OPT__(...)=]
// a variadic arg, but it contains a placemarker
// it's a kind of third case - no visible tokens, but not exclusively "whitespace"
//H 02:
//H 02: printf("hello world\n" )
//H 03: printf("hello world\n" )
//H 00: t_8_001.cpp(30): LOG("hello %d\n", n), [t_8_001.cpp(17): LOG(msg, ...)=printf(msg __VA_OPT__(,) __VA_ARGS__)]
//H 00: t_8_001.cpp(17): __VA_OPT__(,), [<built-in>(1): __VA_OPT__(...)=]
// a single token for variadic args:
//H 02: ,
//H 02: printf("hello %d\n" , n)
//H 03: printf("hello %d\n" , n)
//H 00: t_8_001.cpp(35): SDEF(foo), [t_8_001.cpp(18): SDEF(sname, ...)=S sname __VA_OPT__(= { __VA_ARGS__ })]
//H 00: t_8_001.cpp(18): __VA_OPT__(= { __VA_ARGS__ }), [<built-in>(1): __VA_OPT__(...)=]
// no varargs, emit placeholder:
//H 02: �
//H 02: S foo �
//H 03: S foo
//H 00: t_8_001.cpp(36): SDEF(bar, 1, 2, 3), [t_8_001.cpp(18): SDEF(sname, ...)=S sname __VA_OPT__(= { __VA_ARGS__ })]
//H 00: t_8_001.cpp(18): __VA_OPT__(= { __VA_ARGS__ }), [<built-in>(1): __VA_OPT__(...)=]
//H 02: = { 1, 2, 3 }
//H 02: S bar = { 1, 2, 3 }
//H 03: S bar = { 1, 2, 3 }
//H 00: t_8_001.cpp(43): LOG2(�), [t_8_001.cpp(19): LOG2(...)=printf("at line=%d" __VA_OPT__(": "), __LINE__); __VA_OPT__(printf(__VA_ARGS__);) printf("\n")]
//H 00: t_8_001.cpp(20): __VA_OPT__(": "), [<built-in>(1): __VA_OPT__(...)=]
//H 02:
//H 00: t_8_001.cpp(21): __VA_OPT__(printf(__VA_ARGS__);), [<built-in>(1): __VA_OPT__(...)=]
//H 02:
//H 02: printf("at line=%d" , __LINE__); printf("\n")
//H 01: <built-in>(1): __LINE__
//H 02: 43
//H 03: 43
//H 03: printf("at line=%d" , 43); printf("\n")
//H 00: t_8_001.cpp(44): LOG2("All well in zone %d", n), [t_8_001.cpp(19): LOG2(...)=printf("at line=%d" __VA_OPT__(": "), __LINE__); __VA_OPT__(printf(__VA_ARGS__);) printf("\n")]
//H 00: t_8_001.cpp(20): __VA_OPT__(": "), [<built-in>(1): __VA_OPT__(...)=]
//H 02: ": "
//H 00: t_8_001.cpp(21): __VA_OPT__(printf(__VA_ARGS__);), [<built-in>(1): __VA_OPT__(...)=]
//H 02: printf("All well in zone %d", n);
//H 02: printf("at line=%d" ": ", __LINE__); printf("All well in zone %d", n); printf("\n")
//H 01: <built-in>(1): __LINE__
//H 02: 44
//H 03: 44
//H 03: printf("at line=%d" ": ", 44); printf("All well in zone %d", n); printf("\n")
21 changes: 21 additions & 0 deletions test/testwave/testfiles/t_8_008.cpp
Expand Up @@ -46,17 +46,38 @@ __BASE_FILE__ //R "$F"
//H 01: <built-in>(1): __STDC_HOSTED__
//H 02: 0
//H 03: 0
//H 01: <built-in>(1): __LINE__
//H 02: 20
//H 03: 20
//H 01: <built-in>(1): __FILE__
//H 02: "$P(t_8_008.cpp)"
//H 03: "$P(t_8_008.cpp)"
//H 01: <built-in>(1): __BASE_FILE__
//H 02: "$F"
//H 03: "$F"
//H 01: <built-in>(1): __WAVE_HAS_VARIADICS__
//H 02: 1
//H 03: 1
//H 01: <built-in>(1): __INCLUDE_LEVEL__
//H 02: 0
//H 03: 0
//H 10: t_8_008.cpp(26): #line
//H 17: 53 "test.cpp" (53, "test.cpp")
//H 01: <built-in>(1): __LINE__
//H 02: 53
//H 03: 53
//H 01: <built-in>(1): __FILE__
//H 02: "test.cpp"
//H 03: "test.cpp"
//H 01: <built-in>(1): __BASE_FILE__
//H 02: "$F"
//H 03: "$F"
//H 01: <built-in>(1): __LINE__
//H 02: 59
//H 03: 59
//H 01: <built-in>(1): __FILE__
//H 02: "test.cpp"
//H 03: "test.cpp"
//H 01: <built-in>(1): __BASE_FILE__
//H 02: "$F"
//H 03: "$F"
3 changes: 3 additions & 0 deletions test/testwave/testfiles/t_9_016.cpp
Expand Up @@ -23,6 +23,9 @@ EXPAND(#) define later
//H 10: t_9_016.cpp(11): #define
//H 08: t_9_016.cpp(11): inclusion=
//H 10: t_9_016.cpp(12): # include
//H 01: <built-in>(1): __FILE__
//H 02: "$P(t_9_016.cpp)"
//H 03: "$P(t_9_016.cpp)"
//H 04: "$P(t_9_016.cpp)"
//H 05: $B(t_9_016.cpp) ($B(t_9_016.cpp))
//H 10: t_9_016.cpp(10): #if
Expand Down