備忘録

プログラムやゲーム関連に関すること

【Lua】スタック

スタックを把握する為に以下ソースコードをメモする。
詳しいことは、以下参考URLから参照。

参考: その2 Luaスクリプト事始め

#include <iostream>
#include <lua.hpp>

// スタック確認
void printStack(lua_State* L)
{
	// スタック数を取得
	const int num = lua_gettop(L);
	if (num == 0)
	{
		printf("No stack.\n");
		return;
	}

	for (int i = num; i >= 1; --i)
	{
		// インデックス番号(昇順・降順)
		printf("%03d(%04d):", i, -num + i - 1);

		// 型確認
		int type = lua_type(L, i);
		switch (type)
		{
		case LUA_TNIL: printf("NIL\n"); break;
		case LUA_TBOOLEAN: printf("BOOLEAN %s\n", lua_toboolean(L, i) ? "true" : "false"); break;
		case LUA_TLIGHTUSERDATA: printf("LIGHTUSERDATA\n"); break;
		case LUA_TNUMBER: printf("NUMBER %f\n", lua_tonumber(L, i)); break;
		case LUA_TSTRING: printf("STRING %s\n", lua_tostring(L, i)); break;
		case LUA_TTABLE: printf("TABLE\n"); break;
		case LUA_TFUNCTION: printf("FUNCTION\n"); break;
		case LUA_TUSERDATA: printf("USERDATA\n"); break;
		case LUA_TTHREAD: printf("THREAD\n"); break;
		}
	}

	printf("------------------------------\n\n");
}

// スタックを積んで表示する
void testPrintStack()
{
	lua_State *L = luaL_newstate();

	// スタックする
	lua_pushboolean(L, 1);
	lua_pushnumber(L, 100.0);
	lua_pushstring(L, "test");

	// スタックを表示する
	printStack(L);

	lua_close(L);
}

// Luaコードを読み込んで表示する
void testInit()
{
	lua_State* L = luaL_newstate();

	// Luaファイルを開いて読み込み(失敗は0以外を返却)
	// ファイルが存在しないかLuaコードに間違いがある場合は失敗する
	if (luaL_dofile(L, "init.lua"))
	{
		// スタックからエラー文字列を表示
		printf("%s\n", lua_tostring(L, lua_gettop(L)));
		lua_close(L);
		return;
	}

	// Luaステートに読み込まれたグローバル変数をスタックする
	// スタックできない場合は、NILがスタックされる
	lua_getglobal(L, "windowWidth");
	lua_getglobal(L, "windowHeight");
	lua_getglobal(L, "windowName");

	// スタックを表示する
	printStack(L);

	// スタックを削除
	int num = lua_gettop(L);
	lua_pop(L, num);
	printStack(L); // No Stack.

	lua_close(L);
}

// C言語からLuaの関数を呼ぶ
void testLuaFunc()
{
	lua_State* L = luaL_newstate();

	// Luaファイルを読み込み
	if (luaL_dofile(L, "func.lua"))
	{
		printf("%s\n", lua_tostring(L, lua_gettop(L)));
		lua_close(L);
		return;
	}

	// Luaステート内にあるcalc関数をスタックする
	lua_getglobal(L, "calc");

	// 引数をスタックする
	lua_pushnumber(L, 100);
	lua_pushnumber(L, 200);

	// 現時点でのスタックを確認する
	printStack(L);

	// Lua関数を実行して関数をスタックからポップさせ、
	// 複数な戻り値をスタックさせる
	// int lua_pcall(arg1, arg2, arg3, arg4) 引数は以下を参照
	// arg1: 関数が登録されているLuaステート
	// arg2: 関数の引数の数
	// arg3: 関数の戻り値の数
	// arg4: 独自のエラーメッセージを取り扱う時に使用、デフォルトは0
	if (lua_pcall(L, 2, 4, 0))
	{
		printf("%s\n", lua_tostring(L, lua_gettop(L)));
		lua_close(L);
		return;
	}

	// 実行後のスタックを確認する
	printStack(L);

	// 複数な戻り値を取得する
	float add = (float)lua_tonumber(L, 1);
	float sub = (float)lua_tonumber(L, 2);
	float mult = (float)lua_tonumber(L, 3);
	float dev = (float)lua_tonumber(L, 4);

	// 取得した値を表示する
	printf("add:%f sub:%f mult:%f dev:%f\n\n", add, sub, mult, dev);

	// スタックを削除する
	int num = lua_gettop(L);
	lua_pop(L, num);

	lua_close(L);
}

int main(int argc, char* argv[])
{
	//testPrintStack();
	//testInit();
	testLuaFunc();

	return 0;
}


以下は、読み込ませるLuaのコードとなる。
ファイルの拡張子は別に付けなくても可能である。

init.lua

windowWidth = 640
windowHeight = 480
windowName = "init"

func.lua

--複数の値を返却する
function calc(val1, val2)
	return val1 + val2, val1 - val2, val1 * val2, val1 / val2
end