📌 置頂: 請把任何比你弱勢的用路人當作你的至親對待。跟前車保持安全車距 (2秒以上)。

Python 底層運作 02 – PyTokenizer_Get 分析

In

Tags:



by

當 Python 在讀入程式碼的時候, 第一步就是對程式碼 lexing,將程式碼拆解成 token,標記出每個元素的分類為何。

以下面的程式碼為例:

我們透過 tokenize module 來分析,會變成:

我們可以看到 foo 被標記為 NAME,= 標記為 OP (operator),12345 則被標記為 NUMBER。

在 CPython 中,負責將程式碼標記成 token 的程式碼是 PyTokenizer_Get ,位於 Parser/tokenizer.c。PyTokenizer_Get 本身是 tok_get 的一個 wrapper,用來處理 decoding error 的 handling;其回傳值是該 token 的類別,這些類別的值在 Include/token.h 以 macro 的方式被定義出來;p_start 以及 p_end 則是該 token 的起始以及結束位置:

主要的處理集中在 tok_get 當中,這個 function 的目的是要獲得下一個 token,並且會將空白 strip 掉。

整段 tok_get 的 function code 有點長,大致上可以拆成兩段來看:

  • 獲得 next token 的 first character
  • 透過 first character 分類
    • Identifier
    • Newline
    • Period or number starting with period
    • Number
    • String
    • Line continuation
    • Two-character token
    • Parentheses nesting level

介紹 struct tok_state

稍候會用到 struct tok_state 因此必須先介紹這個 structure:

獲得 next token 的 first character

一些初始化動作。

重點是在 tok_nextc 這 function。

tok_nextc – 擷取下一個 token 的字元

  • decoding_fgets, bring fp to buf
  • tok->done = E_OK;
  • tok->inp = strchr(tok->buf, ‘\0’);
  • done = tok->inp == tok->buf || tok->inp[-1] == ‘\n’;

透過 first character 分類

拿到 first character 後,大致上的程式碼如下:

透過這些 if statement 來判斷目前的 token 屬於哪個 type,這裡也是解析一些特殊型態的數值的地方,例如說在 3.6 版新增的 “f-string”,可以看到會在第一段的地方處理:

或是新的底線數值 “10_000_000” 的解析,則是在 tok_decimal_tail 處理:

回到 parsetok

最後,PyTokenizer_Get 會將數值回傳到 parsetok 裏面:

  • type: 當前 token type
  • a: token_position_start
  • b: token_position_end

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.