tipos programas partes interprete informatica fases ejemplos compiladores compilador compiler-construction theory bootstrapping

compiler construction - programas - Arrancando un compilador: ¿por qué?



programas compiladores (11)

Entiendo cómo un lenguaje puede arrancar, pero no he podido encontrar mucha referencia sobre por qué debería considerar el arranque.

La respuesta intuitiva es que el lenguaje que está escribiendo ofrece utilidades que no se encuentran en el lenguaje "base" del compilador, y las características del idioma son relativamente adecuadas para un compilador.

Por ejemplo, tendría sentido arrancar un compilador de C ++: potencialmente podría ser mucho más fácil mantener el compilador cuando se usa correctamente la POO, en lugar de usar la C simple.

Por otro lado, MATLAB ciertamente hace que las matrices sean mucho más sencillas que C simple, pero no veo ningún beneficio aparente al escribir un compilador / intérprete de MATLAB en MATLAB; parece que sería menos fácil de mantener. Una vista similar podría aplicarse al lenguaje de programación R. O un ejemplo bastante extremo sería el arranque de Whitespace , que está escrito en Haskell, definitivamente un super conjunto masivo de Whitespace.

¿Es la única razón por la que Bootstrapping aprovecha las características del nuevo idioma? Sé que también existe la razón "porque podemos", pero eso no es lo que estoy buscando :)


Bootstrapping también tiene otra ventaja: si su idioma es bueno, puede ahorrar tiempo al escribir su compilador en <inserte el idioma aquí> que en digamos C. Por ejemplo, el compilador de C # fue escrito en C ++, pero ahora lo están reescribiendo. C #, que les permite (entre otras cosas) usar el marco de subprocesamiento del CLR en lugar de rodar el suyo en C ++ (y seguir el ejemplo de los chicos de Mono también, en cuanto a marketing, Mono estaba en una mejor posición al poder para decir que nuestro compilador de C # está realmente escrito en C #).


Como ejemplo concreto, en la versión 1.5 (lanzada en agosto de 2015), Go se convirtió en un idioma totalmente bootstrapped [1] [2] . Enumeraron las siguientes razones:

  • Ir es más fácil de escribir (correctamente) que C.
  • Ir es más fácil de depurar que C (incluso sin un depurador).
  • Go es el único idioma que necesitarías saber; fomenta las contribuciones.
  • Go tiene mejor modularidad, herramientas, pruebas, perfiles, ...
  • Ir hace que la ejecución paralela sea trivial.

De estos, el único que valdría para todos los idiomas es que solo necesita saber un idioma para contribuir al compilador. Los otros argumentos pueden resumirse como "Nuestro nuevo lenguaje es mejor que el anterior". Lo que probablemente debería ser cierto, ¿por qué más escribirías un nuevo idioma?


Hay dos ventajas principales para las implementaciones de lenguaje bootstrapped: primero, como sugiere, aprovechar las características de alto nivel de dicho lenguaje en la implementación. Sin embargo, una ventaja menos obvia, pero no menos importante, es que le permite personalizar y extender el idioma sin caer en una capa inferior escrita en C (o Java, o lo que sea que se encuentre debajo del tiempo de ejecución del nuevo idioma).

La metaprogramación puede no ser útil para la mayoría de las tareas del día a día, pero hay ocasiones en que puede ahorrarle mucho código duplicado o repetitivo. Ser capaz de conectarse al compilador y al tiempo de ejecución central para un lenguaje de alto nivel puede hacer que las tareas avanzadas de metaprogramación sean mucho más fáciles.


Hay un par de razones por las que podrías querer hacerlo (en teoría):

  1. Su compilador genera más código optimizado que otros compiladores en la plataforma de arranque.
  2. Su compilador genera un código más correcto que los otros compiladores en la plataforma bootstrap.
  3. Eres un imbécil egoísta que está convencido de que uno de los anteriores es cierto, aunque no lo sea.
  4. No hay un compilador disponible en su plataforma (esta era la lógica original de GCC, porque muchas plataformas no tenían un compilador de C en el pasado).
  5. Quieres probar que tu compilador puede manejarlo (esto es, después de todo, una prueba bastante buena de un compilador).

Hay un principio llamado "comer tu propia comida para perros". Al usar una herramienta, demuestras la utilidad de la herramienta.

A menudo se pregunta: "si el compilador para el lenguaje X no está escrito en el lenguaje X, ¿por qué debería arriesgarme a usarlo?"

Por supuesto, esto solo se aplica a los idiomas adecuados para el dominio de escritura del compilador.


Los compiladores resuelven una amplia variedad de problemas no triviales, incluida la manipulación de cadenas, el manejo de grandes estructuras de datos y la interconexión con el sistema operativo. Si su idioma está destinado a manejar esas cosas, entonces escribir su compilador en su idioma demuestra esas capacidades. Además, crea un efecto exponencial porque a medida que su idioma incluye más funciones, tiene más funciones que puede usar en su compilador. Si implementas alguna característica única que facilitaría la escritura del compilador, tienes esas nuevas herramientas disponibles para implementar aún más características.

Sin embargo, si su idioma no tiene la intención de manejar los mismos problemas que la compilación, entonces el programa de arranque solo lo tentará a saturar su idioma con características relacionadas con la compilación pero no con su problema objetivo. La autocompilación con Matlab o SQL sería ridícula; Matlab no tiene ninguna razón para incluir funciones de manipulación de cadenas fuertes y SQL no tiene ninguna razón para admitir la generación de código. El lenguaje resultante sería innecesario y abarrotado.

También vale la pena señalar que los idiomas interpretados son un problema ligeramente diferente y deben tratarse en consecuencia.


Los lenguajes de bajo nivel a menudo se inician porque, para colocar el código en el nuevo sistema, se necesita un compilador de bajo nivel. Obtenga un compilador de C y ahora tiene toneladas de código disponible para usar. Tener un compilador bootstrapped lo hace más fácil, solo requiere la presencia de su propio código para compilar y mejorar su propio código.

Hay otras formas de lograr esto, como hacer un compilador cruzado, en la mayoría de los sistemas que nunca necesita poder compilar lenguajes estáticos en el dispositivo en uso ordinario (de hecho, los sistemas como Windows se envían sin compilador).

Otra razón por la que los compiladores suelen arrancar es que no tienen que preocuparse por los errores en el compilador con el que están compilados. Asegúrese de que su compilador pueda compilarse consigo mismo y limite las combinaciones de errores que de lo contrario podrían aparecer si compila con otro compilador.

Creo que los lenguajes de arranque de alto nivel se realizan principalmente para mostrar las habilidades de programación de torso peludo.


No arrancas un compilador para DSL. No escribes un compilador de consultas SQL en SQL. MATLAB puede parecer un lenguaje de propósito general, pero en realidad no lo es, es un lenguaje diseñado para cálculos numéricos.


Puede considerarse la barra que separa los idiomas de "juguete" de los idiomas "reales". Si el lenguaje no es lo suficientemente rico como para implementarse, sigue siendo un juguete. Pero esta es probablemente una actitud de una época en gran medida pasada, dada la cantidad de idiomas populares en la actualidad que se implementan en C.


Una ventaja sería que los desarrolladores que trabajan en el compilador solo necesitarían saber el lenguaje que se está compilando. De lo contrario, los desarrolladores necesitarían saber el idioma que se está compilando, así como el idioma en el que está escrito el compilador.


Reflexiones de Ken Thompson sobre la confianza fidedigna explica una de las mejores razones para el arranque. Esencialmente, su compilador aprende cosas nuevas para cada versión del compilador en la cadena de arranque que nunca más tendrá que enseñarlo.

En el caso que menciona, el primer compilador (C1) que escriba debe explicarse explícitamente cómo manejar el escape de barra invertida. Sin embargo, el segundo compilador (C2) se compila usando C1, por lo que el manejo de escape de barra invertida se maneja de forma nativa.

La piedra angular de su charla es la posibilidad de que usted pueda enseñar a un compilador a agregar una puerta trasera a los programas, ¡y a los compiladores futuros compilados con el compilador comprometido también se les otorgaría esta capacidad y que nunca aparecería en la fuente!

Esencialmente, su programa puede aprender nuevas características en cada ciclo de compilación que no tienen que volver a implementarse o volver a compilarse en ciclos de compilación posteriores porque su compilador ya lo sabe todo.

Tómate un minuto para darte cuenta de las ramificaciones.

[editar]: Esta es una forma bastante terrible de construir un compilador, pero el factor cool es a través del techo. Me pregunto si podría ser manejable con el marco adecuado.