jueves, 2 de junio de 2016

Caratula

Universidad Capitan General Gerardo Barrios.

Estudiante:
             
                   Hugo Balmore Vallejo Díaz
                  



Catedrática:                                                          
                  Ing. Marvin Osmaro Parada. 



Facultad:                                                          
                  Ciencia & Tecnología. 
    
   
Carrera:
               Ingeniería En Sistemas & Redes Informáticas.


Catedra:
               Compiladores e Interpretes.

martes, 31 de mayo de 2016

EJEMPLOS DE COMPILACION DE CODIGO ENSAMBLADOR USANDO TASM Y TLINK

EJEMPLOS DE COMPILACIÓN DE CÓDIGO ENSAMBLADOR USANDO TASM Y TLINK

Antes de iniciar la realización de cualquier programa en Lenguaje Ensamblador debemos conocer algunos conceptos básicos. En este caso es primordial el software que utilizaremos para todo el proceso de realización de dichos programas. 

TASM.

El Turbo Assembler (TASM), un paquete ensamblador principalmente destinado a la plataforma del IBM PC y sus compatibles. Fue la oferta de Borland en el mercado de herramientas de programación en lenguaje ensamblador para la familia de los microprocesadoresx86.   

Turbo Assembler también se refiere a un ensamblador común, basado en el microprocesador 6502 para el Commodore 64, creado por la compañía alemana Omikron en 1985. 

TLINK.

El enlazador o linkador permite combinar varios módulos objeto, realizando las conexiones entre ellos y, finalmente, los convierte en módulo ejecutable de tipo EXE (empleando el ML de MASM 6.X se obtiene directamente el fichero EXE ya que invoca automáticamente al linkador). El linkador permite el uso de librerías de funciones y rutinas. TLINK, a diferencia de LINK, permite generar un fichero de tipo COM directamente de un OBJ si se indica el parámetro /t, lo que agiliza aún más el proceso. Puede obtenerse ayuda ejecutándolo sin parámetros. Los parámetros de TLINK son sensibles a mayúsculas y minúsculas, por lo que /T no es lo mismo que /t.   

Un enlazador (en inglés, linker) es un programa que toma los ficheros de código objeto generado en los primeros pasos del proceso de compilación, la información de todos los recursos necesarios (biblioteca), quita aquellos recursos que no necesita, y enlaza el código objeto con su(s)biblioteca con lo que finalmente produce un fichero ejecutable o una biblioteca.. En el caso de los programas enlazados dinámicamente, el enlace entre el programa ejecutable y las bibliotecas se realiza en tiempo de carga o ejecución del programa. 

EDITOR DE TEXTO PARA EL CÓDIGO FUENTE. 

Un editor de texto es un programa que permite crear y modificar archivos digitales compuestos únicamente por texto sin formato, conocidos comúnmente como archivos de texto ó texto plano. Se utiliza para escribir el código fuente de los programas considerando que al guardarse no conserve la extencion txt, ya que debe cambiarse por la extensión asm. En el caso de Windows se usa el Block de Notas de Microsoft, en linus podemos usar gedit o nano.   

PROCESO DE COMPILACIÓN CON TASM Y TLINK  

Para iniciar la compilación de los programas de ejemplo, debemos copiar los dos archivos ejecutables TASM.EXE y TLINK.EXE.

Con los archivos de código fuente y los ejecutables al iniciar el proceso de compilación, vamos al directorio y ejecutamos el comando que corresponda. 


CODIGOS DE EJEMPLO, COMPILADO Y LINKADO 


Creamos el primer ejemplo llamado saludo.asm 
  1. Entramos al símbolo del sistema (MS-DOS) nos direccionamos en donde se encuentra nuestra carpeta   
  2. Una vez situados en la dirección correcta, nos dirigimos a compilar nuestro programa.  
  3.  Para la compilación se debe ejecutar la siguiente instrucción:   tasm /zi saludo.asm  
  4. Una vez compilado nos aparecerá un reporte, el cual nos muestra si hay errores en nuestras líneas de código.   

Con esto se ah realizado la compilación de nuestro programa y está listo para ser ligado. Para linkar el programa. Esto lo haremos con la siguiente instrucción.   
tlink /v saludo 


El último paso es la ejecución del programa. Solo escribimos el nombre del programa, sin extensiones.   
Saludo   



Al ejecutarlo podemos comprobar que no se realiza acción alguna y que genera ciertos mensajes de advertencia, es porque el programa solo tiene la estructura básica y no estamos indicando que realice una acción determinada. 

Los caracteres especiales /v y /z tiene la siguiente finalidad. 







Lenguaje Ensamblador.

Lenguaje Ensamblador.

El término ensamblador (del inglés assembler) se refiere a un tipo de programa informático que se encarga de traducir un fichero fuente escrito en un lenguaje ensamblador, a un fichero objeto que contiene código máquina, ejecutable directamente por la máquina para la que se ha generado. 

El propósito para el que se crearon este tipo de aplicaciones es la de facilitar la escritura de programas, ya que escribir directamente en código binario, que es el único código entendible por la computadora, es en la práctica imposible. 

La evolución de los lenguajes de programación a partir del lenguaje ensamblador originó también la evolución de este programa ensamblador hacia lo que se conoce como programa compilador.

Historia.

El primer compilador fue escrito por Grace Hopper, en 1952 para el lenguaje de programación A-0. 

En 1950 John Backus dirigió una investigación en IBM sobre un lenguaje algebraico. 

En 1954 se empezó a desarrollar un lenguaje que permitía escribir fórmulas matemáticas de manera traducible por un ordenador; le llamaron FORTRAN (FORmulae TRANslator). 

Fue el primer lenguaje de alto nivel y se introdujo en 1957 para el uso de la computadora IBM modelo 704.

El primer compilador de FORTRAN tardó 18 años persona en realizarse y era muy sencillo.

El primer compilador autocontenido, es decir, capaz de compilar su propio código fuente fue el creado para Lisp por Hart y Levin en el MIT en 1962. Desde 1970 se ha convertido en una práctica común escribir el compilador en el mismo lenguaje que este compila, aunque Pascal y C han sido alternativas muy usadas.
Crear un compilador autocontenido genera un problema llamado bootstrapping, es decir el primer compilador creado para un lenguaje tiene que o bien ser compilado por un compilador escrito en otro lenguaje o bien compilado al ejecutar el compilador en un intérprete.

Componentes.

Los elementos básicos del lenguaje ensamblador son:
  • Etiquetas
  • Instrucciones
  • Operandos
  • Directivas
  • Comentarios

Etiquetas.

Una etiqueta es una palabra utilizada para designar alguna línea o sección del programa, se pueden utilizar para saltar de una parte hacia esa etiqueta.

Es importante que las etiquetas empiecen con una letra o con un guión bajo "_". La longitud de una etiqueta puede ser de hasta 32 caracteres y como ya se dijo se deben escribir en la primer columna.

Instrucciones.

Las instrucciones son las operaciones  que realiza el microcontrolador, así que estas ya están definidas para cada familia de  PIC.

MicrocontroladorPIC 

Los PIC son una familia de microcontroladores tipo RISC fabricados por Microchip Technology Inc. y derivados del PIC1650, originalmente desarrollado por la división de microelectrónica de General Instrument. El nombre actual no es un acrónimo. En realidad, el nombre completo es PICmicro, aunque generalmente se utiliza como Peripheral Interface Controller (controlador de interfaz periférico).




Operandos.

Son los elementos que emplea la instrucción que se está ejecutando. Usualmente los operandos son los registros, las variables o las constantes.

Directivas.

  • Las directivas son similares a las instrucciones, pero a diferencia de  estas las directivas son propias del lenguaje ensamblador e independientes del microcontrolador que se utilice. 
  • Las directivas representan algunas características del lenguaje ensamblador, se utilizan para especificar el procesador empleado así como la configuración de este, también para asignar locaciones de memoria.

Comentarios.

Los comentarios son las palabras, frases y oraciones que se pueden escribir en el código para hacer el programa más claro y legible, o solo para recordar. 

Los comentarios se pueden escribir en cualquier parte del código pero siempre deben empezar con punto y coma ";".

Software editores.

Un programador escribe el programa origen en  lenguaje ensamblador utilizando cualquier editor de textos o procesador de palabras que sea capaz de  producir una salida de texto en ASCII. Una vez que el código origen ha sido escrito, el archivo origen es  ensamblado mediante su procesamiento a través de algún ensamblador.

Software reglas de programación.

Para la programación se utiliza una cierta tabulación que se debe respetar, además utilizar una tabulación adecuada hace los programas más claros y le gibles. 

Las etiquetas 

Se escriben en la primer columna de cualquier línea, las instrucciones y directivas en la  segunda y por último, en la tercer columna, los operandos. 

Los comentarios 

Se pueden escribir en cualquier parte del programa.

Software ENS2001


Software MASM



Software TAST





Software MASM Y TLINK

El Turbo Assembler (TASM) un paquete ensamblador principalmente destinado a la plataforma del IBM PC y sus compatibles. 

El enlazador o linkador LINK permite convertir el código objeto generado por TASM en archivo ejecutable de tipo EXE*.

*empleando el ML de MASM 6.X se obtiene directamente el fichero EXE ya que invoca automáticamente al linkador.

Registros.

Se trata de una serie de "variables", que contienen información que puede ser cambiada.

REGISTROS IP Y CS.

El registro CS es una variable de un tamaño de dos bytes. Contiene el Segmento actual en que se encuentra el programa.


El registro IP es la variable, de dos bytes también, que contiene el Offset actual. Esto significa, el ordenador va interpretando las secuencias de bytes, pero necesita "algo" que le indique donde tiene que leer.

COMBINACION DE REGISTROS IP Y CS

La combinación CS:IP contiene la dirección en la que el ordenador está interpretando información en el momento. Indica la dirección de la próxima instrucción que se va a ejecutar.


El registro DS y el registro ES también sirven para guardar direcciones de Segmentos, y también son variables de dos bytes, pueden ser utilizados para por ejemplo mover datos en memoria, imprimir cadenas, etc. Son "punteros", que apuntan a cierta zona de memoria. El registro SS apunta a la pila, y el SP es el que contiene el offset de la pila.

Instrucciones.

Se pueden clasificar en los siguientes grupos:


  • De Transferencia. 
  • Aritméticos. 
  • Lógicos. 
  • De salto.
















Análisis Semántico

Análisis Semántico.

¿Que es la semántica?

Se refiere a los aspectos del significado, sentido o interpretación del significado de un determinado elemento, símbolo, palabra, expresión o representación formal.



Se trata de determinar el tipo de los resultados intermedios, comprobar que los argumentos que tiene un operador pertenecen al conjunto de los operadores posibles, y si son compatibles entre sí, etc. En definitiva, comprobará que el significado de lo que se va leyendo es válido.

El análisis semántico se realiza posteriormente al sintáctico y mucho más difícil de formalizar que éste.

La salida “teórica” de la fase de análisis semántico sería un árbol semántico.

¿Que es un árbol semántico?

Es una estructura jerárquica en la cual se registran las operaciones que implica u operan dentro del programa fuente.

En cada una de las ramas del  árbol semántico se registra el valor o significado que este debe tener, y el análisis semántico se encarga de terminar cual de los valores registrados en las ramas es aplicable.

Tabla de símbolos en esta fase.

Un compilador necesita guardar y usar la información de los objetos que se va encontrando en el texto fuente, como variables, etiquetas, declaraciones de tipos, etc.

Esta información se almacena en una estructura de datos interna conocida como tabla de símbolos.

El compilador debe desarrollar una serie de funciones relativas a la manipulación de esta tabla como consultar un elemento en ella, y consultar la información relacionada con un símbolo, etc.

Como se tiene que acceder mucho a la tabla de símbolos los accesos deben ser lo más rápidos posible para que la compilación sea eficiente.

Sistemas de tipo:

Es el conjunto de reglas que determinan el criterio para asignar expresiones de tipo a las diferentes partes del código fuente.
  • Tipo básico: entero, carácter, real, lógico 
  • Nombres de tipo 
  • Constructores de tipo: estructuras, uniones, objetos 
  • Apuntadores: referencias a tipos ◦ Funciones a=suma();
Chequeos de tipos (y otros)

Un compilador debe realizar una serie de chequeos estáticos, como chequeos de tipos:
  • Consistencia: unicidad, existencia, no-ciclicidad, ... 
  • Equivalencia y compatibilidad de tipos 
  • Inferencia de tipos (en valores) 
  • Sobrecarga de funciones y operadores
COMPROBACIONES SEMÁNTICAS TIPOS

Comprobaciones ESTÁTICAS. 
  • Las comprobaciones sintácticas y semánticas. 
Comprobaciones DINÁMICAS. 
  • Realizadas en tiempo de ejecución.
COMPROBACIONES SEMÁNTICAS TIPOS

Comprobaciones SEMÁNTICAS
 
De TIPO.
Verificación del tipo de los operando en las expresiones.

De FLUJO de CONTROL.

Verifica los puntos del programa de salida y entrada del control.


COMPROBACIONES SEMÁNTICAS


De UNICIDAD. 

Verifica la presencia de símbolos de forma única. (ejemplo: declarar un símbolo una sólo vez).

 Relación de NOMBRES. 

Un mismo nombre puede aparecer más de una vez.

Análisis Sintáctico.

Análisis Sintáctico.


  •  Determina  la  sintaxis,  o  estructura  de  un programa.
  •  Es un análisis a nivel de sentencias, y es mucho más complejo que el análisis léxico.
  •  Su función es tomar  el  programa  fuente  en  forma  de  tokens,  que  recibe  del analizador  léxico,  y  determinar  la  estructura  de  las sentencias del programa.
  •  Este proceso es similar a determinar la estructura de una frase

La tarea del AS es determinar la estructura sintáctica de un programa a partir de los tokens producidos por el AL. 
En resumen una función que toma como entrada la secuencia de tokens y salida el AS.

Secuencia de tokens <> árbol sintáctico

El árbol se define como estructura de datos dinámica, nodos, atributos, campos del atributo.
Manejo de errores, no solo mostrar mensaje sino recuperarse (inferir código corregido) y continuar el análisis, para encontrar tantos errores como sea posible.

Al proceso de reconocer la estructura del lenguaje fuente se conoce con el nombre de análisis sintáctico (parsing). 
 
Hay distintas clases de analizadores o reconocedores sintácticos, pero en general se clasifican en 2 grandes grupos: 
 
A.S. Ascendentes y A.S. Descendentes.

Tipos de Análisis Sintácticos

Análisis descendente: 
Partimos de la raíz del árbol (donde estará situado el símbolo inicial de la gramática) y se van aplicando reglas por la izquierda de forma que se obtiene una derivación por la izquierda de la cadena de entrada. 

Para decidir qué regla aplicar, se lee un token de la entrada.

Análisis ascendente: 
Partiendo de la cadena de entrada, se construye el árbol de análisis sintáctico empezando por las hojas (donde están los tokens) y se van creando nodos intermedios hasta llegar a la raíz (hasta el símbolo inicial), construyendo así el árbol de abajo a arriba. 

El recorrido del árbol se hará desde las hojas hasta la raíz.

La principal tarea del analizador sintáctico no es comprobar que la sintaxis del programa fuente sea correcta, sino construir una representación interna de ese programa y en el caso en que sea un programa incorrecto, dar un mensaje de error.

Función principal

Comprueba que el orden en que el analizador léxico le va entregando los tokens es válido. Si esto es así significará que la sucesión de símbolos que representan dichos tokens puede ser generada por la gramática correspondiente al lenguaje del código fuente.




Análisis Léxico.

Análisis Léxico y Díagramas de Transición.

  • Está constituido por todas las palabras y símbolos que lo componen. Para un lenguaje de programación la definición también es válida.
  • Lo constituyen todos los elementos individuales del lenguaje, denominados frecuentemente en inglés tokens.
¿Que es Token?

Son palabras reservadas del lenguaje, los símbolos que denotan los distintos tipos de operadores, identificadores (de variables, de funciones, de procedimientos, de tipos, etc.), separadores de sentencias y otros.

¿Que es Patrón?

  • Expresión regular que define el lenguaje.
  • Letra (Letra | Dígito)*
¿Que es Lexema?

  • Secuencia de caracteres que concuerda con un patrón.
  • Numero, carácter.

¿Que son Atributos?
  • Estructura de datos de cada token para almacenarse en la TS.
  • Depende del tipo de token.
  • [ID. Lexema, Tipo, Valor, Línea]

Un programa fuente es una serie de símbolos que representan las construcciones del lenguaje tales como variables, etiquetas, palabras reservadas, constantes, operadores, entre otros.

El programa fuente se trata inicialmente con el analizador léxico.

 Pasos del AL.

  • Identificar la colección de tokens.
  • Estructurar la colección de tokens.
  • Describir el lenguaje como expresiones regulares.



El análisis léxico es un análisis a nivel de caracteres, su misión es reconocer los componentes léxicos o tokens, enviando al analizador sintáctico.

Analizador léxico que reconozca los siguientes elementos: 
  • Números enteros 
  • Operadores aritméticos suma, resta, producto, división, incremento y decremento (+, - *, /, ++,--) 
  • Identificadores 
  •  WHILE
Especificación formal 
  1. Gramáticas Lineales:  Recursivas a izquierdas y Recursivas a derechas 
  2. Expresiones regulares .
  3. Autómatas Finitos (Diagramas de Transición).
  4. Tratar con la tabla de símbolos 
  5.  Generar tokens bajo demanda del analizador sintáctico 
  6.  Manejar el fichero fuente 
  7. Ignorar comentarios 
  8. Contabilizar posición de tokens 
  9. Preprocesar macros, constantes, includes…


lunes, 30 de mayo de 2016

Tabla de Simbolos

 Tabla de Símbolos.

Almacena todos los nombres declarados en el programa y sus atributos (tipo, valor, dirección, parámetros, etc).

Se usa en las distintas fases del compilador.

Estructura de datos.

Almacena información sobre:
  • Los identificadores.
  • Las palabras reservadas.
  • Las constantes.
Contiene una entrada para cada uno de los símbolos definidos en el programa fuente.

Sobre los identificadores, y opcionalmente sobre las palabras reservadas y las constantes.

Información sobre el lexema, tipo de datos, ámbito y dirección en memoria.

Por cada entrada en la tabla de símbolos habrá que guardar:
  • Lexema correspondiente.
  • Tipo.(depende de la implementación).
  • Ámbito.(depende de la implementación).
  • Dirección de memoria asignada.
  • Forma.(depende de la implementación).
¿Utilidad de la tabla de símbolos?

  • Analizador Léxico: Pasa en el token y la entrada de la TS creada.
  • Analizador Sintáctico y Semántico: busca el token y si no la encuentra crea una nueva entrada.

Datos que se almacenan:
Para un array:
  • Tipo de los elementos.
  • Número de elementos.
  • Limites inferior y superior.
Para una función:
  • Número de parámetros.
  • Tipo de los parámetros.
  • Forma de paso de parámetros.
  • Tipo de retorno.
Operaciones Principales.
  • Insertar: introduce un símbolo tras una declaración.
  • Buscar: recupera información asociada a un símbolo.
  • Eliminar: borra la información.
Ejemplo de Uso I.

Declaración previa al uso de variables:
  • En las declaraciones, inserción en la TS.
Aparición de una variable en una sentencia, búsqueda en la TS:
  • Si se encuentra Fue declarada.
  • Si no se encuentra Error de compilación.
Ejemplos de Uso II.

Acceso a una posición de un array:
  • Declaración > Inserción en la TS.
  • Acceso a un array > Búsqueda en la TS.
  1. Comprobación de tipo array.
  2. Comprobación acceso a una posición válida.
Tabla de Símbolos.


Ejemplo:



  • Analizador Lexicográfico: Inserta en TS cada id que detecta y si corresponde da error si ya existe.
  • Analizador Sintáctico: Inserta el tipo de id.
  • Analizador Semántico: Verifica que cada id sea declarado antes de usarlo y recupera el tipo de id.
  • Generación de Código Intermedio: recupera tipo y dirección del id.
  • Generación de Código: Inserta y recupera información sobre la memoria asignada.
Estructuras usadas para implementar una tabla de símbolos.
Lista
  1. Simple de implementar.
  2. Lenta cuando se trabaja con muchos identificadores.
Árbol
  1. Rápida.
  2. Consume más memoria.
  3. Es útil cuando hay muchas declaraciones.
Tabla de Hashing

  1. Rápida.
  2. Difícil de implementar.
  3. Se debe definir una función de hashing apropiada para evitar colisiones.

Operaciones sobre TS.
  • Búsqueda (lexema): entero;
  • Inserción (lexema, descriptor): boolean;
  • Obt_atributo (lexema, atributo): valor;
  • Eliminación (lexema): entero.
Manejo de palabra

Si el scanner diferencia entre un identificador y una palabra reservada, entonces devuelve al parser el código correspondiente. Aquí no se requiere el ingreso de la palabra clave en la TS.

Si el scanner no las diferencia de los identificadores:

  • Pueden almacenarse en una tabla separada.
  • Estar inicializadas al principio de la TS.
  • Una entrada, en TS para una palabra reservada.
Entrada en la TS.

Una primera desagregación de una entrada de la tabla de símbolos.

No todos los atributos se introducen a la vez, estos se completan conforme avanzan las etapas de compilación.

Parte Fija.


Parte Variante.

  • Depende del objeto computacional asociado con el identificador.
  • Variable Simple: la parte variante es vacía excepto cuando se admitan valores de inicialización.
  • Variable Estructurada (Arreglo).





Procedimiento o Función.


Operaciones sobre TS: Lenguajes estructurados a bloques.

Crean un ámbito, una visibilidad y un tiempo de vida para los identificadores.


Tareas que se deben realizar cuando se ingresa a un nuevo bloque:
  • Dar de alta un nuevo bloque.
  • Insertar cada identificador encontrado en dicho bloque.

Tareas realizadas cuando se finaliza el análisis de un bloque:
  • Eliminar cada identificador en el bloque.
  • Eliminar el bloque.
Operaciones sobre TS: Lenguajes Estructurados a Bloques.

Cuando se busque un identificador en la TS se debe retornar el último identificador insertado, es decir, el identificador declarado en el bloque actual, si en tal bloque no existe el identificador buscarlo en el bloque que lo contenga, y así sigue hasta encontrarlo. Si el identificador no se encuentra en ninguno de los bloques anidados entonces no existe.

Ejemplo:


Lectura obligatoria.

Capítulo 8 de “The Theory and Practice of Compiler Writing”, Tremblay& Sorenson. McGrawHill. 1985.