我为标识符定义了一个规则:以字母字符开头,后跟任意数量的字母数字字符。当我直接解析为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% ");
}
输出结果为:
解析的结果是:'v'
解析的结果是:'' 解析的结果是:'validId2'
解析的结果是:''
正如预期的那样,两种错误情况都不匹配。但在第一种情况下,我的结构只捕获第一个字符。我想保留结构用于组织目的。
如果我调试节点,我得到这个输出:
<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
嵌套在[[[.]]]
内,而正确的情况只有[[.]]
。但我不知道该怎么做。 :)
为什么会出现这种情况?
答案 0 :(得分:5)
为了让你前进,你必须在一个额外的规则中包装你的字符串。
我不知道确切的解释,但您要做的是使用一系列char
解析器解析字符串。使用string
作为属性类型,qi能够使用该属性作为容器来存储多个字符,而结构只是不知道如何执行此操作。也许它有助于提供struct容器属性,但我没有经验。而且只是解析一个可能有点过分的字符串。
在这里改变你的解析器有帮助:
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;
};
}