Boost logo

Boost Users :

From: Hartmut Kaiser (hartmut.kaiser_at_[hidden])
Date: 2005-12-09 08:47:21


Max Motovilov wrote:

First of all, thanks for your suggestions!

> > What exactly do you expect in this context?
>
> Well, like I said, it is typical for a C/C++ preprocessor to
> allow macro re-definitions in violation of the standard, and
> there's likely quite a bit of [sloppy] code that won't be
> processed correctly otherwise. I am not 100% sure what is the
> best paradigm for handling this situation in the context of
> Wave.

One of the reasons Wave was written was exactly this sloppyness of existing
preprocessors, which makes it nearly impossible to rely on the Standard and
beeing portable at the same time.

> It would, of course, be nice to have a generic
> mechanism for rolling back to pre-error state of the
> lexer/preprocessor system while providing sufficient
> information to enact recovery (i.e. providing the name of a
> failed macro so that user's code can call undefine_macro()
> and re-process the failed definition). I imagine that may be
> quite expensive, however, as it might entail having to save
> the state in the beginning of any operation that may consume
> tokens from the input without returning them to user --
> potentially any operation!

Yes, this involves deep copying of the whole context object which may turn
out to be a costly operation not good as a 'preventive' error handling
scheme. Error recovery itself may be costly, even very costly, because in
case of an error time doesn't matter so much anymore, but this should not
have heavy inpact on the normal operation.
 
> Perhaps a cheaper way is adding
> another hook to the context policy? For example,
>
> template<typename X> bool pre_exception( const X& err );
>
> that will have a chance to recover and return true or return
> false and allow the exception to proceed. Again, I am not
> sure just how easy it would be to incorporate such a policy
> hook into the existing code. In simple cases, the sequence of:
>
> action;
> if( test ) throw some_exception( parameters );
>
> could be rewritten as
>
> do {
> action;
> } while( !test && checked_throw( some_exception( parameters ) ) );
>
> where
>
> template <typename X> bool checked_throw( const X& x ) {
> if( !pre_exception(x) ) throw x;
> return false;
> }
>
> but it requires "action" to leave the system state unchanged
> whenever "test"
> is true at the end of it.

This solution seems to be cheaper at the first look, but it may turn out to
be very costly afterwards, because Wave has to provide the user supplied
function with all the information it may need to decide, what todo.

> This may be easy to achieve in some
> cases and hard in others;

Yeah, that's not always possible.

> aside from that, enough information
> has to be delivered to
> pre_exception() to undertake sensible actions which in all
> likelihood will require creating a separate exception class
> for each type of error or at least many of them.

Wouldn't make a lot of different exception types the overall error handling
a lot more difficult for the average user?

> After all, the easiest course may be to provide a default
> error recovery option for most errors.

Default error recovery is bad for two reasons:
- first of all it leads towards more weakness of Wave with regard to the
Standard as it makes it more forgiving. As it was pointed out already,
Wave's main focus is Standards compliance and it should report as much error
information as possible to the user.
- second, what seems to be a good default in one context may be a very bad
idea in others, i.e. undefining the first definition of a macro in case of a
redefinition and using the second definition provided may be useful for you,
others may want to keep the first definition and disregard the second one.

But I agree with you that Wave as a library should give the user the
possibility to recover from errors in a way it is appropriate to him/her.

> Which may not be all
> that bad: for macro re-definition, use the new definition;
> for #undefine unknown macro -- ignore etc. I guess your
> is_recoverable() mechanics is good enough for that already,
> as long as the default recovery actions are reasonable.

The question is: what is reasonable?

> Wave
> is a fairly specialized library and natural expectation is
> that it would be used by either C/C++ compilers or other
> applications working with C or C++ code in a way similar to a
> compiler (in my case -- a code instrumentation tool that
> attempts partial parsing of class definitions).

AFAIU compilers normally do not recover from errors in the sense that they
try to correct them. And that's for a good reason: compilers normally are
not to read the programmers minds, so they don't have enough information to
do the right thing :-P
Compilers simply report errors and try to continue from this point on
leaving the required corrections to the author of the source code.

> Thus any such
> code should benefit from handling preprocessor errors in the
> same exact way a typical C++ compiler would handle them.

That's correct, but normally doesn't involve any default error correction as
you suggested to do above.

Overall, I'm still not sure how to solve all these issues and I guess we
will have to take smaller steps first to get a feeling how to design a
generic error recovery scheme suitable for most of the needs a user of Wave
might have.

Thanks again!
Regards Hartmut


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net