boost.spirit x3 move_to并列出ast成员

时间:2017-04-17 18:16:12

标签: c++ boost boost-spirit-x3

我实施的BNF有一个有趣的规则,根据运营商的说法,这些条款可以被链接或不属于此生产规则的事件。因此,我使用相同的AST数据结构,因为只有枚举更改:

#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;
}

这就是想法 - 操作员X,Y,Z只添加一个块列表。在编译器错误之后,我必须专门化x3 :: traits :: move_to,但是我没有找到任何解决方案来编译它。有什么方法可做?列表:: emplace()和std :: move()在这里安全吗?

1 个答案:

答案 0 :(得分:0)

我没有这个特质。相反,使用vector<T>

人工制作语法结果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 ]
    ;