3. コンパイルパイプライン
トークン化、解析、AST、シンボル テーブル、コンパイラ パス、コード オブジェクト、定数とローカル、バイトコード生成、およびバイトコードの最適化。
| 章 | タイトル |
|---|---|
| 18 | トークン化 |
| 19 | 解析 |
| 20 | AST |
| 21 | シンボルテーブル |
| 22 | コンパイラ パス |
| 23 | コードオブジェクト |
| 24 | 定数、名前、ローカル変数 |
| 25 | バイトコードの生成 |
| 26 | バイトコードの最適化 |
-
18. トークン化
#18. トークン化 トークン化は、CPython のコンパイル パイプラインの最初の構造段階です。 Python ソース テキストを受け取り、トークンのストリームを生成します。パーサーはそのトークン ストリームを消費し、そこから構文構造を構築します。 この段階では、CPython はプログラムが意味があるかどうかをまだ知りません。名前、数値、文字列、演算子、改行、インデント、ファイルの終わりマーカーなどの語彙単位のみを認識します。 トークナイザーは次のように変換します。 python def add(a, b): return a + b 次のような形のストリームになります。 text NAME "def" NAME "add" LPAR "(" NAME "a" COMMA "," NAME "b" RPAR ")" COLON ":" NEWLINE "\n" INDENT " " NAME "return" NAME "a" PLUS "+" NAME "b" NEWLINE "\n" DEDENT "" ENDMARKER "" 正確なトークン名とパーサー インターフェイスは CPython のバージョンによって異なりますが、中心的な考え方は安定しています。 Python 標準ライブラリは、次の方法で Python レベルのトークナイザーを公開します。 tokenize 一方、CPython のパーサーは内部で独自の C トークナイザーを使用します。一般の人々…
-
19. 解析
#19. 解析 解析は、トークン ストリームを構文構造に変換する段階です。 トークナイザーは語彙単位を認識します。パーサーは文法構造を認識します。一連のトークンが有効な Python プログラムであるかどうかを判断し、有効な場合は抽象構文ツリーを構築します。 このソースの場合: python def add(a, b): return a + b トークナイザーは次のようなトークンを生成します。 text NAME "def" NAME "add" LPAR "(" NAME "a" COMMA "," NAME "b" RPAR ")" COLON ":" NEWLINE "\n" INDENT " " NAME "return" NAME "a" PLUS "+" NAME "b" NEWLINE "\n" DEDENT "" ENDMARKER "" パーサーはこれらのトークン構造を次のように与えます。 text Module FunctionDef name="add" arguments arg "a" arg "b" body Return BinOp Name "a" Add Name…
-
20. AST
#20. AST 抽象構文ツリーは通常 AST と呼ばれ、解析後の Python ソース コードの構造化表現です。 トークナイザーは、トークンのフラット ストリームを生成します。パーサーは文法を認識します。 AST は、結果をステートメントと式のツリーとして記録します。 このソースの場合: python x = 1 + 2 AST は次のような形になります。```text Module Assign targets: Name id="x", ctx=Store value: BinOp left: Constant value=1 op: Add right: Constant value=2 ## 20.1 コンパイルパイプラインでの位置 AST は解析とコンパイラ分析の間に位置します。 ``` text source bytes ↓ tokenization ↓ parsing ↓ AST ↓ AST validation ↓ symbol table ↓ compiler ↓ code object ↓ bytecode execution ``` パーサーは AST を構築します。後のフェーズではそれを消費します。…
-
21. シンボルテーブル
#21. シンボルテーブル 解析によって AST が生成された後、CPython はスコープ分析を実行します。 この段階ではシンボル テーブルを構築します。 シンボル テーブルには、各スコープ内で名前がどのように動作するかが記録されます。これにより、名前がローカル、グローバル、フリー、セル、パラメータ、インポート、注釈付き、またはネストされたスコープから参照されるかどうかが決まります。 このソースの場合:```python x = 10 def outer(): y = 20 def inner(): return x + y return inner シンボル テーブル フェーズによって次のことが決まります。```text x global from inner y free variable in inner y cell variable in outer inner local variable in outer outer global variable in module ```バイトコード生成はそれに依存するため、この分析は不可欠です。ローカル変数のロードには、グローバル変数またはクロージャ変数のロードとは異なるバイトコードが使用されます。 ## 21.1 コンパイルパイプラインでの位置 シンボル テーブル フェーズは、AST 構築とバイトコード生成の間にあります。```text source ↓ tokenization ↓ parsing ↓ AST ↓…
-
22. コンパイラパス
#22. コンパイラパス コンパイラ パスは、AST およびシンボル テーブル情報を実行可能コード オブジェクトに変換します。 初期段階では構造的な質問に答えます。```text id="lfk0j9" tokenizer: What lexical units are in the source? parser: What syntax tree do these tokens form? symbol table: What scope does each name belong to? コンパイラーは実行に関する質問に答えます。 text id="ju2gsy" Which bytecode instructions should be emitted? Which constants belong in co_consts? Which names belong in co_names? Which local variables belong in co_varnames? Where should jumps go? How large can the evaluation stack grow?…
-
23. コードオブジェクト
#23. コードオブジェクト コード オブジェクトは、実行可能な Python コードを CPython がコンパイルして表現したものです。 バイトコードとメタデータが含まれています。インタプリタはそれを実行できますが、コード オブジェクト自体は、グローバル、デフォルト引数、クロージャ セル、バインドされたメソッドなどの実行時状態を保持しません。 このソースの場合: python def add(a, b): return a + b 関数オブジェクト add コードオブジェクトが含まれています:```python code = add. code print(code.co_name) print(code.co_varnames) print(code.co_consts) print(code.co_names) ## 23.1 コンパイルパイプラインでの位置 コード オブジェクトはコンパイルの出力です。 ``` text source text ↓ tokenization ↓ parsing ↓ AST ↓ symbol table ↓ compiler ↓ code object ↓ frame execution ``` コード オブジェクトは、コンパイラとインタプリタ間の受け渡しです。 コンパイラはコード オブジェクトを生成します。 評価ループはフレーム内のコード オブジェクトを実行します。 ## 23.2 コードオブジェクトと関数オブジェクト 関数オブジェクトはコード オブジェクトをラップします。 例:…
-
24. 定数、名前、ローカル変数
#24. 定数、名前、ローカル変数 コード オブジェクトは、Python ソース コードをテキストとして保存しません。コンパクトなテーブルと、それらのテーブルをインデックスで参照するバイトコード命令が格納されます。 最も重要なテーブルは次の 3 つです。```text id="mx2a9w" co_consts co_names co_varnames この関数の場合 : ``` python id = "wg80pj" def f ( a ): b = len ( a ) return b + 1 ``` CPython ストア : ``` text id = "jxh1ou" constants : None 1 names : len local variables : a b ``` バイトコード命令はインデックスによってそれらのエントリを参照します。 ## 24.1 コンパイルパイプラインでの位置 定数、名前、およびローカルはコンパイル中にアセンブルされます。 ``` text id = "la84x8" AST ↓ symbol…
-
25. バイトコードの生成
#25. バイトコードの生成 バイトコード生成は、CPython が構造化構文を実行可能な仮想マシン命令に変換する段階です。 パーサーは AST を構築します。 シンボル テーブルはスコープの動作を決定します。 次に、コンパイラは、Python セマンティクスを実装するバイトコード命令を発行します。 このソースの場合: python id="bjlwm8" def add(a, b): return a + b CPython は次のようなバイトコードを生成します。 text id="plhxq4" LOAD_FAST a LOAD_FAST b BINARY_OP + RETURN_VALUE 正確な命令名と形式は Python のバージョンによって異なりますが、モデルは安定しています。```text id="ecx81v" bytecode is a low-level instruction stream executed by the CPython virtual machine バイトコードの生成は、 AST の構築とスコープ分析の後に行われます。 ``` text id = "5v2o9v" source ↓ tokenization ↓ parsing ↓ AST ↓ symbol table ↓ bytecode generation ↓…
-
26. バイトコードの最適化
#26. バイトコードの最適化 バイトコードの最適化は、コード オブジェクトの実行準備が整う前の最後のクリーンアップと改良の段階です。 コンパイラの初期段階で、プログラムの意味が決定され、命令が発行されます。最適化では、Python のセマンティクスを維持しながら、これらの命令をより小さく、よりシンプルに、またはより高速にしようとします。 例えば: python id="u88pli" x = 1 + 2 書かれているかのようにコンパイルできます:```python id="k8v2ef" x = 3 しかし、これは: ``` python id = "lbwhpl" x = a + b ``` 折りたためないので、 ` a ` そして ` b ` は実行時の値です。それらの型は、任意の動作を定義する可能性があります。 `+` 。 ## 26.1 コンパイルパイプラインでの位置 最適化は、最適化の種類に応じて、バイトコード生成後または生成中に行われます。 ``` text id = "olp5um" source ↓ tokenization ↓ parsing ↓ AST ↓ symbol table ↓ instruction generation ↓ optimization ↓ assembly ↓ code…