Imbutindo Common Lisp (ECL) em C

Hoje comecei a brincar com ECL (Embeddable Common Lisp). Como o nome diz, é possível embarcá-lo [1] em um programa escrito em C. Na verdade, ele é mais que isso; é possível também rodar o comando ecl para ter um interpretador de Common Lisp ou usá-lo como um compilador de Common Lisp para C/binário.

Esses dois últimos usos são relativamente simples e estão bem documentados. Meu interesse mesmo era como embarcar em um programa escrito em C e acessar funções definidas em C a partir do programa em Lisp e vice versa. Infelizmente, essa parte consta com um “TBD” no manual, que eu imagino que signifique To Be Done, a ser feito. Mesmo assim, consegui achar algumas informações na mailing list e em outros sites e fazer um programa básico.

Começamos incluindo a biblioteca necessária e com as funções responsáveis por inicializar e finalizar o processo.

#include <ecl/ecl.h>
cl_boot(int argc, char** argv);
cl_shutdown();

Além de carregar o cabeçalho ecl/ecl.h, é necessário também passar o argumento -lecl para o GCC quando for compilar, já que é necessário linkar à biblioteca. Não tenho certeza de para que servem os dois argumentos de cl_boot, no momento tenho passado os próprios argc e argv da função main.

Para o uso efetivo do Common Lisp dentro do programa em C, duas funções são importantes: cl_def_c_function e cl_safe_eval. A primeira permite que uma função definida no código em C possa ser utilizada no interpretador Lisp, já a segunda executa uma expressão como se ela tivesse sido digitada no interpretador.

Os argumentos passados para cl_def_c_function são o símbolo pelo qual a função será acessada, o nome da função definida em C e o número de argumentos da função. Não me pergunte como se faz, por exemplo se você quiser definir os argumentos da função usando os modificadores existentes em Lisp – &key, &rest etc.

Para a outra função, cl_safe_eval, o primeiro argumento é uma string (um char*, na verdade) que será convertido em uma expressão Lisp (usando a função c_string_to_object), o segundo e o terceiro argumento não sei o que são, tenho usado Cnil e OBJNULL.

Eu não introduzi a função c_string_to_object que falei no parágrafo anterior antes, mas seu uso é bastante simples: ela aceita um char* como argumento e retorna um cl_object.

O código abaixo deve dar uma idéia de geral de como usar as funções. Os dois códigos comentados mostram como definir uma função que tenha argumentos e o segundo mostra como chamar o read-eval-print loop a partir do programa em C. Basta descomentar a definição de lisp_code e passá-la para um cl_safe_eval. Good hacking!

/* lembre-se de compilar com gcc -ecl arquivo.c */
#include <stdio.h>

#include <ecl/ecl.h>

static cl_object hello(void)/*(cl_object arg1, cl_object arg2)*/
{
	printf("Hello World!\n");
	return Cnil;
}

int main(int argc, char *argv[])
{
	/*const char *lisp_code = "(si:top-level)";*/
	const char *code1 = "(format t \"Hello World!~%\")";
	const char *code2 = "(hello)";
	cl_object output;

	cl_boot(argc, argv);
	si_select_package(make_simple_base_string("CL-USER"));
	cl_def_c_function(c_string_to_object("HELLO"),
			  hello, 0);
	
	output = cl_safe_eval(c_string_to_object(code1),
			      Cnil, OBJNULL);
	output = cl_safe_eval(c_string_to_object(code2),
			      Cnil, OBJNULL);
	cl_shutdown();
	return (0);
}

[1] Não acho que essa seja a melhor tradução, mas enfim.

Publicidade

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s

%d blogueiros gostam disto: