2

To keep it simple let's say I need to parse A followed by B

I don't mean the letter, of course, A and B could be (qi::char_), or (qi::char_('$') | qi::char_('_') | ascii::alpha), or whatever.

so:

rule = A >> B;

Problem is that if B fails, rule doesn't fail, I get A. I tried with +B but the result was the same. And:

rule = A > B;

Throws and exception if it fails.

UPDATE: I edited this question to explain that the above statements are false (as user sehe proved), I believed that the rule wasn't failing because when I tried to:

auto A = qi::copy(qi::char_("$") | qi::alpha);
auto B = qi::copy(qi::char_("z"));
auto C = qi::copy(qi::string("$x"));
std::string s1 = "$x";
std::string s2 = "";
qi::parse(s1.begin(), s1.end(), (A >> B) | C, s2);

I would get that s2="$$x" , so I thought that A was not failing. Now I know that this is a different problem. But the rule does fail.

kaladin
  • 55
  • 4
  • SO is well suited for focused questions. You combine many questions (in fact, more unbased assertions) and only hide your true goal in the last paragraph. That's not useful for future user of the site. (I suggest removing the unneeded noise from the question and expanding on the thing you want to achieve) – sehe Jul 15 '15 at 23:07
  • I think that [`qi::hold`](http://www.boost.org/libs/spirit/doc/html/spirit/qi/reference/directive/hold.html) may help you with the problem in your update (`qi::hold[A >> B] | C`). – llonesmiz Jul 16 '15 at 20:16

1 Answers1

2

Q. Problem is that if B fails, rule doesn't fail, I get A

A. That's not true, see extensive demo below


Q. it could be followed by E, but I don't want to get CE

A. In the test cases below look for positive assertion (C >> &E would do here)


This is because I'm trying to parse keywords and identifiers, so int is a keyword, int4 is identifier. Therefore keyword is a string I define that is not followed by digits or letters. Any idea?

Yes, see:

Live Coliru

#include <boost/spirit/include/qi.hpp>

namespace qi = boost::spirit::qi;

template <typename Grammar>
bool check(Grammar const& g, std::string const& input, qi::unused_type) {
    auto f = input.begin(), l = input.end();
    try {
        return qi::parse(f, l, g);
    } catch(...) {
        return false;
    }
}

template <typename Grammar, typename Skipper>
bool check(Grammar const& g, std::string const& input, Skipper const& s) {
    auto f = input.begin(), l = input.end();
    try {
        return qi::phrase_parse(f, l, g, s);
    } catch(...) {
        return false;
    }
}

#define REPORT(g, i, s, expect) do { assert(expect == check(g, i, s)); } while(0)
#define SHOULD_WORK(g, i, s) REPORT(g, i, s, true)
#define SHOULD_FAIL(g, i, s) REPORT(g, i, s, false)

template <typename Skipper = qi::unused_type>
void do_all_tests(Skipper const& s = Skipper()) {

    auto A = qi::copy(qi::char_("$_") | qi::alpha);
    auto B = qi::copy(qi::char_("z"));

    // using skipper:
    SHOULD_WORK(A >> B , "$z", s);
    SHOULD_FAIL(A >> B , "$.", s);
    SHOULD_FAIL(A >> B , "$" , s);

    SHOULD_WORK(A  > B , "$z", s);
    SHOULD_FAIL(A  > B , "$.", s);
    SHOULD_FAIL(A  > B , "$" , s);

    // positive assertion (does not consume B)
    SHOULD_WORK(A >> &B, "$z", s);
    SHOULD_FAIL(A >> &B, "$.", s);
    SHOULD_FAIL(A >> &B, "$" , s);

    SHOULD_WORK(A  > &B, "$z", s);
    SHOULD_FAIL(A  > &B, "$.", s);
    SHOULD_FAIL(A  > &B, "$" , s);

    // negative assertion:
    SHOULD_FAIL(A >> !B, "$z", s);
    SHOULD_WORK(A >> !B, "$.", s);
    SHOULD_WORK(A >> !B, "$" , s);

    SHOULD_FAIL(A  > !B, "$z", s);
    SHOULD_WORK(A  > !B, "$.", s);
    SHOULD_WORK(A  > !B, "$" , s);

}

int main() {
    do_all_tests(qi::unused); // no skipper
    do_all_tests(qi::space);
    std::cout << "All tests succeeded\n";
}

Prints

All tests succeeded
Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Expanded my answer to address all the questions and use-cases you had in the question. – sehe Jul 15 '15 at 23:06