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.
That's what I thought -- ultimately, the recovery may require access to (and what's even worse -- understanding of, on part of the Wave's user) large parts of Wave context. There may be some compromise point though -- to make the whole mechanism more useful, if not perfectly generic.
Wouldn't make a lot of different exception types the overall error handling a lot more difficult for the average user?
I tend to disagree with the idea of an "average" user ever using Wave for two reasons: first, writing any kind of C++-source-code-processing application is a fairly advanced activity, not undertaken lightly; and second, just setting up a "hello world" app with Wave is already nontrivial, especially if one wants his compile times to be shorter than the respective lunch break. Of course it is possible to start with one of your boilerplates but that's not generally a good approach to mastery of a tool (as legions of "MFC" programmers have so profoundly demonstrated! :-) ). It took me a long evening that rolled over into a medium-sized weekend session to get the Wave driver-like project to work from scratch; my usual ramp-up time on a new Boost library (Spirit EXCEPTED!!!) is half an hour. I guess what I am trying to say is adding a few more class names to Wave shouldn't change the complexity side of the equation too much.
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.
I agree that "default error recovery turned on by default" is a bad idea. However, a "default error recovery policy" -- default in a sense that Wave implements it itself requiring from the user only to turn it on -- may be OK, wherever such policy is indeed default or well accepted in existing C/C++ preprocessors.
The question is: what is reasonable?
At risk of repeating myself ;-) I'll say -- whatever most C/C++ preprocessors do by default or can be coaxed into doing by command-line options is probably reasonable. While you state Wave's primary purpose as being a benchmark for standard-conformal preprocessor functionality, I still suspect that most practical uses will require it to work with existing code. And if some bad practices prevail in the existing code, the tool maker often has to provide an option of supporting them in some way, just to make his tool more useful. Note how Micro$oft still preserves an option for non-conformant visibility of loop control variable names (even though they finally changed the default to OFF in 8.0).
AFAIU compilers normally do not recover from errors in the sense that they try to correct them.
That's only 99% true, I think. There's a degree of tolerance present everywhere, which usually shows up in discouraging, but not outright prohibiting certain practices either at the compiler level or even at the language definition level (like, support for "implicit int" names which is prohibited by C++ standard, or using base class names without an access tag which is still allowed though switched meanings from public to private at a certain point in time). I'd say that ability to re-define macro names falls squarely within that 1% -- from the times when I was actively concurrently working with a large number of C++ compilers on various platforms, I can't remember a single one that would fully prohibit the practice or produced different results. There may not be all that many of those "accepted errors" at preprocessor level, but being able to support them appears to be a clear plus... Oh, and I don't think I ever remembered to thank you for coming up with Wave in the first place! True, it is possible to use an available C++ preprocessor on the front end of a C++ code-analyzing tool but having a _library_ to do it, along with the lexical analysis, is a whole lot less messier -- especially outside of the Unix environment (read in Win*) where having to string together multiple executables into a pipe may bring along some undesirable externalities. Regards, ...Max...