Contenido

25
NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍA MATERIA: COMPILADORES 1. COMPILADOR Un compilador no es más que un traductor, es decir, un programa que nos permite pasar información de un lenguaje a otro. Por ejemplo, un compilador de C nos permite traducir ficheros escritos en lenguaje C a un lenguaje legible para la máquina (ensambladora). En este proceso de compilación no siempre es directo. Esto quiere decir que nos permite que un lenguaje A lo queremos traducir a un lenguaje B, no siempre será recomendable traducir directamente de A a B, si no que puede ser conveniente usar un lenguaje intermedio (que llamaremos X) y entonces diseñaremos un traductor de A a X, y otro de X a B. En este caso, el primer traductor recibe el nombre de front-end mientras que el segundo se llama back-end. El lenguaje A es el lenguaje fuente y el lenguaje B es el lenguaje objeto o destino. 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, 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 los problemas de las memorias prácticamente resueltas, se puede hablar de un gran predominio de los compiladores frente a los intérpretes, aunque intérpretes como los incluidos a 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 ejecutan varias 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 de mensajes de error es más detallada. 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, para obtener un programa ejecutable a partir de un programa fuente en un lenguaje de alto nivel. Algunos de esos programas son preprocesados, el linker, el depurador y el ensamblador. El preprocesado se ocupa dependiendo del lenguaje de incluir ficheros, expandir macros, eliminar comentarios, y otras tareas similares. CISNERO, ADRIAN JUSTINIANI, ALIKI REINA DAVID VON CHONG, ROLANDO 1

Transcript of Contenido

Page 1: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

1. COMPILADOR

Un compilador no es más que un traductor, es decir, un programa que nos permite pasar información de un lenguaje a otro. Por ejemplo, un compilador de C nos permite traducir ficheros escritos en lenguaje C a un lenguaje legible para la máquina (ensambladora).

En este proceso de compilación no siempre es directo. Esto quiere decir que nos permite que un lenguaje A lo queremos traducir a un lenguaje B, no siempre será recomendable traducir directamente de A a B, si no que puede ser conveniente usar un lenguaje intermedio (que llamaremos X) y entonces diseñaremos un traductor de A a X, y otro de X a B. En este caso, el primer traductor recibe el nombre de front-end mientras que el segundo se llama back-end. El lenguaje A es el lenguaje fuente y el lenguaje B es el lenguaje objeto o destino.

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, 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 los problemas de las memorias prácticamente resueltas, se puede hablar de un gran predominio de los compiladores frente a los intérpretes, aunque intérpretes como los incluidos a 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 ejecutan varias 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 de

mensajes de error es más detallada.• 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, para obtener un programa ejecutable a partir de un programa fuente en un lenguaje de alto nivel. Algunos de esos programas son preprocesados, el linker, el depurador y el ensamblador. El preprocesado se ocupa dependiendo del lenguaje de incluir ficheros, expandir macros, eliminar comentarios, y otras tareas similares.

CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

1

Page 2: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

Los linker se encargan 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. Algunos se encargan de depurador permitiendo asi 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. CARACTERÍSTICAS DE LOS COMPILADOR

Generalmente un compilador se divide en dos partes:

* Front End: 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. Parte que suele ser independiente de las plataformas sistema operativo para el que funcionará.

* Back End: parte en donde se genera el código máquina exclusivo para una plataforma a partir de lo analizado en el front end.

Por lo general el resultado del back end no puede ser ejecutado directamente, se necesita pasar por un proceso de enlazado (linker).

Existen varios tipos de compiladores: Compiladores cruzados, Compiladores optimizadores, Compiladores de una sola pasada, Compiladores de varias pasadas, Compiladores JIT.

Para el uso de la informática como herramienta de ayuda a la medicina es una realidad en auge. Desde hace algún tiempo muchas de las actividades humanas se han basado en la repetición, en algunos cálculos y del mismo modo que se inventaron operaciones matemáticas básicas para simplificarlas, surgió la necesidad de mejorar las limitadas prestaciones que ofrece la mente del hombre para calcular, a medida que las diversas ciencias se hicieron más complejas.CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

2

Page 3: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

Las primeras aplicaciones desarrolladas fueron dirigidas a resolver tareas (task- oriented) centradas en ciertos servicios o departamentos, siendo sus típicos usuarios secretarias o técnicos empleados para la introducción de datos, usándose sobre todo con fines administrativos, análisis financieros, manejo de bases de datos, sistemas de información de laboratorios o servicios de radiología.

Estas aplicaciones han tenido un gran impacto desde el punto de vista administrativo o de organización, pero no están dirigidos a las tareas propiamente médicas, aunque han contribuido a reducir el tiempo dedicado a acceder a este tipo de datos.

Posteriormente el mayor beneficio para las actividades propiamente médica ha sido la posibilidad de acceder a la bibliografía médica de una forma rápida mediante la aparición de las bases de datos bibliográficos inicialmente en cederrón y actualmente a través de INTERNET y en los últimos años, se intenta realizar aplicaciones informáticas que vayan dirigidas a resolver problemas (problem-based), más cercanas a la práctica médica, pero encontramos algunos problemas basados fundamentalmente en la ausencia de comprensión de cual es el proceso que seguimos los médicos para tomar una decisión y en la forma de representar el conocimiento y el proceso de razonamiento dentro del ordenador.

En estos últimos años se han añadido nuevas aplicaciones informáticas a la medicina, como son las publicaciones electrónicas biomédicas, la telemedicina, impulsada con un gran auge de INTERNET y su World Wide Web y los registros informáticos de la historia clínica. Hemos agregado sobre todo en sistemas privados por el pago por servicio, que obliga a un gran detalle de las actuaciones médicas para identificar el costo de beneficio, precisando crear registros informáticos de alta calidad.

La telemedicina es quizá, la que más ventajas aporta y con la que se puede obtener reducción de costos, al poder establecer comunicación con lugares lejanos del mundo, gracias a INTERNET y a los satélites de comunicación, evitando desplazamientos innecesarios y comunicaciones rápidas entre médicos, otros miembros del sistema sanitario e incluso los propios pacientes.

En la informática se ha introducido una nueva dimensión en el pensamiento humano, haciendo reales los sueños. No obstante, las aplicaciones informáticas para el manejo clínico del paciente siguen estando en el campo de los proyectos, con honrosas excepciones, existiendo pocos sistemas que sean operativos de una forma generalizada.

Los avances en esta tecnología y en el desarrollo de redes de información van a permitir una reducción de costos y un aumento en la calidad del cuidado de nuestros pacientes. El cambio en la enseñanza de las ciencias médicas permitirá entender al ordenador como una importante herramienta de trabajo, que además permitirá cambiar la actual forma memorística e intuitiva de la actuación médica a una forma basada en una

CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

3

Page 4: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

estructura con una mayor base de conocimientos, un proceso analítico de los mismos y una mayor eficacia en la toma de decisiones.

El médico no solo quedará apoyado por el ordenador sino que se mantendrá liberado de sus tareas más repetitivas y tediosas, pasará a ser el eje sobre el que se apoye todo el soporte informático, al actuar como selector y controlador de los datos de entrada, creador de los protocolos y algoritmos que éste seguirá, interpretando, además, sus resultados y por lo tanto siendo el máximo responsable del sistema.

1.2. FASES DE LOS COMPILADOR

En el llamado análisis léxico, el compilador revisa y controla que las palabras estén bien escritas y pertenezcan a algún tipo de token definido dentro del lenguaje, como por ejemplo que sea algún tipo de palabra reservada, o si es el nombre de una variable que este escrita de acuerdo a las pautas definidas del lenguaje. En esta etapa se crea la tabla de símbolos, la cual contiene las variables y el tipo de dato al que pertenece, las constantes literales, el nombre de funciones y los argumentos que reciben.

El análisis semántico se encarga de revisar que cada agrupación o conjunto de token tenga sentido, y no sean muy absurdo. En esta etapa se reúne la información sobre los tipos para la fase posterior, en la otra etapa se utilizara la estructura jerárquica de la etapa anterior y así poder determinar los operadores, y operando de expresiones y preposiciones.

En el análisis sintáctico como su nombre lo indica se encarga de revisar que los tokens estén ubicados y agrupados de acuerdo a la definición del lenguaje. Dicho esto de otra manera, que los tokens pertenezcan a frases gramaticales validas, que el compilador utiliza para sintetizar la salida. Por lo general las frases gramaticales son representadas por estructuras jerárquicas, por medio de árboles de análisis sintáctico. En esta se completa la tabla de símbolos con la dimensión de los identificadores y los atributos necesarios.

Generación de código intermedio, aunque algunos compiladores no la tienen, es bueno saber que existen, en esta etapa se lleva el código del programa fuente a un código interno para poder trabajar más fácilmente sobre él. Esta representación interna debe tener dos propiedades, primero debe ser fácil de representar y segundo debe ser fácil de traducir al código objeto.

Optimización de código, se busca obtener el código más corto y rápido posible, utilizando distintos algoritmos de optimización.

Etapa de generación de código, se lleva el código intermedio final a código maquina o código objeto, que por lo general consiste en un código maquina re localizable o código ensamblador. Se selecciona las posiciones de memoria para los datos variables y se traduce cada una de las instrucciones intermedias a una secuencia de instrucciones de maquina puro.

CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

4

Page 5: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

La tabla de símbolos no es una etapa del proceso de compilación, sino que una tarea, una función que debe realizar el proceso de compilación. En ella se almacenan los identificadores que aparecen en el código fuente puro, como así también los atributos de los mismos, su tipo, su ámbito y en el caso de los procedimientos el número de argumentos el tipo del mismo. En otras palabras una tabla de símbolos es una estructura de datos, que contiene un registro por cada identificador, y sus atributos. La tabla de símbolo es accedida tanto para escritura como parar lectura por todas las etapas.

Los detectores de errores o manejador de errores, al igual que la tabla de símbolos no es una etapa del proceso de compilación, si no que es una función, muy importante, pues al ocurrir un error esta función debe tratar de alguna forma el error para así seguir con el proceso de compilación la mayoría de errores son detectados en las etapas de análisis léxico, análisis sintáctico, análisis semántico.

1.3.

ESTRUCTURACION DE LOS COMPILADORES

La estructura de un compilador, está dividida en cuatro grandes módulos, cada uno independiente del otro, se podría decir que un compilador está formado por cuatros módulos más a su vez.

El primero de ellos es el preprocesador, es el encargado de transformar el código fuente de entrada original en el código fuente puro. Es decir en expandir las macros,

CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

5

Page 6: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

incluir las librerías, realizar un preprocesado racional con la capacidad de enriquecer a un lenguaje antiguo con recursos más modernos, extender el lenguaje y todo aquello que en el código de entrada sea representativo de una abreviatura para facilitar la escritura del mismo.

En el segundo modulo encontramos compilación que recibe el código fuente puro, este es él modulo principal de un compilador, pues si ocurriera algún error en esta etapa el compilador no podría avanzar. En esta etapa se somete al código fuente puro de entrada a un análisis léxico gráfico, a un análisis sintáctico, a un análisis semántico, que construyen la tabla de símbolos, se genera un código intermedio al cual se optimiza para así poder producir un código de salida generalmente en algún lenguaje ensamblador.

Para este tercer modulo es el llamado modulo de ensamblado, este modulo no es ni más mi menos que otro compilador pues recibe un código fuente de entrada escrito en ensamblador, y produce otro código de salida, llamado código binario no enlazado. Si por un momento viéramos a este modulo como un programa independiente, veríamos que en este caso los términos programa compilador y proceso de compilación son los mismos.

Pues este modulo no es mas que un compilador, que en su interior realiza como su antecesor un análisis léxico gráfico, un análisis sintáctico, un análisis semántico, crea una tabla de símbolos, genera un código intermedio lo optimiza y produce un código de salida llamado código binario no enlazado, y a todo este conjunto de tares se los denomina proceso de compilación.

Como se puede ver este compilador (llamado ensamblador) a diferencia de los demás compiladores no realiza una expansión del código fuente original (código fuente de entrada), tiene solamente un proceso de compilación y por supuesto no enlaza el código fuente. Es un compilador que carece de los módulos de preprocesado y enlazado, y donde los módulos de compilación y ensamblado son los mismos.

CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

6

Page 7: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

El cuarto y ultimo modulo es el encargado de realizar el enlazado del código de fuente de entrada (código maquina re localizable) con las librerías que necesita, como así también de proveer al código de las rutinas necesarias para poder ejecutarse y cargarse a la hora de llamarlo para su ejecución, modifica las direcciones re localizables y ubica los datos en las posiciones apropiadas de la memoria.

Este ultimo modulo es el que produce como salida el código binario enlazado. Ya sea dinámico o estático, al decir dinámico se refiere a que el código producido utiliza librerías dinámicas (librerías ya cargadas en el sistema), esto implica que se obtendrá un código más corto y que se actualizara automáticamente si aparece alguna nueva versión de las librerías, mientras que el estático se refiere al echo que no se realiza enlace con ninguna librería y por lo tanto se obtendrá un código mas largo con una copia de las rutinas de librería que necesita.

2. ELEMENTOS DE UN COMPILADOR

Elementos primarios

Elemento Descripción

Elemento

<configuration>

Elemento raíz de cada archivo de configuración usado por las

aplicaciones de Common Language Runtime y .NET Framework.

<system.codedom>

(Elemento)

Especifica las opciones de configuración del compilador para los

proveedores de lenguaje disponibles.

Elemento <compilers> Contenedor de elementos de configuración del compilador; contiene

CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

7

Page 8: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

el cero o más elementos <compiler>.

Elementos secundarios

Elemento Descripción

<providerOption>

(Elemento)

Especifica los atributos de versión del compilador para un proveedor

de lenguaje.

2.1. TIPOS DE COMPILADORES

Esta taxonomía de los tipos de compiladores no es excluyente, por lo que puede haber compiladores que se adscriban a varias categorías:

Compiladores cruzados: generan código para un sistema distinto del que están funcionando.

Compiladores optimizadores: realizan cambios en el código para mejorar su eficiencia, pero manteniendo la funcionalidad del programa original.

Compiladores de una sola pasada: generan el código máquina a partir de una única lectura del código fuente.

Compiladores de varias pasadas: necesitan leer el código fuente varias veces antes de poder producir el código máquina.

Compiladores JIT (Just In Time): forman parte de un intérprete y compilan partes del código según se necesitan.

Pauta de creación de un compilador: En las primeras épocas de la informática, el software de los compiladores era considerado como uno de los más complejos existentes.

Los primeros compiladores se realizaron programándolos directamente en lenguaje máquina o en ensamblador. Una vez que se dispone de un compilador, se pueden escribir nuevas versiones del compilador (u otros compiladores distintos) en el lenguaje que compila ese compilador.

Actualmente existen herramientas que facilitan la tarea de escribir compiladores ó intérpretes informáticos. Estas herramientas permiten generar el esqueleto del analizador sintáctico a partir de una definición formal del lenguaje de partida, especificada normalmente mediante una gramática formal y barata, dejando únicamente al programador del compilador la tarea de programar las acciones semánticas asociadas

3. EMSAMBLADOR

CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

8

Page 9: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

El ensamblador 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.

Los lenguajes ensambladores fueron desarrollados hace muchos años atrás, cuando fueron referidos como lenguajes de programación de segunda generación. Por ejemplo, el SOAP (Symbolic Optimal Assembly Program) era un lenguaje ensamblador para el computador IBM 650. Los lenguajes ensambladores eliminaron mucha de la propensión a errores y del consumo de tiempo de la programación de los lenguajes de primera generación que se necesitaban con los primeros computadores, liberando a los programadores como recordar códigos numéricos y cálculo de direcciones.

Una vez fueron ampliamente usados para todo tipo de programación. Sin embargo, los microcomputadores se usaban en gran parte suplantado por los lenguajes de alto nivel, en la búsqueda de una mejorada productividad en programación. Hoy en día, aunque el lenguaje ensamblador es casi siempre manejado y generado por los compiladores, todavía se usa para la manipulación directa del hardware, acceso a instrucciones especializadas del procesador, o para resolver problemas de desempeño crítico. Los usos típicos son drivers de dispositivo, sistemas embebidos de bajo nivel, y sistemas de tiempo real.

Un gran número de programas han sido escritos enteramente en lenguaje ensamblador. Los sistemas operativos fueron casi exclusivamente escritos en lenguaje ensamblador hasta la aceptación amplia del lenguaje de programación C. También, muchas aplicaciones comerciales fueron escritas en lenguaje ensamblador, incluyendo una gran cantidad del software escrito por grandes corporaciones para mainframes de IBM. Los lenguajes COBOL y FORTRAN eventualmente desplazaron mucho de este trabajo, aunque un número de organizaciones grandes conservaran las infraestructuras de aplicaciones en lenguaje ensamblador.

La mayoría de los primeros microcomputadores confiaron en el lenguaje ensamblador codificado a mano, incluyendo la mayoría de los sistemas operativos y de las aplicaciones grandes. Esto era porque estos sistemas tenían limitaciones severas de recursos, impusieron idiosincráticas arquitecturas de memoria y de pantalla que proporcionaron servicios de sistema limitados con errores. Quizás más importante era la falta de compiladores de primera clase de lenguajes de alto nivel adecuados para el uso en el microcomputador.

En un contexto más comercial, las más grandes razones para usar el lenguaje ensamblador era hacer programas con mínimo tamaño, mínima sobrecarga, mayor velocidad y confiabilidad.

Los típicos ejemplos de programas grandes en lenguaje ensamblador de ese tiempo son los sistemas operativos IBM PC DOS y aplicaciones tempranas tales como la hoja de cálculo Lotus 1-2-3, y casi todos los juegos populares para la familia Atari 800 de computadores personales. La mayoría de los videojuegos de consola fueron escritos en ensamblador, incluyendo la mayoría de los juegos para la Mega Drive/Genesis y el Super Nintendo Entertainment System.

CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

9

Page 10: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

Según algunos insiders de la industria, el lenguaje ensamblador era el mejor lenguaje de programación a usar para obtener el mejor desempeño del Sega Saturn, una consola para la cual era notoriamente desafiante desarrollar y programar juegos. El popular juego de arcade NBA Jam es otro ejemplo. El ensamblador ha sido por largo trecho, el lenguaje de desarrollo primario en los computadores hogareños Commodore 64, Atari ST, así como el ZX Spectrum.

Esto fue así en gran parte porque los dialectos del BASIC en estos sistemas ofrecieron insuficiente velocidad de ejecución, así como insuficientes características para aprovechar completamente el hardware disponible. Algunos sistemas, más notablemente el Amigo, incluso tienen IDEs con características de depuración y macros altamente avanzados, tales como el freeware ASM-One assembler, comparable a las del Microsoft Visual Studio (el ASM-Uno precede al Microsoft Visual Studio).

El ensamblador para el VIC-20 fue escrito por Don French y publicado por French Silk. Con 1639 bytes de longitud, se cree que es el más pequeño ensamblador simbólico jamás escrito. El ensamblador soportaba el direccionamiento simbólico usual y la definición de cadenas de caracteres o cadenas hexadecimales. También permitía expresiones de direcciones que podían combinarse con las operaciones de adición, substracción, multiplicación, división, AND lógico, OR lógico, y exponenciación.

Han habido siempre debates sobre la utilidad y el desempeño del lenguaje ensamblador relativo a lenguajes de alto nivel. El lenguaje ensamblador tiene algunas especificaciones donde son importante. Pero, en general, los modernos compiladores de optimización para traducir lenguajes de alto nivel en el código que puede correr tan rápidamente como el lenguaje ensamblador escrito a mano, a pesar de los contra ejemplos que pueden ser encontrados. La complejidad de los procesadores modernos y del subsistema de memoria hace la optimización efectiva cada vez más difícil para los compiladores, así como para los programadores en ensamblador. Adicionalmente, y para la consternación de los amantes de la eficiencia, el desempeño cada vez mayor del procesador ha significado que la mayoría de los CPU estén desocupados la mayor parte del tiempo, con retardos causados por embotellamientos predecibles tales como operaciones de entrada/salida y paginación de memoria. Esto ha hecho la velocidad de ejecución cruda del código un problema para muchos programadores.

Hay algunas situaciones en las cuales los profesionales pudieran elegir utilizar el lenguaje ensamblador. Por ejemplo cuando:

• es requerido un ejecutable binario independiente (stand-alone), es decir uno que deba ejecutarse sin recursos a componentes de tiempo de ejecución o a bibliotecas asociadas con un lenguaje de alto nivel; ésta es quizás la situación más común. Son programas empotrados que solo almacenan una pequeña cantidad de memoria y el dispositivo está dirigido para hacer tareas para un simple propósito. Ejemplos consisten en teléfonos, sistemas de combustible e ignición para automóviles, sistemas de control del aire acondicionado, sistemas de seguridad, y sensores.

• interactuando directamente con el hardware, por ejemplo en drivers de dispositivo y manejadores de interrupción.

CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

10

Page 11: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

• usando instrucciones específicas del procesador no explotadas o disponibles por el compilador. Un ejemplo común es la instrucción de rotación bit wise en el núcleo de muchos algoritmos de cifrado.

• creando funciones vectorizadas para programas en lenguajes de alto nivel como C. En el lenguaje de alto nivel esto es a veces ayudado por funciones intrínsecas del compilador que mapean directamente a los mnemónicos del SIMD, pero sin embargo resulta en una conversión de ensamblador de uno a uno para un procesador de vector asociado.

• es requerida la optimización extrema, en un bucle interno en un algoritmo intensivo en el uso del procesador. Los programadores de juegos toman ventaja de las habilidades de las características del hardware en los sistemas, permitiendo a los juegos correr más rápidamente. También las grandes simulaciones científicas requieren algoritmos altamente optimizados, ej, álgebra lineal con BLAS o la transformada de coseno discreta la versión SIMD en ensamblador del x264, una biblioteca para codificar streams de video.

• un sistema con severas limitaciones de recursos un sistema empotrado debe ser codificado a mano para maximizar el uso de los limitados recursos; pero esto está llegando a ser menos común a medida que el precio del procesador decrece y el desempeño mejora.

• no existe ningún lenguaje de alto nivel, en un procesador nuevo o especializado.• escribiendo programas de tiempo real que necesitan sincronización y respuestas

precisas, tales como sistemas de navegación de vuelo, y equipo médico. En un sistema fly-by-wire, vuelo por mandos eléctricos, la telemetría debe ser interpretada y hay que actuar dentro de limitaciones estrictas de tiempo. Tales sistemas deben eliminar fuentes de retrasos impredecibles, que pueden ser creados para algunos lenguajes interpretados, recolección de basura automática, operaciones de paginación, o multitarea preventiva. Sin embargo, algunos lenguajes de alto nivel incorporan componentes de tiempo de ejecución e interfaces de sistema operativo que pueden introducir tales retrasos. Elegir el ensamblador o lenguajes de bajo nivel para tales sistemas da a los programadores mayor visibilidad y control sobre el proceso de los detalles.

• es requerido control total sobre el ambiente, en situaciones de seguridad extremadamente alta donde nada puede darse por sentado.

• se escriben virus de computadora, bootloaders, ciertos drivers de dispositivo, u otros elementos muy cerca del hardware o al sistema operativo de bajo nivel

• se escriben simuladores del conjunto de instrucciones para monitoreo, trazado y depuración de errores donde la sobrecarga adicional es mantenida al mínimo

• se hace ingeniería inversa en binarios existentes que pueden o no haber sido escritos originalmente en un lenguaje de alto nivel, por ejemplo al crackear la protección anticopia del software propietario.

• se hace ingeniería inversa y modificación de video juegos, también denominado ROM hacking, que es posible por medio de varios métodos. El más ampliamente implementado es alterando el código del programa a nivel de lenguaje ensamblador

• se escribe código automodificable, algo para lo que el lenguaje ensamblador se presta bien

• se escriben juegos y otros softwares para calculadoras gráficas• se escribe software compilador que genera código ensamblador, y por lo tanto los

desarrolladores deben ser programadores de lenguaje ensamblador.• se escriben algoritmos criptográficos que siempre deben tomar estrictamente el

mismo tiempo para ejecutar, previniendo ataques de tiempo.CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

11

Page 12: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

Sin embargo, el lenguaje ensamblador es todavía enseñado en la mayoría de los programas de ciencias de la computación e ingeniería electrónica. Aunque hoy en día, pocos programadores trabajan regularmente con el lenguaje ensamblador como una herramienta, los conceptos fundamentales continúan siendo muy importantes.

Tales tópicos fundamentales, como aritmética binaria, asignación de memoria, procesamiento del stack, codificación de conjunto de caracteres, procesamiento de interrupciones, y diseño de compiladores, serían duros de estudiar en detalle sin la comprensión de cómo el computador opera a nivel del hardware. Puesto que el comportamiento del computador es fundamentalmente definido por su conjunto de instrucciones, la manera lógica de aprender tales conceptos es estudiar un lenguaje ensamblador.

La mayoría de los computadores modernos tienen un conjunto de instrucciones similares. Por lo tanto, estudiar un solo lenguaje ensamblador es suficiente para aprender: i) los conceptos básicos; ii) reconocer situaciones donde el uso de lenguaje ensamblador puede ser apropiado; y iii) ver cómo el código ejecutable eficiente puede ser creado por los lenguajes de alto nivel18

El lenguaje ensamblador hard-coded es típicamente usado en el ROM de arranque del sistema (BIOS en los sistemas compatible IBM PC). Este código de bajo nivel es usado, entre otras cosas, para inicializar y probar el hardware del sistema antes de cargar el sistema operativo, y está almacenado en el ROM. Una vez que ha tomado lugar un cierto nivel de inicialización del hardware, la ejecución se transfiere a otro código, típicamente escrito en lenguajes de alto nivel; pero el código corriendo inmediatamente después de que es aplicada la energía usualmente está escrito en lenguaje ensamblador. Lo mismo es cierto para los boot loaders.

Muchos compiladores traducen lenguajes de alto nivel a lenguaje ensamblador primero, antes de la compilación completa, permitiendo que el código en ensamblador sea visto para propósitos de depuración y optimización. Lenguajes de relativo bajo nivel, como C, con frecuencia proveen sintaxis especial para empotrar lenguaje ensamblador en cada plataforma de hardware. El código portable del sistema entonces puede usar estos componentes específicos a un procesador a través de una interface uniforme.

El lenguaje ensamblador también es valioso en ingeniería inversa, puesto que muchos programas solamente son distribuidos en una forma de código de máquina. El código de máquina es usualmente fácil de trasladar hacia lenguaje ensamblador para luego ser cuidadosamente examinado en esta forma, pero es muy difícil de trasladar hacia un lenguaje de alto nivel. Herramientas como Interactive Disassembler, hacen uso extenso del desensamblador para tales propósitos.

Un nicho que hace uso del lenguaje ensamblador es el demoscene. Ciertas competiciones requieren a los concursantes restringir sus creaciones a un muy pequeño tamaño 256 bytes, 1 KB, 4 KB ó 64 KB, y el lenguaje ensamblador es el lenguaje de preferencia para alcanzar este objetivo.

Cuando los recursos son una preocupación, es una necesidad la codificación en ensamblador, especialmente en sistemas constreñidos por el procesamiento del CPU, como los primeros modelos del Amiga, y el Commodore 64. El código optimizado en

CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

12

Page 13: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

ensamblador es escrito "a mano" por los programadores en un intento de minimizar el número de ciclos de CPU usados. Las limitaciones del CPU son tan grandes que cada ciclo cuenta. Usar tales métodos ha habilitado, a sistemas como el Commodore 64, para producir gráficos en 3D en tiempo real con efectos avanzados, una hazaña que puede ser considerada improbable o incluso imposible para un sistema con un procesador de 0.99 MHz.

4. ÁRBOLES PARTE SEMANTICAS.

Hemos visto que las deducciones pueden hacerse atendiendo a los problemas de derivación, realizándose esta última a través de la aplicación de las reglas básicas o derivadas.

Pero también podemos utilizar otro criterio: el semántico, según el cual, y suponiendo que la deducción sea correcta, no podemos obtener una conclusión falsa de premisas verdaderas. La semántica atiende por una parte al hecho al que se refiere la proposición y, por otra parte, a su valor de verdad.

El método de las tablas semánticas supone una búsqueda de contraejemplos que invaliden el argumento. Es una especie de reducción al absurdo, en la que se supone la verdad de la negación de la conclusión y, a partir de ella, se llega a una contradicción.

CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

13

Page 14: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

14

Page 15: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

4.1. COMO SE IDENTIFICAN

El analizador semántico verificara que en este caso cada operador tenga los operadores permitidos.

=/ \id1 +/ \id2 +/ \id3 tipo_ent|10

5. GRAMATICA BNF

Una especificación de BNF es un sistema de reglas de derivación, escrito como:

<simbolo> ::= <expresión con símbolos>

donde <símbolo> es un no terminal, y la expresión consiste en secuencias de símbolos o secuencias separadas por la barra vertical, '|', indicando una opción, el conjunto es una posible substitución para el símbolo a la izquierda. Los símbolos que nunca aparecen en un lado izquierdo son terminales.

Ejemplo

Como ejemplo, considere este BNF para una dirección postal de los EE.UU.

<dirección postal> ::= <nombre> <dirección> <apartado postal><personal> ::= <primer nombre> | <inicial> "."<nombre> ::= <personal> <apellido> [<trato>] <EOL> | <personal> <nombre><dirección> ::= [<dpto>] <número de la casa> <nombre de la calle> <EOL><apartado postal> ::= <ciudad> "," <código estado> <código postal> <EOL>

Esto se traduce a español como:

• Una dirección postal consiste en un nombre, seguido por una dirección, seguida por un apartado postal.

• Una parte "personal" consiste en un nombre o una inicial seguido(a) por un punto.• Un nombre consiste de: una parte personal seguida por un apellido seguido

opcionalmente por una jerarquía o el trato que se la da a la persona (Jr., Sr., o número dinástico) y un salto de línea (end-of-line), o bien una parte personal seguida por un nombre (esta regla ilustra el uso de la repetición en BNFs, cubriendo el caso de la gente que utiliza múltiples nombres y los nombres medios o las iniciales).

CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

15

Page 16: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

• Una dirección consiste de una especificación opcional del departamento, seguido de un número de casa, seguido por el nombre de la calle, seguido por un salto de línea (end-of-line).

• Un apartado postal consiste de una ciudad, seguida por una coma, seguida por un código del estado (recuerde que es un ejemplo que ocurre en EE.UU.), seguido por un código postal y este seguido por un salto de línea (end-of-line).

Observe que muchas cosas (tales como el formato de una parte personal, de una especificación del apartamento, o código postal) están dejadas sin especificar aquí. Si es necesario, pueden ser descritas usando reglas adicionales de BNF, o dejadas como abstracción si es inaplicable para el propósito actual.

Otros ejemplos

Bastante interesante, la sintaxis de BNF se puede representar en BNF como sigue:

<syntax> ::= <rule> [<syntax>] <rule> ::= <whitespace> "<" <rule-name> ">" <whitespace> "::=" <expression> <whitespace> <line-end> <expression> ::= <whitespace> <or-expression> <or-expression> ::= <whitespace> <list-expression> [ "|" <or-expression> ] <list-expression> ::= <whitespace> ("<" <rule-name> ">" | <QUOTE> <text> <QUOTE> | "(" <expression> ")" | "[" <expression> "]") [<list-expression>] <whitespace> ::= [" " <whitespace>] <line-end> ::= [<whitespace>] <EOL> [<line-end>]

Esto asume que no hay Whitespace necesario para la interpretación apropiada de la regla. El <QUOTE> se presume para ser el carácter ", y el <EOL> para ser el fin de línea apropiado especificado (en ASCII, retorno de carro o línea nueva, dependiendo del sistema operativo). El <rule-name> y el <text> deben ser substituidos con nombre/etiqueta o el texto literal de una regla declarada, respectivamente.

Hay muchas variantes y extensiones de BNF, posiblemente conteniendo algunos o todos los comodines de expresiones regulares como un "*" o "+". El Extended Backus-Naur form (EBNF) es una variante común. De hecho el ejemplo anterior no es la forma pura inventada para el informe del ALGOL 60. La notación de los corchetes "[ ]" fue introducida algunos años más tarde en la definición de PL/I de la IBM pero ahora se reconoce universal. La ABNF es otra extensión usada comúnmente para describir protocolos del IETF.

Las expresiones gramaticales de analizadores sintácticos construidas en BNF y las notaciones de expresión regular para formar una clase alternativa de la gramática formal, que es esencialmente analítica más que generativa en carácter.

Muchas especificaciones de BNF disponibles en línea tienen como propósito ser legibles a simple vista y no son especificaciones formales. Estas incluyen con frecuencia algunas de estas reglas sintácticas y extensiones:

CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

16

Page 17: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

• Elementos opcionales son presentados entre paréntesis cuadrados. Por ejemplo [<elemento-x>]

• Los elementos que se repiten 0 o más veces son presentados entre paréntesis de llave o terminados con un asterisco. Por ejemplo <palabra> ::= <letra> {<letra>}

• Los elementos que se repiten 1 o más veces son terminados con un '+'• Los terminales pueden aparecer en negrillas y los no-terminales en texto normal

en lugar de utilizar itálicas o paréntesis de ángulo• Alternativas opcionales son separadas por el símbolo '|'

Cuando se requiere agrupar varios elementos, se hace con paréntesis simple

5.1. SU DEFINICION

La notación de Backus-Naur, también conocida por sus denominaciones inglesas Backus-Naur form (BNF), Backus-Naur formalism o Backus normal form, es una metasintaxis usada para expresar gramáticas libres de contexto: es decir, una manera formal de describir lenguajes formales.

El BNF se utiliza extensamente como notación para las gramáticas de los lenguajes de programación de la computadora, de los sistemas de comando y de los protocolos de comunicación, así como una notación para representar partes de las gramáticas de la lengua natural (por ejemplo, el metro en la poesía de Venpa). La mayoría de los libros de textos para la teoría o la semántica del lenguaje de programación documentan el lenguaje de programación en BNF.

Algunas variantes, tales como la Augmented Backus-Naur form (ABNF) y la Extended Backus–Naur Form (EBNF), tienen su propia documentación.

Con la aparición de la notación BNF - desarrollada en primer lugar por Backus en 1960 cuando trabajaba en un borrador del ALGOL 60, modificada en 1963 por Naur y formalizada por Knuth en 1964 - se tiene una guía para el desarrollo del análisis sintáctico. Los diversos métodos de parsers ascendentes y descendentes se desarrollan durante la década de los 60. En 1959, Sheridan describe un método de parsing de FORTRAN que introducía paréntesis adicionales alrededor de los operandos para ser capaz de analizar las expresiones. Más adelante, Floyd introduce la técnica de la precedencia de operador y el uso de las funciones de precedencia.

A mitad de la década de los 60, Knuth define las gramáticas LR y describe la construcción de una tabla canónica de parser LR. Por otra parte, el uso por primera vez de un parsing descendente recursivo tuvo lugar en el año 1961. En el año 1968 se estudian y definen las gramáticas LL así como los parsers predictivos. También se estudia la eliminación de la recursión a la izquierda de producciones que contienen acciones semánticas sin afectar a los valores de los atributos.

En los primeros años de la década de los 70, se describen los métodos SLR y LALR de parser LR. Debido a su sencillez y a su capacidad de análisis para una gran variedad de lenguajes, la técnica de parsing LR va a ser la elegida para los generadores automáticos de parsers. A mediados de los 70, Johnson crea el generador

CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

17

Page 18: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

de analizadores sintácticos YACC para funcionar bajo un entorno UNIX . Junto al análisis sintáctico, también se fue desarrollando el análisis semántico.

La idea de transcribir la estructura del lenguaje con reglas de reescritura se remontan cuando menos al trabajo del gramático indio Panini (hacia el 460 a. C. ), que la utilizó en su descripción de la estructura de palabras del idioma sánscrito (algunos incluso han sugerido renombrar BNF a Forma Panini-Backus). Lingüïstas estadounidenses como Leonard Bloomfield y Zellig Harris llevaron esta idea un paso más adelante al tratar de formalizar el lenguaje y su estudio en términos de definiciones formales y procedimientos (1920-1960).

Noam Chomsky, maestro de lingüística de alumnos de teoría de la información del MIT, combinó la lingüística y las matemáticas, tomando esencialmente el formalismo de Axel Thue como la base de su descripción de la sintaxis del lenguaje natural. También introdujo una clara distinción entre reglas generativas (de la gramática libre de contexto) y reglas transformativas (1956).

John Backus, un diseñanor de lenguajes de programación de IBM, adoptó las reglas generativas de Chomsky para describir la sintaxis del nuevo lenguaje de programación IAL, conocido en la actualidad como ALGOL 58 (1959), presentando en el primer Congreso de Computación Mundial (World Computer Congress) el artículo "The syntax and semantics of the proposed international algebraic language of the Zurich ACM-GAMM Conference".

Peter Naur, en su reporte sobre ALGOL 60 de 1963, identificó la notación de Backus como la Forma Normal de Backus (Backus Normal Form), y la simplificó para usar un conjunto de símbolos menor, pero a sugerencia de Donald Knuth, su apellido fue agregado en reconocimiento a su contribución, reemplazando la palabra "Normal" por Naur, dado que no se trata de una forma normal en ningún sentido, a diferencia, por ejemplo de la Forma Normal de Chomsky.

6. LAS MAQUINAS DE TURING

Una máquina de Turing (MT) es un modelo computacional que realiza una lectura/escritura de manera automática sobre una entrada llamada cinta, generando una salida en esta misma.

Este modelo está formado por un alfabeto de entrada y uno de salida, un símbolo especial llamado blanco (normalmente b, Δ o 0), un conjunto de estados finitos y un conjunto de transiciones entre dichos estados. Su funcionamiento se basa en una función de transición, que recibe un estado inicial y una cadena de caracteres (la cinta, la cual puede ser infinita) pertenecientes al alfabeto de entrada.

La máquina va leyendo una celda de la cinta en cada paso, borrando el símbolo en el que se encuentra posicionado su cabezal y escribiendo un nuevo símbolo perteneciente al alfabeto de salida, para luego desplazar el cabezal a la izquierda o a la derecha (solo una celda a la vez). Esto se repite según se indique en la función de transición, para finalmente detenerse en un estado final o de aceptación, representando así la salida.

CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

18

Page 19: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

La entrada de una máquina de Turing viene determinada por el estado actual y el símbolo leído, un par (estado, símbolo), siendo el cambio de estado, la escritura de un nuevo símbolo y el movimiento del cabezal, las acciones a tomar en función de una entrada. En el caso de que para cada par (estado, símbolo) posible exista a lo sumo una posibilidad de ejecución, se dirá que es una máquina de Turing determinista, mientras que en el caso de que exista al menos un par (estado, símbolo) con más de una posible combinación de actuaciones se dirá que se trata de una máquina de Turing no determinista.

La función de transición δ en el caso no determinista, queda definida como sigue:

¿Cómo sabe una máquina no determinista qué acción tomar de las varias posibles? Hay dos formas de verlo: una es decir que la máquina es "el mejor adivino posible", esto es, que siempre elige la transición que finalmente la llevará a un estado final de aceptación. La otra es imaginarse que la máquina se "clona", bifurcándose en varias copias, cada una de las cuales sigue una de las posibles transiciones. Mientras que una máquina determinista sigue un único "camino computacional", una máquina no determinista tiene un "árbol computacional". Si cualquiera de las ramas del árbol finaliza en un estado de aceptación, se dice que la máquina acepta la entrada.

La capacidad de cómputo de ambas versiones es equivalente; se puede demostrar que dada una máquina de Turing no determinista existe otra máquina de Turing determinista equivalente, en el sentido de que reconoce el mismo lenguaje, y viceversa. No obstante, la velocidad de ejecución de ambos formalismos no es la misma, pues si una máquina no determinista M reconoce una cierta palabra de tamaño

n en un tiempo , la máquina determinista equivalente reconocerá la palabra en

un tiempo . Es decir, el no determinismo permitirá reducir la complejidad de la solución de los problemas, permitiendo resolver, por ejemplo, problemas de complejidad exponencial en un tiempo polinómico.

Una máquina de Turing con una sola cinta puede definirse como una 7-tupla

donde:

CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

19

Page 20: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

• es un conjunto finito de estados.• es un conjunto finito de símbolos distinto del espacio en blanco, denominado

alfabeto de máquina o de entrada.• es un conjunto finito de símbolos de cinta, denominado alfabeto de cinta (

).

• es el estado inicial.• es un símbolo denominado blanco, y es el único símbolo que se puede

repetir un número infinito de veces.

• es el conjunto de estados finales de aceptación.

• es una función parcial denominada función de transición, donde es un movimiento a la izquierda y es el movimiento a la derecha.

Existen en la literatura un abundante número de definiciones alternativas, pero todas ellas tienen el mismo poder computacional, por ejemplo se puede añadir el símbolo como símbolo de "no movimiento" en un paso de cómputo.

7. ANALISIS SINTACTICO.

Como ya sabemos la sintaxis en lógica es la forma correcta de escribir una fórmula

y la semántica es lo que significa. Como en lógica solamente tenemos dos valores una

fórmula solamente puede ser verdadera o falsa. Para determinar su valor seguimos las

reglas simples que dimos en las definiciones básicas de acuerdo a su tabla de verdad.

Esto lo hacemos mediante interpretaciones. Una interpretación de una fórmula es un

conjunto de valores que se les asignan a sus proposiciones atómicas.

Al interpretar una fórmula lo que finalmente vamos a obtener es un valor de

verdad, bien sea verdadero o falso. Pero para poder encontrarlo muchas veces el proceso

en laborioso porque puede estar formada por varias proposiciones atómicas.

Primeramente se le asignan valores de verdad a los átomos y se puede encontrar el valor

de la expresión.

Si deseamos hacerlo en general, debemos analizar todas las posibilidades, esto se

puede hacer construyendo una tabla de verdad. Para fines prácticos cuando se tienen

varios átomos las tablas de verdad no resultan prácticas por lo que analizaremos

solamente expresiones con tres átomos como máximo.

Por supuesto que se puede construir una tabla para un número mayor de átomos,

pero notemos que por cada átomo que se aumente el número de renglones se duplica.

CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

20

Page 21: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

Esto es, para un átomos son dos renglones, para dos átomos son cuatro, para tres

átomos son ocho, para cuatro dieciséis, etc.

Algoritmo para construir una tabla de verdad de una fórmula en lógica de

proposiciones.

Escribir la fórmula con un número arriba de cada operador que indique su

jerarquía. Se escriben los enteros positivos en orden, donde el número 1 corresponde al

operador de mayor jerarquía. Cuando dos operadores tengan la misma jerarquía, se le

asigna el número menor al de la izquierda.

Construir el árbol sintáctico empezando con la fórmula en la raíz y utilizando en

cada caso el operador de menor jerarquía. O sea, del número mayor al menor.

Numerar las ramas del árbol en forma secuencial empezando por las hojas hacia

la raíz, con la única condición de que una rama se puede numerar hasta que estén

numerados los hijos. Para empezar con la numeración de las hojas es buena idea hacerlo

en orden alfabético, así todos obtienen los renglones de la tabla en el mismo orden para

poder comparar resultados.

Escribir los encabezados de la tabla las fórmulas siguiendo la numeración que se

le dió a las ramas en el árbol sintáctico.

Al asignarle a los átomos, las hojas del árbol, todos los posibles valores de verdad

de acuerdo al orden establecido. Por supuesto que el orden es arbitrario, pero como el

número de permutaciones es n!, conviene establecer un orden para poder comparar

resultados fácilmente.

Asignar valor de verdad a cada una de las columnas restantes de acuerdo al

operador indicado en el árbol sintáctico utilizando la tabla de verdad correspondiente,

conviene aprenderse de memoria las tablas de los operadores, al principio pueden tener

un resumen con todas las tablas mientras se memorizan.

La última columna, correspondiente a la fórmula original, es la que indica los

valores de verdad posibles de la fórmula para cada caso.

Ejemplo. Construya la tabla de verdad de las siguientes expresiones lógicas:

i) (p → ¬q) v (¬p v r)

ii) p → (q ^ r)CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

21

Page 22: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

iii) (p → ¬ r) ↔ (q v p)

iv) ¬(p ¬ q) → ¬ r

v) (¬p ^ q) → ¬(q v ¬r)

Solución:

i) Seguimos los pasos del algoritmo con la fórmula (p → ¬q) v (¬p v r)

1. Vemos que los operadores de los paréntesis tienen mayor jerarquía, empezamos por el

paréntesis izquierdo por lo que la fórmula con jerarquías marcadas sería:

7.1. LIMITACION

El análisis semántico toma su nombre por requerir información relativa al significado del lenguaje, fuera del alcance del análisis sintáctico.

Mediante el empleo de gramáticas sensibles al contexto tipo 1 se podrían comprobar características del lenguaje. Ejemplo: la utilización de una variable requiere que esté declarada previamente.

Un autómata de tipo 1 es complejo de implementar e ineficiente.

Solución: Análisis semántico a partir de gramáticas y autómatas de tipo 2 sintáctico e implementación de reglas semánticas del lenguaje.

Se emplean estructuras de datos auxiliares como las tablas de símbolos.

El análisis semántico realiza todas las comprobaciones del lenguaje necesarias y no llevadas a cabo por el sintáctico

7.2. COMO SE UTILIZA

El analizador sintáctico impone una estructura jerárquica a la cadena de componentes léxicos, generada por el analizador léxico, que es representada en forma de un árbol sintáctico.

=/ \id1 +/ \id2 +/ \id3 10

CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

22

Page 23: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

7.3. DESCENDENTE Y ASCENDENTE

El estudio de gramáticas atribuidas se basa en la distinción de atributos heredados y sintetizados.

Determinará cómo podremos implementarlas.

Sintetizados: se calculan ascendentemente en el árbol sintáctico.Heredados: cálculo descendente.

8. ANALISIS LEXICO

Analizador léxico (scanner): lee la secuencia de caracteres del programa fuente, carácter a carácter, y los agrupa para formar unidades con significado propio, los componentes léxicos (tokens en ingles). Estos componentes léxicos representan: palabras reservadas: if, while, do, . . .identificadores: asociados a variables, nombres de funciones, tipos definidos por el usuario, etiquetas,... Por ejemplo: posición, velocidad, tiempo, . . . operadores: = * + - / == > < & ! = . . . símbolos especiales: ; ( ) [ ] f g ... constantes numéricas: literales que representan valores enteros, en coma dotante, etc, 982, 0xF678, -83.2E+2,... constantes de caracteres: literales que representan cadenas concretas de caracteres, \hola mundo",...

El analizador léxico opera bajo petición del analizador sintáctico devolviendo un componente léxico conforme el analizador sintáctico lo va necesitando para avanzar en la gramática. Los componentes léxicos son los símbolos terminales de la gramática.

Suele implementarse como una subrutina del analizador sintáctico. Cuando recibe la orden obtiene el siguiente componente léxico, el analizador léxico lee los caracteres de entrada hasta identificar el siguiente componente lexico.analizador

El analizador léxico lee los caracteres del programa fuente, y verifica que correspondan a una secuencia lógica (identificador, palabra reservada etc.). Esta

CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

23

Page 24: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

secuencia de caracteres recibe el nombre componente léxico o lexema. En este caso el analizador léxico verifica si el identificador id1 (nombre interno para "suma") encontrado se halla en la tabla de símbolos, si no esta produce un error porque todavía no fue declarado, si la preposición hubiese sido la declaración del identificador "suma" en lenguajes C, C++ (int suma;) el analizador léxico agregaría un identificador en la tabla de símbolos, y así sucesivamente con todos los componentes léxicos que aparezcan.id1= id2+ id3 * 10

8.1. BUFFER DE ENTRADA

El proceso de lectura de los caracteres de la entrada y formar los componentes léxicos es lo mas costoso en tiempo en el proceso de traducción. Es importante implementarlo eficientemente.

Se utiliza un buffer dividido en dos mitades de tamaño N caracteres, donde N es un bloque de disco (1024, 4096). Se leen N caracteres de la entrada en cada mitad del buffer con una única orden de lectura. Se mantienen dos apuntadores. Uno marca el inicio del lexema y el otro el carácter actual que se mueve hasta encontrar una subcadena que corresponde con un patrón. Una vez reconocido un componente léxico ambos apuntadores se colocan en la misma posición y justo detrás del lexema reconocido.buffer de entradaif avanza est´a final primera mitad then recargar segunda mitad; avanza = avanza+1;else if avanza est´a final segunda mitad then recargar primera mitad; pasar avanza a principio primera mitad;else avanza = avanza+1;

8.2. LAS EXPRESIONES REGULARES

Expresiones Regulares:

Los componentes léxicos se especifican haciendo uso de expresiones regulares. Además de las tres operaciones básicas: concatenación, repetición (*) y alternativas (j) vamos a usar los siguientes meta símbolos:

Una o mas repeticiones +r+ indica una o mas repeticiones de r(0j1)+ = (0j1)(0j1)*Cualquier carácter..*b.* indica cualquier cadena que contiene una letra bUn rango de caracteres [ ] (clase)[a-z] indica cualquier carácter entre la a y z minúsculas[a-zA-Z] indica cualquier letra del abecedario minúscula o mayúscula[0-9] indica cualquier digito de 0 a 9[abc] indica ajbjc

Cualquier caracter excepto un conjunto dado ~CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

24

Page 25: Contenido

NIVERSIDAD METROPOLITANA DE EDUCACION, CIENCIA Y TECNOLOGÍAMATERIA: COMPILADORES

~ (ajb) indica cualquier caracter que no sea una a o bOpcionalidad ?r? indica que la expresion r puede aparecer o no. En el caso deque aparezca solo lo haria una vez.Cuando queremos usar estos simbolos con su significado ten-emos que usar la barra de escape, [an-z] significar a cualquier letraque sea a, guion o z.Algunos ejemplos:Numerosnat = [0-9]+signedNat = ( + j -)? natnumber = signedNat(‘‘.’’nat)? (E signedNat)?Identi¯cadoresletter = [a-zA-Z]digit = [0-9]

8.3. LAS EXPRESIONES DE MAQUINAS FINITAS.

Los AFD se pueden utilizar para reconocer las expresiones regulares asociadas a los componentes léxicos.

Identificadores

identifier = letter (letter j digit)*Números naturales y realesnat = [0-9]+signedNat = (-)? natnumber = signedNat(‘‘.’’nat)? (E signedNat)?

CISNERO, ADRIANJUSTINIANI, ALIKIREINA DAVIDVON CHONG, ROLANDO

25