1

I am currentl adding expectation points to my grammar in X3. Now I came accross an rule, which looks like this.

auto const id_string = +x3::char("A-Za-z0-9_);

auto const nested_identifier_def =
        x3::lexeme[
                *(id_string >> "::")
                >> *(id_string >> ".")
                >> id_string
        ];

I am wondering how I can add conditional expectation points to this rule. Like "if there is a "::" then there musst follow an id_string" or "when there is a . then there musst follow an id_string" and so on. How can I achieve such a behaviour for such a rule?

Mike Kinghan
  • 55,740
  • 12
  • 153
  • 182
Exagon
  • 4,798
  • 6
  • 25
  • 53
  • please provide an working example, http://ciere.com/cppnow15/x3_docs/spirit/quick_reference/operator.html you could use 'expect >' or validate with sematic actions and/or _pass() – Roby Aug 20 '16 at 11:58
  • I would like to avoid semantic actions and use the expectation operator > – Exagon Aug 20 '16 at 12:04
  • @Roby note x3 has the `x3::expect [ p ]` directive too, which helps if you want a rule to start with an expectation point (equivalent to `x3::eps > p`) – sehe Aug 20 '16 at 14:37
  • @sehe, oh wow, didn't find this in the documents (got in in the sources) - is there a updated version ? – Roby Aug 20 '16 at 14:52

1 Answers1

2

I'd write it exactly the way you intend it:

auto const identifier 
    = lexeme [+char_("A-Za-z0-9_")];

auto const qualified_id 
    = identifier >> *("::" > identifier);

auto const simple_expression // only member expressions supported now
    = qualified_id >> *('.' > identifier);

With a corresponding AST:

namespace AST {
    using identifier = std::string;

    struct qualified_id : std::vector<identifier> { using std::vector<identifier>::vector; };

    struct simple_expression {
        qualified_id lhs;
        std::vector<identifier> rhs;
    };
}

LIVE DEMO

Live On Coliru

#include <iostream>
#include <string>
#include <vector>

namespace AST {
    using identifier = std::string;

    struct qualified_id : std::vector<identifier> { using std::vector<identifier>::vector; };

    struct simple_expression {
        qualified_id lhs;
        std::vector<identifier> rhs;
    };
}

#include <boost/fusion/adapted.hpp>
BOOST_FUSION_ADAPT_STRUCT(AST::simple_expression, lhs, rhs)

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

namespace Parser {
    using namespace boost::spirit::x3;

    auto const identifier 
        = rule<struct identifier_, AST::identifier> {}
        = lexeme [+char_("A-Za-z0-9_")];

    auto const qualified_id 
        = rule<struct qualified_id_, AST::qualified_id> {}
        = identifier >> *("::" > identifier);

    auto const simple_expression // only member expressions supported now
        = rule<struct simple_expression_, AST::simple_expression> {}
        = qualified_id >> *('.' > identifier);
}

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

    for (std::string const input : { "foo", "foo::bar", "foo.member", "foo::bar.member.subobject" }) {
        It f = input.begin(), l = input.end();
        AST::simple_expression data;

        bool ok = phrase_parse(f, l, Parser::simple_expression, boost::spirit::x3::space, data);

        if (ok) {
            std::cout << "Parse success: ";
            for (auto& el : data.lhs) std::cout << "::" << el;
            for (auto& el : data.rhs) std::cout << "." << el;
            std::cout << "\n";
        }
        else {
            std::cout << "Parse failure ('" << input << "')\n";
        }

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

Prints

Parse success: ::foo
Parse success: ::foo::bar
Parse success: ::foo.member
Parse success: ::foo::bar.member.subobject
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Wow thank you very very much (again) this works perfect – Exagon Aug 20 '16 at 14:38
  • @sehe, could you explain the AST, specially the vector deriving and using part (and x3::forward_ast) – Roby Aug 20 '16 at 14:55
  • I'm not using forward ast. And the deriving was intended as a ["strong typedef"](http://stackoverflow.com/questions/28916627/strong-typedefs) to make _distinct types_ for `qualified_id` and `member_expression` (but I dropped the latter). The using is [c++11 inherited constructors](http://en.cppreference.com/w/cpp/language/using_declaration) – sehe Aug 20 '16 at 14:57