提升灵气问题与字符串和跳跃
Boost Spirit QI issues with strings and skipping
所以我已经开始玩Boost Spirit库了,它绝对令人惊叹!但在这一过程中,我遇到了很多错误——其中许多是代表我没有完全阅读文档。。但是,在尽可能多地浏览之后,我被关于跳过的属性字符串所困扰。
目前,我想检测一个类似ASM的标签,并将其打印在控制台中,如下所示:
Identifier = qi::lexeme[qi::alpha >> (*qi::alnum | qi::lit("_"))]
Label = Identifier >> ":"
Syntax = Label[phx::bind(&Grammar::print, this, qi::_1)];
其中phx::bind向cout调用一个简单的打印字符串函数。规则是这样定义的:
qi::rule<Iterator, std::string(), ascii::space_type> Identifier;
qi::rule<Iterator, std::string(), ascii::space_type> Label;
qi::rule<Iterator, ascii::space_type> Syntax;
这是有效的,但问题是,我不希望船长在标识符和":"之间跳过。
我试过:
Label = qi::lexeme [Identifier >> ":"]
Label = qi::no_skip[.................]
etc
但我收到错误消息,例如转换为参数4-无法转换未使用的跳过程序<..>到char_class<..>这是有道理的。我还尝试删除规则定义中的队长类型,但没有成功。然后我试着把它混合起来,让一些规则属性字符串,而另一些则不然,并使用as_string将它们转换为字符串,效果很好,但输出是空的。所以我来了。被难住了。
关于属性传播,是否有我不了解的地方?或者可能是关于一般属性的东西。甚至可能是一个从非跳过序列中返回字符串的方法?
有人能告诉我我的错误吗&未来有什么关于属性的提示吗?
非常感谢,亚当。
lexeme解决方案确实有效。
no_skip
和lexeme
指令要求包含的解析器不使用队长,因此需要将Identifier
更改为
qi::rule<Iterator, std::string()> Identifier;
顺便说一句,然后它内部的lexeme
变成了冗余:
qi::rule<It, std::string() > Identifier = qi::alpha >> *(qi::alnum | qi::char_("_"));
qi::rule<It, std::string(), qi::space_type> Label = qi::lexeme [ Identifier >> ':' ];
qi::rule<It, qi::space_type> Syntax = Label [ handle_label_(qi::_1) ];
事实上,您可以进一步减少它(通过依赖Syntax
规则中的预跳过):
static const rule<std::string::const_iterator, std::string()>
Identifier = alpha >> *(alnum | char_("_")),
Label = Identifier >> ':';
完整的测试程序:在Coliru上查看直播
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/phoenix/function/adapt_function.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
void handle_label(std::string const& s) { std::cout << "Parsed label '" << s << ":'n"; }
BOOST_PHOENIX_ADAPT_FUNCTION(void, handle_label_, handle_label, 1)
bool using_lexeme(std::string const& input)
{
using namespace qi;
static const rule<std::string::const_iterator, std::string()>
Identifier = alpha >> *(alnum | char_("_")),
Label = Identifier >> ':';
auto f(input.begin()), l(input.end());
return phrase_parse(f, l, Label [ handle_label_(_1) ], space);
}
int main()
{
assert( using_lexeme("some_id:"));
assert( using_lexeme("some_id: "));
assert( using_lexeme(" some_id:"));
assert(!using_lexeme("some_id :"));
}
另外两个注意事项:
no_skip
也没有预先跳过(lexeme
的意思更像是"保持在一起")。尝试差异,看看第三个测试用例将如何失败使用
lit('_')
可以防止将下划线附加到字符串属性。