从 Cpp 调用 Lua |
|
Luna(参见 SimplerCppBinding)适用于从 Lua 调用 C++ 函数。但如果您希望从 C++ 调用 Lua 函数,则需要将您的 Lua 函数存储在注册表或全局表的一个子表中,然后使用 lua_pcall 从您的 C++ 代码中调用它。此示例使用 Lunar(参见 CppBindingWithLunar),它是 Luna 的一个修订版本,它使此操作变得更加容易。
您可以在 CppBindingWithLunar 页面上找到 lunar.h。
extern "C" {
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
#include "lunar.h"
class Account {
lua_Number m_balance;
public:
Account(double balance=0) : m_balance(balance) { }
void deposit(double amount) { m_balance += amount; }
void withdraw(double amount) { m_balance -= amount; }
double balance(void) { return m_balance; }
~Account() { printf("deleted Account (%p)\n", this); }
// Lua interface
Account(lua_State *L) : m_balance(luaL_checknumber(L, 1)) { }
int deposit (lua_State *L) { deposit (luaL_checknumber(L, 1)); return 0; }
int withdraw(lua_State *L) { withdraw(luaL_checknumber(L, 1)); return 0; }
int balance (lua_State *L) { lua_pushnumber(L, balance()); return 1; }
static const char className[];
static Lunar<Account>::RegType methods[];
};
const char Account::className[] = "Account";
#define method(class, name) {#name, &class::name}
Lunar<Account>::RegType Account::methods[] = {
method(Account, deposit),
method(Account, withdraw),
method(Account, balance),
{0,0}
};
static int report (lua_State *L, int status)
{
if (status) {
const char *msg = lua_tostring(L, -1);
if (msg == NULL) msg = "(error with no message)";
fprintf(stderr, "ERROR: %s\n", msg);
lua_pop(L, 1);
}
return status;
}
static int application (lua_State *L)
{
lua_settop(L, 0);
lua_pushliteral(L, "_TRACEBACK");
lua_gettable(L, LUA_GLOBALSINDEX); // get traceback function
int tb = lua_gettop(L);
Account a;
Account *b = new Account(30);
int A = Lunar<Account>::push(L, &a);
int B = Lunar<Account>::push(L, b, true);
lua_pushliteral(L, "a");
lua_pushvalue(L, A);
lua_settable(L, LUA_GLOBALSINDEX);
lua_pushliteral(L, "b");
lua_pushvalue(L, B);
lua_settable(L, LUA_GLOBALSINDEX);
lua_pushvalue(L, A);
lua_pushnumber(L, 100.00);
report(L, Lunar<Account>::call(L, "deposit", 1, 0, tb) < 0);
lua_pushvalue(L, A);
report(L, Lunar<Account>::call(L, "show", 0, 0, tb) < 0);
lua_pushvalue(L, B);
report(L, Lunar<Account>::call(L, "show", 0, 0, tb) < 0);
lua_pushliteral(L, "main");
lua_gettable(L, LUA_GLOBALSINDEX);
report(L, lua_pcall(L, 0, 0, tb));
return 0;
}
int main (int argc, char *argv[])
{
lua_State *L = lua_open();
luaopen_base(L);
luaopen_table(L);
luaopen_io(L);
luaopen_string(L);
luaopen_math(L);
luaopen_debug(L);
Lunar<Account>::Register(L);
if (argc>1) {
printf("loading '%s'\n", argv[1]);
if (report(L, luaL_loadfile(L, argv[1]) || lua_pcall(L, 0, 0, 0)) == 0) {
printf("running application\n");
if (report(L, lua_cpcall(L, &application, 0)) == 0) {
printf("okay\n");
}
}
}
lua_setgcthreshold(L, 0); // collected garbage
printf("close\n");
lua_close(L);
printf("done\n");
return 0;
}
此代码可以为 Lua 5.0 编译如下
g++ -o test account.cc -L/usr/local/lib -llua -llualib
function printf(...) io.write(string.format(unpack(arg))) end function Account:show() printf("Account balance = $%0.02f\n", self:balance()) end parent = {} function parent:rob(amount) amount = amount or self:balance() self:withdraw(amount) return amount end getmetatable(Account).__index = parent function main() print('a =', a) print('b =', b) print('metatable =', getmetatable(a)) print('Account =', Account) table.foreach(Account, print) a:show() a:deposit(50.30) a:show() a:withdraw(25.10) a:show() debug.debug() end
$ ./test setup.lua
loading 'setup.lua'
running application
Account balance = $100.00
Account balance = $30.00
a = Account (0x22fcb0)
b = Account (0xa041d98)
metatable = table: 0xa044f28
Account = table: 0xa044f28
show function: 0xa0464a0
balance function: 0xa0455f8
withdraw function: 0xa045300
deposit function: 0xa045508
new function: 0xa044fe8
Account balance = $100.00
Account balance = $150.30
Account balance = $125.20
lua_debug> a:show()
Account balance = $125.20
lua_debug> b:show()
Account balance = $30.00
lua_debug> b:deposit(0.01) b:show()
Account balance = $30.01
lua_debug> c = Account(19.99) c:deposit(b:rob()) c:show()
Account balance = $50.00
lua_debug> b:show()
Account balance = $0.00
lua_debug> b = nil
lua_debug> print('c =', c)
c = Account (0xa048cf8)
lua_debug> cont
deleted Account (0x22fcb0)
okay
deleted Account (0xa041d98)
close
deleted Account (0xa048cf8)
done