パーサー— Python解析ツリーにアクセス—Pythonドキュメント

提供:Dev Guides
< PythonPython/docs/3.8/library/parser
移動先:案内検索

parser —Python解析ツリーにアクセスします


parser モジュールは、Pythonの内部パーサーおよびバイトコードコンパイラへのインターフェイスを提供します。 このインターフェースの主な目的は、PythonコードがPython式の解析ツリーを編集し、これから実行可能コードを作成できるようにすることです。 これは、任意のPythonコードフラグメントを文字列として解析および変更しようとするよりも優れています。これは、解析がアプリケーションを形成するコードと同じ方法で実行されるためです。 また、より高速です。

ノート

Python 2.5以降では、 ast モジュールを使用して、抽象構文木(AST)の生成およびコンパイル段階で割り込む方がはるかに便利です。


このモジュールについては、作成されたデータ構造を利用するために重要な注意事項がいくつかあります。 これはPythonコードの解析ツリーの編集に関するチュートリアルではありませんが、 parser モジュールの使用例をいくつか示します。

最も重要なことは、内部パーサーによって処理されるPython文法を十分に理解している必要があります。 言語構文の詳細については、 Python言語リファレンスを参照してください。 パーサー自体は、標準のPythonディストリビューションのファイルGrammar/Grammarで定義されている文法仕様から作成されます。 このモジュールによって作成されたSTオブジェクトに格納されている解析ツリーは、以下で説明する expr()または suite()関数によって作成されたときの内部パーサーからの実際の出力です。 sequence2st()によって作成されたSTオブジェクトは、これらの構造を忠実にシミュレートします。 「正しい」と見なされるシーケンスの値は、言語の正式な文法が改訂されるにつれて、Pythonのバージョンごとに異なることに注意してください。 ただし、あるPythonバージョンから別のバージョンにソーステキストとしてコードを転送すると、ターゲットバージョンで正しい解析ツリーを常に作成できます。唯一の制限は、古いバージョンのインタープリターに移行すると、最新の言語構造がサポートされないことです。 解析ツリーは通常、バージョン間で互換性がありませんが、ソースコードは通常、メジャーリリースシリーズ内で上位互換性があります。

st2list()または st2tuple()によって返されるシーケンスの各要素は、単純な形式です。 文法の非終端要素を表す配列は、常に1より大きい長さを持ちます。 最初の要素は、文法の生成を識別する整数です。 これらの整数には、CヘッダーファイルInclude/graminit.hおよびPythonモジュールシンボルでシンボル名が付けられています。 シーケンスの各追加要素は、入力文字列で認識されるプロダクションのコンポーネントを表します。これらは常に、親と同じ形式のシーケンスです。 注意すべきこの構造の重要な側面は、if_stmtのキーワード if など、親ノードタイプを識別するために使用されるキーワードが、特別なことなくノードツリーに含まれることです。処理。 たとえば、ifキーワードはタプル(1, 'if')で表されます。ここで、1は、変数名と関数名を含むすべてのNAMEトークンに関連付けられた数値です。ユーザーが定義します。 行番号情報が要求されたときに返される別の形式では、同じトークンが(1, 'if', 12)として表される場合があります。ここで、12は終端記号が見つかった行番号を表します。

ターミナル要素はほとんど同じ方法で表されますが、子要素がなく、識別されたソーステキストが追加されていません。 上記の if キーワードの例は代表的なものです。 さまざまなタイプの終端記号は、CヘッダーファイルInclude/token.hおよびPythonモジュールトークンで定義されています。

STオブジェクトは、このモジュールの機能をサポートする必要はありませんが、3つの目的で提供されます。アプリケーションが複雑な解析ツリーの処理コストを償却できるようにすること、Pythonと比較してメモリスペースを節約する解析ツリー表現を提供することです。リストまたはタプル表現、および解析ツリーを操作するCでの追加モジュールの作成を容易にするため。 単純な「ラッパー」クラスをPythonで作成して、STオブジェクトの使用を隠すことができます。

parser モジュールは、いくつかの異なる目的のために関数を定義します。 最も重要な目的は、STオブジェクトを作成し、STオブジェクトを解析ツリーやコンパイル済みコードオブジェクトなどの他の表現に変換することですが、STオブジェクトによって表される解析ツリーのタイプを照会する機能もあります。

も参照してください

モジュールシンボル
解析ツリーの内部ノードを表す便利な定数。
モジュールトークン
解析ツリーのリーフノードを表す便利な定数と、ノード値をテストするための関数。


STオブジェクトの作成

STオブジェクトは、ソースコードまたは解析ツリーから作成できます。 ソースからSTオブジェクトを作成する場合、'eval'フォームと'exec'フォームを作成するためにさまざまな関数が使用されます。

parser.expr(source)
expr()関数は、パラメーター sourcecompile(source, 'file.py', 'eval')への入力であるかのように解析します。 解析が成功すると、内部解析ツリー表現を保持するためにSTオブジェクトが作成されます。それ以外の場合は、適切な例外が発生します。
parser.suite(source)
suite()関数は、パラメーター sourcecompile(source, 'file.py', 'exec')への入力であるかのように解析します。 解析が成功すると、内部解析ツリー表現を保持するためにSTオブジェクトが作成されます。それ以外の場合は、適切な例外が発生します。
parser.sequence2st(sequence)

この関数は、シーケンスとして表される解析ツリーを受け入れ、可能であれば内部表現を構築します。 ツリーがPython文法に準拠し、すべてのノードがPythonのホストバージョンで有効なノードタイプであることを検証できる場合、STオブジェクトは内部表現から作成され、呼び出されたものに返されます。 内部表現の作成に問題がある場合、またはツリーを検証できない場合は、 ParserError 例外が発生します。 この方法で作成されたSTオブジェクトは、正しくコンパイルされると想定すべきではありません。 STオブジェクトが compilest()に渡されたときに、コンパイルによって発生した通常の例外が引き続き開始される場合があります。 これは、構文に関係のない問題( MemoryError 例外など)を示している可能性がありますが、Pythonパーサーをエスケープするがチェックされているdel f(0)の解析結果などの構造が原因である可能性もあります。バイトコードコンパイラによる。

ターミナルトークンを表すシーケンスは、(1, 'name')形式の2要素リストまたは(1, 'name', 56)形式の3要素リストのいずれかとして表すことができます。 3番目の要素が存在する場合、それは有効な行番号であると見なされます。 行番号は、入力ツリーの終端記号の任意のサブセットに指定できます。

parser.tuple2st(sequence)
これは sequence2st()と同じ関数です。 このエントリポイントは、下位互換性のために維持されています。


STオブジェクトの変換

STオブジェクトは、それらの作成に使用された入力に関係なく、リストツリーまたはタプルツリーとして表される解析ツリーに変換されるか、実行可能コードオブジェクトにコンパイルされます。 解析ツリーは、行番号情報の有無にかかわらず抽出できます。

parser.st2list(st, line_info=False, col_info=False)

この関数は、 st の呼び出し元からSTオブジェクトを受け取り、同等の解析ツリーを表すPythonリストを返します。 結果のリスト表現は、検査またはリスト形式の新しい解析ツリーの作成に使用できます。 この関数は、リスト表現を構築するためにメモリが使用可能である限り失敗しません。 解析ツリーが検査にのみ使用される場合は、代わりに st2tuple()を使用して、メモリ消費と断片化を減らす必要があります。 リスト表現が必要な場合、この関数は、タプル表現を取得してネストされたリストに変換するよりも大幅に高速です。

line_info がtrueの場合、行番号情報は、トークンを表すリストの3番目の要素としてすべての端末トークンに含まれます。 提供される行番号は、トークンが終了する行を指定することに注意してください。 フラグがfalseまたは省略されている場合、この情報は省略されます。

parser.st2tuple(st, line_info=False, col_info=False)

この関数は、 st の呼び出し元からSTオブジェクトを受け取り、同等の解析ツリーを表すPythonタプルを返します。 リストの代わりにタプルを返すことを除けば、この関数は st2list()と同じです。

line_info がtrueの場合、行番号情報は、トークンを表すリストの3番目の要素としてすべての端末トークンに含まれます。 フラグがfalseまたは省略されている場合、この情報は省略されます。

parser.compilest(st, filename='<syntax-tree>')

PythonバイトコンパイラをSTオブジェクトで呼び出して、組み込みの exec()または eval()関数の呼び出しの一部として使用できるコードオブジェクトを生成できます。 この関数は、 filename パラメーターで指定されたソースファイル名を使用して、 st からパーサーに内部解析ツリーを渡すコンパイラーへのインターフェイスを提供します。 filename に指定されたデフォルト値は、ソースがSTオブジェクトであったことを示します。

STオブジェクトをコンパイルすると、コンパイルに関連する例外が発生する場合があります。 例としては、del f(0)の解析ツリーによって引き起こされる SyntaxError があります。このステートメントは、Pythonの形式文法内では有効と見なされますが、有効な言語構造ではありません。 この条件で発生する SyntaxError は、実際にはPythonバイトコンパイラによって通常どおり生成されます。そのため、この時点で parser モジュールによって発生する可能性があります。 コンパイルの失敗のほとんどの原因は、解析ツリーを調べることでプログラムで診断できます。


STオブジェクトに関するクエリ

STが式として作成されたかスイートとして作成されたかをアプリケーションが判別できるようにする2つの関数が提供されています。 これらの関数はいずれも、STが expr()または suite()を介してソースコードから作成されたか、 sequence2st()[を介して解析ツリーから作成されたかを判断するために使用できません。 X172X]。

parser.isexpr(st)
st'eval'形式を表す場合、この関数はTrueを返します。それ以外の場合は、Falseを返します。 通常、既存の組み込み関数を使用してこの情報をコードオブジェクトに照会することはできないため、これは便利です。 compilest()によって作成されたコードオブジェクトもこのようにクエリすることはできず、組み込みの compile()関数によって作成されたものと同じであることに注意してください。
parser.issuite(st)
この関数は、STオブジェクトが一般に「スイート」として知られる'exec'フォームを表すかどうかを報告するという点で、 isexpr()を反映しています。 将来、追加の構文フラグメントがサポートされる可能性があるため、この関数がnot isexpr(st)と同等であると想定するのは安全ではありません。


例外とエラー処理

パーサーモジュールは単一の例外を定義しますが、Pythonランタイム環境の他の部分からの他の組み込み例外を渡すこともあります。 発生する可能性のある例外については、各関数を参照してください。

exception parser.ParserError
パーサーモジュール内で障害が発生すると例外が発生します。 これは通常、通常の解析中に発生する組み込みの SyntaxError ではなく、検証の失敗に対して生成されます。 例外引数は、失敗の理由を説明する文字列、または sequence2st()に渡された解析ツリーから失敗を引き起こしたシーケンスを含むタプルと説明文字列のいずれかです。 sequence2st()の呼び出しは、どちらのタイプの例外も処理できる必要がありますが、モジュール内の他の関数の呼び出しは、単純な文字列値のみを認識する必要があります。

関数 compilest()expr()、および suite()は、通常、解析およびコンパイルプロセスによって発生する例外を発生させる可能性があることに注意してください。 これらには、組み込みの例外 MemoryErrorOverflowErrorSyntaxError 、および SystemError が含まれます。 これらの場合、これらの例外は、通常それらに関連付けられているすべての意味を持ちます。 詳細については、各機能の説明を参照してください。


STオブジェクト

STオブジェクト間で、順序付きおよび同等性の比較がサポートされています。 STオブジェクトの酸洗い( pickle モジュールを使用)もサポートされています。

parser.STType
expr()suite()、および sequence2st()によって返されるオブジェクトのタイプ。

STオブジェクトには次のメソッドがあります。

ST.compile(filename='<syntax-tree>')
compilest(st, filename)と同じです。
ST.isexpr()
isexpr(st)と同じです。
ST.issuite()
issuite(st)と同じです。
ST.tolist(line_info=False, col_info=False)
st2list(st, line_info, col_info)と同じです。
ST.totuple(line_info=False, col_info=False)
st2tuple(st, line_info, col_info)と同じです。


例: compile()のエミュレーション

解析とバイトコード生成の間に多くの便利な操作が行われる可能性がありますが、最も簡単な操作は何もしないことです。 この目的のために、 parser モジュールを使用して中間データ構造を生成することは、コードと同等です。

>>> code = compile('a + 5', 'file.py', 'eval')
>>> a = 5
>>> eval(code)
10

parser モジュールを使用した同等の操作はやや長く、中間の内部解析ツリーをSTオブジェクトとして保持できます。

>>> import parser
>>> st = parser.expr('a + 5')
>>> code = st.compile('file.py')
>>> a = 5
>>> eval(code)
10

STオブジェクトとコードオブジェクトの両方を必要とするアプリケーションは、このコードをすぐに利用できる関数にパッケージ化できます。

import parser

def load_suite(source_string):
    st = parser.suite(source_string)
    return st, st.compile()

def load_expression(source_string):
    st = parser.expr(source_string)
    return st, st.compile()