0
点赞
收藏
分享

微信扫一扫

MySQL 源码|20 - 词法解析:词法解析器调用方法


MySQL 源码|词法解析:词法解析器调用方法

源码位置:(版本 = MySQL 8.0.37)

  • router/src/routing/src/sql_lexer.cc
next_token()

lex_one_token() 函数在 SqlLexer::iterator::Token SqlLexer::iterator::next_token() 函数中被调用:

SqlLexer::iterator::Token SqlLexer::iterator::next_token() {
  const auto token_id = lex_one_token(&st, session_);

  return {get_token_text(token_id), token_id};
}

其中的 token_id 即 lex_one_tokenint 类型返回值。接着查看 get_token_text(token_id) 的逻辑:

std::string_view SqlLexer::iterator::get_token_text(TokenId token_id) const {
  auto &lip = session_->m_parser_state->m_lip;

  auto raw_token = std::string_view{
      lip.get_tok_start(),
      static_cast<size_t>(lip.get_ptr() - lip.get_tok_start())};

  if (token_id == END_OF_INPUT) {
    return {"\0", 1};
  } else if (token_id == 0) {  // YYEOF
    return {};
  } else if (token_id < 256) {  // 0-255 are plain ASCII characters
    return raw_token;
  } else if (token_id == IDENT) {
    // in 'SET @@SESSION.timestamp' 'timestamp' is a IDENT
    // in 'SET SESSION timestamp' 'timestamp' is a keyword

    return to_string_view(st.lex_str);
  } else if (is_keyword_or_func(raw_token.data(), raw_token.size())) {
    return {st.keyword.str, st.keyword.length};
  } else {
    return to_string_view(st.lex_str);
  }
}

get_token_text() 函数返回 std::string_view 类型,该类型包含两个成员,一个是指向字符串数据的指针和一个表示长度的整数。根据不同的 token_idget_token_text(TokenId token_id) 的返回结果如下:

  • token_id 为 411(END_OF_INPUT)时,则返回长度为 0 字符串;
  • token_id 为 0 时,返回空结果;
  • token_id 小于 256,即为 ASCII 字符时,返回当前 token 的字符串
  • token_id 为 482(IDENT)时,返回使用 Lexer_yystype 类型 SqlLexer -> stlex_str 构造的字符串
  • 否则,如果 token 的字符串是关键字或函数,则返回该关键字和函数的字符串
  • 否则,返回使用 Lexer_yystype 类型 SqlLexer -> stlex_str 构造的字符串
next_token() 函数的调用位置

下面来看 next_token() 被调用的位置。

  • SqlLexer::iterator 类的构造函数,在初始化时将成员变量 token_ 初始化为 next_token 函数的 string_view 类型返回值。

SqlLexer::iterator::iterator(THD *session) : session_(session) {
  if (session_) {
    // init the first token
    token_ = next_token();
  }
}

  • SqlLexer::iterator 类重载实现后置递增运算符的函数,将 next_token 函数的 string_view 类型返回值返回。

SqlLexer::iterator SqlLexer::iterator::operator++(int) {
  // the last token is END_OF_INPUT, +1 is past the "end()"
  if (is_final_token(token_)) {
    return {nullptr};
  }

  return {session_, next_token()};
}

  • SqlLexer::iterator 类重载实现前置递增运算符的函数,将成员变量 token_ 置为 next_token 函数的 string_view 类型返回值。

SqlLexer::iterator &SqlLexer::iterator::operator++() {
  // the last token is END_OF_INPUT, +1 is past the "end()"
  if (is_final_token(token_)) {
    token_ = {};
  } else {
    token_ = next_token();
  }

  return *this;
}

SqlLexer

可以看到,next_token() 函数被用来实现 SqlLexer::iterator 类的初始化和递增运算,下面我们来看 SqlLexer 的实现逻辑:

class SqlLexer {
 public:
  using TokenId = int;

  SqlLexer(THD *session);

  class iterator {
   public:
    struct Token {
      std::string_view text;
      TokenId id;
    };

    using lexer_state = Lexer_yystype;
    using value_type = Token;
    using pointer = value_type *;
    using const_pointer = const value_type *;

    iterator(THD *session);

    iterator(THD *session, Token token)
        : session_(session), token_{std::move(token)} {}

    value_type operator*() const { return token_; }
    pointer operator->() { return &token_; }
    const_pointer operator->() const { return &token_; }

    iterator operator++(int);
    iterator &operator++();

    friend bool operator==(const iterator &a, const iterator &b);
    friend bool operator!=(const iterator &a, const iterator &b);

   private:
    Token next_token();
    std::string_view get_token_text(TokenId token_id) const;

    THD *session_;
    lexer_state st;

    Token token_;
  };

  iterator begin() { return iterator(session_); }
  iterator end() { return iterator(nullptr); }

 private:
  THD *session_;
};

到这里,我们基本已经了解了词法解析器的使用方法,下面开始梳理词法解析器的具体逻辑。


举报

相关推荐

0 条评论