boost :: spirit在第一场比赛时停止

时间:2014-11-07 10:41:46

标签: c++ boost-spirit-qi

我正在尝试解析以下内容:

  [SOFT] AQUA+
  [FORWARD_SPEED]   0.00
  [some other key] string value
  [PERIODS_NUMBER]  6
  [HEADINGS_NUMBER] 13
  [LOWEST_HEADINGS]   0.00
  [HIGHEST_HEADINGS] 180.00

我事先并不知道钥匙是什么。

我想在向量结构中解析它们。

namespace hdb
{
    typedef std::string Header;
    template <typename T> struct Key
    {
        Header header;
        T      value;
    };

    struct AST
    {
        std::vector<Key<std::string> > string_keys;
        std::vector<Key<double> >      value_keys;
    }
}

我写了适配器:

BOOST_FUSION_ADAPT_STRUCT(
    hdb::Key<std::string>,
    (hdb::Header, header)
    (std::string, value)
)

BOOST_FUSION_ADAPT_STRUCT(
    hdb::Key<double>,
    (hdb::Header, header)
    (double, value)
)

namespace boost { namespace spirit { namespace traits {

template<>
    struct is_container<hdb::AST, void> : mpl::true_ { };
template<>
    struct container_value<hdb::AST, void> {
         typedef boost::variant<
                 hdb::Key<std::string>
                ,hdb::Key<double>
         > type;
    };

template <>
    struct push_back_container<hdb::AST, hdb::Key<std::string>, void> {
        static bool call(hdb::AST& f, const hdb::Key<std::string>& val) {
            f.string_keys.push_back(val);
            return true;
        }
    };
template <>
        struct push_back_container<hdb::AST, hdb::Key<double>, void> {
            static bool call(hdb::AST& f, const hdb::Key<double>& val) {
                f.value_keys.push_back(val);
                return true;
            }
        };

语法如下:

template <typename Iterator>
struct hdb_grammar : qi::grammar<Iterator, hdb::AST(), ascii::space_type>
{

    hdb_grammar() : hdb_grammar::base_type(ast)
    {

        ast        %= string_key | value_key;
        header     %= lexeme['[' >> +(char_ - '[' - ']') >> ']'];
        string_key %= header >> +(char_ - '[' - ']');
        value_key  %= header >> double_;
    }

    qi::rule<Iterator, hdb::AST(), ascii::space_type>                  ast;
    qi::rule<Iterator, hdb::Header(), ascii::space_type>               header;
    qi::rule<Iterator, hdb::Key<double>(), ascii::space_type>          value_key;
    qi::rule<Iterator, hdb::Key<std::string>(), ascii::space_type>     string_key;
};

我像这样调用解析器:

const std::string contents = "[key 1] value 1\n"
                             "[key 2] value 2\n";

typedef hdb_grammar<std::string::const_iterator> grammar;
grammar g; // Our grammar
hdb::AST ast; // Our tree

using boost::spirit::ascii::space;
std::string::const_iterator begin = contents.begin(), end = contents.end();
bool success = qi::phrase_parse(begin, end, g.ast, space, ast); // Only fills "key 1" & not "key 2"

我认为问题在于我的语法,但我不能为我的生活看到它的错误。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

您只需有效地解析(string_key | value_key)。如果您想重复此操作,请使用Kleene star或plus:

bool success = qi::phrase_parse(begin, end, *g, space, ast); 

这允许0个或更多AST匹配,每次都会传递相同的属性。

使用调试信息查看 Live On Coliru


及其简化

那就是说,我宁愿用自然的灵魂模式来写同样的东西。这是22行(从~100)包含的相同功能:

Live On Coliru

#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/include/qi.hpp>
#include <map>

typedef boost::variant<double, std::string> Value;
typedef std::map<std::string, Value>        AST;

int main() {
    namespace qi = boost::spirit::qi;
    typedef boost::spirit::istream_iterator It;
    static qi::rule<It, std::string()> const string_ = +~qi::char_("[]\r\n");

    It begin(std::cin >> std::noskipws), end;

    AST ast;
    bool success = qi::phrase_parse(begin, end, 
            ('[' >> string_ >> ']' >> (qi::double_|string_)) % qi::eol,
            qi::blank, ast);

    if (success) for (auto& e : ast) 
        std::cout << '[' << e.first << "]\t" << e.second << "\n";
}

打印

[FORWARD_SPEED] 0
[HEADINGS_NUMBER]   13
[HIGHEST_HEADINGS]  180
[LOWEST_HEADINGS]   0
[PERIODS_NUMBER]    6
[SOFT]  AQUA+
[some other key]    string value