30 mayo, 2008

CSI XIII: El lenguaje de las máquinas

Muchas personas han oído hablar alguna vez de lenguajes de programación. Se intuye que los lenguajes de programación sirven para decir a un computador qué instrucciones debe ejecutar para llevar a cabo determinada tarea. Claro, que eso es bastante complicado de realizar. Si nosotros pudiésemos hablar al ordenador le diríamos: "conéctate a Internet" o "Inserta al nuevo cliente en la base de datos". Bueno, eso podemos, podemos hablar al computador todo lo que queramos. El problema es que dudo mucho que entienda nuestro lenguaje.

¿Qué lenguaje entiende un computador?. Según el párrafo anterior la respuesta sería: lenguajes de programación. Otro, quizá, más versado, diga: "el de unos y ceros". En realidad es una pregunta trampa, porque el concepto de lenguaje es una abstracción humana. Si llamamos lenguaje al conjunto de señales que emitimos y recibimos para comunicar algo, entonces el lenguaje de las máquina sería el de las señales eléctricas de tensión que según sus niveles, llamamos 0 lógico o 1 lógico. Si en cambio llamamos lenguaje a una construcción de símbolos (o palabras) gobernadas por una gramática, entonces la respuesta está más cerca de la primera.

No sólo los computadores como su PC entienden lenguajes: muchas máquinas, robots de procesos industriales o ascensores entienden algún tipo de lenguaje que los hace funcionar: qué características tiene ese lenguaje es lo que voy a intentar explicar en los siguientes posts.


[Antes de continuar aviso que me estoy metiendo en camisa de once varas, porque éste no es, ni mucho menos, mi campo natural. Avisado queda el lector avanzado]

Nos ayudará a entender qué lenguajes entienden las máquinas una pequeña revisión histórica. La programación más antigua de una máquina conocida es la de los telares de de Jacqard (1801), donde una tarjeta perforada controlaba el movimiento de las agujas. Aquí, por supuesto, no había computación alguna sino que los agujeros en las tarjetas permitían ciertos movimientos. Otras máquinas utilizaron este sistema y cuando nacieron los primeros computadores, basados en dispositivos electromecánicos, la tarjeta perforada se empleó para asignarles instrucciones y entrada de datos.

Durante la IIGM, por ejemplo, los grandes computadores se utilizaban para los complicados cálculos de trayectorias. Richard Feynman, en los laboratorios de Los Álamos estaba encargado de la sección informática. En el libro ¿Está usted de broma, sr. Feynman? narra cómo los ingenieros debían escribir los programas en tarjetas y, secuencialmente, introducirlas en la máquina para que ésta realizara su trabajo. Si te equivocas en el orden las has fastidiado1. Aquí hay que entender que un computador es un procesador de instrucciones, nada más. Y las instrucciones que puede ejecutar son específicas de cada chip o circuito impreso.

Las tarjetas representaban en ocasiones códigos binarios (ceros y unos). Cada código identifica una instrucción o operación que puede hacer la máquina. Las operaciones que puede hacer un procesador son terriblemente sencillas: lee una instrucción de la tarjeta, multiplica un dato por otro, escribe sobre una posición de memoria... muy poco más, no se crean. Al lenguaje de unos y ceros se le llama código máquina.

Se pueden imaginar lo complicado que era programar de este modo un computador. Pero pronto, en la década de 1950 aparecieron una serie de códigos mnemónicos para identificar cada instrucción. Estos códigos consistían en unas pocas letras, que representaban el nombre de la instrucción seguidas de los operandos propios de cada una de ellas. Por ejemplo:

ADD A, #03h

significa, una vez traducida al código máquina:

00100100 00000011

Y representa la instrucción que dice que hay que sumar un número (3) al registro acumulador, que guarda los resultados de la unidad sumadora. Como ven, se trata de un avance significativo, porque programar se convierte en algo mucho más sencillo. Es muy fácil recordar los códigos de un procesador y más difícil equivocarnos. Por ejemplo, si escribo AFD A, #03h, el programa que traduce estos códigos a lenguaje máquina se quejará, porque no existe ningún código llamado AFD.

El programa que traduce estos códigos al lenguaje máquina se llama ensamblador1. Y también se llama así al lenguaje generado por estos códigos. El paso de lenguaje máquina a lenguaje ensamblador produjo la llamada segunda generación de lenguajes.

Pero el ensamblador tiene algunas pegas: la operación que hemos visto, por ejemplo, pertenece al juego de instrucciones del procesador 8051 y, por tanto, no sirve para ningún otro procesador que no sea compatible con éste. Esto significa que un mismo programa no nos sirve para distintas máquinas y que cada vez que una compañía de chips cambie el juego de instrucciones del procesador, necesitaremos reescribir todos los programas que tenemos (por eso se intenta cambiar pocas veces el juego de instrucciones y cuando se hace es para ampliar, pocas veces para quitar).

Efectivamente, el lenguaje ensamblador está demasiado pegado a la máquina: para programar bien tienes que conocer detalles de la arquitectura del procesador. Por ejemplo, si no sabes cómo funciona ni donde está el registro acumulador del procesador, difícilmente sabrás cómo hacer una suma, por más que exista una instrucción llamada 'ADD'.

Era necesario "independizar" de alguna manera el código que escribíamos en cierto lenguaje del modo en que el procesador actúa. Y por cierto, estamos hablando de 'lenguaje', pero está claro que una secuencia de estos códigos se parece a todo menos a un lenguaje tal y como lo hablamos o leemos.

Sin embargo, imaginen poder decir a cualquier procesador algo así como:

si nuevo_nombre es_igual_a Ramon
entonces dime "Hola Ramon"
y_si_no dime "No te conozco"


Pues bien hay maneras de crear lenguajes de esta manera: a la nueva generación de lenguajes que pudo hacer eso: abstraerse de la máquina donde son ejecutados se les llamó lenguajes de tercera generación y los primeros surgieron hacia los años 60. Los lenguajes de tercera generación se separan tanto del computador que están más cerca del ser humano que de la máquina: por su nivel de abstracción se llaman lenguajes de alto nivel.

Y en el siguiente capítulo veremos cómo se puede conseguir hacer eso.

1 Como le pasó al pobre Apu, el creador del primer programa para jugar al tres en raya. Bart desordenó sus tarjetas perforadas.
2 Quizá se pregunten cómo se ha escrito el propio programa ensamblador. Pues los primeros de ellos, claro está, se escribieron en lenguaje máquina.

Por si les interesa: aquí el juego de instrucciones del 8051

Posts relacionados