从逗号分隔的整数解析std :: vector <int>

时间:2017-02-12 18:49:41

标签: c++ c++11 dsl boost-spirit boost-spirit-qi

我试图实现一个非常具体的语法,这需要我在某个点解析逗号分隔的整数列表。 qi规则如下所示:

qi::rule<Iterator, ascii::space_type> ident;
qi::rule<Iterator, ascii::space_type> nlist;

...

ident = char_ >> nlist;
nlist = ("(" >> int_ % "," >> ")");

...

我需要将值传递到ident规则(表达式ident必须创建一个语法树节点,其中构造函数需要来自nlist的解析值)。我考虑过创建和填充std::vector并使用像_val = vector<int>...这样的语义操作。我现在不清楚的是如何根据此规则创建任意长度的向量,因为我不会对输入的长度或使用examples之类的预定义向量做出任何假设。

这是否可行,或者有更好的方法吗?

1 个答案:

答案 0 :(得分:0)

这是灵气的面包和黄油。

只需使用任何兼容的属性类型和利润:

    using nlist_t = std::vector<int>;
    using ident_t = std::pair<char, nlist_t>;

    qi::rule<Iterator, ident_t(), qi::ascii::space_type> ident;
    qi::rule<Iterator, nlist_t(), qi::ascii::space_type> nlist;
  

注意:对于std::pair属性兼容性,请包含相关的fusion标题:

<强> Live On Coliru

#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/include/qi.hpp>

namespace qi = boost::spirit::qi;

int main()
{
    using nlist_t = std::vector<int>;
    using ident_t = std::pair<char, nlist_t>;

    using Iterator = std::string::const_iterator;
    qi::rule<Iterator, ident_t(), qi::ascii::space_type> ident;
    qi::rule<Iterator, nlist_t(), qi::ascii::space_type> nlist;

    ident = qi::char_ >> nlist;
    nlist = '(' >> qi::int_ % ',' >> ')';

    for (std::string const input : { "a (1,2,3)", "+(881,-2,42)    \n", "?(0)" }) {

        ident_t data;
        if (qi::phrase_parse(input.begin(), input.end(), ident, qi::ascii::space, data)) {
            std::cout << "Parsed: " << data.first << "(";
            for (auto i : data.second) std::cout << i << ",";
            std::cout << ")\n";
        } else
            std::cout << "Parse failed: '" << input << "'\n";
    }
}

打印

Parsed: a(1,2,3,)
Parsed: +(881,-2,42,)
Parsed: ?(0,)

<强>奖金

使用phoenix::construct的想象Ast类型的版本:

<强> Also Live On Coliru

#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/phoenix.hpp>

namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;

namespace OoShinyAst {

    using MyName = char;
    using MyArgument = int;
    using MyArgumentList = std::vector<MyArgument>;

    struct MyIdent {
        MyName         name;
        MyArgumentList args;

        MyIdent() = default;
        MyIdent(MyName name, MyArgumentList args)
            : name(std::move(name)), args(std::move(args)) { }
    };
}

int main()
{
    using Iterator = std::string::const_iterator;
    qi::rule<Iterator, OoShinyAst::MyIdent(),        qi::ascii::space_type> ident;
    qi::rule<Iterator, OoShinyAst::MyArgumentList(), qi::ascii::space_type> nlist;

    nlist = '(' >> qi::int_ % ',' >> ')';
    ident = (qi::char_ >> nlist) [ qi::_val = px::construct<OoShinyAst::MyIdent>(qi::_1, qi::_2) ];

    for (std::string const input : { "a (1,2,3)", "+(881,-2,42)    \n", "?(0)" }) {

        OoShinyAst::MyIdent data;
        if (qi::phrase_parse(input.begin(), input.end(), ident, qi::ascii::space, data)) {
            std::cout << "Parsed: " << data.name << "(";
            for (auto i : data.args) std::cout << i << ",";
            std::cout << ")\n";
        } else
            std::cout << "Parse failed: '" << input << "'\n";
    }
}