Archive for the ‘Squirrel’ Category

squirrel のバージョンが新しくなってました。
Squirrel 本家

2.2.3 の変更点まとめ
今回から SQUSEDOUBLE を利用してコンパイルすることで、内部で使用している浮動小数点を float -> double にすることが出来るらしい。
合わせて、_floatsize_ で設定されている浮動小数点のバイト数が取得可能。
デバッグ用の関数として sq_getfunctioninfo が追加されてる。
sq_getstackinfos 関数と合わせて利用するといいかも。
sqstd_format は printf と同様のフォーマットが利用できる。
フォーマット文字列はスタック上に配置して、sqstd_format にはスタックのインデックスを渡す形になる。

以下、変更点の引用

***version 2.2.3 stable***
-added sq_getfunctioninfo
-added compile time flag SQUSEDOUBLE to use double precision floats
-added global slot _floatsize_ int the base lib to recognize single precision and double precision builds
-sq_wakeupvm can now resume the vm with an exception
-added sqstd_format
-generators can now be instantiated by calling sq_call() or closure.call()
-fixed a bug in sqstd_printcallstack(thx takayuki_h)
-fixed modulo by zero(thx jup)
-fixed negative enums and constants
-fixed generator crash bug if invoked as tail call (thx Mr.Accident)
-fixed some minor bug

***version 3.0 alpha 2***
-added real free variables(thx Paul Ruizendaal)
-added refactored function call implementation and compiler(thx Paul Ruizendaal)
-added sq_getfunctioninfo
-added compile time flag SQUSEDOUBLE to use double precision floats
-added global slot _floatsize_ int the base lib to recognize single precision and double precision builds
-sq_wakeupvm can now resume the vm with an exception
-added sqstd_format
-now blobs can be cloned
-generators can now be instantiated by calling sq_call() or closure.call()
-added compile time flag SQUSEDOUBLE to use double precision floats
-fixed debughook bug
-fixed cooroutine error propagation

明日はCEDEC 2008 ですね。Squirrel のセッションは聞いてきますよー。

さて、今日はコメントにもありました sq_readclosure/sq_writeclosure/sq_compilebuffer を使ってみます。
これらは SqPlus のものではなく、Squirrel の関数ですね。

まずは簡単に使うだけの話。

sq_compilebuffer は SqPlus 版があるので、SqPlus::CompileBuffer を使います。
これはメモリ上のスクリプトをコンパイルし、スタックに積むというもの。

C++:
  1. // スクリプト
  2. const SQChar script[64] = _T("print(\"hogehoge-\");");
  3.  
  4. // compilebuffer 部分。
  5. SqPlus::CompileBuffer(script);

次に sq_readclosure。
これはコンパイル済みのスクリプトを読み込むというもの。
sq_readclosure も SqPlus で一発。

C++:
  1. // コンパイル済みスクリプトの読み込み
  2. SquirrelObject obj = SquirrelVM::CompileScript(_T("helloworld.cnut"));

実はSqPlus を使わなくても sqstd_loadfile 関数がヘッダをチェックして自動的に読み込んでくれるのです。おいしいです。

最後に sq_writeclosure。
VMに積まれているスクリプトをバイナリで吐き出すというもの。
SqPlus には無いので、Squirrel のものを使います。

C++:
  1. // バイナリで書き出す
  2. sqstd_writeclosuretofile(vm, _T("helloworld.cnut"));

てことで、簡単に使えます。
でもめんどくさい方法もあります。それはまた次回!

前回は C++ 側の関数やクラスを Squirrel 側で呼び出したので、今回はその逆です。

C++:
  1. // main.cpp
  2. #include <iostream>
  3. #include <sqplus.h>
  4.  
  5. #ifdef _DEBUG
  6. #  pragma comment(lib, "squirrelD.lib")
  7. #  pragma comment(lib, "sqplusD.lib")
  8. #  pragma comment(lib, "sqstdlibD.lib")
  9. #  pragma comment(lib, "sqdbglibD.lib")
  10. #else
  11. #  pragma comment(lib, "squirrel.lib")
  12. #  pragma comment(lib, "sqplus.lib")
  13. #  pragma comment(lib, "sqstdlib.lib")
  14. #  pragma comment(lib, "sqdbglib.lib")
  15. #endif //_DEBUG
  16.  
  17. int main(int argc, char** argv)
  18. {
  19.     SquirrelVM::Init();
  20.  
  21.     //----------------------------------------------------
  22.     // スクリプトの読み込みとコンパイル
  23.     //----------------------------------------------------
  24.     SquirrelObject obj = SquirrelVM::CompileScript(_T("helloworld.nut"));
  25.  
  26.  
  27.     //----------------------------------------------------
  28.     // スクリプトの実行
  29.     //----------------------------------------------------
  30.     try {
  31.         SquirrelVM::RunScript(obj);
  32.  
  33.         //----------------------------------------------------
  34.         // Squirrel 側の関数を呼び出す
  35.         // ※ まず SquirrelVM::RunScript の呼出しが必要!!
  36.         //----------------------------------------------------
  37.         // template のパラメータは戻り値の型, 関数名を指定
  38.         SqPlus::SquirrelFunction<void>(_T("func01"))();
  39.         // 引数付き関数を呼び出す
  40.         SqPlus::SquirrelFunction</void><void>(_T("func02"))("fuga");
  41.         // 戻り値の型を指定
  42.         std::cout <<SqPlus::SquirrelFunction<float>(_T("func03"))() <<std::endl;
  43.     } catch (SquirrelError& e) {
  44.         // error 処理
  45.         std::cout <<e.desc <<std::endl;
  46.     }
  47.  
  48.     SquirrelVM::Shutdown();
  49.  
  50.     return 0;
  51. }

C++:
  1. // helloworld.nut
  2. function func01() {
  3.     print("call : func01()");
  4. }
  5.  
  6. function func02(var) {
  7.     print("call : func02(), " + var);
  8. }
  9.  
  10. function func03() {
  11.     print("call : func03()");
  12.     return 3.14;
  13. }

cl /EHsc /MT /DNOUNICODE /I..\SQUIRREL2_1_1_sqplus_25\sqplus /I..\SQUIRREL2_1_1_sqplus_25\squirrel /I..\SQUIRREL2_1_1_sqplus_25\include main.cpp /link /LIBPATH:..\SQUIRREL2_1_1_sqplus_25\lib

実行結果

call : func01()
call : func02(), fuga
call : func03()
3.14

コードを見てもらうとわかるように、非常に簡単に Squirrel 側の関数を呼び出せます。
Squirrel では class の定義もできますが、それを C++ 側で使うのはちょっとわかりません。
# わかる人教えてください。

今回の注意点は、Squirrel の関数呼び出しは SquirrelVM::RunScript の後に行うこと!
まぁ、当然っちゃ当然ですね。

ではまた次回!

バインドー、バインド。えぇ、いつもバインドボイスに悩まされます(MHP2G)

ってことで、今回はバインドしてみましょう。

いきなりソースですが、これは前回のソースをちょろちょろっと修正してるだけです。

C++:
  1. // main.cpp
  2. #include <iostream>
  3. #include <sqplus.h>
  4.  
  5. #ifdef _DEBUG
  6. #  pragma comment(lib, "squirrelD.lib")
  7. #  pragma comment(lib, "sqplusD.lib")
  8. #  pragma comment(lib, "sqstdlibD.lib")
  9. #  pragma comment(lib, "sqdbglibD.lib")
  10. #else
  11. #  pragma comment(lib, "squirrel.lib")
  12. #  pragma comment(lib, "sqplus.lib")
  13. #  pragma comment(lib, "sqstdlib.lib")
  14. #  pragma comment(lib, "sqdbglib.lib")
  15. #endif //_DEBUG
  16.  
  17. class Hoge
  18. {
  19. public:
  20.     Hoge() : data_(1230) {}
  21.     explicit Hoge(int data) : data_(data) {}
  22.     ~Hoge() {}
  23.     void print() { std::cout <<data_ <<std::endl; }
  24.  
  25.     static void bind() {
  26.         SqPlus::SQClassDef<Hoge>(_T("Hoge")).
  27.             staticFunc(Hoge::constructHoge, _T("constructor")).
  28.             func(&Hoge::print, _T("print")).
  29.             var(&Hoge::data_, _T("data_"));
  30.     }
  31.  
  32.     static int constructHoge(int data, HSQUIRRELVM v) {
  33.         return SqPlus::PostConstruct<hoge>(v, new Hoge(data), SqPlus::ReleaseClassPtr</hoge><hoge>::release);
  34.     }
  35.  
  36. private:
  37.     int data_;
  38. };
  39.  
  40. int main(int argc, char** argv)
  41. {
  42.     SquirrelVM::Init();
  43.  
  44.     //----------------------------------------------------
  45.     // バインド
  46.     //----------------------------------------------------
  47.     // 変数
  48.     int   intValue   = 100;
  49.     float floatValue = 1.234f;
  50.     // 文字列は ScriptStringVar を使う
  51.     SqPlus::ScriptStringVar8 charValue = _T("hoge");
  52.  
  53.     // バインド
  54.     SqPlus::BindVariable(&intValue  , _T("intValue"));
  55.     SqPlus::BindVariable(&floatValue, _T("floatValue"));
  56.     SqPlus::BindVariable(&charValue , _T("charValue"));
  57.  
  58.  
  59.     //----------------------------------------------------
  60.     // Squirrel スクリプト側にクラスをバインド
  61.     //----------------------------------------------------
  62.     Hoge::bind();
  63.  
  64.  
  65.     //----------------------------------------------------
  66.     // スクリプトの読み込みとコンパイル
  67.     //----------------------------------------------------
  68.     SquirrelObject obj = SquirrelVM::CompileScript(_T("helloworld.nut"));
  69.  
  70.  
  71.     //----------------------------------------------------
  72.     // スクリプトの実行
  73.     //----------------------------------------------------
  74.     try {
  75.         SquirrelVM::RunScript(obj);
  76.     } catch (SquirrelError& e) {
  77.         // error 処理
  78.     }
  79.  
  80.     // 変更された後の値
  81.     std::cout <<"intValue = " <<intValue <<std::endl;
  82.  
  83.     SquirrelVM::Shutdown();
  84.  
  85.     return 0;
  86. }

C++:
  1. // helloworld.nut
  2. print("-- Begin SquirrelScript. --");
  3.  
  4. // 各種変数
  5. print("intValue   = " + intValue);
  6. print("floatValue = " + floatValue);
  7. print("charValue  = " + charValue);
  8.  
  9. // データ更新してみる
  10. intValue += 23;
  11.  
  12. // classValue
  13. local hoge = Hoge(2);
  14. hoge.print();
  15.  
  16. print("-- End SquirrelScript. --");


cl /EHsc /MT /DNOUNICODE /I..\SQUIRREL2_1_1_sqplus_25\sqplus /I..\SQUIRREL2_1_1_sqplus_25\squirrel /I..\SQUIRREL2_1_1_sqplus_25\include main.cpp /link /LIBPATH:..\SQUIRREL2_1_1_sqplus_25\lib

実行結果

-- Begin SquirrelScript. --
intValue = 100
floatValue = 1.234
charValue = hoge
2
-- End SquirrelScript. --
intValue = 123

まぁ、予想通りだと思います。
今回特殊なのはこれ。 Hoge::bind() の中で呼び出している staticFunc(Hoge::constructHoge, _T("constructor"))
Squirrel では引数付きコンストラクタはこのような形で登録してやらないと呼び出せない。
デフォルトコンストラクタとデストラクタについては、登録しなくても自動的に登録される。
# なぜか引数付きコンストラクタを登録すると、デフォルトコンストラクタが呼び出せなくなってしまう。

ではまた次回!次は Squirrel 側の関数を C++側から呼び出す方法などやりますかね。

さて、squirrel やってみましょうか。
squirrel
Squirrel 2.2 リファレンスマニュアル

生の Squirrel はリファレンスマニュアル触ればよいと思いますので、バインドを紹介します。
いくつかバインドがありますが、今回は SqPlus を紹介します。(てか自分はそれしか使っていない ^^;

まずはダウンロード。SqPlus
現在の最新安定バージョンは SQUIRREL2_1_1_sqplus_25 のようなので、これをダウンロード。
SqPlus には Squirrel 本体も含まれているので、これをダウンロードするだけで Squirrel + SqPlus が使えます。

ダウンロードしたアーカイブを展開すると squirrel.sln がありますので、ビルドしましょう。
> vcbuild squirrel.sln
>error C3861: 'printf': 識別子が見つかりませんでした
>error C3861: 'sprintf': 識別子が見つかりませんでした

あれ、エラーがでました。
てことで、ソースを修正します。
SQUIRREL2_1_1_sqplus_25/sqdbg/sqrdbg.cpp
SQUIRREL2_1_1_sqplus_25/sqdbg/sqdbgserver.cpp

この2つのソースコードの先頭に stdio.h のインクルード を加えました。(cstdio にしようかと思いましたが、ソース全般が **.h だったので。)

これで再度ビルドすることでバッチリでした。
 

今回は導入編なので、簡単なコードを試しておしまいにしましょう。
ディレクトリ階層はこのようにしています。
/root/SQUIRREL_2_1_1_sqplus_25
/root/test

testの下に、下記のコードを用意します。

C++:
  1. // main.cpp
  2. #include <iostream>
  3. #include <sqplus.h>
  4.  
  5. #ifdef _DEBUG
  6. #  pragma comment(lib, "squirrelD.lib")
  7. #  pragma comment(lib, "sqplusD.lib")
  8. #  pragma comment(lib, "sqstdlibD.lib")
  9. #else
  10. #  pragma comment(lib, "squirrel.lib")
  11. #  pragma comment(lib, "sqplus.lib")
  12. #  pragma comment(lib, "sqstdlib.lib")
  13. #endif //_DEBUG
  14.  
  15.  
  16. int main(int argc, char** argv)
  17. {
  18.     SquirrelVM::Init();
  19.  
  20.     // スクリプトの読み込みとコンパイル
  21.     SquirrelObject obj = SquirrelVM::CompileScript(_T("helloworld.nut"));
  22.  
  23.     // スクリプトの実行
  24.     try {
  25.         SquirrelVM::RunScript(obj);
  26.     } catch (SquirrelError& e) {
  27.         // error 処理
  28.     }
  29.  
  30.     SquirrelVM::Shutdown();
  31.  
  32.     return 0;
  33. }

さらに squirrel 用のスクリプトファイルを作成します。

C++:
  1. // helloworld.nut
  2. print("Welcome to Squirrel.");

これをビルドします。
cl /EHsc /MT /I..\SQUIRREL2_1_1_sqplus_25\sqplus /I..\SQUIRREL2_1_1_sqplus_25\squirrel /I..\SQUIRREL2_1_1_sqplus_25\include main.cpp /link /LIBPATH:..\SQUIRREL2_1_1_sqplus_25\lib

実行結果は、まぁ予想通りですw
まだ SqPlus を使っていませんが、今回はここまで。