C++ Boost::Spirit中的复合语法

C++ Boost::Spirit中的复合语法,c++,parsing,boost,boost-spirit,C++,Parsing,Boost,Boost Spirit,我有下面的语法,它按预期工作 struct query_term { std::string term; bool is_tag; query_term(const std::string &a, bool tag = false): term(a), is_tag(tag) { } }; template<typename Iterator> struct query_grammar: grammar<Iterator, std::vect

我有下面的语法,它按预期工作

struct query_term {
    std::string term;
    bool is_tag;

    query_term(const std::string &a, bool tag = false): term(a), is_tag(tag) { } };

template<typename Iterator> struct query_grammar: grammar<Iterator, std::vector<query_term>(), space_type> {
    query_grammar():
        query_grammar::base_type(query) {

        word %= +alnum;
        tag  =  (omit[word >> ':'] >> word[_val = phoenix::construct<query_term>(_1, true)]);
        non_tag  =  word[_val = phoenix::construct<query_term>(_1, false)];
        query = (
                  (omit[word >> ':'] >> word[push_back(_val, phoenix::construct<query_term>(_1, true))])
                |
                  word[push_back(_val,
                            phoenix::construct<query_term>(_1))
                  ]
                ) % space;
    };

    qi::rule<Iterator, std::string(), space_type> word;
    qi::rule<Iterator, query_term, space_type> tag;
    qi::rule<Iterator, query_term, space_type> non_tag;
    qi::rule<Iterator, std::vector<query_term>(), space_type> query; };
<代码>结构查询\u术语{ std::字符串项; 布尔是一个标签; query_term(const std::string&a,bool tag=false):term(a),是_tag(tag){}; 模板结构查询语法:语法{ 查询语法(): 查询语法::基本类型(查询){ 字%=+alnum; tag=(省略[word>>':']>>word[\u val=phoenix::construct(_1,true)]; non_tag=word[_val=phoenix::construct(_1,false)]; 查询=( (省略[word>>':']>>word[push_-back(_-val,phoenix::construct(_-1,true))) | 单词[推回, 凤凰城:构造(_1)) ] )%空间; }; 齐:规则词; qi::规则标签; qi::规则非_标记; qi::规则查询;}; 但当我将查询替换为

query = (
          tag[phoenix::push_back(_val, _1)]
        |
          word[push_back(_val,
                    phoenix::construct<query_term>(_1))
          ]
        ) % space;
query=(
标记[phoenix::推回(_val,_1)]
|
单词[推回,
凤凰城:构造(_1))
]
)%空间;
代码不能编译。基本上,我试图将语法拆分为可以在更大的语法中重用的组件。解析单词或标记时,在tagword规则中创建一个带有适当标志的查询词对象。在查询规则中重新使用这些属性

在以前的版本中,标记和单词规则内联在查询语法中

我不确定我在这里错过了什么。任何帮助都将不胜感激

仅供参考:这不是最终代码。在生产代码中使用规则之前,我正在尝试这些规则

Thanx,
--baliga

真正的问题是将标记/非标记规则的属性定义为
query\u term
(而不是
query\u term()

一些小问题似乎是:

  • 使用
    word
    而不是
    non_标记
    (公开一个std::string,它不会转换为
    查询类型
  • %space
    与一个空格跳过器一起使用是没有意义的
  • 您可能希望在
    word
    规则中使用
    lexeme
    ,因为否则,它只会保持“吃”字符,而不考虑空格
其他建议:

  • 使用命名空间避免超出
    的范围(或完全避免)。您将遇到难以发现或难以修复的冲突(例如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;
};

依我看,代码并不漂亮。尝试整理一下,您可能会发现问题所在。代码本身很漂亮,Boost::Spirit有一个运算符重载的语法,您必须使用它。@AshBurlaczenko Thanx,谢谢您的建议。一些提示在这里会有所帮助。我可以为ANTLR插入一个插头吗?:)好吧,你已经遇到了Boost Spirit的一个基本问题,当你做了一些轻微的错误时,这是一个有趣的编译器诊断。试试ANTLR——它真的更好。你真厉害!Thanx用于指出查询类型与查询类型()。这完全是一个打字错误,应该避免。@DudeFromManaglore哈哈,随时都可以!
// #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