2009-02-22 27 views
22

Quiero escribir mi propio compilador C++ en C++. Digamos que voy a construirlo en VS. La idea principal es que debe haber sido capaz de compilarse, lo que significa que no puedo usar bibliotecas STL, boost, etc., ¿o sí? Entonces, ¿significa que debo hacer todo desde cero, desde el analizador léxico hasta la generación de código binario?Escribiendo mi propio compilador C++

+23

Me gusta la etiqueta 'insane' :) –

+34

Buscando un desafío, ¿eh? Ya tenemos compiladores C++ decentes. Ir a curar el cáncer en su lugar. –

+0

También debe tener mucha experiencia en la construcción de compiladores. No hay nada que puedas diseñar sobre la marcha. – EricSchaefer

Respuesta

46

lo que significa que no puedo usar las bibliotecas STL, boost, etc., ¿o sí?

¿Por qué no? No usan magia (por así decirlo), solo C++. Entonces, si su compilador conoce todo C++, esto no debería ser un problema. Lo cual es por supuesto completamente ridículo, considerando que C++ es probablemente el más difícil de analizar el lenguaje de programación que existe en la actualidad, y que construir un compilador desde cero probablemente tomaría cientos (!) De años-hombre. (En realidad, no inventé este número, lo leí en alguna parte. Desafortunadamente, no puedo encontrar la fuente ahora.)

Pero entonces, supongo que la pregunta era completamente hipotética, por lo que la respuesta hipotética es: no, puedes usar bibliotecas existentes.

Entonces, ¿por qué C++ es tan difícil de compilar?

En primer lugar, C++ es un lenguaje sensible al contexto. Producir un analizador para tal gramática es mucho más difícil. Sin embargo, este sigue siendo uno de los aspectos más simples. Lo que hace que C++ sea realmente difícil son ciertas reglas relacionadas con declaraciones/definiciones, búsqueda de nombres (considere la búsqueda de nombres dependiente del argumento), reglas de conversión implícitas y, por supuesto, la resolución de las plantillas. Creo que ningún compilador existente obtiene las plantillas correctas en todas las circunstancias.

Considera Andrej Alexandrescu's efford to write template-function versions of min and max that behave as correctly as the macro version. Afirma que ningún compilador tiene éxito en la compilación de su código (teóricamente correcta):

todo sería tan agradable, pero hay un pequeño detalle digno de mención. Lamentablemente, Min no funciona con ningún compilador al que tenga acceso. Para ser justos, cada compilador se ahoga en una pieza diferente de código.

+0

en realidad, nuestro conferencista en la universidad quiere que escribamos el compilador para que pueda compilarse. ¿será posible si uso boost, por ejemplo? – chester89

+1

Su conferencista tal vez solo quiera que descubra de la peor manera lo difícil que es esto, o (s) quiere que implemente solo un subconjunto severamente limitado (en ese caso, sí, STL y Boost están fuera). ¡En cualquier caso, verifique las especificaciones con cuidado! –

+0

@ chester89: No. Puede usar cualquier característica que admita su compilador ... Escriba su compilador en C++, compilador con el compilador del sistema, para obtener una compilación "sucia". Use la compilación sucia para generar una compilación limpia, use la compilación limpia para generar una compilación de prueba. Si los dos últimos son iguales, ganas. – dmckee

9

Usted tendrá que bootstrap su compilador. Además, lea el Dragon Book (referencia obligatoria).

+1

No, no es necesario reiniciar el compilador, ya que el sistema ya ofrece un compilador completamente funcional. Bootstrapping funciona alrededor de la * falta * de un compilador completamente funcional. –

+1

Quizás no entendí la pregunta, pero él quiere compilar su compilador usando su propio compilador. Entonces, ¿usa un compilador de C++ existente para arrancar el suyo? ¿Derecha? – eljenso

+1

Sí. Perdón por la confusion. Lo que no se requiere, sin embargo, es varias iteraciones. Teóricamente, una iteración es suficiente. Por supuesto, eso es bastante improbable, como habrás notado, pero también lo es escribir un compilador de C++ en primer lugar. –

1

Yo diría que tienes dos opciones básicas compilando un compilador de C++. En primer lugar, compilarlo en C, lo que obviamente significa que no es autohospedado, pero trasladarlo a un sistema operativo diferente sería mucho más fácil, ya que todo lo que necesita es un compilador de C en la plataforma de destino.

Sin embargo, si usted quiere construir un compilador de C++ en C++, yo podría pensar que la construcción de ésta utilizando bibliotecas como Boost o de la biblioteca estándar de C++ sería una buena cosa, ya que tendrá que ser capaz de construir código usando estas bibliotecas de todos modos. Lo consideraría una ventaja si su compilador utilizara estas bibliotecas y es autohospedado, ya que allí tiene un caso de prueba bastante masivo.

El argumento en contra del uso de estas bibliotecas, bueno, al menos un poco de impulso, es que posiblemente terminará persiguiendo problemas de plantilla poco claros cuando debería estar trabajando en agregar funcionalidad al compilador. Pero al menos no tendrá que probar su compilador con las partes de impulso que usa su compilador.

Sin embargo, tendrás que implementar una gran cantidad de funcionalidades desde cero, pero al menos podrás concentrarte en escribir el compilador en lugar de crear una matriz dinámica ...

5

En realidad, nuestro conferencista en la universidad quiere que escribamos el compilador para que pueda compilarse.

¿Necesita su compilador soportar todas las características de C++?

  • Si necesita para apoyar/compile todas las características de C++, entonces eso es un gran proyecto ! También es grande para ser tarea, OMI, por lo que debe haber algún hecho importante sobre esta tarea que no haya mencionado.

  • Si hace no necesidad para apoyar/compile todas las características de C++ (si por el contrario sólo tiene que apoyar un subconjunto de C++, y en particular el subconjunto que utiliza en su propia implementación, por lo que puede compilarse a sí mismo), entonces debe evitar el uso de STL y Boost en su implementación: porque STL y Boost se implementan mediante plantillas, por lo que si (y solo si) los usa, tendrá que incluir/implementar soporte para compilar plantillas .

1

Estoy impresionado de su entusiasmo.

¿Has pensado qué formato de archivo quieres generar? archivos de objetos? archivos de la biblioteca? ejecutables? COFF/ELF/etc

Se podría buscar en la fabricación de un simple compilador que genera código C, es decir, como fue creado para C++ en el principio. Ver CFront. Esta puede ser una forma de enfocarse inicialmente en el análisis sintáctico de C++.

Agregado

seguro de que su profesor significaba C++? Tal vez la tarea fue inventar un lenguaje fácil en el que pudieras escribir el compilador. Creo que, por ejemplo, Lisp generalmente se utiliza en la academia para tareas como esta.

+0

CFront era un enfoque plausible en aquel momento. C++ es mucho más complejo hoy en día, por lo que ese enfoque sería tan difícil hoy como un compilador "tradicional". – jalf

+0

¿Crees? Si puede dejar fuera de la CPU cosas como registros, ABI, etc., formatos de archivo para archivos de objetos/bibliotecas/ejecutables. Solo concéntrese en el lenguaje ... pero no me puedo imaginar que la creación de un compilador completo de C++ sea realmente lo que el conferencista quiso decir para una asignación de clase – epatel

24

Esta es una tarea extremadamente difícil. Incluye:

  • Selección de C++ que desea admitir. ARM de Stroustrup? ISO/IEC 14882: 2003?
  • Encontrar una gramática correcta para su versión C++ elegida.
  • Escribir un lexer/analizador que pueda manejar las complejidades contextuales.
  • Selección de una plataforma de hardware para su generador de código.
  • Posiblemente escribir un enlazador que cumpla con los estándares, para que pueda utilizar bibliotecas de terceros.

GCC ha tardado 22 años en llegar a su destino. Visual C++ ha tardado 17 años (y hubo un compilador MS C++ varios años antes de VC++). Estos productos son masivos.

chester89, no quiero insinuar que no lo es, pero se necesita un profesional y un genio como Walter Bright para simplemente salir y escribir su propio compilador de C++ (y luego un compilador de D).

Creo que ayudaría si primero escribes otros compiladores más simples, aunque solo sea para ilustrar la enormidad de esta tarea.

Vas a necesitar un montón de café.

+1

Decidir cómo construir los niveles intermedios del compilador también es una tarea desafiante. Comenzar con compiladores más pequeños debería ser dulce. – Elroy

+1

gracias por sus comentarios, también creo que el hombre de la universidad no quería decir que escribiéramos Visual Studio desde cero, él solía ser un programador, pero ahora no, y lo que hace en sus conferencias y clases prácticas es diciéndonos cómo la programación lo decepcionó, filosofó sobre la vida, etc. :) – chester89

+1

"Selección de una plataforma de hardware para su generador de código". o use un generador de código existente, como LLVM. –

1

Estas son respuestas de alta calidad.

Si se trata de un proyecto de juguete, consideraré cuidadosamente el alcance.

Si solo tiene que compilarse, hay muchas características que puede omitir, como plantillas.

¿Se puede utilizar un preprocesador estándar?

¿Tiene que generar el código de ensamblaje, o simplemente C? C es mucho más fácil, obviamente.

Para el análisis, vas a necesitar LR1 (yacc o equivalente).

Si puede encuadernar el alcance, los principales desafíos deben estar en el área de gestión de tablas de símbolos y tipo de inferencia. Mantenlo simple (es decir, no te metas en tablas hash). Y no se preocupan por la optimización.

2

Escribir un compilador es un juego completamente diferente. Soy parte de un equipo de desarrollo que está desarrollando un compilador para un lenguaje similar a Pascal. Y debo decirle que todo suena muy bien teóricamente, pero si no conoce las especificaciones completas de antemano y no tiene un diseño adecuado, no obtendrá nada.

No es imposible que un ejército de un solo hombre desarrolle un compilador de C++, es solo que no llega hasta el final. Yo recomendaría lo que dijo Paul Beckingham sobre comenzar cosas con un compilador más pequeño solo para aclarar la idea. Hable con su profesor y hágale saber que va a comenzar y, con suerte, terminará el compilador mientras esté en la universidad, lo que en el primer caso no sería posible.

+0

Sí, la arquitectura de la aplicación es uno de los aspectos más importantes, estoy de acuerdo con esa afirmación 100% – Rik

11

Como muchos han dicho, es muy dudoso que cualquier equipo humano llegue a cualquier parte de importancia con un compilador de cero a partir de cero.

Dicho esto, puedo ver algunas estrategias diferentes para pensar sobre esto.

  1. Focus on auto-compile aspect. Comience con un kernel de lenguaje muy pequeño, algo incluso más pequeño que el c normal (olvide C++ inicialmente). Una vez que sea capaz de compilarse, agregue características de a una por vez, hasta que tenga C++ (o más probable que se rinda debido a la eventual muerte por calor del universo).
  2. Divida cada porción del sistema en minúscula bits. Por ejemplo, un lexer puede ser fácil si usa una biblioteca de expresiones regulares estándar para la mayor parte del trabajo. Va a ser lento, pero puede que sea bastante sólido en solo unos días.
  3. Muchos han dicho comenzar con un traductor de C++ a C, similar a Cfront. Esto se salta demasiado. comenzar con un verificador. Esto solo verifica si el programa está bien formado y compilaría. Agregar el analizador, que se traduce en un árbol sintáctico abstracto intermedio, se puede agregar a un verificador con relativa facilidad, y usar un AST para producir salida de código de máquina (en C o en lenguaje ensamblado o código de máquina) es también un pequeño paso.
  4. Aunque puedo ver el encanto de no usar bibliotecas, porque entonces tienes que compilar demasiado, no estoy seguro de que tome la misma decisión. Por un lado, BOOST aumentará su productividad. Boost tiene todo tipo de herramientas útiles para producir y manipular las estructuras de datos que necesita para construir un compilador.
  5. Una de las partes más complicadas para que un compilador de C++ funcione es el manejo adecuado de las plantillas. Se supone que el enlazador elimina las instancias de plantillas duplicadas de diferentes unidades de compilación, de modo que solo una de cada instancia está presente. Duplicados de otro código es un error. Probablemente eliminaría todos los duplicados, incluso si son errores. O algo como esto. Varíe de la norma de forma que no rompa muchos códigos válidos en cualquier lugar que pueda ayudar.
+0

Me gusta la forma en que lo pones, realmente pones la tensión adecuada en el factor TIEMPO. No se necesita un genio, solo tiempo, paciencia y una mente analítica. – Rik

17

Escribir su propio compilador de C++ es difícil. Lexing C++ es suficientemente malo ya que el lexer necesita saber en qué estado está el analizador (definiciones de plantilla anidadas). Aún no hay una gramática probada de YACCable para C++, incluso si se le da un lexer correcto, por lo que podría estar en un problema aún peor.

Dicho esto, le voy a dar algunos consejos.

  • Primero escriba el preprocesador C++.
  • Escriba el analizador/lexer con un programa principal que imprima bastante el árbol de análisis sintáctico.
  • Amplíe este programa para crear tablas de espacio de nombres y captar símbolos indefinidos.
  • Modifique este programa para escupir todas las expresiones en notación de postfijo.
  • Escribe el compilador básico de este tipo, sacando un ensamblaje intermedio para este tipo. Ignorar en línea/volátil/const/registrarse por ahora. Necesitará una "llamada externa" en su conjunto.
  • Escriba un intérprete para el ensamblaje intermedio. Ver si el compilador funciona.
  • Implemente #file y #line en el compilador (haga que el preprocesador también se escuche). Esto te ahorrará mucho dolor en el siguiente paso.
  • Agregue suficientes funciones al compilador para poder compilarse. Como aún no tiene módulos, use el preprocesador (un archivo # incluye todos los demás)
  • Archive todo esto.
  • Comience a usar su compilador como su propio compilador de arranque (esto eliminará los errores muy rápido).
  • Escriba el ensamblaje básico-> ensamblaje de máquina back-end. Pase esto a través de un ensamblador para obtener los archivos de objetos que puede vincular en ejecutables.
  • Archive todo esto
  • Comience a usar su compilador con ensamblador de stock para compilarse. Esto hará que salgan aún más insectos.
  • Escriba el binario maestro que puede llamar a todos los pasos.
  • Siga agregando características hasta que tenga todas las funciones que desea/necesita.

O renunciar a este proyecto y considerar G ++. Incluso si tiene una nueva combinación de arquitectura/sistema operativo de la CPU, le resultará más fácil portar G ++ que escribir la suya propia.

+0

Ojalá pudiera dar esto más que +1. – Fingolfin

+0

@ xci13 Puedes otorgarle una recompensa. –

+0

@DacSaunders: De hecho, él puede, pero en mayo del '13 no creo que eso haya funcionado todavía. – Joshua

Cuestiones relacionadas