Lenguajes de
Programación
Al
desarrollarse las primeras computadoras electrónicas, se vio la necesidad de
programarlas, es decir, de almacenar en memoria la información sobre la tarea
que iban a ejecutar. Las primeras se usaban como calculadoras simples; se les
indicaban los pasos de cálculo, uno por uno.
John Von Neumann desarrolló el modelo
que lleva su nombre, para describir este concepto de "programa
almacenado". En este modelo, se tiene una abstracción de la memoria como
un conjunto de celdas, que almacenan simplemente números. Estos números pueden
representar dos cosas: los datos, sobre los que va a trabajar el programa; o
bien, el programa en sí.
¿Cómo
es que describimos un programa como números? Se tenía el problema de
representar las acciones que iba a realizar la computadora, y que la memoria,
al estar compuesta por switches correspondientes al
concepto de bit, solamente nos permitía almacenar
números binarios.
La
solución que se tomó fue la siguiente: a cada acción que sea capaz de realizar
nuestra computadora, asociarle un número, que será su código de operación (opcode) . Por ejemplo, una
calculadora programable simple podría asignar los opcodes :
1 =
SUMA, 2 = RESTA, 3 = MULTIPLICA, 4 = DIVIDE.
Supongamos
que queremos realizar la operación 5 * 3 + 2, en la calculadora descrita
arriba. En memoria, podríamos "escribir" el programa de la siguiente
forma:
Localidad
Opcode Significado Comentario 0 5 5
En esta localidad, tenemos el primer número de la fórmula 1 3 * En esta
localidad, tenemos el opcode que representa la
multiplicación. 2 3 3 En esta localidad, tenemos el
segundo número de la fórmula 3 1 + En esta localidad, tenemos el opcode que representa la suma. 4 2 2
En esta localidad, tenemos el último número de la fórmula
Podemos
ver que con esta representación, es simple expresar las operaciones de las que
es capaz el hardware (en este caso, nuestra calculadora imaginaria), en la
memoria.
La
descripción y uso de los opcodes es lo que llamamos
lenguaje de máquina . Es decir, la lista de códigos
que la máquina va a interpretar como instrucciones, describe las capacidades de
programación que tenemos de ella; es el lenguaje más primitivo, depende
directamente del hardware, y requiere del programador que conozca el
funcionamiento de la máquina al más bajo nivel.
los
lenguajes más primitivos fueron los lenguajes de máquina. Esto, ya que el
hardware se desarrolló antes del software, y además cualquier software
finalmente tiene que expresarse en el lenguaje que maneja el hardware.
La
programación en esos momentos era sumamente tediosa, pues el programador tenía
que "bajarse" al nivel de la máquina y decirle, paso a pasito, cada
punto de la tarea que tenía que realizar. Además, debía expresarlo en forma
numérica; y por supuesto, este proceso era propenso a errores, con lo que la
productividad del programador era muy limitada. Sin embargo, hay que recordar
que en estos momentos, simplemente aún no existía alternativa.
La programación consiste en
desarrollar programas para procesar información.
programación como termino se utiliza
para designar la creacion de programas a pequeña
escala, el desarrollo de sistemas complejos se denomina ingenieria
de software.
Una computadora es
totalmente inutil si no dispone de un programa capaz
de procesar información.
Para que se realize dicho procesamiento de
información habra sido necesario construir un
ordenador (hardware), pensar y crear un programa (software) y ejecutar dicho
programa o aplicacion en el computador.
La ultima de estas fases es la que realiza el usuario,
las anteriores son realizadas por tecnicos que
construyen el hardware y por programadores que desarrollan el software.
programación e ingenieria de software son complementarias entre si. Para el desarrollo de grandes sistemas informaticos se divide el trabajo en tareas que diversos
programadores desarrollaran. Al terminar se unen las piezas como en un puzzle
para completar el sistema en si. Asi programación tambien se aplica para el desarrollo de grandes sistemas en
las ingenierias de software.
La programación tiene como
objetivo el tratamiento de la información correctamente, con lo que se espera
que un programa de el resultado correcto y no uno erroneo.
Asi que cada aplicacion
debe funcionar segun lo esperado en terminos de programación.
Otro objetivo
fundamental de la programación es que sean de codigos
claros y legibles, con lo que si un programador inicia un programa y no lo
termina, otro programador sea capaz de entender la codificacion
y poder terminarlo.
Normalmente en programación existen ciertas normas no escritas de como han de
nombrarse los componentes, objetos o controles de cada sistema, asi como sus variables que deben ser relativas al termino
al cual se van a vincular. Por ejemplo el texto que contenga la edad del
individuo se llamaria TxtEdad,
y su variable se llamaria Edad.
Por ultimo la programación
pretende que sus programas sean utiles y eficientes.
De multitud de maneras la programación nos dara el
mismo resultado de un programa, un buen programador llegara al mismo resultado
con un minimo de codigo y
de la forma más clara y logica posible.
De los anteriormente
nombrados objetivos de la programación el más importante es el de la correccion, ya que un codigo
claro y legible facilita el mantenimiento de la aplicacion
o sistema.
Un computador no hará nada si no se le dan órdenes.
Estas pueden ser tipeadas directamente en el teclado
pero, salvo que la tarea sea muy sencilla -como hacer alguna operación
aritmética-, sería muy ineficiente, por lo cual se requiere redactar primero un
programa, con la serie completa de instrucciones para que la máquina realice lo
que deseamos. Pero si hablamos tanto de "tipear"
órdenes directas como de agruparlas en un programa, estamos hablando de usar un
teclado parecido al de una máquina de escribir, con letras, cifras y signos. Ha
de usarse, por lo tanto, un determinado lenguaje... ¡que el computador,
originalmente, no entiende!
Todas las
"aplicaciones" (software para el "usuario final") que
conocemos han debido ser creadas especificando primero sus funciones y
traduciendo éstas en "instrucciones" comprensibles por la máquina.
Para ésto, el o los programadores utilizan un
determinado "lenguaje de programación", que es como un idioma: cuenta
con un diccionario (los "comandos") y una gramática (reglas de
sintaxis). El programador traduce las especificaciones de funciones y
operaciones (que están en su idioma natural y/o en gráficos que especifican su
secuencia) en este idioma, elaborando un producto llamado "programa
fuente".
Este programa fuente ha de ser luego traducido (por el mismo computador) en el
"lenguaje de máquina", que es el que "entiende" el
microprocesador. La traducción, por lo tanto, debe hacerse teniendo en cuenta
el "lenguaje" propio del chip procesador (de ahí que un mismo
programa tendrá una versión "para PowerPC
(PPC)", "para Pentium", etc.
Esta traducción puede hacerse de dos maneras: en forma previa al uso, con lo
cual se genera el "programa compilado" o "programa objeto",
o bien se instala junto con el programa de traducción en el computador del
usuario y se hace que la máquina traduzca las órdenes a medida que lee el
programa fuente.
A diferencia de un programa interpretado, un programa compilado (como la
mayoría de las aplicaciones que hoy puede comprar el usuario común) sólo puede
ser utilizado, pero no puede ser leído, revisado o modificado: la compilación
lo hace ilegible. Tratar de "decompilarlo"
para conocer su estructura y modo de funcionar (lo cual se llama "reverse engineering") es muy complejo y normalmente prohibido
en las condiciones de venta. Así, la versión "fuente" constituye un
"secreto comercial", celosamente guardado por los fabricantes.
Veremos, al final del capítulo, que este secreto puede ser algunas veces perjudicial
para los usuarios.
El
primer gran avance que se dio, como ya se comentó, fue la abstracción dada por
el Lenguaje Ensamblador, y con él, el nacimiento de las primeras herramientas
automáticas para generar el código máquina. Esto redujo los errores triviales,
como podía ser el número que correspondía a una operación, que son sumamente
engorrosos y difíciles de detectar, pero fáciles de cometer. Sin embargo, aún
aquí es fácil para el programador perderse y cometer errores de lógica, pues
debe bajar al nivel de la forma en que trabaja el CPU, y entender bien todo lo
que sucede dentro de él.
Con el
desarrollo en los 50s y 60s de algoritmos de más elevado nivel, y el aumento de
poder del hardware, empezaron a entrar al uso de computadoras científicos de
otras ramas; ellos conocían mucho de Física, Química y otras ramas similares,
pero no de Computación, y por supuesto, les era sumamente complicado trabajar
con lenguaje Ensamblador en vez de fórmulas. Así, nació el concepto de Lenguaje
de Alto Nivel, con el primer compilador de FORTRAN (FORmula
TRANslation), que, como su nombre indica, inició como
un "simple" esfuerzo de traducir un lenguaje de fórmulas, al lenguaje
ensamblador y por consiguiente al lenguaje de máquina. A partir de FORTRAN, se
han desarrollado innumerables lenguajes, que siguen el mismo concepto: buscar
la mayor abstracción posible, y facilitar la vida al programador, aumentando la
productividad, encargándose los compiladores o intérpretes de traducir el
lenguaje de alto nivel, al lenguaje de computadora.
Hay
que notar la existencia de lenguajes que combinan características de los de
alto nivel y los de bajo nivel (es decir, Ensamblador). Mi ejemplo favorito es
C: contiene estructuras de programación de alto nivel, y la facilidad de usar
librerías que también son características de alto nivel; sin embargo, fue
diseñado con muy pocas instrucciones, las cuales son sumamente sencillas,
fáciles de traducir al lenguaje de la máquina; y requiere de un entendimiento
apropiado de cómo funciona la máquina, el uso de la memoria, etcétera. Por
ello, muchas personas consideramos a lenguajes como C (que fue diseñado para
hacer sistemas operativos), lenguajes de nivel medio.
Las tendencias en los lenguajes de
programación
El
estudio de los lenguajes de programación agrupa tres intereses diferentes; el
del programador profesional, el del diseñador del lenguaje y del Implementador del lenguaje.
Además,
estos tres trabajos han de realizarse dentro de las ligaduras y capacidades de
la organización de una computadora y de las limitaciones fundamentales de la
propia "calculabilidad". El termino
"el programador" es un tanto amorfo, en el sentido de que camufla
importantes diferencias entre distintos niveles y aplicaciones de la
programación. Claramente el programador que ha realizado un curso de doce
semanas en COBOL y luego entra en el campo del procesamiento de datos es
diferente del programador que escribe un compilador en Pascal, o del
programador que diseña un experimento de inteligencia artificial en LISP, o del
programador que combina sus rutinas de FORTRAN para resolver un problema de
ingeniería complejo, o del programador que desarrolla un sistema operativo
multiprocesador en ADA.
En
esta investigación, intentaremos clarificar estas distinciones tratando
diferentes lenguajes de programación en el contexto de cada área de aplicación
diferente. El "diseñador del lenguaje" es también un termino algo
nebuloso. Algunos lenguajes (como APL y LISP) fueron diseñados por una sola
persona con un concepto único, mientras que otros (FORTRAN y COBOL) son el
producto de desarrollo de varios años realizados por comités de diseño de
lenguajes.
El
"Implementador del lenguaje" es la persona
o grupo que desarrolla un compilador o interprete para un lenguaje sobre una
maquina particular o tipos de maquinas. Mas frecuentemente, el primer
compilador para el lenguaje Y sobre la maquina X es desarrollada por la
corporación que manufactura la maquina X . Por
ejemplo, hay varios compiladores de Fortran en uso;
uno desarrollado por IBM para una maquina IBM, otro desarrollado por DEC para
una maquina DEC, otro por CDC, y así sucesivamente. Las compañías de software
también desarrollan compiladores y también lo hacen los grupos de investigación
de las universidades. Por ejemplo, la universidad de Waterloo
desarrolla compiladores para FORTRAN Y PASCAL, los cuales son útiles en un
entorno de programación de estudiantes debido a su superior capacidad de
diagnostico y velocidad de compilación.
Hay
también muchos aspectos compartidos entre los programadores, diseñadores de un
lenguaje implementadores del mismo. Cada uno debe
comprender las necesidades y ligaduras que gobiernan las actividades de los
otros dos.
Hay,
al menos, dos formas fundamentales desde las que pueden verse o clasificarse
los lenguajes de programación: por su nivel y por principales aplicaciones.
Además, estas visiones están condicionadas por la visión histórica por la que
ha transcurrido el lenguaje. Además, hay cuatro niveles distintos de lenguaje
de programación.
Los
"Lenguajes Declarativos" son los mas
parecidos al castellano o ingles en su potencia expresiva y funcionalidad están
en el nivel mas alto respecto a los otros. Son fundamentalmente lenguajes de
ordenes, dominados por sentencias que expresan "Lo que hay que hacer"
en ves de "Como hacerlo". Ejemplos de estos lenguajes son los
lenguajes estadísticos como SAS y SPSS y los lenguajes de búsqueda en base de
datos, como NATURAL e IMS. Estos lenguajes se desarrollaron con la idea de que
los profesionales pudieran asimilar mas rápidamente el
lenguaje y usarlo en su trabajo, sin necesidad de programadores o practicas de
programación.
Los
lenguajes de " Alto Nivel" son los mas
utilizados como lenguaje de programación. Aunque no son fundamentalmente
declarativos, estos lenguajes permiten que los algoritmos se expresen en un
nivel y estilo de escritura fácilmente legible y comprensible por otros
programadores. Además, los lenguajes de alto nivel tienen normalmente las
características de " Transportabilidad". Es
decir, están implementadas sobre varias maquinas de forma que un programa puede
ser fácilmente " Transportado " (Transferido) de una maquina a otra
sin una revisión sustancial. En ese sentido se llama "Independientes de la
maquina". Ejemplos de estos lenguajes de alto nivel son PASCAL
, APL y FORTRAN (para aplicaciones científicas ), COBOL (para
aplicaciones de procesamiento de datos), SNOBOL( para aplicaciones de
procesamiento de textos), LISP y PROLOG (para aplicaciones de inteligencia
artificial), C y ADA (para aplicaciones de programación de sistemas) y PL/I
(para aplicaciones de propósitos generales) .
Los
"Lenguajes Ensambladores" y los "Lenguajes Maquina" son
dependientes de la maquina. Cada tipo de maquina, tal como VAX de digital,
tiene su propio lenguaje maquina distinto y su lenguaje ensamblador asociado.
El lenguaje Ensamblador es simplemente una representación simbólica del
lenguaje maquina asociado, lo cual permite una programación menos tediosa que
con el anterior. Sin embargo, es necesario un conocimiento de la arquitectura mecánica
subyacente para realizar una programación efectiva en cualquiera de estos
niveles lenguajes.
Los
siguiente tres segmentos del programa equivalentes exponen las distinciones
básicas entre lenguajes maquina, ensambladores de alto nivel:
Como
muestra este ejemplo, a mas bajo nivel de lenguaje mas
cerca esta de las características de un tipo e maquina particular y mas alejado
de ser comprendido por un humano ordinario. Hay también una estrecha relación ( correspondencia 1:1 ) entre las sentencias en lenguaje
ensamblador y sus formas en lenguaje maquina codificada. La principal
diferencia aquí es que los lenguajes ensambladores se utilizan símbolos (X,Y,Z,A para " sumar", M
para "multiplicar"), mientras que se requieren códigos numéricos
(OC1A4, etc.) para que lo comprenda la maquina.
La
programación de un lenguaje de alto nivel o en un lenguaje ensamblador
requiere, por tanto, algún tipo de interfaz con el lenguaje maquina para que el
programa pueda ejecutarse. Las tres interfaces mas comunes: un "ensamblador" , un "compilador" y un
"interprete". El ensamblador y el compilador traduce el programa a
otro equivalente en el lenguaje X de la maquina "residente" como un
paso separado antes de la ejecución. Por otra parte, el interprete
ejecuta directamente las instrucciones en un lenguaje Y de alto nivel, sin un
paso de procesamiento previo.
La
compilación es, en general, un proceso mas eficiente que la interpretación para
la mayoría de los tipos de maquina. Esto se debe principalmente a que las
sentencias dentro de un "bucle" deben ser reinterpretadas cada vez
que se ejecutan por un interprete. Con un compilador.
Cada sentencia es interpretada y luego traducida a lenguaje maquina solo una
vez.
Algunos
lenguajes son lenguajes principalmente interpretados, como APL, PROLOG y LISP.
El resto de los lenguajes -- Pascal, FORTRAN, COBOL, PL/I, SNOBOL, C, Ada y
Modula-2 – son normalmente lenguajes compilados. En algunos casos, un
compilador estará utilizable alternativamente para un lenguaje interpretado
(tal como LISP) e inversamente (tal como el interprete SNOBOL4 de los
laboratorios Bell). Frecuentemente la interpretación
es preferible a la compilación en un entorno de programación experimental o de
educación, donde cada nueva ejecución de un programa implicado un cambio en el
propio texto del programa. La calidad de diagnosis y depuración que soportan
los lenguajes interpretados es generalmente mejor que la de los lenguajes
compilados, puesto que los mensajes de error se refieren directamente a
sentencias del texto del programa original. Además, la ventaja de la eficiencia
que se adjudica tradicionalmente a los lenguajes compilados frente a los
interpretados puede pronto ser eliminado, debido a la evolución de las maquinas
cuyos lenguajes son ellos mismos1lenguajes de alto nivel. Como ejemplo de estos
están las nuevas maquinas LISP, las cuales han sido diseñadas recientemente por
Symbolics y Xerox Corporations.
Los
lenguajes de Programación son tomados de diferentes perspectivas. Es importante
para un programador decidir cuales conceptos emitir o cuales incluir en la
programación. Con frecuencia el programador es osado a usar combinaciones de
conceptos que hacen al lenguaje "DURO" de usar, de entender e
implementar. Cada programador tiene en mente un estilo particular de
programación, la decisión de incluir u omitir ciertos tipos de datos que pueden
tener una significativa influencia en la forma en que el Lenguaje es usado, la
decisión de usar u omitir conceptos de programación o modelos.
Existen
cinco estilo de programación y son los siguientes:
1.
Orientados a Objetos.
2.
Imperativa : Entrada, procesamiento y salidas
de Datos.
3.
Funcional : "Funciones", los datos
son funciones, los resultados pueden ser un valor o una función.
4.
Lógico : {T,F} +
operaciones lógicos (Inteligencia Artificial).
5.
Concurrente : Aún esta en proceso de
investigación.
El programador, diseñador e implementador
de un lenguaje de programación deben comprender la evolución histórica de los
lenguajes para poder apreciar por que presentan características diferentes. Por
ejemplo, los lenguajes "mas jóvenes" desaconsejan (o prohiben) el uso de las sentencias GOTO como mecanismo de
control inferior, y esto es correcto en el contexto de las filosofías actuales
de ingeniería del software y programación estructurada. Pero hubo un tiempo en
que la GOTO, combinada con la IF, era la única estructura de control
disponible; el programador no dispone de algo como la construcción WHILE o un
IF-THEN-ELSE para elegir. Por tanto, cuando se ve un lenguaje como FORTRAN, el
cual tiene sus raíces en los comienzos de la historia de los lenguajes de
programación, uno no debe sorprenderse de ver la antigua sentencia GOTO dentro
de su repertorio.
Lo mas importante es que
la historia nos permite ver la evolución de familias de lenguajes de
programación, ver la influencia que ejercer las arquitecturas y aplicaciones de
las computadoras sobre el diseño de lenguajes y evitar futuros defectos de
diseño aprendido las lecciones del pasado. Los que estudian se han elegido
debido a su mayor influencia y amplio uso entre los programadores, así como por
sus distintas características de diseño e implementacion.
Colectivamente cubren los aspectos más importantes con los que ha de
enfrentarse el diseñado de lenguajes y la mayoría de las aplicaciones con las
que se enfrenta el programador. Para los lectores que estén interesados en
conocer con mas detalle la historia de los lenguajes
de programación recomendamos las actas de una recién conferencia (1981) sobre
este tema, editadas por Richard Wexelblat. Vemos que
FORTRAN I es un ascendente directo de FORTRAN II, mientras que FORTRAN, COBOL,
ALGO 60, LISP, SNOBOL y los lenguajes ensambladores, influyeron en el diseño de
PL/I.
También varios lenguajes están prefijados por las
letras ANS. Esto significa que el American National Standards Institute ha adoptado esa versión del lenguaje como el
estándar nacional. Una vez que un lenguaje esta estandarizado, las maquinas que
implementan este lenguaje deben cumplir todas las especificaciones estándares,
reforzando así el máximo de transportabilidad de
programas de una maquina a otra. La policía federal de no comprar maquinas que
no cumplan la versión estándar de cualquier lenguaje que soporte tiende a
"fortalecer" el proceso de estandarizacion,
puesto que el gobierno es, con mucho, el mayor comprador de computadoras de la
nación.
Finalmente, la notación algebraica ordinaria, por
ejemplo, influyo fuertemente en el diseño de FORTRAN y ALGOL. Por otra parte, el ingles influyo en el desarrollo del COBOL. El lambda calculo de Church dio los
fundamentos de la notación funcional de LISP, mientras que el algoritmo de Markov motivo el estilo de reconocimiento de formas de
SNOBOL. La arquitectura de computadoras de Von Neumann, la cual fue una evolución de la maquina mas
antigua de Turing, es el modelo básico de la mayoría
de los diseños de computadoras de las ultimas tres décadas. Esta maquina no
solo influyeron en los primeros lenguajes sino que también suministraron el
esqueleto operacional sobre el que evoluciono la mayoría de la programación de
sistemas.
Una discusión mas directa
de todos estos primeros modelos no están entre los objetivos de este texto. Sin
embargo, es importante apuntar aquí debido a su fundamental influencia en la
evolución de los primeros lenguajes de programación, por una parte, y por su
estado en el núcleo de la teoría de la computadora, por otra. Mas sobre este
punto, cualquier algoritmo que pueda describirse en ingles o castellano puede
escribirse igualmente como una maquina de Turing
(maquina de Von Neumann),
un algoritmo de Markov o una función recursiva. Esta
sección, conocida ampliamente como "tesis de Church",
nos permite escribir algoritmos en distintos estilos de programación
(lenguajes) sin sacrificar ninguna medida de generalidad, o potencia de
programación, en la transición.
La programación orientada a
objetos, intenta simular el mundo real a traves del
significado de objetos que contiene caracteristicas y
funciones. Los lenguajes orientados a objetos se clasifican como lenguajes de
quinta generacion.
Como su mismo nombre indica, la
programación orientada a objetos se basa en la idea de un objeto, que es una combinacion de variables locales y procedimientos llamados metodos que juntos conforman una entidad de programación.
El termino encapsulacion
se usa para describir la combinacion de estructuras
de datos y de metodos que son manipulados por el
objeto. La llamada a un objeto es lo que se denomina pasar un "aviso"
a un objeto.
En la programación orientada a
objetos, encapsular significa, reunir y controlar el grupo resultante como un
todo y no individualmente.
En la programación orientada a
objetos la abstraccion es un termino
externo al objeto, que controla la forma en que es visto por los demas.
En la programación orientada a
objetos la modularidad se considera de la siguiente
manera: Un programa grande siempre sera más
complicado que la suma de varios programas pequeños, con lo que se considera
ventajoso dividir un gran sistema en diversos modulos.
En la programación orientada a objetos
tenemos la jerarquia, la cual consiste en la clasificacion y organizacion de
las abstracciones segun su naturaleza. El más claro
ejemplo de jerarquia es la herencia.
En la programación orientada a
objetos se define la herencia como una jerarquia de
extracciones, y la relacion entre clases, donde se
comparte la estructura y el comportamiento de una o más clase considerada como
clases superiores o una superclase, con lo cual se resume que la herencia es
una unidad independiente por si misma heredada de una abstraccion
o superclase. Un ejemplo cotidiano lo encontramos en las aplicaciones que
existen cactualmente en el mercado, donde un
formulario cualquiera hereda las caracteristicas de uan ventana del sistema operativo Windows (Maximizar,
Minimizar, Cerrar)
LENGUAJES DE BAJO Y ALTO NIVEL
En efecto, lo único que
entienden y pueden manipular la Unidad de Control y la Unidad Aritmética son
dígitos binarios o sea series de ceros y unos (paso o no paso de corriente
eléctrica). Así, mientras el hombre usa un "lenguaje natural"
(idioma) muy rico en significados, la máquina usa un sistema en que existiría
un sólo "significado": la diferencia entre 0 y 1 (o sea un bit de información).
¿Cómo lograr más? Simplemente concibiendo un nuevo lenguaje constituído
de "bloques" de dígitos binarios (llamados "bytes").
Este es el primer paso o "primer nivel" en la construcción de
lenguajes de computación.
1er Nivel
Se dice que el código binario es de "bajo nivel" o "primer
nivel" (porque al usar pocos signos logra muy dificilmente
expresar cosas complicadas), mientras un lenguaje humano es de "muy alto
nivel" (con una cantidad mayor de signos y con reglas combinatorias logra
expresar con facilidad cosas muy complicadas). Todo el esfuerzo, entonces, para
facilitar la comunicación del hombre con el computador, ha de centrarse en el
desarrollo de lenguajes de mayor nivel.
El fabricante de un procesador fija los bloques de bits que llevarán a la CPU
(unidad central de procesos) a reconocer y realizar diferentes operaciones. Este
el el "código de máquina", primer lenguaje
que la máquina puede interpretar y transformar en acciones. Pero es
evidentemente muy difícil de usar para un ser humano. Supongamos que quiera
hacer imprimir y para ello deba decir "10011101 11100010": ¿cómo recordar
órdenes de este tipo y no equivocarse al escribirlas?
Practicamente nadie trabaja hoy a este nivel, excepto
los diseñadores de "chips" procesadores. Del mismo modo que es
posible pasar de un sistema binario a un sistema decimal (más comprensible y
más desarrollado en términos de signos legibles) es posible asociar a los
bloques de bits no solo valores decimales sino también otros signos. Esto lleva
a un segundo nivel de expresión.
Hemos de recordar que el teclado equivale a un conjunto de interruptores: cada
tecla que pulsamos equivale a cerrar brevemente uno de éstos, es decir
produciendo un bit de información (no teclear = 0,
teclear =1). Pero dado que hay muchas teclas, hay que identificar cada una, por
lo cual pulsar una tecla significa activar un circuito que generará un
"bloque" binario (byte) específico que
identifica esa tecla.
A cada tecla está asociado un código decimal y un código hexadecimal.
El hexadecimal (16 caracteres: de 0 a 9 y de la A a la F) es el que sirve de intermediario a la máquina, para
traducir nuestro código natural (alfanumérico) al código binario. Algunos
ejemplos de equivalentes decimales y hexadecimales
del teclado son los siguientes:
Tecla |
Valor Decimal |
Valor Hexadecimal |
1 |
49 |
31 |
2 |
50 |
32 |
9 |
57 |
39 |
a |
97 |
61 |
b |
98 |
62 |
i |
105 |
69 |
j |
106 |
6A |
k |
107 |
6B |
o |
111 |
6F |
p |
112 |
70 |
z |
122 |
7A |
! |
33 |
21 |
? |
63 |
3F |
= |
61 |
3D |
Esto permite no sólo reconocer los signos del
teclado y reproducirlos (como en un procesador de palabras), sino también
atribuir a cada tecla otra función y hacer -por ejemplo- que transmita una
orden a la CPU. Así, podríamos ordenar la impresión con un simple "?", o -como es común hoy en los Macintosh- apretando
simultáneamente una tecla de "comando" y la letra "P".
2º Nivel
La creación de un lenguaje más comprensible por el hombre consiste por lo tanto
en establecer la equivalencia de bloques binarios con signos de nuestro
lenguaje habitual. Para permitir la programación (secuencia de comandos), se
usan pequeños conjuntos de signos ("palabras") de fácil memorización,
con las cuales se redactan programas, por ejemplo "ADC" significará
"sumar con reserva" (en inglés: "ADd with Carry"). Este tipo de
lenguaje se llama "ensamblador" o "Assembler"
(Vea más adelante la "Descripción" de Lenguajes). La máquina misma
hará la tarea de traducirlo en código binario, para seguir las instrucciones,
gracias a otro programa cuya función es traducir la expresión humana en
"lenguaje de máquina" (binario). Es programa se llama
"compilador".
Aunque el Assembler es un inmenso progreso en
relación al código binario, su desventaja reside en que permanece estrechamente
ligado a los bloques binarios que reconoce la CPU (es decir al
"hardware"). Para facilitar más la tarea, se han inventado lenguajes
de "alto nivel", es decir más cercanos al modo de expresar del hombre
que de operación de la máquina. Los primeros y más comunes son los llamados de
"tercera generación", más fáciles de manejar y más independientes de
las características técnicas de los procesadores. Ahora, hasta un aficionado
puede llegar a redactar un programa, sin tener que preocuparse por el código
binario o de ensamble: si un programa traductor podía resolver la
transformación de bloques de signos en bloques binarios, era cosa de extender
las habilidades del traductor para "enseñar" a la máquina cómo
"entender" un lenguaje más complejo y agregar mecanismos automáticos
de manejo de la memoria para poder utilizar lenguajes aún más comprensibles.
3er Nivel
El avance en el desarrollo de "compiladores" e
"intérpretes" (los dos tipos de programas traductores) ha sido por lo
tanto fundamental en el desarrollo de los lenguajes de "3º
generación" cuyas ventajas además de la facilidad de aprendizaje y
lectura/escritura son las facilidades de corrección, transformación y conversión
de un lenguaje a otro.
Los más antiguos son el FORTRAN (para aplicaciones matemáticas y científicas) y
el COBOL (para aplicaciones de administración y contabilidad).
Con los micro-computadores nació el BASIC ("para principiantes"). Mucha importancia
tiene el PASCAL, especialmente en la docencia. (Más detalles luego, en la
"Descripción" de los lenguajes).
Generadores de aplicaciones o 4º Nivel
Posteriormente, usando estos lenguajes, se han redactado programas destinados a
facilitar un número variado de operaciones en campos de aplicación específicos
como simulación de fenómenos físicos, manipulación de datos estadísticos, etc.
Los más avanzados y flexibles de estos programas son las planillas electrónicas
u hojas de cálculo y los programas de administración de archivos o bases de
datos (Vea el capítulo "Aplicaciones").
Dados que tales aplicaciones no "hacen nada" sin que el usuario
defina ciertas estructuras y ciertas operaciones, pueden ser consideradas como
"generadores" de aplicaciones, aunque este nombre se reserva
habitualmente para niveles más avanzados en que los usuarios pueden generar
sistemas muy diferentes unos de otros, con "herramientas" que se
parecen a lenguajes de programación. Estas herramientas conforman los lenguajes
de cuarto nivel que son por esencia "programas para crear programas"
con una finalidad específica, como el "CASE" destinado a facilitar el
trabajo de los analistas de sistemas.
Todo lenguaje, para
permitir la programación, ha de contener diversos tipos de instrucciones:
Instrucciones simples:
·
de entrada: para buscar y
recoger datos en la memoria central o auxiliar, o bien obtenerla por
interacción con el usuario (p.ej. mensaje en el
monitor de video que debe ser contestado en el teclado),
·
de salida: datos expuestos
en el monitor de video o impresos, o transmitidos en una red,
·
de asignación: asignar un
valor a una variable, sea directamente (p.ej.
Variable1 = 15) sea por cálculo (p.ej. Var3 = Var1 +
Var2).
Instrucciones compuestas:
·
de secuencia: por principio
el orden dado a las instrucciones determina el orden en que se ejecuten, salvo
instrucciones especiales de "salto" como las previstas en
instrucciones de alternación o iteración.
Toda instrucción compuesta debe tener una ENTRADA y una SALIDA. Puede siempre
reemplazarse una instrucción simple por una compuesta manteniéndose el
principio de secuencialidad de las instrucciones.
·
de alternación: escoger
entre dos alternativas en función del cumplimiento de una condición (p.ej. if X > 15 then ... else ...: si X es mayor
que 15 haga esto, sino este otro)
·
de iteración: ejecutar
repetidamente un grupo de instrucciones mientras se cumpla una condición (p.ej. para contar de 1 hasta 10: N=1,
while N < 10 repeat {N =
N+1, print N}. O sea
mientras N sea inferior a 10, agregue 1 al valor anterior de N).
En este ejemplo, se introduce un concepto muy
importante en el desarrollo y uso de lenguajes de programación: la
recursividad, factible por el hecho de que lo que se manipula es siempre un
valor colocado en alguna celda de memoria. Así, si bien la matemática no puede
aceptar una ecuación como N=N+1, aquí estamos ante
una instrucción (no una ecuación) que significa "tomar el valor que está
en una celda llamada N, sumarle 1 y volver a colocar el nuevo valor en la celda
llamada N. Ésta es una "instrucción de asignación".
Algunos lenguajes (el Algol y sus descendientes como Pascal y "C", y
también Lisp y Prolog en
que este procedimiento constituye la esencia del lenguaje) van aún más lejos y
permiten una recursividad consistente en la posibilidad de que una instrucción
compuesta ordene la ejecución de sí misma. El siguiente podría ser una breve ejemplo:
Para imprimir una lista con una instrucción recursiva, basta tener en cuenta
que una lista se compone de una cabeza (primer elemento) y una cola (el resto).
Obviamente la cola es también una lista, por lo cual se le puede aplicar el
procedimiento consistente en separar su cabeza de su cola, y así sucesivamente,
hasta encontrar una cola vacía. Por lo tanto, se puede ordenar algo así:
imprimir lista = imprimir cabeza
lista =
cola [borra de la lista la cabeza ya
impresa]
si lista no es vacía,
imprimir lista [orden de recursión]
sino: fín.
PROGRAMACION ESTRUCTURADA
Como explicado a propósito
de las "Instrucciones", todo programa se compone de una secuencia de
instrucciones que pueden ser simples o compuestas. La presencia de
instrucciones que deban repetirse muchas veces no sólo se expresa en las
iteraciones, donde dicha repetición es inmediata. Existen muchos casos en que
la repetición no es un flujo contínuo sino
dependiente de otras operaciones o condiciones que son muy variables. Es el
caso por ejemplo de las instrucciones para leer o grabar datos en un disco.
La programación estructurada, que es una forma de redacción de programas
(obligatoria u optativa, según el lenguaje escogido), se hace cargo de este
requisito facilitando la constitución de "paquetes" de instrucciones
(llamados "sub-rutinas" o
"procedimientos"), los que pueden escribirse una sola vez y ser
"llamados" (utilizados) las veces que se requiera.
Además, pone énfasis en la conveniencia de facilitar la lectura de los
programas haciendo más visible la dependencia jerárquica de las instrucciones
compuestas mediante "indentación", es decir
modificando el ancho del margen izquierdo para cada grupo de instrucciones.
Los 'SISTEMAS
OPERATIVOS" son programas de funcionamiento permanente, no específicos,
que deben cargarse en la memoria principal antes de cualquier otro programa o
aplicación específica. Son conjuntos de instrucciones que cualquier programa
requiere para poder operar, por lo cual era más razonable y económico
separarlos (en vez de repetir las mismas instrucciones preliminares en cada
programa). Responden tanto a un concepto de modularidad
como de eficiencia ya que -al ser independientes- basta que se carguen al
encender el computador para luego poder ejecutar varios programas sin necesidad
de volver a dar estas instrucciones.
Su objetivo fundamental es "tender un puente" activo entre el
hardware y el software encargándose de las funciones de:
1. Interfaz con el usuario:
La interfaz (o forma de interacción) puede ser de tipo intuitivo, como el
escritorio, los íconos y las ventanas del Macintosh o de Windows (llamados por
ello "entorno de escritorio"), o bien basada en "lenguaje de
comandos" como en DOS,
2. Administración de la CPU y la memoria
principal:
Crea subdivisiones en la RAM, indicando dónde deben colocarse las
instrucciones, los datos originales y los que generen los programas. En algunos
casos puede hacer que sólo una parte de un programa o de los datos sea
"cargada" -y reemplazada en el momento oportuno-, para economizar
espacio y trabajar con un conjunto de información mayor que el que cabe en la
RAM (caso común de las bases de datos). (En este caso se habla del uso de
"memoria virtual").
3. Administración de la memoria auxiliar:
Determina la longitud de los "paquetes" de datos que leen desde o
envían a los dispositivos de memoria auxiliar, la forma y el lugar físico en
que se guardan, la forma de acceder a ellos (construyen el
"directorio" o índice de los discos, por ejemplo).
Para todas estas funciones, el sistema operativo reconoce ciertas instrucciones
que forman parte del lenguaje de alto nivel (p.ej.
"open", "read",
"write", "save",
etc.) y genera para cada una múltiples instrucciones en lenguaje de máquina de
tal modo que el procesador efectúe todas las operaciones requeridas.
Los sistemas operativos también determinan la forma en que se codifican las
instrucciones y los datos que provienen del teclado. Todos los sistemas de
origen americano hoy usan el ASCII (American
Standard Code for Information Interchange), que
tenía originalmente 128 caracteres (suficiente para el inglés). Pero esta
cantidad impedía el uso de varios signos, entre ellos los acentos. Por ello se
usa hoy el "Ascii extendido", que cuenta
con 256 caracteres. Pero en la segunda serie de 128 caracteres, los diferentes
sistemas operativos han recurrido a opciones diferentes y no son compatibles
entre sí (razón por la cual los textos acentuados se ven con caracteres
extraños cuando se pasa de un tipo de computador a otro, como del Macintosh al
PC).
Es también la razón por la cual, en el correo electrónico, conviene escribir
sin acentos (usando el ASCII reducido), para asegurar un texto más legible.
Sistemas operativos de computadores personales
Los sistemas operativos hoy más difundidos en los computadores personales (PC)
son dos:
·
el DOS (Disk Operating System), para los PC
llamados "IBM compatibles", que utilizan principalmente chips
procesadores Intel (como los Pentium),
·
el MacOS
(Macintosh Operating System),
para los Apple Macintosh, que utilizan chips
procesadores Motorola (como los PowerPC).
El DOS, nacido a fines de los años setenta, ya
tiene numerosas versiones, que han tenido que introducir numerosos
"parches" para poder administrar la cantidad de memoria de que hoy se
dispone (en RAM y en disco) y en la cual no se soñaba en la época de su creación.
Originalmente destinado a expertos, ha tenido que ser complementado con una
interfaz gráfica -de la cual no disponía-, conocida como "Windows".
Dada la gran libertad de manejo de las instrucciones básicas, las aplicaciones
variaban mucho en la manera en que presentaban al usuario las opciones de
trabajo (ventanas, comandos, etc.), hasta que "Windows 95" se impuso
como estándar para las aplicaciones finales en PC-DOS.
El MacOS fue concebido desde el inicio (1984) como un
sistema basado en metáforas visuales y orientado al
tratamiento de información gráfica, lo cual facilita enormemente la interacción
humana. También se ha caracterizado por la coherencia de todas las aplicaciones
que funcionan con él. Siempre se respeta el mismo diseño y manejo de las
ventanas, la estructura de los menus y posición de
los comandos en éstos, etc. lo cual hace muy fácil aprender a usar aplicaciones
nuevas y pasar de una a otra. El MacOS es además
capaz de leer datos generados en "PC compatibles" y guardados
en diskettes de formato DOS (aunque no todos los
formatos de datos, ya que éstos dependen de las aplicaciones que los crearon):
su diskettera es más "compatible" que la de
los otros PC. Las máquinas más potentes también pueden ser cargadas con una
aplicación especial ("SoftPC" o "SoftWindows") para utilizar programas hechos para el
DOS.
En el futuro es probable que estas diferencias desaparezcan, ya que se está
trabajando en un sistema operativo más universal y en aplicaciones que
funcionen cualquiera sea el sistema operativo (gracias, por ejemplo, al
lenguaje "Java").
Importancia creciente está tomando el sistema operativo "Linux", que es un sistema derivado del Unix (sistema operativo de "mainframes"
y estaciones de trabajo) y destinado a los computadores personales (con
versiones para los procesadores Intel y Motorola-PPC). Su principal ventaja es que su código fuente
es "abierto", es decir de conocimiento público, a diferencia de los
códigos-fuente de los MacOS, DOS y Windows, que sólo
se entregan compilados. De este modo, cualquier programador capacitado puede
revisar, mejorar o ajustar a sus propias necesidades su propio Linux, mientras esto es imposible con MacOS
y DOS/Windows. Incluso los programadores de aplicaciones finales deben contar
con licencias especiales de los fabricantes (Apple y
Microsoft) para poder conocer las funciones incluídas
en estos sistemas operativos, lo cual da a dichos fabricantes un poder de
control que puede ser excesivo (razón, en parte, de los juicios contra
Microsoft). . En efecto, es posible incluir en el sistema operativo funciones
no reveladas, lo cual permite a su fabricante desarrollar aplicaciones finales
que funcionan mejor que las de sus competidores, o incluso que impiden que
éstas tengan acceso al procesador o que fallen reiteradas veces (lo cual
facilita una competencia desleal). Por todo ello crece un importante movimiento
en favor de los sistemas y aplicaciones "libres" (es decir de código
fuente "abierto", o sea público, lo cual no quiere decir
"gratis").
RESUMEN DE LENGUAJES DE PROGRAMACION MAS
COMUNES
ADA
Es un lenguaje estructurado parecido al PASCAL,
destinado a controlar mecanismos en "tiempo real" (o sea una
velocidad compatible con las necesidades reales), pero de gran complejidad.
Admite una programación "orientada a objetos" y un sistema de alta modularidad de tipo hipertexto.
Fue elaborado a pedido del Departamento de Defensa de los Estados Unidos y
establecido como norma para todos los fabricantes que participaban en el
programa de la Iniciativa de Defensa Estratégica (IDE, también llamado
"Guerra de las Galaxias").
ASSEMBLER (ENSAMBLADOR)
Como señalado a propósito del "Primer Nivel" de los lenguajes, el Assembler es directamente dependiente de los circuitos
electrónicos de los procesadores (que constituyen el núcleo de los
computadores), por lo cual escribir en Ensamblador sigue siendo una tarea muy
compleja, a lo cual hay que sumar que el código varía de un procesador a otro
aunque existe ya un jerga común para ciertas operaciones como las aritméticas y
lógicas, por ejemplo:
ADD para sumar (sin reserva) ADC para sumar
con reserva ("add with
carry") MUL para multiplicar ORA para el
"o" lógico ("or and")
EOR para el "o" exclusivo (o bien... o bien...)
Las instrucciones de este tipo deben ir seguidas
sea de dos valores (dos números a sumar o multiplicar por ejemplo) o del nombre
de una variable. Cuando se ejecute el programa, el valor de una variable
nombrada deberá provenir de una operación anterior que
·
haya terminado por una
instrucción del tipo "almacenar el resultado del operación en la variable
X",
·
haya extraído el valor de
la variable de una determinada celda de memoria, o
·
haya efectuado una
interacción con el usuario, por ejemplo escribir en pantalla "Escriba el
valor de X".
(Estas son
"instrucciones de asignación").
El Assembler contiene además un conjunto mínimo de
instrucciones de alternación e iteración indispensables para que un programa
pueda funcionar como tal.
Cuando abstraemos los opcodes
y los sustituimos por una palabra que sea una clave de su significado, a la
cual comúnmente se le conoce como mnemónico , tenemos
el concepto de Lenguaje Ensamblador . Así, podemos definir simplemente al
Lenguaje Ensamblador de la siguiente forma:
Lenguaje Ensamblador es la primera abstracción del
Lenguaje de Máquina , consistente en asociar a los opcodes palabras clave que faciliten su uso por parte del
programador
Como se puede ver, el Lenguaje Ensamblador es
directamente traducible al Lenguaje de Máquina, y viceversa; simplemente, es
una abstracción que facilita su uso para los seres humanos. Por otro lado, la
computadora no entiende directamente al Lenguaje Ensamblador; es necesario
traducirle a Lenguaje de Máquina. Originalmente, este proceso se hacía a mano,
usando para ello hojas donde se escribían tablas de programa similares al
ejemplo de la calculadora que vimos arriba . Pero, al
ser tan directa la traducción, pronto aparecieron los programas Ensambladores,
que son traductores que convierten el código fuente (en Lenguaje Ensamblador) a
código objeto (es decir, a Lenguaje de Máquina).
Una característica que hay que resaltar, es que al
depender estos lenguajes del hardware, hay un distinto Lenguaje de Máquina (y,
por consiguiente, un distinto Lenguaje Ensamblador) para cada CPU. Por ejemplo,
podemos mencionar tres lenguajes completamente diferentes, que sin embargo
vienen de la aplicación de los conceptos anteriores:
1.Lenguaje Ensamblador de la familia Intel
80x86 2.Lenguaje Ensamblador de la familia Motorola
68000 3.Lenguaje Ensamblador del procesador POWER, usado en las IBM RS/6000.
Tenemos 3 fabricantes distintos, compitiendo entre
sí y cada uno aplicando conceptos distintos en la manufactura de sus
procesadores, su arquitectura y programación; todos estos aspectos, influyen en
que el lenguaje de máquina y ensamblador cambie bastante.
Ventajas y desventajas del Lenguaje Ensamblador
Una vez que hemos visto la evolución de los
lenguajes, cabe preguntarse: ¿En estos tiempos "modernos", para qué
quiero el Lenguaje Ensamblador?
El proceso de evolución trajo consigo algunas
desventajas, que ahora veremos como las ventajas de usar el Lenguaje
Ensamblador, respecto a un lenguaje de alto nivel:
1.Velocidad
2.Eficiencia de tamaño
3.Flexibilidad
Por otro lado, al ser un lenguaje más primitivo, el
Ensamblador tiene ciertas desventajas respecto a los lenguajes de alto nivel:
1.Tiempo de programación 2.Programas fuente grandes
3.Peligro de afectar recursos inesperadamente 4.Falta de portabilidad
Velocidad
El proceso de traducción que realizan los
intérpretes, implica un proceso de cómputo adicional al que el programador
quiere realizar. Por ello, nos encontraremos con que un intérprete es siempre
más lento que realizar la misma acción en Lenguaje Ensamblador, simplemente
porque tiene el costo adicional de estar traduciendo el programa, cada vez que
lo ejecutamos.
De ahí nacieron los compiladores, que son mucho más
rápidos que los intérpretes, pues hacen la traducción una vez y dejan el código
objeto, que ya es Lenguaje de Máquina, y se puede ejecutar muy rápidamente.
Aunque el proceso de traducción es más complejo y costoso que el de ensamblar
un programa, normalmente podemos despreciarlo, contra las ventajas de codificar
el programa más rápidamente.
Sin embargo, la mayor parte de las veces, el código
generado por un compilador es menos eficiente que el código equivalente que un
programador escribiría. La razón es que el compilador no tiene tanta
inteligencia, y requiere ser capaz de crear código genérico, que sirva tanto
para un programa como para otro; en cambio, un programador humano puede
aprovechar las características específicas del problema, reduciendo la
generalidad pero al mismo tiempo, no desperdicia ninguna instrucción, no hace
ningún proceso que no sea necesario.
Para darnos una idea, en una PC, y suponiendo que
todos son buenos programadores, un programa para ordenar una lista tardará
cerca de 20 veces más en Visual Basic (un intérprete), y 2 veces más en C (un
compilador), que el equivalente en Ensamblador.
Por ello, cuando es crítica la velocidad del
programa, Ensamblador se vuelve un candidato lógico como lenguaje.
Ahora bien, esto no es un absoluto; un programa
bien hecho en C puede ser muchas veces más rápido que un programa mal hecho en
Ensamblador; sigue siendo sumamente importante la elección apropiada de
algoritmos y estructuras de datos. Por ello, se recomienda buscar optimizar
primero estos aspectos, en el lenguaje que se desee, y solamente usar Ensamblador
cuando se requiere más optimización y no se puede lograr por estos medios.
Tamaño
Por las mismas razones que vimos en el aspecto de
velocidad, los compiladores e intérpretes generan más código máquina del
necesario; por ello, el programa ejecutable crece. Así, cuando es importante
reducir el tamaño del ejecutable, mejorando el uso de la memoria y teniendo
también beneficios en velocidad, puede convenir usar el lenguaje Ensamblador.
Entre los programas que es crítico el uso mínimo de memoria, tenemos a los
virus y manejadores de dispositivos (drivers). Muchos
de ellos, por supuesto, están escritos en lenguaje Ensamblador.
Flexibilidad
Las razones anteriores son cuestión de grado:
podemos hacer las cosas en otro lenguaje, pero queremos hacerlas más
eficientemente. Pero todos los lenguajes de alto nivel tienen limitantes en el
control; al hacer abstracciones, limitan su propia capacidad. Es decir, existen
tareas que la máquina puede hacer, pero que un lenguaje de alto nivel no
permite. Por ejemplo, en Visual Basic no es posible cambiar la resolución del
monitor a medio programa; es una limitante, impuesta por la abstracción del GUI
Windows. En cambio, en ensamblador es sumamente sencillo, pues tenemos el
acceso directo al hardware del monitor.
Resumiendo, la flexibilidad consiste en reconocer
el hecho de que
Todo lo que puede hacerse con una máquina, puede
hacerse en el lenguaje ensamblador de esta máquina; los lenguajes de alto nivel
tienen en una u otra forma limitantes para explotar al
máximo los recursos de la máquina.
Tiempo de programación
Al ser de bajo nivel, el Lenguaje Ensamblador
requiere más instrucciones para realizar el mismo proceso, en comparación con
un lenguaje de alto nivel. Por otro lado, requiere de más cuidado por parte del
programador, pues es propenso a que los errores de lógica se reflejen más
fuertemente en la ejecución.
Por todo esto, es más lento el desarrollo de
programas comparables en Lenguaje Ensamblador que en un lenguaje de alto nivel,
pues el programador goza de una menor abstracción.
Programas fuente grandes
Por las mismas razones que aumenta el tiempo,
crecen los programas fuentes; simplemente, requerimos más instrucciones
primitivas para describir procesos equivalentes. Esto es una desventaja porque
dificulta el mantenimiento de los programas, y nuevamente reduce la
productividad de los programadores.
Peligro de afectar recursos inesperadamente
Tenemos la ventaja de que todo lo que se puede
hacer en la máquina, se puede hacer con el Lenguaje Ensamblador (flexibilidad).
El problema es que todo error que podamos cometer, o todo riesgo que podamos
tener, podemos tenerlo también en este Lenguaje. Dicho de otra forma, tener
mucho poder es útil pero también es peligroso.
En la vida práctica, afortunadamente no ocurre
mucho; sin embargo, al programar en este lenguaje verán que es mucho más común
que la máquina se "cuelgue", "bloquee" o "se le vaya
el avión"; y que se reinicialize. ¿Por qué?,
porque con este lenguaje es perfectamente posible (y sencillo) realizar secuencias
de instrucciones inválidas, que normalmente no aparecen al usar un lenguaje de
alto nivel.
En ciertos casos extremos, puede llegarse a sobreescribir información del CMOS de la máquina (no he
visto efectos más riesgosos); pero, si no la conservamos, esto puede causar que
dejemos de "ver" el disco duro, junto con toda su información.
Falta de portabilidad
Como ya se mencionó, existe un lenguaje ensamblador
para cada máquina; por ello, evidentemente no es una selección apropiada de
lenguaje cuando deseamos codificar en una máquina y luego llevar los programas
a otros sistemas operativos o modelos de computadoras. Si bien esto es un
problema general a todos los lenguajes, es mucho más notorio en ensamblador: yo
puedo reutilizar un 90% o más del código que desarrollo en "C", en
una PC, al llevarlo a una RS/6000 con UNIX, y lo mismo si después lo llevo a
una Macintosh, siempre y cuando esté bien hecho y siga los estándares de
"C", y los principios de la programación estructurada. En cambio, si
escribimos el programa en Ensamblador de la PC, por bien que lo desarrollemos y
muchos estándares que sigamos, tendremos prácticamente que reescribir
el 100 % del código al llevarlo a UNIX, y otra vez lo mismo al llevarlo a Mac.
ALGOL
El ALGOL ("ALGOrithmic Lenguage")
es el primer lenguaje que fue creado por un comité internacional. En 1960 se
reunieron representantes de varios países europeos y de Estados Unidos para
crear un lenguaje destinado a "describir procesos" mediante
instrucciones de control (iteraciones y alternaciones) de nivel más elevado que
las existentes en las versiones existentes de su predecesor, el FORTRAN.
Permite escribir programas de resolución de problemas en forma limpia y clara,
de fácil lectura. Aunque poco "transportable" (no permite con
facilidad que un programa escrito para un tipo de computador funcione en otro),
es de gran importancia conceptual por cuanto introdujo la "programación
estructurada", lo cual influyó en muchos lenguajes creados posteriormente.
En 1968 se implementó una nueva versión multi-propósito
especialmente orientada a la tercera generación de computadores que empezaban a
copar el mercado. (A diferencia de la primera versión, ésta resultó muy
compleja y, por ello, tuvo poco éxito).
EJEMPLO:
REAL PROCEDURE exp(x);
VALUE x; REAL x;
BEGIN
REAL sum, term, n;
sum:= 1; term:= 1; n:= 0;
FOR n:= n+1 WHILE abs (term) > 0.001 DO
BEGIN
term:= x * term / n;
sum:= sum + term
END;
exp:= sum
END.
BASIC
El BASIC ("Beginner's All-purpose Symbolic
Instruction Code")nació con los microcomputadores, como un lenguaje
simplificado y multi-propósito destinado a los usuarios
no-especialistas.
Permite resolver problemas numéricos o comerciales así como crear y mantener
archivos, realizar gráficos lineales, etc. Es por esencia un lenguaje
interpretado y no-estructurado. Sin embargo, existen algunos compiladores, pero
no es común recurrir a ellos. Y también es factible redactar los programas en
forma estructurada.
EJEMPLO
10 INPUT A
20 INPUT B
30 C = A+ B
40 IF C >
100 THEN 90
50 PRINT
"Suma = "; C
60 PRINT
70 PRINT "Desea seguir? "; : GET R$
80 IF R$ =
"S" THEN 10
90 PRINT "Resultado superior a 100!"
100 END
QBasic
Qbasic es un lenguaje de alto nivel, el cual consiste en
instrucciones que los humanos pueden relacionar y entender. El compilador de Qbasic se encarga de traducir el mismo a lenguaje de
máquina.
Un programa es una secuencia de instrucciones. El
proceso de ejecutar esas instrucciones se llama correr el programa. Los
programas contienen las funciones de entrada, procesamiento y salida. La
persona que resuelve problemas mediante escribir programas en la computadora se
conoce como programador. Después de analizar el problema y desarrollar un plan
para solucionarlo, escribe y prueba el programa que instruye a la computadora
como llevar a cabo el plan. El procedimiento que realiza el programador se define
como "problem solving".
Pero es necesario especificar que un programador y un usuario no son lo mismo.
Un usuario es cualquier persona que use el programa.
Ejemplo de qbasic, para
hacer una calculadora
DIM total
AS DOUBLE
DIM number
AS DOUBLE
DIM secondNumber AS DOUBLE
DIM more AS
STRING
DIM moreNumbers AS STRING
DIM
operation AS STRING
total = 0
more = "y"
moreNumbers = "c"
CLS
WHILE more
= "y"
INPUT
"Enter the first number"; number
total = number
WHILE moreNumbers = "c"
COLOR 14
PRINT
"The total is:"; total
COLOR 7
PRINT
"Select an operation"
COLOR 2
PRINT
"(+)"
COLOR 5
PRINT
"(-)"
COLOR 1
PRINT
"(x)"
COLOR 4
INPUT
"(/)"; operation
COLOR 7
CLS
IF
operation = "+" THEN
REM where
we do additions
PRINT
"Enter the number to Add to"; total
INPUT secondNumber
total = secondNumber + total
COLOR 14
PRINT
"The total is now:"; total
COLOR 7
ELSE
IF
operation = "-" THEN
REM
subtraction
PRINT
"Enter the number to Subtract from"; total
INPUT secondNumber
total = total - secondNumber
COLOR 14
PRINT
"The total is now:"; total
COLOR 7
ELSE
IF
operation = "x" THEN
REM
multiplication
PRINT
"Enter the number to Multiply"; total;
"by"
INPUT secondNumber
total = secondNumber * total
REM * is
the multiplication sign in programs
COLOR 14
PRINT
"The total is now:"; total
COLOR 7
ELSE
IF
operation = "/" THEN
REM
division
PRINT
"Enter the number to Divide"; total; "by"
INPUT secondNumber
IF secondNumber = 0 THEN
COLOR 4
PRINT
"You cannot divide by zero"
COLOR 7
ELSE
total = total / secondNumber
REM / is
the division sign in programs
END IF
COLOR 14
PRINT
"The total is now:"; total
COLOR 7
ELSE
PRINT
"you must select an operation"
END IF
END IF
END IF
END IF
INPUT
"Do you wish to continue (c) or start with new numbers
(n)";moreNumbers
CLS
WEND
COLOR 14
PRINT
"The grand total is:"; total
COLOR 7
INPUT
"Do you wish to make more calculations (y - n)"; more
moreNumbers = "c"
REM if we
don't put "moreNumbers" back to y, it will
always
REM come
back to "Do you wish to make more calculations" and never REM ask
for numbers again
REM (try
it)
total = 0
REM if we
don't reset the total to 0, it will just
REM keep on adding to the total
WEND
END
C y C++
El lenguaje "C" es bastante reciente y está especialmente orientado
hacia el desarrollo de software de sistemas operativos y utilitarios que
anteriormente se escribían en Assembler. Se usa hoy
como base para crear el software que funciona con el sistema operativo
"UNIX", logrando un alto grado de portabilidad, es decir de
independencia respecto de los procesadores (con lo cual es fácil lograr que un
mismo programa pueda ser ejecutado en diferentes modelos de computadores).
El "C++" es un lenguaje desarrollado a partir del "C" pero
con una estructura "orientada a objetos", lo cual facilita un mejor
manejo de datos.
C
C es un lenguaje de programación diseñado por Dennis Ritchie, de los
Laboratorios Bell, y
se instaló en un PDP-11 en 1972; se diseñó para ser
el lenguaje de los Sistemas Operativos
UNIX1. A su vez, UNIX es un Sistema Operativo
desarrollado por Ken Thompson,
quién
utilizó el lenguaje ensamblador y un lenguaje llamado B
para producir las versiones originales de UNIX, en 1970. C se inventó para
superar las limitaciones de B.
C es un lenguaje maduro de propósitos generales que
se desarrolló a partir de estas raíces;
su definición aparece en 1978 en el apéndice ``C Reference Manual'' del libro The
C
Programming
Language, de Brian W. Kernighan y Dennis M. Ritchie (Englewood Cliffs,
Nueva Jersey, Prentice-Hall 1978), pero el
estándar recomendable más reciente apareció en
junio de 1983, en el documento de los Laboratorios Bell titulado The C Programming
Language-Reference Manual,
escrito por Dennis M. Ritchie
Un programa en C
Generalizando, un programa en C consta de tres
secciones. La primera sección es donde van todos los ``headers''.
Estos ``headers'' son comúnmente los ``#define'' y
los ``#include''. Como segunda sección se tienen las
``funciones''. Al igual que Pascal, en C todas las funciones que se van a
ocupar en el programa deben ir antes que la función principal (main()).
Declarando las funciones a ocupar al principio del programa, se logra que la
función principal esté antes que el resto de las funciones. Ahora, solo se
habla de funciones ya que en C no existen los procedimientos.
Y como última sección se tiene a la función
principal, llamada main. Cuando se ejecuta el
programa, lo primero que se ejecuta es esta función, y de ahí sigue el resto
del programa.
Los símbolos { y } indican
``begin'' y ``end''
respectivamente. Si en una función o en un ciclo while,
por ejemplo, su contenido es de solamente una línea, no es necesario usar
``llaves'' ({ }), en caso contrario es obligación usarlos.
Ejemplo de un programa en C
/*Programa ejemplo que despliega el contenido de
"ROL" en pantalla*/
#include
<stdio.h>
#define ROL
"9274002-1"
despliega_rol() {
printf("Mi rol es : \%s\n", ROL);
}
void main() {
despliega_rol();
}
/* Fin programa */
COBOL
EL COBOL ("COmmon Business-Oriented Language") es uno
de los primeros lenguajes de programación creados. Fue desarrollado en 1960 por
CODASYL (Conference on Data
Systems Languages), un
comité en que participaron fabricantes y usarios, a
pedido de la Marina de los Estados Unidos. Este comité estuvo dirigido por la
Dra. Grace Hopper, una de
las primeras programadoras de la computadora ENIAC. Es uno de los pocos
lenguajes reconocidos como norma internacional (americana por el ANSI -American National Standards Institute- y europea
por el ISO -International Organization
for Standardization-).
Está orientado -como su nombre indica- a aplicaciones comerciales, por lo cual
sus instrucciones están especialmente diseñadas para facilitar la entrada y
salida de datos (impresión de tablas, etc.). Se pretendió que se pareciera lo
más posible a un lenguaje natural, por lo cual requiere mucho más escritura que
otros lenguajes. Esto facilita la lectura posterior pero resulta aburrido para
los redactores. Debe iniciarse con secciones donde se declaran todas las
variables y los periféricos que se van a usar, cosas que muchos lenguajes
posteriores ya no requieren.
Los programas escritos en COBOL, que es un lenguaje compilado, se clasifican en
cuatro divisiones: Identification, Enviroment, Data y Procedure.
La Identification division
especifica el nombre del programa y contiene información general del programa
como puede ser su autor, fecha en que se escribió y una pequeña descripción de
su utilidad, así como cualquier otra documentación que el programador desee
añadir.
La Enviroment division
especifica qué equipo o equipos se están utilizando, y los archivos empleados
en el programa para la entrada y la salida.
La Data division describe los datos utilizados
en el programa.
La Procedure division
contiene la parte del procesamiento que dicta las acciones del programa.
EJEMPLO
IDENTIFICATION DIVISION.
PROGRAM-ID. SUMA.
ENVIRONMENT DIVISION.
INPUT-OUTPUT
SECTION.
FILE-CONTROL.
SELECT ENTRADA
ASSIGN TO INPUT.
SELECT SALIDA ASSIGN
TO OUTPUT.
DATA DIVISION.
FILE SECTION.
FD ENTRADA LABEL RECORD IS
OMITTED.
01 VENTA.
02 VALOR
PICTURE 9999V99.
03 FILLER
PICTURE X(44).
FD SALIDA LABEL RECORD IS
OMITTED.
01 RESULTADOS
PICTURE X(132).
WORKING
STORAGE SECTION.
...
PROCEDURE DIVISION.
...
FORTRAN
El FORTRAN ("FORmula TRANslator")
fue desarrollado entre los años 1954 y 1957 por un equipo dirigido por James Backus, fue el primer lenguaje compilado e inclusive hoy en
día es usado ampliamente en la solución de problemas numéricos. Aunque fue el
más común hasta 1970, sigue siendo de primera importancia en aplicaciones
científicas por cuanto se adapta muy bien a la forma tradicional de escribir
fórmulas matemáticas. Al contrario, no se presta con facilidad al manejo de
archivos y produccción de tablas de resultados.
Existen numerosas versiones y perfeccionamientos posteriores. (La versión de
1966 fue instituída como estándar por el Instituto
Americano de Estandarización, reemplazándola por el FORTRAN 77 en la década
siguiente).
EJEMPLO
INTEGER A, B, C
10 READ (5,1010)
A, B
1010
FORMAT (I4,I4)
C = A - B
IF (C. EQ. 0) GO TO 20
WRITE (6,1020) C
1020 FORMAT (I4)
GO TO 10
20 STOP
END
HYPERTALK
"HyperTalk" es el lenguaje desarrollado por
Dan Winkler para Bill Atkinson, el creador del "HyperCard"
para Apple-Macintosh. Está orientado a la creación de
aplicaciones conforme al sistema de "hiperarchivos"
(sistemas de fichas interrelacionadas donde se facilita el "navegar"
de un archivo a otro).
HyperTalk es un buen ejemplo de lenguaje orientado a
objetos. Este tipo de lenguaje combina la lógica declarativa con los algoritmos
(Vea "PROLOG").
Un programa ya no es una secuencia de instrucciones sino un conjunto de objetos
agrupados en conjuntos, definidos mediante atributos y a los cuales pueden
asociarse instrucciones. Así, en HyperCard, existen
archivos ("stacks" o "pilas") que
agrupan fichas ("cards"), y cada una de
éstas contiene campos de datos y botones. Todos son "objetos" que -si
bien mantienen entre sí una relación jerárquica- tienen asociados paquetes de
instrucciones ("scripts") independientes
unos de otros. Cada objeto pertenece a un conjunto (como fichas o botones) que
tiene "atributos" propios comunes a todos sus miembros, y cada
atributo tendrá un valor común o específico para cada caso. Para dar o buscar
dicho valor intervienen "facetas" que son instrucciones
(procedimientos) asociadas.
HTML
El HTML o "HyperText Marking
Language" es el lenguaje que se utiliza para
crear páginas -como la presente- en World Wide Web.
El HTML se basa en los mismos principios que el HyperTalk,
permitiendo definir segmentos (de texto o ilustraciones) que remiten a otros,
facilitando una "navegación" por múltiples vías, a gusto del usuario.
Así es como el botón "Home" tiene asociadas
las instrucciones que indican al procesador que busque la primera ficha o
página del archivo llamado "Home" o "index" en el archivo del computador que presta el
servicio de conexión (servidor). Y si se hace un clic en una palabra
subrayada, se pasa a ver otra sección del mismo documento o algún otro
documento (otro "objeto").
El HTML no es propiamente un lenguaje de programación ,
sino solo de exhibición de contenidos y navegación, porque no define
operaciones.
JAVA
JAVA es un lenguaje de programación basado en el C++ (con
cambios en la sintaxis y nuevas restricciones de codificación). Permite agregar
animaciones y puntos sensibles en páginas de texto. Aunque se lo pretende
presentar como "EL" lenguaje destinado a desarrollos para World Wide
Web, es mucho mas complejo que el HTML e
incluso que otros lenguajes utilizables por los browsers
(navegadores) de la Web.
Una versión muy reducida es el "JavaScript",
que se puede combinar con el lenguaje HTML,
dentro de una página web.
El
lenguaje de programación Java, fue diseñado por la compañía Sun
Microsystems Inc, con el
propósito de crear un lenguaje que pudiera funcionar en redes computacionales
heterogéneas ( redes de computadoras formadas por más
de un tipo de computadora, ya sean PC, MAC's,
estaciones de trabajo, etc.),y que fuera independiente de la plataforma en la
que se vaya a ejecutar. Esto significa que un programa de Java puede ejecutarse
en cualquier máquina o plataforma. El lenguaje fue diseñado con las siguientes
características en mente:
·
Simple. Elimina la
complejidad de los lenguajes como "C" y da paso al contexto de los
lenguajes modernos orientados a objetos. Orientado a Objetos. La filosofía de
programación orientada a objetos es diferente a la programación convencional.
·
Familiar. Como la mayoría de los programadores
están acostumbrados a programar en C o en C++, el
sintaxis de Java es muy similar al de estos.
·
Robusto. El sistema de Java maneja la memoria de la
computadora por ti. No te tienes que preocupar por apuntadores, memoria que no
se esté utilizando, etc. Java realiza todo esto sin necesidad de que uno se lo
indique.
·
Seguro. El sistema de Java tiene ciertas políticas
que evitan se puedan codificar virus con este lenguaje. Existen muchas
restricciones, especialmente para los applets, que
limitan lo que se puede y no puede hacer con los recursos críticos de una
computadora.
·
Portable. Como el código
compilado de Java (conocido como byte code) es interpretado, un programa compilado de Java puede
ser utilizado por cualquier computadora que tenga implementado el interprete de
Java.
·
Independiente a la arquitectura. Al compilar un
programa en Java, el código resultante un tipo de código binario conocido como byte code. Este códido es interpretado por diferentes computadoras de igual
manera, solamente hay que implementar un intérprete para cada plataforma. De
esa manera Java logra ser un lenguaje que no depende de una arquitectura
computacional definida.
·
Multithreaded. Un lenguaje
que soporta multiples threads
es un lenguaje que puede ejecutar diferentes líneas de código al mismo tiempo.
·
Interpretado. Java corre en máquina virtual, por lo
tanto es interpretado.
·
Dinámico. Java no requiere que compiles todas las
clases de un programa para que este funcione. Si realizas una modificación a
una clase Java se encarga de realizar un Dynamic Bynding o un Dynamic Loading para encontrar las clases.
Java puede funcionar como una aplicación sola o
como un "applet", que es un pequeño
programa hecho en Java. Los applets de Java se pueden
"pegar" a una página de Web (HTML), y con esto puedes tener un
programa que cualquier persona que tenga un browser
compatible podrá usar.
Nota:Diferencia entre Java y CGI La diferencia es esencialmente
simple, un CGI se ejecuta en el servidor mientras que un programa en Java se
ejecuta en la máquina del usuario.
Java funciona de la siguiente manera: El compilador
de Java deja el programa en un Pseudo-código (no es código maquinal) y luego el
intérprete de Java ejecuta el programa (lo que se conoce como el "Java
Virtual Machine"). Por eso Java es
multiplataforma, existe un intérprete para cada máquina diferente. Nota:
El código maquinal es el código binario que la computadora entiende y puede
ejecutar.
Para entender bien como funciona un applet de Java vean el siguiente ejemplo:
1.
Existe un código de
Java en un servidor de Web. (Los códigos de Java se caracterizan por tener la
extensión *.class).
2.
Una persona en Internet, con un browser
compatible con Java, realiza una conección al
servidor.
3.
El servidor envía el documento HTML y el código en
Java (*.class).
4.
En la computadora del usuario remoto llegan ambos,
y la Máquina Virtual de Java, que está en el browser,
transforma el código Java en un código que entienda la máquina local y se
ejecuta el programa dentro de la página de Web.
5.
Si el usuario realiza otra conexión a otro URL o se
sale del browser, el programa se deja de ejecutar y
en la computadora no queda rastro de el.
Ejemplo de tutorial de
Java:
En Java hay tres tipos de comentarios:
// comentarios para una
sola línea
/* comentarios de una o
más líneas
*/
/** comentario de
documentación, de una o más líneas
*/
Los dos primeros tipos de comentarios son los que
todo programador conoce y se utilizan del mismo modo. Los comentarios de
documentación, colocados inmediatamente antes de una declaración (de variable o
función), indican que ese comentario ha de ser colocado en la documentación que
se genera automáticamente cuando se utiliza la herramienta de Java, javadoc. Dichos comentarios sirven como descripción del
elemento declarado permitiendo generar una documentación de nuestras clases
escrita al mismo tiempo que se genera el código.
En este tipo de comentario para documentación, se
permite la introducción de algunos tokens o palabras
clave, que harán que la información que les sigue aparezca de forma diferente
al resto en la documentación.
Identificadores
Los identificadores nombran variables, funciones,
clases y objetos; cualquier cosa que el programador necesite identificar o
usar.
En Java, un identificador comienza con una letra,
un subrayado (_) o un símbolo de dólar ($). Los siguientes caracteres pueden
ser letras o dígitos. Se distinguen las mayúsculas de las minúsculas y no hay
longitud máxima.
Serían identificadores válidos:
identificador
nombre_usuario
Nombre_Usuario
_variable_del_sistema
$transaccion
y su uso sería, por ejemplo:
int contador_principal;
char _lista_de_ficheros;
float $cantidad_en_Ptas;
Unix
Ejemplo de Unix:
No todo el "árbol" de directorios está
compuesto por directorios de usuario. Existen muchos de ellos que son de uso
general o del propio sistema y con los que habrá que familiarizarse. Los más
importantes son:
/
El raíz, del que "cuelgan" todos.
/bin y /usr/bin
Contienen comandos UNIX ejecutables.
/etc
Es quizá el directorio más importante. Contiene
ficheros de datos y configuración del sistema, el fichero de password, configuración de terminales, red, etc (de ahí su nombre).
/dev
Ficheros de dispositivos E/S.
/usr/man
Manual
/tmp
Directorio para arreglos temporales. TODOS los
usuarios pueden leer y escribir en él.
LISP
LISP ("LIst Processing
Language") es un lenguaje computacional bastante
diferente de los demás. Es un lenguaje funcional, es decir que acumula
informaciones e instrucciones bajo la apariencia de fórmulas (como en álgebra).
Estas informaciones toman la forma de listas (de ahí su nombre), que son memorizadas
y comparadas para efectuar luego operaciones que consisten en "evaluar las
fórmulas". El conjunto de funciones constituye el programa en cuanto la
evaluación de una función llama a otra y así sucesivamente (en forma
eminentemente recursiva). El control de la ejecución depende del intérprete
(que busca la secuencia y la traduce en lenguaje máquina), mientras depende del
programador la forma en que las funciones se llaman entre sí.
El objetivo de este tipo de lenguaje es asemejarse a una forma humana de
conservación de información (la de las descripciones) y permitir la
construcción de programas que se enriquezcan o ajusten en función del uso
(simulando aprendizaje). Así, LISP es el primer lenguaje creado con el fín de ser una herramienta para el desarrollo de la
inteligencia artificial.
EJEMPLO
? (de
append (L1 L2)
(if (null L1)
L2
(cons (cor L1)
(append (cdr
L1) L2))))
LOGO
Creado por Seymour Papert,
padre de la "computación educativa", el LOGO está destinado a la
enseñanza de la programación a los niños, desde temprana edad. Por ello es
sobretodo conocido por su capacidad gráfica y su "tortuga", que es el
puntero con el cual se realizan los dibujos. Es altamento
modular y deja gran libertad al usuario para definir procedimientos desde muy
simples hasta muy complejos, en forma jerárquica, permitiendo incluso el
control de periféricos mecánicos (operación de pequeños robots). Aunque
bastante poderoso (se han escrito procesadores de palabras en LOGO), practicamente no es utilizado fuera de la escuela básica.
EJEMPLO
Comandos para dibujar un cuadrado de 20 pixels (puntos) por lado:
BAJAR_PLUMA. ADELANTE 20. ROTACION 90. ADELANTE 20.
ROTACION 90. ADELANTE 20. ROTACION 90. ADELANTE 20. LEVANTAR_PLUMA.
Lo que conforma el cuadrado puede simplificarse como: HACER 4 (ADELANTE
20. ROTACION 90). y ser utilizado repetidamente
definiendo el comando "Cuadrado":
>CUADRADO: HACER 4 (ADELANTE 20. ROTACION 90).
Esta definición se puede generalizar reemplazando la longitud por una
variable (El programa pide automáticamente en pantalla el valor de una variable
si lo desconoce): >CUADRADO: HACER 4 (ADELANTE LADO. ROTACION 90).
(Las órdenes para bajar y levantar la "pluma" -que permiten
dejar o no dejar rastro al mover la "tortuga" - pueden introducirse o
no en la definición, a voluntad).
PASCAL
Del nombre del filosófico y matemático francés, PASCAL es un lenguaje
inicialmente diseñado para la docencia introductoria de la programación (a
nivel superior). Surgió alrededor de 1970, en gran parte como reacción
simplificadora después de la creación de los muy complejos PL/1 y
ALGOL68 para los nuevos computadores de tercera generación.
Muy inspirado en la primera versión oficial de ALGOL
(60), es un lenguaje muy estructurado y con alta modularidad.
Tuvo por ello -y por su simplicidad- mucha aceptación al punto de ser utilizado
para crear importantes aplicaciones e incluso compiladores y sistemas
operativos (antes desarrollados en Assembler).
EJEMPLO
PROGRAM CALCULATOR;
VAR
A, B: INTEGER;
OPERATION; CHAR;
BEGIN
REPEAT
READLN (A, OPERATION, B);
IF OPERATION = '+' THEN
WRITELN (A + B)
ELSE IF OPERATION = '-' THEN
WRITELN (A - B)
ELSE IF OPERATION = '*' THEN
WRITELN ( A* B)
ELSE IF OPERATION = '/' THEN
WRITELN (A /
B)
UNTIL FALSE
END.
Pascal
Pascal es un lenguaje de programación de alto nivel
de propósito general; esto es, se puede utilizar para escribir programas para
fines científicos y comerciales.
El lenguaje de programación Pascal fue desarrollado
por el profesor Niklaus (Nicolás) Wirth
en Zurich, Zuiza, al final
de los años 1960s y principios de los 70s. Wirth
diseñó este lenguaje para que fuese un buen primer lenguaje de programación
para personas comenzando a aprender a programar. Pascal tiene un número
relativamente pequeño de conceptos para aprender y dominar. Su diseño facilita
escribir programas usando un estilo que está generalmente aceptado como
práctica estándar de programación buena. Otra de las metas del diseño de Wirth era la implementación fácil. Él diseñó un lenguaje
para el cual fuese fácil escribir un compilador para un nuevo tipo de
computadora.
program Sorting;
{
Este programa lee un natural y una secuencia de N
caracteres de la entrada estandar; construye un indice para ordenarlos de menor a mayor e imprime en la
salida la secuencia ordenada.
}
uses CRT;
Const
Max = 10;
Espacio = ' ';
Enter = chr (13);
type Indice = 1..Max;
Cantidad= 0..Max;
SecOfChar = record
elems : array [Indice]
of char;
ult : Cantidad;
end;
SecOfInd = record
elems : array [Indice]
of Indice;
ult : Cantidad;
end;
Natural = 0..MaxInt;
function PosMin (idx:
SecOfInd; i: Indice; s: SecOfChar): Cantidad;
{ Devuelve la posicion en el indice idx del menor caracter en s, para
las posiciones >= i. }
var j: Indice;
pm: Cantidad;
begin
if i > idx.ult then
pm := 0
else begin
pm := i;
for j := i+1 to idx.ult do
if s.elems[idx.elems[j]]
< s.elems[idx.elems[pm]]
then
pm := j;
end;
PosMin := pm;
end;
procedure Swap (var idx: SecOfInd; i,j: Indice);
{ Intercambia las posiciones i j en idx.
}
var tmp:
Indice;
begin
if (i<=idx.ult) and
(j<=idx.ult) then begin
tmp := idx.elems[i];
idx.elems[i] :=
idx.elems[j];
idx.elems[j] := tmp;
end;
end;
procedure InicInds (var idx: SecOfInd;
cant: Indice);
{ Construye la secuencia de indices
1,2,3,...,n. Sera el indice
inicial para el ordenamiento de una secuencia de
caracteres
c1,c2,...,cn. }
var n: Natural;
begin
n := cant;
idx.ult := n;
while n > 0 do begin
idx.elems [n] := n;
n := n-1;
end;
end;
procedure InicSecChar (var s: SecOfChar);
{ Devuelve la secuencia vacia. }
begin
s.ult := 0;
end;
function Llena (s: SecOfChar): Boolean;
begin
Llena := s.ult
= Max;
end;
{ PRE: not Llena(s) }
procedure InsCar (var
s: SecOfChar; c: char);
{ Inserta el caracter c en la
secuencia s }
begin
s.ult := s.ult
+ 1;
s.elems [s.ult] :=
c;
end;
procedure IndSelSort (s: SecOfChar; var
{ Construye el indice que ordena la
secuencia s. Ordena el indice
inicial 1,2, ..., n por el metodo
de selection sort }
var i:
Indice;
begin
InicInds (
for i := 1 to ind.ult-1 do begin
Swap (
end
end;
procedure WriteSorted (idx: SecOfInd; s: SecOfChar);
{ Imprime en la salida estandar la
secuencia s ordenada segun el
indice idx
}
var i:
Indice;
begin
write ('Ordenado: ');
for i := 1 to idx.ult
do
write (s.elems[idx.elems[i]],' ');
writeln;
end;
procedure LeerCar (var c: char; var ok: boolean; sep: Char);
{ Lee de la entrada estandar
un caracter seguido del caracter
sep }
var c1, c2: char;
begin
c := ReadKey; write (c);
c1 := ReadKey; write (c1);
ok := c1 = sep;
end;
procedure LeerSecOfChar (var s: SecOfChar; cant: Natural; var ok: Boolean);
{ Construye una secuencia de cant
caracteres provistos por el
procedimeinto LeerCar. Si cant > Max trunca. }
var bien:
Boolean;
i: Natural;
ch, sep: Char;
begin
writeln ('Ingrese ',cant, '
caracteres separados por blancos. Enter para terminar
');
write (' > ');
InicSecChar (s);
i := 1;
ok := true;
sep := Espacio;
while ok and (i <= cant) and not Llena (s) do begin
if i = cant then sep := Enter;
LeerCar (ch, bien,
sep);
i := i+1;
ok := ok and bien;
if ok then
InsCar (s, ch);
end;
end;
procedure LeerCant
(var n: Natural);
{ Lee de la entrada estandar
un natural <= Max }
begin
repeat
writeln ('Ingrese cantidad de caracteres (<=',Max,')');
write (' > ');
readln (n);
until n <= Max;
end;
procedure Continuar (var seguir: Boolean);
var car: Char;
begin
writeln;
writeln ('Otro
? (s/n)');
write (' > ');
car := ReadKey;
writeln (car);
seguir := car in ['s','S'];
end;
var cant: Natural;
cars: SecOfChar;
inds: SecOfInd;
seguir, ok: boolean;
begin
repeat
ClrScr;
LeerCant (cant);
LeerSecOfChar (cars, cant, ok);
if ok then begin
IndSelSort (cars, inds);
writeln;
WriteSorted (inds, cars);
end
else begin
writeln;
writeln ('Error en los datos');
end;
Continuar (seguir);
until not
seguir;
end.
PERL
Es un lenguaje especializado en el procesamiento de textos, particularmente
extraer y validar las respuestas a cuestionarios incluidos en páginas web.
PL/1
EL "PL/1" es un lenguaje multi-propósito
creado por IBM y SHARE, especialmente a raíz del paso de la segunda a la
tercera generación de computadores, cuando se preveía la creciente difusión de
estas máquinas y su posible uso en una gama creciente de actividades. Pretendía
ampliar las posibilidades del FORTRAN
fusionando conceptos provenientes del COBOL
y el ALGOL.
La gran cantidad de instrucciones, tipos de datos y casos especiales que
contempla lo hacen difícil de aprender y dominar, razón de su poca difusión.
EJEMPLO
TRAPZ: PROCEDURE OPTIONS (
DECLARE (J,K) FIXED DECIMAL (2),
AREA FIXED DECIMAL (8,6);
PUT SKIP EDIT ('AREA
BAJO LA CURVA') (X(9),A);
PUT SKIP;
DO K=4 TO 10;
AREA=0.5/K;
DO J=1 TO K-1;
AREA=AREA+((J/K)**2)/K);
END;
PUT SKIP
EDIT ('
(X(2),A,F(2),X(6),F(9,6);
END;
END;
PHP
Lenguaje que se acopla al HTML
(páginas web) para definir procedimientos que ha de
realizar el servidor de web, por ejemplo procesar un
formulario, enviar o extraer datos de una base de datos (acoplándose también
con un lenguaje de tipo SQL),
enviar una u otra página web según determinadas
condiciones prefijadas por el programador, etc.
PROLOG
Los primeros años de la décado del 70 son conocidos
como un período de "crisis del software", en que se descubrió que la
creación de buenos programas involucraba costos mayores que los del hardware
que los ejecuta. También se hacía patente una creciente necesidad de procesar
"conocimientos" (algo mucho más amplio y complejo que los datos
cuantitativos o meras "secuencias de caracteres" a los cuales se
reducen muchos lenguajes de programación). Esta crisis llevó a investigar
numerosas alternativas, entre las cuales nuevos lenguajes no basados en
instrucciones algorítmicas o procedimientos. Si el hombre "procesa"
más información por inferencia lógica que por cálculo, ¿no podría la máquina
hacer lo mismo?
PROLOG ("PROgramación en LOGica")
es una respuesta a esta crisis, producto del avance de la lógica moderna (de
tipo funcional). Lo crearon A. Colmenauer y Ph. Roussel, con la colaboración
de R. Kowalski, simultáneamente en la Universidad de Aix-Marseille (Francia) y
Edimburgo (Gran Bretaña). Se basa en el cálculo de predicados de primer orden y
en el principio de resolución de Robinson. En vez de
ser algorítmico ("procedural" en inglés,
término sin traducción), es decir concebido como un conjunto de instrucciones
que la máquina debe ejecutar en forma secuencial, es "declarativo",
es decir basado en definiciones (de "hechos" o "reglas",
como se explica más abajo).
EJEMPLO
Si sabemos que una línea aérea une París con
Río con el vuelo 36 y otra une Río con Santiago con el vuelo 71, concluimos sin
dificultad alguna que es posible viajar de París a Santiago con una escala en
Río.
En lógica funcional, los datos básicos ("hechos" en
terminología PROLOG) podrían escribirse:
une(Paris,Rio,Vuelo36).
une(Rio,Santiago,Vuelo71).
Vemos que la relación ("une") es la
misma y que hay un término común en la lista de argumentos (lo que hay entre
paréntesis). Solo falta explicitar una regla idéntica a la que se usa para
extraer una conclusión a partir de dos premisas en un silogismo:
camino(Paris,Santiago) <-
une(Paris, x, n),
une(x, Santiago, m).
o sea "Hay un camino entre París y Santiago si
algún vuelo (n) une París con una ciudad 'x' y (&) otro vuelo (m) une esta
ciudad 'x' con Santiago.
Un "programa" en PROLOG se conforma con
estos dos tipos de expresiones (llamadas "cláusulas"):
"hechos" y "reglas". Una cláusula con forma de hecho y
seguida de un '?' constituye la forma habitual de
consultar la información. Si no contiene ninguna variable, el programa verifica
si existe una "copia" en la lista de hechos y contesta por sí o no.
Si contiene una o más variables busca cuales se ajustan a la descripción o
pueden ser deducidas mediante las reglas y señala el valor correcto de las
diferentes variables (o bien "No" si no hay respuesta posible).
SQL
Lenguaje desarrollado especialmente para facilitar la consulta de bases de
datos (BD), acotando progresivamente la búsqueda (de ahí el nombre de "Sequential Query Language").
Existen hoy numerosas aplicaciones de administración de bases de datos que
recurren al SQL (Las más conocidas, potentes - y caras - son Oracle e Informix).
Hoy se pueden acoplar las bases de datos a hipertextos (páginas web), para lo cual las buenas aplicaciones ya traen módulos
que hacen la conexión. El lenguaje PHP del
cual hablamos más arriba también sirve para definir procedimientos de inserción
y de consulta de datos en BD (Base de Datos) que funcionan con SQL.
Linux
Linux es una implementación del sistema operativo UNIX
(uno más de entre los numerosos clónicos del histórico Unix),
pero con la originalidad de ser gratuito y a la vez muy potente, que sale muy
bien parado (no pocas veces victorioso) al compararlo con las versiones
comerciales para sistemas de mayor envergadura y por tanto teóricamente
superiores. Comenzó como proyecto personal del –entonces estudiante- Linus Torvalds, quien tomó como
punto de partida otro viejo conocido, el Minix de Andy. S. Tanenbaum (profesor de
sistemas operativos que creó su propio sistema operativo Unix
en PCs XT para usarlo en su docencia). Actualmente Linus lo sigue desarrollando, pero a estas alturas el
principal autor es la red Internet, desde donde una gigantesca familia de
programadores y usuarios aportan diariamente su tiempo aumentando sus
prestaciones y dando información y soporte técnico mútuo.
La versión original -y aun predominante- comenzó para PCs
compatibles (Intel 386 y superiores), existiendo
también en desarrollo versiones para prácticamente todo tipo de plataformas:
PowerPC
<http://www.cs.us.es/archive/linuxppc/>,
Sparc
<http://www.geog.ubc.ca/sparclinux.html>,
Alpha
<http://www.azstarnet.com/~axplinux>,
Mips <http://www.fnet.fr/linux-mips/>,
etc.
De todas ellas la más reciente en este momento es
la versión para PowerMac
<http://www.mklinux.org> (el PowerPC de Apple) basada en el microkernel
Mach 3.0 y de la que ya hay una distribución para desarrolladores avalada directamente
por Apple y OSF pero conservando el espíritu
(gratuito, de libre distribución, etc) de la version original. Un servidor la acaba de probar hace unos
días y se ha llevado una grata sorpresa (aún tendrá muuuchos
fallos, pero para ser una primerísima versión y el
poco tiempo que lleva en marcha, ha avanzado más de lo que me esperaba).
Ejemplo de linux:
Compilar el Kernel
Dado que un diskette sólo
almacena 1.44 Megabytes (1440 Kilobytes)
de datos, no puedes el mismo kernel que utilizas al diskette. Primero debes conseguir los fuentes del núcleo y
descomprimirlos en /usr/src/linux. Luego ejecuta la siguiente orden desde el directorio
/usr/src/linux:
make config
Configura solamente aquello que realmente
necesites. Yo, personalmente, sólo configuro el soporte para "ext2",
soporte para la disquetera (floppy disk), y soporte
para "PPP". Tus elecciones pueden se diferentes en función de lo que
decidas incluir. Ahora introduce el siguiente comando:
make dep;
make clean; make zImage
¡make
zImage es muy importante! Comprime el kernel definitivo. Después de que termine la compilación,
deberás buscar el nuevo núcleo en /usr/src/linux/arch/i386/boot bajo el
nombre de zImage.
El sistema de ficheros: No es solamente un conjunto
de ficheros
Ahora hemos de crear el sistema de ficheros (en
inglés: filesystem, fs)
para el diskette. En vez de copiar los ficheros tal
cual directamente al diskette, los comprimiremos
antes de copiarlos. Esto nos hará un poco más difícil la faena de modificar
todo permanentemente. Primero tecleamos el siguiente
comando:
dd if=/dev/zero of=[DEVICE]
bs=1k count=3000
Donde [DEVICE] es "lugar" en el disco
duro donde vas a guardar el sistema de ficheros descomprimido. Luego, introduce
el siguiente comando y pulsa ENTER, sustituyendo [DEVICE] por el directorio en
tu disco duro donde estás guardando el sistema de ficheros descomprimido:
mke2fs -m 0
[DEVICE]
Si make2fs te pregunta si realmente quieres hacer
esto (Do you really want to do this?),
acepta tecleando "y" (yes).
Después tenemos que montar este sistema de ficheros
que hemos creado. Para ello, el núcleo que utilices tiene que permitir
"montar ficheros", en otras palabras, ha de tener habilitada la
posibilidad de "loopback devices".
Para ello has de compilar el núcleo de tu máquina (no el núcleo que hemos
creado, sino el de tu propia máquina) con la opción:
Loopback device support (CONFIG_BLK_DEV_LOOP) [M/n/y/?]
bien como módulo (M) o en el mismo núcleo (Y). Si lo
compilas como módulo (lo más recomendable) luego tienes que insertar el módulo modprobe loop !No olvides rearrancar la máquina
si has tenido que recompilar el núcleo!
mount -t ext2 DEVICE /mnt
Si se queja la orden mount
puedes intentar con la siguiente orden:
mount -o loop -t ext2 DEVICE /mnt
Ahora debes copiar todos los ficheros que necesites
en el nuevo sistema de ficheros. Primero, ponte en el directorio /mnt, (cd /mnt),
y crea los siguientes directorios:
/dev
/pro
/etc
/bin
/lib
/mnt
/usr
Ahora crearemos el directorio /dev
tecleando lo siguiente:
cp -dpR /dev
/mnt/dev
Si se te acaban los i-nodos
del diskette, puedes ir a /mnt/dev y borrar los archivos de dispositivo que no necesites.
Cuando acabes de copiar los ficheros necesarios para /dev,
ves a /etc. Para estar seguro copia todos los ficheros de /etc
a /mnt/etc:
cp -dpR /etc
/mnt/etc
Luego copia todo del directorio /lib en /mnt:
cp -dpR /lib
/mnt/lib
Para el directorio /bin,
copia sólo aquello que creas que necesitas en /mnt/bin.
Copiar todo a tu diskette
Ahora hemos de copiar todo en el/los diskette/s. Para hacer esto, debemos comprimir ahora el
sistema de ficheros tecleando las siguientes ordenes:
cd /
umount /mnt
dd if=[DEVICE] bs=1k | gzip -9 > rootfs.gz
Ahora es importante comprobar el tamaño del núcleo.
Ponte en /usr/src/linux/arch/i386/boot y teclea "ls -l".
Luego divide el tamaño del núcleo entre 1024.
Por ejemplo, si el tamaño es de 250000 bytes, entonces son 245 KB. En adelante, reemplaza
[ROOTBEGIN] en las ordenes que aparezca por el número total de kilobytes que has calculado. Ahora copia el kernel al diskette usando el
siguiente comando:
dd if=zImage
of=/dev/fd0
Este comando grabará el kernel
en el diskette. Luego introduce el siguiente comando
para que el kernel pueda encontrar la raíz del
sistema de ficheros en el diskette.
rdev /dev/fd0 /dev/fd0
Ahora tendrás que hacer un pequeño cálculo en hexadecimal. Suma 4000 al equivalente en hexadecimal de [ROOTBEGIN] (que en nuestro ejemplo es F5).
Convierte el resultado a decimal y teclea el siguiente comando, sustituyendo
16629 con el resultado que tú has obtenido:
rdev -r /dev/fd0
16629
Finalmente, teclea lo siguiente para copiar el
sistema de ficheros al diskette:
dd if=/rootfs.gz
of=/dev/fd0 bs=1k seek=[ROOTBEGIN]
El sistema de ficheros raíz será copiado al diskette justo después del kernel.
¡Ya lo tienes! Para el segundo diskette, el proceso
es más fácil. Copia los ficheros que quieras en el diskette.
No obstante, para poder usar los ficheros que hay en el segundo disco, tendrás
que entrar lo siguiente después de arrancar con el diskette:
mount /dev/fd0
/usr
El "COMPILADOR"
es un programa especial destinado a traducir automáticamente un lenguaje
de segunda o tercera generación en código de máquina (bits), de tal modo que
todas las instrucciones y los datos contenidos en el programa estén en condiciones
de ser reconocidos y ejecutados por la CPU. El programa original se llama
"programa fuente" y se conserva igual que un texto preparado con un
procesador de palabras. La "traducción" es una serie diferentes de
caracteres (utilizables por la CPU) que debe ser grabado en otro espacio de
memoria auxiliar. Se llama "programa objeto". El usuario
"carga" el programa objeto en la memoria principal (RAM) cuando desea
utilizarlo. (Los programas comerciales que compramos vienen bajo la forma de
"programa objeto").
Dado que cada procesador tiene su propio "set"
de instrucciones, los compiladores deben estar asociados a los diversos modelos
de procesadores (p.ej. Intel
8088, Motorola 68000, PowerPC).
Y ya que existen múltiples lenguajes de más alto nivel que el código de
máquina, también están ligados a dichos lenguajes. En consecuencia, debería
haber un número de compiladores igual al número de modelos de procesadores
multiplicado por el número de lenguajes (ej.
compilador de PASCAL para Motorola 68000, para Intel 8088, etc.; de BASIC para Motorola 68000, para Intel 8088,
etc.; etc.).
En la realidad el número es menor, ya que no se confeccionan compiladores para
todas las combinaciones posibles.
Los "INTERPRETES"
son programas especiales destinados a "traducir" programas redactados
en lenguajes de tercera generación, pero operan de un modo distinto de los
compiladores. Aquí, no se crea un "programa objeto", sino que -cada
vez que se desea usar el programa fuente- se opera leyéndolo y traduciéndolo
instrucción por instrucción en lenguaje de máquina. En este caso, el
intérprete debe estar previa y constantemente disponible en la memoria
principal, ya que de él depende la ejecución del programa.
Los primeros microcomputadores (especialmente los modelos
"hogareños") se entregaban con un intérprete de BASIC
"incorporado", lo cual quiere decir que tenían un chip con el
intérprete grabado en ROM, adjunto al procesador. De este modo podían traducir
y ejecutar instrucciones de BASIC desde el momento en
que se encendían.