jueves, 10 de diciembre de 2009

Haciendo un intérprete de LISP (VI)

El resultado de una evaluación era o bien un valor muy fácilmente calculable (literal, error, nombre) o bien una aplicación de una función (nativa o lambda) a unos argumentos. En este post veremos cómo realizar una función nativa.

La interfaz de la función nativa

Si recordamos del último post, había tres cosas que pasábamos con la aplicación de la función nativa: El montículo por si queríamos reservar más celdas; la lista de argumentos y el entorno por si necesitamos calcular el valor de un nombre. Así que la interfaz de una función nativa debe ser:

typedef Cell& (*NATIVE)(Heap& heap, Cell& args, Cell& envir);

Es importante recordar aquí que los argumentos no están evaluados. Se pasaban directamente (ver en el último post). Será un detalle a tener en cuenta.

Una función para sumar enteros

Como uno de los tipos de literales que tenemos son los enteros, hagamos una pequeña función nativa que sume enteros. Sabemos empezarla con la interfaz de arriba.

Cell& FOL_Add(Heap& heap, Cell& args, Cell& envir)
{

Luego hemos de pensar en evaluar los argumentos. Si son literales no hay problemas (se evalúan a ellos mismos), pero si tenemos dos sumas anidadas hay que evaluar. Así pues necesitamos dos cosas: los argumentos y el resultado parcial de la suma.

 Cell* qa=&args;
INTEGER result=0;

Lo que vamos a hacer es ir recorriendo la lista de argumentos sin evaluar (qa) e ir añadiendo los resultados de la evaluación de los argumentos a result. Como una lista es una cadena de pares, el código sería así:

 while(qa->IsPair())
{
result+=heap.Evaluate(qa->GetHead(), envir).GetInteger();
qa=&qa->GetTail();
}

Finalmente, el resultado es un entero pero lo tenemos en una variable, no en una celda. Hay que crear la celda y retornarla. Usamos el montículo para eso.

 return heap.CreateInteger(result);
}

Con lo que sólo faltaría probar la función nativa.

El bucle de lectura-evaluación-impresión

Un intérprete LISP hace tres cosas en ciclo y de forma indefinida. Primero, lee una expresión S. Luego, la evalúa obteniendo un resultado. Finalmente, la imprime. Hasta ahora sólo hemos hablado de la evaluación. La lectura y la impresión son asuntos menores.

Otro aspecto importante es que no podemos usar la función nativa directamente. Hay que darle primero un nombre. Para eso necesitamos manipular entornos. Tampoco es excesivamente difícil y lo veremos algo más adelante. Si le damos el nombre "add" a la función nativa de arriba, interactuamos con el intérprete de la siguiente manera:

> (add 13 72)

85

>

En los siguientes posts hablaré de qué es una celda CT_LAMBDA, cómo generarlas y cómo usarlas. Esto nos deparará algunas interesantes sorpresas como las clausuras léxicas.

0 comentarios:

Publicar un comentario