Avoid throwing expectation_failure when the expectation parser fails

How to avoid throwing an exception when the wait parser fails?

I have a rule "function" > (!x3::lexeme[keyword >> !(x3::alnum | '_')] >> symbol) > ('(' > -lvalue_list > ')') > statements > "end"

for parsing code:

function a() return one end

      

keyword

( zero

, one

, function

, return

, end

Etc.).

If I pass the parser with the code function one() return zero end

, then in the function an expect_directive::parse

exception is thrown here:

if (!r)
{
    boost::throw_exception(
        expectation_failure<Iterator>(
        first, what(this->subject)));
}

      

When that happens, I got it . The program ended unexpectedly. or Canceled (kernel dump) (depending on the terminal used).

When debugging gdb code is automatically terminated when the curly brace '}' is closed boost::throw_exception

with the message:

The inferior stopped because it received a signal from the Operating System.

Signal name : 
SIGABRT
Signal meaning : 
Aborted

      

When you go through the specified function step by step, you can see that the line throw enable_current_exception(enable_error_info(e));

is the last line executed before the signal. Why is there no stack search to find exception handlers? Why is the interrupt raised immediately (looks like it boost::throw_exception

has a specifier noexcept

)?

I have included a function call try { ... } catch (x3::expectation_failure< input_iterator_type > const & ef) { ... }

x3::phrase_parse

. x3::expectation_failure< input_iterator_type >

- this is exactly deduction from boost::throw_exception

. None of this matters.

Is there a way to completely throw the exception x3::expectation_failure

in Boost.Spirit X3, but still abort the parsing of the code altogether and make the wait fail x3::phrase_parse

to return false

?

My suspicions are as follows:

Due to the normal return value of parse()

the member function of all parsers (as a concept in X3) bool

, I suspect that there are only two ways to report a failure: the xor return exception code (which can only be true

or false

, but is true

already taken to report the results of a successful parsing Parse). This is inherent in the recursive implementation of top-down parsers in C ++. But if we change the type of the result parse

from bool

something wider, we can clearly or hard-communicate hard or soft errors (or whatever) during parsing โ€” with different return code values.

+3


source to share


1 answer


You cannot avoid throwing a wait when using a wait parser. This is the purpose of this operator.

Use operator>>

for "tracked expectations" (ie alternatives).

When you use waitpoints ( operator>

), just handle the exception too.

Note This looks like a typo

('(' > -lvalue_list > '>')

      

it should be

('(' > -lvalue_list > ')')

      

Also return one end

does not match "begin" >> statements >> "end"

whatever is statements

defined as ...

Fixing things:

Live With Rule Debugging (C ++ 14 only)

#define BOOST_SPIRIT_X3_DEBUG
#include <iostream>
#include <boost/spirit/home/x3.hpp>

namespace SO {
    namespace x3 = boost::spirit::x3;

    x3::symbols<char> const keyword = []{
        x3::symbols<char> kw;
        kw += "for","begin","end","function","while","break","switch";
        return kw;
    }();

    x3::rule<struct symbol_tag>      const symbol     ("symbol");
    x3::rule<struct identifier_tag>  const identifier ("identifier");
    x3::rule<struct lvalue_list_tag> const lvalue_list("lvalue_list");
    x3::rule<struct statements_tag>  const statements ("statements");
    x3::rule<struct rule_tag>        const rule       ("rule");

    auto symbol_def      = x3::lexeme[x3::alnum >> *(x3::alnum | '_')];
    auto identifier_def  = (!(x3::lexeme[keyword >> !(x3::alnum | '_')]) >> symbol);
    auto lvalue_list_def = identifier % ',';
    auto statements_def  = *identifier;
    auto rule_def        = "function"
                     >> identifier
                     >> ('(' > -lvalue_list > ')')
                     >> ("begin" > statements > "end")
                     ;

    BOOST_SPIRIT_DEFINE(symbol, identifier, lvalue_list, statements, rule)
}

int main() {
    std::string const sample = "function a() begin return one end";
    auto f = sample.begin(), l = sample.end();

    bool ok = phrase_parse(f, l, SO::rule, SO::x3::space);
    if (ok)
        std::cout << "Parse success\n";
    else
        std::cout << "Parse failed\n";

    if (f!=l)
        std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}

      

Printing



<rule>
  <try>function a() begin r</try>
  <identifier>
    <try> a() begin return on</try>
    <symbol>
      <try> a() begin return on</try>
      <success>() begin return one </success>
    </symbol>
    <success>() begin return one </success>
  </identifier>
  <lvalue_list>
    <try>) begin return one e</try>
    <identifier>
      <try>) begin return one e</try>
      <symbol>
        <try>) begin return one e</try>
        <fail/>
      </symbol>
      <fail/>
    </identifier>
    <fail/>
  </lvalue_list>
  <statements>
    <try> return one end</try>
    <identifier>
      <try> return one end</try>
      <symbol>
        <try> return one end</try>
        <success> one end</success>
      </symbol>
      <success> one end</success>
    </identifier>
    <identifier>
      <try> one end</try>
      <symbol>
        <try> one end</try>
        <success> end</success>
      </symbol>
      <success> end</success>
    </identifier>
    <identifier>
      <try> end</try>
      <fail/>
    </identifier>
    <success> end</success>
  </statements>
  <success></success>
</rule>
Parse success

      

No debugging

It's much easier:

Live On Coliru (g ++ / clang ++)

#include <boost/spirit/home/x3.hpp>
#include <iostream>

int main() {
    namespace x3 = boost::spirit::x3;

    x3::symbols<char> keyword;
    keyword += "for","begin","end","function","while","break","switch";

    static auto symbol      = x3::lexeme[x3::alnum >> *(x3::alnum | '_')];
    static auto identifier  = (!(x3::lexeme[keyword >> !(x3::alnum | '_')]) >> symbol);
    static auto lvalue_list = identifier % ',';
    static auto statements  = *identifier;
    static auto rule        = "function"
                            >> identifier
                            >> ('(' > -lvalue_list > ')')
                            >> ("begin" > statements > "end")
                            ;

    std::string const sample = "function a() begin return one end";
    auto f = sample.begin(), l = sample.end();

    bool ok = phrase_parse(f, l, rule, x3::space);
    if (ok)
        std::cout << "Parse success\n";
    else
        std::cout << "Parse failed\n";

    if (f!=l)
        std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}

      

Just prints

Parse success

      


ยน And just to show that it can handle waiting failures just fine: Handling waiting failures

+4


source







All Articles