1.25k likes | 1.68k Views
LENGUAJES DE PROGRAMACIÓN. Javier Martín Centro Asociado de Móstoles UNED. Introducción. JAVIER MARTIN (jmartin@escet.urjc.es) TUTORIAS: JUEVES de 5 a 7 PLAN DE TRABAJO Exposición de los temas y mediante transparencia, abundando en los puntos más importantes. Resolución de dudas
E N D
LENGUAJES DE PROGRAMACIÓN Javier Martín Centro Asociado de Móstoles UNED
Introducción • JAVIER MARTIN (jmartin@escet.urjc.es) • TUTORIAS: JUEVES de 5 a 7 • PLAN DE TRABAJO • Exposición de los temas y mediante transparencia, abundando en los puntos más importantes. • Resolución de dudas • Propuesta y resolución de ejercicios y problemas
Unidad Didáctica 0: “Introducción” • Tema 1: • “El estudio de los lenguajes de programación”
¿Porqué estudiar lenguajes de programación? • La pregunta es ¿cuál es la ventaja de estudiar una variedad de lenguajes diferentes que es poco probable que uno llegue a utilizar?: • Mejorar la habilidad para desarrollar algoritmos eficaces. • Mejorar el uso del lenguaje de programación disponible. • Acrecentar el propio vocabulario con construcciones útiles sobre programación. • Hacer posible una mejor elección del lenguaje de programación. • Facilitar el aprendizaje de un nuevo lenguaje. • Facilitar el diseño de un nuevo lenguaje.
Breve historia de los lenguajes de programación: • Desarrollo de los primeros lenguajes: • Lenguajes basados en el cálculo numérico (Ejemplo: FORTRAN). • Lenguajes para negocios (Ejemplo: COBOL). • Lenguajes para Inteligencia Artificial (Ejemplo: LISP). • Lenguajes para sistemas (Ejemplo: C).
Evolución de los Lenguajes de Programación Declarativos
Evolución de los Lenguajes de Programación Orientados a Objetos e Imperativos
El papel de los lenguajes de programación • Inicialmente los lenguajes se proyectaban para ejecutar programas con eficiencia. A mediados de los años sesenta la programación cambia: • Las máquinas son menos costosas y aumentan los costos de programación. • Surge la necesidad de trasladar programas de unos sistemas a otros. • El mantenimiento del producto consume mayores recursos de cómputo. • La tarea del lenguaje de alto nivel es la de facilitar el desarrollo de programas correctos para resolver problemas en alguna área de aplicación dada. • Los lenguajes de programación evolucionan o dejan de usarse. Influencias que obligan a la revisión del los lenguajes: • Capacidad de las computadoras. • Aplicaciones: Los requerimientos de nuevas áreas de aplicación afectan los diseños de nuevos lenguajes y las revisiones y ampliaciones de los más antiguos. • Métodos de programación. • Métodos de implementación. • Estudios teóricos. • Estandarización.
Atributos de un buen lenguaje • Claridad, sencillez y unidad (legibilidad): La sintaxis del lenguaje afecta la facilidad con la que un programa se puede escribir, por a prueba, y más tarde entender y modificar. • Ortogonalidad: Capacidad para combinar varias características de un lenguaje en todas las combinaciones posibles, de manera que todas ellas tengan significado. • Naturalidad para la aplicación: La sintaxis del programa debe permitir que la estructura del programa refleje la estructura lógica subyacente. • Apoyo para la abstracción: Una parte importante de la tarea del programador es proyectar las abstracciones adecuadas para la solución del problema y luego implementar esas abstracciones empleando las capacidades más primitivas que provee el lenguaje de programación mismo. • Facilidad para verificar programas: La sencillez de la estructura semántica y sintáctica ayuda a simplificar la verificación de programas. • Entorno de programación: Facilita el trabajo con un lenguaje técnicamente débil en comparación con un lenguaje más fuerte con poco apoyo externo. • Portabilidad de programas • Costo de uso: • 1. Costo de ejecución del programa. • 2. Costo de traducción de programas. • 3. Costo de creación, prueba y uso de programas. • 4. Costo de mantenimiento de los programas: costo total del ciclo de vida.
Dominios de aplicación • Aplicaciones de los años sesenta. Durante la década de 1960, casi toda la programación se podía dividir en cuatro modelos básicos de programación: • De procesamiento de negocios (COBOL). • Científicos (FORTRAN). • De sistemas (ALGOL, JOVIAL, etc.): Para construir sistemas operativos. • De Inteligencia Artificial (LISP). • Aplicaciones de los años noventa. La situación actual tiene más dominios de aplicación: • De procesamiento de negocios (COBOL). • Científicos (FORTRAN 90). • De sistemas: Con el advenimiento de los microprocesadores baratos que gobiernan automóviles, hornos de microondas, etc., ha aumentado la necesidad de contar con lenguajes para tiempo real. • Edición: Los sistemas de procesamiento de texto tienen su propia sintaxis para mandatos de entrada y archivos de salida. El traductor TEX produce un programa en el lenguaje PostScript de descripción de páginas. PostScript se puede compilar por medir de un procesador adecuado. Éste suele ser la impresora láser que se utiliza para imprimir el documento. • De proceso: Dentro de UNIX, el lenguaje de comandos de usuario se conoce como shell y a los programas se les llama guiones de shell (parecidos a los archivos .bat). Estos guiones se pueden invocar siempre que ocurren ciertas condiciones habilitadoras.
Estandarización de los lenguajes • Los estándares son en general de dos clases: • 1. Estándares patentados (DE PACTO): Son las definiciones elaboradas por la compañía que desarrollo el lenguaje y que es su propietaria. • 2. Estándares de consenso (DE FACTO): Se trata de documentos elaborados por organizaciones con base en un acuerdo entre los participantes pertinentes. Método principal para asegurar la uniformidad entre varias implementaciones de un lenguaje. Ejemplo: ANSI, IEEE, ISO, etc.. • Proceso en el desarrollo de normas: Un grupo decide que un lenguaje requiere una definición estándar. El organismo normativo organiza un grupo de trabajo de voluntarios para desarrollar esa norma. Cuando el grupo de trabajo llega a un acuerdo sobre su norma, se somete a votación por parte de un bloque más grande de individuos interesados. Los desacuerdos se resuelven y se produce el estándar del lenguaje.
Uso de estándares en forma eficaz • Es necesario ocuparse de tres cuestiones: • Oportunidad (¿Cuándo estandarizar un lenguaje?): Lo deseable sería estandarizar un lenguaje lo suficientemente pronto para que exista suficiente experiencia en el uso del lenguaje, pero no demasiado tarde, para no alentar muchas implementaciones incompatibles. • Conformidad (¿Qué significa que un programa se adhiere a un estándar y que un compilador compila un estándar?): Si existe un estándar para un lenguaje, se suele hablar de conformidad con respecto a ese estándar. Un programa es conforme si sólo utiliza características definidas en el estándar. Un compilador conformable es uno que, cuando se le da un programa conforme, produce un programa ejecutable que genera la salida correcta. • Obsolescencia (¿Cuándo envejece un estándar y cómo se modifica?): Los estándares se tienen que revisar cada 5 años y ya sea renovarse o descartarse. Casi todos los estándares requieren compatibilidad hacia atrás; El nuevo estándar debe incluir versiones más antiguas del lenguaje. Esto tiene el problema de que el lenguaje se puede hacer difícil de manejar a causa de las numerosas construcciones obsoletas. Una característica es obsolescentesi es candidata a ser descartada en la próxima versión del estándar. Una característica desaprobada se puede volver obsolescente en el próximo estándar, por lo cual puede ser descartada después de dos revisiones.
Efectos de los entornos sobre los lenguajes • Cuatro clases generales de entornos objetivo cubre casi todas las aplicaciones de programación: • de procesamiento por lotes, • interactivo, • de sistema empotrado, y • de programación (entorno interactivo). Cada uno plantea distintos requerimientos sobre los lenguajes adaptados a esos entornos.
Entornos de procesamiento por lotes • El más simple entorno operativo se compone sólo de archivos externos de datos. Un programa toma un cierto conjunto de archivos de datos como entrada, procesa los datos y produce un conjunto de archivos de datos de salida. El nombre de procesamiento por lotes viene porque los datos de entrada se reúnen en “lotes” de archivos y son procesados en lotes por programas. • Los archivos constituyen la base para casi toda la estructura de E/S. • Un error que termine la ejecución del programa es aceptable aunque costoso. No es posible la ayuda externa por parte del usuario para manejar o corregir errores de inmediato. • Carencia de restricciones de regulación de tiempo. No hay recursos para monitorear o afectar directamente la velocidad de ejecución del programa.
Entornos interactivos • El programa interactúa durante su ejecución directa con un usuario en una consola de visualización, enviando alternativamente salidas hacia ésta y recibiendo entradas desde el teclado o ratón (procesadores de texto, hojas de cálculo, juegos, etc.). • Las características de E/S interactivas son diferentes de las operaciones ordinarias con archivos. • El programa debe ser capaz de gestionar el manejo de errores. La terminación del programa como respuesta aun error no es ordinariamente aceptable (a diferencia del procesamiento por lotes). • Los programas interactivos deben utilizar con frecuencia algún concepto de restricciones de tiempo. • El concepto de programa principal suele estar ausente. En su lugar, el programa se compone de un conjunto de subprogramas y el usuario introduce el “programa principal como una serie de comandos en el terminal.
Entornos de sistemas incrustados (empotrados) • Un sistema de computadora que se usa para controlar parte de un sistema más grande como una planta industrial, una aeronave, etc., se conoce con el nombre de sistema de computadora incrustado. El fallo de una aplicación empotrada puede poner en peligro la vida. La seguridad de funcionamiento y corrección son atributos principales. • Suelen operar sin un sistema operativo subyacente y sin archivos de entorno y dispositivos de E/S usuales. El programa debe interactuar directamente con la máquina. • El manejo de errores tiene gran importancia. Cada programa debe estar preparado para manejar todos los errores en forma interna, adoptando acciones apropiadas para recuperarse y continuar. La interrupción del programa no es aceptable y no hay un usuario en el entorno que pueda proporcionar la corrección interactiva del error. • Operan en tiempo real, donde la respuesta las entradas debe producirse en intervalos de tiempo restringidos. • Suele ser un sistema distribuido, compuesto por más de una computadora. • Una vez iniciadas las tareas, se ejecutan por lo común de forma simultánea e indefinida.
Entornos de programación • Es el entorno en el cual los programas se crean y se ponen a prueba. Consiste en un conjunto de herramientas (editor, depurador, verificador, generadores de datos de prueba, etc.) de apoyo y un lenguaje para invocarlas. • Al compilar por separado cada subprograma el compilador necesita información de: • La especificación del número, orden y tipo de parámetros. • La declaración de tipo de datos. • La definición de un tipo de datos (para la declaración local de variables). • Un problema común, es encontrar, durante el ensamblado del programa final completo, que varios subprogramas y otras unidades de programa tienen nombres (de variables) iguales. Métodos para evitar este problema: • Todo nombre compartido debe ser único. Se deben usar convenciones para la asignación de nombres desde un principio. • Definir, en el lenguaje, reglas de ámbito, para ocultar nombre. • Los nombres se pueden conocer agregando explícitamente sus definiciones desde una biblioteca externa (herencia en POO). • Características que ayudan a poner a prueba y depurar programas. • Características para rastreo de ejecución. • Puntos de interrupción. Cuando se alcanza un punto de interrupción durante la ejecución del programa, la misma se interrumpe y el control se traslada al programador en un terminal. • Asertos: expresan relaciones que deben cumplirse entre los valores de las variables en ese punto del programa.
Marcos de ambiente • Un ambiente de apoyo consiste en servicios de infraestructura que se conocen como marco de ambiente. Este marco suministra servicios como un depósito de datos, interfaz gráfica de usuario, seguridad y servicios de comunicación. Los programas se escriben de modo que utilicen estos servicios.
Máquinas virtuales • Aunque hay muchos rasgos que se podrían destacar como candidatos para formar parte de una definición del concepto de máquina virtual (a partir de ahora MV), una MV se puede definir sencillamente como una capa de abstracción que separa el funcionamiento de un ordenador de su hardware. Además, las MV se dividen en abstractas o teóricas, como sería la máquina de Turing (el primer ejemplo de una MV), y concretas o prácticas (a las que se quiere normalmente se hace referencia al hablar de MV). En esta sección se tratarán las MV concretas que, como se verá, son capas de software que juegan un papel relevante tanto en el funcionamiento de los lenguajes compilados como interpretados.
Introducción al concepto • Las MV se construyeron para simplificar el proceso del control del hardware de un ordenador porque extienden y enmascaran la funcionalidad del hardware a través de procedimientos y datos abstractos. • Se pueden identificar dos tipos de MV concretas: • las que juegan un papel en la preparación de un programa para su ejecución (tiempo de compilación) y • las que permiten la ejecución de dicho programa. La figura muestra la diferencia entre los dos tipos:
El papel de las máquinas virtuales en la compilación y la ejecución de un programa.
Introducción al concepto • Las MV suelen aparecer en una jerarquía. Usamos la jerarquía de MV de compilación, por ejemplo, cada vez que invocamos el compilador de C++. Y dos ejemplos muy comunes del papel de una MV en la jerarquía de MV de ejecución son PostScript (que define una MV para una impresora) y MSDOS bajo MS Windows (que define una MV que permite que antiguos programas de DOS funcionen bajo Windows). • PostScript es una MV que incluye el estado gráfico, la ruta actual, el estado del diccionario y, aunque sea bastante complejo, presenta una visión de alto nivel de muchos tipos distintos de impresoras, aislando las características de las impresoras de las aplicaciones que las usan. • A la hora de implementar un lenguaje de programación, las estructuras de datos y algoritmos utilizados en la ejecución de un programa (es decir, la sintaxis y semántica de cada estructura) definen las MV (implícitamente) para este lenguaje. Y las decisiones que toma el desarrollador afectan tanto a la traducción como a la ejecución de los programas escritos en este lenguaje. Las MV se distinguen entre sí según tres criterios: • •La concepción de las MV que tiene el desarrollador basada en la definición del lenguaje. • •Las facilidades disponibles en el hardware del ordenador. • •Las decisiones de implementación tomadas por los desarrolladores.
Introducción al concepto • Aunque se puede escribir un compilador para traducir (o compilar) un programa escrito en un lenguaje de alto nivel directamente al código máquina (en el sentido de no depender de ninguna otra pieza en el sistema para producirlo), no es nada común hacerlo hoy en día por varias razones, dos de las cuales son: • Cuando aparezca en el mercado el siguiente procesador (por ejemplo, Pentium IVdespués de Pentium III), habrá que modificar el compilador. • No tiene sentido repetir el proceso de diseño y desarrollo, que es costoso, cuando ya se ha hecho lo mismo muchas veces antes para otros lenguajes para una máquina concreta. • Un caso lo constituyen los compiladores C, que ya llevan mucho tiempo en funcionamiento y son muy eficientes y estables. Por lo tanto, hay varios lenguajes como C++ (al menos en las primeras versiones) cuyo “compilador” tradujo el código fuente de C++ a C para poder luego usar el compilador C estándar. En general, sólo se suele rediseñar un compilador nuevo desde cero cuando los ingenieros del lenguaje están intentando alcanzar nuevos objetivos para ese lenguaje, en caso de que vayan más allá que el modelo funcional de los compiladores ya disponibles como, por ejemplo, es el caso de Java.
Jerarquías de máquinas virtuales • La realidad es que el desarrollador de un lenguaje suele implementar las MV (de compilación y/o ejecución) de su lenguaje en términos de otras MV ya existentes. Y en el futuro, un programador de aplicaciones utilizará las MV implementadas por el desarrollador del lenguaje para producir programas que a su vez puedan servir como MV para otras aplicaciones, etc. La conclusión, como puede verse, es que una MV no suele existir aislada, sino como parte de una jerarquía de MV. A continuación se va a ver el papel de las jerarquías de MV en el tiempo de compilación y de ejecución. • En primer lugar, se va a considerar el papel de la jerarquía de MV en el tiempo de compilación. En el caso de C++, como lenguaje de alto nivel que se compila a un lenguaje tan cerca del nivel de máquina como sea posible, se puede ver que el proceso de compilación de un programa de C++ consiste en la interacción de la jerarquía de MV mostrada en la figura 2 (aunque puede haber diferencias entre compiladores de C++; por ejemplo, aquí se supone que es un proceso de compilación que usa C como código intermedio). El pre-procesador acepta el código C++ como fuente y produce otra versión del mismo código C++ con algunas extensiones e incorporaciones resueltas. El traductor convierte el código fuente C++ estándar a código fuente C. El compilador C acepta este código como fuente y lo traduce a código ensamblador (una representación simbólica del código máquina). El ensamblador traduce este código simbólico a un código máquina reubicable. Y por fin, el cargador de librerías acepta este código máquina como entrada y produce un programa simple ejecutable, compuesto por el código máquina de entrada y todos los subprogramas necesarios con direcciones de memoria contiguas. Además del proceso de compilación, la traducción completa de los programas de alto nivel (previa a su ejecución) en una forma que corre sobre la máquina, también existe otro proceso, que se llama interpretación, que tiene más que ver con el papel de las MV en el tiempo de ejecución que en el tiempo de compilación.
Jerarquías de máquinas virtuales • Además de los lenguajes compilados “completamente”, hay otros que son compilados “parcialmente” en el sentido de que terminan el proceso de compilación en un código (o lenguaje) intermedio, en vez de en código máquina (lenguajes intermedios). • En segundo lugar, vamos a considerar el papel de la jerarquía de MV en el tiempo de ejecución. Se puede ver un ejemplo en la figura 3. Como se puede ver en él, lo que se podría llamar una aplicación Web (unas páginas Web con elementos interactivos incrustados) está escrita en HTML y funciona sobre una MV dada por el navegador Web, que a su vez está implementado en C o C++. Éste corre sobre una MV compuesta por las librerías de tiempo de ejecución que encapsulan el funcionamiento de los procedimientos (o métodos) y datos de navegador Web que, a su vez, utilizan las funciones de la MV del sistema operativo implementadas en código máquina. Y los programas que componen esta MV corren sobre el firmware, un conjunto de programas de micro-código que controlan directamente el hardware del ordenador.
Jerarquías de máquinas virtuales • Las jerarquías del tipo mostrado en la figura tienen una estructura muy parecida a una jerarquía “usa”, donde cada capa usa la capa que está directamente debajo. La diferencia es que una MV puede tener una interfaz hacia abajo, además de la interfaz hacia arriba, que especifica los servicios que requiere de la capa inferior, pero sin especificar exactamente qué implementación de los servicios es necesario. • Un ejemplo sería la jerarquía de MV que compone el sistema de ventanas X, donde hay una capa que define el funcionamiento independientemente de los dispositivos y, directamente debajo, una capa que define el funcionamiento en términos de los dispositivos. Aquí X depende de la capa que depende de los dispositivos, no de una implementación en concreto de esta capa (por lo tanto, hay versiones de X para muchos tipos de hardware donde la única diferencia es la implementación de la capa relacionada con los dispositivos; las demás capas superiores son idénticas).
Lenguajes intermedios • Un lenguaje intermedio se puede definir como una manera de representar procedimientos y estructuras de datos que sirva como entrada para una MV en alguna parte de su jerarquía, entre el lenguaje de entrada (el nivel más alto) y el código ejecutado en la máquina (el nivel más bajo) tanto en el tiempo de compilación como en el de ejecución.
Lenguajes intermedios • Un lenguaje intermedio se puede definir como una manera de representar procedimientos y estructuras de datos que sirva como entrada para una MV en alguna parte de su jerarquía, entre el lenguaje de entrada (el nivel más alto) y el código ejecutado en la máquina (el nivel más bajo) tanto en el tiempo de compilación como en el de ejecución.
Lenguajes intermedios • Para considerar el papel de los lenguajes intermedios y sus ventajas y desventajas, conviene destacar la diferencia entre la traducción de un lenguaje de alto nivel a código máquina anteriormente a su ejecución (su compilación) y su interpretación, es decir, la conversión de cada instrucción del lenguaje a código máquina y su ejecución, una por una, al ejecutar el programa. Este proceso se realiza a través de una MV de interpretación que simula un ordenador cuyo código máquina es el lenguaje de alto nivel que está siendo interpretado. Y típicamente, esta MV se construye a través de un conjunto de programas de código máquina que representa los algoritmos y estructuras de datos necesarios para la ejecución de las instrucciones del lenguaje de alto nivel. Hay ventajas y desventajas en cada manera de convertir los lenguajes de alto nivel a código máquina, que se pueden resumir así:
Lenguajes intermedios • Estos dos casos representan los dos extremos porque, como ya se ha visto, existe también lo que se llama la compilación parcial, que es una mezcla de los dos enfoques, donde se compila el lenguaje de alto nivel a un lenguaje intermedio (más cerca de las estructuras presentes en el código máquina que las del código fuente) y luego se interpreta este lenguaje al ejecutar el programa. • Como puede imaginarse, esta técnica combina las ventajas y desventajas de los dos enfoques anteriores. Un ejemplo de esta combinación existe en el lenguaje de programación Java y su entorno.
Lenguajes intermedios • Entre otras cosas, Java empezó con la idea de liberar al programador de las dificultades de portar su aplicación a nuevas plataformas lo cual, si el programa está muy vinculado a algún aspecto del sistema operativo donde fue escrito, podría ser muy difícil. • Se compilará el código fuente de Java a un código byte (bytecode) antes de ejecutarlo. Y a la hora de correr el programa, este código, como lenguaje intermedio, sería el lenguaje de entrada para una MV, que con un conjunto de librerías (el entorno de ejecución de Java, Java Runtime o JRE), la interpretaría para su ejecución. • Por lo tanto, este bytecode podría correr en cualquier hardware donde haya una versión del JRE disponible. Como este bytecode está más cerca del nivel de máquina que de un lenguaje de alto nivel, los programas correrán más rápidamente que los programas completamente interpretados, aunque más despacio que los programas previamente compilados al código máquina.
Lenguajes intermedios • Como se puede ver en la figura 1, tanto los programas compilados parcialmente a un lenguaje intermedio (como Java) como los programas escritos en lenguajes de alto nivel que se interpretan (como Lisp) requieren una MV para interpretar el programa. La principal ventaja del lenguaje intermedio en este caso es su proximidad al nivel del código máquina, en el sentido de que supone menos trabajo a la hora de ejecutarlo y, por lo tanto, los programas corren más rápidamente que los puramente interpretados.
Lenguajes intermedios • Además del papel de los lenguajes intermedios en la compilación parcial, se puede destacar su papel en la compilación estándar. Como ejemplo se puede considerar C como lenguaje intermedio para un lenguaje compilado nuevo. Si el autor de un nuevo lenguaje decide utilizar C, por ejemplo, como su lenguaje intermedio, sólo tendrá que implementar una MV para convertir el código fuente de su lenguaje a C, ahorrando mucho trabajo.
Lenguajes intermedios • Las ventajas de utilizar un lenguaje tan establecido como C como lenguaje intermedio son: • •La facilidad de portar el lenguaje a una nueva máquina (sólo hay que tener un compilador C disponible allí). • •La generación de código máquina es una tarea muy compleja que requiere un conocimiento profundo de la arquitectura de la máquina en cuestión – y de cada máquina en que se quiere una versión del lenguaje. • •La facilidad de modificar algún rasgo del comportamiento del lenguaje en alguna máquina en concreto (por ejemplo, características de memoria o rendimiento – se pueden añadir librerías C customizadas sin grandes problemas). • •Las posibilidades disponibles para mapear estructuras intermedias del nuevo lenguaje a estructuras de datos de C.
Lenguajes intermedios • Y las desventajas son: • •La depuración es muy difícil porque, entre otras cosas, los errores que ocurren en el código C no son muy fáciles de localizar en lo que ha escrito el programador originalmente en el nuevo lenguaje. • •Las características de rendimiento y eficiencia del lenguaje están determinadas por el • compilador C. • •Habrá ocasiones en las que no exista una buena traducción entre una estructura en el nuevo lenguaje y las estructuras de datos en C, por lo que habrá una pérdida de eficiencia en el programa resultante (como, por ejemplo, ocurre en la mayoría de las ocasiones en que se compilan estructuras de Prolog a C – sólo se puede expresar iteración en Prolog utilizando recursión).
La máquina virtual de Java como ejemplo de una MV • La MV de Java es una máquina de pila. Las instrucciones interpretadas por ella manipulan datos almacenados como elementos en una pila. El contenido ejecutable de un archivo de bytecodes contiene un vector de instrucciones bytecode para cada método. Los bytecodes son instrucciones para la MV, que tiene algunos registros de variables locales y una pila para la evaluación de expresiones. • Las primeras variables locales son inicializadas con los parámetros actuales. Cada variable local o elemento de la pila es una palabra que corresponde a un entero de 32 bits, a un punto flotante o a una referencia a objeto (puntero). Para puntos flotantes dobles y enteros largos se utilizan dos huecos de la pila.
La máquina virtual de Java como ejemplo de una MV • Los huecos de la pila no están relacionados con un tipo de datos, es decir, en algún punto un hueco podría contener un valor entero y en otro, el mismo hueco podría contener una referencia a un objeto. Sin embargo, no se puede almacenar un entero en un hueco y luego recuperarlo reinterpretándolo como si fuera una referencia a un objeto. Aún más, en cualquier punto del programa, el contenido de cada hueco está asociado con un único tipo de datos que puede ser determinado usando un flujo estático de datos. • El tipo de datos podría ser “no asignado”, con lo cual no se permite leer el valor del hueco. Estas restricciones son parte del modelo de seguridad de Java y se ven reforzadas por el verificador de bytecodes.
La máquina virtual de Java como ejemplo de una MV • El código interpretado es generalmente más lento que un programa escrito en un lenguaje compilado, y Java no es distinto en este aspecto. Se han señalado muchas posibilidades para mejorar el rendimiento de los intérpretes. • Una muy común hoy en día es incluir un compilador relativamente simple en el tiempo de ejecución de la MV. Es decir, en vez de interpretar los bytecodes del programa una y otra vez, se compilan una sola vez “al instante” en el interior de la MV, y la representación compilada de los métodos que corresponden al programa es ejecutada al efectuar una llamada. Esto es conocido como un compilador al instante (o JIT, Just In Time).
Unidad Didáctica 1: “Sintaxis y Semántica de los Lenguajes de Programación” • Tema 2: • “Sintaxis formal de los lenguajes de programación”
Ver Sintaxis y Semántica del resumen en • Problema de traducción de lenguajes (Capitulo 2)
Unidad Didáctica 2: “Paradigmas y lenguajes ” • Tema 4: • “Descripción de los paradigmas más representativos ”
PARADIGMAS DE PROGRAMACIÓN • La clasificación de los lenguajes atendiendo a sus características intrínsecas conduce a los llamados paradigmas de programación. Un paradigma de programación es un modelo de programación que engloba a ciertos lenguajes que comparten: • Elementos estructurales: ¿con qué se confeccionan los programas? • Elementos metodológicos: ¿cómo se confecciona un programa?
Programación Imperativa o Procedural: FORTRAN • Es la primera que se desarrolla porque va determinando las operaciones que hay que realizar sobre una máquina ideal de Von Neumann. Desde este punto de vista un programa es una secuencia de acciones (instrucciones) que se realizan en un cierto orden determinado por el flujo del programa. • Las estructuras para el control son generalmente sentencias condicionales y bucles. Como un ejemplo ilustrativo veamos el aspecto de un programa en lenguaje Pascal que calcula el factorial de un número positivo x:
FORTRAN. Historia • Primer lenguaje de alto nivel (1957). • Desarrollado por IBM para el IBM 704. • Estaba orientado a la eficiencia en la ejecución. • Definición estándar del lenguaje en el 66. • Otras versiones: • FORTRAN 77 • FORTRAN 90
FORTRAN. Ejemplo PROGRAM TRIVIAL INTEGER I I=2 IF(I .GE. 2) CALL PRINTIT STOP END SUBROUTINE PRINTIT PRINT *,’Hola Mundo’ RETURN END
FORTRAN. Características Tipos de datos: • Numéricos (enteros, reales, complejos y doble precisión). • Booleanos (logical) • Arreglos • Cadenas de caracteres • Archivos • FORTRAN 90 ya es estructurado, y no requiere sentencias GOTO. • Sólo dos ámbitos para las variables: local y global
FORTRAN. Objetos de datos Variables y constantes • FORTRAN no es sensible a mayúsculas y minúsculas. Los nombre de variables tienen de 6 a 31 caracteres máximo y deben comenzar por una letra. Los blancos son significativos. • Declaración explicita de variables. • Enteras (I-N), el resto reales. (se modifica con IMPLICIT). • Punteros: en los primeros FORTRAN no hay punteros y todas las variables se almacenan en memoria estática. En FORTRAN 90 se declaran INTEGER, POINTER::P. • Para memoria dinámica ALLOCATE y DEALLOCATE
FORTRAN. Objetos de datos Tipos de datos estructurados • Arrays, pueden tener hasta 7 dimensiones y se guardan por colummnas. • REAL M(20),N(-5:5) • DIMENSION I(20,20) (tipo por nomenclatura implícita) • Cadenas de caracteres, el primer carácter es el 1, el operador // permite concatenar cadenas. • CHARACTER S*10, T*25 • Almacenamiento de datos. Se usa COMMON para datos compartidos y EQUIVALENCE cuando almacenamos una variable con dos posibles tipos en la misma posición de memoria (como union en C). Se usa DATA para inicializar datos estáticos. • DATA X/1.0/,Y/3.1416/,K/20/ • Tipos definidos por el usuario, con TYPE <nombre>... END TYPE <nombre>