Clase 3:
Caracteristicas y componentes de los compiladores
Objetivos
Realizar
un recordatorio sobre la clasificación de lenguajes de programación.
Conocer
los conceptos generales de compiladores, intérpretes, traductores.
Comprender
las fases de un compilador.
Distinguir
los diferentes tipos de traductores.
Realizar ejemplos
sencillos de compilación en lenguaje C++.
Clasificación de los lenguajes de programación
La programación de computadoras
se realiza en los llamados lenguajes de programación, éstos posibilitan la
comunicación entre el programador y la computadora, a través de un conjunto de
instrucciones u órdenes especificadas por el lenguaje.
Un
lenguaje de programación puede definirse como: “Notación
formal para describir algoritmos o funciones
que serán ejecutados por una computadora”, o bien, un lenguaje para comunicar
instrucciones al computador.
Diferentes
puntos de vista para clasificar los lenguajes de programación:
1.
Su
grado de independencia con la máquina.
2.
La
forma de sus instrucciones y la forma de procesar el código fuente.
3.
Por
generaciones.
Los
lenguajes de programación según su grado de independencia de la máquina:
a)
Lenguaje
máquina (representación binaria o hexadecimal.).
b) Lenguaje
ensamblador o de bajo nivel (versión simbólica de un lenguaje máquina).
c)
Lenguaje
de medio nivel (lenguaje C).
d)
Lenguaje
de alto nivel (FORTRAN, COBOL, Pascal).
Aunque todos los lenguajes de
programación tienen un conjunto de instrucciones que permiten realizar dichas
operaciones, existe una marcada diferencia en los símbolos, caracteres y
sintaxis de los lenguajes de máquina, lenguajes ensambladores y lenguajes de
alto nivel.
a) Lenguaje
de máquina.
El
lenguaje de máquina de una computadora consta de cadenas de números binarios
(ceros y unos) y es el único que "entienden" directamente los
procesadores. Todas las instrucciones preparadas en cualquier lenguaje de máquina
tienen por lo menos dos partes. La primera es el comando u operación, que dice
a la computadora cuál es la función que va a realizar. Todas las computadoras
tienen un código de operación para cada una de sus funciones. La segunda parte
de la instrucción es el operando, que indica a la computadora donde hallar o
almacenar los datos y otras instrucciones que se van a manipular; el número de
operando de una instrucción varía en las distintas computadoras.
b) Lenguaje
ensamblador
La comunicación en lenguaje de
máquina es particular de cada procesador que se usa, y programar en este
lenguaje es muy difícil y tedioso, por lo que se empezó a buscar mejores medios
de comunicación con ésta.
A fin de facilitar la labor de
los programadores en el pasado, se desarrollaron códigos mnemotécnicos para las
operaciones y direcciones simbólicas. Uno de los primeros pasos para mejorar el
proceso de preparación de programas fue sustituir los códigos de operación
numéricos del lenguaje de máquina por símbolos alfabéticos, que conforman un
lenguaje mnemotécnico.
Todas las computadoras actuales
tienen códigos mnemotécnicos aunque, naturalmente, los símbolos que se usan
varían en las diferentes marcas y modelos. La computadora sigue utilizando el
lenguaje de máquina para procesar los datos, pero los programas ensambladores traducen antes los símbolos de código de operación especificados a sus
equivalentes en lenguaje de máquina.
Los lenguajes ensambladores
tienen ventajas sobre los lenguajes de máquina. Ahorran tiempo y requieren
menos atención a detalles. Se incurren en menos errores y los que se cometen
son más fáciles de localizar. Además, los
programas en lenguaje ensamblador son más fáciles de modificar que los programas en lenguaje de máquina. Pero
existen limitaciones. La codificación en lenguaje ensamblador es todavía un
proceso lento. Además, una desventaja
importante de estos lenguajes es que tienen
una orientación a la máquina. Es decir, están diseñados para la marca y modelo
específico de procesador que se utiliza.
En el principio de la
computación este era el lenguaje que tenía que "hablar" el ser humano
con la computadora y consistía en insertar en un tablero miles de conexiones y
alambres y encender y apagar interruptores. Aunque en la actualidad ya no se
emplea, es importante reconocer que ya no es necesario que nos comuniquemos en
este lenguaje de "unos" y "ceros", pero es el que
internamente una computadora reconoce o "habla".
c) Lenguajes
de alto nivel
Los primeros programas
ensambladores producían sólo una instrucción en lenguaje de máquina por cada
instrucción del programa fuente. Para agilizar la codificación, se
desarrollaron programas ensambladores que podían producir una cantidad variable
de instrucciones en lenguaje de máquina por cada instrucción del programa
fuente. Dicho de otra manera, una sola macroinstrucción podía producir varias
líneas de código en lenguaje de máquina.
A diferencia de los programas
de ensamble, los programas en lenguaje de alto nivel se pueden utilizar con
diferentes marcas de computadoras sin tener que hacer modificaciones
considerables. Esto permite reducir sustancialmente el costo de la
reprogramación cuando se adquiere equipo nuevo.
Los lenguajes de programación
según su forma de instrucciones
Lenguajes imperativos o
procedimentales: lenguajes orientados a instrucciones (Pascal, C. C++, Ada,
FORTRAN).
Lenguajes declarativos,
funcionales o aplicativos: sus construcciones se basan en llamadas a funciones
matemáticas, utilizados a menudo en Inteligencia Artificial ( LISP, ML. APL,
Haskell ). o Lógicos: manejan relaciones entre objetos. Las relaciones se
especifican con reglas y hechos. La
ejecución de programas lógicos, consiste en la demostración de hechos sobre las
relaciones por medio de preguntas. (PROLOG es el más utilizado de este tipo).
Lenguajes orientados a objetos: si
soportan tipos de datos abstractos y clases.
o (C++,
Smalltalk, Java, Prolog++). Los lenguajes de programación por generaciones son
aquellos nombrados como: 1ª., 2ª., 3ª. 4ª. generación y aquellos identificados
como generación visual y generación internet.
Los
lenguajes de programación según su forma de procesar el código fuente
Ø
Traductores
(translators).
Ø
Compiladores
(compilers).
Ø
Ensambladores
(assemblers).
Ø
Interpretes
(interpreters).
Ø
Editores
(editors).
* Traductor: Un traductor es un programa que
procesa un texto fuente destino.
* Compiladores:
Un traductor que transforma textos fuente de lenguajes de alto nivel a
lenguajes de bajo nivel se le denomina compilador.
o El
tiempo que se necesita para traducir un lenguaje de alto nivel a lenguaje objeto
se denomina tiempo de compilación.
o El
tiempo que tarda en ejecutarse un programa objeto se denomina tiempo de
ejecución.
* Intérpretes:
Los intérpretes son programas que simplemente ejecutan las instrucciones que
encuentran en el texto fuente. En muchos casos coexisten en memoria el programa
fuente y el programa intérprete.
Un ejemplo de lenguaje
interpretado es BASIC en sus primeras versiones. La
ejecución de un programa compilado es mucho
más rápida que la de un programa interpretado. Sin embargo los intérpretes
son más interactivos y facilitan la puesta a punto de programas.
Arquitectura de la computadora
En la disciplina de los
procesadores de lenguajes, los compiladores son los más utilizados por los
programadores para el desarrollo de aplicaciones. En el caso particular del
desarrollo de compiladores, hay que tener bien definida la arquitectura de la
computadora.
¿Cómo se pueden
ejecutar las aplicaciones desarrolladas para otras arquitecturas de
computadoras en la nueva arquitectura?
El problema planteado
anteriormente no sólo es aplicable a la construcción de nuevas arquitecturas,
sino también cuando es necesaria la compatibilidad de aplicaciones entre
diferentes sistemas operativos y arquitecturas de computadoras.
Algunas de las técnicas utilizadas para realizar migraciones de
aplicaciones entre distintas arquitecturas y sistemas operativos se muestran en
la siguiente figura:
Un
intérprete software o emulador de software es un programa en código binario que
lee una a una las instrucciones binarias de la arquitectura antigua de las
computadoras, que se
encuentran en un fichero ejecutable, y las interpreta. Los
intérpretes no son muy rápidos, pero pueden construir y adaptar a distintas
arquitecturas sin excesivos costos de desarrollo.
Algunos ejemplos de
intérpretes software binario son:
Emuladores de DOS para
distintos sistemas operativos (SoftPC de Insignia Solutions).
Intérpretes de la
máquinaabstracta JVM (Java Virtual Machine) para distintas plataformas y ue
permiten ejecutar los códigos binarios denominados bytecode (ficheros con la
extensión .class).
Un emulador hardware trabaja de
forma similar a un intérprete de software, pero está implementado en HW de
forma que decodifica las instrucciones de la arquitectura antigua y las traduce
a la nueva arquitectura. Un ejemplo de emulador
de hardware son los microprocesadores Java, que emulan la máquina abstracta JVM (Java Virtual Machine).
Un traductor entre códigos
binarios o ensambladores son conjuntos de instrucciones de la nueva
arquitectura que reproducen el comportamiento de un programa en la arquitectura antigua (la información de la máquina antigua se almacena en registros de la nueva máquina). Un ejemplo de estos traductores son los desarrollados por DEC
(Digital Equipment Corporation) para traducir instrucciones de la arquitectura
VAX y MIPS a la nueva arquitctura ALPHA.
Un compilador nativo es aquél
que toma un programa fuente antiguo y lo vuelve a compilar (recompilar) con
compiladores desarrollados para la nueva arquitectura. Son los más rápidos y
óptimos con respecto a las demás técnicas, pues produce la mejor calidad del
código objeto.
Gramaticas de lenguajes de programación
Reglas para escribir las
sentencias del lenguaje.
Conjunto de símbolos que
definen la estructura de procesamiento de un lenguaje.
Fase de
Análisis:
En el llamado análisis
lexicográfico o léxico, el compilador revisa y
controla que las "palabras" estén
bien escritas y pertenezcan a algún tipo de token (cadena) definido dentro del
lenguaje, como por ejemplo que sea algún tipo de palabra reservada, o si es
el nombre de una variable que este escrita de acuerdo a las pautas de
definición del lenguaje. En esta etapa se crea
la tabla de símbolos, la cual contiene
las variables y el tipo de dato al que pertenece, las constantes literales, el
nombre de funciones y los argumentos que reciben etc.
En el análisis sintáctico como
su nombre lo indica se encarga de revisar que
los tokens estén ubicados y agrupados de
acuerdo a la definición del lenguaje. Dicho de otra manera, que los tokens
pertenezcan a frases gramaticales validas, que el compilador utiliza para
sintetizar la salida. Por lo general las frases gramaticales son representadas
por estructuras jerárquicas, por medio de árboles de análisis sintáctico. En
esta etapa se completa la tabla de símbolos con la dimensión de los
identificadores y los atributos necesarios etc.
El análisis semántico se
encarga de revisar que cada agrupación o
conjunto de token tenga sentido, y no sea
un absurdo. En esta etapa se reúne la información sobre los tipos para la
fase posterior, en esta etapa se utiliza la estructura jerárquica de la etapa
anterior y así poder determinar los operadores, y operandos de expresiones y
preposiciones.
Fase de
Síntesis:
Etapa de generación de código
intermedio, aunque algunos compiladores no la tienen, es bueno saber de su
existencia, en esta etapa se lleva el código del programa fuente a un código
interno para poder trabajar más fácilmente sobre él. Esta representación
interna debe tener dos propiedades, primero debe ser fácil de representar y
segundo debe ser fácil de traducir al código objeto.
En la etapa de optimización de
código, se busca obtener el código más corto y rápido posible, utilizando
distintos algoritmos de optimización.
Etapa de generación de código,
se lleva el código intermedio final a código maquina o código objeto, que por
lo general consiste en un código maquina re localizable o código ensamblador.
Se selecciona las posiciones de memoria para los datos (variables) y se traduce
cada una de las instrucciones intermedias a una secuencia de instrucciones de
maquina puro.
La tabla de símbolos no es una
etapa del proceso de compilación, sino que una tarea, una función que debe
realizar el proceso de compilación. En ella se almacenan los identificadores
que aparecen en el código fuente puro, como así también los atributos de los
mismos, su tipo, su ámbito y en el caso de los procedimientos el número de
argumentos el tipo del mismo etc. En otras palabras una tabla de símbolos es
una estructura de datos, que contiene un registro por cada identificador, y sus
atributos. La tabla de símbolo es accedida
tanto para escritura como parar lectura por
todas las etapas. Detector de errores o manejador de errores, al igual que
la tabla de símbolos no es una etapa del
proceso de compilación, sino que es una
función, muy importante, pues al ocurrir un error esta función debe tratar
de alguna forma el error para así seguir con el proceso de compilación (la
mayoría de errores son detectados en las etapas de análisis léxico, análisis
sintáctico, análisis semántico).
Ejemplo explicativo sobre las etapas de un compilador
¿Qué es lo que hacen los
componentes de un compilador en sus Fases cuando tiene que analizar la
siguiente expresión?
suma = var1
+ var2 + 10 ;
Análisis Léxico
El analizador léxico lee los
caracteres del programa fuente, y verifica que correspondan a una secuencia
lógica (identificador, palabra reservada etc.). Esta secuencia de caracteres
recibe el nombre componente léxico o lexema. En este caso el analizador léxico
verifica si el identificador id1 (nombre interno para "suma") encontrado
se halla en la tabla de símbolos, si no está produce un error porque todavía no
fue declarado, si la preposición hubiese sido la declaración del identificador
"suma" en lenguajes C, C++ (int suma;) el analizador léxico agregaría
un identificador en la tabla de símbolos, y así sucesivamente con todos los
componentes léxicos que aparezcan.
id1= id2+ id3 + 10
Análisis Sintáctico
El analizador sintáctico impone
una estructura jerárquica a la cadena de componentes léxicos, generada por el
analizador léxico, que es representada en forma de un árbol sintáctico.
Análisis Semántico
El analizador semántico
verificara en este caso que cada operador tenga los operandos permitidos.
Generador de código
intermedio
Esta etapa se lleva la
preposición a una representación intermedia como un programa para una maquina
abstracta.
temp1= tipo_ent(10) temp2= id3 *
temp1 temp3= id2 + tem2 id1= temp3
Optimización
de código El código intermedio obtenido es representado de una forma más óptima
y eficiente. temp1=
id3 * 10.0 id1= id2 + temp1
Generador de código
Finalmente lleva el código
intermedio a un código objeto que en este caso es un código re localizable o
código ensamblador (también llamado código no enlazado).
MOVF id3, R2
MULT #10.0, R2
MOVF id2, R1
ADDF R2, R1
MOVF R1, id1
Este el código objeto
obtenido que es enviado al módulo de ensamblado.
Actividades en el aula - Responder a las siguientes preguntas
1.
¿Cuáles
son los conceptos asociados a compiladores?
2.
¿Cuál
es la clasificación de los lenguajes de programación de menor a mayor?
3.
¿Cuáles
son los componentes de un compilador?
4.
¿Analizar
cómo se implementan los componentes de un compilador?
5.
¿Cuáles
es la diferencia entre un compilador y un intérprete, explica?
6. Elabore
un esquema que permita comprender las fases del proceso de compilación y las
etapas.
7. Realizar
un mapa mental sobre los conceptos generales, clasificación, etapas y fases de
los traductores, compiladores e intérpretes
PORCENTAJE ASIGNADO DEL LABORATORIO 1 COMPUTO 1: 40%
Glosario
PROGRAMACIÓN DE SISTEMAS:
Conjunto de reglas para crear soluciones a problemas computables. Conjunto de
herramientas que nos permiten crear software de base que son de utilidad para
interactuar con la máquina.
SOFTWARE DE BASE:
Compilador, Querys, Sistema Operativo, Cargador.
AUTÓMATA: Son las
cadenas posibles que aceptan un lenguaje.
EXPRESIONES REGULARES:
Conjunto de símbolos que aceptan una palabra reservada.
GRAMÁTICA: Reglas para
escribir las sentencias del lenguaje.
LENGUAJE DE PROGRAMACIÓN: Es la
notación formal para la descripción de algoritmos, basada en un conjunto de
instrucciones en alto nivel, que finalmente pasarán a bajo nivel para
interactuar con el hardware y generar herramientas de trabajo.
Mapas y esquemas









No hay comentarios.:
Publicar un comentario