Introducción a Compiladores e Intérpretes
Contenido
Traductores
Definiciones
Ventajas y desventajas de compiladores
Ventajas y desventajas de Interpretes
Etapas del proceso de compilación
Traductor: Un Traductor es un programa que toma como entrada un texto escrito en un lenguaje y da como salida otro texto en un lenguaje diferente.
Tipos de Traductores Traductor
Traductor de Idioma
Compilador
Interprete
Preprocesador
Interprete de Comandos
Ensamblador
MacroEnsamblador
Conversor de Código
AutoCompilador
MetaCompilador
Descompilador
Autómata
Gramática
Ligador
Ensamblador: Es un lenguaje de bajo nivel, donde cada sentencia del lenguaje fuente se traduce a una instrucción en código máquina.
Compilador: Es un traductor que convierte un texto escrito en un lenguaje de alto nivel a un lenguaje de bajo nivel (código objeto o máquina).
Podemos decir que es el tipo de traductor más conocido. Se trata de un programa que traduce código fuente escrito en un lenguaje de alto nivel (
Pascal )
en código
máquina (no siempre). Son más rápidos que los intérpretes pero presentan mayor dificultad a la hora de detectar errores. Un compilador es un programa que lee el código escrito en un lenguaje (lenguaje origen), y lo traduce o traduce en un programa equivalente escrito en otro lenguaje (lenguaje objetivo). Como una parte fundamental de este proceso de traducción, el compilador le hace notar al usuario la presencia de errores en el código fuente del programa.
Etapas del proceso de compilación:
1. Edición. Esta fase consiste en escribir el programa empleando algún lenguaje y un editor. Como resultado nos dará el código fuente de nuestro programa. 2. Compilación. En esta fase se traduce el código fuente obtenido en la fase anterior a código máquina. Si no se produce ningún error se obti ene el código objeto. En caso de errores el compilador los mostraría para ayudarnos a corregirlos y se procedería a su compilación de nuevo, una vez corregidos. 3. Linkado. Esta fase consiste en unir el archivo generado en la fase dos con determinadas rutinas internas del lenguaje, obteniendo el programa ejecutable. Existen dos tipos de linkados: o
Linkado estático: Los binarios de las librerías se añaden a nuestros
binarios compilados generando el archivo ejecutable. o
Linkado dinámico: no se añaden las librerías a nuestro binario sino
que hará que se carguen en memoria las librerías que en ese momento se necesiten. Una vez traducido, compilado y linkado el archivo está listo para su ejecución donde también podrán surgir problemas y fallos, para los cuales tendríamos que volver a
realizar todo el proceso anteriormente citado, de modo que puedan ser corregidos. Por este motivo es importante realizar numerosas pruebas en tiempo de ejecución antes de presentar el programa al cliente.
Partes de un compilador
Normalmente los compiladores están divididos en dos partes:
: es Front End
la parte que analiza el código fuente, comprueba su validez,
genera el árbol de derivación y rellena los valores de la tabla de símbolos. Esta parte suele ser independiente de la plataforma o sistema para el cual se vaya a compilar.
Back End : es
la parte que genera el código máquina, específico de una
plataforma, a partir de los resultados de la fase de análisis, realizada por el Front End . Esta división permite que el mismo
Back End se
utilice para generar el código
máquina de varios lenguajes de programación distintos y que el mismo End
que
sirve
para
analizar
el
código
fuente
de
un
lenguaje
Front
de
programación concreto sirva para la generación de código máquina en varias plataformas distintas. El código que genera el
Back End
normalmente no se puede ejecutar
directamente, sino que necesita ser enlazado por un programa enlazador (
linker ).
Tipos de compiladores
Esta taxonomía de los tipos de compiladores no es excluyente, por lo que puede haber compiladores que se adscriban a varias categorías:
Compiladores cruzados: generan código para un sistema distinto del que
están funcionando.
Compiladores optimizadores: realizan cambios en el código para mejorar
su eficiencia, pero manteniendo la funcionalidad del programa original.
Compiladores de una sola pasada: generan el código máquina a partir de
una única lectura del código fuente.
Compiladores de varias pasadas: necesitan leer el código fuente varias
veces antes de poder producir el código máquina.
Compiladores JIT ( J u s t
I n T i m e ) : forman
parte de un intérprete y compilan
partes del código según se necesitan.
Fases de un Compilador
Cada fase lleva a cabo una tarea sobre el programa fuente. Las primeras tres fases suelen agruparse en una sola fase llamada fase de análisis y las últimas tres en una llamada fase de síntesis. Las fases de un compilador son:
La etapa de análisis (front end o etapa inicial) agrupa aquellas fases que dependen principalmente del lenguaje fuente, y comprende:
Análisis Léxico: Esta fase se encarga de verificar si todas las cadenas pertenecen
o no al lenguaje. Es decir realiza un análisis símbolo por símbolo indicando el token por cada uno de los elementos reconocidos o el error en caso de no reconocer. Este análisis no logra detectar muchos errores por su característica. Esto comprende expresiones regulares y AFN, diseño de un generador de analizadores léxicos, autómatas finitos determinísticos, autómatas finitos no determinísticos. Ejemplo: total=valor*5 Luego del análisis léxico: id = id * num
Esta fase se encarga de verificar si una cadena de entrada del código fuente pertenece
o
no
al
lenguaje,
es
decir
se
realiza
un análisis símbolo a símbolo indicando el tóken para cada una de las cadenas reconocidas o un error en caso de no reconocer la cadena.
Por ejemplo, en en análisis léxico los caracteres de las siguientes proposiciones de asignación
Análisis Sintáctico: En esta fase se analiza la estructura de las expresiones en
base a gramáticas. Aquí ya se puede determinar si una estructura por ejemplo una expresión matemática mal formada. El análisis que se realiza es jerárquico es decir en base a árboles de derivación que se obtienen de las mismas gramáticas. Ejemplo: position:=initial + rate*60
Análisis Semántico: Este análisis es más dificil de formalizar, determina el tipo de
los resultados intermedios, comprobar que los argumentos que tienen un operador pertenecen al conjunto de operadores posible, y si son compatibles entre sì.
La etapa de síntesis (back end o etapa final) agrupa aquellas fases que dependen principalmente de la máquina objetivo, y comprende: Generación de Código Intermedio: El código intermedio es una representación en
base a elementos de 3 y 4 direcciones. Lo que nos permite llegar a la fase de optimizaciòn de código. a=b+c 1: + b c T1 2: = a T1 Optimización de Código: Consiste en realizar una mejora en el código intermedio,
para reducir el número de líneas y hacer que la ejecución sea más rápida a=b+c 1: + b c a Generación de Código: Llegamos a la generación de código ensamblador o código
máquina del procesador que nos interese por ejemplo: a:=b+c LOAD B ADD C STORE A
Cómo saber si estamos ante un compilador: Cuando el lenguaje fuente está en un lenguaje de programación de alto nivel y el objeto generado sea de bajo nivel (ensamblador o código de maquina).
Ventajas de los Compiladores:
Produce un código optimizado.
La ejecución del programa objeto es mucho más rápida que si se interpreta el programa fuente.
El compilador tiene una visión global del programa, por lo que la información de mensajes de error es más detallada.
Se debe ejecutar muchas veces el código fuente para ver los cambios en el resultado.
Mayor consumo de memoria.
Intérprete: Un intérprete es un programa que analiza y ejecuta simultáneamente el programa fuente, es decir no producen un código objeto, siendo su ejecución simultánea a la del programa fuente.
No genera código objeto, analiza y ejecuta directamente cada proposición del código fuente.
Un intérprete es como un compilador, solo que la salida es una ejecución. El programa de entrada se reconoce y ejecuta a la vez. No se produce un resultado físico (código máquina) sino lógico (una ejecución).
Ventajas de los Interpretes
Su principal ventaja es que permiten una fácil depuración. Permiten una mayor interactividad con el código en tiempo de desarrollo.
En algunos lenguajes (Smalltalk, Prolog, LISP) está permitido y es frecuente añadir código según se ejecuta otro código, y esta característica solamente es posible implementarla en un intérprete.
Puede ser interrumpido con facilidad.
Puede ser rápidamente modificado y ejecutado nuevamente.
Un Intérprete necesita menos memoria que un compilador.
Facilita la búsqueda de errores.
En algunos lenguajes está permitido añadir código según se ejecuta otro código.
Menor consumo de memoria.
Lentitud de ejecución, ya que al ejecutar a la vez que se traduce no puede aplicarse un alto grado de optimización.
Cada instrucción debe ser traducida a código máquina tantas veces como sea ejecutada
Durante la ejecución, el intérprete debe residir en memoria ya que no genera código objeto.
Software Utilizado para Construccion de Compiladores
Software de uso General para Interpretación o Generación de Código.
Microsoft Assembler_6.11
C estándar y C++
Dev C++
Free Pascal
Java
Visual C++ de Visual Studio 2010
Autómatas y Gramáticas
JFlap
Thoth
Chalchalero
SDGLL1 Sistema Detector de Gramáticas LL(1).
Análisis Léxico
COCO/R C/C++
Flex
Lex
Jlex
Análisis Sintáctico
Bison Generador de Analizadores Sintácticos Ascendentes tipo YACC. YACC Generador de Analizadores Sintácticos Ascendentes LR(1).
Análisis Semántico y Tablas de Símbolos
TS 2006
TS
TS-OO
Generación de Código Intermedio y Final
ENS 2001 (Entorno Consola Windows) Lenguaje ensamblador basado en el
estándar IEEE 694.
W-ENS 2001 (Entorno gráfico Windows) Lenguaje ensamblador basado en
el estándar IEEE 694.
L-ENS 2001 (Linux) Lenguaje ensamblador basado en el estándar IEEE 694.
ASS 1.3 (Linux) Lenguaje ensamblador sencillo.
TASM
TLINK
GCC. GNU Compiler Colection
Prácticas de Lenguajes de Alto Nivel Práctica 1
Objetivos: Practicar la compilación y depuración de un programa sencillo. Práctica: Diseñar un programa sencillo para hacer una estadística de las letras de cadenas de texto introducidas por teclado. El programa deberá repetir en un lazo lo siguiente: • Pedir un string de hasta 50 caracteres • Mostrar el número de vocales • Mostrar el número de consonantes • Preguntar si se desea continuar o finalizar (en este último caso, abandonar el
programa). Nota: Recordar que el carácter número i de un string S se obtiene con: S(i) Realización: Diseñar el programa, y luego escribirlo en visual y compilarlo. Una vez finalizado, probar el programa con el depurador, y mostrar el programa al profesor. Aspectos que deben probarse con el depurador son: • Pararse al comienzo del programa • Mostrar valores de las variables • Ejecutar paso a paso • Poner algún punto de ruptura y ejecutar • Etc.
Entregar: Un listado del programa (suficientemente comentado).