C++ 编译boost spirit解析器时出现奇怪的静态\u强制转换编译错误

C++ 编译boost spirit解析器时出现奇怪的静态\u强制转换编译错误,c++,parsing,boost,boost-spirit,C++,Parsing,Boost,Boost Spirit,要分析如下表达式: "asd {img} {ref I}sdkflsdlk {img} wmrwerml" 我有这样的代码: struct CMyTag { std::string tagName; std::string tagData; }; BOOST_FUSION_ADAPT_STRUCT(::CMyTag, (std::string, tagName) (std::string, tagData)); struct fillMyTag { template

要分析如下表达式:

"asd {img} {ref I}sdkflsdlk {img} wmrwerml"
我有这样的代码:

struct CMyTag
{
    std::string tagName;
    std::string tagData;
};
BOOST_FUSION_ADAPT_STRUCT(::CMyTag, (std::string, tagName) (std::string, tagData));

struct fillMyTag
{
    template <typename A, typename B = boost::spirit::unused_type, typename C = boost::spirit::unused_type, typename D = boost::spirit::unused_type>
    struct result { typedef void type; };


    void operator()(::CMyTag& _tag, const std::string& _name, const std::string& _type) const
    {
        _tag.tagName = _name;
        _tag.tagData = _type;
    }
};

template <typename Iterator>
struct testTag_grammar : qi::grammar<Iterator, std::vector<CMyTag>()>
{
    testTag_grammar() :
        testTag_grammar::base_type(data)
    {
        data = (text | imgtag | vartag | inctag | blktag | reftag) >> *data;

        imgtagraw %= '{' >> qi::lit("img") >> *(+qi::lit(' ') >> lexeme[+(char_ - '{' - '}')]) >> '}';
        imgtag = imgtagraw[op(qi::labels::_val, "img", boost::spirit::_1)];

        vartagraw %= '{' >> qi::lit("var") >> *(+qi::lit(' ') >> lexeme[+(char_ - '{' - '}')]) >> '}';
        vartag = vartagraw[op(qi::labels::_val, "var", boost::spirit::_1)];

        inctagraw %= '{' >> qi::lit("inc") >> *(+qi::lit(' ') >> lexeme[+(char_ - '{' - '}')]) >> '}';
        inctag = inctagraw[op(qi::labels::_val, "inc", boost::spirit::_1)];

        blktagraw %= '{' >> qi::lit("blank") >> *(+qi::lit(' ') >> lexeme[+(char_ - '{' - '}')]) >> '}';
        blktag = blktagraw[op(qi::labels::_val, "blk", boost::spirit::_1)];

        reftagraw %= '{' >> lexeme[("ref")] >> *(+qi::lit(' ') >> lexeme[+(char_ - '{' - '}')]) >> '}';
        reftag = reftagraw[op(qi::labels::_val, "ref", boost::spirit::_1)];

        textraw %= lexeme[+(char_ - '{' - '}')];
        text = textraw[op(qi::labels::_val, "text", boost::spirit::_1)];
    }

    qi::rule<Iterator, std::string()> imgtagraw, vartagraw, inctagraw, blktagraw, reftagraw, textraw;
    qi::rule<Iterator, CMyTag()> imgtag, vartag, inctag, blktag, reftag, text;
    qi::rule<Iterator, std::vector<CMyTag>()> data;

    boost::phoenix::function<fillMyTag> op;
};
根据opvec的定义:

struct fillMyVec
{
    template <typename A, typename B = boost::spirit::unused_type, typename C = boost::spirit::unused_type, typename D = boost::spirit::unused_type>
    struct result { typedef void type; };


    void operator()(std::vector<CMyTag>& _tagvec, const CMyTag& _name) const
    {
        _tagvec.push_back(_name);
    }

    void operator()(std::vector<CMyTag>& _tagvec, std::vector<CMyTag>& _name) const
    {
        _tagvec.insert(_tagvec.end(), _name.begin(), _name.end());
    }
};

boost::phoenix::function<fillMyVec> opvec;
struct fillMyVec
{
模板
结构结果{typedef void type;};
void运算符()
{
_tagvec.push_back(_name);
}
void运算符()
{
_插入(_tagvec.end(),_name.begin(),_name.end());
}
};
boost::phoenix::功能opvec;
代码开始编译成功,但作为运行的结果,我得到的列表中只有一项。同样在修改之前,当CMytag类型仅为std::string时,我得到了一个std::string列表,其中包含正确的项数

现在我不知道出了什么问题,以及如何解决这个问题

  • 首先,我只能假设

    data = (text | imgtag | vartag | inctag | blktag | reftag) >> *data;
    
    was/means/as(…)表达式的1个或多个重复。把它写成

    data = +(text | imgtag | vartag | inctag | blktag | reftag);
    
    表示相同,但允许属性传播与“公开”属性类型匹配

  • 有许多
    lexeme[]
    指令在不使用skipper时没有任何用途

  • *(+lit(' ') >> lexeme[+(char_ - '{' - '}')])
    
  • 有一个可疑的手动跳过空白,使用跳过程序可能会更好

  • *(+lit(' ') >> lexeme[+(char_ - '{' - '}')])
    
    <> >在您希望“标签名”之后需要一个强制空间时,请考虑使用<代码>运算符和< /代码>运算符。这样,您仍然可以使用skipper

    不管怎样,你可能在找像

  • 即使有船长

    *(+lit(' ') >> lexeme[+(char_ - '{' - '}')])
    
    没有意义,因为
    lexeme[…]
    会占用任何空格直到结束“}”,因此
    *()
    的第二次重复将永远不会应用

    另见

  • 规则之间有很多手动重复。考虑使用<代码> Q::符号< /代码>将输入映射到标签类型。

  • 如果这样做,就更容易避免语义操作(好东西:)。即使没有,也可以使用
    qi::attr
    将特定值公开为
    类型

  • 考虑添加调试信息(请参见下面演示中的
    BOOST\u SPIRIT\u debug

  • 语法简化了 我将把整个语法简化为:

    data = +( ('{' >> tag >> '}') | text );
    
    tag  = lexeme[type >> &char_(" {}")] >> lexeme[*~char_("{}")];
    text = attr("text")                  >> lexeme[+~char_("{}")];
    
    完成了!不再有语义动作,不再有几十条基本相同的规则。没有更复杂的嵌套重复和不清楚的多重性
    type
    现在是一个
    qi::symbols
    解析器,它包含标记名的映射:

    type.add
        ("img",   "img")
        ("var",   "var")
        ("inc",   "inc")
        ("blank", "blk")
        ("ref",   "ref");
    
    下面是一个完整的演示:

    演示

    //#define BOOST_SPIRIT_DEBUG
    #include <boost/fusion/adapted.hpp>
    #include <boost/spirit/include/qi.hpp>
    namespace qi  = boost::spirit::qi;
    
    struct CMyTag
    {
        std::string tagName;
        std::string tagData;
    };
    BOOST_FUSION_ADAPT_STRUCT(::CMyTag, (std::string, tagName) (std::string, tagData))
    
    template <typename Iterator, typename Skipper = qi::space_type>
    struct testTag_grammar : qi::grammar<Iterator, std::vector<CMyTag>(), Skipper>
    {
        testTag_grammar() :
            testTag_grammar::base_type(data)
        {
            using namespace qi;
    
            data = +( ('{' >> tag >> '}') | text );
    
            type.add
                ("img",   "img")
                ("var",   "var")
                ("inc",   "inc")
                ("blank", "blk")
                ("ref",   "ref");
    
            tag  = lexeme[type >> &char_(" {}")] >> lexeme[*~char_("{}")];
            text = attr("text")                  >> lexeme[+~char_("{}")];
    
            BOOST_SPIRIT_DEBUG_NODES( (data) (tag) (text))
        }
    
      private:
        qi::symbols<char, std::string> type;
        qi::rule<Iterator, CMyTag(), Skipper>              tag, text;
        qi::rule<Iterator, std::vector<CMyTag>(), Skipper> data;
    };
    
    int main() {
        testTag_grammar<std::string::const_iterator> l_gramar;
        std::string const l_test = "asd {img} {ref I}sdkflsdlk {img} wmrwerml";
    
        std::vector<CMyTag> l_result;
        auto f = l_test.begin(), l = l_test.end();
        bool result = qi::phrase_parse(f, l, l_gramar, qi::space, l_result);
    
        if (result) {
            std::cout << "Parse success: " << l_result.size() << "\n";
    
            for (auto& v : l_result)
                std::cout << "Name '" << v.tagName << "', Data '" << v.tagData << "'\n";
        }
        else {
            std::cout << "Parse failed\n";
        }
    
        if (f!=l) {
            std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
        }
    }
    

    您可能希望看到类似的语法:或者我在更改
    data=(text | imgtag | vartag | inctag | blktag | reftag)>*数据时解决了这个问题
    数据=(text | imgtag | vartag | inctag | blktag | reftag)>>数据fusion::vector2
    ,因此当解析器“自然”合成兼容的属性类型时(如文件所述,对引用的属性的赋值将是自动的。此外,该解析器的工作方式也不正确,例如
    asd{img}alksdla{blank}{img}s{ref s 0x5464564}s
    和第二个文本必须是“alksdla”,但它有后面的内容“alksdla”,而不是空格)begining@RuslanUsifov嗯,我得编一些“合理的”由于语法非常复杂,无法正常工作!下次,请指定预期的输出。更改非常简单:。如果您在此处花一些时间学习新内容,可能还可以:)。也请注意,这就是我为什么选择其他两个示例的原因。看起来它们与您在这里所做的完全一样。我不是有意冒犯您,您发布的内容对我非常有用,正如我所说。在第一个示例中,输出与预期一样。因此我认为Skipper和短语_parse不适用于这种情况,我必须使用qi::parse,但空间c非常奇怪但仅仅从一开始,我就认为在短语_的情况下,解析空间将从字符串的开头和结尾移除(就像trim一样)
    //#define BOOST_SPIRIT_DEBUG
    #include <boost/fusion/adapted.hpp>
    #include <boost/spirit/include/qi.hpp>
    namespace qi  = boost::spirit::qi;
    
    struct CMyTag
    {
        std::string tagName;
        std::string tagData;
    };
    BOOST_FUSION_ADAPT_STRUCT(::CMyTag, (std::string, tagName) (std::string, tagData))
    
    template <typename Iterator, typename Skipper = qi::space_type>
    struct testTag_grammar : qi::grammar<Iterator, std::vector<CMyTag>(), Skipper>
    {
        testTag_grammar() :
            testTag_grammar::base_type(data)
        {
            using namespace qi;
    
            data = +( ('{' >> tag >> '}') | text );
    
            type.add
                ("img",   "img")
                ("var",   "var")
                ("inc",   "inc")
                ("blank", "blk")
                ("ref",   "ref");
    
            tag  = lexeme[type >> &char_(" {}")] >> lexeme[*~char_("{}")];
            text = attr("text")                  >> lexeme[+~char_("{}")];
    
            BOOST_SPIRIT_DEBUG_NODES( (data) (tag) (text))
        }
    
      private:
        qi::symbols<char, std::string> type;
        qi::rule<Iterator, CMyTag(), Skipper>              tag, text;
        qi::rule<Iterator, std::vector<CMyTag>(), Skipper> data;
    };
    
    int main() {
        testTag_grammar<std::string::const_iterator> l_gramar;
        std::string const l_test = "asd {img} {ref I}sdkflsdlk {img} wmrwerml";
    
        std::vector<CMyTag> l_result;
        auto f = l_test.begin(), l = l_test.end();
        bool result = qi::phrase_parse(f, l, l_gramar, qi::space, l_result);
    
        if (result) {
            std::cout << "Parse success: " << l_result.size() << "\n";
    
            for (auto& v : l_result)
                std::cout << "Name '" << v.tagName << "', Data '" << v.tagData << "'\n";
        }
        else {
            std::cout << "Parse failed\n";
        }
    
        if (f!=l) {
            std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
        }
    }
    
    Parse success: 6
    Name 'text', Data 'asd '
    Name 'img', Data ''
    Name 'ref', Data 'I'
    Name 'text', Data 'sdkflsdlk '
    Name 'img', Data ''
    Name 'text', Data 'wmrwerml'