Реальная проблема заключается в том, что вы определяете атрибут для правил tag / non_tag как query_term
(вместо query_term()
).
Некоторые незначительные проблемы:
- с использованием
word
вместо non_tag
(предоставляет std :: string, которая не преобразуется в query_type
)
- использование
% space
с космическим шкипером не имеет смысла
- вы, вероятно, хотели
lexeme
в правиле word
, потому что в противном случае он будет просто "съедать" символы независимо от пробела
Другие предложения:
избегайте избыточного объема using namespace
(или избегайте его полностью). Вы будете сталкиваться с трудными для обнаружения или трудно исправить конфликтами (например, boost :: cref против std :: cref, std :: string против qi :: string и т. Д.).
старайтесь не использовать Феникс. В этом случае, я думаю, вам будет гораздо проще использовать qi::attr
с адаптированной структурой.
используйте макросы BOOST_SPIRIT_DEBUG_ *, чтобы получить представление о вашем парсере
Вот вся грамматика, как я бы ее предложил:
template<typename Iterator> struct query_grammar: qi::grammar<Iterator, std::vector<query_term>(), qi::space_type>
{
query_grammar() : query_grammar::base_type(query)
{
using namespace qi;
word = lexeme[ +alnum ];
tag = omit[word >> ':'] >> word >> attr(true);
non_tag = word >> attr(false);
query = *(tag | non_tag);
};
qi::rule<Iterator, std::string() , qi::space_type> word;
qi::rule<Iterator, query_term() , qi::space_type> tag, non_tag;
qi::rule<Iterator, std::vector<query_term>(), qi::space_type> query;
};
Полностью рабочий пример с выводом (тривиально, используя карму):
// #define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;
struct query_term {
std::string term;
bool is_tag;
};
BOOST_FUSION_ADAPT_STRUCT(query_term, (std::string,term)(bool,is_tag));
template<typename Iterator> struct query_grammar: qi::grammar<Iterator, std::vector<query_term>(), qi::space_type>
{
query_grammar() : query_grammar::base_type(query)
{
using namespace qi;
word = lexeme[ +alnum ];
tag = omit[word >> ':'] >> word >> attr(true);
non_tag = word >> attr(false);
query = *(tag | non_tag);
BOOST_SPIRIT_DEBUG_NODE(word);
BOOST_SPIRIT_DEBUG_NODE(tag);
BOOST_SPIRIT_DEBUG_NODE(non_tag);
BOOST_SPIRIT_DEBUG_NODE(query);
};
qi::rule<Iterator, std::string() , qi::space_type> word;
qi::rule<Iterator, query_term() , qi::space_type> tag, non_tag;
qi::rule<Iterator, std::vector<query_term>(), qi::space_type> query;
};
int main()
{
const std::string input = "apple tag:beer banana grape";
typedef std::string::const_iterator It;
query_grammar<It> parser;
std::vector<query_term> data;
It f(input.begin()), l(input.end());
bool ok = qi::phrase_parse(f, l, parser, qi::space, data);
if (ok)
std::cout << karma::format(karma::delimit [ karma::auto_ ] % karma::eol, data) << '\n';
if (f!=l)
std::cerr << "Unparsed: '" << std::string(f,l) << "'\n";
return ok? 0 : 255;
}
Выход:
apple false
beer true
banana false
grape false