Anuncios

Bienvenidos sean a este post, cual puede ser una mejor explicacion sino una a traves de un ejemplo, para el tema de hoy haremos un interprete primitivo de Lua, veamos el codigo:

#include <stdio.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"

int main(void) 
{
	char buff[256];
	int error;
	lua_State *L = luaL_newstate();
	luaL_openlibs(L);
	
	while(fgets(buff, sizeof(buff), stdin) != NULL)
	{
		error = luaL_loadbuffer(L, buff, strlen(buff), "line") ||
			lua_pcall(0, 0, 0);
		if (error) 
		{
			fprintf(stderr, "%s", lua_tostring(L, -1));
			lua_pop(L, 1);
		}
	}

	lua_close(L);
	return 0;
}
Anuncios

Para el que no conozca C, la primera linea de #include es a la que carga las librerias estandar para manejar los dispositivos basicos de entrada/salida (I/O), en este caso el teclado (entrada) y el monitor (salida), luego viene la libreria lua.h define las funciones basicos provistas por Lua, incluye funciones para crear un nuevo entorno de Lua para invocar funciones de Lua, por ejemplo lua_pcall, para leer y escribir variables globales en el entorno de Lua para nuevas funciones para ser llamadas por Lua, todo lo definido en lua.h tiene un prefijo lua_.

Anuncios

La libreria lauxlib.h define las funciones provistas por la libreria auxiliar (auxlib), todas sus definiciones comienzan con luaL_ (p.e. luaL_loadbuffer), la libreria auxiliar usa la API basica provista por nuestra libreria anterior (lua.h) para proveer un nivel mas alto de abstraccion, todas las librerias estandar de Lua usan el auxlib, mientras la API basica se esfuerza por fluidez y la perpendicularidad, en cambio auxlib se esfuerza por la practicidad para tareas comunes, por supuesto es mas facil para tu programa crear otras abstracciones que necesita.

Anuncios
Nota: Recuerda que la auxlib no tiene acceso a los internos de Lua.
Anuncios

Todo el trabajo se realiza a traves de la API basica oficial. La libreria de Lua no define variables globales en absoluto, mantiene todos su estado en la estructura dinamica lua_State y un apuntador a esta estructura es pasado como un argumento para todas las funciones dentro de Lua, esta implementacion hace a Lua reentrante y lista para ser usada en un codigo de multiprocesos, la funcion luaL_newstate crea un nuevo entorno, o estado, cuando esta funcion crea un entorno nuevo, esta no tiene funciones predefinidas, ni siquiera a print.

Anuncios

Para mantener a Lua pequeño, todas las librerias estandar son provistas como paquetes separados, asi que no tienes que usarlas si no las necesitas, la libreria lualib.h define funciones para abrir las librerias, la funcion luaL_openlibs abre todas las librerias estandar.

Anuncios

Despues de crear un estado y completarlo con las librerias estandar, es tiempo para interpretar la entrada del usuario, por cada linea que el usuario entra el programa primero llama a luaL_loadbuffer para compilar el codigo, si no hay errores la llamada devuelve cero y empuja el chunk resultante en la pila, luego el programa llama a lua_pcall, la cual saca el chunk de las pila y lo ejecuta en modo protegido, al igual que luaL_loadbuffer lua_pcall devuelve cero si no hay errores, en caso de error ambas funciones envian un mensaje de error en la pila, conseguimos este mensaje por medio de lua_tostring y despues de mostrarlo lo quitamos de la pila con lua_pop.

Recuerden que en caso de error este programa simplemente muestra el mensaje de error al stream estandar de error (stderr), manejar errores reales puede ser complejo en C y como lo hace depende de la naturaleza de tu aplicacion, el nucleo de Lua nunca escribe directamente a los streams y señala errores devolviendo codigo de error y mensaje de error donde cada aplicacion puede manejar estos mensajes en una manera mas apropiada para sus necesidades, para simplificar nuestras dicusiones asumiremos por ahora un manipulador mas simple de errores como el que veremos a continuacion, el cual imprime un mensaje de error, cierra el estado de Lua y sale por completo de la aplicacion:

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>

void error (luaL_State *L, const char *fmt, ...)
{
	va_list argp;
	va_start(argp, fmt);
	vfprint(stderr, fmt, argp);
	va_end(argp);
	lua_close(L);
	exit(EXIT_FAILURE);
}
Anuncios

En proximos post hablaremos mas a detalle sobre la manipulacion de errores en el codigo de aplicacion.

Anuncios

Como se puede compilar Lua tanto con codigo de C como con codigo de C++, lua.h no incluye este tipico codigo de ajuste que esta presente en otras librerias de C:

#ifdef __cplusplus
extern "C" {
#endif
	...
#ifdef __cplusplus
}
#endif
Anuncios

Si has compilado Lua como codigo de C (lo mas habitual) y la estas usando en C++, se puede incluir lua.hpp en lugar de lua.h, su definicion es como sigue:

extern "C" {
#include "lua.h"
}
Anuncios

En resumen, hoy hemos visto un primer ejemplo de la API de C, cuales son las librerias necesarias para su implementacion, una breve explicacion de ellas, como se implementan, un breve concepto de errores, como manejarlos, y como usarlo en C o C++, espero les haya sido util sigueme en 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