Sqratの概要、導入手順、および基本的な使い方について説明しています。
Sqratの各クラスの説明については別ページを参照してください。
Sqratとは、Brandon Jones氏によって開発されている、組み込み言語Squirrelをより便利に扱うためのC++用ライブラリです。
Squirrelについては主な言語まとめのページのSquirrelの項を参照してください。
Sqratライブラリは次の3つの機能を提供しています。
C++とSquirrelのバインダとしてはSqPlusが有名です。
両者の違いは、SqPlusがVM(仮想マシン)を含む全てをラップしているのに対して、SqratではVMに対する一連の操作(C++クラスのバインド等)に絞ってラップしていることです。
そのため、SqPlusを使う場合はすべてSqPlusで書かなければなりませんが*1、Sqratを使う場合は必要に応じてSquirrelのAPIを直に使うこともできます。
この文書では、Sqratの機能の一つであるバインダの導入手順および簡単な内容の説明を行います。
モジュールインポートやスレッドモジュールについては一切触れません。
Sqratにはわかりやすいドキュメントが付属しており、普通はそれを見るだけで利用の上では問題ありません。
しかし、ドキュメントでは触れられておらず、コードを見て初めてわかる機能もいくつかあります。
また、ドキュメントは英語であるため、英語恐怖症を患っている方には辛いものがあります(サンプルコードが多いので英語が読めなくても大体理解できるのですが)。
そこで、ドキュメントに載っている情報+αを日本語で説明するのがこの文書の主旨となります。
ただし、筆者の理解が完璧であるとは言えないため、間違いを含む可能性があることに留意してください。
Sqratを使うためには、当然ながら使用するプログラムでSquirrelを扱えるようにする(即ち、Squirrelのライブラリをリンクする)必要があります。
SqratがサポートするのはSquirrel2.2系なので、まずはSquirrelのダウンロードページから2.2系の最新版を落としてきましょう。
圧縮ファイルを展開後、 make できる環境(Linux等)であれば普通にトップディレクトリで make するだけです。
lib ディレクトリ内に libsquirrel.a および libsqstdlib.a ができあがります。
WindowsでVisual Studio 2005やVisual Studio 2008を使って開発している場合、次の手順でビルドします。
プログラムに組み込むには、 include ディレクトリおよび lib ディレクトリをそれぞれインクルードパス、ライブラリパスに追加し、squirrelライブラリおよびsqstdlibライブラリをプログラムにリンクすればOKです。
Windowsかつ非Unicode設定でSquirrelを使用する場合、そのままでは日本語(Shift_JIS)を扱うことができません。
squirrelプロジェクトのソースファイル sqlexer.cpp の330行目付近(default
句の直後)に次のようにコードを追加する必要があります。
#if
と #endif
で囲まれている部分が追加する行となります。
! ! | | | | | | - | | | ! | | | ! ! |
|
取得した文字コードがShift_JISの2バイト文字の上位1バイトであった場合、その次の文字コードまで読み取るという処理です。
このコードは次のページを参考にして記述しました。
Squirrelの導入が済んでいれば、Sqratのバインダの導入自体はとても簡単です。
#include <sqrat.h>
を書きます。これだけです。
Sqratのバインダはテンプレートクラス群として提供されており、予めビルドすべきものはありません。
この項ではSqratの基本的な使い方を説明します。
Sqratで定義されているクラスの詳細については各クラスの説明のページを参照してください。
SqratはSquirrelのVM自体をラップしてはいません。
そのため、VMのインスタンスは普通にSquirrelのAPIを使うときと同じようにして初期化、解放する必要があります。
大抵は次のように書くことになるでしょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | - ! - | | | | | | | | ! - ! - - ! | - ! | - ! | - ! | - | | ! - ! | | ! |
|
当文書での説明におけるC++サンプルコード片は、上記コード中の ※
の部分のみ書かれている場合があります。
C++のクラスや関数等をSquirrelのVMにバインドする基本的な手順は次のようになります。
簡単なC++コーディング例を次に示します。
bindMyTable
関数は、 MyClass
クラスおよび printNum
関数を MyTable
テーブルにバインドし、その MyTable
テーブルをルートテーブルにバインドしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | - ! - | | | ! - ! - | ! - | | - ! | - ! | - ! | | - ! | | - ! ! |
|
なお、コード中の _SC
はSquirrelで定義されているマクロであり、意味は _T
マクロと同じです。
_T
マクロについては当サイトのUnicode対応コーディングのページを参照してください。
この関数を通したVMでは、次のようなSquirrelスクリプトを実行することができます。
1 2 3 |
|
ちなみに、テーブルへの MyClass
クラスのバインドは次のようにまとめて書くこともできます。
どちらでも好きな書き方で書くとよいでしょう。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| - | | - ! | - ! | | | | | | - ! | - ! ! |
|
なお、この項のコーディング例のようにしてクラスオブジェクトを作成する場合、そのクラスで引数無しのコンストラクタが公開されている必要があります。
コンストラクタを公開せずにクラスオブジェクトを作成する方法については、各クラスの説明の Class<C,A> クラスの項を参照してください。
C++の値やインスタンスをSquirrelのVMにグローバル変数としてバインドするコーディング例を次に示します。
なお、あらかじめ MyStruct
構造体と MyClass
クラスの定義をバインド済みであるものとします。
1 2 3 4 5 6 7 8 9 10 11 12 | - ! - ! |
|
値のバインドには BindValue
メンバ関数を、インスタンスのバインドには BindInstance
メンバ関数を用います。
どちらも第一引数が変数名、第二引数が値となります。
対象テーブル内に指定した名前の変数が存在しない場合は新規作成され、存在する場合は上書きされます。
BindValue
メンバ関数でバインドした値はSquirrel側で操作してもC++側には反映されません(コピーが渡される)。
一方、 BindInstance
メンバ関数でバインドしたインスタンスをSquirrel側で操作するとC++側にも反映されます(参照が渡される)。
上記のコーディング例ではルートテーブルにバインドしてグローバル変数としていますが、ルートテーブル以外のテーブルにも同様にしてバインドできます。
次のようなSquirrelスクリプトを実行済みのVMがあるとします。
この時、グローバル変数やクラスのメンバ変数などの値は次のコーディング例のようにして取得できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | - ! - ! - ! - ! - ! |
|
GetSlot
メンバ関数によってSquirrel変数の値を Object
クラスのインスタンスとして取得できます。
そして Cast<T>
メンバ関数によって目的の型として取得できます。
変数が存在するかどうかわからない場合は、次のコーディング例のように IsNull
メンバ関数を用いてチェックします。
IsNull
メンバ関数は変数を取得できなかった場合(即ち null
が返った場合)に真となります。
Squirrelでは関数も値の一つです。
しかしSqratでは、Squirrelの関数をC/C++の関数的に扱える仕組みが用意されています。
次のようなSquirrelスクリプトを実行済みのVMがあるとします。
この時、Squirrel関数は次のようにして取得および実行できます。
1 2 3 4 5 6 7 8 9 10 11 | - ! - ! - ! |
|
関数の取得にはテーブルまたはクラスの GetFunction
メンバ関数を用います。
もしくは Function
クラスのコンストラクタでも同等のことが行えます。
ちなみに、変数の場合と同じく、 IsNull
メンバ関数で存在チェックできます。
取得した関数の実行には Execute
メンバ関数か Evaluate
メンバ関数を用います。
返り値が不要な場合には Execute
メンバ関数を用います(上記の例のように operator()
でも行えます)。
返り値が必要な場合には Evaluate
メンバ関数を用い、テンプレート引数に返り値の型を指定します。
引数および返り値の型には、 int
や float
等の基本型に加え、あらかじめバインドしておいたクラス型を用いることもできます。
各クラスの説明のページにて。