62
45

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Pythonはどうやって文のブロックをインデントで実現しているのか?

Last updated at Posted at 2021-02-02

##動機

CPythonのソースを読もうと思った動機のひとつに、文のブロックをどうやってインデントで実現しているのか、インタプリタのメカニズムはどうなっているかを解明したいというものがあった。やっと解明できたので、メモを書いておく。

リポジトリはここ: https://github.com/python/cpython

##字句解析(トーカナイザ)のひみつ

秘密は字句解析器にあった。Pythonのソースコードからトークンの切り出しをおこなう処理の、コアの部分は tok_get() という関数が行っている。ソースコードではこの部分。

tok_get() : githubへのリンク

字句解析は状態を持つステートフルな処理になっていて、状態を保持する重要な構造体 tok_state がある。この中にどのようなデータが保持されているか理解すると、字句解析の動きが理解できるようになる。

struct tok_state : githubへのリンク

インデント処理のための最も重要なデータは、この構造体tok_state のメンバである indstack というスタックである。このスタックには、処理するソースコードの最初の部分から、現在処理している部分までのインデントされたカラムの位置が積まれている。インデントが深くなるたびに、カラムの位置がpushされ、インデントが(正しく)浅くなると値がpopされる。

ちなみに、このスタックの上限はもちろん決まっていて、デフォルトは100である。よって101段以上のインデントをつけたソースコードは、エラーになる(はず)。またこの処理は巧妙に作られていて、ある部分のインデントはスペース4個、ある部分のインデントは空白2個といった、かなり変態的なソースコードでも処理でも正しく処理できる。(インデントを浅くなるとき、それまでのインデントと整合性がとれている必要がある)。次のようなソースでもエラーにはならない。

$ cat test_indent.py
def foo():

  def bar(): # indent 2 spaces
        pass # indent 8 spaces

def baz():
            pass # indent 12 spaces

$ ./python.exe test_indent.py
$

字句解析器は、インデントが変化(深くなったり、浅くなったり)したときに、ソースコード上には存在しない仮想的トークン、INDENTDEDENT というトークンを構文解析器に渡す。これにより、構文解析器の立場からからみたPythonの文法は、伝統的な言語のようなブロックを表すためのシンボル( { } begin end などなど)を持つ言語となんら変わらないものとなる。ソースコードは以下の部分。

仮想的トークン INDENT, DEDENT を返す処理 : githubへのリンク

参考までに、PEG (Parsing Expression Grammar) による block の具象構文の定義はこのようになっている。

block[asdl_seq*] (memo):
    | NEWLINE INDENT a=statements DEDENT { a }
    | simple_stmt
    | invalid_block

この部分

なんとなく、NEWLINE(改行)の次にINDENTがきて、文が並び DEDENT が来ることがわかる。PEG は python 3.9 で採用された文法記述で詳細は PEP 617 を参照のこと。

62
45
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
62
45

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?