Los compiladores avanzados tienen gusto de gcc
compilar códigos en archivos legibles por máquina según el lenguaje en el que se ha escrito el código (por ejemplo, C, C ++, etc.). De hecho, interpretan el significado de cada código según la biblioteca y las funciones de los idiomas correspondientes. Corrígeme si estoy equivocado.
Deseo comprender mejor los compiladores escribiendo un compilador muy básico (probablemente en C) para compilar un archivo estático (por ejemplo, Hello World en un archivo de texto). Intenté algunos tutoriales y libros, pero todos son para casos prácticos. Se ocupan de compilar códigos dinámicos con significados relacionados con el lenguaje correspondiente.
¿Cómo puedo escribir un compilador básico para convertir un texto estático en un archivo legible por máquina?
El siguiente paso será introducir variables en el compilador; imagine que queremos escribir un compilador que compile solo algunas funciones de un lenguaje.
La introducción de tutoriales y recursos prácticos es muy apreciada :-)
fuente
Respuestas:
Introducción
Un compilador típico realiza los siguientes pasos:
La mayoría de los compiladores modernos (por ejemplo, gcc y clang) repiten los últimos dos pasos una vez más. Utilizan un lenguaje intermedio de bajo nivel pero independiente de la plataforma para la generación inicial de código. Luego, ese lenguaje se convierte en código específico de la plataforma (x86, ARM, etc.) haciendo aproximadamente lo mismo de una manera optimizada para la plataforma. Esto incluye, por ejemplo, el uso de instrucciones vectoriales cuando sea posible, la reordenación de instrucciones para aumentar la eficiencia de predicción de ramales, etc.
Después de eso, el código objeto está listo para vincular. La mayoría de los compiladores de código nativo saben cómo llamar a un enlazador para producir un ejecutable, pero no es un paso de compilación per se. En lenguajes como Java y C #, la vinculación puede ser totalmente dinámica, realizada por la máquina virtual en el momento de la carga.
Recuerda lo básico
Esta secuencia clásica se aplica a todo el desarrollo de software, pero conlleva repetición.
Concéntrese en el primer paso de la secuencia. Crea la cosa más simple que podría funcionar.
¡Lee los libros!
Lea el Libro del Dragón de Aho y Ullman. Esto es clásico y todavía es bastante aplicable hoy.
El diseño moderno del compilador también es alabado.
Si estas cosas son demasiado difíciles para usted en este momento, lea primero algunas introducciones sobre el análisis; Por lo general, las bibliotecas de análisis incluyen introducciones y ejemplos.
Asegúrese de sentirse cómodo trabajando con gráficos, especialmente árboles. Estas cosas son las cosas de las que están hechos los programas en el nivel lógico.
Define bien tu idioma
Use la notación que desee, pero asegúrese de tener una descripción completa y coherente de su idioma. Esto incluye tanto la sintaxis como la semántica.
Ya es hora de escribir fragmentos de código en su nuevo idioma como casos de prueba para el compilador futuro.
Usa tu idioma favorito
Está totalmente bien escribir un compilador en Python o Ruby o cualquier idioma que sea fácil para usted. Use algoritmos simples que entienda bien. La primera versión no tiene que ser rápida, eficiente o completa. Solo necesita ser lo suficientemente correcto y fácil de modificar.
También está bien escribir diferentes etapas de un compilador en diferentes idiomas, si es necesario.
Prepárate para escribir muchas pruebas
Todo su idioma debe estar cubierto por casos de prueba; efectivamente será definido por ellos. Conozca bien su marco de prueba preferido. Escribe exámenes desde el primer día. Concéntrese en las pruebas 'positivas' que aceptan el código correcto, en lugar de la detección de código incorrecto.
Ejecute todas las pruebas regularmente. Arregle las pruebas rotas antes de continuar. Sería una pena terminar con un lenguaje mal definido que no puede aceptar un código válido.
Crea un buen analizador
Los generadores de analizadores son muchos . Elige lo que quieras. También puede escribir su propio analizador de cero, pero sólo vale la pena si la sintaxis de la lengua es muerto simple.
El analizador debe detectar e informar errores de sintaxis. Escriba muchos casos de prueba, tanto positivos como negativos; Reutilice el código que escribió al definir el idioma.
La salida de su analizador es un árbol de sintaxis abstracta.
Si su idioma tiene módulos, la salida del analizador puede ser la representación más simple del 'código objeto' que genera. Hay muchas formas simples de volcar un árbol en un archivo y volver a cargarlo rápidamente.
Crear un validador semántico
Lo más probable es que su lenguaje permita construcciones sintácticamente correctas que pueden no tener sentido en ciertos contextos. Un ejemplo es una declaración duplicada de la misma variable o pasar un parámetro de un tipo incorrecto. El validador detectará tales errores mirando el árbol.
El validador también resolverá las referencias a otros módulos escritos en su idioma, cargará estos otros módulos y los usará en el proceso de validación. Por ejemplo, este paso se asegurará de que el número de parámetros pasados a una función desde otro módulo sea correcto.
Nuevamente, escriba y ejecute muchos casos de prueba. Los casos triviales son tan indispensables en la resolución de problemas como inteligentes y complejos.
Generar codigo
Usa las técnicas más simples que conoces. A menudo está bien traducir directamente una construcción de lenguaje (como una
if
declaración) a una plantilla de código ligeramente parametrizada, a diferencia de una plantilla HTML.Nuevamente, ignore la eficiencia y concéntrese en lo correcto.
Apunte a una VM de bajo nivel independiente de la plataforma
Supongo que ignoras las cosas de bajo nivel a menos que estés muy interesado en los detalles específicos del hardware. Estos detalles son sangrientos y complejos.
Sus opciones:
Ignorar optimización
La optimización es difícil. Casi siempre la optimización es prematura. Generar código ineficiente pero correcto. Implemente todo el lenguaje antes de intentar optimizar el código resultante.
Por supuesto, las optimizaciones triviales están bien para introducir. Pero evite cualquier astucia y cosas peludas antes de que su compilador sea estable.
¿Y qué?
Si todo esto no es demasiado intimidante para usted, ¡proceda! Para un lenguaje simple, cada uno de los pasos puede ser más simple de lo que piensas.
Ver un 'Hola mundo' de un programa que creó su compilador podría valer la pena.
fuente
Let's Build a Compiler de Jack Crenshaw , aunque no está terminado, es una introducción y un tutorial eminentemente legibles.
La construcción del compilador de Nicklaus Wirth es un muy buen libro de texto sobre los conceptos básicos de la construcción del compilador simple. Se enfoca en el descenso recursivo de arriba hacia abajo, que, seamos sinceros, es MUCHO más fácil que lex / yacc o flex / bison. El compilador PASCAL original que escribió su grupo se hizo de esta manera.
Otras personas han mencionado los diversos libros del Dragón.
fuente
En realidad, comenzaría escribiendo un compilador para Brainfuck . Es un lenguaje bastante obtuso para programar, pero solo tiene 8 instrucciones para implementar. Es lo más simple posible y hay instrucciones C equivalentes para los comandos involucrados si encuentra que la sintaxis es desagradable.
fuente
Si realmente desea escribir solo un código legible por máquina y no está dirigido a una máquina virtual, entonces deberá leer los manuales de Intel y comprender
a. Vinculación y carga de código ejecutable
si. Formatos COFF y PE (para Windows), alternativamente entienda el formato ELF (para Linux)
Mucho más duro que lo dicho. Le sugiero que lea Compiladores e Intérpretes en C ++ como punto de partida (por Ronald Mak). Alternativamente, "vamos a construir un compilador" de Crenshaw está bien.
Si no desea hacer eso, también podría escribir su propia VM y escribir un generador de código dirigido a esa VM.
Consejos: Aprenda Flex y Bison PRIMERO. Luego continúe para construir su propio compilador / VM.
¡Buena suerte!
fuente
El enfoque de bricolaje para un compilador simple podría verse así (al menos así es como se veía mi proyecto uni):
Debe haber mucha literatura que describa cada paso en detalle.
fuente