Boost logo

Boost :

From: Juan Carlos Arevalo-Baeza (jcab.lists_at_[hidden])
Date: 2002-10-20 15:13:10


On Sun, 20 Oct 2002 13:15:58 -0600, Larry Evans wrote:

>>Try the cpp_grammar test/thingy that I have here:
>>
>>http://home.JCABs-Rumblings.com/ftp/SpiritX/
>
>This looks great.  What about the possibility of resynchronizing the
>input for the next error message?  There are some methods like skipping
>all input to the next, for example, closing paren or curly brace before
>restarting the parse.  The purpose of these is to diagnose as many mistakes
>as possible.  Does anybody have any ideas about doing this next?

   Yes. Look at the error_handler functor in the C++ grammar above. Basically, it looks like this:

struct error_handler {
    template <typename ScannerT, typename ErrorDescrT>
    error_status<>
    operator()(ScannerT const& scan,
               parser_error<ErrorDescrT,
                   typename ScannerT::iterator_t
> const& error) const
    {
        file_position lc = FindFinalLineColumn(error.where);
        cout << "\n" << lc << "Error: " << error.what << "\n";
        return error_status<>(error_status<>::fail);
    }
};

   You'd need to add another one that knows how to store and use a skip parser, it would look like this:

tenmplate < typename SkipperT >
struct skip_error_handler {
    SkipperT skipper;
    skip_error_handler(SkipperT const& skipper_): skipper(skipper_) {}
    template <typename ScannerT, typename ErrorDescrT>
    error_status<>
    operator()(ScannerT const& scan,
               parser_error<ErrorDescrT,
                   typename ScannerT::iterator_t
> const& error) const
    {
        file_position lc = FindFinalLineColumn(error.where);
        if (skipper.parse(scan)) {
            cout << "\n" << lc << "Error: " << error.what << "\n";
            return error_status<>(error_status<>::accept);
        } else {
            return error_status<>(error_status<>::rethrow);
        }
    }
};

   And then, you'd declare an error skipper parser such as:

template < typename ParserT, typename SkipperT >
struct error_skipper_parser: parser<error_skipper_parser<ParserT, SkipperT> > {
    typedef error_skipper_parser<ParserT, SkipperT> self_t;

    ParserT parser;
    SkipperT skipper;
    error_skipper_parser(ParserT const& parser_, SkipperT const& skipper_):
        parser(parser_), skipper(skipper_) {}

    template < typename ScannerT >
    struct result {
        typedef typename parser_result<ParserT, ScannerT>::type type;
    }

    template <typename ScannerT>
    typename parser_result<self_t, ScannerT>::type
    parse(ScannerT const& scan) const;
        return cpp_guard(parser)[skip_error_handler(skipper)].parse(scan);
    }
};

   And now you can use this through a generator to make it easy. This is a simple one. You could make more complex but nicer looking ones (using operator[] and such):

template < typename ParserT, typename SkipperT >
error_skipper_parser<ParserT, SkipperT>
error_skipper_p(ParserT const& parser_, SkipperT const& skipper_)
{
    return error_skipper_parser<ParserT, SkipperT>(parser_, skipper_);
}

   A simple example of use:

rule_t case_label =
    KWD_CASE >> error_skipper_p(
        expression >> OP_COLON,
        anychar_p >> OP_COLON
    );

   a case label is "case <expression> :", and if the expression fails parsing, then skip until the colon, report the error and continue.

   This code is untested, but it should work almost without changes.

   Also note that, with the typeof extension (or actually researching the complete type, but that's painful), the skipper_error_parser is not needed:

template < typename ParserT, typename SkipperT >
typeof(cpp_guard(parser)[skip_error_handler(skipper)])
error_skipper_p(ParserT const& parser_, SkipperT const& skipper_)
{
    return cpp_guard(parser)[skip_error_handler(skipper)];
}

   How's that for another reason to keep it? Or even to provide a mechanism, similar to the proposed "auto" extension, to eliminate the redundancy? I'd propose something like macro functions:

template < typename ParserT, typename SkipperT >
auto error_skipper_p(ParserT const& parser_, SkipperT const& skipper_)
    = cpp_guard(parser)[skip_error_handler(skipper)];

   But I digress...

   Salutaciones,
                    JCAB
email: jcab_at_[hidden]
ICQ: 10913692 @WORK: 101728263
WWW: http://www.JCABs-Rumblings.com


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk