¿Qué es un compilador?

Aprende cómo funciona un compilador y por qué a veces el código no se compila
En esta guía aprenderás qué es un compilador y cómo funciona. Analizaremos las etapas de compilación y qué determina la elección de un compilador adecuado. Este material te ayudará a comprender mejor cómo el ordenador ejecuta el código de un programa y por qué a veces el código no se compila.
¿Para qué sirve un compilador?
El procesador es la parte más importante de un ordenador. Procesa información, ejecuta comandos del usuario y supervisa el funcionamiento de todos los dispositivos conectados. Sin embargo, el procesador solo puede entender el código de máquina, una serie de 0 y 1 escritos en un orden específico.

¿Por qué 0 y 1? El procesador recibe señales eléctricas. Una señal fuerte se representa con el número 1, mientras que una señal débil se representa con el número 0. Una serie de estos números representa un comando. El procesador lo reconoce y lo ejecuta.

Los programas para los primeros ordenadores consistían en enormes series de 0 y 1. Para escribir un programa de este tipo, los ingenieros utilizaban tarjetas perforadas de cartón flexibles. Los números en las tarjetas se escribían en varias filas, uno tras otro. Para escribir un 1, el programador hacía un agujero en la tarjeta. Las áreas sin agujeros se representaban con un 0.
El ordenador leía la tarjeta perforada con un dispositivo especial y ejecutaba el comando escrito en ella. Para un solo programa, se utilizaban cientos de tarjetas perforadas.

Escribir estos programas era lento y complicado, por lo que los ingenieros comenzaron a crear lenguajes de programación, utilizando palabras y signos para representar comandos. Para que el procesador entendiera qué comandos estaban escritos en el programa, los programadores crearon un compilador, un programa que convierte el código de programación en código de máquina.
¿Cómo funciona un compilador?
La conversión del código de programación en código de máquina se llama compilación. La compilación solo transforma el código, no lo ejecuta. En este momento, se traduce "estáticamente" (es decir, sin ejecución) a código de máquina. Este es un proceso complejo en el que primero se descompone y analiza el texto del programa, y luego se genera un código que el procesador puede entender.

#include <iostream>

int main()
{
    double a=2.5, b=5, P;
    P = 2 * (a + b);
    printf("Ancho del rectángulo - %4.1f", a);// => Ancho del rectángulo - 2.5
    printf("\nLargo del rectángulo - %4.1f", b);// => Largo del rectángulo - 5.0
    printf("\nEl perímetro del rectángulo es %4.1f", P);// => El perímetro del rectángulo es 15.0
    return 0;
}
Después de ejecutar el programa, el compilador necesita determinar qué comandos están escritos en él. Primero, el compilador divide el programa en palabras y signos, llamados tokens, y los guarda en una lista. Este proceso se llama análisis léxico. Su principal objetivo es obtener los tokens.

# include <iostream> int main ( ) { double a = 2.5 , b = 5 , P ;  P = 2 * ( a + b ) ; printf ( " Ancho del rectángulo - % 4.1 f " , a ) ; printf ( " \ n Largo del rectángulo - % 4.1 f " , b ) ; printf ( " \ n El perímetro del rectángulo es % 4.1 f " ,   P ) ; return 0 ; }
Luego, el compilador lee la lista y busca tokens que sean operadores. Estos pueden ser operadores de asignación (=), operadores aritméticos (+, -, *, /), operadores de impresión (printf()) y otros operadores del lenguaje de programación. Estos operadores trabajan con números, texto y variables.

El compilador debe entender qué tokens en la lista están relacionados con un operador. Para hacerlo correctamente, se construye una estructura especial para cada operador: un árbol de análisis o árbol de sintaxis.

Así, la operación P = 2*(a + b) se convertirá en un árbol de sintaxis:
Ahora, cada árbol debe descomponerse en comandos y cada comando debe convertirse en código de máquina. El compilador comienza a leer el árbol de abajo hacia arriba y crea una lista de comandos:
  • Tomar la variable a, tomar la variable b, sumarlas
  • Tomar el resultado de la suma, tomar el número 2 y multiplicarlos
  • Asignar (escribir) el resultado de la multiplicación en la variable P
El compilador verifica los comandos nuevamente, encuentra errores y trata de mejorar el código. Si este paso se completa con éxito, el compilador convierte cada comando en una serie de 0 y 1. Estas series se escriben en un archivo que el procesador puede leer y ejecutar.

10111011 00010001 00000001 10111001 00001101 00000000 10110100 00001110 10001010 00000111 01000011 11001101 00010000 11100010 11111001 11001101 00100000 01001000 01100101 01101100 01101100 01101111 00101100 00100000 01010111 01101111 01110010 01101100 01100100 00100001
¿En qué está escrito un compilador?
En la década de 1950, un grupo de desarrolladores de IBM liderado por John Backus desarrolló el primer lenguaje de programación de alto nivel, Fortran, que permitía escribir programas en un lenguaje comprensible para los humanos. Además del lenguaje, los ingenieros también trabajaron en el compilador. Era un programa con un conjunto de comandos ejecutables que podía compilar otros programas en Fortran, incluida una versión mejorada de sí mismo.

Posteriormente, el lenguaje Fortran y su compilador se utilizaron para escribir compiladores para nuevos lenguajes de programación. Los programadores todavía utilizan este enfoque en la actualidad. Escribir código de máquina es lento e incómodo. Además, puede variar para los procesadores modernos. Tendrías que escribir varias versiones del mismo compilador para diferentes ordenadores. Es más rápido y sencillo escribir un compilador en un lenguaje de programación existente. Para ello, los desarrolladores eligen un lenguaje conveniente y escriben la primera versión de su compilador en él. Será más versátil para los ordenadores y podrá compilar fácilmente una versión mejorada de sí mismo.
¿Qué tipos de compiladores existen?
Ningún lenguaje de programación compilado puede prescindir de un compilador. Algunos compiladores trabajan con varios lenguajes de programación. Sin embargo, el programador también debe tener en cuenta los parámetros del ordenador en el que se ejecutará el programa.

El motivo es que los procesadores modernos difieren en su estructura, por lo que el código de máquina para un procesador puede ser comprensible, mientras que para otro no. Esto también se aplica a los sistemas operativos: un programa puede funcionar en Windows, pero no se ejecutará en Linux o macOS. Por lo tanto, debes utilizar el compilador adecuado que funcione con el procesador y el sistema operativo necesarios.

Si el programa se ejecutará en varios sistemas operativos, se necesita un compilador cruzado, que convierte el código de máquina universal. Por ejemplo, GNU Compiler Collection (GCC) admite C++, Objective-C, Java, Fortran, Ada, Go y diferentes arquitecturas de procesadores.

Los programadores principiantes ni siquiera saben que tienen un compilador en su ordenador. Escriben programas en un entorno de desarrollo integrado que incluye un compilador, a veces más de uno. En este caso, el entorno elige el compilador, no el programador. Por ejemplo, MS Visual Studio admite compiladores para los sistemas operativos Windows, Linux y Android. Al elegir el tipo de proyecto, Visual Studio determina el procesador y el sistema operativo del ordenador y luego selecciona el compilador adecuado.
¿Qué errores puede detectar un compilador?
Cuando el compilador analiza el texto del programa, verifica si el enunciado del operador cumple con los estándares del lenguaje. Si encuentra alguna discrepancia, el compilador muestra un mensaje de error. Hasta que el programador corrija los errores, el compilador no pasará a la siguiente etapa, que es generar el código de máquina para el procesador. En general, el compilador muestra al usuario:
  • errores de declaración de variables o falta de valores iniciales
  • errores de incompatibilidad de tipos
  • errores de sintaxis en la escritura de operadores y funciones
A veces, el compilador puede detectar código que produce un resultado incorrecto durante la ejecución. Sin embargo, aún es posible convertir dicho programa en código de máquina. En este caso, el compilador muestra una advertencia al usuario. Esta respuesta del compilador se asemeja más a una recomendación, pero vale la pena prestar atención a ella. El programador decide si dejar el código con la advertencia o modificar el programa. Al analizar el texto del programa, el compilador no solo busca errores, sino que también simplifica el código. Este proceso se llama optimización. Durante la optimización, el compilador modifica el código del programa, pero las funciones que realiza el programa siguen siendo las mismas.
Conclusiones y recomendaciones
Un compilador es un traductor entre el programador y el procesador. Convierte el texto del programa en código de máquina, detecta errores en el programa y optimiza su funcionamiento. Al elegir dónde compilar un programa, es importante recordar que el código de máquina para procesadores y sistemas operativos será diferente, por lo que debes seleccionar el compilador adecuado. Cuanto más precisamente el compilador identifique los comandos, más correcto y rápido funcionará el programa. Para ello, sigue estas recomendaciones sencillas:
  • utiliza comandos simples y comprensibles;
  • ten en cuenta la correspondencia de los tipos de datos;
  • escribe el código con cuidado, evitando errores de sintaxis;
  • evita acciones repetitivas y variables innecesarias.
Preguntas frecuentes
¿Cuál es la diferencia entre un compilador y un intérprete?

Un compilador es un programa que realiza la conversión del texto del programa a otro formato, generalmente código de máquina, sin ejecutarlo, de forma estática. Luego, este programa se puede ejecutar. Un intérprete ejecuta el código de inmediato y lo ejecuta durante la lectura. No hay una etapa intermedia como en la compilación.
Recursos adicionales
Leer otros artículos de Guías
Lea otros artículos relevantes del mundo de la tecnología y el espíritu empresarial.