为什么Boost.Spirit可以正确地将标识符解析为std :: string而不是解析为仅由std :: string组成的适应结构? [英] Why does Boost.Spirit correctly parse an identifier into a std::string, but not into an adapted struct consisting solely of std::string?

查看:115
本文介绍了为什么Boost.Spirit可以正确地将标识符解析为std :: string而不是解析为仅由std :: string组成的适应结构?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我为标识符定义了一条规则:以字母字符开头,后跟任意数量的字母数字字符.当我直接解析为std::string而不是包含单个std::string的经过调整的结构时,我会得到不同的结果.

I have defined a rule for an identifier: start with an alpha character, followed by any number of alpha-numeric characters. I have differing results when I parse directly into a std::string versus an adapted struct containing a single std::string.

如果我的语法属性是std::string,则Qi会正确地将字符序列调整到其中.但是使用该结构时,仅存储第一个字符.我不太清楚为什么会这样. (请注意,如果该结构是真正"适应的,或者是由Fusion inline定义的,则没有区别.)

If the attribute for my grammar is std::string, Qi will correctly adapt the sequence of characters into it. But with the struct, only the first character is stored. I'm not quite sure why this is. (Note that it makes no difference if the struct is "truly" adapted, or if it was defined by Fusion inline.)

这是一个 SSCCE ,可对其进行配置以进行调试:

Here's a SSCCE, configurable to debug:

// Options:
//#define DEFINE_STRUCT_INLINE
//#define DEBUG_RULE

#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

#include <boost/fusion/adapted/struct/define_struct_inline.hpp>
#include <boost/fusion/include/define_struct_inline.hpp>

#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/include/adapt_struct.hpp>

#include <iostream>
#include <string>

namespace qi = boost::spirit::qi;

#ifdef DEFINE_STRUCT_INLINE
    namespace example
    {
        BOOST_FUSION_DEFINE_STRUCT_INLINE(
            identifier_result,
            (std::string, name)
            )
    }
#else
    namespace example
    {
        struct identifier_result
        {
            std::string name;
        };
    }

    BOOST_FUSION_ADAPT_STRUCT(
        example::identifier_result,
        (std::string, name)
        )
#endif

namespace example
{
    typedef std::string identifier_result_str;

    template <typename Iterator, typename Result>
    struct identifier_parser : qi::grammar<Iterator, Result()>
    {
        identifier_parser() :
        identifier_parser::base_type(identifier, "identifier_parser")
        {
            identifier %=
                qi::alpha >>
                *qi::alnum
                ;

            identifier.name("identifier");

            #ifdef DEBUG_RULE
                debug(identifier);
            #endif
        }

        qi::rule<Iterator, Result()> identifier;
    };
}

std::string strip(example::identifier_result identifier)
{
    return identifier.name;
}

std::string strip(std::string str)
{
    return str;
}

template <typename Result>
void test_parse(const std::string& input)
{
    using namespace example;

    auto&& first = input.cbegin();
    auto&& last = input.cend();

    auto&& parser = identifier_parser<std::string::const_iterator, Result>();
    auto&& skipper = qi::space;

    Result result;
    qi::phrase_parse(first, last, parser, skipper, result);

    std::cout << "Result of the parse is: \'"
              << strip(result) << "\'" << std::endl;
}

int main()
{
    using namespace example;

    test_parse<identifier_result>(" validId1 ");
    test_parse<identifier_result>(" %error1% ");

    test_parse<identifier_result_str>(" validId2 ");
    test_parse<identifier_result_str>(" %error2% ");
}

输出为:

解析结果为:'v'
解析的结果是:''
解析的结果是:'validId2'
解析的结果是:''

Result of the parse is: 'v'
Result of the parse is: ''
Result of the parse is: 'validId2'
Result of the parse is: ''

如预期的那样,两种错误情况都不匹配.但在第一种情况下,我的结构仅捕获第一个字符.我想保留该结构用于组织目的.

As expected, both error cases don't match. But in the first case, my struct only captures the first character. I'd like to keep the struct for organization purposes.

如果我调试节点,则会得到以下输出:

If I debug the node, I get this output:

<identifier>
  <try>validId1 </try>
  <success> </success>
  <attributes>[[[v]]]</attributes>
</identifier>

[ ... ]

<identifier>
  <try>validId2 </try>
  <success> </success>
  <attributes>[[v, a, l, i, d, I, d, 2]]</attributes>
</identifier>

所以我可以看到规则正在消耗整个标识符,只是没有正确存储它.我唯一的区别是第一种情况下的v嵌套在[[[.]]]内,而正确的情况只是[[.]].但是我不知道该怎么办. :)

So I can see the rule is consuming the entire identifier, it just isn't storing it correctly. The only "hint" I have at the difference is that the v in the first case is nested within [[[.]]], while the correct case is only [[.]]. But I don't know what to do with it. :)

为什么会出现这种现象?

Why does this behavior occur?

推荐答案

只是为了让您前进,您必须将字符串包装在一条附加规则中.

Just to get you going, you have to wrap your string in an extra rule.

我不知道确切的解释,但是您想要做的是使用一个char解析器序列解析一个字符串.使用string作为属性类型,qi可以使用该属性作为容器来存储几个字符,对于结构,它只是不知道如何执行此操作.也许有助于提供struct容器的属性,但是我在这里没有经验.并且仅用于解析可能会过大的字符串.

I don't know the exact explanation, but what you want to do is parsing a string with a sequence of char parsers. With string as attribute type qi is able to use the attribute as container to store several chars, with a struct it just doesn't know how to do this. Maybe it would help to give the struct container properties, but I've no experience here. And for just parsing a string that might be overkill.

只需更改解析器,即可在以下方面有所帮助:

Just altering your parser helps here:

namespace example
{
    typedef std::string identifier_result_str;

    template <typename Iterator, typename Result>
    struct identifier_parser : qi::grammar<Iterator, Result()>
    {
        identifier_parser() :
        identifier_parser::base_type(identifier, "identifier_parser")
        {
            string %=
                qi::alpha >>
                *qi::alnum
                ;

            identifier = string;
            identifier.name("identifier");

            #ifdef DEBUG_RULE
                debug(identifier);
            #endif
        }

        qi::rule<Iterator, Result()> identifier;
        qi::rule<Iterator, std::string()> string;
    };
}

这篇关于为什么Boost.Spirit可以正确地将标识符解析为std :: string而不是解析为仅由std :: string组成的适应结构?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆