1

the BNF I implement has a funny rule where, depending on operator, the terms can be chained or event not at this production rule. Hence I use the same AST data structure since only the enumeration changes:

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

#include <iostream>
#include <string>
#include <list>


namespace ast
{
    struct identifer {
        int                     name;
    };
    struct expression {
        struct chunk {
            char                operator_;
            ast::identifer      identifer;
        };
        ast::identifer          identifer;
        std::list<chunk>        chunk_list;
    };
}

BOOST_FUSION_ADAPT_STRUCT(ast::identifer,
    name
)

BOOST_FUSION_ADAPT_STRUCT(ast::expression::chunk,
    operator_, identifer
)

BOOST_FUSION_ADAPT_STRUCT(ast::expression,
    identifer, chunk_list
)


namespace boost { namespace spirit { namespace x3 { namespace traits {


void move_to(ast::expression::chunk&& chunk, std::list<ast::expression::chunk>& chunk_list,
        mpl::identity<container_attribute>)
{
    chunk_list.emplace(chunk_list.end(), std::move(chunk));
}

} } } }


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

    auto const identifier = x3::rule<struct _, int> { "identifier" } =
        x3::int_;

    auto const operator_1 = x3::rule<struct _, char> { "operator" } =
        x3::char_("ABC");
    auto const operator_2 = x3::rule<struct _, char> { "operator" } =
        x3::char_("XYZ");

    auto const expression_chunk_1 = x3::rule<struct _, ast::expression::chunk> { "expression" } =
        operator_1 > identifier
        ;
    auto const expression_chunk_2 = x3::rule<struct _, ast::expression::chunk> { "expression" } =
        operator_2 > identifier
        ;
    auto const expression = x3::rule<struct _, ast::expression> { "expression" } =
          identifier >> *expression_chunk_1 // foo { and  foo }
        // rule below fails to compile
        | identifier >>  expression_chunk_2 // foo [ nand foo ]
        ;
}


struct visitor {
    visitor(std::ostream& os) : os{ os } { }
    void operator()(ast::expression const& node) {
        os << "(";
        (*this)(node.identifer);
        for(auto const& chunk : node.chunk_list) {
            os << "(" << chunk.operator_ << " ";
            (*this)(chunk.identifer);
            os << ")";
        }
        os << ")\n";
    }
    void operator()(ast::identifer const& node) {
        os << "(" << node.name << ")";
    }
    std::ostream& os;
};


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

    for(std::string const str: {
        "1 X 2",
        "3 A 4 A 5"
    }) {
      auto iter = str.begin(), end = str.end();

      ast::expression attr;
      bool r = x3::phrase_parse(iter, end, parser::expression, x3::space, attr);

      std::cout << "parse '" << str << "': ";
      if (r && iter == end) {
        std::cout << "succeeded:\n";
        visitor(std::cout)(attr);

      } else {
        std::cout << "*** failed ***\n";
      }
    }

    return 0;
}

This was the idea - the operator X,Y,Z adds only one chunk to list. Following the compiler errors, I have to specialize x3::traits::move_to, but I don't found any solution to get this to compile. What is the wayy to do? is the list::emplace() and std::move() safe here?

Olx
  • 163
  • 8

1 Answers1

0

I'd do without the trait. Instead, make the grammar result in a vector<T> artificially using repeat:

auto const expression = x3::rule<struct _, ast::expression> { "expression" } =
      identifier >> *expression_chunk_1 // foo { and  foo }
    | identifier >> x3::repeat(1) [ expression_chunk_2 ] // foo [ nand foo ]
    ;
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Thank you - a pragamtic way to solve the problem. These solution compiles as shown at [link](http://coliru.stacked-crooked.com/a/898343ea7611a40a) but parsing failed. There are small only changes (identifier is a char now, rules have unique names). It is abvious by running with ...DEBUG, that the identifier is consumed and expression_chunk_1 must fail. One (possible) way would be to write – Olx Apr 20 '17 at 09:12
  • If you tell me the expected outcome for `"1 X 2"` you can ask about that in a new question, I think. I saw that wouldn't pass, but looking at it I saw no reason why it should pass the grammar. – sehe Apr 20 '17 at 09:13
  • a pragamtic way to solve the problem. These solution compiles as shown at [link](http://coliru.stacked-crooked.com/a/898343ea7611a40a) but parsing failed. There are small only changes (identifier is a char now, rules have unique names). It is abvious by running with ...DEBUG, that the identifier is consumed and expression_chunk_1 must fail. One (possible) way would be to write (identifier >> *expression_chunk_1) | (identifier >> x3::repeat(1)[expression_chunk_2]) but this not clever due to backtracing/unwinding the iterator for the identifier. Follow next comment ... – Olx Apr 20 '17 at 09:25
  • ah, I see ... First time I use stackoverflow (and pressed ENTER to fast) and the limitations in editing here ... I will open a new topic. – Olx Apr 20 '17 at 09:27
  • ... or maybe related here again: Hence I rewrote the subrules to with std::list attribute and use the alternative in the real expression rule like here: [link](http://coliru.stacked-crooked.com/a/f31f59923b694a02) and run into a similar compile error. I assume, that X3 flattens the attribute correct for `expression_chunk_1` to a list. Isn't it? How to continue here? – Olx Apr 20 '17 at 09:29
  • I'm sorry but I lost the goal here. I'd be willing to look at it as a new question though – sehe Apr 20 '17 at 09:30