Lua
Introduktion till Lua C API
Sök…
Syntax
- lua_State * L = lua_open (); // Skapa ett nytt VM-tillstånd; Lua 5,0
- lua_State * L = luaL_newstate (); // Skapa ett nytt VM-tillstånd; Lua 5.1+
- int luaL_dofile (lua_State * L, const char * filnamn ); // Kör ett lua-skript med det givna filnamnet med det angivna lua_State
- void luaL_openlibs (lua_State * L); // Ladda alla standardbibliotek i det angivna lua_State
- void lua_close (lua_State * L); // Stäng VM-tillstånd och släpp resurser inuti
- void lua_call (lua_State * L, int nargs, int nresults); // Ring luvvärden vid index - (nargs + 1)
Anmärkningar
Lua tillhandahåller också ett korrekt C API till sin virtuella maskin. Till skillnad från själva VM är C API-gränssnittet stackbaserat. Så de flesta av de funktioner som är avsedda att användas med data är att antingen lägga till några saker ovanpå den virtuella stacken eller ta bort dem. Dessutom måste alla API-samtal användas noggrant inom stacken och det är begränsningar.
I allmänhet kan allt tillgängligt på Lua-språk göras med C API. Det finns också en viss tilläggsfunktion som direkt tillgång till internt register, ändra beteende hos standardminnesdelare eller sopor.
Du kan sammanställa tillhandahållna exempel på Lua C API genom att utföra följande på din terminal:
$ gcc -Wall ./example.c -llua -ldl -lm
Skapa Lua Virtual Machine
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
int main(void)
{
/* Start by creating a new VM state */
lua_State *L = luaL_newstate();
/* Load standard Lua libraries: */
luaL_openlibs(L);
/* For older version of Lua use lua_open instead */
lua_State *L = lua_open();
/* Load standard libraries*/
luaopen_base(L);
luaopen_io(L);
luaopen_math(L);
luaopen_string(L);
luaopen_table(L);
/* do stuff with Lua VM. In this case just load and execute a file: */
luaL_dofile(L, "some_input_file.lua");
/* done? Close it then and exit. */
lua_close(L);
return EXIT_SUCCESS;
}
Ringer Lua-funktioner
#include <stdlib.h>
#include <lauxlib.h>
#include <lua.h>
#include <lualib.h>
int main(void)
{
lua_State *lvm_hnd = lua_open();
luaL_openlibs(lvm_hnd);
/* Load a standard Lua function from global table: */
lua_getglobal(lvm_hnd, "print");
/* Push an argument onto Lua C API stack: */
lua_pushstring(lvm_hnd, "Hello C API!");
/* Call Lua function with 1 argument and 0 results: */
lua_call(lvm_hnd, 1, 0);
lua_close(lvm_hnd);
return EXIT_SUCCESS;
}
I exemplet ovan gör vi dessa saker:
- skapa och ställa in Lua VM som visas i det första exemplet
- få och trycka på en Lua-funktion från globala Lua-tabell på virtuell stack
- trycka strängen
"Hello C API"
som ett inmatningsargument på den virtuella stacken - instruera VM att ringa en funktion med ett argument som redan finns på bunten
- stängning och städning
NOTERA:
lua_call()
att lua_call()
dyker upp funktionen och det är argument från stacken som bara lämnar resultatet.
Det skulle också vara säkrare att använda Lua-skyddat samtal - lua_pcall()
istället.
Inbyggd Lua-tolk med anpassad API och Lua-anpassning
Visa hur man bäddar in en lua-tolk i C-kod, exponerar en C-definierad funktion för Lua-skript, utvärderar ett Lua-skript, kallar en C-definierad funktion från Lua och kallar en Lua-definierad funktion från C (värden).
I det här exemplet vill vi att stämningen ska ställas in av ett Lua-manus. Här är mood.lua:
-- Get version information from host
major, minor, build = hostgetversion()
print( "The host version is ", major, minor, build)
print("The Lua interpreter version is ", _VERSION)
-- Define a function for host to call
function mood( b )
-- return a mood conditional on parameter
if (b and major > 0) then
return 'mood-happy'
elseif (major == 0) then
return 'mood-confused'
else
return 'mood-sad'
end
end
Observera, mood()
kallas inte i skriptet. Det är precis definierat för värdapplikationen att ringa. Observera också att skriptet kallar en funktion som kallas hostgetversion()
som inte definieras i skriptet.
Därefter definierar vi en värdapplikation som använder 'mood.lua'. Här är 'hostlua.c':
#include <stdio.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
/*
* define a function that returns version information to lua scripts
*/
static int hostgetversion(lua_State *l)
{
/* Push the return values */
lua_pushnumber(l, 0);
lua_pushnumber(l, 99);
lua_pushnumber(l, 32);
/* Return the count of return values */
return 3;
}
int main (void)
{
lua_State *l = luaL_newstate();
luaL_openlibs(l);
/* register host API for script */
lua_register(l, "hostgetversion", hostgetversion);
/* load script */
luaL_dofile(l, "mood.lua");
/* call mood() provided by script */
lua_getglobal(l, "mood");
lua_pushboolean(l, 1);
lua_call(l, 1, 1);
/* print the mood */
printf("The mood is %s\n", lua_tostring(l, -1));
lua_pop(l, 1);
lua_close(l);
return 0;
}
Och här är utgången:
The host version is 0 99 32
Lua interpreter version is Lua 5.2
The mood is mood-confused
Även efter att vi har sammanställt "hostlua.c", är vi fortfarande fria att ändra "mood.lua" för att ändra resultatet från vårt program!
Tabellmanipulation
För att komma åt eller ändra ett index på ett bord måste du på något sätt placera bordet i bunten.
Låt oss anta, för detta exempel att din tabell är en global variabel med namnet tbl.
Få innehållet i ett visst index:
int getkey_index(lua_State *L)
{
lua_getglobal(L, "tbl"); // this put the table in the stack
lua_pushstring(L, "index"); // push the key to access
lua_gettable(L, -2); // retrieve the corresponding value; eg. tbl["index"]
return 1; // return value to caller
}
Som vi har sett är allt du behöver göra att skjuta bordet i bunten, skjuta indexet och ringa lua_gettable. argumentet -2 innebär att tabellen är det andra elementet från toppen av bunten.
lua_gettable utlöser metametoder. Om du inte vill utlösa metametoder, använd istället lua_rawget. Den använder samma argument.
Ställa in innehållet i ett visst index:
int setkey_index(lua_State *L)
{
// setup the stack
lua_getglobal(L, "tbl");
lua_pushstring(L, "index");
lua_pushstring(L, "value");
// finally assign the value to table; eg. tbl.index = "value"
lua_settable(L, -3);
return 0;
}
Samma borr som att få innehållet. Du måste trycka på bunten, trycka på indexet och sedan trycka in värdet i bunten. efter det ringer du lua_settable. -3-argumentet är tabellens position i bunten. Använd lua_rawset i stället för lua_settable för att undvika att utlösa metametoder. Den använder samma argument.
Överföra innehållet från en tabell till en annan:
int copy_tableindex(lua_State *L)
{
lua_getglobal(L, "tbl1"); // (tbl1)
lua_getglobal(L, "tbl2");// (tbl1)(tbl2)
lua_pushstring(L, "index1");// (tbl1)(tbl2)("index1")
lua_gettable(L, -3);// (tbl1)(tbl2)(tbl1.index1)
lua_pushstring(L, "index2");// (tbl1)(tbl2)(tbl1.index1)("index2")
lua_pushvalue(L, -2); // (tbl1)(tbl2)(tbl1.index1)("index2")(tbl1.index1)
lua_settable(L, -4);// (tbl1)(tbl2)(tbl1.index1)
lua_pop(L, 1);
return 0;
}
Nu sätter vi ihop allt vi lärt oss här. Jag lägger in stackens innehåll på kommentarerna så att du inte går vilse.
Vi lägger båda tabellerna i bunten, trycker in indexet för tabell 1 i bunten och får värdet på tbl1.index1
. Notera -3
argumentet om gettable. Jag tittar på det första bordet (tredje från toppen) och inte det andra. Sedan trycker vi på indexet för det andra bordet, kopierar tbl1.index1
till toppen av bunten och ringer sedan lua_settable
, på det fjärde objektet uppifrån.
För hushållens skull har jag rensat det övre elementet, så att bara de två borden finns kvar vid traven.