尝试学习Boost :: Spirit并希望解决c风格标识符的简单示例。下面的语法没有编译声明“incompatible_start_rule”#。目标是这个语法返回一个字符串而不是一个字符串向量,就像默认的属性传播规则一样。
template <typename IT>
struct cppIdentifier : qi::grammar<IT, std::string, space_type()>
{
cppIdentifier() : cppIdentifier::base_type(start)
{
start = char_("a-zA-Z_")[boost::phoenix::push_back(_val, _1)]
>> *(char_("a-zA-Z0-9_")[boost::phoenix::push_back(_val, _1)]);
}
qi::rule<IT, std::string, space_type> start;
};
我需要做些什么来实现这个目标?
另请注意,我很清楚这个特定问题可能有很多替代的,更方便的选项,但我在学术上对如何操纵自定义语法的属性类型感兴趣,所以请留下这些评论而不是答案。
答案 0 :(得分:2)
首先,您需要使用function-signature-style模板参数来指定规则的输出属性类型(以及继承的属性类型,如果有的话)。而不是qi::grammar<IT, std::string, space_type()>
,请尝试qi::grammar<IT, std::string(), space_type>
。
其次,你不需要在这里进行语义动作 - 但是如果你计划使用短语解析器,那么你需要lexeme[]
指令:
template <typename IT>
struct cppIdentifier : qi::grammar<IT, std::string(), qi::space_type>
{
cppIdentifier() : cppIdentifier::base_type(start)
{
start = qi::lexeme[char_("a-zA-Z_") >> *(char_("a-zA-Z0-9_"))];
}
qi::rule<IT, std::string(), qi::space_type> start;
};
最后,确保将兼容的skipper对象传递给phrase_parse:
std::string s = "HELLO 123";
cppIdentifier < std::string::const_iterator> id;
std::string ident;
qi::phrase_parse(s.cbegin(), s.cend(), id, qi::space_type(), ident);
// without lexeme[], ident becomes "HELLO123", not "HELLO"