programacion - Escribiendo mi propio compilador de C++
jdoodle (10)
de hecho, nuestro conferencista en la universidad quiere que escribamos el compilador para que pueda compilarse.
¿Tu compilador necesita soportar todas las características de C ++?
Si necesita soportar / compilar cada característica de C ++, ¡entonces es un gran proyecto! Es demasiado grande para ser tarea, OMI, así que debe haber algún hecho importante sobre esta tarea que no hayas mencionado.
Si no necesita soportar / compilar todas las características de C ++ (si en cambio solo necesita soportar un subconjunto de C ++, y en particular el subconjunto que usa en su propia implementación, para que pueda compilarse a sí mismo), entonces debe evitar usando STL y Boost en su implementación: porque STL y Boost se implementan usando plantillas, por lo que si (y solo si) los usa, tendrá que incluir / implementar soporte para compilar plantillas.
Quiero escribir mi propio compilador de 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?
lo que significa que no puedo usar bibliotecas STL, boost, etc., ¿verdad?
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.
Considere el esfuerzo de Andrej Alexandrescu para escribir versiones de función de plantilla de min
y max
que se comporten tan correctamente como la versión de macro . Él afirma que ningún compilador tiene éxito en compilar su código (teóricamente correcto):
Todo sería tan lindo, pero hay un pequeño detalle que vale la pena mencionar. 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.
Como muchos han dicho, es muy dudoso que cualquier equipo humano logre cualquier significado con un compilador de C ++ desde cero.
Dicho esto, puedo ver algunas estrategias diferentes para pensar sobre esto.
- Centrarse en el aspecto de autocompilación. 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 probablemente se rinda debido a la eventual muerte por calor del universo).
- Divida cada porción del sistema en pequeños pedazos. 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.
- 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 ensamblador o máquina) es también un pequeño paso.
- 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.
- 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.
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 desea compilar un compilador de C ++ en C ++ , creo que construirlo con bibliotecas como Boost o la biblioteca estándar de C ++ sería una buena idea, porque de todos modos tendrá que ser capaz de crear código utilizando estas bibliotecas. 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 algo 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 muchas funcionalidades desde cero, pero al menos podrás concentrarte en escribir el compilador en lugar de crear una matriz dinámica ...
Escribir tu 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 eso, voy a darte 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 arrojar todas las expresiones en notación postfija.
- 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.
- Escribe un intérprete para el ensamblaje intermedio. Ver si el compilador funciona.
- Implemente #file y #line en el compilador (haga que el preprocesador arroje también). Esto te ahorrará mucho dolor en el siguiente paso.
- Agregue suficientes características 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 la máquina back-end. Pase esto a través de un ensamblador para obtener los archivos de objeto que puede vincular en ejecutables.
- Archive todo esto
- Comience a usar su compilador con el ensamblador de acciones 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.
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 que sea imposible para un ejército de un solo hombre desarrollar 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.
Esta es una tarea extremadamente difícil. Incluye:
- Seleccionar qué C ++ desea apoyar. 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.
- Seleccionar 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 donde está. 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 eres, pero se necesita un profesional y un genio como Walter Bright para simplemente salir y escribir tu propio compilador C ++ (y luego un compilador 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 mucho café.
Estas son respuestas de alta calidad.
Si se trata de un proyecto de juguete, consideraría cuidadosamente el alcance.
Si solo tiene que compilarse, hay muchas características que puede omitir, como plantillas.
¿Puedes usar un preprocesador estándar?
¿Tiene que generar código ensamblador o solo C? C es mucho más fácil, obviamente.
Para el análisis, vas a necesitar LR1 (yacc o equivalente).
Si puede vincular el alcance, los principales desafíos deben estar en el área de gestión de tabla de símbolos e inferencia de tipo. Mantenlo simple (es decir, no te metas en tablas hash). Y no te preocupes por la optimización.
Estoy impresionado de tu entusiasmo.
¿Has pensado en qué formato de archivo quieres generar? archivos de objetos? archivos de la biblioteca? ejecutables? COFF / ELF / etc.
Podría buscar crear un compilador más simple que genere código C, es decir, como se creó para C ++ al principio. Ver CFront . Esta puede ser una forma de enfocarse inicialmente en el análisis sintáctico de C ++.
Adicional
¿Seguro que su conferencista quiso decir 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.