如何使用强制精神列表操作符强制最小元素数量?(How to use boost spirit list operator with mandatory minimum amount of elemen

编程入门 行业动态 更新时间:2024-10-25 14:32:53
如何使用强制精神列表操作符强制最小元素数量?(How to use boost spirit list operator with mandatory minimum amount of elements?)

我想解析点语言( http://www.graphviz.org/content/dot-language )。 它是一种图形定义语言,用于定义它们之间的节点和连接。 典型的语句看起来像node1->node2->node3; 。 使用boost :: spirit列表运算符%来制作节点列表会很不错。 一个天真的方法是:

edge_stmt %= ( node_or_subgraph(_r1) % (qi::eps(_r1) >> tok.diredgeop | tok.undiredgeop) ) >> -attr_list;

_r1表示这是有向图还是无向图, diredgeop是->的标记, undiredgeop分别是--的标记。

问题是上面的代码只对node1;成功node1; ,这是不正确的。 为了获得正确的解析器,我必须以某种方式声明由%构建的列表中必须至少有两个元素。 怎么样?

文档说a % b相当于a >> *(omit[b] >> a) ,这是不正确的。 有人可能想试试这个:

edge_stmt %= ( node_or_subgraph(_r1) >> +( qi::omit [ qi::eps(_r1) >> tok.diredgeop | tok.undiredgeop ] >> node_or_subgraph(_r1) ) ) >> -attr_list;

但是这段代码不会产生向量,它的合成属性是一个元组。

我当然可以尝试语义行为,但有没有一个优雅的替代方案而没有单调行动?

I would like to parse dot language (http://www.graphviz.org/content/dot-language). It's a graph definition language that defines nodes and connections between them. A typical statement looks like node1->node2->node3;. It would be nice to use a boost::spirit list operator % to make a list of nodes. A naive approach would be:

edge_stmt %= ( node_or_subgraph(_r1) % (qi::eps(_r1) >> tok.diredgeop | tok.undiredgeop) ) >> -attr_list;

_r1 indicates if this is directed or undirected graph, diredgeop is a token for ->, undiredgeop is respectively a token for --.

The problem is the above code will succeed for just node1;, which is incorrect. In order to get a correct parser I have to somehow declare that there must be at least two elements in the list built by %. How?

The documentation says that a % b is equivalent to a >> *(omit[b] >> a), which is incorrect. One might want to try this:

edge_stmt %= ( node_or_subgraph(_r1) >> +( qi::omit [ qi::eps(_r1) >> tok.diredgeop | tok.undiredgeop ] >> node_or_subgraph(_r1) ) ) >> -attr_list;

But this code doesn't produce a vector, its synthesized attribute is a tuple.

I can try semantic actions of course, but is there an elegant alternative without sematic actions?

最满意答案

使列表运算符接受最少数量的元素将需要创建引入该行为的全新解析器,因为与repeat不同,它没有配置为执行此操作。 我希望以下示例可以帮助您了解如何使用a >> +(omit[b] >> a)来实现您想要的效果。

在WandBox上运行

#include <iostream> #include <vector> #include <boost/spirit/include/qi.hpp> #include <boost/fusion/include/std_pair.hpp> namespace qi= boost::spirit::qi; void print(const std::vector<std::string>& data) { std::cout << "{ "; for(const auto& elem : data) { std::cout << elem << " "; } std::cout << "} "; } void print(const std::pair<std::string,double>& data) { std::cout << "[ " << data.first << ", " << data.second << " ]"; } template <typename Parser,typename... Attrs> void parse(const std::string& str, const Parser& parser, Attrs&... attrs) { std::string::const_iterator iter=std::begin(str), end=std::end(str); bool result = qi::phrase_parse(iter,end,parser,qi::space,attrs...); if(result && iter==end) { std::cout << "Success."; int ignore[] = {(print(attrs),0)...}; std::cout << "\n"; } else { std::cout << "Something failed. Unparsed: \"" << std::string(iter,end) << "\"\n"; } } template <typename Parser> void parse_with_nodes(const std::string& str, const Parser& parser) { std::vector<std::string> nodes; parse(str,parser,nodes); } template <typename Parser> void parse_with_nodes_and_attr(const std::string& str, const Parser& parser) { std::vector<std::string> nodes; std::pair<std::string,double> attr_pair; parse(str,parser,nodes,attr_pair); } int main() { qi::rule<std::string::const_iterator,std::string()> node=+qi::alnum; qi::rule<std::string::const_iterator,std::pair<std::string,double>(),qi::space_type> attr = +qi::alpha >> '=' >> qi::double_; parse_with_nodes("node1->node2", node % "->"); parse_with_nodes_and_attr("node1->node2 arrowsize=1.0", node % "->" >> attr); parse_with_nodes("node1->node2", node >> +("->" >> node)); //parse_with_nodes_and_attr("node1->node2 arrowsize=1.0", node >> +("->" >> node) >> attr); qi::rule<std::string::const_iterator,std::vector<std::string>(),qi::space_type> at_least_two_nodes = node >> +("->" >> node); parse_with_nodes_and_attr("node1->node2 arrowsize=1.0", at_least_two_nodes >> attr); }

Making the list operator accept a minimum number of elements would require creating a brand new parser introducing that behaviour because, unlike repeat, it is not configured to do so. I hope the following example can help you understand how you can use a >> +(omit[b] >> a) to achieve what you want.

Running on WandBox

#include <iostream> #include <vector> #include <boost/spirit/include/qi.hpp> #include <boost/fusion/include/std_pair.hpp> namespace qi= boost::spirit::qi; void print(const std::vector<std::string>& data) { std::cout << "{ "; for(const auto& elem : data) { std::cout << elem << " "; } std::cout << "} "; } void print(const std::pair<std::string,double>& data) { std::cout << "[ " << data.first << ", " << data.second << " ]"; } template <typename Parser,typename... Attrs> void parse(const std::string& str, const Parser& parser, Attrs&... attrs) { std::string::const_iterator iter=std::begin(str), end=std::end(str); bool result = qi::phrase_parse(iter,end,parser,qi::space,attrs...); if(result && iter==end) { std::cout << "Success."; int ignore[] = {(print(attrs),0)...}; std::cout << "\n"; } else { std::cout << "Something failed. Unparsed: \"" << std::string(iter,end) << "\"\n"; } } template <typename Parser> void parse_with_nodes(const std::string& str, const Parser& parser) { std::vector<std::string> nodes; parse(str,parser,nodes); } template <typename Parser> void parse_with_nodes_and_attr(const std::string& str, const Parser& parser) { std::vector<std::string> nodes; std::pair<std::string,double> attr_pair; parse(str,parser,nodes,attr_pair); } int main() { qi::rule<std::string::const_iterator,std::string()> node=+qi::alnum; qi::rule<std::string::const_iterator,std::pair<std::string,double>(),qi::space_type> attr = +qi::alpha >> '=' >> qi::double_; parse_with_nodes("node1->node2", node % "->"); parse_with_nodes_and_attr("node1->node2 arrowsize=1.0", node % "->" >> attr); parse_with_nodes("node1->node2", node >> +("->" >> node)); //parse_with_nodes_and_attr("node1->node2 arrowsize=1.0", node >> +("->" >> node) >> attr); qi::rule<std::string::const_iterator,std::vector<std::string>(),qi::space_type> at_least_two_nodes = node >> +("->" >> node); parse_with_nodes_and_attr("node1->node2 arrowsize=1.0", at_least_two_nodes >> attr); }

更多推荐

本文发布于:2023-07-25 19:44:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1265237.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:如何使用   最小   元素   数量   精神

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!