我的boost :: spirit语法中有以下规则;
rule = (qi::token(ABSTRACT) ^ qi::token(STATIC) ^ qi::token(FINAL))
此构造的类型为;
boost::fusion::vector3<boost::optional<boost::iterator_range<std::string::iterator>>, boost::optional<boost::iterator_range<std::string::iterator>>, boost::optional<boost::iterator_range<std::string::iterator>>>
然而,我宁愿拥有的是;
boost::fusion::vector3<bool, bool, bool>
如果每个bool
具有相应boost::optional<...> operator bool() const
的值,只有一个案例,我会按照here使用qi::matches
。然而,应用这种方法会产生;
(qi::matches[qi::raw_token(ABSTRACT)] ^ qi::matches[qi::raw_token(STATIC)] ^ qi::matches[qi::raw_token(FINAL)])
哪种类型;
boost::fusion::vector3<boost::optional<bool>, boost::optional<bool>, boost::optional<bool>>
这确实不是我想要的,所以我将如何进行,以随机顺序匹配这三个令牌,并确定它们是否匹配为布尔值?
答案 0 :(得分:2)
我假设您并不真正需要fusion::vector<bool,bool,bool>
,而您只是想让它发挥作用。如果这个假设是错误的,只需在评论中说些什么。
正如您在documentation中所看到的,置换解析器的属性为tuple<optional<A>,optional<B>>
。在您的情况下,这会转换为fusion::vector<optional<bool>,optional<bool>,optional<bool>>
。由于Spirit使用属性的方式,这个向量与简单的fusion::vector<bool,bool,bool>
兼容。在这种情况下,这意味着可选向量的每个非空组件(由置换解析器实际匹配的组件)被分配给其对应的一个普通bool向量,并且后一个向量中的其余组件保持不变不变。
我在你的例子中看到的问题是qi::matches
directive(它总是成功)和置换解析器(置换集中的每个元素最多可能出现一次)的工作方式。您可以在以下程序的输出中看到此问题:
USING MATCHES: final abstract static
<abstract1>
<try>final abstract stati</try>
<success>final abstract stati</success>
<attributes>[0]</attributes>
</abstract1>
<static1>
<try>final abstract stati</try>
<success>final abstract stati</success>
<attributes>[0]</attributes>
</static1>
<final1>
<try>final abstract stati</try>
<success> abstract static</success>
<attributes>[1]</attributes>
</final1>
它尝试的第一个规则是abstract1
,因为此时的输入是“final”,qi::matches
的参数失败,因此qi::matches
成功返回false。由于abstract1
已经成功,因此置换解析器永远不会再尝试。尝试下一个static1
,结果完全相同。之后输入仍然是“最终”,并且尝试的规则是final1
,它成功返回true。所有三个参数都已成功,因此排列解析器结束,留下“抽象静态”未解析。
你想做的事情的一种方法是使用与他的答案中推荐的第二种选择类似的东西。您需要使用(qi::raw_token(ABSTRACT) >> qi::attr(true)) ^ (qi::raw_token(STATIC) >> qi::attr(true)) ^ (qi::raw_token(FINAL) >> qi::attr(true))
。当KEYWORD >> qi::attr(true)
匹配时,KEYWORD
将成功返回true,否则将失败。如前所述,与空选项对应的最终向量的组件保持不变,因此您需要确保将它们初始化为false(例如,使用默认构造函数)。
#include <iostream>
#include <string>
#include <vector>
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
struct class_info
{
class_info():abstract_(),static_(),final_(){}
bool abstract_;
bool static_;
bool final_;
};
BOOST_FUSION_ADAPT_STRUCT
(
class_info,
(bool, abstract_)
(bool, static_)
(bool, final_)
)
namespace qi=boost::spirit::qi;
template <typename Parser>
void parse_triplet(const std::string& test, const Parser& parser)
{
std::string::const_iterator iter=test.begin(), end=test.end();
class_info parsed_class;
bool result=qi::phrase_parse(iter,end,parser,qi::space,parsed_class);
if(!result)
{
std::cout << "The triplet could not be parsed. Unparsed: " << std::string(iter,end) << std::endl;
}
else
{
if(iter==end)
{
std::cout << "A triplet was parsed." << std::endl;
std::cout << parsed_class.abstract_ << parsed_class.static_ << parsed_class.final_ << std::endl;
}
else
{
std::cout << "A triplet was parsed, but part of the input remained unparsed." << std::endl;
std::cout << parsed_class.abstract_ << parsed_class.static_ << parsed_class.final_ << std::endl;
std::cout << "Unparsed: " << std::string(iter,end) << std::endl;
}
}
}
int main()
{
std::vector<std::string> tests;
tests.push_back("final abstract static");
tests.push_back("final abstract");
tests.push_back("static");
tests.push_back("static abstract");
qi::rule<std::string::const_iterator,bool(),qi::space_type> abstract1, abstract2, static1, static2, final1, final2;
abstract1 = qi::matches[qi::lit("abstract")];
abstract2 = qi::lit("abstract") >> qi::attr(true);
static1 = qi::matches[qi::lit("static")];
static2 = qi::lit("static") >> qi::attr(true);
final1 = qi::matches[qi::lit("final")];
final2 = qi::lit("final") >> qi::attr(true);
BOOST_SPIRIT_DEBUG_NODES( (abstract1)(abstract2)(static1)(static2)(final1)(final2) );
for(std::size_t cont=0; cont < tests.size(); ++cont)
{
//THIS IS WRONG
std::cout << "USING MATCHES: " << tests[cont] << std::endl;
parse_triplet(tests[cont],abstract1 ^ static1 ^ final1);
//THIS WORKS
std::cout << "USING EXPLICIT ATTRIBUTE: " << tests[cont] << std::endl;
parse_triplet(tests[cont],abstract2 ^ static2 ^ final2);
}
}