精灵x3如何将矢量添加到AST

时间:2017-07-09 02:41:00

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

我正在尝试解析文件并将数据复制到类对象中的向量中。我采用了员工的例子并将其修改为我正在尝试做的事情。正在解析的文件看起来像这样(但更多行)......

1 0.2 0.3 0.4

我已经为struct employee添加了一个向量,并且我在phrase_parse行上遇到了断言失败。

static assertion failed: Attribute does not have the expected size.
static_assert(
^

我有点认为预期的大小与矢量有关。关于我哪里出错的想法?​​

namespace client {
    namespace ast {

    struct employee
    {
        int id;
        std::vector<double> coords;
    };

    using boost::fusion::operator<<;
}}

BOOST_FUSION_ADAPT_STRUCT(
    client::ast::employee,
    (int, id)
    (std::vector<double>, coords)
)

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

        using x3::int_;
        using x3::double_;

        x3::rule<class employee, ast::employee> const employee = "employee";
        auto const employee_def =
             int_ >> double_ >> double_ >> double_;
        BOOST_SPIRIT_DEFINE(employee)
    }
}

int main()
{
    using boost::spirit::x3::ascii::space;
    using client::parser::employee;

    string fil("test-file.in");

    mapped_file_source map(fil);
    istringstream iss(map.data());
    map.close();

    client::ast::employee emp;

    boost::spirit::istream_iterator iter(iss >> noskipws), eof;

    phrase_parse(iter, eof, employee, space, emp);
    // failure on above line
}

1 个答案:

答案 0 :(得分:1)

根据文档,double_ >> double_ >> double_合成了double,double,double(所以fusion::tuple<double, double, double>fusion::list<double, double, double>等)的Fusion 序列

你想要一个向量,所以你需要一个重复的解析器(运算符)

  • repeat指令将执行repeat(3) [double_]
  • Kleene星(operator *)或加号(operator +)很有意思(但无限制)
  • 列表运算符(operator %)也是无界限的,但接受分隔符(例如double_ % ','

在这种情况下,我会采用另一种方式:使用适当的AST语法:

<强> Live On Coliru

struct coord {
    double x,y,z;
};

struct employee
{
    int id;
    coord coords;
};

调整它们比您使用的旧式方法更简单:

BOOST_FUSION_ADAPT_STRUCT(client::ast::coord, x, y, z)
BOOST_FUSION_ADAPT_STRUCT(client::ast::employee, id, coords)

解析器是干净的

auto const coord_def = double_ >> double_ >> double_;
auto const employee_def = int_ >> coord;

完整演示:

<强> Live On Coliru

#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <boost/fusion/adapted/struct.hpp>
#include <iostream>

namespace client {
    namespace ast {

    struct coord {
        double x,y,z;
    };

    struct employee
    {
        int id;
        coord coords;
    };

    using boost::fusion::operator<<;
}}

BOOST_FUSION_ADAPT_STRUCT(client::ast::coord, x, y, z)
BOOST_FUSION_ADAPT_STRUCT(client::ast::employee, id, coords)

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

        using x3::int_;
        using x3::double_;

        x3::rule<class employee, ast::coord>    const coord    = "coord";
        x3::rule<class employee, ast::employee> const employee = "employee";

        auto const coord_def = double_ >> double_ >> double_;
        auto const employee_def = int_ >> coord;

        BOOST_SPIRIT_DEFINE(employee, coord);
    }
}

int main()
{
    using boost::spirit::x3::ascii::space;
    using client::parser::employee;

    std::istringstream iss("1 0.2 0.3 0.4");

    client::ast::employee emp;

    boost::spirit::istream_iterator iter(iss >> std::noskipws), eof;

    bool ok = phrase_parse(iter, eof, employee, space, emp);
    if (ok)
        std::cout << "parsed: " 
             << emp.id       << " "
             << emp.coords.x << " "
             << emp.coords.y << " "
             << emp.coords.z << "\n";
}