1.Luaの特徴
Luaは小さなスクリプト言語です。作者はブラジル人。アプリケーションに組み込んで、アプリケーションの拡張やカスタマイズを柔軟に行えるように設計されています。ホームページはwww.lua.org。
Luaの最も有名なアプリケーションは、Blizzard社のオンラインゲーム「WOW」です。
Luaスクリプトは、C/C++コードから簡単に呼び出すことができ、またその逆も可能であるため、Luaを幅広いアプリケーションで使用することができます。拡張スクリプトとしてだけでなく、XML、Ini、その他のファイル形式の代わりに一般的な設定ファイルとしても使用でき、理解や保守が容易になります。
Luaは標準的なC言語で書かれており、コードはシンプルで美しく、ほとんどすべてのオペレーティングシステムとプラットフォームでコンパイル、実行することができます。完全なLuaインタプリタはわずか200kで、Luaは現在のすべてのスクリプトエンジンの中で最速です。これらのことから、Luaは組み込みスクリプトに最適です。
Luaには、特定のプラットフォーム上でオンザフライ・コンパイルを提供する並行JITプロジェクトがあり、これによりLuaのパフォーマンスがさらに向上します。このプロジェクトについては、http://..et/をご覧ください。
Pythonなどのスクリプトと違い、Luaには強力なライブラリがありません。そのため、Luaはスタンドアロンのアプリケーションを開発するための言語としては適していません。ただし、数学演算や文字列操作などの基本的な機能は備えています。
Luaの最新バージョンは現在5.1です。
Luaのデータ型はテーブルのみで、実際にはハッシュテーブルです。これを用いて、配列やリンクリストなどをモデル化します。 構文的には、Luaは以下の形式をサポートしています:
データ = {} --テーブルを定義する
データ.i = 1
データ.name = "jason"
データ.package = {1,2,2,3,56,7}
データ.others = {}
データ.others.a = 1
data.others.b = 1.1
これによりLuaはCのstructに似た形式を持ち、C関数のパラメータ設計が非常に簡単になり、非常に複雑なパラメータを1つのテーブルで渡すことができます。
2.SDMXの紹介
Lua プログラムと C プログラムはスタックを介してデータを交換します。
スタックの数は、スタックの最上部と最下部から数えることができます。 スタックの最下部から数えた場合、スタックの最下部は1であり、スタックの最上部に向かってインクリメントされます。スタックの一番上から数えた場合、スタックの一番上は -1 で、スタックの一番下に向かって減っていきます。一般的には、スタックの先頭から数えます。スタックのデフォルトサイズは20ですが、lua_checkstackで変更できます。lua_gettopでスタックの要素数を取得できます。これは、スタックの一番上にプラスチックの要素があるという意味ではありません。その代わり、スタックの一番上の要素の正のインデックスが計算され、それが要素数に等しくなります。
LuaがC関数を呼び出す際に使用するスタックは一時的なもので、呼び出しが終わると破棄されます。
Luaスクリプトからスタックからパラメータを取得する方法
Luaスクリプトのグローバル変数の名前がわかっている場合、void lua_getglobal .この関数は、その名前を持つLua変数の値をスタックの先頭に置きます。
C関数の場合は、Lua呼び出し関数で使用されるパラメータを取得します:
まずlua_gettopで引数の数をチェックします。
lua_is...クラス関数は、引数の型を検出し、エラー処理を行います。
引数を数値や文字列に変換するには、lua_to...クラスの関数を使用します。
lua_tonumber は double を返します。
lua_tostring は char* を返します。
lua_remove でスタックから要素を削除します。
続けて次の要素を取得します。 lua_removeは毎回呼び出されるため、lua_tonumberを呼び出すたびに使用されるインデックスはスタックの先頭である-1に固定されます。
lua_istableが成立する場合、スタックの先頭がテーブルであることを意味します。テーブルを削除することはできず、テーブル内の要素のみを1つずつ削除できることに注意してください。
lua_pushstring(L, "i"); 次に lua_gettable を呼び出すと、スタックの一番上に値が置かれます。同時に、先ほど押された要素名がポップされます。 値は上記の方法で取り出すことができます。もし、tableの要素の1つもtableだった場合は、lua_removeを繰り返します。 tableの要素がすべて取り出されたら、スタック上にtableそのものが残っているので、lua_removeで削除することを忘れないでください。
配列を取得したい場合は、lua_nextを使用して配列を繰り返し処理します:
まず lua_pushnil で null 値を入力し、次に
while (lua_next(L, -2) != 0)
{
if(lua_isnumber(L,-1)) //要素の型を決定する(文字列の場合もある)。
{
arrf.add((float)lua_tonumber(L, -1));//要素の値を取得する
lua_remove(L,-1);
}
}
lua_remove(L,-1);//NILを削除する
C言語からLuaスクリプトにデータを返す方法
lua_push...クラスの関数を使用してデータをスタックにプッシュし、return n; を使用して返り値がいくつ返されたかを Lua に伝えます。 Luaは、x,y = Test()のように、複数の戻り値をサポートしています。 Luaはnに基づいてスタックから適切なデータを取り出します。
テーブルを返したい場合
lua_newtable(L);//テーブルを作成し、スタックの一番上に置く。
lua_pushstring(L, "mydata");//キーを押す
lua_pushnumber(L,66);//値を押し込む
lua_settable(L,-3);//スクリプトのコードは以下の通りである。
lua_pushstring(L, "subdata");//キーを押す
lua_newtable(L);//値を押す。
lua_pushstring(L, "mydata");//サブテーブルのキーを押す
lua_pushnumber(L,53);//value
lua_settable(L,-3);//ポップアップ・キー、値、サブテーブルにセットする。
lua_settable(L,-3);//この時点では、親テーブルの位置はまだ-3であり、ポップアップキー、値、そして移動するテーブルに設定される。
lua_pushstring(L, "mydata2");//上記と同じ
lua_pushnumber(L,77);
lua_settable(L,-3);
return 1;//スタックに.スクリプトのコードは以下の通りだ。
#p#
配列を返すには、以下のコードを使用します:
Lua_pushstring(L,"arri");
Lua_newtable(L);
{
//a trick:otherwise the lua engine will crash. This element is invisible in Lua script
lua_pushnumber(L,-1);
lua_rawseti(L,-2,0);
for(int i = 0; i < arri.size();i++)
{
lua_pushnumber(L,arri[i]);
lua_rawseti(L,-2,i+1);
}
}
lua_settable(L,-3);
結果の配列はLuaで次のように走査できます:
for i,v in ipairs(data.arri) do
print
終わり
または
for i=1,table.getn(data.arri) do print(data.arri[i]) 終わり
配列のみが可能で、レコードの名前、値はできません。table.getnも配列に対してのみ有効です。
上記のコードは類似性が高いため、これらのコードの自動生成を実装するのは簡単です。例えば、C言語の構造体定義に基づいて
typedef enum
{
BR_9600,
BR_4800,
} BaudRate;
typedef struct flag
{
int onoff;
int j;
long l;
double d;
char* name;
BaudRate rate;
}flag;
以下のコードは自動的に生成されます:
bool DataToLua(flag data, Lua_State *L)
{
Lua_newtable(L);
lua_pushstring(L,"onoff");
lua_pushnumber(L,(double)data.onoff);
lua_settable(L,-3);
lua_pushstring(L,"j");
lua_pushnumber(L,(double)data.j);
lua_settable(L,-3);
lua_pushstring(L,"l");
lua_pushnumber(L,(double)data.l);
lua_settable(L,-3);
lua_pushstring(L,"d");
lua_pushnumber(L,(double)data.d);
lua_settable(L,-3);
lua_pushstring(L,"name");
lua_pushstring(L,data.name.c_str());
lua_settable(L,-3);
lua_pushstring(L,"rate");
lua_pushnumber(L,(double)(int)data.rate);
lua_settable(L,-3);
return true;
}
LuaToDataも同様です。
オブジェクト指向の方法でフラグをカプセル化し、DataToLuaをフラグクラスのメソッドにした方が便利でしょう。
3.CスクリプトとLuaスクリプトの相互呼び出しの例
最初のステップは、メインのCプログラムがLuaスクリプトエンジンを初期化し、スクリプト内で呼び出す関数を登録することです:
//function for Lua to call
//return a integer array to the script
static int l_getarr ( Lua_State *L)
{
lua_newtable(L);//create table
lua_pushnumber(L,1);//push the value
lua_rawseti(L,-2,1);//set t[1]=v
lua_pushnumber(L,2);
lua_rawseti(L,-2,2);
lua_pushnumber(L,3);
lua_rawseti(L,-2,3);
lua_pushnumber(L,4);
lua_rawseti(L,-2,4);
return 1;
}
int main()
{
lua_State *L = lua_open(); /* opens Lua */
luaopen_base(L); /* opens the basic library */
luaopen_table(L); /* opens the table library */
luaopen_string(L); /* opens the string lib. */
luaopen_math(L); /* opens the math lib. */
lua_pushcfunction(L, l_getarr); // Register a function
lua_setglobal(L, "getarr");
if (lua_dofile(L, "testlua.lua"))//Load the script file and Run it
{
printf("run script failed
");
}
else
{
lua_getglobal(L, "result"); //Get the global variant in Lua script
if(lua_isnumber(L,-1))
{
printf("The result of the Lua script is %d
",lua_tonumber(L,-1));
}
}
lua_close(L);
return 0;
}
スクリプトのコードは以下の通りです:
array = getarr()
if array ~= nil then
結果 = 1
for i=1,table.getn(array),1 do
print(array[i])
終わり
else
結果 = 0
終わり