CアプリにLuaを埋める

LuaのCモジュールを作るのではなく、CからLuaを使うパターン。

まず、luaの新しいステートを作る。
そのステートで設定ファイル(luaスクリプト)を実行してluaのグローバル値を作る。
最後にluaのスタックを通して、luaのグローバル値を得るという段取りになる。



以前は、JSON形式で3Dのモデル情報を保存するのを画策していたがこっちの方が
luaの文法丸ごと使ってOKなのでよいかもしれぬ。

main.cpp

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <lua.hpp> // lua.hだとリンク時にエラーになる
#include <lauxlib.h>
#include <lualib.h>

class LuaState
{
  lua_State *L_;
public:
  LuaState()
  {
    // 新しいLuaステート
    L_=luaL_newstate();
    // Luaに標準関数をオープンする
    luaL_openlibs(L_);
  }

  ~LuaState()
  {
    // Luaステートを終了
    lua_close(L_);
  }

  void error()
  {
    fprintf(stderr, "%s\n", lua_tostring(L_, -1));
    exit(EXIT_FAILURE);
  }

  void error(const char *fmt, ...)
  {
    va_list argp;
    va_start(argp, fmt);
    vfprintf(stderr, fmt, argp);
    va_end(argp);
    exit(EXIT_FAILURE);
  }

  void dofile(const char *path)
  {
    // Luaスクリプト(チャンク)
    // をコンパイルしてスタックのトップに関数として積む
    if(luaL_loadfile(L_, path)){
      error();
    }
    // スタックトップの関数を保護モード(エラーが発生したら
    // エラーコードを返す)で実行する。
    if(lua_pcall(L_, 0, 0, 0)){
      error();
    }
  }

  // Luaのグローバル変数をintとして取得する
  int getInt(const char *key)
  {
    // スタックの最初の高さ
    int top=lua_gettop(L_);
    // グローバル変数をスタックに乗せる
    lua_getglobal(L_, key);
    // Luaの型チェック
    if(!lua_isnumber(L_, -1)){
      error("%s is not number.\n", key);
    }
    // スタックトップ(-1)の値をCのintとして取得
    int num=lua_tointeger(L_, -1);
    // スタックを元に戻す
    lua_settop(L_, top);

    return num;
  }

  // Luaのグローバル変数をstringとして取得する
  std::string getString(const char *key)
  {
    // スタックの最初の高さ
    int top=lua_gettop(L_);
    // グローバル変数をスタックに乗せる
    lua_getglobal(L_, key);
    // Luaの型チェック
    if(!lua_isstring(L_, -1)){
      error("%s is not string.\n", key);
    }
    // スタックトップ(-1)の値をCのintとして取得
    const char *str=lua_tostring(L_, -1);
    // スタックを元に戻す
    lua_settop(L_, top);

    return str;
  }
};

int main(int argc, char **argv)
{
  if(argc<2){
    fprintf(stderr, "usage: %s {lua script}\n", argv[0]);
    return 1;
  }

  LuaState lua;

  // スクリプト実行
  lua.dofile(argv[1]);

  // グローバル変数の値を取得
  std::cout << "num: " << lua.getInt("num") << std::endl;
  std::cout << "name: " << lua.getString("name") << std::endl;

  return 0;
}

config.lua

num=150
name="ほげ"

build, execute

$ g++ main.cpp -llua
$ ./a.out config.lua