はじめに
Luaのデータ型の一つにテーブル型があり、ネストさせることができます。 今回は、ネストしたテーブル型のデータをLuaのC APIを使って作成する方法を紹介します。
lua_setglobal()
を呼ぶ際に、誤ってキーに型名であるtable
を指定してしまっていた(スタックの扱いが不適切)- 後始末のための
lua_close(L)
を呼び出していない
ネストしていないテーブル型のデータを作成するには
いきなりネストしたテーブルを作成する方法を説明するとややここしくなるので、先にネストしていないテーブル型の場合を説明します。
Luaでprint(inspect(animal))
した結果、次のように表示されるテーブルをC APIを使って作成します。1
{
cat = "Meow",
dog = "Bow"
}
このテーブルは次のようなサンプルコードで作成できます。
#include <stdio.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
int main(void)
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_newtable(L);
lua_pushstring(L, "Meow");
lua_setfield(L, -2, "cat");
lua_pushstring(L, "Bow");
lua_setfield(L, -2, "dog");
lua_setglobal(L, "animal");
luaL_dostring(L, "local inspect=require('inspect'); print(inspect(animal))");
lua_close(L);
return 0;
}
コンパイル後のバイナリを実行すると、標準出力に次のようにanimal
テーブルの内容が表示されます。
{
cat = "Meow",
dog = "Bow"
}
上記のサンプルは、Cでテーブルを作成して、Luaスクリプトでそのテーブルを参照して表示します。
Luaはスタックを使ってCとデータをやりとりします。そのため、次のような流れで処理する必要があります。
-
lua_newtable(L);
でテーブル作成してスタックに積む -
lua_pushstring(L, "Meow");
でスタックに文字列"Meow"を積む -
lua_setfield(L, -2, "cat");
でキーを"cat"、値をスタックに積んである"Meow"としてスタックに積んであるテーブルに設定する
lua_setfield
を呼ぶと、スタックに積まれた"Meow"は除去されます。
-2
はスタックのトップを0としたインデックスを意味します。
つまり、テーブル、"Meow"の順にスタックに積み上げているので、-1は"Meow"を、-2はテーブルを意味します。
ここまでを図示すると次のようになります。
setfieldを使わない場合(参考)
テーブルを作成するサンプルでは、lua_setfield
を使わずに、lua_settable
を使っていることもあります。
lua_settable
の場合は、キーと値を積んだ状態で呼びだします。例えば、次のような使い方をします。
lua_newtable(L);
lua_pushstring(L, "cat");
lua_pushstring(L, "Meow");
lua_settable(L, -3);
lua_settable(L, -3);
ではキーが"cat"、"Meow"が値としてスタックに積んだテーブルに設定します。
テーブル、"cat"、Meow"の順にスタックに積み上げているので、-1は"Meow"を、-2は"cat"を、-3はテーブルを意味します。
lua_settable
の場合も同様に図示すると次のようになります。
ネストしているテーブル型のデータを作成するには
ネストしていないテーブル型のデータの作成方法がわかったところで、本題のネストしたテーブルを作成する方法を説明します。
Luaでprint(inspect(sample))
した結果、次のように表示されるテーブルを作成します。
{
animal = {
cat = "Meow"
}
}
このテーブルは次のようなサンプルコードで作成できます。
#include <stdio.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
int main(void)
{
lua_State *L = luaL_newstate();
int status = 0;
luaL_openlibs(L);
lua_newtable(L);
lua_pushstring(L, "animal");
lua_newtable(L);
lua_pushstring(L, "cat");
lua_pushstring(L, "Meow");
lua_settable(L, -3);
lua_settable(L, -3);
lua_setglobal(L, "sample");
luaL_dostring(L, "inspect=require('inspect'); print(inspect(sample))");
lua_close(L);
return 0;
}
-
lua_newtable(L);
でテーブルを作成してスタックに積む -
lua_pushstring(L, "animal");
でスタックに文字列"animal"を積む -
lua_newtable(L);
でネストしているテーブルを作成してスタックに積む -
lua_pushstring(L, "cat");
でネストしているテーブルのキーとなる"cat"をスタックに積む -
lua_pushstring(L, "Meow");
でネストしているテーブルの値となる"Meow"をスタックに積む -
lua_settable(L, -3);
でスタックからキー(cat)と値(Meow)をとりだし、ネストしているテーブルに設定する -
lua_settable(L, -3);
(2つめ)でスタックからキー"animal"と値(ネストしたテーブル)をとりだし、テーブルに設定する
この場合も同様に図示すると次のようになります。
ポイントは、キーである"animal"の値としてネストしたテーブルをlua_settable
していることです。
このようにすることで、多段にネストしたテーブル型のデータを作成できます。
まとめ
今回は、ネストしたテーブル型のデータをLuaのC APIを使って作成する方法を紹介しました。 Luaの言語バインディングを書く機会があったら参考にしてみてください。
-
inspectはluarocks install inspectでインストールしているものとします。 ↩