facebook

mi facebook

miércoles, 20 de abril de 2011

1. Traductores Bajo Nivel

¿QUÉ ES UN TRADUCTOR?

Un traductor es cualquier programa que toma como entrada un texto escrito en un lenguaje, llamado fuente y da como salida otro texto en un lenguaje, denominado objeto.

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:

Se compila una vez, se ejecuta n veces.

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.

El compilador tiene una visión global del programa, por lo que la información

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.

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, generan un programa en lenguaje ensamblador que debe después convertirse en un ejecutable mediante un programa ensamblador.

1.1 Ensamblador

El lenguaje ensamblador, o assembler (assembly language en inglés ) es un lenguaje de programación debajo nivel para los computadores, microprocesadores, microcontroladores, y otros circuitos integradosprogramables. Implementa una representación simbólica de los códigos de máquina binarios y otras constantes necesarias para programar una arquitectura dada de CPU y constituye la representación más directa del código máquina específico para cada arquitectura legible por un programador. Esta representación es usualmente definida por el fabricante de hardware, y está basada en los mnemónicos que simbolizan los pasos de procesamiento (las instrucciones), los registros del procesador, las posiciones de memoria, y otras características del lenguaje. Un lenguaje ensamblador es por lo tanto específico a cierta arquitectura de computador física (o virtual). Esto está en contraste con la mayoría de los lenguajes de programación de alto nivel, que, idealmente son portables.

Características

  • El código escrito en lenguaje ensamblador posee una cierta dificultad de ser entendido ya que su estructura se acerca al lenguaje máquina, es decir, es un lenguaje de bajo nivel.
  • El lenguaje ensamblador es difícilmente portable, es decir, un código escrito para un microprocesador, puede necesitar ser modificado, para poder ser usado en otra máquina distinta. Al cambiar a una máquina con arquitectura diferente, generalmente es necesario reescribirlo completamente.
  • Los programas hechos, por un programador experto, en lenguaje ensamblador, son generalmente mucho más rápidos y consumen menos recursos del sistema (memoria RAM y ROM.) que el programa equivalente compilado desde un lenguaje de alto nivel. Al programar cuidadosamente en lenguaje ensamblador se pueden crear programas que se ejecutan más rápidamente y ocupan menos espacio que con lenguajes de alto nivel.
  • Con el lenguaje ensamblador se tiene un control muy preciso de las tareas realizadas por un microprocesador por lo que se pueden crear segmentos de código difíciles y/o muy ineficientes de programar en un lenguaje de alto nivel, ya que, entre otras cosas, en el lenguaje ensamblador se dispone de instrucciones del CPU que generalmente no están disponibles en los lenguajes de alto nivel.
  • También se puede controlar el tiempo en que tarda una rutina en ejecutarse, e impedir que se interrumpa durante su ejecución.

[editar]
Programa ensamblador

Artículo principal: Ensamblador

Típicamente, un programa ensamblador (assembler en inglés) moderno crea código objeto traduciendo instrucciones mnemónicas de lenguaje ensamblador en opcodes, y resolviendo los nombres simbólicos para las localizaciones de memoria y otras entidades.1 El uso de referencias simbólicas es una característica clave del lenguaje ensamblador, evitando tediosos cálculos y actualizaciones manuales de las direcciones después de cada modificación del programa. La mayoría de los ensambladores también incluyen facilidades de macros para realizar sustitución textual - ej. generar cortas secuencias de instrucciones como expansión en línea en vez de llamar a subrutinas.

Los ensambladores son generalmente más simples de escribir que los compiladores para los lenguajes de alto nivel, y han estado disponibles desde los años 1950. Los ensambladores modernos, especialmente para las arquitecturas basadas en RISC, tales como MIPS, Sun SPARC, y HP PA-RISC, así como también para el x86 (-64), optimizan la planificación de instrucciones para explotar la segmentación del CPU eficientemente.

1.2 Pasadas del texto fuente

Tratamiento de operandos
Las instrucciones de maquina operan sobre los datos, las categorías mas importantes de datos son:
Numéricos
• Enteros o de punto fijo.
• Punto flotante.
• BCD ( Decimal codificado ó binario).- Los datos BCD comprimidos presentan dos dígitos por byte y los no
comprimidos presentan un dígito por byte.
Caracteres
Unidades de 8 bits que normalmente contienen representaciones ASCII de símbolo.
Datos lógicos
• Byte con o sin signo (8 bits).- El bit 7 es el bit de signo de un byte sin signo.
• Palabra con o sin signo (word-16 bits).- El bit 15 es el bit de signo de una word sin signo
• Doble palabra con o sin signo (dword-32 bits).- El bit 31 es el bit de signo de una dword sin signo
• Cuádruple palabra con o sin signo (qword-64 bits).- El bit 63 es el bit de signo de una qword sin signo
Direcciones
Son una forma de dato. En muchos casos, algún calculo se debe ejecutar sobre la referencia de un operando en una
instrucción para determinar la dirección de la memoria principal o virtual. En este contexto, las direcciones se pueden
considerar como enteros sin signo.
• Desplazamiento.- Son cantidades de 16 o 32 bits que contienen la distancia de la dirección base o la
dirección referenciada.
• Punteros.- Consistentes en selectores de segmento de 16 bits y un desplazamiento de 16 o 32 bits.
Estilo de programación.- Un programa en ensamblador es una serie de instrucciones ejecutables que le dice al
ensamblador que sentencia tiene que ejecutar. Cada sentencia esta compuesta por cuatro campos:
a) Campo nombre.- Se emplea con frecuencia como punto de entrada o regreso. Algunas veces es denominado
campo del rotulo, asigna un nombre simbólico a la dirección del comienzo de memoria real de una instrucción de
ensamblador. Debe comenzar con un carácter alfabético de 31 caracteres máximo.
b) Campo operación.- Contiene un mnemónico de 2 a 6 caracteres normalmente es una abreviatura en ingles, puede
representar una instrucción maquina, una macroinstruccion, o una pseudo-operación.
c) Campo operando.- Contiene la posición o posiciones donde están los datos que van a ser manipulados por la
instrucción de la operación, si la instrucción mide 1 o 2 operandos, están separados de la instrucción por lo menos
de un espacio en blanco, si hay dos operandos estos están separados por una coma.
d) Campo comentario.- Se utiliza para documentar internamente el código, este debe comenzar con un punto y coma
( ; ).
Formato general de una sentencia
[nombre] mnemónico [operando] [; comentario]

MOV AX, BX = destino, fuente
Operando destino.- La operación puede producir un resultado.
Operando fuente.- La operación puede involucrar uno o mas operandos fuentes, esto es, operandos que son
entradas para la operación.

1.3 Tratamientos de Operandos y Modos de Direccionamiento de Maquina Objeto

Técnicas de direccionamiento
El campo o campos de dirección en un formato de instrucción típico son algo limitados. Para hacer referencia a un rango mas grande de localidades en memoria principal o, para sistemas en memoria virtual. Para lograr este objetivo, se han empleado una variedad de técnicas de direccionamiento. Todos involucran un trueque entre el rango de direcciones y/o la flexibilidad de direccionamiento por una parte, y el numero de referencias de memoria y/o la complejidad de calculo de la dirección por otro.
• Direccionamiento Inmediato. El microprocesador decodifica el modo de direccionamiento que está siendo referenciado. Se transfiere un byte, word o dword de datos inmediatos hacia el registro o localidad en la memoria del destino. Ejemplo:
MOV AL, 22H
La instrucción copia el 22H de tamaño byte al registro AL.
• Direccionamiento de registros. Transfiere un byte, word o dword desde el registro fuente o localidad en la memoria, hasta el registro o localidad destino en la memoria. Ejemplos:
MOV AX, BX
MOV CX, DX
La instrucción copia el contenido de tamaño de palabra en el registro DX y lo pasa al registro CX. NOTA: de los 8
modos de direccionamiento, el inmediato y el de registros tienen los ciclos de ejecución mas pequeños, como el dato operando puede ser incluido en la misma instrucción y ya este almacenado internamente se evita el tiempo de acceso a dispositivos externos o memoria externa.
• Direccionamiento directo. Mientras el direccionamiento inmediato solamente almacena datos en registros o locaciones de memoria, el direccionamiento directo mueve datos de locaciones de memoria a registro ó desde registro a locaciones de memoria. Ejemplo:
LOC_1 DB 00
LOC_2 DW 0000
MOV AL, LOC_1
MOV BX, LOC_2
MOV LOC_1, AH
• Direccionamiento indirecto por registros. En lugar de diferenciar con un rotulo de dirección del operando fuente, el valor del operando es señalado por una dirección de desplazamiento almacenada en alguno de los siguientes registros: SI (índice fuente), DI (índice destino), BX (registro base) y BP (puntero base). El designador del operando fuente es reconocido por corchetes ( [ ] ). Ejemplo:
MOV AX, [BX]
REGISTROS
GENERALES
REGISTROS DE
SEGMENTACION

3
La instrucción copia los datos en una dirección del segmento de datos con un desplazamiento dado por BX y lo pasa al registro AX.
• Direccionamiento relativo a la base. La dirección efectiva de un operando se obtiene de la suma del desplazamiento y contenido de un registro base ( BX o BP ) relativo al segmento relacionado. Ejemplo:
MOV AL, [BX] + 4 ó MOV AL, [BX + 4] ó MOV AL, 4[BX]
La instrucción copia los datos de una dirección en el segmento de datos, formada por el contenido de BX mas 4, y lo pone en el registro AL.
• Direccionamiento indexado directo. La dirección del desplazamiento del operando se calcula sumando el
desplazamiento a un registro índice (SI o DI) en el desplazamiento seleccionado. Frecuentemente se utiliza para
acceder a los elementos de un array estático. Ejemplo:
MOV AL, ARRAY [SI]
La instrucción copia la dirección formada de sumar ARRAY y SI entonces la coloca en el registro AL.
• Direccionamiento base indexado. El operando se localiza en el segmento seleccionado en un desplazamiento determinado por la suma de los contenido del registro base, registro índice y opcionalmente el desplazamiento. Si no se incluye desplazamiento entonces, el registro base indexado se utiliza con mas frecuencia para acceder a los elementos de un array dinámico. Ejemplo:
MOV AX, ARRAY [ BX+ DI]
La instrucción copia la dirección formada de sumar ARRAY, BX y DI entonces la coloca en el registro AX.
• Extensiones del 80386. Los modos de direccionamiento de 32 bits se extienden para permitir que cualquier registro sea utilizado como registro base o registro índice. Los modos de 32 bits requieren que los registros índices y bases si se usan tengan valores validos de 32 bits.
Ensambladores residentes y cruzados Los ensambladores son traductores que transforman programas fuentes escritos en lenguaje ensamblador, en programas objetos equivalentes escritos en lenguaje máquina. La traducción se realiza de tal forma que cada instrucción escrita en ensamblador se transforma en una única instrucción en lenguaje maquina. El lenguaje ensamblador es una simplificación simbólica del lenguaje maquina y el programa ensamblador es su traductor.
• Ensamblador cruzado (cross assembler). Es un traductor de lenguaje ensamblador a lenguaje maquina que traduce en una computadora y ejecuta en otra distinta. La ventaja que ofrece este tipo de traductor es utilizar una computadora de características potentes para desarrollar programas que van dirigidos a otra cuya potencia y facilidades para el programador están ciertamente limitados.
• Macroensamblador (macroassembler). Es un ensamblador que posee la característica de permitir el uso de lo que se denomina microinstrucción. Una micro instrucción no es mas que un grupo de instrucciones que de forma global reciben nombre simbólico al que se puede hacer referencia en un programa tantas veces como se desee.
El macroensamblador coloca en la traducción el mencionado grupo de instrucciones en cada una de las referencias (expansión de macros).
• Microensamblador. Es un traductor utilizado en la microprogramacion que algunas computadoras tienen. Estos microprogramas permiten cierta flexibilidad al repertorio de instrucciones maquina de la computadora.
• Ensamblador de una pasada o increméntales. Traducen en una sola pasada construyendo la tabla de símbolos a medida que van apareciendo las variables y etiquetas. Tienen el pequeño inconveniente de no permitir lo que se denomina referencias adelantadas, es decir, referencias a líneas de programa posteriores no traducidos.
• Ensamblador de dos pasadas. Realizan la traducción en dos pasadas, en la primera leen el programa fuente construyendo la tabla de símbolos y asignando las correspondientes direcciones, en la segunda vuelven a leer el programa traduciéndolo a lenguaje maquina. Si están permitidos las referencias adelantadas, siendo este tipo de ensamblador los mas utilizados actualmente.

1.4 Ensambladores Residentes y Cruzados

Ensambladores Residentes.

Son aquellos que permanecen en la memoria principal de la computadora y cargan, para su ejecución, al programa objeto producido. Este tipo de ensamblador tiene la ventaja de que se puede comprobar inmediatamente el programa sin necesidad de transportarlo de un lugar a otro, como se hacía en cross-assembler, y sin necesidad de programas simuladores.

Sin embargo, puede presentar problemas de espacio de memoria, ya que el traductor ocupa espacio que no puede ser utilizado por el programador. Asimismo, también ocupará memoria el programa fuente y el programa objeto. Esto obliga a tener un espacio de memoria relativamente amplio. Es el indicado para desarrollos de pequeños sistemas de control y sencillos automatismo empleando microprocesadores(1).

La ventaja de estos ensambladores es que permiten ejecutar inmediatamente el programa; la desventaja es que deben mantenerse en la memoria principal tanto el ensamblador como el programa fuente y el programa objeto.

Ensambladores Cruzados (Cross-Assembler).

Se denominan así los ensambladores que se utilizan en una computadora que posee un procesador diferente al que tendrán las computadoras donde va a ejecutarse el programa objeto producido.

El empleo de este tipo de traductores permite aprovechar el soporte de medios físicos (discos, impresoras, pantallas, etc.), y de programación que ofrecen las máquinas potentes para desarrollar programas que luego los van a ejecutar sistemas muy especializados en determinados tipos de tareas.


1.5 Ensamble condicional

Se emplean para que el ensamblador evalúe unas condiciones y, según ellas, ensamble o no ciertas zonas de código. Es frecuente, por ejemplo, de cara a generar código para varios ordenadores: pueden existir ciertos símbolos definidos que indiquen en un momento dado si hay que ensamblar ciertas zonas del listado o no de manera condicional, según la máquina. En los fragmentos en ensamblador del código que generan los compiladores también aparecen con frecuencia (para actuar de manera diferente, por ejemplo, según el modelo de memoria). Es interesante también la posibilidad de definir un símbolo que indique que el programa está en fase de pruebas y ensamblar código adicional en ese caso con objeto de depurarlo. Sintaxis:

IFxxx [símbolo/exp./arg.] ; xxx es la condición

...ELSE ; el ELSE es opcional

...ENDIF

IF expresion (expresión distinta de cero)

IFE expresión (expresión igual a cero)

IF1 (pasada 1 del ensamblador)

IF2 (pasada 2 del ensamblador)

IFDEF símbolo (símbolo definido o declarado como externo)

IFNDEF símbolo (símbolo ni definido ni declarado como externo)

IFB (argumento en blanco en macros -incluir '<' y '>'-)

IFNB (lo contrario, también es obligado poner '<' y '>')

IFIDN , (arg1 idéntico a arg2, requiere '<' y '>')

IFDIF , (arg1 distinto de arg2, requiere '<' y '>')

1.6 Microprocesador

El microprocesador, o simplemente procesador, es el circuito integrado central y más complejo de una computadora u ordenador; a modo de ilustración, se le suele asociar por analogía como el "cerebro" de una computadora.
El procesador es un circuito integrado constituido por millones de componentes electrónicos integrados. Constituye la unidad central de procesamiento (CPU) de un PC catalogado como microcomputador.
Desde el punto de vista funcional es, básicamente, el encargado de realizar toda operación aritmético-lógica, de control y de comunicación con el resto de los componentes integrados que conforman un PC, siguiendo el modelo base de Von Neumann. También es el principal encargado de ejecutar los programas, sean de usuario o de sistema; sólo ejecuta instrucciones programadas a muy bajo nivel, realizando operaciones elementales, básicamente, las aritméticas y lógicas, tales como sumar, restar, multiplicar, dividir, las lógicas binarias y accesos a memoria.
Esta unidad central de procesamiento está constituida, esencialmente, por registros, una unidad de control y una unidad aritmético lógica (ALU), aunque actualmente todo microprocesador también incluye una unidad de cálculo en coma flotante, (también conocida como "coprocesador matemático"), que permite operaciones por hardware con números decimales, elevando por ende notablemente la eficiencia que proporciona sólo la ALU con el cálculo indirecto a través de los clásicos números enteros.
El microprocesador está conectado, generalmente, mediante un zócalo específico a la placa base. Normalmente para su correcto y estable funcionamiento, se le adosa un sistema de refrigeración, que consta de un disipador de calor fabricado en algún material de alta conductividad térmica, como cobre o aluminio, y de uno o más ventiladores que fuerzan la expulsión del calor absorbido por el disipador; entre éste último y la cápsula del microprocesador suele colocarse pasta térmica para mejorar la conductividad térmica. Existen otros métodos más eficaces, como la refrigeración líquida o el uso de células peltier para refrigeración extrema, aunque estas técnicas se utilizan casi exclusivamente para aplicaciones especiales, tales como en las prácticas de overclocking.
La "velocidad" del microprocesador suele medirse por la cantidad de operaciones por ciclo de reloj que puede realizar y en los ciclos por segundo que este último desarrolla, o también en MIPS. Está basada en la denominada frecuencia de reloj (oscilador). La frecuencia de reloj se mide hertzios, pero dada su elevada cifra se utilizan múltiplos, como el megahertzio o el gigahertzio.
Cabe destacar que la frecuencia de reloj no es el único factor determinante en el rendimiento, pues sólo se podría hacer comparativa entre dos microprocesadores de una misma microarquitectura.
Es importante notar que la frecuencia de reloj efectiva no es el producto de la frecuencia de cada núcleo físico del procesador por su número de núcleos, es decir, uno de 3 GHz con 6 núcleos físicos nunca tendrá 18 GHz, sino 3 GHz, independientemente de su número de núcleos.
Hay otros factores muy influyentes en el rendimiento, como puede ser su memoria caché, su cantidad de núcleos, sean físicos o lógicos, el conjunto de instrucciones que soporta, su arquitectura, etc; por lo que sería difícilmente comparable el rendimiento de dos procesadores distintos basándose sólo en su frecuencia de reloj.
Un computador de alto rendimiento puede estar equipado con varios microprocesadores trabajando en paralelo, y un microprocesador puede, a su vez, estar constituido por varios núcleos físicos o lógicos. Un núcleo físico se refiere a una porción interna del microprocesador cuasi-independiente que realiza todas las actividades de una CPU solitaria, un núcleo lógico es la simulación de un núcleo físico a fin de repartir de manera más eficiente el procesamiento.
Estos últimos años ha existido una tendencia de integrar el mayor número de elementos de la PC dentro del propio procesador, aumentando así su eficiencia energética y su rendimiento. Una de las primeras integraciones, fue introducir la unidad de coma flotante dentro del encapsulado, que anteriormente era un componente aparte y opcional situado también en la placa base, luego se introdujo también el controlador de memoria, y más tarde un procesador gráfico dentro de la misma cámara, aunque no dentro del mismo encapsulado. Posteriormente se llegaron a integrar completamente en el mismo encapsulado (die).
Respecto a esto último, compañías tales como Intel ya planean integrar el puente sur dentro del microprocesador, eliminando completamente ambos circuitos auxiliares de la placa.
También la tendencia general, más allá del mercado del PC, es integrar varios componentes en un mismo chip para dispositivos tales como Tablet PC, teléfonos móviles, videoconsolas portátiles, etc. A estos circuitos integrados "todo en uno" se los conoce como system on a chip; por ejemplo nVidia Tegra o Samsung Hummingbird, ambos integran microprocesador, unidad de procesamiento gráfico y controlador de memoria dentro de un mismo circuito integrado.

1.7 Biblioteca de Macros

Una macro es un grupo de instrucciones repetitivas en un programa que se codifican solo una vez y pueden utilizarse cuantas veces sea necesario.

La principal diferencia entre una macro y un procedimiento es que en la macro se hace posible el paso de parámetros y en el procedimiento no (esto es aplicable solo para el MASM, hay otros lenguajes de Programación que si lo permiten). Al momento de ejecutarse la macro cada parámetro es sustituido por el nombre o valor especificado al momento de llamarla.

Podemos decir entonces que un procedimiento es una extensión de un determinado programa, mientras que la macro es un módulo con funciones específicas que puede ser utilizado por diferentes programas.

Otra diferencia entre una macro y un procedimiento es la forma de llamar a cada uno, para llamar a un procedimiento se requiere el uso de una directiva, en cambio la llamada a las macros se realiza como si se tratara de una instrucción del ensamblador.

Sintaxis de una macro

Las partes que componen a una macro son:

    • Declaración de la macro
    • código de la macro
    • Directiva de terminación de la macro
La declaración de la macro se lleva a cabo de la siguiente forma:

NombreMacro MACRO [parametro1, parametro2...]

Aunque se tiene la funcionalidad de los parametros es posible crear una macro que no los necesite.

La directiva de terminación de la macro es: ENDM

Un ejemplo de macro, para colocar el cursor en alguna posición determinada de la pantalla es:

Posicion MACRO Fila, Columna
PUSH AX
PUSH BX
PUSH DX
MOV AH, 02H
MOV DH, Fila
MOV DL, Columna
MOV BH, 0
INT 10H
POP DX
POP BX
POP AX
ENDM

Para utilizar una macro solo es necesario llamarla por su nombre, como si fuera una instrucción mas del ensamblador, ya no son necesarias las directivas como en el caso de los procedimientos.

Bibliotecas de macros

Una de las facilidades que ofrece el uso de las macros es la creación de bibliotecas, las cuales son grupos de macros que pueden ser incluidas en un programa desde un archivo diferente.

La creación de estas bibliotecas es muy sencilla, unicamente tenemos que escribir un archivo con todas las macros que se necesitarán y guardarlo como archivo de texto.

Para llamar a estas macros solo es necesario utilizar la instrucción Include NombreDelArchivo, en la parte de nuestro programa donde escribiriamos normalmente las macros, esto es, al principio de nuestro programa (antes de la declaración del modelo de memoria).

Suponiendo que se guardó el archivo de las macros con el nombre de MACROS.TXT la instrucción Include se utilizaría de la siguiente forma:

;Inicio del programa
Include MACROS.TXT
.MODEL SMALL
.DATA
;Aqui van los datos
.CODE
Inicio:
;Aqui se inserta el código del programa
.STACK
;Se define la pila
End Inicio
;Termina nuestro programa

1.8 Expansión Condicional

2 Traductor del Alto Nivel

Lenguajes de alto nivel
Por lo general se piensa que los ordenadores son máquinas que realizan tareas de cálculos o procesamiento de textos. La descripción anterior es sólo una forma muy esquemática de ver una computadora. Hay un alto nivel de abstracción entre lo que se pide a la computadora y lo que realmente comprende. Existe también una relación compleja entre los lenguajes de alto nivel y el código máquina.
Los lenguajes de alto nivel son normalmente fáciles de aprender porque están formados por elementos de lenguajes naturales, como el inglés. En BASIC, el lenguaje de alto nivel más conocido, los comandos como "IF CONTADOR = 10 THEN STOP" pueden utilizarse para pedir a la computadora que pare si CONTADOR es igual a 10. Por desgracia para muchas personas esta forma de trabajar es un poco frustrante, dado que a pesar de que las computadoras parecen comprender un lenguaje natural, lo hacen en realidad de una forma rígida y sistemática.
Intérpretes y compiladores La traducción de una serie de instrucciones en lenguaje ensamblador (el código fuente) a un código máquina (o código objeto) no es un proceso muy complicado y se realiza normalmente por un programa especial llamado compilador. La traducción de un código fuente de alto nivel a un código máquina también se realiza con un compilador, en este caso más complejo, o mediante un intérprete. Un compilador crea una lista de instrucciones de
código máquina, el código objeto, basándose en un código fuente. El código objeto resultante es un programa rápido y listo para funcionar, pero que puede hacer que falle el ordenador si no está bien diseñado. Los intérpretes, por otro lado, son más lentos que los compiladores ya que no producen un código objeto, sino que recorren el código fuente una línea cada vez. Cada línea se traduce a código máquina y se ejecuta. Cuando la línea se lee por segunda vez,
como en el caso de los programas en que se reutilizan partes del código, debe compilarse de nuevo. Aunque este proceso es más lento, es menos susceptible de provocar fallos en la computadora.
1. Intérpretes
• Lenguajes para aplicaciones específicas susceptibles o idóneos para interpretación
Interpretación directa o mediante pseudo código
Traductores que realizan lo que podemos llamar traducción directa, es decir, traducir y ejecutar simultáneamente. La ventaja frente a un compilador es la ocupación en memoria es menor ya que suelen ser programas mas reducidos en
tamaño que un compilador. La desventaja es el tiempo de ejecución que tarda un programa sujeto a este tipo de traducción. En la actualidad existen interpretes que incorporan una pequeña fase de análisis antes de la interpretación para evitar los problemas originados por la suspensión del programa en ejecución al aparecer el primero de los errores, con lo cual todo proceso transcurrido se pierde. Una buena aplicación de los interpretes es la de depurar programas que una vez en funcionamiento correcto se compilan ejecutándose el producto de dicha compilación en el uso normal del programa.
2. Compiladores
• Tipos de gramáticas formales Una gramática se define como un conjunto finito de reglas sintácticas. La gramática esta formada de 4 elementos los cuales se identifican como (V, T, P, Z) donde:
V es el alfabeto.
T es el conjunto de símbolos terminales, de donde T esta en V.
P es el conjunto de reglas sintácticas.
Z es un símbolo de V - T, al cual se le llama el símbolo inicial.
El lenguaje de una gramática, es el conjunto de cadenas de símbolos terminales, los cuales pueden ser generados desde Z. Para resolver el problema del análisis de enunciados en un lenguaje de programación se desarrollo la teoría de los lenguajes formales, que enumera diferentes clases de lenguajes con ciertas propiedades, y que pueden ser definidos en términos de sus gramáticas, las cuales generan solamente lenguajes de esa clase, Se definen 4 tipos básicos de gramáticas, los cuales son:
• De tipo 0 ò sin restricciones
• De tipo 1 ó dependientes del contexto
• De tipo 2 ó libres del contexto
• De tipo 3 o regulares
El tipo de gramática que usa un compilador es de tipo 2 ó libre de contexto. Este tipo de gramáticas tienen 4
componentes:
1.- Un conjunto de componentes léxicos, denominados símbolos terminales.
2.- Un conjunto de no terminales
3.- Un conjunto de producciones, en el cada producción consta de un no terminal, llamado lado izquierdo de la producción, una flecha y una secuencia de componentes léxicos y no terminales, o ambos llamado lado derecho de la producción.
4.- La denominación de uno de los no terminales como símbolo inicial.

2.1 Interprete

intérprete o interpretador es un programa informático capaz de analizar y ejecutar otros programas, escritos en un lenguaje de alto nivel. Los intérpretes se diferencian de los compiladores en que mientras estos traducen un programa desde su descripción en un lenguaje de programación al código de máquina del sistema, los intérpretes sólo realizan la traducción a medida que sea necesaria, típicamente, instrucción por instrucción, y normalmente no guardan el resultado de dicha traducción.

Usando un intérprete, un solo archivo fuente puede producir resultados iguales incluso en sistemas sumamente diferentes (ej. una PC y un PlayStation 3). Usando un compilador, un solo archivo fuente puede producir resultados iguales solo si es compilado a distintos ejecutables específicos a cada sistema.

Los programas interpretados suelen ser más lentos que los compilados debido a la necesidad de traducir el programa mientras se ejecuta, pero a cambio son más flexibles como entornos de programación y depuración (lo que se traduce, por ejemplo, en una mayor facilidad para reemplazar partes enteras del programa o añadir módulos completamente nuevos), y permiten ofrecer al programa interpretado un entorno no dependiente de la máquina donde se ejecuta el intérprete, sino del propio intérprete (lo que se conoce comúnmente comomáquina virtual).

Para mejorar el desempeño, algunas implementaciones de programación de lenguajes de programación pueden interpretar o compilar el código fuente original en una más compacta forma intermedia y después traducir eso al código de máquina (ej. Perl, Python, MATLAB, y Ruby). Algunos aceptan los archivos fuente guardados en esta representación intermedia (ej. Python, UCSD Pascal y Java).

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, uno de los entornos más comunes de uso de los intérpretes informáticos es Internet, debido a la posibilidad que estos tienen de ejecutarse independientemente de la plataforma.


La desventaja principal de los interpretadores es que cuando se interpreta un programa, típicamente corre más lentamente que si hubiera sido compilado. La diferencia en velocidades puede ser minúscula o grande; a menudo un orden de magnitud y a veces más. Generalmente toma más tiempo correr un programa bajo un interpretador que correr el código compilado, pero puede tomar menos tiempo para interpretarlo que el tiempo total requerido para compilarlo y ejecutarlo. Esto es especialmente importante si se está haciendo y probando un código prototipo cuando un ciclo de editar, interpretar y depurar del interpretador, a menudo puede ser mucho más corto que el ciclo de editar, compilar, ejecutar y depurar del compilador.

La interpretación de código es más lenta que la ejecución de código compilado porque el interpretador debe analizar cada sentencia en el programa cada vez que es ejecutada y entonces realizar la acción deseada, mientras que el código compilado solo realiza la acción dentro de un determinado contexto fijo por la compilación. Este análisis en tiempo de ejecución se conoce como "sobrecarga interpretativa". En un interpretador, el acceso a las variables es también más lento porque el mapeo de identificadores hacia las localizaciones de almacenamiento debe hacerse repetidamente en tiempo de ejecución en vez de en el tiempo de compilación. Hay varios compromisos entre la velocidad de desarrollo al usar un interpretador y la velocidad de ejecución al usar un compilador. Algunos sistemas (ej., algunos LISPs) permiten al código interpretado y al compilado llamarse el uno al otro y compartir variables. Esto significa que una vez que una rutina ha sido probada y depurada bajo el interpretador puede ser compilada y por lo tanto beneficiarse de una ejecución más rápida mientras que otras rutinas están siendo desarrolladas. Muchos interpretadores no ejecutan el código fuente tal y como está sino que lo convierten en una forma interna más compacta. Por ejemplo, algunos interpretadores BASIC reemplazan palabras clave (keywords) con tokens de un simple byte que pueden ser usados para encontrar la instrucción en una tabla de saltos. Un interpretador puede bien usar el mismo analizador lexicográfico y el analizador sintáctico (parser) que el compilador y entonces interpretar el árbol de sintaxis abstractaresultante.

Algunos ejemplos de lenguajes que son normalmente interpretados en vez de compilados son:

2.2 Interpretacion Directa Mediante Seudocodigo

son traductores que realizan lo que podemos llamar traducción directa, es decir, traducir y ejecutar simultáneamente. La ventaja frente a un compilador es la ocupación en memoria es menor ya que suelen ser programas mas reducidos en tamaño que un compilador. La desventaja es el tiempo de ejecución que tarda un programa sujeto a este tipo de traducción. En la actualidad existen interpretes que incorporan una pequeña fase de análisis antes de la interpretación para evitar los problemas originados por la suspensión del programa en ejecución al aparecer el primero de los errores, con lo cual todo proceso transcurrido se pierde. Una buena aplicación de los interpretes es la de depurar programas que una vez en funcionamiento correcto se compilan ejecutándose el producto de dicha compilación en el uso normal del programa.

2.3 Compiladores

Un compilador es un programa informático que traduce un programa escrito en un lenguaje de programación a otro lenguaje de programación, generando un programa equivalente que la máquina será capaz de interpretar. Usualmente el segundo lenguaje eslenguaje de máquina, pero también puede ser simplemente texto. Este proceso de traducción se conoce como compilación.1

Un compilador es un programa que permite traducir el código fuente de un programa en lenguaje de alto nivel, a otro lenguaje de nivel inferior (típicamente lenguaje de máquina). De esta manera un programador puede diseñar un programa en un lenguaje mucho más cercano a como piensa un ser humano, para luego compilarlo a un programa más manejable por una computadora.


Partes de un compilador

La construcción de un compilador involucra la división del proceso en una serie de fases que variará con su complejidad. Generalmente estas fases se agrupan en dos tareas: el análisis del programa fuente y la síntesis del programa objeto.

  • Análisis: Se trata de la comprobación de la corrección del programa fuente, e incluye las fases correspondientes al Análisis Léxico (que consiste en la descomposición del programa fuente en componentes léxicos), Análisis Sintáctico (agrupación de los componentes léxicos en frases gramaticales ) y Análisis Semántico (comprobación de la validez semántica de las sentencias aceptadas en la fase de Análisis Sintáctico).
  • Síntesis: Su objetivo es la generación de la salida expresada en el lenguaje objeto y suele estar formado por una o varias combinaciones de fases de Generación de Código (normalmente se trata de código intermedio o de código objeto) y de Optimización de Código (en las que se busca obtener un código lo más eficiente posible).

Alternativamente, las fases descritas para las tareas de análisis y síntesis se pueden agrupar en Front-end y Back-end:

  • Front-end: es 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, y está compuesta por las fases comprendidas entre el Análisis Léxico y la Generación de Código Intermedio.
  • 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 Front End que sirve para analizar el código fuente de un lenguaje de programación concreto sirva para generar código máquina en varias plataformas distintas. Suele incluir la generación y optimización del código dependiente de la máquina.

El código que genera el Back End normalmente no se puede ejecutar directamente, sino que necesita ser enlazado por un programa enlazador (linker)

Diagrama a bloques de la operación de un buen compilador


2.4 Topicos de compilacion

Intérpretes puros
Los intérpretes puros son los que analizan y ejecutan sentencia a sentencia todo el programa
fuente. Siguen el modelo de interpretación iterativa y, por tanto, se utilizan principalmente para lenguajes sencillos.
Los intérpretes puros se han venido utilizando desde la primera generación de ordenadores al
permitir la ejecución de largos programas en ordenadores de memoria reducida, ya que sólo debían contener en memoria el intérprete y la sentencia a analizar y ejecutar en cada momento. El principal problema de este tipo de intérpretes es que si a mitad del programa fuente se producen errores, se debe de volver a comenzar el proceso.

Intérpretes avanzados
Los intérpretes avanzados o normales incorporan un paso previo de análisis de todo el
programa fuente. Generando posteriormente un lenguaje intermedio que es ejecutado por ellos mismos.
De esta forma en caso de errores sintácticos no pasan de la fase de análisis. Se utilizan para lenguajes más avanzados que los intérpretes puros, ya que permiten realizar un análisis más detallado del programa fuente (comprobación de tipos, optimización de instrucciones, etc.)

Intérpretes incrementales
Existen ciertos lenguajes que, por sus características, no se pueden compilar directamente. La
razón es que pueden manejar objetos o funciones que no son conocidos en tiempo de compilación, ya que se crean dinámicamente en tiempo en ejecución. Entre estos lenguajes, pueden considerarse Smalltalk, Lisp o Prolog. Con el propósito de obtener una mayor eficiencia que en la interpretación simple, se diseñan compiladores incrementales. La idea es compilar aquellas partes estáticas del programa en lenguaje fuente, marcando como dinámicas las que no puedan compilarse. Posteriormente, en tiempo de ejecución, el sistema podrá compilar algunas partes dinámicas o recompilar partes dinámicas que hayan sido modificadas. Estos sistemas no producen un código objeto independiente, sino que acompañan el sistema que permite compilar módulos en tiempo de ejecución (run time system) al código objeto generado.
Normalmente, los compiladores incrementales se utilizan en sistemas interactivos donde conviven módulos compilados con módulos modificables [Rober94].

Compiladores “Just in Time”
Con la aparición de Internet surge la necesidad de distribuir programas de una forma
independiente de la máquina permitiendo su ejecución en una amplia variedad de plataformas. Los códigos de bytes de la máquina Virtual de Java permiten la ejecución de programas distribuidos, ya que la mayoría de los visualizadores tienen un mecanismo capaz de interpretarlos. La interpretación de códigos de bytes supone una demora en los tiempos de ejecución.
Para evitar la interpretación, muchos sistemas transforman los códigos de bytes en código nativo
siguiendo el modelo “just in time”. En este modelo, una unidad de compilación o clase se transmite en el formato de códigos de bytes, pero no se realiza la interpretación. En lugar de ello, el código es compilado a código nativo justo en el momento en que lo necesita el programa que se está ejecutando.

Compilación Continua
La compilación continua surge como un intento de mejorar la compilación “Just in Time”. El
sistema mezcla el proceso de compilación a código nativo con el proceso de interpretación. Para
conseguirlo, el sistema dispone de dos módulos: un módulo de intérpretación de los códigos de bytes y otro módulo de compilación de códigos de bytes a código nativo. La idea consiste en que ambos módulos actúen a la vez (lo ideal sería disponer de dos procesadores), de forma que el sistema no se detenga a compilar un módulo, sino que vaya interpretándolo hasta que el compilador haya generado el código nativo.

2.5 Ambientes Integrados

Es un entorno compuesto por un conjunto de herramientas de programacion

Puede dedicarse en exclusiva a un sólo lenguaje de programacion o bien, poder utilizarse para varios.

Un ambiente de ingeniería de software es un conjunto de herramientas de hardware y software las cuales actúan en combinación de una manera integrada para proporcionar soporte a todos los procesos de software desde la especificación inicial pasando por las pruebas y hasta la liberación del sistema.

Componentes

§ Un editor de texto

§ Un compilador

§ Un interprete

§ Un depurador

§ Posibilidad de ofrecer un sistema de control de conversiones

§ Factibilidad para ayuda en la construcción de interfaces graficas de usuarios

Herramientas del ambiente

Herramientas integradas

Herramientas que manejan todos los datos usando los servicios del área de trabajo e implementando sus estructuras de datos en un sistema de manejo de objetos

Herramientas semi-aisladas

Herramientas menos integradas. Manejan sus propios datos pero los archivos en los cuales están almacenados son manejados usando servicios del área de trabajo

Herramientas foráneas

Herramientas las cuales corren en la misma plataforma que el SEE pero solamente usan servicios de plataforma

En si el ambiente integrado proporciona soporte para una amplia gama de actividades de procesos, proporcionar los 5 niveles de integración herramientas y tablas de comparación la cual ha sido discutida, son generalmente para trabajo plataforma central-remota Servicios de plataforma los cuales son proporcionados incluyen archivos, manejo de procesos, red, comunicación, ventanas y servicios de impresión.