Max Motovilov wrote:
You hit the nail on the head (like we Germans say). Wave currently doesn't really support error recovery. The main focus of Wave was conformance and not usability. Adding error recovery is one of my high priority tasks for Wave, but I'm not sure yet how to design this.
Perhaps you could give me some insight into what is going on within Wave context when an error condition arises? Currently I am only interested in very common situtations, perhaps macro re-definition IS the only error recovery case I'll ever need to support. I was thinking along the lines of last_known_good paradigm but as I have absolutely no idea whether all necessary state information is indeed copied along with an iterator and which methods trigger the next_token() step, I can't do it in an intelligent way. I guess, my questions to you would be:
The iterators carry _all_ of the context information, so from this point of view I don't expect any difficulties. The problems I'm not able to disgust currently is how to _reliably_ find a synchronisation point where the preprocessor has to be restarted.
- Is there any way to return the state of the Wave context back to a specific position? I probably don't even care much if such an operation would be expensive since error conditions like that are relatively rare in real C++ code, as long as it is not as expensive as restarting the parsing from the beginning.
- Which methods cause next_token() to be called? operator ==/!=, operator*, operator++? Only some of them?
It's in the operator!=() and operator++(). So most, if not all of the exceptions are generated here.
- Also, it would be nice if I could extract the cause of error at the point where an exception is caught, but it looks like the current codebase doesn't preserve the error itself, only severity. It would be enough for me to know that the last two tokens consumed were <#define> and <Identifier> but since those are processed by the Wave itself I will not know about it. So, any suggestions how I could determine that the cause of error was indeed macro re-definition?
That's a very good point. I've added it to the exception classes.
A bit of background: I am trying to use Wave for a small project that might or might not grow into something useful [e.g. for Boost] and am in no way pressed for time, so if you think you might be able to answer some of these concerns later, in subsequent versions of Wave, please let me know. Also I am perfectly willing to try out any of the alpha quality (or worse :) ) code you might be developing. My platform for this project is Visual C++ 8.0 (VStudio 2005), I don't plan to port it elsewhere until I decide the whole thing I am trying to put together is indeed worthwhile.
Understood. Generally Wave issues two different types of errors: - errors occuring during a processing step not generating tokens on the context::iterator level. For example the macro redefinition errors you are interested in belong to this group of errors. It is quite easy to handle these. Just use the following code snippet instead of the simple "while (first != last) { ++first; }" loop. The following snippet is taken from the wave driver, where I've implemented the new techniques: // loop over all generated tokens outputting the generated text bool finished = false; do { try { while (first != last) { // store the last known good token position current_position = (*first).get_position(); // print out the current token value output << (*first).get_value(); // advance to the next token ++first; } finished = true; } catch (boost::wave::cpp_exception const &e) { // some preprocessing error cerr << e.file_name() << "(" << e.line_no() << "): " << e.description() << endl; } } while (!finished); - errors occuring during processing of language constructs supposed to produce tokens on the context::iterator level. A good example for this are errors occuring during macro expansion. It is a lot harder to recover from these errors. The solution given above will not always work in this case. As a first simple attempt I've added a function bool is_recoverable(cpp_exception const&) giving back, whether it is possible to recover using the solution above. This allows to write catch (boost::wave::cpp_exception const &e) { // some preprocessing error if (boost::wave::is_recoverable(e)) { cerr << e.file_name() << "(" << e.line_no() << "): " << e.description() << endl; } else { throw; } } Certainly you will have to add an addditional catch clause outside of the loop. BTW, most of the thrown exceptions are recoverable (that was a surprise for me). Please note, that lexing_exception's are currently non-recoverable, because there is no destinction where these were thrown from. HTH Regards Hartmut