Está en la página 1de 14

Programación de sistemas

CAPITULO 1.
Introducción a la programación de sistemas

La programación de sistemas es un área que estudia los aspectos relacionados


con la teoría de las máquinas y su aplicación en el diseño de sistemas digitales y
de arquitectura de computadoras. La introducción a la programación de sistemas
define todos aquellos conceptos que forman parte del software de base importante
para cualquier programador, como lo son, los sistemas operativos, cargadores,
ligadores, traductores, compiladores, etc., y su estructura para operar de una
manera eficiente, considerando aspectos como tiempo y espacio.

1.1 ¿Qué es y qué estudia la programación de sistemas?

Es un área de las ciencias computacionales que se encarga del estudio de


diferentes plataformas de software que sirven de base para el uso de una
computadora, así como el diseño y desarrollo de software de base.
La programación de sistemas o el software de sistemas (SS) es el conjunto de
instrucciones que las computadoras emplean para manipular datos. Sin el SS, la
computadora sería un conjunto de medios sin utilizar. Al cargar los programas en
una computadora, la máquina actuará como si recibiera una educación
instantánea; de pronto “sabe” cómo pensar y cómo operar.
Es simplemente el conjunto de instrucciones individuales que se le proporcionan al
microprocesador para que pueda procesar los datos y generar los resultados
esperados.
Comprende el estudio de las componentes de un sistema de computación, su
estructura operacional y las facilidades de programación en lenguaje de bajo nivel,
ascendiendo luego, al estudio de las estructuras y características de los lenguajes
procedimentales llamados de alto nivel, y su fundamentación teórica en las
gramáticas y lenguajes formales y en la teoría de autómatas.
En esta área se estudia la teoría de máquinas y su aplicación en el diseño de
sistemas digitales y de arquitectura de computadoras.

1.2 Herramientas desarrolladas con la teoría de programación de sistemas

Mayores alternativas en la generación de los programas proporcionarán una mayor


flexibilidad para su adaptación, distribución, y generación pero también crearán un
mayor número de escenarios que deberán tenerse presentes para la integración
de las aplicaciones. Algo más a tener en consideración es tanto el lenguaje a
utilizar como la correspondiente herramienta. Existe un creciente número de
lenguajes de programación. Cada uno refleja un paradigma de desarrollo diferente,
las implicaciones de éste pueden ser las de mayor peso en la selección de la
herramienta, pero la naturaleza misma de la herramienta deben ser tomadas en
cuenta.

Ing. Karina Cabrera Chagoyan 1


Programación de sistemas

1.3 Lenguajes

Concepción Científica del Lenguaje


Para Noam Chomsky el lenguaje es un conjunto finito o infinito de oraciones, cada
una de ellas de longitud finita y construida a partir de un conjunto finito de
elementos".
Al pronunciar una oración, éste es un conjunto finito de unidades léxicas, si la
oración fuera un conjunto infinito de unidades léxicas no tendría fin y carecería de
sentido completo. Es infinito porque el número de oraciones que un sujeto puede
construir en el transcurso de su vida es ilimitado y más aún si le agregamos las
que pueden construir los demás habitantes.
Un lenguaje se considera como un conjunto de oraciones, que usualmente es
infinito y se forma con combinaciones de palabras del diccionario. Es necesario
que esas combinaciones sean correctas (con respecto a sintaxis) y tengan sentido
(con respecto a la semántica).
En este punto podemos distinguir entre dos clases de lenguajes: los lenguajes
naturales (ingles, alemán, español, etc.) y lenguajes formales (matemático, lógico,
etc.).

1.3.1 Lenguajes Naturales

Existe una variedad de clasificación de los lenguajes, pero tomando en cuenta las
necesidades contemporáneas, lo más importante es distinguir entre los llamados
lenguajes naturales o vernáculos y los lenguajes artificiales.

Lenguaje Natural.- Se utilizan para la comunicación social en la vida cotidiana y


con algunas variantes, para cierto tipo de comunicación científica, permite también
ser autónomos por no tener que apelar a otro lenguaje para interpretar
correctamente los mensajes que recibe de su lengua materna.

1.3.2 Lenguajes Artificiales

Los lenguajes de máquina constituyen otro ejemplo de lenguaje artificial, también


denominado lenguaje formalizado, en el que los signos no hacen referencia a
objetos sino a operaciones o acciones sin embargo las reglas de manejo de dichos
signos usualmente se dan en lenguaje natural. Lo mismo ocurre con los lenguajes
formalizados. Consecuentemente, un lenguaje artificial es un sistema de signos
cuyo mensaje solamente pueden ser decodificados dentro del contexto de un
lenguaje natural.

1.3.3 Proceso de la comunicación

Según Hans Horman el proceso de la comunicación pasa por cinco componentes.


a) El comportamiento intencional del hablante: Referente a la actitud
voluntaria o disposición favorable de una persona para comunicarse con
otra persona que también posee conciencia y es capaz de comprender
pensamientos, datos, sentimientos etc.

Ing. Karina Cabrera Chagoyan 2


Programación de sistemas

b) El comportamiento codificador del hablante: Es decir, la voluntad del


hablante y su competencia para usar un código lingüístico. (Sistema de
signos y reglas para construir e interpretar un mensaje).
c) El mensaje o información codificada: Usando signos lingüísticos con
intención de trasmitirla a otra persona.
d) El comportamiento decodificador: Es la capacidad del oyente para
recepcionar un mensaje, identificando el significado de la combinación de
signos.
e) La capacidad para comprender el sentido o la intención del mensaje
recibido: Es el comportamiento interpretador del oyente, con un criterio de
totalidad.

1.4 Traductor y su estructura

Los programas que convierten un programa escrito de un lenguaje a otro lenguaje


distinto se llaman traductores. El lenguaje que está escrito en el programa original
se llama lenguaje fuente y al que se convierte se llama lenguaje objeto. Ambos
lenguajes. El fuente y el objeto, definen niveles. Si contáramos con un procesador
que ejecutara directamente los programas escritos en el lenguaje fuente, no habría
ninguna necesidad de traducirlos al lenguaje objeto.
La traducción se usa cuando se dispone de un procesador para el lenguaje objeto,
y no se cuenta con uno para el fuente. Si la traducción se hace correctamente, la
ejecución del programa traducido dará exactamente los mismos resultados que
daría la ejecución del programa fuente si dispusiéramos de un procesador para él.
Es importante hacer notar la diferencia entre la traducción y la interpretación. En la
traducción, el programa original, escrito en lenguaje fuente, no se ejecuta
directamente, lo que se hace es convertirlo en un programa equivalente, llamado
programa objeto o módulo objeto, que se ejecuta después de que se ha terminado
la traducción. En la traducción hay dos pasos bien definidos:

1 Generación de un programa equivalente en lenguaje objeto


2 Ejecución del nuevo programa que se ha generado

Estos dos pasos no tienen lugar simultáneamente; el segundo no comienza hasta


que el primero ha terminado. En la interpretación, en cambio, hay sólo un paso: la
ejecución de programa fuente original. No se genera primero un programa
equivalente. La interpretación tiene la ventaja de que el programa suele ser más
pequeño y de mayor flexibilidad, pero la traducción suele producir programas más
rápidos.
Los traductores se pueden dividir a grandes rasgos en dos grupos, según la
relación que haya entre el lenguaje fuente y el objeto. Cuando el lenguaje fuente
es, en esencia, una representación simbólica de un lenguaje numérico de
máquina, el traductor se llama ensamblador y el lenguaje fuente se llama lenguaje
ensamblador. Cuando el lenguaje fuente es el lenguaje de alto nivel en adelante
como el C o Pascal, y el lenguaje objeto es un lenguaje de máquina numérico o
una representación simbólica de uno de ellos, el traductor se llama compilador.

Ing. Karina Cabrera Chagoyan 3


Programación de sistemas

1.4.1 Ensambladores

Un lenguaje ensamblador puro es aquel en que cada sentencia produce


exactamente una instrucción máquina. Es decir, hay una correspondencia
biunívoca entre las instrucciones de máquina y las sentencias del programa en
ensamblador.
La razón por la que se usa el lenguaje ensamblador en lugar de programar el
lenguaje máquina (octal o hexadecimal) consiste en que es mucho más fácil
programar en ensamblador. Los lenguajes ensambladores tienen otra propiedad,
además de la correspondencia uno a uno entre las sentencias en ensamblador y
las instrucciones máquina, que los distinguen de los lenguajes de alto nivel. El
programador en ensamblador tiene acceso a todos los recursos e instrucciones de
la máquina a la que se aplica, pero no el programador en un lenguaje de alto nivel.
Los lenguajes para la programación de sistemas suelen ser un híbrido entre ambos
tipos, con la sintaxis de un lenguaje de alto nivel pero con las posibilidades de
acceso a la máquina de un lenguaje ensamblador.
Existe otra diferencia importante, la cual consiste en que un programa en lenguaje
ensamblador solo puede correr en una familia de máquinas, mientras que un
programa escrito en un lenguaje de alto nivel, puede, en potencia, correr en
muchas máquinas. La habilidad de poder mover software de una máquina a otra,
resulta de gran importancia práctica para muchas aplicaciones.
Un ensamblador es un programa que toma un programa fuente escrito en lenguaje
ensamblador y lo traduce a lenguaje maquina. Este último lenguaje es el conjunto
de información binaria que interpreta el procesador.
Pero, con esta definición no se establece una diferencia clara entre ensambladores
y compiladores, ya que éstos también efectúan la traducción de programas
escritos en lenguaje fuente a programas escritos en lenguaje de máquina.
¿De dónde viene la denominación de ensamblador? Es una consecuencia natural
del desarrollo histórico de la programación, al aumentar el tamaño de los
programas y el número de subrutinas de biblioteca disponibles. Un programador
que tiene que codificar un programa muy largo, normalmente lo descompone, lo
divide en un número más o menos grande de subprogramas o rutinas
independientes o no los escribe, los traduce y los prueba por separado. Por
consiguiente, el traductor debe seguir la pista de todas las referencias cruzadas
entre los diversos subprogramas y subrutinas con el fin de generar un programa
que éste en condiciones de ser procesado; es decir, debe estar en condiciones de
ensamblar (unir) todas las partes para dar un resultado único; y de ahí viene el
nombre de ensamblador.
La evolución de la programación ha ido variando la estructura de los
ensambladores haciéndolos cada vez más complejos. Los más sencillos son
llamados en ensambladores sobre la marcha, ya que aceptan un programa en
forma simbólica; y en cuanto entra, lo ensambla en binario en la memoria,
generalmente, mediante una exploración (scan) del programa fuente.
Las ventajas de dividir un programa en subprograma son grandes. A parte de
poder trabajar con unidades independientes, cuando hay que cambiar o corregir un
programa basta con reprogramar y ensamblar de nuevo los subprogramas o
rutinas afectados por el cambio.

Ing. Karina Cabrera Chagoyan 4


Programación de sistemas

A los ensambladores que pueden realizar la incorporación automática de


subrutinas de biblioteca y el enlazamiento de las diversas partes de un programa
se les denomina ensambladores de rutinas de subprogramas. Este tipo de
ensambladores suele trabajar en dos pasos, es decir, haciendo dos exploraciones
del programa fuente: en el primer paso, construyen la tabla de símbolos y
acumulan todas las definiciones de símbolos que se encuentran en la rutina para
efectuar la traducción en el segundo paso. Las rutinas ensambladas se suelen
almacenar en un medio externo (cinta magnética, discos, tarjetas, etc.).
Un ensamblador debe trabajar con tres tipos de información en el programa fuente:

 Información que no va a depender del lugar en que se almacene el


subprograma en la memoria, como pueden ser los códigos de operación y
las constantes numéricas. Por consiguiente, su traducción es independiente
de si el subprograma está encadenado con otros o no. Son las llamadas
cantidades absolutas.
 Información a la que se hace referencia o que se define en otros
subprogramas. El valor de estos símbolos no puede ser conocido hasta que
todo el programa sea enlazado. Son los llamados valores (cantidades o
variables) globales o externas.
 Por último, información que sólo es definida o referenciada en ese
subprograma y, por consiguiente, su dirección absoluta de almacenamiento
en memoria dependerá de la posición del subprograma, que será
independiente de la combinación con otros subprogramas. Basta conocer la
dirección de inicio del subprograma para, añadiéndosela a la dirección
relativa, obtener la dirección absoluta. Esta información se denomina
localizable (variables locales o internas).

Para obtener el verdadero programa objeto del procesado por la computadora, es


necesario encadenar todos los subprogramas entre sí y con las subrutinas de
biblioteca que sea preciso. Esta fusión es realizada por un programa de servicio
que recibe varios nombres según autores: editor de encadenamiento, cargador,
introductor o montador de enlaces.
La forma de trabajar de un cargador es la siguiente: por cada rutina que entra en
forma semi-compilada anota la dirección de memoria en que almacena la primera
instrucción, el llamado origen del subprograma.

Característica del lenguaje ensamblador


1-. Las direcciones son simbólicas.
2-.Traducción de las instrucciones en lenguaje ensamblador a lenguaje
máquina de una en una.
3-.Existen unas traducciones no traducibles a código máquina llamadas
pseudo-instrucciones. Sirven para el control del programa.

Se pueden hacer varios tipos de ensambladores, con las anteriores características


básicas, según el tipo de máquina y de la potencia del lenguaje ensamblador
deseado.

Ing. Karina Cabrera Chagoyan 5


Programación de sistemas

En definitiva, el ensamblador empleado dependerá de que en las instrucciones se


emplee uno o varios operandos, de que existan uno o varios tipos de
direccionamiento, etc.

Motivos para utilizarlo.

 Rapidez: Como el programador directamente selecciona las instrucciones


que se ejecutan en el programa, el programa final queda más optimizado
que un programa generado por un compilador.
 Mayor control de la computadora: Un programa puede accesar directamente
cualquier componente y periférico de la computadora.
 Independencia del lenguaje: No depende de librerías o del lenguaje mismo
para realizar una tarea específica. Lenguajes como el Basic limitan al
programador a lo que el lenguaje puede hacer.
 La mayoría de las computadoras pueden ensamblar: Los recursos
necesarios para ensamblar un programa son mucho menores que los
compiladores o intérpretes. El ensamblador generalmente es más rápido
ensamblando un programa que un compilador generando un archivo
ejecutable.

Motivos para no utilizarlo.

Desafortunadamente, también existen motivos para no crear los programas con


ensamblador.

 Dependencia del hardware: El código se hace en extremo dependiente del


microprocesador, de los dispositivos, de los controladores, etc. Este punto
será analizado con más detenimiento en dependencias de hardware.
 Mayor tiempo de codificación: El número de líneas de un programa hecho
en ensamblador es mayor a uno hecho en un lenguaje de alto nivel (por
ejemplo: Función en C puede realizar varias decenas o centenas de
instrucciones del microprocesador).
 Comprensión más profunda de la computadora: Entender un lenguaje de
alto nivel es generalmente más sencillo que el ensamblador. Comprender
ensamblador requiere conocimientos más exactos sobre el funcionamiento
interno de la computadora.
 Errores más frecuentes en el programa: El evitar un error o encontrar
alguno que ya exista es difícil. Las herramientas para este caso (como el
CodeView y el TurboDebbuger) ayudan en gran medida a ver lo que está
ocurriendo en la maquina, pero no localizan los errores.

1.4.2 Compiladores

Un compilador es un programa escrito en algún lenguaje; en general, en el


lenguaje ensamblador de la correspondiente computadora, que admite como
entrada un programa fuente y da como salida un programa objeto.

Ing. Karina Cabrera Chagoyan 6


Programación de sistemas

La tendencia actual es la de escribir los compiladores en lenguaje de alto nivel


para reducir los tiempos de programación y depuración. Incluso existen lenguajes
diseñados especialmente para escribir compiladores. Se estudiarán al hablar del
compilador de compiladores.
Un compilador se diferencia de un intérprete en que el último acepta un lenguaje
fuente y lo ejecuta. Siempre analiza cada sentencia al ejecutarla; por lo que es
muy lento.
En el caso de que el lenguaje fuente sea un lenguaje de programación de alto nivel
y el objeto sea un lenguaje de bajo nivel (ensamblador o código de máquina), a
dicho traductor se le denomina compilador. Un ensamblador es un compilador
cuyo lenguaje fuente es el lenguaje ensamblador. Un intérprete no genera un
programa equivalente, sino que toma una sentencia del programa fuente en un
lenguaje de alto nivel y la traduce al código equivalente y al mismo tiempo lo
ejecuta. Históricamente, con la escasez de memoria de los primeros ordenadores,
se puso de moda el uso de intérpretes frente a los compiladores, pues el programa
fuente sin traducir y el intérprete juntos daban una ocupación de memoria menor
que la resultante de los compiladores. Por ello los primeros ordenadores
personales iban siempre acompañados de un intérprete de BASIC (Spectrum,
Commodore VIC-20, PC XT de IBM, etc.). La mejor información sobre los errores
por parte del compilador así como una mayor velocidad de ejecución del código
resultante hizo que poco a poco se impusieran los compiladores. Hoy en día, y con
el problema de la memoria prácticamente resuelto, se puede hablar de un gran
predominio de los compiladores frente a los intérpretes, aunque intérpretes como
los incluidos en los navegadores de Internet para interpretar el código JVM de
Java son la gran excepción.

Ventajas de compilar frente a interpretar:

o Se compila una vez, se ejecuta n veces.


o En bucles, la compilación genera código equivalente al bucle, pero
interpretándolo se traduce tantas veces una línea como veces se
repite el bucle.
o El compilador tiene una visión global del programa, por lo que la
información de mensajes de error es más detallada.

Un compilador no es un programa que funciona de manera aislada, sino que


necesita de otros programas para conseguir su objetivo: obtener un programa
ejecutable a partir de un programa fuente en un lenguaje de alto nivel. Algunos de
esos programas son el preprocesador, el linker, el depurador y el ensamblador. El
preprocesador se ocupa (dependiendo del lenguaje) de incluir ficheros, expandir
macros, eliminar comentarios, y otras tareas similares. El linker se encarga de
construir el fichero ejecutable añadiendo al fichero objeto generado por el
compilador las cabeceras necesarias y las funciones de librería utilizadas por el
programa fuente. El depurador permite, si el compilador ha generado
adecuadamente el programa objeto, seguir paso a paso la ejecución de un
programa. Finalmente, muchos compiladores, en vez de generar código objeto,

Ing. Karina Cabrera Chagoyan 7


Programación de sistemas

generan un programa en lenguaje ensamblador que debe después convertirse en


un ejecutable mediante un programa ensamblador.

Proceso de Compilación.
El proceso de compilación realiza primero un análisis del programa fuente para
producir la sintaxis del programa objeto. Para ello utiliza diversas tablas.
Para realizar estas funciones las estructuras deben obedecer a reglas muy rígidas,
puesto que la ambigüedad no podría ser dilucidada por la máquina. De ahí la
importancia de los lenguajes formales y de los autómatas en relación con los
lenguajes evolucionados y los compiladores, pues las tareas esenciales del
compilador son la evaluación semántica (o traducción propiamente dicha).
Entre las tablas utilizadas, se halla la tabla de bucles empleada para la estructura
en lazo y para las variables de control.
El explorador (scanner) o analizador lexicográfico tiene como misión indagar
sobre los caracteres del programa fuente y generar los símbolos del programa
para pasarlos a los analizadores sintáctico y semántico.
El programa fuente se representa internamente de muy diferentes formas: árbol,
lista de cuartetos (operador, operador, operador, resultado) o en notación polaca.
Por último, se realizara la generación del código, que es la traducción del
programa fuente interno a lenguaje de máquina o a un lenguaje intermedio.

Clasificación de Compiladores
El programa compilador traduce las instrucciones en un lenguaje de alto nivel a
instrucciones que la computadora puede interpretar y ejecutar. Para cada lenguaje
de programación se requiere un compilador separado. El compilador traduce todo
el programa antes de ejecutarlo. Los compiladores son, pues, programas de
traducción, insertados en la memoria por el sistema operativo para convertir
programas de cómputo en pulsaciones electrónicas ejecutables (lenguaje de
máquina). Los compiladores pueden ser de:

 Una sola pasada: examina el código fuente una vez, generando el código o
programa objeto.
 Pasadas múltiples: requieren pasos intermedios para producir un código en
otro lenguaje, y una pasada final para producir y optimizar el código
producido durante los pasos anteriores.
 Optimación: lee un código fuente, lo analiza y descubre errores potenciales
sin ejecutar el programa.
 Compiladores incrementales: generan un código objeto instrucción por
instrucción (en vez de hacerlo para todo el programa) cuando el usuario
teclea cada orden individual. El otro tipo de compiladores requiere que
todos los enunciados o instrucciones se compilen conjuntamente.
 Ensamblador: el lenguaje fuente es lenguaje ensamblador y posee una
estructura sencilla.
 Compilador cruzado: se genera código en lenguaje objeto para una
máquina diferente de la que se está utilizando para compilar. Es
perfectamente normal construir un compilador de Pascal que genere código

Ing. Karina Cabrera Chagoyan 8


Programación de sistemas

para MS-DOS y que el compilador funcione en Linux y se haya escrito en


C++.
 Compilador con montador: compilador que compila distintos módulos de
forma independiente y después es capaz de enlazarlos.
 Autocompilador: compilador que está escrito en el mismo lenguaje que va a
compilar. Evidentemente, no se puede ejecutar la primera vez. Sirve para
hacer ampliaciones al lenguaje, mejorar el código generado, etc.
 Meta compilador: es sinónimo de compilador de compiladores y se refiere a
un programa que recibe como entrada las especificaciones del lenguaje
para el que se desea obtener un compilador y genera como salida el
compilador para ese lenguaje. El desarrollo de los meta compiladores se
encuentra con la dificultad de unir la generación de código con la parte de
análisis. Lo que sí se han desarrollado son generadores de analizadores
léxicos y sintácticos. Por ejemplo, los conocidos: generador de analizadores
léxicosLEX, generador de analizadores sintácticosYACC, desarrollados
para UNIX. Los inconvenientes que tienen son que los analizadores que
generan no son muy eficientes.
 Descompilador: es un programa que acepta como entrada código máquina
y lo traduce a un lenguaje de alto nivel, realizando el proceso inverso a la
compilación.

Estructura del proceso de compilación


Conceptualmente un compilador opera en fases. Cada una de las cuales
transforma el programa fuente de una representación en otra. En la figura se
muestra una descomposición típica de un compilador. En la práctica se pueden
agrupar fases y las representaciones intermedias entres las fases agrupadas no
necesitan ser construidas explícitamente.

El compilador se divide en 6 fases, de las cuales las tres primeras se denominan


como nivel superior o fase de análisis y las tres últimas el nivel inferior o fases de
síntesis. En el nivel superior de un compilador depende del lenguaje y el nivel

Ing. Karina Cabrera Chagoyan 9


Programación de sistemas

inferior es más dependiente de la máquina. Otras dos actividades, la


administración de la tabla se símbolos y el manejo de errores, se muestran en
interacción con las seis fases de análisis léxico, análisis sintáctico, análisis
semántico, generación de código intermedio, optimación de código y generación
de código. De modo informal, también se llamarán "fases" al administrador de la
tabla de símbolos y al manejador de errores.

Análisis Léxico.
El análisis lexicográfico, también conocido como rastreo o en ocasiones rastreo y
filtrado, agrupa secuencias de caracteres desde el programa fuente de entrada en
unidades llamadas componentes léxicas o tokens. Así, el rastreo puede
considerarse un mapeo.
En la fase de análisis léxico se leen los caracteres del programa fuente y se
agrupan en cadenas que representan los componentes léxicos. Cada componente
léxico es una secuencia lógicamente coherente de caracteres relativa a un
identificador, una palabra reservada, un operador o un carácter de puntuación.
A la secuencia de caracteres que representa un componente léxico se le llama
lexema (o con su nombre en inglés token). En el caso de los identificadores
creados por el programador no solo se genera un componente léxico, sino que se
genera otro lexema en la tabla de símbolos.

Análisis Sintáctico.
En esta fase, los componentes léxicos se agrupan en frases gramaticales que el
compilador utiliza para sintetizar la salida. La estructura reconocida por el análisis
sintáctico se describe en forma semejante a un árbol y es conocido como árbol
sintáctico, árbol gramatical o árbol de estructura.

Análisis Semántico.
Esta fase determina el significado (semántica) el programa mediante la creación
de tabla de símbolos, verificando cuales de las variables utilizadas han sido
definidas (lenguajes como Pascal requieren esto) y una infinidad de otras tareas
anteriores a la generación de código. Dos de las tareas principales en la fase del
análisis semántico son (1) la verificación estática del programa y (2) la generación
de una representación Intermedia (RI).
La fase de análisis semántico se intenta detectar instrucciones que tengan la
estructura sintáctica correcta, pero que no tengan significado para la operación
implicada.
La generación estática completa el análisis iniciado por el analizador gramatical y
efectúa actividades como la afirmación de que una variable con valor de carácter
no haya sido asignada a una variable declarada con valor entero. Esto se conoce
como verificación de tipos. La verificación estática de tipos varía con el lenguaje
que está siendo compilado.

Representación Intermedia (RI)


La representación intermedia, en ocasiones denominada Lenguaje Intermedio o
Código Intermedio (RI, LI o CI, respectivamente), es una forma alternativa para un
árbol de análisis gramatical.

Ing. Karina Cabrera Chagoyan 10


Programación de sistemas

Generación de código Intermedio.


Algunos compiladores generan una representación intermedia explícita del
programa fuente, una vez que se han realizado las fases de análisis. Se puede
considerar esta operación intermedia como un subprograma para una máquina
abstracta. Esta representación intermedia debe tener dos propiedades
importantes: debe ser fácil de producir y fácil de traducir al programa objeto.

Optimización de Código.
En esta fase se trata de mejorar el código intermedio, de modo que resulte un
código de máquina más rápido de ejecutar.

Generación de Código.
Esta constituye la fase final de un compilador. En ella se genera el código objeto
que por lo general consiste en código en lenguaje máquina (código relocalizable) o
código en lenguaje ensamblador.

Administrador de la tabla de símbolos.


Una tabla de símbolos es una estructura de datos que contiene un registro por
cada identificador. El registro incluye los campos para los atributos del
identificador.
El administrador de la tabla de símbolos se encarga de manejar los accesos a la
tabla de símbolos, en cada una de las etapas de compilación de un programa.

Manejador de errores.
En cada fase del proceso de compilación es posibles encontrar errores. Es
conveniente que el tratamiento de los errores se haga de manera centralizada a
través de un manejador de errores. De esta forma podrán controlarse más
eficientemente los errores encontrados en cada una de las fases de la compilación
de un programa.

1.4.3 Interpretes

El intérprete en los lenguajes de programación simula una máquina virtual, donde


el lenguaje de máquina es similar al lenguaje fuente.
Traductor de lenguajes de programación de alto nivel, los intérpretes ejecutan un
programa línea por línea. El programa siempre permanece en su forma original
(programa fuente) y el interprete proporciona la traducción al momento de ejecutar
cada una de las instrucciones. Un intérprete es un programa que procesa los
programas escritos en un lenguaje de alto nivel, sin embargo, está diseñado de
modo que no existe independencia entre la etapa de traducción y la etapa de
ejecución. Un intérprete traduce cada instrucción o sentencia del programa escrito
a un lenguaje máquina e inmediatamente se ejecuta. Encuentran su mayor ventaja
en la interacción con el usuario, al facilitar el desarrollo y puesta a punto de
programas, ya que los errores son fáciles de detectar y sobre todo de corregir.
Un intérprete no genera un programa equivalente, sino que toma una sentencia del
programa fuente en un lenguaje de alto nivel y la traduce al código equivalente y al

Ing. Karina Cabrera Chagoyan 11


Programación de sistemas

mismo tiempo lo ejecuta. Históricamente, con la escasez de memoria de los


primeros ordenadores, se puso de moda el uso de intérpretes frente a los
compiladores, pues el programa fuente sin traducir y el intérprete juntos daban una
ocupación de memoria menor que la resultante de los compiladores.
La ventaja del proceso interprete es que no necesita de dos fases para ejecutar el
programa, sin embargo su inconveniente es que la velocidad de ejecución es más
lenta ya que debe analizar e interpretar las instrucciones contenidas en el
programa fuente.
En informática, un intérprete acepta programas escritos en un lenguaje de alto
nivel, los analiza y los ejecuta bajo control del propio intérprete. En este caso, no
se genera un programa equivalente en otro lenguaje, como ocurre con un
compilador por lo que, si se desea repetir la ejecución del programa, es preciso
volver a traducirlo.

En un intérprete sólo hay que distinguir dos lenguajes diferentes:


 el de los programas de partida (LA)
 el lenguaje en que está escrito el intérprete (LC).

Los programas interpretados suelen ser más lentos que los compilados, pero los
intérpretes son más flexibles como entornos de programación y depuración.
Comparando su actuación con la de un ser humano, un compilador equivale a un
traductor profesional que, a partir de un texto, prepara otro independiente traducido
a otra lengua, mientras que un intérprete corresponde al intérprete humano, que
traduce de viva voz las palabras que oye, sin dejar constancia por escrito.
En la actualidad el entorno más común de uso de los intérpretes informáticos es
Internet, debido a la posibilidad que éstos tienen de ejecutarse
independientemente de la plataforma.
PHP, Javascript, ASP (hasta la versión 3) y HTML son ejemplos de lenguajes
interpretados.

Ventajas del intérprete frente al compilador:


 Un intérprete necesita menos memoria que un compilador. En principio eran
más abundantes dado que los ordenadores tenían poca memoria.
 Permiten una mayor interactividad con el código en tiempo de desarrollo.

1.5 Generadores de código para compiladores (compilador de compilador)

El proceso de la escritura de un compilador implica mucho tiempo y esfuerzo. En


algunas áreas, en especial en la construcción de analizadores de léxicos y
sintácticos, es posible realizar automáticamente gran parte de este trabajo. Un
compilador de compiladores es una herramienta de software que puede usarse
para ayudar en la tarea de la construcción del compilador. Estas herramientas se
llaman también generadores de compiladores o sistemas de escritura para
traductores.
El proceso de uso de un compilador de compiladores característico se ilustra en la
figura1.

Ing. Karina Cabrera Chagoyan 12


Programación de sistemas

Figura 1.

El usuario (esto es, el escritor del compilador) proporciona una descripción del
lenguaje que se va a traducir. Esta descripción puede consistir en un conjunto de
reglas léxicas para la definición de los componentes léxicos y una gramática para
el lenguaje fuente. Algunos compiladores de compiladores manejan esta
información para generar directamente un analizador de léxico y uno sintáctico.
Otros crean tablas para ser utilizadas por rutinas de análisis léxico estándar
manejado por tabla y por rutinas de análisis sintáctico, proporcionadas por el
compilador de compiladores.
Además de la descripción del lenguaje fuente, el usuario proporciona un conjunto
de rutinas semánticas o de generación de código. A menudo existe una rutina
para cada regla de la gramática. El analizador sintáctico llama a esta rutina cada
vez que reconoce la construcción del lenguaje descrita por la regla asociada. Sin
embargo, algunos compiladores de compiladores pueden analizar sintácticamente
una sección más grande del programa antes de llamar a una rutina semántica. En
este caso, puede pasarse una forma interna de las proposiciones que se han
analizado, como sucedería con una porción del árbol sintáctico, a la rutina
semántica. Este último enfoque se usa mucho cuando se efectúa la optimación de
código. Los compiladores de compiladores suelen proporcionar lenguajes
especiales, notaciones, estructuras de datos y otras posibilidades similares, que
pueden emplearse en la escritura de rutinas semánticas.
La principal ventaja de hacer uso de un compilador de compiladores es, por
supuesto, la facilidad de construir y probar un compilador. Sin embargo, la
cantidad de trabajo requerido por el usuario varía considerablemente de un
compilador de compiladores a otro, dependiendo del grado de flexibilidad
proporcionado. Los compiladores generados de esta forma tienden a necesitar
más memoria y compilan los programas con más lentitud que los compiladores
escritos a mano. Sin embargo, el código objeto generado por el compilador puede
ser realmente mejor cuando se usa un compilador de compiladores. A causa de la
construcción automática de analizadores de léxicos y sintácticos, y a las
herramientas especiales que se proporcionan para la escritura de rutinas
semánticas, el escritor del compilador se libera de muchos detalles mecánicos de
la construcción del compilador, por lo que puede centrar más la atención en una
buena generación y optimación de código.
Con el fin de aumenta la velocidad de producción de los compiladores y reducir el
personal que intervenga en ellos, se han desarrollado lenguajes de alto nivel
llamados compilador de compiladores.
Los primeros lenguajes de este tipo aparecieron en 1958 y suelen estructurarse en
sublenguajes específicos para cada parte del proceso de compilación.

Ing. Karina Cabrera Chagoyan 13


Programación de sistemas

En general el programa objeto producido por un compilador a su vez generado por


un compilador de compiladores es mejor y está más optimizado que el producido
por un compilador escrito a mano. Es evidente: las características especiales que
un computador determinado imprime en la traducción de los programas objetos
son más fáciles de expresar en un lenguaje de alto nivel y los algoritmos usados
generalizan más que los manuales.
Los programas yacc y lex son herramientas de gran utilidad para un diseñador de
compiladores. Muchos compiladores se han construido utilizando estas
herramientas (por ejemplo, el compilador de C de GNU, gcc) o versiones mas
avanzadas.
Los programas bison y flex son las versiones más modernas (no comerciales) de
yacc y lex, y se distribuyen bajo licencia GPL con cualquier distribución de Linux (y
también están disponibles para muchos otros UNIX).Lex puede verse como una
herramienta que nos permite ejecutar acciones tras la localización de cadenas de
entrada que confrontan con expresiones regulares.
Lex puede ser visto como la primera etapa necesaria a la hora de elaborar un
compilador, un intérprete, un emulador o cualquier otro tipo de herramienta que
necesite procesar un fichero de entrada para poder cumplir su misión.

Ing. Karina Cabrera Chagoyan 14

También podría gustarte