parserモジュールはPythonの内部パーサとバイトコード・コンパイラへのインターフェイスを提供します。このインターフェイスの第一の目的は、PythonコードからPythonの式の解析木を編集したり、これから実行可能なコードを作成したりできるようにすることです。これは任意のPythonコードの断片を文字列として構文解析や変更を行うより良い方法です。なぜなら、構文解析がアプリケーションを作成するコードと同じ方法で実行されるからです。その上、高速です。
このモジュールについて注意すべきことが少しあります。それは作成したデータ構造を利用するために重要なことです。この文書はPythonコードの解析木を編集するためのチュートリアルではありませんが、parserモジュールを使った例をいくつか示しています。
もっとも重要なことは、内部パーサが処理するPythonの文法についてよく理解しておく必要があるということです。言語の文法に関する完全な情報については、Python言語リファレンスを参照してください。標準のPythonディストリビューションに含まれるファイルGrammar/Grammarの中で定義されている文法仕様から、パーサ自身は作成されています。このモジュールが作成するASTオブジェクトの中に格納される解析木は、下で説明するexpr()またはsuite()関数によって作られるときに内部パーサから実際に出力されるものです。sequence2ast()が作るASTオブジェクトは忠実にこれらの構造をシミュレートしています。言語の形式文法が改訂されるために、``正しい''と考えられるシーケンスの値がPythonのあるバージョンから別のバージョンで変化することがあるということに注意してください。しかし、Pythonのあるバージョンから別のバージョンへテキストのソースのままコードを移せば、目的のバージョンで正しい解析木を常に作成できます。ただし、インタープリタの古いバージョンへ移行する際に、最近の言語コンストラクトをサポートしていないことがあるという制限だけがあります。ソースコードが常に前方互換性があるのに対して、一般的に解析木はあるバージョンから別のバージョンへの互換性がありません。
ast2list()またはast2tuple()から返されるシーケンスのそれぞれの要素は単純な形式です。文法の非終端要素を表すシーケンスは常に一より大きい長さを持ちます。最初の要素は文法の生成規則を識別する整数です。これらの整数はCヘッダファイルInclude/graminit.hとPythonモジュールsymbolの中の特定のシンボル名です。シーケンスに付け加えられている各要素は、入力文字列の中で認識されたままの形で生成規則の構成要素を表しています: これらは常に親と同じ形式を持つシーケンスです。この構造の注意すべき重要な側面は、if_stmtの中のキーワードifのような親ノードの型を識別するために使われるキーワードがいかなる特別な扱いもなくノードツリーに含まれているということです。例えば、ifキーワードはタプル(1, 'if')
と表されます。ここで、1
は、ユーザが定義した変数名と関数名を含むすべてのNAMEトークンに対応する数値です。行番号情報が必要なときに返される別の形式では、同じトークンが(1, 'if', 12)
のように表されます。ここでは、12
が終端記号の見つかった行番号を表しています。
終端要素は同じ方法で表現されますが、子の要素や識別されたソーステキストの追加は全くありません。上記のifキーワードの例が代表的なものです。終端記号のいろいろな型は、CヘッダファイルInclude/token.hとPythonモジュールtokenで定義されています。
ASTオブジェクトはこのモジュールの機能をサポートするために必要ありませんが、三つの目的から提供されています: アプリケーションが複雑な解析木を処理するコストを償却するため、Pythonのリストやタプル表現に比べてメモリ空間を保全する解析木表現を提供するため、解析木を操作する追加モジュールをCで作ることを簡単にするため。ASTオブジェクトを使っていることを隠すために、簡単な``ラッパー''クラスをPythonで作ることができます。
parserモジュールは二、三の別々の目的のために関数を定義しています。もっとも重要な目的はASTオブジェクトを作ることと、ASTオブジェクトを解析木とコンパイルされたコードオブジェクトのような他の表現に変換することです。しかし、ASTオブジェクトで表現された解析木の型を調べるために役に立つ関数もあります。