C++ 如何在没有前置标记的情况下解析异构列表?
我应该如何修改boost::spirit代码来解析任何范围或列表的组合 请注意,这个问题与我的问题有些不同。在本例中,我没有像C++ 如何在没有前置标记的情况下解析异构列表?,c++,boost-spirit,boost-spirit-qi,C++,Boost Spirit,Boost Spirit Qi,我应该如何修改boost::spirit代码来解析任何范围或列表的组合 请注意,这个问题与我的问题有些不同。在本例中,我没有像范围:和列表:这样的特殊前置标记来帮助我进行解析,因此我不确定我们是否需要某种前瞻性 不过,我确实需要将解析分开,因为这样做可以帮助我将结果捕获到不同的数据结构中 目标让四个测试用例全部通过 编辑似乎适用于更复杂表达式的答案 // #define BOOST_SPIRIT_DEBUG #include <boost/foreach.hpp> #include
范围:
和列表:
这样的特殊前置标记来帮助我进行解析,因此我不确定我们是否需要某种前瞻性
不过,我确实需要将解析分开,因为这样做可以帮助我将结果捕获到不同的数据结构中
目标让四个测试用例全部通过
编辑似乎适用于更复杂表达式的答案
// #define BOOST_SPIRIT_DEBUG
#include <boost/foreach.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/tuple.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/fusion/include/boost_tuple.hpp>
#include <iostream>
namespace qi = boost::spirit::qi;
typedef std::vector<boost::tuple<std::string,std::vector<int>>> MY_TYPE;
template <typename Iterator, typename Skipper>
struct my_grammar :
qi::grammar<Iterator, MY_TYPE(), Skipper>
{
my_grammar() :
my_grammar::base_type( entries )
{
entries %=
*(
+(qi::char_ - '-')
>> qi::lit( "->" )
>> ( comma | range )
)
;
range %= '{' >> qi::int_ >> ':' >> qi::int_ >> ':' >> qi::int_ >> '}';
comma %= '{' >> (qi::int_ % ',') >> '}';
BOOST_SPIRIT_DEBUG_NODE( range );
BOOST_SPIRIT_DEBUG_NODE( comma );
BOOST_SPIRIT_DEBUG_NODE( entries );
}
qi::rule<Iterator, std::vector<int>(), Skipper>
range, comma;
qi::rule<Iterator, MY_TYPE(), Skipper>
entries;
};
// -----------------------------------------------------------------------------
static void TryParse( const std::string& input, const std::string& label )
{
MY_TYPE entries;
auto it(input.cbegin()), end( input.cend() );
my_grammar<decltype(it), qi::space_type> entry_grammar;
if (qi::phrase_parse(it, end, entry_grammar, qi::space, entries)
&& it == end)
{
std::cerr << label << " SUCCESS" << std::endl;
}
else
{
std::cerr << label << " FAIL" << std::endl;
}
}
int
main( int argc, char* argv[] )
{
std::string range_first = "foo -> {1:9:1}\nbar -> {1,2,3,4,5}\n";
std::string comma_first = "foo -> {1,2,3,4,5}\nbar -> {1:9:1}\n";
std::string comma_only = "foo -> {1,2,3,4,5}\n";
std::string range_only = "foo -> {1:9:1}\n";
TryParse( range_first, "RANGE FIRST" );
TryParse( comma_first, "COMMA FIRST" );
TryParse( range_only, "RANGE ONLY" );
TryParse( comma_only, "COMMA ONLY" );
}
编辑改进的代码(仍然无法处理异构列表)
sandbox.cpp
// #define BOOST_SPIRIT_DEBUG
#include <boost/foreach.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iostream>
namespace qi = boost::spirit::qi;
typedef int Entry;
template <typename Iterator, typename Skipper>
struct my_grammar :
qi::grammar<Iterator, std::vector<Entry>(), Skipper>
{
my_grammar() :
my_grammar::base_type(entries)
{
entries %=
*(
'{' >>
( comma_list | range_list )
>> '}'
)
;
comma_list %= qi::int_ % ',';
range_list %= qi::int_ >> ':' >> qi::int_ >> ':' >> qi::int_;
BOOST_SPIRIT_DEBUG_NODE(entries);
BOOST_SPIRIT_DEBUG_NODE(comma_list);
BOOST_SPIRIT_DEBUG_NODE(range_list);
}
qi::rule<Iterator, std::vector<Entry>(), Skipper> entries, comma_list, range_list;
};
// -----------------------------------------------------------------------------
static void TryParse( const std::string& input, const std::string& label )
{
std::vector<Entry> entries;
auto it(input.cbegin()), end( input.cend() );
my_grammar<decltype(it), qi::blank_type> entry_grammar;
if (qi::phrase_parse(it, end, entry_grammar, qi::blank, entries)
&& it == end)
{
std::cerr << label << " SUCCESS" << std::endl;
}
else
{
std::cerr << label << " FAIL" << std::endl;
}
}
int
main( int argc, char* argv[] )
{
std::string range_first = "{3:5:7}\n{1,2,3,4,5}";
std::string comma_first = "{1,2,3,4,5}\n{3:5:7}";
std::string comma_only = "{1,2,3,4,5}";
std::string range_only = "{3:5:7}";
TryParse( range_first, "COMMA FIRST" );
TryParse( comma_first, "RANGE FIRST" );
TryParse( comma_only, "COMMA ONLY" );
TryParse( range_only, "RANGE ONLY" );
}
/#定义BOOST_SPIRIT_调试
#包括
#包括
#包括
名称空间qi=boost::spirit::qi;
输入类型定义;
模板
结构我的语法:
语法
{
我的语法:
我的语法::基本类型(条目)
{
条目%=
*(
'{' >>
(逗号列表|范围列表)
>> '}'
)
;
逗号_list%=qi::int_%',';
范围\列表%=qi::int \ u>>':'>>qi::int \ u>>':'>>qi::int \;
BOOST_SPIRIT_DEBUG_节点(条目);
BOOST_SPIRIT_DEBUG_节点(逗号列表);
BOOST_SPIRIT_DEBUG_节点(范围列表);
}
qi::规则条目、逗号列表、范围列表;
};
// -----------------------------------------------------------------------------
静态void TryParse(const std::string和input,const std::string和label)
{
std::向量条目;
autoit(input.cbegin()),end(input.cend());
我的语法输入语法;
if(qi::短语解析(it,end,entry\u语法,qi::blank,entries)
&&it==结束)
{
std::cerr使用公共代码中的前导数字。该数字之后有一个范围尾部或一个列表尾部。列表尾部以a开头,范围尾部以a开头:
可能将}折叠到尾部,因此列表尾部为(,number)*},范围尾部为:number:number},这使得空列表更容易解析。+1对于一个好的答案,我已经编辑了OP以使用尾部递归,因此我们现在可以处理范围尾部
或逗号尾部
,但仍然试图使这两种方法的任何组合都起作用。因此,它现在可以处理一个列表或另一个列表。如果你按照上面的建议跳过新行,它会处理一个列表,然后处理另一个?实际上,跳过新行可能是主要原因。我用空格
而不是空白
修复了OP中的第二块代码,它对列表和范围的组合起到了作用。但是,我会接受你的回答,因为它在代码中明确说明了这种语法的一个问题:在我分析第一项之外的内容之前,我无法判断我是否有范围类型或逗号类型。blank
不会跳过\n
仅跳过空格或制表符()<代码>空格
会跳过返回和新行。+1@llonesmiz-ty-你说得对-将所有内容更改为空格
会修复它。。。不幸的是,这个片段并不是我真正问题的一个好例子。我有一个解析,其中逗号列表
或范围列表
深入到语句解析(rhs)中。不知何故,这个示例在实际代码中不起作用。。。现在调查一下。
// #define BOOST_SPIRIT_DEBUG
#include <boost/foreach.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iostream>
namespace qi = boost::spirit::qi;
template <typename Iterator, typename Skipper>
struct my_grammar :
qi::grammar<Iterator, std::vector<int>(), Skipper>
{
my_grammar() :
my_grammar::base_type(entries)
{
entries %=
*('{' >> qi::int_
>> ( range_tail | comma_tail ))
;
range_tail %= ':' >> qi::int_ >> ':' >> qi::int_ >> '}';
comma_tail %= *( ',' >> qi::int_ ) >> '}';
BOOST_SPIRIT_DEBUG_NODE(entries );
BOOST_SPIRIT_DEBUG_NODE(comma_tail);
BOOST_SPIRIT_DEBUG_NODE(range_tail);
}
qi::rule<Iterator, std::vector<int>(), Skipper> entries, comma_tail, range_tail;
};
// -----------------------------------------------------------------------------
static void TryParse( const std::string& input, const std::string& label )
{
std::vector<int> entries;
auto it(input.cbegin()), end( input.cend() );
my_grammar<decltype(it), qi::blank_type> entry_grammar;
if (qi::phrase_parse(it, end, entry_grammar, qi::blank, entries)
&& it == end)
{
std::cerr << label << " SUCCESS" << std::endl;
}
else
{
std::cerr << label << " FAIL" << std::endl;
}
}
int
main( int argc, char* argv[] )
{
std::string range_first = "{3:5:7}\n{1,2,3,4,5}";
std::string comma_first = "{1,2,3,4,5}\n{3:5:7}";
std::string comma_only = "{1,2,3,4,5}";
std::string range_only = "{3:5:7}";
TryParse( comma_first, "COMMA FIRST" );
TryParse( range_first, "RANGE FIRST" );
TryParse( comma_only, "COMMA ONLY" );
TryParse( range_only, "RANGE ONLY" );
}
/tmp$ g++ -g -std=c++11 sandbox.cpp -o sandbox && ./sandbox
COMMA FIRST FAIL
RANGE FIRST FAIL
COMMA ONLY SUCCESS
RANGE ONLY FAIL
/tmp$
// #define BOOST_SPIRIT_DEBUG
#include <boost/foreach.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iostream>
namespace qi = boost::spirit::qi;
typedef int Entry;
template <typename Iterator, typename Skipper>
struct my_grammar :
qi::grammar<Iterator, std::vector<Entry>(), Skipper>
{
my_grammar() :
my_grammar::base_type(entries)
{
entries %=
*(
'{' >>
( comma_list | range_list )
>> '}'
)
;
comma_list %= qi::int_ % ',';
range_list %= qi::int_ >> ':' >> qi::int_ >> ':' >> qi::int_;
BOOST_SPIRIT_DEBUG_NODE(entries);
BOOST_SPIRIT_DEBUG_NODE(comma_list);
BOOST_SPIRIT_DEBUG_NODE(range_list);
}
qi::rule<Iterator, std::vector<Entry>(), Skipper> entries, comma_list, range_list;
};
// -----------------------------------------------------------------------------
static void TryParse( const std::string& input, const std::string& label )
{
std::vector<Entry> entries;
auto it(input.cbegin()), end( input.cend() );
my_grammar<decltype(it), qi::blank_type> entry_grammar;
if (qi::phrase_parse(it, end, entry_grammar, qi::blank, entries)
&& it == end)
{
std::cerr << label << " SUCCESS" << std::endl;
}
else
{
std::cerr << label << " FAIL" << std::endl;
}
}
int
main( int argc, char* argv[] )
{
std::string range_first = "{3:5:7}\n{1,2,3,4,5}";
std::string comma_first = "{1,2,3,4,5}\n{3:5:7}";
std::string comma_only = "{1,2,3,4,5}";
std::string range_only = "{3:5:7}";
TryParse( range_first, "COMMA FIRST" );
TryParse( comma_first, "RANGE FIRST" );
TryParse( comma_only, "COMMA ONLY" );
TryParse( range_only, "RANGE ONLY" );
}