[Wave] advanced preprocessing hooks

Hi, I have a question and a suggestion regarding Wave. First I have a problem when preprocessing the following file: #if 0 #elif 1 test #endif #if 1 #elif 0 int x; #endif The first '#elif' directive is registered as an 'evaluated_conditional_expression(...)', but the second '#elif' is never evaluated since the previous '#if' directive is true, and it is therefore not registered as either a 'skipped_token(...)' or an 'evaluated_conditional_expression(...)'. The way I expected it to work was to register it as a 'skipped_token(...)'. Do you have a suggestion to how I should otherwise be handling this? If not, could it be possible to add the non-evaluated '#elif' to the skipped token stream? The suggestion is for preprocessor generated tokens where the ' macro.get_position().get_file().size() == 0'. An example of this is in the following code #ifdef SOME_MACRO //DO SOMETHING #endif Since 'SOME_MACRO' is not defined the 'expanding_object_like_macro(TokenT const ¯o,....)' will be passed a TokentT& const& macro with no position object, so asking for the line or column number will give a hard to debug segmentation fault. In order to detect this to avoid an error it is necessary to always ask for the size of the file as demonstrated above before asking for the line, file or column My suggestion is that alternatively a position object could be attached to 'macro', and a Boolean flag 'is_preprocessor_generated' could be used to find out if the position object is preprocessor generated or not. What do you think? Thanks Andreas

Andreas Sæbjørnsen wrote:
I have a question and a suggestion regarding Wave. First I have a problem when preprocessing the following file: #if 0 #elif 1 test #endif
#if 1 #elif 0 int x; #endif The first '#elif' directive is registered as an 'evaluated_conditional_expression(...)', but the second '#elif' is never evaluated since the previous '#if' directive is true, and it is therefore not registered as either a 'skipped_token(...)' or an 'evaluated_conditional_expression(...)'. The way I expected it to work was to register it as a 'skipped_token(...)'. Do you have a suggestion to how I should otherwise be handling this? If not, could it be possible to add the non-evaluated '#elif' to the skipped token stream?
This is fixed now (Boost CVS::HEAD and Boost CVS::BOOST_RC_1_34). Thanks for reporting.
The suggestion is for preprocessor generated tokens where the 'macro.get_position().get_file().size() == 0'. An example of this is in the following code
#ifdef SOME_MACRO //DO SOMETHING #endif
Since 'SOME_MACRO' is not defined the 'expanding_object_like_macro(TokenT const ¯o,....)' will be passed a TokentT& const& macro with no position object, so asking for the line or column number will give a hard to debug segmentation fault.
This one is really strange, because if SOME_MACRO is not defined then the expanding_object_like_macro() pp hook shouldn't be called for this macro. For this reason I'm not able to reproduce this issue here. Nevertheless, I think it's a bug if 'macro.get_position().get_file().size() == 0' in any case (any token should have some associated file/position it was encountered at). Could you please try to isolate this problem and send me a sample? Regards Hartmut

Andreas Sæbjørnsen wrote:
The first '#elif' directive is registered as an 'evaluated_conditional_expression(...)', but the second '#elif' is never evaluated since the previous '#if' directive is true, and it is therefore not registered as either a 'skipped_token(...)' or an 'evaluated_conditional_expression(...)'. The way I expected it to work was to register it as a 'skipped_token(...)'. Do you have a suggestion to how I should otherwise be handling this? If not, could it be possible to add the non-evaluated '#elif' to the skipped token stream?
This is fixed now (Boost CVS::HEAD and Boost CVS::BOOST_RC_1_34). Thanks for reporting.
Thank you very much! I appreciate the fast fix.
The suggestion is for preprocessor generated tokens where the
'macro.get_position().get_file().size() == 0'. An example of this is in the following code
#ifdef SOME_MACRO //DO SOMETHING #endif
Since 'SOME_MACRO' is not defined the 'expanding_object_like_macro(TokenT const ¯o,....)' will be passed a TokentT& const& macro with no position object, so asking for the line or column number will give a hard to debug segmentation fault.
This one is really strange, because if SOME_MACRO is not defined then the expanding_object_like_macro() pp hook shouldn't be called for this macro. For this reason I'm not able to reproduce this issue here.
Nevertheless, I think it's a bug if 'macro.get_position ().get_file().size() == 0' in any case (any token should have some associated file/position it was encountered at). Could you please try to isolate this problem and send me a sample?
No problem. I will send it to you as soon as I have it. :)
A change I have done to Wave which I have not told you about earlier is to
change the behaviour of on_warning(...) in
'tboost/wave/util/cpp_iterator.hpp' to
continue if a #warning directive is found, and not treat it like an error. I
do not know
if the CVS-version still behaves in this way. I also added a preprocessing
hook
on_warning(..) for the warning directive as I need to extract it. What do
you think of this
change? (Code Below for on_warning. Changed 'preprocessing_hooks.hpp'
attached).
Thanks
Andreas
#if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
///////////////////////////////////////////////////////////////////////////////
//
// on_warning(): handle #warning directives
//
///////////////////////////////////////////////////////////////////////////////
template <typename ContextT>
inline void
pp_iterator_functor<ContextT>::on_warning(
typename parse_tree_type::const_iterator const &begin,
typename parse_tree_type::const_iterator const &end)
{
BOOST_ASSERT(ctx.get_if_block_status());
// preprocess the given sequence into the provided list
token_sequence_type expanded;
get_token_value
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Andreas Sæbjørnsen wrote:
A change I have done to Wave which I have not told you about earlier is to change the behaviour of on_warning(...) in 'tboost/wave/util/cpp_iterator.hpp' to continue if a #warning directive is found, and not treat it like an error. I do not know if the CVS-version still behaves in this way. I also added a preprocessing hook on_warning(..) for the warning directive as I need to extract it. What do you think of this change? (Code Below for on_warning. Changed 'preprocessing_hooks.hpp' attached).
Hmmm. The 'warning_directive' preprocess_exception is recoverable. That means you may simply continue to iterate after catching this type of exception (see the wave driver how this may be achieved). That's the reason why I made the warning to throw an exception (same as #error). I'm not sure if we really should change this behaviour (even more as the driver currently depends on that). OTOH I like your idea to add a on_warning() pp hook function (same should be added for #error as well). What do you think, what if we use the return value of the on_warning() pp hook to decide, whether to throw the exception? This way we could keep the default behaviour (throwing) but you could enforce the non-throwing behaviour simply by returning false. Regards Hartmut
Thanks Andreas
#if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0 ////////////////////////////////////////////////////////////// ///////////////// // // on_warning(): handle #warning directives // ////////////////////////////////////////////////////////////// ///////////////// template <typename ContextT> inline void pp_iterator_functor<ContextT>::on_warning( typename parse_tree_type::const_iterator const &begin, typename parse_tree_type::const_iterator const &end) { BOOST_ASSERT(ctx.get_if_block_status());
// preprocess the given sequence into the provided list token_sequence_type expanded; get_token_value
get_value; typename ref_transform_iterator_generator< get_token_value
, typename parse_tree_type::const_iterator >::type first = make_ref_transform_iterator(begin, get_value); #if BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY != 0 // preprocess the body of this #warning message token_sequence_type toexpand;
std::copy(first, make_ref_transform_iterator(end, get_value), std::inserter(toexpand, toexpand.end()));
typename token_sequence_type::iterator begin2 = toexpand.begin(); ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded, false); #else // simply copy the body of this #warning message to the issued diagnostic // message std::copy(first, make_ref_transform_iterator(end, get_value), std::inserter(expanded, expanded.end())); #endif //AS(051706) Added an extra hook to send the warning directive std::cout << "The warning is: " << boost::wave::util::impl::as_string(expanded).c_str() << std::endl; ctx.get_hooks().on_warning(toexpand);
//AS(051606) Do not treat warning directives as errors #if 0 // report the corresponding error BOOST_WAVE_THROW(preprocess_exception, warning_directive, boost::wave::util::impl::as_string(expanded).c_str(), act_pos); #endif
} #endif // BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
Regards Hartmut
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Hmmm. The 'warning_directive' preprocess_exception is recoverable. That means you may simply continue to iterate after catching this type of exception (see the wave driver how this may be achieved). That's the reason why I made the warning to throw an exception (same as #error). I'm not sure if we really should change this behaviour (even more as the driver currently depends on that).
OTOH I like your idea to add a on_warning() pp hook function (same should be added for #error as well). What do you think, what if we use the return value of the on_warning() pp hook to decide, whether to throw the exception? This way we could keep the default behaviour (throwing) but you could enforce the non-throwing behaviour simply by returning false.
I think using the return value form on_warning() or on_hook() to decide if an exception should be thrown is an excellent idea. That would fit very well with my needs. Regards Andreas
Thanks Andreas
#if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0 ////////////////////////////////////////////////////////////// ///////////////// // // on_warning(): handle #warning directives // ////////////////////////////////////////////////////////////// ///////////////// template <typename ContextT> inline void pp_iterator_functor<ContextT>::on_warning( typename parse_tree_type::const_iterator const &begin, typename parse_tree_type::const_iterator const &end) { BOOST_ASSERT(ctx.get_if_block_status());
// preprocess the given sequence into the provided list token_sequence_type expanded; get_token_value
get_value; typename ref_transform_iterator_generator< get_token_value
, typename parse_tree_type::const_iterator >::type first = make_ref_transform_iterator(begin, get_value); #if BOOST_WAVE_PREPROCESS_ERROR_MESSAGE_BODY != 0 // preprocess the body of this #warning message token_sequence_type toexpand;
std::copy(first, make_ref_transform_iterator(end, get_value), std::inserter(toexpand, toexpand.end()));
typename token_sequence_type::iterator begin2 = toexpand.begin(); ctx.expand_whole_tokensequence(begin2, toexpand.end(), expanded, false); #else // simply copy the body of this #warning message to the issued diagnostic // message std::copy(first, make_ref_transform_iterator(end, get_value), std::inserter(expanded, expanded.end())); #endif //AS(051706) Added an extra hook to send the warning directive std::cout << "The warning is: " << boost::wave::util::impl::as_string(expanded).c_str() << std::endl; ctx.get_hooks().on_warning(toexpand);
//AS(051606) Do not treat warning directives as errors #if 0 // report the corresponding error BOOST_WAVE_THROW(preprocess_exception, warning_directive, boost::wave::util::impl::as_string(expanded).c_str(), act_pos); #endif
} #endif // BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
Regards Hartmut
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Andreas,
OTOH I like your idea to add a on_warning() pp hook function (same should be added for #error as well). What do you think, what if we use the return value of the on_warning() pp hook to decide, whether to throw the exception? This way we could keep the default behaviour (throwing) but you could enforce the non-throwing behaviour simply by returning false.
I think using the return value form on_warning() or on_hook() to decide if an exception should be thrown is an excellent idea. That would fit very well with my needs.
I've added two new pp hook functions: found_error_directive() and found_warning_directive(), both taking the context and the directive argument token sequence as their arguments. The return vaue is used to suppress the corresponding exception (true suppresses, false keeps the old behaviour). I have not updated the docs yet (but will do soon). The changes are in the CVS::HEAD branch only (I'm not allowed to add new features to the release branch). HTH Regards Hartmut
participants (2)
-
Andreas Sæbjørnsen
-
Hartmut Kaiser