Tema 29 – Utilidades para el desarrollo y prueba de programas.

Tema 29 – Utilidades para el desarrollo y prueba de programas.

1. HERRAMIENTAS PARA EL DESARROLLO DE PROGRAMAS. 1

2. COMPILADORES. 1

2.1 Introducción. 1

2.2 Análisis y síntesis. 2

2.3 Fases de análisis. 2

2.4 Fases de síntesis. 5

2.5 Fases de un compilador. 6

2.6 Administrador de la tabla de símbolos. 6

2.7 Manejador de errores. 6

2.8 Programas relacionados con un compilador. 7

2.9 Herramientas para la construcción de compiladores. 8

3. INTÉRPRETES. 8

4. COMPILADORES INTERPRETADOS. 8

5. DEPURADORES (Debuggers). 9

1. HERRAMIENTAS PARA EL DESARROLLO DE PROGRAMAS

Los lenguajes de alto nivel son los más sencillos de aprender y de depurar.

El ordenador solo entiende el lenguaje máquina (código binario). Por lo tanto, existen programas comerciales que toman nuestras instrucciones escritas en alto nivel y la pasan a bajo nivel. (traductores)

Hay 2 tipos de traductores:

· Compiladores: Toman un programa inicial (programa fuente) y generan un programa objeto. Primero traducimos el programa. Posteriormente lo ejecutamos.

· Intérpretes: Traducen y ejecutan las instrucciones simultáneamente y no genera ningún tipo de programa objeto.

Normalmente existen para el mismo lenguaje tanto compiladores como intérpretes. Aunque cuando se crea un lenguaje lo normal es que sea para traducirse con una u otra herramienta.

Compiladores

Intérpretes

Hay que traducir el programa fuente…

Una vez.

Cada vez que se ejecute el programa.

¿Genera programa objeto?

Si.

No.

La optimización se realiza…

A nivel global y local. Se consigue mayor eficiencia.

A nivel local. Se consigue menor eficiencia.

La localización de errores tiene lugar…

Al ejecutar y traducir el programa

Según vamos editando el fuente y en la ejecución.

¿Tiene depuradores? (Herramientas que facilitan la localización de errores)

Si.

No.

Ejemplos

Turbo Pascal, Turbo C++, Borland C++, Borland Pascal, QBASIC…

PC Scheme, GW Basic, SmallTalk, Lisp,Intérprete de comando de UNIX, Intérprete de SQL.

2. COMPILADORES

2.1 Introducción

clip_image002Toma un lenguaje alto nivel à devuelve un programa equivalente bajo nivel

De acuerdo al método que usan para la compilación, se clasifican en:

De una pasada: Sólo leemos la fuente una vez. Se tiene que resolver el problema de las sentencias de salto GOTO o JMP. Cuando procesamos esa línea no sabemos la dirección de la instrucción a la que hace referencia el salto. Por lo tanto, dejamos un hueco en la dirección de salto y cuando conocemos la misma parcheamos (volver atrás y darle el valor exacto a la dirección)

De dos pasadas: Accedemos 2 veces a la fuente del programa. Primera pasada resolvemos las referencias, y en la segunda, generamos el código.

Incrementales: Intentan, una vez compilado la fuente y después de modificarle alguna instrucción, evitar la recompilacion completa del programa.

Con optimización de código: Una vez compilado, se intenta simplificar el programa, ahorrar variables, optimizar instrucciones, Técnica PIPE LINE o mirilla (consiste en estudiar instrucciones próximas entre sí)

2.2 Análisis y síntesis

El trabajo de un compilador se divide en 2 fases:

Análisis o FrontEnd: Descomponemos el programa fuente en los elementos que lo componen à llevando al programa a una representación intermedia.

Síntesis o BackEnd: Partimos de esa representación intermedia y construimos el programa objeto.

Durante las 2 fases están siempre presentes el manejador de errores y el administrador de la tabla de símbolos.

clip_image004

2.3 Fases de análisis

El análisis del programa se divide en otras fases:

1. Simplificamos cada parte: Más sencillo dividir las 3 fases de forma independiente que una fase grande.

2. Aumenta la portabilidad: Podemos modificar una fase sin alterar las demás.

2.3.1 Análisis léxico

Los caracteres que componen nuestro programa se leen de izquierda a derecha y se agrupan en tokens (componentes léxicos)

El analizador léxico toma cada token generando una tabla de símbolos.

Ejemplos:

Total: = Parcial * 0.15 – Descuento

Operadores: = * –

Variables: Total, Parcial, Descuento

Constantes: 0.15

clip_image006

El analizador léxico trabaja conjuntamente con el analizado sintáctico (va solicitando el siguiente token a analizar)

clip_image007clip_image008clip_image009

Otras tareas que debe realizar el analizador léxico:

– Eliminación de espacios en blanco, y comentarios.

– Generador y manejo de errores correspondiente al análisis léxico.

– Proceso de macros.

– Listado de fuente: a veces se le añaden los números de las líneas…

Para construir análisis léxicos o scanners hay 2 formas:

– Hacerlo nosotros mismos

– Usar programas Lex o Flex

¿Cómo identificar un token? à Usando autómatas finitos deterministas à representan mediante grafo de transición:

1. Tiene un conjunto de estados finitos

2. Tiene un único estado inicial

3. Posee uno o más estados finales o de aceptación

4. Para pasar de un estado a otro, siempre hay que consumir, cada entrada tiene un único salto.

clip_image011

2.3.2 Análisis sintáctico

· clip_image012Los tokens se agrupan en unidades jerárquicas. Para representar estas unidades se usan árboles de análisis sintáctico.

· El analizado sintáctico o parser:

– Lo podemos crear nosotros con lenguaje de programación

– Utilizar herramientas para crearlo, como yacc, byson…

Para llegar a este árbol sintáctico es necesario usar una serie de reglas:

Por ejemplo: Las reglas que definen las expresiones:

1. E -> E Op E

2. E -> (E)

3. E -> -E

4. E -> ID

5. E -> Cte

6. Op -> + | – | * | / | ^

· Ejemplo de gramática, un conjunto de reglas que nos describen cómo escribir una expresión.

· La primera regla es básica, se denomina el símbolo inicial de la gramática. Primer patrón a examinar.

· Vamos a explicar las reglas:

1. Una expresión, puede estar formada por un operador y 2 expresiones más. (recursiva)

2. Una expresión puede estar entre paréntesis. (recursiva)

3. Una expresión puede estar precedida por signo menos. (recursiva)

4. Una expresión puede ser un identificador. (no recursiva)

5. Una expresión puede ser una constante. (no recursiva)

6. Los operadores que usamos serán la suma, resta, multiplicación, división y potencia.

2.3.3 Análisis semántico

Comprueba sin los componentes del programa tienen coherencia entre sí. Una de las tareas más importantes que realiza el análisis semántico es la revisión de tipos.

Principales tareas:

· Chequeo y conversión de tipos

· Comprobación de los accesos a índices de vectores (no se sale de los límites)

· Declaración de variables (¿declaración correcta?)

· Signatura de funciones. (nombramiento y llamamiento correcto a las funciones)

2.4 Fases de síntesis

Se divide en otras fases:

1. Generador de código intermedio:

Se basa en una máquina abstracta. Código de 3 direcciones es el más famosos. En este código cada instrucción tiene como máximo 2 operadores.

2. Optimizador de código: A partir del código intermedio tratamos de mejorarlo para que sea más rápido de ejecutar.

3. Generador de código: Creamos el código objeto que suele darse en código máquina reubicable. O ensamblador.

2.5 Fases de un compilador

Hemos de volver a rediseñar nuestro esquema del compilador.

clip_image013

2.6 Administrador de la tabla de símbolos

Contiene información sobre los diferentes identificadores que aparecen en el código fuente.

Cada vez que encontramos un identificador, tenemos que ir a la tabla de símbolos y comprobar si aparece, sino, hemos de añadirlo a la misma.

Número

Nombre

Tipo

Dirección

0

Total

Real

600

1

Parcial

Real

604

2

Descuento

Real

608

50

Calcular_factorial

Función

1500

2.7 Manejador de errores

Se encuentra presente en todas las partes de compilación.

Su misión es detectar e informar al programador de los errores que se producen durante la compilación y siempre que sea posible intentar seguir con el proceso de la compilación.

Dependiendo de la fase en la que nos encontremos, los errores a detectar y a tratar son diferentes:

1. Análisis léxico: Los errores a tratar consisten en detectar tokens que no corresponden a ningún componente léxico del lenguaje. (instrucciones mal escritas…)

2. Análisis sintáctico: Los errores se corresponden con el nivel sintáctico del lenguaje. Estudiaremos los errores que violan las reglas de las estructuras sintácticas del lenguaje. (si en vez de paréntesis hemos usado otro símbolo…)

3. Análisis semántico: Pueden existir instrucciones correctas, desde el punto de vista de la sintaxis cuyo significado no es coherente. (intentar asignar un valor a una constante)

2.8 Programas relacionados con un compilador

Un compilador no trabaja solo, requiere de una serie de programas de apoyo para llegar hasta el programa ejecutable.

La mayoría de los compiladores modernos utilizan los que se denomina EID (IDE) Entorno Integrado de Desarrollo. Tenemos todas las herramientas de programación incluidas en un único programa. Este programa se encarga de gestionar las demás utilidades.

Ventaja à comodidad

Desventaja à se pierde la visión de que se está haciendo en cada momento.

Los programas que necesita un compilador, para llegar al ejecutable son:

1. Editores: Nos ayudan a crear el código fuente. Son procesadores de texto adaptados al lenguaje.

2. Preprocesadores: Preprocesan la fuente, para facilitar tarea al compilador. Pueden utilizar muchas funciones como:

a. Procesamiento de macros: abreviaturas de instrucciones más grandes.

b. Inclusión de archivos de encabezamiento: Cada vez que se incluye otro archivo, introduce todas las cabeceras del mismo.

c. Preprocesadores racionales: Actualiza lenguajes antiguos.

d. Extensión a lenguajes: Nuevas macros incorporadas, podemos usarlos directamente sin definirlas.

3. Ensambladores o (assemblers): En caso de que nuestro compilador genere código ensamblador, se utiliza el ensamblador para producir código maquina reubicable.

4. Editores de carga, o loaders y enlace, o linkers: Se encarga de resolver todas las referencias a módulos externos, como pueden ser librerías.

clip_image015Otra herramienta que es una ayuda para la creación de programas es el depurador.

2.9 Herramientas para la construcción de compiladores

Afortunadamente, no tenemos que hacer los compiladores a mano, de cero. Existen herramientas que permiten crear cada una de sus fases.

1. Generadores de analizadores sintácticos: Byson o Yacc. A partir de las descripciones de patrones, son capaces de generar el analizador sintáctico.

2. Generadores de analizadores léxicos: Se basan en autómatas finitos deterministas. (lex y flex)

3. Dispositivos de traducción dirigida por la sintaxis: Analizan árboles sintácticos.

4. Generadores automáticos de código: Toman el programa fuente de código intermedio y lo transforman en código máquina para un determinado ordenador.

5. Dispositivos para análisis de flujo de datos: Analizan el flujo de datos para optimizar el código final.

3. INTÉRPRETES

Toma un programa fuente y lo va traduciendo y ejecutando de forma simultáneas.

No se crea ningún programa objeto. Se crea una imagen del objeto sobre la memoria del ordenador.

A la vez que se va creando en un editor el programa fuente, se va analizando línea a línea en búsqueda de posibles errores. Facilita al usuario la inmediata corrección de los errores.

En cualquier momento se puede interrumpir y consultar el valor de las variables.

Inconvenientes:

o Si una sentencia toma parte de un bucle, se interpreta tantas veces como se ejecuta el bucle.

o La optimización sólo es posible a nivel de una instrucción, y no a nivel global.

o Cada vez que queramos usar un programa, necesitaremos traducirlo.

Los intérpretes son preferibles a los compiladores, solo cuando vamos a ejecutar un programa pocas veces.

4. COMPILADORES INTERPRETADOS

Esta revolución se llama JAVA.

Si creamos un programa en PC, y queremos que función en Macintosh, es necesario volver a compilarlo en otra herramienta diferente.

El compilador genera instrucciones en el código máquina, lo que crea una fuerte dependencia entre el programa y el procesador.

Para solucionar este problema JAVA dispone de un compilador que genera código ejecutable en una máquina virtual (JVM – Java Virtual Machine). Este código recibe el nombre de bytecodes. Esta máquina virtual no existe, para simularla es necesario tener un intérprete de esta máquina virtual.

El intérprete y el compilador si dependen del ordenado y S.O pero el bytecodes no.

clip_image016

5. DEPURADORES (Debuggers)

Herramientas que facilitan la localización de errores.

Permiten estudiar por dentro los programas.

Hicieron su aparición en los intérpretes.

Utilidades:

o Tracers (rastreadores): permiten ejecutar una a una cada instrucción del programa.

o Breakpoints o puntos de ruptura: Instrucción donde se va a interrumpir la ejecución del programa.

o Watches o examinadores de variables: Permite examinar el contenido de una variable.

Empezaron siendo un programa independiente y opcional. Hoy en día, todas las herramientas incluyen un depurador y están dentro del entorno de desarrollo.

Las últimas versiones de traductores incluyen en sus editores técnicas de depuración como:

o Escritura sintáctica: Cada palabra toma un aspecto según su función sintáctica. (una palabra reservada puede ponerse en negrita, una cadena en azul…) elimina muchos errores de tipografiado.

o Code Insight: Según vamos completando el código va verificando que el código es correcto.