Anuncios

Bienvenidos sean a este post, hoy veremos como referenciar elementos en la pila.

Anuncios

Para esta accion la API usa indices, el primer elemento empujado de la pila tiene el numero 1, el siguiente tendra el numero 2 y asi sucesivamente hasta la parte superior, tambien podemos acceder a elementos usando la parte superior de la pila para nuestra referencia usando indices negativos, en este caso -1 refiere al elemento en la parte superior, es decir el ultimo elemento empujado, -2 sera el elemento previo a este y asi sucesivamente, por ejemplo la siguiente llamada:

lua_tostring(L, -1);
Anuncios

Devuelve el valor en la parte superior de la pila como una cadena, como veremos hay varias ocasiones que es natural indexar la pila desde el fondo (es decir con indices positivos) y en otras ocasiones sera mejor utilizar indices negativos, para chequear si un elemento tiene un tipo especifico la API ofrece una familia de funciones lua_is*, el asterisco es cualquier tipo de Lua, asi que tenemos:

  • lua_isnumber
  • lua_isstring
  • lua_istable
Anuncios

Y otros tipos, todas estas funciones tienen el mismo prototipo:

int lua_is* (lua_State *L, int indice);
Anuncios

En realidad lua_isnumber no chequea si el valor tiene ese tipo especifico pero si el valor puede ser convertido a ese tipo, lua_isstring es similar, por ejemplo cualquier numero satisface a lua_isstring, hay tambien una funcion lua_type la cual devuelve el tipo de un elemento en la pila, cada tipo es representado por una constante definido en la libreria lua.h:

  • LUA_TNIL
  • LUA_TBOOLEAN
  • LUA_TNUMBER
  • LUA_TSTRING
  • LUA_TTABLE
  • LUA_TTHREAD
  • LUA_TUSERDATA
  • LUA_TFUNCTION
Anuncios

Esta funcion es principalmente utilizada en conjunto con una declaracion de switch y tambien es util cuando necesitamos chequear por cadenas y numeros sin coacciones, para conseguir un valor de la pila tenemos las funciones lua_to*:

int		lua_toboolean	(lua_State *L, int indice);
lua_Number	lua_tonumber	(lua_State *L, int indice);
lua_Integer	lua_tointeger	(lua_State *L, int indice);
const char	*lua_tolstring	(lua_State *L, int indice, size_t *len);
size_t		lua_objlen	(lua_State *L, int indice);
Anuncios

Esta bien llamarlo incluso cuando el elemento informado no tiene el tipo correcto, en este caso cuatro de las cinco funciones (excepto lua_tolstring) devuelven cero y las otras funciones devuelven null, y si bien el cero no es muy util sin embargo ANSI C nos provee con un valor numerico invalido que podemos usar para señalar errores, para las otras funciones usualmente no necesitamos usar la funcion lua_is* correspondiente solo llamando a lua_to* y luego chequea si el resultado no es null.

Anuncios

La funcion lua_tolstring devuelve un puntero a una copia interna de la cadena y almacena la longitud de la cadena en la posicion dada por len, la copia interna no se puede modificar (hay un const para recordartelo), lo cual asegura a Lua que este puntero es valido tanto como el valor de la cadena correspondiente que esta en la pila, cuando una funcion de C llamada por Lua retorna, Lua limpia su pila, por lo tanto nunca debes almacenar punteros a cadenas de Lua por fuera de la funcion que las contiene, cualquier cadena que devuelve lua_tolstring siempre tiene un cero extra a su final pero puede contener otros ceros dentro de ella, el tamaño devuelto a traves de su tercer argumento, len, es la verdadera longitud de la cadena, y en particular asumimos que el valor esta en la parte superior de la pila como una cadena, las siguientes afirmaciones son siempre validas:

size_t l;
const char *s = lua_tolstring(L,-1, %l); /* cualquier cadena de Lua */
assert(s[l] == '\0');
assert(strlen(s) <= l);
Anuncios

Puedes llamar a lua_tolstring con null como su tercer argumento si no necesitas su longitud, mejor aun puedes usar la macro lua_tostring la cual simplemente llama a lua_tolstring con el tercer argumento con el valor null, la funcion lua_objlen devuelve la “longitud” de un objeto, para cadenas y tablas, y este valor es el resultado del operador “#”, esta funcion tambien nos permite conseguir el tamaño de todo el dato del usuario, mas adelante hablaremos sobre la data del usuario (userdata).

Anuncios

Para ilustrar el uso de estas funciones veamos el siguiente codigo:

static void pilaVolcado(lua_State *L)
{
	int i;
	int arriba = lua_gettop(L);
	for (i = 1; i <= arriba; i++)
	{
		int t = lua_type(L, i);
		switch(t)
		{
			case LUA_TOSTRING:
			{
			printf("'%s'", lua_tostring(L, i));
			break;
			}
			case LUA_TBOOLEAN:
			{
			printf(lua_toboolena(L, i) ? "true" : "false");
			break;
			}
			case LUA_TNUMBER:
			{
			printf("%g", lua_tonumer(L, i);
			break;
			}
			default:
			printf("%s", lua_typename(L, i));
			break;
			}
		}
		printf("   ");
	}
	printf("\n");
}
Anuncios

Este codigo nos mostrara un volcado completo de la pila, esta funcion atraviesa la pila desde el fondo hasta la parte superior imprimiendo cada elemento de acuerdo a su tipo, imprime las cadenas entre comillas, para los numeros usa el formato %g, para los de tipo booleano usa true o false, y para el resto de los valores (tablas, funciones, etc) imprime solo el tipo, lua_typename convierte un codigo de tipo en un nombre de tipo, este ultimo paso es gracias al default que lo hara si no hubo coincidencia con alguno de los casos anteriores.

Anuncios

En resumen, hoy hemos visto como se busca en la pila, su forma de trabajo, los valores de los indices, la explicacion del signo de los mismos, las funciones que disponemos para trabajar en la pila, espero les haya sido util sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios

Tengo un Patreon donde podes acceder de manera exclusiva a material para este blog antes de ser publicado, sigue los pasos del link para saber como.

Tambien podes donar

Es para mantenimiento del sitio, gracias!

$1.00