Estoy implementando un intérprete lisp en C, lo he implementado junto con algunas primitivas como cons, car, cdr, eq, aritmética básica.
Justo antes de comenzar a implementar define y lambda, se me ocurrió que necesitaba implementar un entorno. No estoy seguro si podría implementarlo en LISP.
Mi intención es implementar una cantidad mínima de ceceo para poder escribir la extensión del lenguaje en sí mismo. No estoy seguro de cuánto es mínimo. ¿Implementar FFI calificaría como mínimo?
La respuesta a tu pregunta depende del significado que le des a la palabra “mínimo”.
Dada su pregunta, y asumiendo que no desea hacer una implementación que compita con las excelentes implementaciones actuales de Common Lisp y Schema, mi hipótesis es que con "mínimo" pretende: Turing completo , que es capaz de expresar cualquier cálculo expresable en un lenguaje de programación de propósito general.
Con esta suposición, debe implementar otras tres cosas:
cond )lambda )labels o defun )Entonces, su intérprete debería poder evaluar los formularios. Esto debería ser suficiente para tener un lenguaje equivalente al LISP inicial, que permita expresar en el lenguaje cualquier función computable.
En primer lugar, está hablando de escribir primero un intérprete LISP. Tiene muchas opciones que tomar en lo que respecta al alcance, LISP1 frente a LISP2, ya que estas preguntas alteran el núcleo de la implementación. Un intérprete es un programa de propósito general que lee y evalúa código. Puede admitir abstracciones, pero no se extenderá haciendo más cosas nativas.
Si está interesado en esas cosas, quizás pueda hacer un compilador en su lugar. P.ej. hay muchos subconjuntos similares a Sceme que se compilan en código C o Java, pero puede crear su propia máquina virtual. Por lo tanto, puede compilarse a sí mismo para ejecutarse en su propia máquina de destino (alojamiento propio) si todos los formularios y procedimientos que utiliza se han implementado utilizando las primitivas admitidas por el compilador.
Hacer un compilador tonto no es muy diferente de hacer un intérprete. Eso está muy claro si ha visto los videos SICP (10A se trata de compilación, 7A-B se trata de intérpretes)
El entorno puede ser una cadena de pares como en un intérprete LISP. Sería difícil implementar el entorno en sí mismo en LISP sin convertirlo en un lenguaje Lisp muy difícil de usar (a menos que esté compilado). Sin embargo, puede usar las estructuras de datos de LISP y las primitivas del código C.
Hacer un FFI es una forma rápida de darle a su idioma muchas funciones. Resuelve el problema del huevo y la gallina usando el trabajo de otras personas dentro de su idioma. In fusiona la parte superior (primitivas y sintaxis) y la capa inferior (un tiempo de ejecución) de su sistema. Es el primitivo definitivo y puede pensar en él como una llamada al sistema o un bus de mensajes para el tiempo de ejecución.
Recomiendo encarecidamente leer el libro de Queinnec: Lisp In Small Pieces . Es un libro dedicado por completo a responder a su pregunta, y explica en detalle las muchas compensaciones y los aspectos internos de las implementaciones y definiciones de Lisp, al brindar muchos ejemplos explicados de intérpretes y compiladores de Lisp.
También podría considerar usar libffi . Te podría interesar el interior de las implementaciones Bigloo & Hop de M.Serrano. Incluso puede mirar dentro de mi lenguaje similar a MELT ceceo para personalizar el compilador GCC .
También necesita obtener más información sobre la recolección de basura (puede leer el manual de GC ). Puede usar el conservador Garbage Collector de Boehm (o algo más, por ejemplo, mi Qish o MPS ) o escribir su propio GC.
Es posible que desee obtener más información sobre Chicken , Scheme 48 , Guile y leer sus documentos y mirar dentro de su código.
Véase también el blog de J.Pitrat : no se trata de Lisp (sino de arrancar una IA fuerte) y tiene varias entradas fascinantes relacionadas con el arranque.