2013年10月22日火曜日

Luaを使ってクラスっぽい物を生成してCから使う方法

2013.11.04 修正版記事を作りました。
2013.11.04 大きな間違いに気がついたので後日書き直します。本記事は大嘘です。
2013.11.01 誤って記事を消してしまったので書き直し。

本記事は間違いだらけです。修正版はこちら。


以下のようなコードによって、Luaで簡単なクラス風のテーブルを作成できる。

クラス風のテーブルを作成する方法はWEB上に多数のサンプルが見受けられたが、 Cとの連携を付記したコードは見当たらなかったので備忘録として作成。

継承にはもう少し工夫が必要だが、複雑なテーブルを作成するならC++で普通にクラスを書いたほうが良い気がする。主観だが。

Luaでグローバル領域に宣言されたテーブルのフィールドを利用する際は、一度テーブルをスタックに積んでからフィールドを取得する点に注意。

main.cpp

#include <lua.hpp>
#include <stdio.h>

int main( void ) {
	lua_State *L = luaL_newstate();	// Luaステートを生成
	luaL_openlibs( L );				// 標準ライブラリを読み込み
	
	// スクリプトの読み込み
	if (luaL_dofile(L, "script.lua") ) {
		// エラー処理
		printf("%s\n", lua_tostring(L, lua_gettop(L) ) );
		lua_close(L);
		return 0;
	}

	// まず犬を生成
	lua_getglobal( L, "Dog" );					// グローバルなテーブル"Dog"をスタックに積む
	lua_getfield( L, lua_gettop( L ), "new" );	// トップに積まれたテーブルのメンバ"new"をスタックに積む
	lua_pushstring( L, "Neko" );				// 名前はNeko。犬なのにNeko。
	lua_pcall( L, 1, 1, 0 );					// 実行!
	int idx_dog = lua_gettop( L );				// Nekoのスタック上の位置を取得

	// 次に猫を生成
	lua_getglobal( L, "Cat" );					// グローバルなテーブル"Cat"をスタックに積む
	lua_getfield( L, lua_gettop( L ), "new" );	// トップに積まれたテーブルのメンバ"new"をスタックに積む
	lua_pushstring( L, "Inu" );					// 名前はInu。猫なのにInu。
	lua_pcall( L, 1, 1, 0 );					// 実行
	int idx_cat = lua_gettop( L );				// Inuのスタック上の位置を取得

	lua_getfield( L, idx_dog, "show" );	// 関数をスタック
	lua_pcall( L, 0, 0, 0 );			// 呼び出し
	
	lua_getfield( L, idx_cat, "show" );	// 関数をスタック
	lua_pcall( L, 0, 0, 0 );			// 呼び出し

    lua_close( L );	// 終了
    return 0;
}

script.lua

-- Dog
Dog = {}
Dog.new = function( name )
	local obj = {}
	obj.name = name
	obj.show = function( self )
		s = string.format( "%s the DOG.", name )
		print( s )
	end
	obj:show()
	return obj
end

-- Cat
Cat = {}
Cat.new = function( name )
	local obj = {}
	obj.name = name
	obj.show = function( self )
		s = string.format( "%s the CAT.", name )
		print( s )
	end
	obj:show()
	return obj
end