本稿では動作速度が高速で、非常に移植性が高い組み込み向けのプログラミング言語「Lua」の使い方について紹介します。Lua は、JavaScript や Pascal に似ていることから、とても手に馴染みやすいのが特徴です。自作アプリケーションにちょっとしたスクリプト言語を組み込みたい場合に重宝します。そこで、 Lua のインストールから、簡単な使い方を紹介し、簡単なアプリケーションに組み込んで使うまでの過程を解説します。
本稿では、Lua がどんなプログラミング言語なのかを紹介し、実際に簡単なアプリケーションに組み込んで使ってみるところまでを紹介します。
前回、Lua と C言語を連携する方法を紹介しました。今回は、もう少し踏み込んで使う方法を紹介します。
さて、前回、C言語の関数を Lua に登録する方法を紹介しましたが、これはグローバル関数として関数を登録するものでした。今回は、MyLib.xxx のように特定のオブジェクト(テーブル)内に複数の関数を一度に登録する方法を紹介します。
ここで定義するのは、C言語側に MyLib.c_add() と MyLib.c_sub() という2つの関数を登録します。以下は、Lua 側のスクリプトです。以下のように利用できるものにします。
-- func3.lua
print(MyLib.c_add(3,4))
print(MyLib.c_sub(8,3))
そして、C言語側のソースです。
// file:test.c
#include <stdio.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
/** 自作関数の登録~足し算 */
int c_add(lua_State* L)
{
// 引数を得る
int a1 = lua_tointeger(L, 1);// 第一引数を得る
int a2 = lua_tointeger(L, 2);// 第二引数を得る
// 結果をスタックに戻す
lua_pushinteger(L, a1 + a2);
return 1; // 戻り値の数を返す
}
/** 自作関数の登録~引き算 */
int c_sub(lua_State* L)
{
int a1 = lua_tointeger(L, 1);
int a2 = lua_tointeger(L, 2);
lua_pushinteger(L, a1 - a2);
return 1; // 戻り値の数を返す
}
/** 自作関数のライブラリの関数テーブルを定義 */
static const luaL_Reg MyLibTable[] = {
{"c_add", c_add },
{"c_sub", c_sub },
{NULL,NULL}
};
/** エラーの表示用 */
void show_error(lua_State* L)
{
const char* err = lua_tostring(L, -1);
printf("ERROR: %s\n", err);
}
/** メイン関数 */
int main(int argc, char* argv)
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);// Luaのライブラリを使えるようにする
// Luaに関数群を登録する
luaL_openlib(L, "MyLib", MyLibTable, 0);
// Luaのスクリプトを読み込む
if (luaL_loadfile(L, "func3.lua") || lua_pcall(L,0,0,0)) {
printf("func3.luaが読めませんでした。\n");
show_error(L);
return -1;
}
// 閉じる
lua_close(L);
return 0;
}
関数を一度に登録するには、以下のように、関数テーブルを定義しておいて、luaL_openlib() 関数で登録します。
/** 自作関数のライブラリの関数テーブルを定義 */
static const luaL_Reg MyLibTable[] = {
{"c_add", c_add },
{"c_sub", c_sub },
{NULL,NULL}
};
int main(int argc, char* argv)
{
...
// Luaに関数群を登録する
luaL_openlib(L, "MyLib", MyLibTable, 0);
...
}
次に、変数の値を読み書きしてみます。変数の値の読み書きにも、スタックを利用します。
まずは、変数の取得方法から見ていきます。まずは、値を設定するLuaスクリプトです。
-- func4.lua
account = "kujira"
password = "hoge"
そして、このスクリプトからグローバル変数を取得して表示するC言語のソースです。
// file:test.c
#include <stdio.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
/** メイン関数 */
int main(int argc, char* argv)
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);// Luaのライブラリを使えるようにする
// Luaのスクリプトを読み込む
if (luaL_loadfile(L, "func4.lua") || lua_pcall(L,0,0,0)) {
printf("func4.luaが読めませんでした。\n");
return -1;
}
// グローバル変数の値をスタックに積む
lua_getglobal(L, "account"); // スタックに値を積む
const char* account = lua_tostring(L,-1); // スタックから値を読む
lua_pop(L, 1); // スタックから値を取り除く
//
lua_getglobal(L, "password");
const char* password = lua_tostring(L,-1);
lua_pop(L, 1);
printf("account=%s, password=%s\n", account, password);
// 閉じる
lua_close(L);
return 0;
}
これを見てみると、変数の値を取得するために、変数の値をスタックに積みスタックから値を取り出すという手順を踏むことが分かります。
そして、変数に値をセットする方法ですが、こちらもスタックに値を積んでから値を設定します。
まずは、Lua スクリプトから。これは、C言語側で設定された変数の値を画面に表示するというものです。
-- func5.lua
print(account)
次に、C言語側のソースです。スタックに値を追加しておいて、lua_setglobal() を利用してスタックの値を変数に代入します。
// file:test.c
#include <stdio.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
/** メイン関数 */
int main(int argc, char* argv)
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);// Luaのライブラリを使えるようにする
// 変数に値を設定する
lua_pushstring(L, "kujira");
lua_setglobal(L, "account");
// Luaのスクリプトを読み込む
if (luaL_loadfile(L, "func5.lua") || lua_pcall(L,0,0,0)) {
printf("func5.luaが読めませんでした。\n");
return -1;
}
// 閉じる
lua_close(L);
return 0;
}
Lua を組み込んで使う場合には、C言語側でスタックの操作を行うことにより、さまざまな操作を実現しています。きっと、Lua の内部でも似たような操作を行っているのでしょう。
以上、これまで、Lua の文法から C言語に組み込むまでの方法を簡単に紹介しました。変数の読み書きと関数の取り扱いが分かれば、自作ゲームや自作アプリケーションに Lua を組み込んで活用することができるでしょう。
C言語の実行速度に、Lua の柔軟性を組み合わせることで、開発効率は飛躍的に向上することと思います。本稿が Lua をはじめるきっかけになれば幸いです。