Boost logo

Boost Users :

From: Hartmut Kaiser (hartmut.kaiser_at_[hidden])
Date: 2005-12-05 17:55:01


 
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


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