X3:如何创建解析器以读取集合? [英] X3: How to create parser to read in sets?

查看:100
本文介绍了X3:如何创建解析器以读取集合?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何创建一个规则,以读取3组中的整数,即...

How would one create a rule for reading integers in sets of 3. I.e., ...

1 2 3                   OK, 1 set of 3 ints
1 2 3 4 5 6             OK, 2 sets of 3 ints
1 2 3 4 5               ERROR, 1 set of 3 ints, 1 short for 2nd
1 2 3 4 5 6 7 8 9       OK, 3 sets of 3 ints
1 2 3 4 5 6 7 8 9 10    ERROR, 3 sets of 3 ints, 1 short for 4th

我在融合适应结构上有问题(如何使args的数量可变)...

I'm having issue with the fusion adapt struct (how to make the number of args variable) ...

BOOST_FUSION_ADAPT_STRUCT(client::ast::number, n1, n2, n3, n4, n5, n6)

并且不确定为什么该规则不起作用.

And not sure why this rule wouldn't work.

... = *(int_ >> int_ >> int_);

这是我的尝试... http://coliru.stacked-crooked.com/a/cb10e8096c95fc55

Here's my attempt ... http://coliru.stacked-crooked.com/a/cb10e8096c95fc55

//#define BOOST_SPIRIT_X3_DEBUG
#include <iostream>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>

namespace client { 
    namespace ast {

        struct number {
            int n1, n2, n3, n4, n5, n6;
        };

        struct comment {
            std::string text;
            bool dummy;
        };

        struct input {
            std::vector<comment> comments;  
            std::vector<number> numbers;
        };
    } 
}

BOOST_FUSION_ADAPT_STRUCT(client::ast::comment, text, dummy)
BOOST_FUSION_ADAPT_STRUCT(client::ast::number, n1, n2, n3) // , n4, n5, n6) error
BOOST_FUSION_ADAPT_STRUCT(client::ast::input, comments, numbers)

namespace client {      
    namespace parser {

        namespace x3 = boost::spirit::x3;
        using namespace x3;

        typedef std::string::const_iterator It;

        using namespace x3;

        auto const comment = rule<struct _c, ast::comment> {"comment"} = lexeme[*(char_ - eol)] >> attr(false);
        auto const number  = rule<struct _n, ast::number> {"number"}   = int_ >> int_ >> int_;
        // auto const number  = rule<struct _n, ast::number> {"number"}   = *(int_ >> int_ >> int_); error

        auto lines = [](auto p) { return *(p >> eol); };

        auto const input = 
            repeat(1)[comment] >> eol >>
            lines(number);
    }
}

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

    std::string const iss("any char string here\n1 2 3\n1 2 3 4 5 6");

    auto iter = iss.begin(), eof = iss.end();

    client::ast::input types;

    bool ok = phrase_parse(iter, eof, client::parser::input, x3::blank, types);

    if (iter != eof) {
        std::cout << "Remaining unparsed: '" << std::string(iter, eof) << "'\n";
    }
    std::cout << "Parsed: " << (100.0 * std::distance(iss.begin(), iter) / iss.size()) << "%\n";
    std::cout << "ok = " << ok << std::endl;

    for (auto& item : types.comments) { std::cout << "comment: " << boost::fusion::as_deque(item) << "\n"; }
    for (auto& item : types.numbers)  { std::cout << "number:  " << boost::fusion::as_deque(item) << "\n"; }
}

打印

Parsed: 71.0526%
ok = 1
comment: (any char string here 0)
number:  (1 2 3)

推荐答案

操作员Kleene-star合成到一个容器属性中(文档显示:vector<T>)

Operator Kleene-star synthesizes into a container attribute (docs show: vector<T>)

您的结构number不是容器属性.是这样.

Your struct number is not a container attribute. So.

此外,我还不清楚您要实现什么目标.您的结构应该是6个整数,但您想解析3个组?这些组的含义是什么?我可能会这样做:

Also, it's completely unclear to me what you want to achieve. Your struct is supposedly 6 ints, but you want to parse groups of 3? What is the meaning of the groups? I'd probably do:

struct number {
    struct group { int n1, n2, n3; };
    std::vector<group> groups;
};

BOOST_FUSION_ADAPT_STRUCT(client::ast::number::group, n1, n2, n3)
BOOST_FUSION_ADAPT_STRUCT(client::ast::number, groups)

然后与解析器表达式兼容

This then is compatible with the parser expression

 *(int_ >> int_ >> int_)

实时演示

两个注意事项:

Live Demo

Two notes:

  1. 需要再次使用假人服装(请考虑using number = std::vector<number_group>;)
  2. 输入末尾缺少\n(请考虑eol | eoi)
  1. the dummy attibrute was needed again (consider using number = std::vector<number_group>;)
  2. there was a missing \n at the end of input (consider eol | eoi)

在Coliru上直播

//#define BOOST_SPIRIT_X3_DEBUG
#include <iostream>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>

namespace client { 
    namespace ast {

        struct number {
            struct group { int n1, n2, n3; };
            std::vector<group> groups;
            bool dummy;
        };

        struct comment {
            std::string text;
            bool dummy;
        };

        struct input {
            std::vector<comment> comments;  
            std::vector<number> numbers;
        };
    } 
}

BOOST_FUSION_ADAPT_STRUCT(client::ast::comment, text, dummy)
BOOST_FUSION_ADAPT_STRUCT(client::ast::number::group, n1, n2, n3)
BOOST_FUSION_ADAPT_STRUCT(client::ast::number, groups, dummy)
BOOST_FUSION_ADAPT_STRUCT(client::ast::input, comments, numbers)

namespace client {      
    namespace parser {

        namespace x3 = boost::spirit::x3;
        using namespace x3;

        typedef std::string::const_iterator It;

        using namespace x3;

        auto const comment = rule<struct _c, ast::comment> {"comment"} = lexeme[*(char_ - eol)] >> attr(false);
        auto const number  = rule<struct _n, ast::number> {"number"}   = *(int_ >> int_ >> int_) >> attr(false);

        auto lines = [](auto p) { return *(p >> eol); };

        auto const input = 
            repeat(1)[comment] >> eol >>
            lines(number);
    }
}

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

    std::string const iss("any char string here\n1 2 3\n1 2 3 4 5 6\n");

    auto iter = iss.begin(), eof = iss.end();

    client::ast::input types;

    bool ok = phrase_parse(iter, eof, client::parser::input, x3::blank, types);

    if (iter != eof) {
        std::cout << "Remaining unparsed: '" << std::string(iter, eof) << "'\n";
    }
    std::cout << "Parsed: " << (100.0 * std::distance(iss.begin(), iter) / iss.size()) << "%\n";
    std::cout << "ok = " << ok << std::endl;

    for (auto &item : types.comments) {
        std::cout << "comment: " << boost::fusion::as_deque(item) << "\n";
    }
    for (auto& item : types.numbers) {
        std::cout << "number:  ";
        for (auto& g : item.groups)
            std::cout << boost::fusion::as_deque(g) << " ";
        std::cout << "\n";
    }
}

打印

Parsed: 100%
ok = 1
comment: (any char string here 0)
number:  (1 2 3) 
number:  (1 2 3) (4 5 6) 

这篇关于X3:如何创建解析器以读取集合?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆