gpt4 book ai didi

c++ - 使用 Boost.Spirit.Lex 和流迭代器

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:34:46 27 4
gpt4 key购买 nike

我想使用 Boost.Spirit.Lex 来对二进制文件进行 lex;为此,我编写了以下程序(这里是摘录):

#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>
#include <boost/bind.hpp>
#include <boost/ref.hpp>
#include <fstream>
#include <iterator>
#include <string>

namespace spirit = boost::spirit;
namespace lex = spirit::lex;

#define X 1
#define Y 2
#define Z 3

template<typename L>
class word_count_tokens : public lex::lexer<L>
{
public:
word_count_tokens () {
this->self.add
("[^ \t\n]+", X)
("\n", Y)
(".", Z);
}
};

class counter
{
public:
typedef bool result_type;

template<typename T>
bool operator () (const T &t, size_t &c, size_t &w, size_t &l) const {
switch (t.id ()) {
case X:
++w; c += t.value ().size ();
break;
case Y:
++l; ++c;
break;
case Z:
++c;
break;
}

return true;
}
};

int main (int argc, char **argv)
{
std::ifstream ifs (argv[1], std::ios::in | std::ios::binary);
auto first = spirit::make_default_multi_pass (std::istream_iterator<char> (ifs));
auto last = spirit::make_default_multi_pass (std::istream_iterator<char> ());
size_t w, c, l;
word_count_tokens<lex::lexertl::lexer<>> word_count_functor;

w = c = l = 0;

bool r = lex::tokenize (first, last, word_count_functor, boost::bind (counter (), _1, boost::ref (c), boost::ref (w), boost::ref (l)));

ifs.close ();

if (r) {
std::cout << l << ", " << w << ", " << c << std::endl;
}

return 0;
}

构建返回以下错误:

lexer.hpp:390:46: error: non-const lvalue reference to type 'const char *' cannot bind to a value of unrelated type

现在,错误是由于具体 词法分析器的定义,lex::lexer<> ;事实上它的第一个参数默认为 const char * .如果我使用 spirit::istream_iterator 我也会得到同样的错误或 spirit::make_default_multi_pass (.....) .
但是如果我指定了 lex::lexer<> 的正确模板参数我收到很多错误!

解决方案?

更新

我已经把所有的源文件;这是 word_counter 网站的示例。

最佳答案

好的,既然问题改了,这里有一个新的答案,用完整的代码示例解决了一些问题。

  1. 首先,您需要使用自定义 token 类型。 IE。

    word_count_tokens<lex::lexertl::lexer<lex::lexertl::token<boost::spirit::istream_iterator>>> word_count_functor;
    // instead of:
    // word_count_tokens<lex::lexertl::lexer<>> word_count_functor;

    显然,习惯上 typedef lex::lexertl::token<boost::spirit::istream_iterator>

  2. 您需要使用 min_token_id而不是 token ID 1、2、3。另外,将其设为枚举以便于维护:

    enum token_ids {
    X = lex::min_token_id + 1,
    Y,
    Z,
    };
  3. 您不能再只使用 .size()在默认 token 上 value()因为迭代器范围不再是 RandomAccessRange。相反,请使用 boost::distance()专用于 iterator_range :

            ++w; c += boost::distance(t.value()); // t.value ().size ();

结合这些修复: Live On Coliru

#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <boost/bind.hpp>
#include <fstream>

namespace spirit = boost::spirit;
namespace lex = spirit::lex;

enum token_ids {
X = lex::min_token_id + 1,
Y,
Z,
};

template<typename L>
class word_count_tokens : public lex::lexer<L>
{
public:
word_count_tokens () {
this->self.add
("[^ \t\n]+", X)
("\n" , Y)
("." , Z);
}
};

struct counter
{
typedef bool result_type;

template<typename T>
bool operator () (const T &t, size_t &c, size_t &w, size_t &l) const {
switch (t.id ()) {
case X:
++w; c += boost::distance(t.value()); // t.value ().size ();
break;
case Y:
++l; ++c;
break;
case Z:
++c;
break;
}

return true;
}
};

int main (int argc, char **argv)
{
std::ifstream ifs (argv[1], std::ios::in | std::ios::binary);
ifs >> std::noskipws;
boost::spirit::istream_iterator first(ifs), last;
word_count_tokens<lex::lexertl::lexer<lex::lexertl::token<boost::spirit::istream_iterator>>> word_count_functor;

size_t w = 0, c = 0, l = 0;
bool r = lex::tokenize (first, last, word_count_functor,
boost::bind (counter (), _1, boost::ref (c), boost::ref (w), boost::ref (l)));

ifs.close ();

if (r) {
std::cout << l << ", " << w << ", " << c << std::endl;
}
}

当自己运行时,打印

65, 183, 1665

关于c++ - 使用 Boost.Spirit.Lex 和流迭代器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23709981/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com