\+-6ren">
gpt4 book ai didi

c++ - 如何使用 Boost Regex 标记化 C++

转载 作者:行者123 更新时间:2023-11-30 02:46:44 25 4
gpt4 key购买 nike

我目前正在为一个使用 boost 正则表达式的类开发分词器。我对 boost 不是很熟悉,所以我可能会偏离目前所拥有的,但无论如何,这是我正在使用的:

regex re("[\\s*,()=;<>\+-]{1,2}");
sregex_token_iterator i(text.begin(), text.end(), re, -1);
sregex_token_iterator j;

sregex_token_iterator begin(text.begin(), text.end(), re), end;

unsigned count = 0;
while(i != j)
{
if(*i != ' ' && *i != '\n')
{
count++;
cout << "From i - " << count << " " << *i << endl;
}
i++;

if(*begin != ' ' && *begin != '\n')
{
count++;
cout << "Form j - " << count << " " << *begin << endl;
}

begin++;
}

cout << "There were " << count << " tokens found." << endl;

所以,基本上,我使用空格和符号作为分隔符,但我仍然输出两者(因为我仍然希望符号是标记)。就像我说的,我对 boost 不是很熟悉,所以我不确定我是否采用了正确的方法。

我的最终目标是拆分一个包含简单 C++ 代码块的文件并将其标记化,这是我正在使用的示例文件:

#define MAX 5


int main(int argc)
{
for(int i = 0; i < MAX; i ++)
{
cout << "i is equal to " << i << endl;
}

return 0;
}

我遇到了麻烦,因为它将下一行和空格计为标记,我真的需要将它们丢弃。另外,我在使用“++”标记时遇到了困难,我似乎无法找出正确的表达式来计算“++”。

如有任何帮助,我们将不胜感激!

谢谢!蒂姆

最佳答案

首先,

  • Boost 有 Boost Wave,它有(我认为有几个)现成的 C++ 源分词器
  • Boost 具有 Spirit Lex,它是一种词法分析器,可以根据正则表达式模式和某些状态支持进行标记化。它允许动态词法分析器表和静态生成的词法分析器表

如果您对使用 Lex 感兴趣,我为自己做了一个快速而简单的手指练习:it tokenizes itself Live On Coliru .

注意事项:

  • Lex 分词器与用于解析的 Boost Spirit Qi 配合得很好(尽管老实说,我更喜欢直接在源迭代器上执行 Spirit 语法)。
  • 它公开了一个迭代器接口(interface),尽管我的示例利用回调接口(interface)来显示标记:

    int main()
    {
    typedef boost::spirit::istream_iterator It;
    typedef lex::lexertl::token<It, boost::mpl::vector<int, double>, boost::mpl::true_ > token_type;
    tokens<lex::lexertl::actor_lexer<token_type> > lexer;

    std::ifstream ifs("main.cpp");
    ifs >> std::noskipws;
    It first(ifs), last;
    bool ok = lex::tokenize(first, last, lexer, process_token());

    std::cout << "\nTokenization " << (ok?"succeeded":"failed") << "; remaining input: '" << std::string(first,last) << "'\n";
    }

    在输出中标记为(修剪前面的输出):

    [int][main][(][)][{][typedef][boost][::][spirit][::][istream_iterator][It][;][typedef][lex][::][lexertl][::][token][<][It][,][boost][::][mpl][::][vector][<][int][,][double][>][,][boost][::][mpl][::][true_][>][token_type][;][tokens][<][lex][::][lexertl][::][actor_lexer][<][token_type][>][>][lexer][;][std][::][ifstream][ifs][(]["main.cpp"][)][;][ifs][>>][std][::][noskipws][;][It][first][(][ifs][)][,][last][;][bool][ok][=][lex][::][tokenize][(][first][,][last][,][lexer][,][process_token][(][)][)][;][std][::][cout][<<]["\nTokenization "][<<][(][ok][?]["succeeded"][:]["failed"][)][<<]["; remaining input: '"][<<][std][::][string][(][first][,][last][)][<<]["'\n"][;][}]
    Tokenization succeeded; remaining input: ''

  • 您实际上应该需要不同的词法分析器状态来解析预处理器指令(行尾变得有意义并且其他几个表达式/关键字有效)。在现实生活中,通常有一个单独的预处理器步骤在这里进行自己的词法分析。 (例如,在对包含文件规范进行词法分析时可以看到这种后果)

  • 词法分析器中标记的顺序对结果至关重要
  • 在此示例中,您始终会匹配 &标记为 binop_ .你可能想匹配 ampersand_ token 并在解析时决定无论是二元运算符(按位与)、一元运算符(地址)、引用类型限定符等。C++ 解析起来真的很有趣:|
  • 支持评论!
  • 不支持双字母/三字母:)
  • 不支持编译指示、行/文件指令等

总而言之,如果您想制作一个简单的语法高亮器或格式化程序,这应该非常有用。除此之外的任何内容都需要更多的解析/语义分析。

完整 list :

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

namespace lex = boost::spirit::lex;

template <typename Lexer>
struct tokens : lex::lexer<Lexer>
{
tokens()
{
pound_ = "#";
define_ = "define";
if_ = "if";
else_ = "else";
endif_ = "endif";
ifdef_ = "ifdef";
ifndef_ = "ifndef";
defined_ = "defined";
keyword_ = "for|break|continue|while|do|switch|case|default|if|else|return|goto|throw|catch"
"static|volatile|auto|void|int|char|signed|unsigned|long|double|float|"
"delete|new|virtual|override|final|"
"typename|template|using|namespace|extern|\"C\"|"
"friend|public|private|protected|"
"class|struct|enum|"
"register|thread_local|noexcept|constexpr";
scope_ = "::";
dot_ = '.';
arrow_ = "->";
star_ = '*';
popen_ = '(';
pclose_ = ')';
bopen_ = '{';
bclose_ = '}';
iopen_ = '[';
iclose_ = ']';
colon_ = ':';
semic_ = ';';
comma_ = ',';
tern_q_ = '?';
relop_ = "==|!=|<=|>=|<|>";
assign_ = '=';
incr_ = "\\+\\+";
decr_ = "--";
binop_ = "[-+/%&|^]|>>|<<";
unop_ = "[-+~!]";

real_ = "[-+]?[0-9]+(e[-+]?[0-9]+)?f?";
int_ = "[-+]?[0-9]+";
identifier_ = "[a-zA-Z_][a-zA-Z0-9_]*";

ws_ = "[ \\t\\r\\n]";
line_comment_ = "\\/\\/.*?[\\r\\n]";
block_comment_ = "\\/\\*.*?\\*\\/";

this->self.add_pattern
("SCHAR", "\\\\(x[0-9a-fA-F][0-9a-fA-F]|[\\\\\"'0tbrn])|[^\"\\\\'\\r\\n]")
;
string_lit = "\\\"('|{SCHAR})*?\\\"";
char_lit = "'(\\\"|{SCHAR})'";

this->self +=
pound_ | define_ | if_ | else_ | endif_ | ifdef_ | ifndef_ | defined_
| keyword_ | scope_ | dot_ | arrow_ | star_ | popen_ | pclose_ | bopen_ | bclose_ | iopen_ | iclose_ | colon_ | semic_ | comma_ | tern_q_
| relop_ | assign_ | incr_ | decr_ | binop_ | unop_
| int_ | real_ | identifier_ | string_lit | char_lit
// ignore whitespace and comments
| ws_ [ lex::_pass = lex::pass_flags::pass_ignore ]
| line_comment_ [ lex::_pass = lex::pass_flags::pass_ignore ]
| block_comment_[ lex::_pass = lex::pass_flags::pass_ignore ]
;
}

private:
lex::token_def<> pound_, define_, if_, else_, endif_, ifdef_, ifndef_, defined_;
lex::token_def<> keyword_, scope_, dot_, arrow_, star_, popen_, pclose_, bopen_, bclose_, iopen_, iclose_, colon_, semic_, comma_, tern_q_;
lex::token_def<> relop_, assign_, incr_, decr_, binop_, unop_;
lex::token_def<int> int_;
lex::token_def<double> real_;
lex::token_def<> identifier_, string_lit, char_lit;
lex::token_def<lex::omit> ws_, line_comment_, block_comment_;
};
struct token_value : boost::static_visitor<std::string>
{
template <typename... T> // the token value can be a variant over any of the exposed attribute types
std::string operator()(boost::variant<T...> const& v) const {
return boost::apply_visitor(*this, v);
}

template <typename T> // the default value is a pair of iterators into the source sequence
std::string operator()(boost::iterator_range<T> const& v) const {
return { v.begin(), v.end() };
}

template <typename T>
std::string operator()(T const& v) const {
// not taken unless used in Spirit Qi rules, I guess
return std::string("attr<") + typeid(v).name() + ">(" + boost::lexical_cast<std::string>(v) + ")";
}
};

struct process_token
{
template <typename T>
bool operator()(T const& token) const {
std::cout << '[' /*<< token.id() << ":" */<< print(token.value()) << "]";
return true;
}

token_value print;
};

#if 0
std::string read(std::string fname)
{
std::ifstream ifs(fname);
std::ostringstream oss;
oss << ifs.rdbuf();
return oss.str();
}
#endif

int main()
{
typedef boost::spirit::istream_iterator It;
typedef lex::lexertl::token<It, boost::mpl::vector<int, double>, boost::mpl::true_ > token_type;
tokens<lex::lexertl::actor_lexer<token_type> > lexer;

std::ifstream ifs("main.cpp");
ifs >> std::noskipws;
It first(ifs), last;
bool ok = lex::tokenize(first, last, lexer, process_token());

std::cout << "\nTokenization " << (ok?"succeeded":"failed") << "; remaining input: '" << std::string(first,last) << "'\n";
}

关于c++ - 如何使用 Boost Regex 标记化 C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23319851/

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