Evolución del software

De Jose Castillo Aliaga
Ir a la navegación Ir a la búsqueda

La forma más sencilla de controlar una máquina electrónica es con señales eléctricas. La dos señales obvias son el encendido y el apagado. Por tanto, el alfabeto de la máquina sólo tiene dos letras y con esas debe crear todo un lenguaje. Estas dos letras se pueden representar como el 0 y el 1, los números binarios.

Inicios

Los primeros programadores se comunicaban con las máquina sólo con 0's y 1's. Era lo que llamaban el lenguaje máquina. Sin embargo, esto era muy tedioso, por lo que el primer paso para simplificar esta comunicación fue inventar notaciones simbólicas que tradujeran una secuencia de 0 y 1 que representa una instrucción en una palabra. Así, para escribir los programas usaban el lenguaje ensamblador.

add A,B → 1000110010100000

El lenguaje ensamblador tiene las mismas instrucciones que el procesador donde se va a ejecutar. Si bien con el ensamblador ya no se necesita conocer todos los códigos de las instrucciones, este presenta algunas desventajas:

  • No es portable, es decir, no se puede ejecutar un mismo código en dos procesadores distintos.
  • Las instrucciones son de muy bajo nivel. Eso quiere decir que cualquier programa requiere muchas instrucciones.
  • Es complicado de leer y de seguir su secuencia.
  • No permiten crear funciones o reutilizar código de manera sencilla. Con excepción de las macro.

En teoría, con el lenguaje ensamblador se pueden crear los programas más óptimos. Por lo que actualmente se usa sólo en esos casos y en los microcontroladores que no tienen un lenguaje de alto nivel para ser programados.

Compiladores

La poca facilidad para programar en ensamblador y la dificultad para hacer los programas portables hizo que se crearan los lenguajes de alto nivel.

Lenguajes como C, creado para desarrollar Unix, permiten programar con palabras y símbolos más cercanos al lenguaje humano. Más tarde, el compilador se encarga de traducirlo al lenguaje máquina.

Cuando se ejecuta un compilador, este tiene dos fases: la de análisis y la de síntesis:

La fase de análisis comprueba la corrección del código del programa fuente.

Para ello realiza en primer lugar un análisis léxico. Un lenguaje de programación es una representación formal de los algoritmos o funciones del sistema. Por ello tiene una serie de símbolos que pertenecen al lenguaje. El análisis léxico comprueba que todos los símbolos que hay en el código fuente pertenezcan al lenguaje de programación. El análisis léxico, si a nivel de símbolos está correctamente escrito en código fuente, crea una tabla de símbolos, que servirá para el siguiente análisis.

El siguiente análisis es el sintáctico. Este componente del compilador también se llama parser. Realiza su análisis a nivel de sentencia Es mucho más complejo, ya que debe coger los tokens que ha dejado en la tabla de símbolos el analizador léxico y determinar la estructura de cada una de las expresiones del código fuente.

El analizador semántico detecta la validez en cuanto al significado de las expresiones que ha aceptado el análisis semántico. Estas son sus funciones:

  • Detectar si las variables, constantes y funciones han sido declaradas antes de ser utilizadas.
  • Verificar que las variables, constantes y funciones sean accesibles (visibilidad) desde el ámbito en que son utilizadas.
  • Comprobar que los diferentes identificadores solo hayan sido declarados una vez.
  • Comprobaciones de tipos al evaluar las expresiones. Por ejemplo que no se multiplique un número por una cadena o que la expresión a evaluar en un IF sea del tipo booleano.
  • Verificar que no se intente modificar el valor de una constante.
  • Generar la tabla de símbolos.

La fase se síntesis traduce del código fuente al código objeto. En primer lugar realiza una traducción del código fuente al código intermedio. Este no corresponde a ninguna máquina real, sino a una máquina abstracta que define el comportamiento de manera general de cualquier máquina. El objetivo del código intermedio es reducir el número de programas necesarios para construir compiladores.

De esta manera, un compilador tiene un frontend que traduce a código intermedio y un backend que lo traduce a la máquina concreta que lo use. Cada lenguaje de programación tiene su frontend que lo traduce a un mismo lenguaje intermedio. Cada máquina tendrá su backend que coge el lenguaje intermedio y lo traduce a código objeto. Este código luego es enlazado por unos programas llamados Linkers y entonces puede ya ser ejecutado.

La siguiente parte de la fase de síntesis es la optimización del código intermedio. En este punto aprovecha propiedades algebraicas de los operadores, reduce expresiones comunes o elimina bucles innecesarios. A continuación pasa a la generación de código. El código intermedio se pasa a código máquina. Entonces aun se puede optimizar más al aprovechar características propias de la máquina.

Hay varios tipos de compiladores. Los más simples son los de una pasada, los cuales ejecutan una sola vez la fase de análisis y síntesis para retornar el programa. Otros tienen múltiples pasadas ya que necesitan leer el código fuente varias veces e ir generando un código intermedio. Otros son optimizadores, que cambian el código resultante sin afectar al funcionamiento del programa, pero mejorando el rendimiento. Otros compiladores son los cruzados, que permiten general código máquina diferente de la máquina en la que están.

Entre los lenguajes que usan compilador, los más usados son: C. C++, ADA, BASIC, PASCAL, FOLTRAN, COBOL, DELPHY o Visual BASIC.