概要
C言語をコンパイルするとき、人が記述したCソースは抽象構文木と呼ばれる中間的な表現に変換され、バイナリ形式になります。
今回は、そのC言語ソースを抽象構文木として解析できるPythonプログラムを使って遊んでみました。
準備
LLVMのインストール
この中の最新のバージョンを選択しましょう。
Windows版はAssetsの中に一見ないかもしれないですが、「LLVM 15.0.5」(執筆時点)でをクリックすれば、windows版のインストーラもダウンロードできます。
インストールするときに環境変数の設定をインストーラの方でやってくれるオプションを選択すれば楽です。
Python用のパッケージをインストール
パッケージをインストールしたい環境を開き、以下コマンドを実行します。
pip install libclang
libclangの詳しい情報はこちら
Pythonソース
import sys
from clang.cindex import Index
def visit_node(node, indent = 0) :
print('{0}{1} : {2}'.format(' ' * indent, node.kind, node.spelling))
for c in node.get_children():
visit_node(c, indent=indent+1)
index = Index.create()
tu = index.parse(sys.argv[1])
visit_node(tu.cursor)
libclangをPythonコードで利用するときは、clang
パッケージをインポートする必要があります。
クラス・メソッドの詳しい情報はこちら
上記ソースは、再帰処理で抽象構文木の各ノードをたどりそのノードを種類を表示します。
インデントの深さ関係が、すぐ上に表示されているノードとの親子関係を示しています。
実行結果
簡単なCソースを対象にしてみます。
int main(){
int a = 0;
if(a == 0)
a = 5;
}
結果
CursorKind.TRANSLATION_UNIT : .\test_c-code\test_if.c
CursorKind.FUNCTION_DECL : main
CursorKind.COMPOUND_STMT :
CursorKind.DECL_STMT :
CursorKind.VAR_DECL : a
CursorKind.INTEGER_LITERAL :
CursorKind.IF_STMT :
CursorKind.BINARY_OPERATOR :
CursorKind.UNEXPOSED_EXPR : a
CursorKind.DECL_REF_EXPR : a
CursorKind.INTEGER_LITERAL :
CursorKind.BINARY_OPERATOR :
CursorKind.DECL_REF_EXPR : a
CursorKind.INTEGER_LITERAL :
後述しますが、libclangだけではリテラルを表示できないようです。
(自分が調査しただいぶ前での認識)
ただし、ノードの種類は区別できるようになっていますし、使っている変数のシンブルについても確認することができます。
リテラルなどを取得するためには?
libclangだけで取得できない情報は以下のものがある認識です。
- リテラル
- 演算子各種(一項、二項、三項)
- 変数型
これらの情報を取得できないとなると、構文解析を超えた利用(e.g. C言語シミュレーション)は厳しいです。
一応下記のパッケージをインストールすればlibclangに加えてインストールすれば、それら情報も取得できるようになります。
https://pypi.org/project/sealang/
しかし、全然更新がなく、サポートしているpythonのバージョンもPython3.5までであることを考慮するとあまり利用はおすすめできないですね。
(以前コアダンプが出て記憶もありますし)
そのためご利用は自己責任でお願いします。