Lua
Wprowadzenie do Lua C. API
Szukaj…
Składnia
- lua_State * L = lua_open (); // Utwórz nowy stan maszyny wirtualnej; Lua 5.0
- lua_State * L = luaL_newstate (); // Utwórz nowy stan maszyny wirtualnej; Lua 5.1+
- int luaL_dofile (lua_State * L, const char * nazwa pliku ); // Uruchom skrypt lua z podaną nazwą pliku, używając określonego stanu lua_State
- void luaL_openlibs (lua_State * L); // Załaduj wszystkie standardowe biblioteki do określonej lua_State
- void lua_close (lua_State * L); // Zamknij stan maszyny wirtualnej i zwolnij wszystkie zasoby w niej
- void lua_call (lua_State * L, int nargs, int nresults); // Wywołaj luavalue na indeksie - (nargs + 1)
Uwagi
Lua również zapewnia właściwy interfejs API języka C do swojej maszyny wirtualnej. W przeciwieństwie do samej VM, interfejs API C jest oparty na stosie. Tak więc większość funkcji przeznaczonych do użycia z danymi to albo dodawanie elementów na stosie wirtualnym, albo usuwanie z niego. Ponadto wszystkie wywołania interfejsu API muszą być używane ostrożnie w ramach stosu i jego ograniczeń.
Ogólnie rzecz biorąc, wszystko, co jest dostępne w języku Lua, można wykonać za pomocą interfejsu API C. Ponadto istnieje kilka dodatkowych funkcji, takich jak bezpośredni dostęp do rejestru wewnętrznego, zmiana zachowania standardowego przydziału pamięci lub modułu wyrzucania elementów bezużytecznych.
Możesz skompilować podane przykłady interfejsu API Lua C, wykonując następujące czynności na swoim terminalu:
$ gcc -Wall ./example.c -llua -ldl -lm
Tworzenie maszyny wirtualnej Lua
#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;
}
Wywoływanie funkcji Lua
#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;
}
W powyższym przykładzie robimy te rzeczy:
- tworzenie i konfigurowanie Lua VM, jak pokazano na pierwszym przykładzie
- pobieranie i wypychanie funkcji Lua z globalnej tabeli Lua na wirtualny stos
- wypychając ciąg
"Hello C API"
jako argument wejściowy na wirtualny stos - instruując VM, aby wywołała funkcję z jednym argumentem, który jest już na stosie
- zamykanie i sprzątanie
UWAGA:
Pamiętaj, że lua_call()
wyskakuje z funkcji i jej argumenty ze stosu pozostawiają tylko wynik.
Ponadto bezpieczniej byłoby używać zamiast tego chronionego wywołania Lua - lua_pcall()
.
Wbudowany interpreter Lua z niestandardowym interfejsem API i dostosowywaniem Lua
Zademonstruj, jak osadzić interpreter lua w kodzie C, wystawić funkcję zdefiniowaną w C na skrypt Lua, ocenić skrypt Lua, wywołać funkcję zdefiniowaną w C z Lua i wywołać funkcję zdefiniowaną w Lua z C (hosta).
W tym przykładzie chcemy, aby nastrój był ustawiony przez skrypt Lua. Oto 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
Zauważ, że mood()
nie jest wywoływany w skrypcie. Zostało właśnie zdefiniowane, aby aplikacja hosta mogła zadzwonić. Zauważ też, że skrypt wywołuje funkcję o nazwie hostgetversion()
która nie jest zdefiniowana w skrypcie.
Następnie definiujemy aplikację hosta korzystającą z „mood.lua”. Oto plik „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;
}
A oto wynik:
The host version is 0 99 32
Lua interpreter version is Lua 5.2
The mood is mood-confused
Nawet po skompilowaniu pliku „hostlua.c” nadal możemy modyfikować plik „mood.lua”, aby zmienić dane wyjściowe naszego programu!
Manipulacje przy stole
Aby uzyskać dostęp lub zmienić indeks tabeli, musisz jakoś umieścić tabelę na stosie.
Załóżmy, dla tych przykładów, że twoja tabela jest zmienną globalną o nazwie tbl.
Uzyskiwanie zawartości o określonym indeksie:
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
}
Jak widzieliśmy, wszystko, co musisz zrobić, to wepchnąć stół do stosu, wcisnąć indeks i wywołać lua_gettable. argument -2 oznacza, że tabela jest drugim elementem z góry stosu.
lua_gettable wyzwala metody. Jeśli nie chcesz uruchamiać metod, użyj zamiast tego lua_rawget. Używa tych samych argumentów.
Ustawienie zawartości pod określonym indeksem:
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;
}
To samo ćwiczenie co pobieranie treści. Musisz wcisnąć stos, wcisnąć indeks, a następnie wcisnąć wartość do stosu. po tym wywołujesz lua_settable. argument -3 oznacza pozycję tabeli na stosie. Aby uniknąć wyzwalania metod, użyj lua_rawset zamiast lua_settable. Używa tych samych argumentów.
Przenoszenie zawartości z tabeli do innej:
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;
}
Teraz łączymy wszystko, czego się tutaj nauczyliśmy. Umieszczam zawartość stosu w komentarzach, abyś się nie zgubił.
Umieszczamy obie tabele w stosie, tbl1.index1
indeks tabeli 1 do stosu i otrzymujemy wartość z tbl1.index1
. Zwróć uwagę na argument -3
w gettable. Patrzę na pierwszy stół (trzeci od góry), a nie na drugi. Następnie tbl1.index1
indeks drugiej tabeli, kopiujemy tbl1.index1
na górę stosu, a następnie wywołujemy lua_settable
na czwartym elemencie z góry.
Dla porządku, wyczyściłem górny element, więc tylko dwa stoły pozostają na stosie.