提升灵气问题与字符串和跳跃

Boost Spirit QI issues with strings and skipping

本文关键字:字符串 跳跃 问题      更新时间:2023-10-16

所以我已经开始玩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_skiplexeme指令要求包含的解析器不使用队长,因此需要将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('_')可以防止将下划线附加到字符串属性。