gpt4 book ai didi

c++ - 为什么 Boost.Spirit 正确地将标识符解析为 std::string,而不是解析为仅由 std::string 组成的适配结构?

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:45:49 24 4
gpt4 key购买 nike

我为标识符定义了一条规则:以字母字符开头,后跟任意数量的字母数字字符。当我直接解析为 std::string 与包含单个 std::string 的改编结构时,我得到不同的结果。

如果我的语法属性是 std::string,Qi 会正确地将字符序列调整到其中。但是对于结构,只存储第一个字符。我不太确定这是为什么。 (请注意,如果结构是“真正”改编的,或者它是由 Fusion 内联定义的,这没有区别。)

这是一个 SSCCE ,可配置调试:

// 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% ");
}

输出是:

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

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

如果我调试节点,我会得到这个输出:

<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 嵌套在 [[[.]]] 中,而正确的情况只有 [[.]]。但我不知道该怎么办。 :)

为什么会出现这种行为?

最佳答案

为了让您继续,您必须将您的字符串包裹在一个额外的规则中。

我不知道确切的解释,但你想要做的是用一系列 char 解析器解析一个字符串。使用 string 作为属性类型,qi 能够使用属性作为容器来存储多个字符,对于结构它只是不知道如何做到这一点。也许给结构容器属性会有所帮助,但我在这里没有经验。仅仅解析一个可能有点矫枉过正的字符串。

只要改变你的解析器就可以帮助这里:

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;
};
}

关于c++ - 为什么 Boost.Spirit 正确地将标识符解析为 std::string,而不是解析为仅由 std::string 组成的适配结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18166958/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com