He oído hablar de la idea de iniciar un lenguaje, es decir, escribir un compilador / intérprete para el lenguaje en sí. Me preguntaba cómo se podría lograr esto y miré un poco a mi alrededor, y vi a alguien decir que solo podía hacerlo cualquiera
- escribir un compilador inicial en un idioma diferente.
- codificar manualmente un compilador inicial en Ensamblador, que parece un caso especial de la primera
Para mí, ninguno de estos parece estar realmente iniciando un lenguaje en el sentido de que ambos requieren apoyo externo. ¿Existe alguna forma de escribir un compilador en su propio idioma?
Respuestas:
Debe tener algún lenguaje existente para escribir su nuevo compilador. Si estuviera escribiendo un compilador nuevo, digamos, C ++, simplemente lo escribiría en C ++ y lo compilaría primero con un compilador existente. Por otro lado, si estuviera creando un compilador para un nuevo lenguaje, llamémoslo Yazzleof, primero tendría que escribir el nuevo compilador en otro lenguaje. Generalmente, este sería otro lenguaje de programación, pero no tiene por qué serlo. Puede ser ensamblado o, si es necesario, código máquina.
Si fuera a iniciar un compilador para Yazzleof, generalmente no escribiría un compilador para el lenguaje completo inicialmente. En su lugar, escribiría un compilador para Yazzle-lite, el subconjunto más pequeño posible de Yazzleof (bueno, al menos un subconjunto bastante pequeño ). Luego, en Yazzle-lite, escribiría un compilador para el lenguaje completo. (Obviamente, esto puede ocurrir de forma iterativa en lugar de en un salto.) Debido a que Yazzle-lite es un subconjunto adecuado de Yazzleof, ahora tiene un compilador que puede compilarse a sí mismo.
Hay un artículo realmente bueno sobre cómo arrancar un compilador desde el nivel más bajo posible (que en una máquina moderna es básicamente un editor hexadecimal), titulado Bootstrapping a simple compiler from nothing . Se puede encontrar en https://web.archive.org/web/20061108010907/http://www.rano.org/bcompiler.html .
fuente
La explicación que ha leído es correcta. Hay una discusión sobre esto en Compiladores: Principios, Técnicas y Herramientas (el Libro del Dragón):
fuente
Un súper interesante discusión de este está en Unix co-creador Ken Thompson 's Premio Turing conferencia.
Comienza con:
y procede a mostrar cómo escribió una versión del compilador Unix C que siempre le permitiría iniciar sesión sin contraseña, porque el compilador C reconocería el programa de inicio de sesión y agregaría un código especial.
fuente
La forma en que he oído hablar es escribir un compilador extremadamente limitado en otro idioma y luego usarlo para compilar una versión más complicada, escrita en el nuevo idioma. Esta segunda versión se puede utilizar para compilarse a sí mismo y la siguiente versión. Cada vez que se compila se utiliza la última versión.
Esta es la definición de bootstrapping:
EDITAR: El artículo de Wikipedia sobre el arranque del compilador cubre el concepto mejor que yo.
fuente
Consulte el episodio 61 de la radio de ingeniería de software del podcast (2007-07-06) que analiza los aspectos internos del compilador de GCC, así como el proceso de arranque de GCC.
fuente
Donald E. Knuth realmente construyó WEB escribiendo el compilador en él y luego lo compiló manualmente en código ensamblador o máquina.
fuente
Según tengo entendido, el primer intérprete Lisp se arrancó compilando manualmente las funciones del constructor y el lector de tokens. El resto del intérprete se leyó luego de la fuente.
Se puede comprobar por sí mismo mediante la lectura del documento McCarthy original, funciones recursivas de expresiones simbólicas y su cómputo por máquina, Parte I .
fuente
Otra alternativa es crear una máquina de código de bytes para su idioma (o usar una existente si sus características no son muy inusuales) y escribir un compilador para el código de bytes, ya sea en el código de bytes o en su idioma deseado usando otro intermedio, como un kit de herramientas del analizador que genera el AST como XML, luego compila el XML en código de bytes usando XSLT (u otro lenguaje de coincidencia de patrones y representación basada en árbol). No elimina la dependencia de otro idioma, pero podría significar que una mayor parte del trabajo de arranque termina en el sistema final.
fuente
Es la versión informática de la paradoja del huevo y la gallina. No puedo pensar en una forma de no escribir el compilador inicial en ensamblador o en algún otro lenguaje. Si se hubiera podido hacer, debería haberlo hecho Lisp.
De hecho, creo que Lisp casi califica. Consulte su entrada de Wikipedia . Según el artículo, la función de evaluación Lisp podría implementarse en un IBM 704 en código de máquina, con un compilador completo (escrito en Lisp mismo) que entraría en vigor en 1962 en el MIT .
fuente
Cada ejemplo de arranque de un lenguaje en el que puedo pensar ( C , PyPy ) se realizó después de que hubiera un compilador en funcionamiento. Tienes que empezar en alguna parte, y volver a implementar un lenguaje en sí mismo requiere escribir un compilador en otro lenguaje primero.
¿De qué otra manera funcionaría? No creo que sea conceptualmente posible hacer otra cosa.
fuente
Algunos compiladores o sistemas bootstrapped mantienen tanto el formato fuente como el formato objeto en su repositorio:
ocaml es un lenguaje que tiene un intérprete de código de bytes (es decir, un compilador de código de bytes Ocaml) y un compilador nativo (para x86-64 o ARM, etc ... ensamblador). Su repositorio svn contiene tanto el código fuente (archivos
*/*.{ml,mli}
) como el formato bytecode (archivoboot/ocamlc
) del compilador. Entonces, cuando lo compila, primero usa su código de bytes (de una versión anterior del compilador) para compilarse a sí mismo. Más tarde, el código de bytes recién compilado puede compilar el compilador nativo. Entonces, el repositorio svn de Ocaml contiene tanto los*.ml[i]
archivos fuente como elboot/ocamlc
archivo de código de bytes.El compilador de rust descarga (usando
wget
, por lo que necesita una conexión a Internet que funcione) una versión anterior de su binario para compilarse.MELT es un lenguaje similar a Lisp para personalizar y ampliar GCC . Se traduce a código C ++ mediante un traductor bootstrap. El código C ++ generado del traductor se distribuye, por lo que el repositorio svn contiene tanto
*.melt
archivos fuente como archivosmelt/generated/*.cc
"objeto" del traductor.El sistema de inteligencia artificial CAIA de J.Pitrat es completamente autogenerador. Está disponible como una colección de miles de
[A-Z]*.c
archivos generados (también con undx.h
archivo de encabezado generado ) con una colección de miles de_[0-9]*
archivos de datos.También se arrancan varios compiladores de Scheme. Scheme48, Plan de pollo, ...
fuente