¿Cómo podría escribirse el primer compilador de C ++ en C ++?

48

Stroustrup afirma que Cfront, el primer compilador de C ++, se escribió en C ++ ( Preguntas frecuentes de Stroustrup ).

Sin embargo, ¿cómo es posible que el primer compilador de C ++ se escriba en C ++?

El código que compone el compilador también debe compilarse y, por lo tanto, el primer compilador de C ++ no podría haberse escrito en C ++, ¿verdad?

Pacerier
fuente

Respuestas:

57

La clave está aquí:

El primer compilador de C ++ (Cfront) se escribió en C ++. Para construir eso, primero usé C para escribir un preprocesador "C con clases" a C. "C con clases" fue un dialecto C que se convirtió en el antepasado inmediato de C ++. Ese preprocesador tradujo construcciones de "C con clases" (como clases y constructores) a C. Era un preprocesador tradicional que no entendía todo el lenguaje, dejaba que la mayoría del tipo verificara que el compilador de C hiciera y traducía individualmente. construcciones sin conocimiento completo. Luego escribí la primera versión de Cfront en "C con clases".

Entonces, la primera versión de Cfront no fue escrita en C ++, sino en el lenguaje intermedio. La capacidad de crear compiladores y preprocesadores de C directamente en C condujo a muchas de las innovaciones (y agujeros de seguridad masivos ) en C. Así que escribe su nuevo preprocesador que convierte su código "C con clases" en C directo (porque C directo puede hacer cualquier cosa) y luego usas "C con clases" para escribir un compilador de C ++ (no es que no puedas hacerlo en C, solo tomará un tiempo) y luego usas ese compilador de C ++ para escribir un compilador más eficiente / completo en C ++. ¿Entendido?

Christopher Bibbs
fuente
55
+1 por incluir un enlace a uno de mis cuentos favoritos de cosas que se pueden hacer (y no deberían).
jwernerny
3
El compilador se escribió en un código válido de C ++, pero solo utilizó algunas de las características completas de C ++, las que eran compatibles con el preprocesador "C con clases". Usó un subconjunto del lenguaje completo, por lo que también compiló el resultado (la primera versión de trabajo de Cfront). Después de realizar este paso de "arranque", probablemente nunca más necesitó usar el preprocesador.
joeytwiddle
2
@jwernerny: ese artículo siempre me pareció insatisfactorio. Él pasa por alto la parte más difícil y no trivial: "El error coincidiría con el código en el comando 'login' de UNIX. El código de reemplazo compilaría mal el comando de inicio de sesión para que aceptara la contraseña cifrada deseada o una contraseña conocida en particular. " ¿Pero cómo se haría esto? ¿Alguna vez se ha demostrado realmente?
detly
3
"condujo a muchas de las innovaciones (y agujeros de seguridad masivos) en C": Hasta donde yo sé, estos trucos se pueden usar en cualquier idioma, no solo en C. Por lo tanto, cualquier otro idioma puede tener los mismos agujeros de seguridad.
Giorgio
2
@detly: Ahora suena trivial, pero en 1983 fue un ataque novedoso que se hizo viable por la falta de diversidad en la implementación. En aquel entonces, confiamos más en los binarios, en parte porque compilar todo desde la fuente era una experiencia mucho más grande de lo que es ahora.
Blrfl
17

Estaba cargado de botas. Tan pronto como se agregó una característica de C ++ a cfront, cfront también podría usar esa característica a partir de ese momento (pero no para implementar esa característica). Esto funcionó porque cfront tenía la capacidad de convertir código C ++ a código C. Entonces, si surgió una nueva plataforma, podría usar cfront en otra plataforma para convertir cfront de C ++ a C, y luego usar el compilador de C de la nueva plataforma para finalizar la compilación de C a código de objeto.

David Schwartz
fuente
9

Creo que BS responde esa pregunta:

El primer compilador de C ++ (Cfront) se escribió en C ++. Para construir eso, primero usé C para escribir un preprocesador "C con clases" a C. "C con clases" fue un dialecto C que se convirtió en el antepasado inmediato de C ++. Ese preprocesador tradujo construcciones de "C con clases" (como clases y constructores) a C. Era un preprocesador tradicional que no entendía todo el lenguaje, dejaba que la mayoría del tipo verificara que el compilador de C hiciera y traducía individualmente. construcciones sin conocimiento completo.

Luego escribí la primera versión de Cfront en "C con clases". Cfront era un compilador tradicional que completaba la sintaxis y la comprobación semántica de la fuente de C ++. Para eso, tenía un analizador completo, construía tablas de símbolos y construía una representación de árbol interna completa de cada clase, función, etc. También optimizaba el nivel de fuente en su representación de árbol interna de construcciones C ++ antes de generar C. La versión que C generado, no se basó en C para ninguna verificación de tipo. Simplemente usó C como ensamblador. El código resultante fue inflexiblemente rápido.

Primero creó algo que llamó "C con clases" implementado por un simple preprocesador en C. Era básicamente C ++, pero el preprocesador hizo poca o ninguna verificación. Luego usó eso para escribir Cfront, la versión más poderosa del traductor de C ++ a C, completa con verificación de tipos, tablas de símbolos, etc.

Mike Dunlavey
fuente
1
así que, básicamente, cuando compilamos un programa C ++, se convierte en C y luego, una vez convertido en C, se vuelve a compilar en código máquina.
Pacerier
@Pacerier: Originalmente, sí, pero ahora no, creo.
Mike Dunlavey
No entiendo tu comentario. ¿Quiere decir que ahora hay compiladores que omiten el segundo paso y simplemente toman la fuente C ++ y la compilan en código máquina?
Pacerier
77
@Pacerier: Bueno, no van directamente al lenguaje ensamblador o al código de máquina. Por lo general, primero van a una representación intermedia independiente de la máquina (triples o cuádruples) y la analizan para su optimización. A partir de eso generan código de ensamblaje o máquina. Si elige un libro sobre diseño de compiladores (Aho y Ullman) , estoy seguro de que lo encontrará interesante.
Mike Dunlavey
1
Es importante tener en cuenta que el C ++ que estaba construyendo también era una fracción del lenguaje que ahora existe. No tenía plantillas, ni bibliotecas nuevas, solo usaba la conversión de C y, si recuerdo bien, no tenía excepciones.
Gort the Robot
2

Agregaré esta respuesta ya que ninguna respuesta cubrió este aspecto.

Técnicamente no necesita software para compilar código. Siempre que tenga las especificaciones necesarias del compilador, puede hacer la compilación real manualmente. No es así como se compiló el primer compilador de C ++. Solo digo que es posible.

Compare con el lenguaje ensamblador. Cuando se usaron en los primeros días, no había software de ensamblador para convertir el código de ensamblaje en código de máquina. Fue hecho a mano, pero el lenguaje ensamblador dio a los programadores una mejor visión general.

klutt
fuente