2

在我的 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,只有一个案例,我会使用qi::matches,如建议的here。然而,应用这种方法会产生;

(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>>

这确实不是我想要的,那么我将如何进行,以随机顺序匹配这三个标记,并获取它们是否匹配为布尔值?

4

1 回答 1

2

我假设您并不真的需要 afusion::vector<bool,bool,bool>并且您只是希望它工作。如果这个假设是错误的,只需在评论中说些什么。

正如您在文档中看到的,排列解析器的属性是tuple<optional<A>,optional<B>>. 在您的情况下,这转换为fusion::vector<optional<bool>,optional<bool>,optional<bool>>. 由于 Spirit 使用属性的方式,该向量与简单的fusion::vector<bool,bool,bool>. 在这种情况下,这意味着可选向量的每个非空分量(由置换解析器实际匹配的分量)都分配给其对应的一个普通 bool 向量,而后一个向量中的其余分量保持不变不变。

我在您的示例中看到的问题在于qi::matches指令(它总是成功)和排列解析器(排列集中的每个元素最多可能出现一次)的工作方式。你可以在下面程序的输出中看到这个问题:

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,因为此时的输入是“最终的”,所以 的参数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)匹配时将成功返回 true KEYWORD,否则失败。如前所述,与空选项对应的最终向量的组件保持不变,因此您需要确保将它们初始化为 false(例如,使用默认构造函数)。

在 Coliru 上运行:

#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);


    }
}
于 2013-09-10T14:57:29.320 回答