如何使用带有强制性最小元素数量的Boost Spirit List运算符? [英] 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列表运算符%
制作节点列表会很好.天真的方法是:
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
指示这是有向图还是无向图,diredgeop
是->
的标记,undiredgeop
分别是--
的标记.
_r1
indicates if this is directed or undirected graph, diredgeop
is a token for ->
, undiredgeop
is respectively a token for --
.
问题是上述代码仅对node1;
成功,这是不正确的.为了获得正确的解析器,我必须以某种方式声明由%
构建的列表中至少必须包含两个元素.怎么样?
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?
文档说a % b
等同于a >> *(omit[b] >> a)
,这是不正确的.一个人可能想尝试一下:
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)
来实现所需的目标.
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.
#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);
}
这篇关于如何使用带有强制性最小元素数量的Boost Spirit List运算符?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!