3

My grammar has various entries which start with a generic name. After I determined the type I would like to use the expectation operator in order to create parsing errors.

rule1=name >> (type1 > something);
rule2=name >> (type2 > something);

I already figured that I cannot mix the two operators > and >> -- that's why the parenthesis. My guess is that the parenthesis causes a tuple to be created. How do I access the elements of the tuple in the semantic action? The following is certainly wrong but should clarify what I want to accomplish.

rule1=(name >> (type1 > something))[qi::_val = boost::phoenix::bind(
    create,
    qi::_1,
    std::get<0>(qi::_2), 
    std::get<1>(qi::_2))];

thanks

sehe
  • 374,641
  • 47
  • 450
  • 633

1 Answers1

2

Directly addressing the question:

using px::at_c;
rule1 = (name >> (type1 > something)) [_val = px::bind(create, _1, at_c<0>(_2), at_c<1>(_2))];

However, I'd use this little trick with qi::eps to avoid the complexity:

rule2 = (name >> type1 >> (eps > something)) [_val = px::bind(create, _1, _2, _3)];

Finally, look at boost::phoenix::function<>:

px::function<decltype(&create)> create_(create); // or just decltype(create) if it's a function object
rule3 = (name >> type1 >> (eps > something)) [_val = create_(_1, _2, _3)];

That way you can even have readable code!

DEMO

Just to prove that all three have the same behaviour¹

Live On Coliru

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/include/at_c.hpp>

namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;

static int create(char n, char t, char s) {
    assert(n=='n' && t=='t' && s=='s');
    return 42;
}

int main() {
    using It = std::string::const_iterator;

    // fake rules just for demo
    qi::rule<It, char()>
        name = qi::char_("n"),
        type1 = qi::char_("t"),
        something = qi::char_("s");

    //using boost::fusion::at_c;
    qi::rule<It, int(), qi::space_type> rule1, rule2, rule3;

    {
        using namespace qi;
        using px::at_c;

        rule1 = (name >> (type1 > something))        [_val = px::bind(create, _1, at_c<0>(_2), at_c<1>(_2))];
        rule2 = (name >> type1 >> (eps > something)) [_val = px::bind(create, _1, _2, _3)];

        px::function<decltype(&create)> create_(create); // or just decltype(create) if it's a function object
        rule3 = (name >> type1 >> (eps > something)) [_val = create_(_1, _2, _3)];
    }

    for(auto& parser : { rule1, rule2, rule3 }) {
        for(std::string const input : { "n t s", "n t !" }) {
            std::cout << "Input: '" << input << "'\n";
            auto f = input.begin(), l = input.end();
            int data;

            try {
                bool ok = qi::phrase_parse(f, l, parser, qi::space, data);
                if (ok) {
                    std::cout << "Parsing result: " << data << '\n';
                } else {
                    std::cout << "Parsing failed\n";
                }
            } catch(qi::expectation_failure<It> const& e) {
                std::cout << "Expectation failure: " << e.what() << " at '" << std::string(e.first, e.last) << "'\n";
            }

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

            std::cout << "-------------------------------------------\n";
        }
    }
}

Which prints 3x the same output:

Input: 'n t s'
Parsing result: 42
-------------------------------------------
Input: 'n t !'
Expectation failure: boost::spirit::qi::expectation_failure at '!'
Remaining unparsed: 'n t !'
-------------------------------------------
Input: 'n t s'
Parsing result: 42
-------------------------------------------
Input: 'n t !'
Expectation failure: boost::spirit::qi::expectation_failure at '!'
Remaining unparsed: 'n t !'
-------------------------------------------
Input: 'n t s'
Parsing result: 42
-------------------------------------------
Input: 'n t !'
Expectation failure: boost::spirit::qi::expectation_failure at '!'
Remaining unparsed: 'n t !'
-------------------------------------------

¹ PS let this serve as an example of how to create a SSCCE code example in your questions

sehe
  • 374,641
  • 47
  • 450
  • 633