Hatena::ブログ(Diary)

C++でゲームプログラミング

2014-04-16

[]Python で iTunes Music Library.xml を読み込む

「iTunes Music Library.xml をパースしたい」みたいな話が出ていたので簡単にやってみた。


[ソース]

# -*- coding: utf-8 -*-
import plistlib


file = "iTunes Music Library.xml"

xml = plistlib.readPlist(file)

# プレイリストの一覧を出力
print "=== プレイリスト ==="
for playlist in xml["Playlists"]:
	print playlist["Name"].encode("utf-8")

# トラック(曲)の一覧を出力
print "=== トラック ==="
for track in xml["Tracks"]:
	info = xml["Tracks"][track]
	print (info["Name"] + " - " + info.get("Artist", "")).encode("utf-8")

[出力]

=== プレイリスト ===
ライブラリ
ミュージック
ムービー
テレビ番組
Podcast
Genius
再生回数
最近再生した項目
最近追加した項目
...
=== トラック ===
イロトリドリ ノ セカイ - JUDY AND MARY
Hello! Orange Sunshine - JUDY AND MARY
手紙をかくよ - JUDY AND MARY
夕暮れ - JUDY AND MARY
RADIO - JUDY AND MARY
風に吹かれて - JUDY AND MARY
BATHROOM - JUDY AND MARY
恋磁石 - ClariS
自転車 - JUDY AND MARY
...

Python だと標準で iTunes Music Library.xml のフォーマットに対応したパーサが用意されているのでだいぶ楽ですね。

読み込み速度もそんなに気にならないレベルだった。

2014-03-02

[][]libclang の Python binding を使用する 〜 詳細な型名の取得 〜

前回はカーソル位置の型名を取得する方法について書きました。

今回は詳細な型名を取得する方法について書きます。


さて、前回使用した方法では例えば以下のように typedef されている場合、typedef した型名を取得します。


typedef int hoge;
hoge h;
// h は hoge 型として取得する

今回は typedef した型名ではなくて typedef された型名を取得する方法についてのコードを書きます。


[ソース]

# -*- coding: utf-8 -*
import clang.cindex
from clang.cindex import Cursor
from clang.cindex import Config
from clang.cindex import _CXString
from clang.cindex import Type


# Clang 3.3 の python binding を使用した場合、
# lib に設定されていないので
# ユーザ側で設定しておく必要がある
conf = Config()
conf.lib.clang_getTypeSpelling.restype  = _CXString
conf.lib.clang_getTypeSpelling.argtypes = [Type]
conf.lib.clang_getTypeSpelling.errcheck = _CXString.from_result

def type_spelling(type):
    return conf.lib.clang_getTypeSpelling(type)


# source code
source = """
template<typename T>
struct X{};

int
main(){
    typedef int hoge;
    hoge h;
    h;
    
    typedef X<hoge> X_hoge;
    X_hoge x;
    x;
}
"""

index = clang.cindex.Index.create()

tu = index.parse("test.cpp", args = ["-std=c++11 "], unsaved_files = [ ("test.cpp", source)])

# Cursor の生成
def make_cursor(file, line, col):
    # location を定義
    location = tu.get_location(file, (line, col))
    
    # location からその位置の cursor を取得
    return Cursor.from_location(tu, location)

# Type の情報を出力
def print_type(type):
    print "kind : %s" % type.kind
    print "spelling : %s" % type_spelling(type)
    print "canonical_spelling : %s" % type_spelling(type.get_canonical())


cursor1 = make_cursor("test.cpp", 8, 5)
print_type(cursor1.type)

cursor2 = make_cursor("test.cpp", 12, 5)
print_type(cursor2.type)

[出力]

kind : TypeKind.TYPEDEF
spelling : hoge
canonical_spelling : int
kind : TypeKind.TYPEDEF
spelling : X_hoge
canonical_spelling : X<int>

元の型名を取得するには type.get_canonical() で取得する事ができます。

これは Type を返すので後は type_spelling() 等で型名を取得する事ができます。

C++ だとテンプレートがすごいことになっている型があるので詳細を調べたい場合は有効だと思います。


[Clang]

  • clang++ (LLVM) 3.3

[2014-03-01 22:33]

2014-03-01

[][]libclang の Python binding を使用する 〜 型名の取得 〜

前回は Type について簡単に書きました。

今回はその Type の名前を取得する方法について書きます。


[注意]

今回使用している clang_getTypeSpelling なのですが、Clang 3.3 以前の python binding を使用している場合はユーザ側で動的ライブラリから呼び出せるように設定しておく必要があります。

Clang 3.4 以降の python binding の場合は clang_getTypeSpelling が Type.spelling から呼び出すように設定されているので clang_getTypeSpelling を設定する必要はありません。


[ソース]

# -*- coding: utf-8 -*
import clang.cindex
from clang.cindex import Cursor
from clang.cindex import Config
from clang.cindex import _CXString
from clang.cindex import Type

# Clang 3.3 の python binding を使用した場合、
# lib に設定されていないので
# ユーザ側で設定しておく必要がある
conf = Config()
conf.lib.clang_getTypeSpelling.restype  = _CXString
conf.lib.clang_getTypeSpelling.argtypes = [Type]
conf.lib.clang_getTypeSpelling.errcheck = _CXString.from_result

def type_spelling(type):
    return conf.lib.clang_getTypeSpelling(type)


# source code
source = """
int
main(){
    int value;
    value = 0;
    
    int* ptr;
    ptr = &value;
    
    struct X{};
    X x;
    x;
    
    auto px = &x;
    px;
    return 0;
}
"""

index = clang.cindex.Index.create()

tu = index.parse("test.cpp", args = ["-std=c++11 "], unsaved_files = [ ("test.cpp", source)])

# Cursor の生成
def make_cursor(file, line, col):
    # location を定義
    location = tu.get_location(file, (line, col))
    
    # location からその位置の cursor を取得
    return Cursor.from_location(tu, location)

# Type の情報を出力
def print_type(type):
    print "kind : %s" % type.kind
    print "spelling : %s" % type_spelling(type)


cursor1 = make_cursor("test.cpp", 4, 5)
print_type(cursor1.type)


cursor2 = make_cursor("test.cpp", 7, 5)
print_type(cursor2.type)

cursor3 = make_cursor("test.cpp", 11, 5)
print_type(cursor3.type)

cursor4 = make_cursor("test.cpp", 15, 5)
print_type(cursor4.type)

[出力]

kind : TypeKind.INT
spelling : int
kind : TypeKind.POINTER
spelling : int *
kind : TypeKind.RECORD
spelling : X
kind : TypeKind.UNEXPOSED
spelling : X *

簡単にですが、こんな感じで使用することができます。

auto を使用した場合の型名なども取得する事ができます。


[Clang]

  • clang++ (LLVM) 3.3

2014-02-25

[][]libclang の Python binding を使用する 〜 Type 編〜

前回からすっかり時間があいてしまいましたがまだ続けますよ。

決して忘れていたわけではない

前回までは Cursor について書いていましたが、今回は型情報について簡単に書きます。

Cursor からその位置の型情報を取得する事ができます。


[ソース]

# -*- coding: utf-8 -*
import clang.cindex
from clang.cindex import Cursor


# source code
source = """
int value;
value = 0;

int* ptr;
ptr = &value;

struct X{};
X x;
x;
"""

index = clang.cindex.Index.create()

tu = index.parse("test.cpp", unsaved_files = [ ("test.cpp", source)])

# Cursor の生成
def make_cursor(file, line, col):
    # location を定義
    location = tu.get_location(file, (line, col))
    
    # location からその位置の cursor を取得
    return Cursor.from_location(tu, location)

# Type の情報を出力
def print_type(type):
    print "kind : %s" % type.kind


cursor1 = make_cursor("test.cpp", 2, 1)
print_type(cursor1.type)

cursor2 = make_cursor("test.cpp", 5, 1)
print_type(cursor2.type)

cursor3 = make_cursor("test.cpp", 9, 1)
print_type(cursor3.type)

[出力]

kind : TypeKind.INT
kind : TypeKind.POINTER
kind : TypeKind.RECORD

任意の位置の型情報を取得する場合は、まずその位置の Cursor を生成して、その Cursor から型情報の取得を行います。

次は型情報から型名を取得する方法について書く予定。


[Clang]

  • clang++ (LLVM) 3.3

2014-02-11

[][]libclang の Python binding を使用する 〜 referenced 編〜

前回から少し時間があきました。

前回は definition に関する記事を書きました。

今回は referenced について書きます。

referenced は前回紹介した definition と似ており定義位置を返します。

definition との違いは definition が宣言のみの場合は None を返すのに対し、referenced の場合は宣言位置を返します。


[ソース]


# -*- coding: utf-8 -*
import clang.cindex
from clang.cindex import Cursor
from clang.cindex import Config

Config.set_compatibility_check(False)
Config.set_library_path("D:/LLVM/BUILD_3_3/bin")


# source code
source = """\

// 宣言のみの関数
void
func1();

// 先に宣言し、後から定義する関数
void
func2(int);

// 定義のみの関数
void
func3(int, float){

}

// func2() の定義
void
func2(int){

}

int
main(){
    func1();
    func2(1);
    func3(1, 3.31f);
    return;
}
"""

index = clang.cindex.Index.create()

tu = index.parse("test.cpp", unsaved_files = [ ("test.cpp", source)])

# Cursor の生成
def make_cursor(file, line, col):
    # location を定義
    location = tu.get_location(file, (line, col))
    
    # location からその位置の cursor を取得
    return Cursor.from_location(tu, location)


# Cursor の情報を出力
def print_cursor(cursor):
    if cursor is None:
        print "None"
        return
    print "displayname: %s" % cursor.displayname
    print "spelling   : %s" % cursor.spelling
    print "kind       : %s" % cursor.kind
    print "location   : %s" % cursor.location

def1 = make_cursor("test.cpp", 24, 2)
print "-------- referenced func1() --------"
print_cursor(def1.referenced)

print ""

def2 = make_cursor("test.cpp", 25, 2)
print "-------- referenced func2() --------"
print_cursor(def2.referenced)

print ""

def3 = make_cursor("test.cpp", 26, 2)
print "-------- referenced func3() --------"
print_cursor(def3.referenced)


[出力]

-------- referenced func1() --------
displayname: func1()
spelling   : func1
kind       : CursorKind.FUNCTION_DECL
location   : <SourceLocation file 'test.cpp', line 4, column 1>

-------- referenced func2() --------
displayname: func2(int)
spelling   : func2
kind       : CursorKind.FUNCTION_DECL
location   : <SourceLocation file 'test.cpp', line 18, column 1>

-------- referenced func3() --------
displayname: func3(int, float)
spelling   : func3
kind       : CursorKind.FUNCTION_DECL
location   : <SourceLocation file 'test.cpp', line 12, column 1>

こんな感じです。

と、書いておいてあれなんですが、具体的な仕様を把握していないのでもしかしたら認識が間違っているかも…。

次こそは型情報について書く予定。


[Clang]

  • clang++ (LLVM) 3.3