Boost.Spirit - 如何使用repeat解析成结构?
Boost.Spirit - How to use repeat to parse into a struct?
我正在尝试编写一个小程序来使用 Boost.Spirit 解析来自 /proc/stat 的 cpu 使用信息。它主要工作,但我无法在使用 repeat 时编译我的语法。我错过了什么?
全部代码:
#include <vector>
#include "boost/fusion/include/adapt_struct.hpp"
#define BOOST_SPIRIT_DEBUG
#include "boost/spirit/include/qi.hpp"
#include "boost/iostreams/device/mapped_file.hpp"
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
struct Cpu
{
unsigned int user;
unsigned int nice;
unsigned int system;
unsigned int idle;
unsigned int iowait;
unsigned int irq;
unsigned int softirq;
unsigned int steal;
unsigned int guest;
unsigned int guest_nice;
};
BOOST_FUSION_ADAPT_STRUCT(
Cpu,
(unsigned int, user)
(unsigned int, nice)
(unsigned int, system)
(unsigned int, idle)
(unsigned int, iowait)
(unsigned int, irq)
(unsigned int, softirq)
(unsigned int, steal)
(unsigned int, guest)
(unsigned int, guest_nice)
)
template< typename Iter, typename Skip = ascii::blank_type >
struct Cpu_parser : qi::grammar< Iter, Cpu(), Skip >
{
qi::rule< Iter, Cpu(), Skip > start;
Cpu_parser() : Cpu_parser::base_type(start)
{
using namespace qi;
start = lexeme[lit("cpu") >> omit[-uint_]] >> repeat(10)[uint_];
//start = lexeme[lit("cpu") >> omit[-uint_]] >> uint_ >> uint_ >> uint_ >> uint_ >> uint_ >> uint_ >> uint_ >> uint_ >> uint_ >> uint_;
BOOST_SPIRIT_DEBUG_NODE(start);
}
};
int main(int argc, char** argv)
{
std::vector< Cpu > cpus;
{
std::ifstream ifs("/proc/stat");
ifs >> std::noskipws;
Cpu_parser< boost::spirit::istream_iterator > cpu_parser;
std::cout << phrase_parse(
boost::spirit::istream_iterator(ifs),
boost::spirit::istream_iterator(),
cpu_parser % qi::eol,
ascii::blank,
cpus) << std::endl;
}
return 0;
}
所有个人 uint_s 的注释行工作正常,但我想知道我在重复时做错了什么。
如果我用无符号整数向量替换 Cpu 结构,我也可以重复工作。
你不能。容易地。那是因为repeat()[]
合成了一个容器属性。你的结构是一个融合序列,而不是一个容器。
你/可以/通过
伪造它
- 不使用FUSION_ADAPT_STRUCT
- 定义自定义点(例如
is_container<Cpu>
。这里有一个描述如何在文档中执行操作的示例:http://www.boost.org/doc/libs/1_60_0/libs/spirit/doc/html/spirit/advanced/customize/iterate/container_iterator.html#spirit.advanced.customize.iterate.container_iterator.example。还有一个答案描述了如何使其与std::array
)
不过,有个好消息:
“好消息”
对于融合序列,qi::auto_
解析器知道该怎么做!
这去除了 80% 的脂肪:
#include "boost/fusion/include/adapt_struct.hpp"
#include "boost/spirit/include/qi.hpp"
#include <fstream>
struct Cpu {
unsigned user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice;
};
BOOST_FUSION_ADAPT_STRUCT(Cpu, user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice)
int main() {
std::vector<Cpu> cpus;
bool ok = [&cpus] {
using It = boost::spirit::istream_iterator;
using namespace boost::spirit::qi;
std::ifstream ifs("/proc/stat");
return parse(
It(ifs >> std::noskipws), {},
("cpu" >> -omit[uint_] >> skip(blank)[auto_]) % eol,
cpus);
}();
std::cout << std::boolalpha << ok << std::endl;
}
NOTE
- The output is
true
. Just not on Coliru (/proc/cpu is not accessible there).
- The lambda trick is there to make the
using namespace
scoped, while being able to return the value for ok
.
我正在尝试编写一个小程序来使用 Boost.Spirit 解析来自 /proc/stat 的 cpu 使用信息。它主要工作,但我无法在使用 repeat 时编译我的语法。我错过了什么?
全部代码:
#include <vector>
#include "boost/fusion/include/adapt_struct.hpp"
#define BOOST_SPIRIT_DEBUG
#include "boost/spirit/include/qi.hpp"
#include "boost/iostreams/device/mapped_file.hpp"
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
struct Cpu
{
unsigned int user;
unsigned int nice;
unsigned int system;
unsigned int idle;
unsigned int iowait;
unsigned int irq;
unsigned int softirq;
unsigned int steal;
unsigned int guest;
unsigned int guest_nice;
};
BOOST_FUSION_ADAPT_STRUCT(
Cpu,
(unsigned int, user)
(unsigned int, nice)
(unsigned int, system)
(unsigned int, idle)
(unsigned int, iowait)
(unsigned int, irq)
(unsigned int, softirq)
(unsigned int, steal)
(unsigned int, guest)
(unsigned int, guest_nice)
)
template< typename Iter, typename Skip = ascii::blank_type >
struct Cpu_parser : qi::grammar< Iter, Cpu(), Skip >
{
qi::rule< Iter, Cpu(), Skip > start;
Cpu_parser() : Cpu_parser::base_type(start)
{
using namespace qi;
start = lexeme[lit("cpu") >> omit[-uint_]] >> repeat(10)[uint_];
//start = lexeme[lit("cpu") >> omit[-uint_]] >> uint_ >> uint_ >> uint_ >> uint_ >> uint_ >> uint_ >> uint_ >> uint_ >> uint_ >> uint_;
BOOST_SPIRIT_DEBUG_NODE(start);
}
};
int main(int argc, char** argv)
{
std::vector< Cpu > cpus;
{
std::ifstream ifs("/proc/stat");
ifs >> std::noskipws;
Cpu_parser< boost::spirit::istream_iterator > cpu_parser;
std::cout << phrase_parse(
boost::spirit::istream_iterator(ifs),
boost::spirit::istream_iterator(),
cpu_parser % qi::eol,
ascii::blank,
cpus) << std::endl;
}
return 0;
}
所有个人 uint_s 的注释行工作正常,但我想知道我在重复时做错了什么。
如果我用无符号整数向量替换 Cpu 结构,我也可以重复工作。
你不能。容易地。那是因为repeat()[]
合成了一个容器属性。你的结构是一个融合序列,而不是一个容器。
你/可以/通过
伪造它- 不使用FUSION_ADAPT_STRUCT
- 定义自定义点(例如
is_container<Cpu>
。这里有一个描述如何在文档中执行操作的示例:http://www.boost.org/doc/libs/1_60_0/libs/spirit/doc/html/spirit/advanced/customize/iterate/container_iterator.html#spirit.advanced.customize.iterate.container_iterator.example。还有一个答案描述了如何使其与std::array
)
不过,有个好消息:
“好消息”
对于融合序列,qi::auto_
解析器知道该怎么做!
这去除了 80% 的脂肪:
#include "boost/fusion/include/adapt_struct.hpp"
#include "boost/spirit/include/qi.hpp"
#include <fstream>
struct Cpu {
unsigned user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice;
};
BOOST_FUSION_ADAPT_STRUCT(Cpu, user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice)
int main() {
std::vector<Cpu> cpus;
bool ok = [&cpus] {
using It = boost::spirit::istream_iterator;
using namespace boost::spirit::qi;
std::ifstream ifs("/proc/stat");
return parse(
It(ifs >> std::noskipws), {},
("cpu" >> -omit[uint_] >> skip(blank)[auto_]) % eol,
cpus);
}();
std::cout << std::boolalpha << ok << std::endl;
}
NOTE
- The output is
true
. Just not on Coliru (/proc/cpu is not accessible there).- The lambda trick is there to make the
using namespace
scoped, while being able to return the value forok
.