Как вы используете переменную, хранящуюся в замыкании духа ускорения, в качестве входных данных для синтаксического анализатора цикла ускорения?

Я хотел бы использовать проанализированное значение в качестве входных данных для синтаксического анализатора цикла.

Грамматика определяет заголовок, который определяет (переменный) размер следующей строки. Например, предположим, что следующая строка является вводом для некоторого синтаксического анализатора.

12 \ r \ nТестовая полезная нагрузка

Синтаксический анализатор должен извлечь 12, преобразовать его в unsigned int, а затем прочитать двенадцать символов. Я могу определить грамматику духа повышения, которая компилируется, но утверждение в коде духа повышения не работает во время выполнения.

#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;
}

Можно ли сказать духу, что закрывающая переменная должна вычисляться лениво? Поддерживается ли такое поведение духом наддува?


person Dan    schedule 25.09.2009    source источник
comment
Ваш вопрос выходит за рамки того, что я сделал с Spirit, но насколько я понимаю, если вы пишете новый код, вам следует использовать Qi вместо Spirit.   -  person Tim Sylvester    schedule 25.09.2009
comment
У меня возникло ощущение, что дух буста претерпевает изменения. Однако мне не удалось найти никакой документации по новому интерфейсу. Я подумал, что он еще не готов.   -  person Dan    schedule 25.09.2009
comment
Я нашел документацию по новому API на странице svn .boost.org / svn / boost / trunk / libs / spirit / doc / html / index.html.   -  person Dan    schedule 25.09.2009
comment
Рассмотрите возможность подписки на список рассылки Boost. Boost.Spirit, вероятно, не то, с чем знакомо большинство пользователей stackoverflow.   -  person sellibitze    schedule 25.09.2009


Ответы (2)


Это намного проще с новым парсером qi, доступным в Spirit 2. Следующий фрагмент кода предоставляет полный пример, который в основном работает. В окончательный результат вставлен неожиданный символ.

#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;
}
person Dan    schedule 06.02.2010

Вам нужен lazy_p, посмотрите пример здесь: http://www.boost.org/doc/libs/1_35_0/libs/spirit/doc/the_lazy_parser.html

person Nova    schedule 04.02.2010