- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
boost 新手,我实际上需要 boost 精神来编写一个简单的解析器来填充一些数据结构。
它们大致如下:
struct Task
{
const string dataname;
const Level level;
const string aggregator;
const set<string> groupby;
void operator();
};
struct Schedule
{
map<Level, ComputeTask> tasks;
// I have left just to make it seems that
// the struct wrapping over the map is not
// useless (this is not the full code)
void operator()(const InstancePtr &node);
};
关于 Task
,我不知道如何使用 BOOST_FUSION_ADAPT_STRUCT
,如 employee example 中所述或变体,以使其与枚举和 STL 容器字段一起使用。
关于 Schedule
的类似问题, 但这次我也使用用户类型(可能已经注册到融合,它是递归的吗?)。
我正在设计文件格式,结构定义和文件格式可能会改变,所以我更喜欢使用 boost 而不是手工制作但难以维护的代码。我这样做也是出于学习目的。
文件可能如下所示:
level: level operation name on(data1, data2, data3)
level: level operation name on()
level: level operation name on(data1, data2)
一行是map
的一个条目在 Schedule
, 在 :
之前是关键,然后它的其余部分定义了 Task
.在哪里level
替换为对应于 enum Level
的一些级别关键字,类似情况 operation
, name
是允许的名称之一(在一组关键字中),on()
是关键字,括号内是用户提供的零个或多个字符串,应填充 set<string> groupby
Task
中的字段.
我希望它是可读的,我什至可以添加英语关键字,这除了可读性外不会增加任何其他内容,这是使用一些解析库而不是手工编写代码的另一个原因。
如果您认为我的问题不够清楚,请随时询问更多细节..
谢谢。
最佳答案
因此,作为您的示例做出一些假设并不能使含义非常清楚。但是这里是:
随机枚举:
enum class Level { One, Two, Three, LEVEL };
Sidenote: the
std::set<>
might need to be a sequential container, because usuallygroupby
operations are not commutative (the order matters). I don't know about your domain, of course,
适应:
BOOST_FUSION_ADAPT_STRUCT(ComputeTask, level, aggregator, dataname, groupby)
BOOST_FUSION_ADAPT_STRUCT(Schedule, tasks)
请注意,我巧妙地将适应的字段按语法顺序排列。这对以后有很大帮助。
想到的最简单的语法:
template <typename It>
struct Parser : qi::grammar<It, Schedule()> {
Parser() : Parser::base_type(_start) {
using namespace qi;
_any_word = lexeme [ +char_("a-zA-Z0-9-_./") ];
_operation = _any_word; // TODO
_group_field = _any_word; // TODO
_dataname = _any_word; // TODO
_level = no_case [ _level_sym ];
_groupby = '(' >> -(_group_field % ',') >> ')';
_task = _level >> _operation >> _dataname >> "on" >> _groupby;
_entry = _level >> ':' >> _task;
_schedule = _entry % eol;
_start = skip(blank) [ _schedule ];
BOOST_SPIRIT_DEBUG_NODES((_start)(_schedule)(_task)(_groupby)(_level)(_operation)(_dataname)(_group_field))
}
private:
struct level_sym : qi::symbols<char, Level> {
level_sym() { this->add
("one", Level::One)
("two", Level::Two)
("three", Level::Three)
("level", Level::LEVEL);
}
} _level_sym;
// lexemes
qi::rule<It, std::string()> _any_word;
qi::rule<It, std::string()> _operation, _dataname, _group_field; // TODO
qi::rule<It, Level()> _level;
using Skipper = qi::blank_type;
using Table = decltype(Schedule::tasks);
using Entry = std::pair<Level, ComputeTask>;
qi::rule<It, std::set<std::string>(), Skipper> _groupby;
qi::rule<It, ComputeTask(), Skipper> _task;
qi::rule<It, Entry(), Skipper> _entry;
qi::rule<It, Table(), Skipper> _schedule;
qi::rule<It, Schedule()> _start;
};
我将输入更改为具有 Level
的唯一键在时间表中,否则实际上只会产生一个条目。
int main() {
Parser<std::string::const_iterator> const parser;
for (std::string const input : { R"(ONE: level operation name on(data1, data2, data3)
TWO: level operation name on()
THREE: level operation name on(data1, data2))" })
{
auto f = begin(input), l = end(input);
Schedule s;
if (parse(f, l, parser, s)) {
std::cout << "Parsed\n";
for (auto& [level, task] : s.tasks) {
std::cout << level << ": " << task << "\n";
}
} else {
std::cout << "Failed\n";
}
if (f != l) {
std::cout << "Remaining unparsed input: " << std::quoted(std::string(f,l)) << "\n";
}
}
}
打印
Parsed
One: LEVEL operation name on (data1, data2, data3)
Two: LEVEL operation name on ()
Three: LEVEL operation name on (data1, data2)
此外,还有 BOOST_SPIRIT_DEBUG
定义:
<_start>
<try>ONE: level operation</try>
<_schedule>
<try>ONE: level operation</try>
<_level>
<try>ONE: level operation</try>
<success>: level operation na</success>
<attributes>[One]</attributes>
</_level>
<_task>
<try> level operation nam</try>
<_level>
<try>level operation name</try>
<success> operation name on(d</success>
<attributes>[LEVEL]</attributes>
</_level>
<_operation>
<try>operation name on(da</try>
<success> name on(data1, data</success>
<attributes>[[o, p, e, r, a, t, i, o, n]]</attributes>
</_operation>
<_dataname>
<try>name on(data1, data2</try>
<success> on(data1, data2, da</success>
<attributes>[[n, a, m, e]]</attributes>
</_dataname>
<_groupby>
<try>(data1, data2, data3</try>
<_group_field>
<try>data1, data2, data3)</try>
<success>, data2, data3)\nTWO:</success>
<attributes>[[d, a, t, a, 1]]</attributes>
</_group_field>
<_group_field>
<try>data2, data3)\nTWO: l</try>
<success>, data3)\nTWO: level </success>
<attributes>[[d, a, t, a, 2]]</attributes>
</_group_field>
<_group_field>
<try>data3)\nTWO: level op</try>
<success>)\nTWO: level operati</success>
<attributes>[[d, a, t, a, 3]]</attributes>
</_group_field>
<success>\nTWO: level operatio</success>
<attributes>[[[d, a, t, a, 1], [d, a, t, a, 2], [d, a, t, a, 3]]]</attributes>
</_groupby>
<success>\nTWO: level operatio</success>
<attributes>[[LEVEL, [o, p, e, r, a, t, i, o, n], [n, a, m, e], [[d, a, t, a, 1], [d, a, t, a, 2], [d, a, t, a, 3]]]]</attributes>
</_task>
<_level>
<try>TWO: level operation</try>
<success>: level operation na</success>
<attributes>[Two]</attributes>
</_level>
<_task>
<try> level operation nam</try>
<_level>
<try>level operation name</try>
<success> operation name on()</success>
<attributes>[LEVEL]</attributes>
</_level>
<_operation>
<try>operation name on()\n</try>
<success> name on()\nTHREE: le</success>
<attributes>[[o, p, e, r, a, t, i, o, n]]</attributes>
</_operation>
<_dataname>
<try>name on()\nTHREE: lev</try>
<success> on()\nTHREE: level o</success>
<attributes>[[n, a, m, e]]</attributes>
</_dataname>
<_groupby>
<try>()\nTHREE: level oper</try>
<_group_field>
<try>)\nTHREE: level opera</try>
<fail/>
</_group_field>
<success>\nTHREE: level operat</success>
<attributes>[[]]</attributes>
</_groupby>
<success>\nTHREE: level operat</success>
<attributes>[[LEVEL, [o, p, e, r, a, t, i, o, n], [n, a, m, e], []]]</attributes>
</_task>
<_level>
<try>THREE: level operati</try>
<success>: level operation na</success>
<attributes>[Three]</attributes>
</_level>
<_task>
<try> level operation nam</try>
<_level>
<try>level operation name</try>
<success> operation name on(d</success>
<attributes>[LEVEL]</attributes>
</_level>
<_operation>
<try>operation name on(da</try>
<success> name on(data1, data</success>
<attributes>[[o, p, e, r, a, t, i, o, n]]</attributes>
</_operation>
<_dataname>
<try>name on(data1, data2</try>
<success> on(data1, data2)</success>
<attributes>[[n, a, m, e]]</attributes>
</_dataname>
<_groupby>
<try>(data1, data2)</try>
<_group_field>
<try>data1, data2)</try>
<success>, data2)</success>
<attributes>[[d, a, t, a, 1]]</attributes>
</_group_field>
<_group_field>
<try>data2)</try>
<success>)</success>
<attributes>[[d, a, t, a, 2]]</attributes>
</_group_field>
<success></success>
<attributes>[[[d, a, t, a, 1], [d, a, t, a, 2]]]</attributes>
</_groupby>
<success></success>
<attributes>[[LEVEL, [o, p, e, r, a, t, i, o, n], [n, a, m, e], [[d, a, t, a, 1], [d, a, t, a, 2]]]]</attributes>
</_task>
<success></success>
<attributes>[[[One, [LEVEL, [o, p, e, r, a, t, i, o, n], [n, a, m, e], [[d, a, t, a, 1], [d, a, t, a, 2], [d, a, t, a, 3]]]], [Two, [LEVEL, [o, p, e, r, a, t, i, o, n], [n, a, m, e], []]], [Three, [LEVEL, [o, p, e, r, a, t, i, o, n], [n, a, m, e], [[d, a, t, a, 1], [d, a, t, a, 2]]]]]]</attributes>
</_schedule>
<success></success>
<attributes>[[[[One, [LEVEL, [o, p, e, r, a, t, i, o, n], [n, a, m, e], [[d, a, t, a, 1], [d, a, t, a, 2], [d, a, t, a, 3]]]], [Two, [LEVEL, [o, p, e, r, a, t, i, o, n], [n, a, m, e], []]], [Three, [LEVEL, [o, p, e, r, a, t, i, o, n], [n, a, m, e], [[d, a, t, a, 1], [d, a, t, a, 2]]]]]]]</attributes>
</_start>
//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted.hpp>
#include <vector>
#include <map>
#include <set>
#include <iostream>
#include <iomanip>
#include <experimental/iterator>
enum class Level { One, Two, Three, LEVEL };
struct ComputeTask {
std::string dataname;
Level level;
std::string aggregator;
std::set<std::string> groupby;
};
struct Schedule {
std::map<Level, ComputeTask> tasks;
};
//////////////////////
// FOR DEBUG DEMO ONLY
static inline std::ostream& operator<<(std::ostream& os, Level l) {
switch(l) {
case Level::One: return os << "One";
case Level::Two: return os << "Two";
case Level::Three: return os << "Three";
case Level::LEVEL: return os << "LEVEL";
}
return os << "?";
}
static inline std::ostream& operator<<(std::ostream& os, ComputeTask const& task) {
os << task.level << ' ' << task.aggregator << ' ' << task.dataname << " on (";
copy(begin(task.groupby), end(task.groupby), std::experimental::make_ostream_joiner(os, ", "));
return os << ')';
}
/////////////
// FOR PARSER
BOOST_FUSION_ADAPT_STRUCT(ComputeTask, level, aggregator, dataname, groupby)
BOOST_FUSION_ADAPT_STRUCT(Schedule, tasks)
namespace qi = boost::spirit::qi;
template <typename It>
struct Parser : qi::grammar<It, Schedule()> {
Parser() : Parser::base_type(_start) {
using namespace qi;
_any_word = lexeme [ +char_("a-zA-Z0-9-_./") ];
_operation = _any_word; // TODO
_group_field = _any_word; // TODO
_dataname = _any_word; // TODO
_level = no_case [ _level_sym ];
_groupby = '(' >> -(_group_field % ',') >> ')';
_task = _level >> _operation >> _dataname >> "on" >> _groupby;
_entry = _level >> ':' >> _task;
_schedule = _entry % eol;
_start = skip(blank) [ _schedule ];
BOOST_SPIRIT_DEBUG_NODES((_start)(_schedule)(_task)(_groupby)(_level)(_operation)(_dataname)(_group_field))
}
private:
struct level_sym : qi::symbols<char, Level> {
level_sym() { this->add
("one", Level::One)
("two", Level::Two)
("three", Level::Three)
("level", Level::LEVEL);
}
} _level_sym;
// lexemes
qi::rule<It, std::string()> _any_word;
qi::rule<It, std::string()> _operation, _dataname, _group_field; // TODO
qi::rule<It, Level()> _level;
using Skipper = qi::blank_type;
using Table = decltype(Schedule::tasks);
using Entry = std::pair<Level, ComputeTask>;
qi::rule<It, std::set<std::string>(), Skipper> _groupby;
qi::rule<It, ComputeTask(), Skipper> _task;
qi::rule<It, Entry(), Skipper> _entry;
qi::rule<It, Table(), Skipper> _schedule;
qi::rule<It, Schedule()> _start;
};
int main() {
Parser<std::string::const_iterator> const parser;
for (std::string const input : { R"(ONE: level operation name on(data1, data2, data3)
TWO: level operation name on()
THREE: level operation name on(data1, data2))" })
{
auto f = begin(input), l = end(input);
Schedule s;
if (parse(f, l, parser, s)) {
std::cout << "Parsed\n";
for (auto& [level, task] : s.tasks) {
std::cout << level << ": " << task << "\n";
}
} else {
std::cout << "Failed\n";
}
if (f != l) {
std::cout << "Remaining unparsed input: " << std::quoted(std::string(f,l)) << "\n";
}
}
}
关于c++ - 使用 Boost Spirit/Fusion 轻松解析带有枚举字段和 STL 容器的结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56805932/
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 4 年前。
以下 C++ 代码和 Makefile 产生了一个无法理解的编译错误(对我来说)。谁能解释一下 问题到底是什么? 修复此代码需要做什么?能举个例子吗? 我在 Cygwin 的 GCC 上成功编译了这段
我大量使用 BOOST_FOREACH 来迭代容器,并且由于我最近转向 c++0x,我认为我可以用基于范围的 替换 BOOST_FOREACH >for 构造。下面这段代码 #include #inc
我编写了代码,允许按照输入的顺序遍历映射数据。 我编写了几次代码的解决方案是: 给定键类型 K 和数据类型 D, 标准:: map std::向量 如果想随机查找数据条目,请使用 map.find(K
我在 cygwin 上使用 gcc 3.4.4。我在下面的代码中收到了这个相当令人费解的 STL 错误消息,它根本不使用 STL: #include using namespace std; con
我正在使用 STL 函数 count_if 来计算所有正值在 double vector 中。例如我的代码是这样的: vector Array(1,1.0) Array.push_back(-1.
我正在尝试使用 numpy-STL 从 STL 模型中提取顶点以用于相干点漂移注册。你如何提取顶点?我了解如何从顶点和面列表创建网格,但不了解如何倒退。 我试过:从顶点和面创建一个新网格。导入创建的网
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2271.html 根据那篇文章,STL 不适合游戏开发。 你对此有何看法? 我目前的
在幕后,STL 映射是一棵红黑树,它使用其键的 typename _Rb_tree::iterator _Rb_tree:: find(const _Key& __k) { iterator _
我对 C++ 有很好的了解,但从未深入研究 STL。我必须学习 STL 的哪一部分才能提高工作效率并减少工作中的缺陷? 谢谢。 最佳答案 I have good knowledge of C++ 恕我
map rollCallRegister; map :: iterator rollCallRegisterIter; pair , bool> returnPair; rollCallRegi
在查看一些算法的模板名称时, 我看到这个名字对应于一个图书馆的概念。 取std::mismatch例如。 template std::pair mismatch( InputIt1 first1, I
我想对 class Person 的对象数组进行排序基于其数据成员' age '.我将对象存储在 vector v 中. 据我所知,至少有 4 种方法可以执行此操作,根据下面编写的方法,我有以下问题。
我对 gcc 或 Visual Studio 打包之外的 STL 实现感到好奇,因此快速 Google 搜索出现了一些结果,例如: Apache stdcxx uSTL rdeSTL 在什么情况下应该
我可以使用例如std::vector吗?在 macOs/XCode 的 DriverKit 驱动程序中? DriverKit 有一些容器类,如 OSArray https://developer.ap
我找不到任何关于如何将范围与容器结合使用的好文档。我正在尝试使用给定的 .insertAfter() 函数将一个元素插入到 SList 中。它需要一个范围,但我不知道如何检索它。 有人可以发布一两个示
如何在(例如)STL 容器中引入聚合初始化支持以正确构造它们?我的意思是: struct A { int i; char c; }; std::list l; // empty l.insert(st
我有一个 STL map : std::map > my_map; 我有两个变量: string name; int age; 这些变量的值发生变化,但本质上我想要做的是: 如果键名不存在,则创建键名
我是 C++ 的新手,请求帮助解决问题。 我正在编写一个简单的 STL 样式函数,它应该返回序列的中间元素( vector 、列表等) 这是我的函数,我尝试使用迭代器的概念 template It
如果我将几个水果名称推回第一个STL列表,同时,我将每个水果的编号推回第二个STL列表;如果我想按字母顺序对第一个STL列表进行排序,我该如何按水果STL列表的顺序对第二个STL列表进行排序? 最佳答
我是一名优秀的程序员,十分优秀!