如何使用存储在 boostspirit 闭包中的变量作为 boostspirit 循环解析器的输入?

发布于 2024-08-05 16:23:29 字数 1559 浏览 2 评论 0原文

我想使用解析值作为循环解析器的输入。

该语法定义了一个标头,该标头指定以下字符串的(可变)大小。例如,假设以下字符串是某个解析器的输入。

12\r\n测试有效负载

解析器应该提取12,将其转换为无符号整数,然后读取12个字符。我可以定义一个可以编译的 boostspirit 语法,但是 boostspirit 代码中的断言在运行时失败。

#include <iostream>
#include <boost/spirit.hpp>

using namespace boost::spirit;

struct my_closure : public closure<my_closure, std::size_t> {
member1 size;
};

struct my_grammar : public grammar<my_grammar> {
template <typename ScannerT>
struct definition {
    typedef rule<ScannerT> rule_type;
    typedef rule<ScannerT, my_closure::context_t> closure_rule_type;

    closure_rule_type header;
    rule_type payload;
    rule_type top;

    definition(const my_grammar &self)
    {
        using namespace phoenix;
        header = uint_p[header.size = arg1];
        payload = repeat_p(header.size())[anychar_p][assign_a(self.result)];
        top = header >> str_p("\r\n") >> payload;
    }

    const rule_type &start() const { return top; }
};

my_grammar(std::string &p_) : result(p_) {}
std::string &result;
};

int
main(int argc, char **argv)
{
const std::string content = "12\r\nTest Payload";
std::string payload;
my_grammar g(payload);
if (!parse(content.begin(), content.end(), g).full) {
    std::cerr << "there was a parsing error!\n";
    return -1;
}
std::cout << "Payload: " << payload << std::endl;
return 0;
}

是否有可能告诉spirit应该延迟评估闭包变量?这种行为是否得到了Boost精神的支持?

I would like to use a parsed value as the input to a loop parser.

The grammar defines a header that specifies the (variable) size of the following string. For example, say the following string is the input to some parser.

12\r\nTest Payload

The parser should extract the 12, convert it to an unsigned int and then read twelve characters. I can define a boost spirit grammar that compiles, but an assertion in the boost spirit code fails at runtime.

#include <iostream>
#include <boost/spirit.hpp>

using namespace boost::spirit;

struct my_closure : public closure<my_closure, std::size_t> {
member1 size;
};

struct my_grammar : public grammar<my_grammar> {
template <typename ScannerT>
struct definition {
    typedef rule<ScannerT> rule_type;
    typedef rule<ScannerT, my_closure::context_t> closure_rule_type;

    closure_rule_type header;
    rule_type payload;
    rule_type top;

    definition(const my_grammar &self)
    {
        using namespace phoenix;
        header = uint_p[header.size = arg1];
        payload = repeat_p(header.size())[anychar_p][assign_a(self.result)];
        top = header >> str_p("\r\n") >> payload;
    }

    const rule_type &start() const { return top; }
};

my_grammar(std::string &p_) : result(p_) {}
std::string &result;
};

int
main(int argc, char **argv)
{
const std::string content = "12\r\nTest Payload";
std::string payload;
my_grammar g(payload);
if (!parse(content.begin(), content.end(), g).full) {
    std::cerr << "there was a parsing error!\n";
    return -1;
}
std::cout << "Payload: " << payload << std::endl;
return 0;
}

Is it possible to tell spirit that the closure variable should be evaluated lazily? Is this behaviour supported by boost spirit?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

原来是傀儡 2024-08-12 16:23:29

使用 Spirit 2 中提供的新 qi 解析器,这要容易得多。以下代码片段提供了一个大部分有效的完整示例。最终结果中插入了意外字符。

#include <iostream>
#include <string>

#include <boost/version.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_repeat.hpp>
#include <boost/spirit/include/qi_grammar.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>

using boost::spirit::qi::repeat;
using boost::spirit::qi::uint_;
using boost::spirit::ascii::char_;
using boost::spirit::ascii::alpha;
using boost::spirit::qi::_1;
namespace phx = boost::phoenix;
namespace qi = boost::spirit::qi;

template <typename P, typename T>
void test_parser_attr(
    char const* input, P const& p, T& attr, bool full_match = true)
{
    using boost::spirit::qi::parse;

    char const* f(input);
    char const* l(f + strlen(f));
    if (parse(f, l, p, attr) && (!full_match || (f == l)))
        std::cout << "ok" << std::endl;
    else
        std::cout << "fail" << std::endl;
}

static void
straight_forward()
{
    std::string str;
    int n;
    test_parser_attr("12\r\nTest Payload",
                     uint_[phx::ref(n) = _1] >> "\r\n" >> repeat(phx::ref(n))[char_],
                     str);
    std::cout << "str.length() == " << str.length() << std::endl;
    std::cout << n << "," << str << std::endl;  // will print "12,Test Payload"
}

template <typename P, typename T>
void
test_phrase_parser(char const* input, P const& p,
                   T& attr, bool full_match = true)
{
    using boost::spirit::qi::phrase_parse;
    using boost::spirit::qi::ascii::space;

    char const* f(input);
    char const* l(f + strlen(f));
    if (phrase_parse(f, l, p, space, attr) && (!full_match || (f == l)))
        std::cout << "ok" << std::endl;
    else
        std::cout << "fail" << std::endl;
}

template <typename Iterator>
struct test_grammar
    : qi::grammar<Iterator, std::string(), qi::locals<unsigned> > {

    test_grammar()
        : test_grammar::base_type(my_rule)
    {
        using boost::spirit::qi::_a;
        my_rule %= uint_[_a = _1] >> "\r\n" >> repeat(_a)[char_];
    }

    qi::rule<Iterator, std::string(), qi::locals<unsigned> > my_rule;
};

static void
with_grammar_local_variable()
{
    std::string str;
    test_phrase_parser("12\r\nTest Payload", test_grammar<const char*>(), str);
    std::cout << str << std::endl;  // will print "Test Payload"
}

int
main(int argc, char **argv)
{
    std::cout << "boost version: " << BOOST_LIB_VERSION << std::endl;

    straight_forward();
    with_grammar_local_variable();

    return 0;
}

This is much easier with the new qi parser available in Spirit 2. The following code snippet provides a full example that mostly works. An unexpected character is being inserted into the final result.

#include <iostream>
#include <string>

#include <boost/version.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_repeat.hpp>
#include <boost/spirit/include/qi_grammar.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>

using boost::spirit::qi::repeat;
using boost::spirit::qi::uint_;
using boost::spirit::ascii::char_;
using boost::spirit::ascii::alpha;
using boost::spirit::qi::_1;
namespace phx = boost::phoenix;
namespace qi = boost::spirit::qi;

template <typename P, typename T>
void test_parser_attr(
    char const* input, P const& p, T& attr, bool full_match = true)
{
    using boost::spirit::qi::parse;

    char const* f(input);
    char const* l(f + strlen(f));
    if (parse(f, l, p, attr) && (!full_match || (f == l)))
        std::cout << "ok" << std::endl;
    else
        std::cout << "fail" << std::endl;
}

static void
straight_forward()
{
    std::string str;
    int n;
    test_parser_attr("12\r\nTest Payload",
                     uint_[phx::ref(n) = _1] >> "\r\n" >> repeat(phx::ref(n))[char_],
                     str);
    std::cout << "str.length() == " << str.length() << std::endl;
    std::cout << n << "," << str << std::endl;  // will print "12,Test Payload"
}

template <typename P, typename T>
void
test_phrase_parser(char const* input, P const& p,
                   T& attr, bool full_match = true)
{
    using boost::spirit::qi::phrase_parse;
    using boost::spirit::qi::ascii::space;

    char const* f(input);
    char const* l(f + strlen(f));
    if (phrase_parse(f, l, p, space, attr) && (!full_match || (f == l)))
        std::cout << "ok" << std::endl;
    else
        std::cout << "fail" << std::endl;
}

template <typename Iterator>
struct test_grammar
    : qi::grammar<Iterator, std::string(), qi::locals<unsigned> > {

    test_grammar()
        : test_grammar::base_type(my_rule)
    {
        using boost::spirit::qi::_a;
        my_rule %= uint_[_a = _1] >> "\r\n" >> repeat(_a)[char_];
    }

    qi::rule<Iterator, std::string(), qi::locals<unsigned> > my_rule;
};

static void
with_grammar_local_variable()
{
    std::string str;
    test_phrase_parser("12\r\nTest Payload", test_grammar<const char*>(), str);
    std::cout << str << std::endl;  // will print "Test Payload"
}

int
main(int argc, char **argv)
{
    std::cout << "boost version: " << BOOST_LIB_VERSION << std::endl;

    straight_forward();
    with_grammar_local_variable();

    return 0;
}
这个俗人 2024-08-12 16:23:29

您正在寻找的是lazy_p,请检查此处的示例: http://www.boost.org/doc/libs/1_35_0/libs/spirit/doc/the_lazy_parser.html

What you are looking for is lazy_p, check the example here: http://www.boost.org/doc/libs/1_35_0/libs/spirit/doc/the_lazy_parser.html

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文