Intuitivamente, se podría parece que un compilador para el lenguaje Foo no puede ser escrito en Foo. Más específicamente, el primera compilador para el lenguaje Foo no puede ser escrito en Foo, pero cualquier posterior compilador podría ser escrito para Foo.

Pero es esto realmente cierto? Yo tengo muy vagos recuerdos de leer acerca de un lenguaje cuyo primer compilador fue escrito en «sí». Es esto posible, y si es así ¿cómo?

  • Posibles duplicados de Bootstrap todavía requiere de apoyo externo
  • Esta es una muy vieja pregunta, pero decir que me escribió un intérprete para el lenguaje de los Foo en Java. Luego, con la lengua foo, me escribió su propio intérprete. Foo requiere todavía de la JRE derecho?
InformationsquelleAutor Dónal | 2008-10-11

11 Comentarios

  1. 220

    Esto se llama «bootstrapping». Primero debe construir un compilador (o intérprete) para su idioma en otro idioma (generalmente de Java o C). Una vez que haya terminado, usted puede escribir una nueva versión del compilador en lenguaje Foo. Utilice la primera bootstrap compilador para compilar el compilador, y, a continuación, utilizar este compilado compilador para compilar todo lo demás (incluyendo a las futuras versiones de sí mismo).

    La mayoría de los lenguajes de hecho son creados de esta manera, en parte debido a los diseñadores de lenguajes como el uso de la lengua en que se están creando, y también porque no trivial de compilador a menudo sirve como un punto de referencia útil para la forma «completa» de la lengua puede ser.

    Un ejemplo de esto sería la Scala. Su primer compilador fue creado en la Pizza, una experimental del lenguaje por Martin Odersky. A partir de la versión 2.0, el compilador fue completamente re-escrito en Scala. A partir de ese punto, el antiguo Pizza compilador puede ser completamente descartada, debido al hecho de que el nuevo compilador de Scala podría ser utilizado para compilar sí mismo para futuras iteraciones.

    • Gracias por la explicación!
    • Tal vez una pregunta estúpida: Si desea puerto el compilador a otro de la arquitectura de microprocesador el arranque debe reiniciar partir de un trabajo de compilador para esa arquitectura. Esto es correcto? Si esto es correcto esto significa que es mejor mantener el primer compilador, ya que podría ser útil para el puerto de su compilador para otras arquitecturas (especialmente si está escrito en algún ‘lenguaje universal’ como en C)?
  2. 71

    Recuerdo escuchar a un Ingeniería de Software podcast de Radio donde Dick Gabriel habló sobre el arranque de la original intérprete de LISP escribiendo una versión básica en LISP en papel y de la mano de su montaje en código máquina. A partir de entonces, el resto de la LISP características fueron escritas en e interpretado con LISP.

  3. 45

    Añadir una curiosidad de las respuestas anteriores.

    He aquí una cita de la Linux Desde Cero manual, en el paso donde uno comienza a construir el compilador GCC de su fuente. (Linux Desde Cero es una forma de instalar Linux que es radicalmente diferente de la instalación de una distribución, en el que tienes que compilar realmente cada binario del sistema de destino.)

    make bootstrap
    

    El ‘bootstrap’ target no sólo compilar GCC, sino que compila varias veces. Utiliza los programas compilados en un primer
    ronda de compilar en sí mismo una segunda vez, y luego de nuevo por tercera vez. Luego se compara el segundo y tercer
    compila para asegurarse de que puede reproducirse sin problemas. Esto implica también que fue compilado correctamente.

    Que el uso de la ‘bootstrap’ destino está motivado por el hecho de que el compilador utiliza para construir el sistema de destino del conjunto de herramientas pueden no tener la misma versión de la meta del compilador. Proceder de esa manera, uno está seguro de obtener, en el sistema de destino, un compilador para compilar sí mismo.

    • «tienes que compilar realmente cada binario del sistema de destino» y, sin embargo, usted tiene que comenzar con un gcc binario que llegó desde algún lugar, debido a que la fuente no se puede compilar en sí. Me pregunto si remonta el linaje de cada gcc binario que se utiliza para compilar cada una de las sucesivas gcc, que te dan todo el camino de regreso a K&R original del compilador de C?
  4. 41

    Cuando usted escribe su primer compilador de C, se escribe en otro idioma. Ahora, usted tiene un compilador de C, por ejemplo, en ensamblador. Finalmente, se llega al lugar donde se ha de analizar las cadenas, específicamente las secuencias de escape. Usted va a escribir el código para convertir \n para el personaje con el código decimal 10 (y \r a 13, etc).

    Después de que el compilador está listo, usted comenzará a reimplementar en C. Este proceso se llama «bootstrapping«.

    La cadena código de análisis será:

    ...
    if (c == 92) { //backslash
        c = getc();
        if (c == 110) { //n
            return 10;
        } else if (c == 92) { //another backslash
            return 92;
        } else {
            ...
        }
    }
    ...
    

    Cuando este se compila, tiene un binario que entiende ‘\n’. Esto significa que usted puede cambiar el código fuente:

    ...
    if (c == '\') {
        c = getc();
        if (c == 'n') {
            return '\n';
        } else if (c == '\') {
            return '\';
        } else {
            ...
        }
    }
    ...
    

    Entonces, ¿dónde está la información que ‘\n’ es el código de la 13? Es en el binario! Es como el ADN: la Compilación de código fuente de C con este binario heredará esta información. Si el compilador compila sí, va a pasar este conocimiento a sus descendientes. A partir de este punto, no hay manera de ver de la fuente solo lo que el compilador va a hacer.

    Si quieres ocultar un virus en el código fuente de algún programa, puedes hacerlo así: Obtener el código fuente de un compilador, encontrar la función que compila las funciones y reemplazarla con la siguiente:

    void compileFunction(char * name, char * filename, char * code) {
        if (strcmp("compileFunction", name) == 0 && strcmp("compile.c", filename) == 0) {
            code = A;
        } else if (strcmp("xxx", name) == 0 && strcmp("yyy.c", filename) == 0) {
            code = B;
        }
    
        ... code to compile the function body from the string in "code" ...
    }
    

    Las partes interesantes son a y B. a es el código fuente para compileFunction incluyendo el virus, probablemente cifrado de alguna manera por lo que no es obvio a partir de la búsqueda de el binario resultante. Esto se asegura de que compilar con el compilador con la propia voluntad de preservar el virus de la inyección de código.

    B es el mismo para la función que desea reemplazar con nuestro virus. Por ejemplo, podría ser la función de «inicio de sesión» en el archivo de origen «inicio de sesión.c», que es, probablemente, desde el kernel de Linux. Podríamos reemplazarlo con una versión que acepta la contraseña «josué» para la cuenta de root, además de la contraseña normal.

    Si compila que y difundirlo como un binario, no habrá forma de encontrar el virus, mirando la fuente.

    La fuente original de la idea: http://cm.bell-labs.com/who/ken/trust.html

    • ¿Cuál es el punto de la segunda mitad sobre la escritura de virus infestado compiladores? 🙂
    • Acaba de difundir el conocimiento de cómo bootstrap puede matar.
  5. 18

    Usted no puede escribir un compilador en sí misma, porque usted no tiene nada para compilar su punto de partida es el código fuente. Hay dos enfoques para la solución de este.

    Los menos favorecidos, es la siguiente. Escribe un mínimo de compilador de ensamblador (puaj) para un conjunto mínimo de la lengua y, a continuación, utilizar ese compilador para implementar funciones adicionales de la lengua. La construcción de su camino hasta que usted tiene un compilador con todas las características del lenguaje por sí mismo. Un proceso doloroso que es normalmente sólo se hace cuando no tienen otra opción.

    El enfoque preferido es el uso de un compilador cruzado. Cambiar el fondo de una existente compilador en una máquina diferente para crear una salida que se ejecuta en la máquina de destino. Entonces usted tiene un buen compilador completa y trabajo en el equipo de destino. Más populares de esto es el lenguaje C, ya que hay un montón de los compiladores existentes que han enchufable en la parte final que puede ser intercambiado.

    Un hecho poco conocido es que el compilador C++ de GNU tiene una aplicación que utiliza sólo el subconjunto C. La razón de ser por lo general es fácil encontrar un compilador de C para un nuevo equipo de destino que permite que usted construya completo compilador C++ de GNU de ella. Usted tiene ahora arranque atado a ti mismo para tener un compilador de C++ en el equipo de destino.

  6. 14

    Generalmente, usted necesita tener un trabajo (si primative) corte del compilador de trabajo de primera, a continuación, usted puede comenzar a pensar acerca de lo que es autosuficiente. Esto realmente es considerado un hito importante en algunos idiomas.

    De lo que recuerdo de «mono», es probable que la necesidad de añadir un par de cosas a la reflexión para que funcione: el mono del equipo de seguir señalando que hay cosas que simplemente no son posibles con Reflection.Emit; por supuesto, el MS equipo podría demostrar que están equivocados.

    Este tiene un par de real ventajas: es una buena prueba de unidad, para empezar! Y sólo tiene un idioma que preocuparse (es decir, que es posible un C# experto puede no saber mucho de C++; pero ahora tu puede arreglar el compilador de C#). Pero me pregunto si no hay una cantidad de orgullo profesional en el trabajo: simplemente quiere a ser autosuficiente.

    No es un compilador, pero recientemente he estado trabajando en un sistema que se auto de alojamiento; el generador de código se utiliza para generar el generador de código… así que si los cambios en el esquema, yo simplemente ejecutar en sí mismo : la nueva versión. Si hay un error, acabo de volver a una versión anterior y volver a intentarlo. Muy cómoda y muy fácil de mantener.


    Actualización de 1

    He visto este video de Anders en el PDC, y (sobre una hora) le da a algunos mucho más razones válidas – todo sobre el compilador como un servicio. Sólo para el registro.

  7. 4

    Aquí un volcado (tema difícil de buscar, en realidad):

    Esta es también la idea de PyPy y Rubinius:

    (Creo que esto podría aplicarse también a Adelante, pero no sé nada acerca de los Demás.)

    • El primer enlace a un supuesto de Smalltalk-artículo relacionado actualmente está apuntando a una página sin aparente útil e inmediata de la información.
  8. 1

    MOSQUITO, el compilador GNU Ada, requiere un compilador Ada para ser totalmente construido. Esto puede ser un dolor de cabeza cuando se traslada a una plataforma donde no hay GNAT binarios disponibles.

    • No veo por qué no? No hay ninguna regla que ha de arrancar más de una vez (como por cada una nueva plataforma), también puede compilación cruzada con una actual.
  9. 1

    De hecho, la mayoría de los compiladores están escritas en el lenguaje que se compila, por las razones antes expuestas.

    La primera bootstrap compilador es generalmente escrito en C, C++ o Asamblea.

  10. 1

    El Mono proyecto compilador de C# ha sido «self-hosted» por un largo tiempo, lo que significa es que ha sido escrito en C# sí mismo.

    Lo que yo sé es que el compilador se inició como puro código C, pero una vez que el «básico» características de ECMA fueron implementados en que empezó a reescribir el compilador de C#.

    No soy consciente de las ventajas de escribir el compilador en el mismo idioma, pero estoy seguro de que ha de cumplir al menos con las características que el lenguaje mismo puede ofrecer (C, por ejemplo, no admite la programación orientada a objetos).

    Usted puede encontrar más información aquí.

  11. 0

    Tal vez usted puede escribir un BNF describir BNF.

    • De hecho, puede (no es tan difícil tampoco), pero la aplicación práctica sería en un parser generator.
    • De hecho, he utilizado ese método para producir la CAL parser generator. Una restringido, simplificado, representación tabular de la metagrammar pasa a través de un simple recursiva-descenso del analizador. Luego, LIMA genera un analizador para el lenguaje de las gramáticas y, a continuación, utiliza el analizador de leer la gramática alguien está realmente interesado en la generación de un analizador para el. Esto significa que no tengo que saber cómo escribir lo que acabo de escribir. Se siente como magia.
    • En realidad no se puede, como BNF no puede describirse. Usted necesita una variante como la que se utiliza en yacc donde los símbolos no terminales no son citados.

Dejar respuesta

Please enter your comment!
Please enter your name here