ホームページ  >  記事  >  バックエンド開発  >  PHP-Parserを使用してAST抽象構文ツリーを生成する

PHP-Parserを使用してAST抽象構文ツリーを生成する

WBOY
WBOYオリジナル
2016-06-23 13:41:106250ブラウズ

0. はじめに

最近、プロジェクトのプロセスが徐々に明らかになってきましたが、多くの主要なテクノロジーは習得されておらず、段階的に探求することしかできません。

データフロー分析に基づいた静的コード分析のため、字句解析や構文解析などのフロントエンド作業が必須となります。 Yacc と Lex は考慮されなくなりました。1 日情報を確認した結果、1 つは Java の ANTLR で、もう 1 つは PHP AST 生成に特化した PHP-Parser がより適していることがわかりました。

ANTLR は、Yacc や Lex と比較して、コンパイル原理の分野でよく知られたツールです。しかし、PHP の構文ファイルは 1 つしかなく、生成と調整に長い間苦労した結果、「$a=1」に対して生成されたトークンは [$,a, =,1] と、課題が認識できませんでした。

それに比べて、PHP-Parser は PHP の字句解析と文法解析に重点を置いています。

1. はじめに

PHP-Parser プロジェクトのホームページは https://github.com/nikic/PHP-Parser です。複数のバージョンの PHP を完全に解析し、抽象構文ツリーを生成できます。

字句解析のために、PHP には、構文解析の入力として TOKEN を取得するために使用できる組み込み関数 token_get_all() が含まれています。このオープン ソース プロジェクトは、token_get_all() によって生成されたトークン ストリームも使用します。

2. インストール

ここでは、PHP のパッケージ管理ツールである Composer を使用して、プロジェクト ディレクトリで次のコマンドを実行するだけでインストールできます。 parser

Composer をダウンロードしていない場合は、まず次のコマンドを実行する必要があります:

Curl -s http://getcomposer.org/installer php

3. Composer を使用して php を追加した後、AST

を生成します。 -parser、便利に使えます。

最初に、PHP パーサーで定義されているいくつかのノード タイプを紹介します。

(1) PhpParserNodeStmt はステートメント ノードであり、代入ステートメント "$a = $b";

( 2 など) の戻り情報 (return) を持たない構造です。 ) PhpParserNodeExpr は、$var や func() などの値言語構造を返すことができる式ノードです。

(3) PhpParserNodeScalar は定数ノードであり、任意の定数値を表すために使用できます。 「文字列」、0、定数式など。

(4) パラメータノード(PhpParserNodeArg)など、含まれていないノードがあります。

一部のノード クラス名は、PHP キーワードとの競合を避けるためにアンダースコアを使用します。

PHP パーサーの HelloWorld プログラムは次のとおりです。このコード スニペットは AST を生成します。

出力結果は次のとおりです:

<span style="font-size:12px;">Array(    [0] => PhpParser\Node\Stmt\Echo_ Object    (            [subNodes:protected] => Array                (                    [exprs] => Array                        (                            [0] => PhpParser\Node\Scalar\String Object                                (                                    [subNodes:protected] => Array                                        (                                            [value] => 1+2                                        )                                    [attributes:protected] => Array                                        (                                            [startLine] => 1                                            [endLine] => 1                                        )                                )                            [1] => PhpParser\Node\Scalar\String Object                                (                                    [subNodes:protected] => Array                                        (                                            [value] => chongrui                                        )                                    [attributes:protected] => Array                                        (                                            [startLine] => 1                                            [endLine] => 1                                        )                                )                        )                )            [attributes:protected] => Array                (                    [startLine] => 1                    [endLine] => 1                )        ))</span>

ご覧のとおり、この AST には Echo_ というノードが 1 つだけあります。このノードには子ノード expr があり、$stmts[0]->exprs を使用してアクセスできます。

ノード内の属性情報は、startLine、endLine、およびコメントを格納するために使用されます。 getAttributes()、getAttribute(‘startLine’)、setAttribute()、hasAttribute() メソッドを使用してアクセスできます。

開始行番号 startLine には、getLine()/setLine() メソッドを通じてアクセスできます (getAttribute(‘startLine’) を使用することもできます)。コメント情報はgetDocComment()で取得できます。

ノード上の値にアクセスする: たとえば、値「chongrui」にアクセスするには、$stmts[0]->exprs[1]->value; を使用します。

4. ノードのトラバーサル

抽象構文ツリーをトラバースするには、PhpParserNodeTraverser クラスを使用するだけで非常に便利です。同時に、カスタマイズされた Visitor オブジェクトもサポートされます。実際のアプリケーションでは、PHP のソースコードを解析する際に、AST の具体的な構造が不明な場合が多いため、この場合、各ノードの型情報を動的に決定する必要があります。

これらの判断は MyNodeVisitor に一律に書き込まれます。このクラスは親クラス NodeVisitorAbstract を継承します。

(1) beforeTraverse() メソッドはトラバーサルの前に使用され、通常は前の値を比較するために使用されます。トラバーサル リセットを実行します。

(2) afterTraverse() メソッドは (1) と同じですが、唯一の違いは、トラバース後にトリガーされることです。

(3) 各ノードがアクセスされると、enterNode() メソッドと LeaveNode() メソッドがトリガーされます。

enterNode は、ノードの子ノードにアクセスする前など、ノードに入るときにトリガーされます。このメソッドは、このノードの子ノードをスキップするために使用される NodeTraverser::DONT_TRAVERSER_CHILDREN を返すことができます。

leaveNode は、ノードのトラバーサルが完了した後にトリガーされます。

NodeTraverser::REMOVE_NODE を返すことができ、その場合、現在のノードが削除されます。ノードのコレクションが返された場合、これらのノードは親ノードの配列 (array(A,B,C) など) にマージされ、B ノードは array(X,Y,Z) に置き換えられ、配列になります。 (A,X ,Y,Z,C) .

次のコード スニペットは $code を解析し、AST を生成し、トラバーサル中に、トラバースされたノードの String 型が見つかると、それを出力します。

結果は 1,2 として出力されます。

5. その他の AST 表現

AST はテキストとして保持される場合があり、PHP-Parser はこの機能もサポートしています。

(1) 単純なシリアル化

シリアル化と逆シリアル化の操作には、serialize() と unserialize() を使用すると、AST を永続化できます。

(2) 読みやすい保存フォーム

これらは完璧な印刷と XML 永続ストレージです。ここでは詳しく説明しません。必要に応じてプロジェクトのドキュメントを参照してください:

https://github.com/nikic/PHP-Parser/blob/master /doc/3_Other_node_tree_representations .markdown

6. まとめ

少なくとも PHP の静的解析に関しては、PHP-Parser は機能の点で ANTLR よりもはるかに優れています。 PHP 自動監査システムを構築する方法、この PHP パーサーは間違いなく大きな役割を果たします:)~


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。