Antología Lenguajes Y Autómatas

37
INSTITUTO TECNOLOGICO SUPERIOR DE ZONGOLICA LENGUAJES Y AUTOMATAS II LSC. RAFAEL JUAN CORDOBA DE LA LLAVE MAYO 2014

description

LYA

Transcript of Antología Lenguajes Y Autómatas

Page 1: Antología Lenguajes Y Autómatas

INSTITUTO TECNOLOGICO SUPERIOR DE ZONGOLICA

LENGUAJES Y AUTOMATAS II

LSC. RAFAEL JUAN CORDOBA DE LA LLAVE

MAYO 2014

Page 2: Antología Lenguajes Y Autómatas

I N T R O D U C C I O N

El desarrollo de software se puede dividir en 2 grandes categorías. Elsoftware comercial y el software científico. La presente materia proporciona lasbases para crear software científico. Es común pensar que el estudiante normalnunca tendrá acceso a desarrollar software científico, sin embargo, esto es unerror ya que cada día las necesidades se van ampliando y todo va siendo másaccesible. Tenemos el clásico ejemplo de la robótica. Actualmente ya hay tiendasdonde venden accesorios para hacer un pequeño robot de juguete. Eso antes nose veía y ahora ya es común.Por lo mismo, es importante proporcionarle al alumno las bases para que él seintroduzca con profundidad en el mundo de los compiladores. Esta materia abrehorizontes impresionantes ya que se conoce a fondo las etapas por las queatraviesa la creación de un lenguaje de computación. Desde la etapa léxica hastala etapa de generación de código, el estudiante debe profundizar enconocimientos que colindan con la parte electrónica de la computadora, ellenguaje ensamblador, el lenguaje máquina.

Esta materia es una aventura racional. Algunos pensarán que es un tormentocerebral, pero los inteligentes sabrán apreciar todas las competencias que sedesarrollan en esta materia.

Cabe mencionar que esta materia es la 2ª. Parte de la materia Lenguajes yautómatas, por lo tanto se debe dedicar cierto tiempo a dar un repaso práctico a la1ª. Parte de la materia que consistió en las 2 primeras fases de los compiladores:fase léxica y fase sintáctica.Si no se da este repaso se corre el peligro de que el alumno no entienda éstasegunda parte ya que van muy ligadas.Es muy recomendable utilizar un compilador didáctico. Se recomiendaampliamente el compilador desarrollado por Kenneth Louden. En la bibliografía alfinal de este documento se encuentra con la referencia número 3 y número 12.Esto debido a que el alumno debe conocer un compilador ya hecho para asíentender al 100% todos los conceptos.

P R O P O S I T O Y C O N T E N I D O

En esta asignatura se debe desarrollar el análisis semántico, la generación decódigo, la optimización y la generación del código objeto para obtener elfuncionamiento de un compilador.Esta asignatura busca proveer al estudiante de herramientas, conocimientos y

Page 3: Antología Lenguajes Y Autómatas

habilidades necesarias para desarrollar un compilador con base en los conocimientosprevios de la asignatura lenguajes y autómatas I. La aportación de esta materia esrelevante en el ámbito del desarrollo de software de sistemas.

Es indispensable distinguir que la carrera de Ingeniería en Sistemas Computacionalesse basa no sólo en el desarrollo de software comercial y administrativo, sino tambiénen el desarrollo de software científico. Esta materia se ubica en la segunda categoríay es indispensable desarrollar software en estos campos para preparar a losegresados y tengan la posibilidad de cursar posgrados de alto nivel.La asignatura trata de concretar un traductor iniciado en la materia previa para que elestudiante comprenda que es capaz, mediante técnicas bien definidas, de crear supropio lenguaje de programación.La aportación de la asignatura al perfil del egresado será específicamente la siguiente:• Desarrollar, implementar y administrar software de sistemas o de aplicación quecumpla con los estándares de calidad buscando como finalidad apoyar laproductividad y competitividad de las organizaciones.• Integrar soluciones computacionales con diferentes tecnologías, plataformas odispositivos.• Diseñar e implementar interfaces hombre – máquina y maquina – máquina para laautomatización de sistemas.• Identificar y comprender las tecnologías de hardware para proponer, desarrollar ymantener aplicaciones eficientes.

O B J E T I V O

Desarrollar software de base: traductor, intérprete o compilador.

COMPETENCIAS PREVIAS Y RELACION CON CURSOS ANTERIORES YPOSTERIORES

Definir, diseñar, construir y programar las fases del analizador léxico y sintáctico de untraductor o compilador.

Su relación con materias anteriores: Fundamentos de programación, Tópicosavanzados de programación, Fundamentos de Ingeniería de Software, Lenguajesy autómatas I.

Su relación con materias posteriores: Sistemas programables

Las competencias logradas en esta materia son: razonamiento deductivo einductivo, análisis – síntesis.

Page 4: Antología Lenguajes Y Autómatas

CONTENIDO

UNIDAD 1 Análisis semántico

1.1. Arboles de expresiones.

1.2. Acciones semánticas de un analizador sintáctico.

1.3. Comprobaciones de tipos en expresiones .

1.4. Pila semántica en un analizador sintáctico.

1.5. Esquema de traducción.

1.6. Generación de la tabla de símbolo y de direcciones.

1.7. Manejo de errores semánticos.

UNIDAD 2 Generación de código intermedio.

2.1 Notaciones

2.1.1 Prefija

2.1.2 Infija

2.1.3 Postfija

2.2 Representaciones de código Intermedio.

2.2.1 Notación Polaca

2.2.2 Código P

2.2.3 Triplos

2.2.4 Cuádruplos.

2.3 Esquema de generación.

2.3.1 Variables y constantes.

2.3.2 Expresiones.

Page 5: Antología Lenguajes Y Autómatas

2.3.3 Instrucción de asignación.

2.3.4 Instrucciones de control.

2.3.5 Funciones

2.3.6 Estructuras

UNIDAD 3 Optimización

3.1 Tipos de optimización.

3.1.1 Locales.

3.1.2 Ciclos.

3.1.3 Globales.

3.1.4 De mirilla.

3.2 Costos.

3.2.1 Costo de ejecución. (memoria, registros, pilas)

3.2.2 Criterios para mejorar el código.

3.2.3 Herramientas para el análisis del flujo de datos.

UNIDAD 4 Generación de código objeto

4.1 Registros.

4.2 Lenguaje ensamblador.

4.3 Lenguaje maquina.

4.4 Administración de memoria.

Page 6: Antología Lenguajes Y Autómatas

COMPETENCIAS A ALCANZAR EN EL CURSO

Al término del curso el participante logrará las siguientes competencias:

Unidad 1: Análisis Semántico.

Diseñar mediante el uso de arboles de expresiones dirigida por la sintaxis unanalizador semántico para un meta-compilador.

Unidad 2: Generación de código intermedio.

Aplicar las herramientas para desarrollar una máquina virtual que ejecute códigointermedio a partir del código fuente de un lenguaje prototipo.

Unidad 3: Optimización.

Conocer e Identificar los diferentes tipos de optimización que permita eficientar elcódigo intermedio.

Unidad 4: Generación del código objeto.

Utilizar un lenguaje de bajo nivel para traducir el código construido a lenguajemáquina para su ejecución.

UNIDAD 1 Análisis Semántico.Competencia específica de la unidad:

Diseñar mediante el uso de arboles de expresiones dirigida por la sintaxis unanalizador semántico para un meta-compilador.

CONTENIDO TEMATICO

En este capítulo analizamos la fase del compilador que calcula la informaciónad~cional necesaria para la compilación una vez que se conoce la estructurasintáctica de un programa. Esta fase se conoce como análisis semántico debido a queinvolucra el cálculo de información que rebasa las capacidades de las gramáticas

Page 7: Antología Lenguajes Y Autómatas

libres de contexto y los algoritmos de análisis sintáctico estándar, por lo que no seconsidera como sintaxis.'La información calculada tambikn está estrechamente relacionada con el significadofinal, o semántica, del programa que se traduce. Como el análisis que realiza uncompilador es estático por definición (tiene lugar antes de la ejecución), dicho análisissemántico también se conoce como análisis semántico estático. En un lenguajetípico estáticamente tipificado como C. el análisis semántico involucra laconstrucción de una tabla de símbolos para mantenerse al tanto de los significados denombres establecidos en declaraciones e inferir tipos y verificarlos en expresiones ysentencias con el fin de determinar su exactitud dentro de las reglas de tipos dellenguaje.El análisis semántico se puede dividir en dos categorías. La primera es el análisis deun programa que requiere las reglas del lenguaje de programación para establecer suexactitud y garantizar una ejecución adecuada. La complejidad de un análisis de estaclase requerido por una definición del lenguaje varía enormemente de lenguaje alenguaje. En lenguajes orientados en forma dinámica, tales como LISP y Smalltalk,puede no haber análisis semántico estático en absoluto, mientras que en un lenguajecomo Ada existen fuertes requerimientos que debe cumplir un programa para serejecutable. Otros lenguajes se encuentran entre estos extremos (Pascal, por ejemplo.no es tan estricto en sus requerimientos estáticos como Ada y C, pero no es tancondescendiente como LISP).

La segunda categoría de análisis semántico es el análisis realizado por un compiladorpara mejorar la eficiencia de ejecución del programa traducido. Esta clase de análisispor lo regular se incluye en análisis de "optimización", o técnicas de mejoramiento decódigo. Investigaremos algunos de estos métodos en el capitulo sobre generación decòdigo, mientras que en este capitulo nos enfocaremos en los análisis comunes quepor exactitud son requeridos para una definición del lenguaje. Conviene advertir quelas técnicas estudiadas aqui se aplican a ambas situaciones. También que las doscategorías no son mutuamente excluyentes, ya que los requerimientos de exactitud,tales como la verificación de tipos estáticos, también permiten que un compiladorgenere código más eficiente que para un lenguaje sin estos requerimientos. Además,vale la pena hacer notar que los requerimientos de exactitud que aqui se comentannunca pueden establecer Ia exactitud completa de un programa, sino sólo una clasede exactitud parcial. Tales requerimientos todavía son útiles debido a queproporcionan al programador información para mejorar la seguridad y fortaleza delprograma.El análisis semántico estático involucra tanto la descripción de los análisis a realizarcomo la implementación de los análisis utilizando algoritmos apropiados. En estesentido, es semejante al análisis léxico y sintáctico. En el análisis sintáctico, porejemplo, utilizamos gramáticas libres de contexto en la Forma Backus-Naus (BNF, porsus siglas en inglés) para describir la sintaxis y diversos algoritmos de análisissintáctico descendente ascendente para implementar la sintaxis. En el análisissemántico la situación no es tan clara, en parte porque no hay un método estándar(como el BNF) que permita espeficar la semántica estática de un lenguaje, y en parteporque la cantidad y categoría del análisis semántico estático varía demasiado de unlenguaje a otro. Un método para describir el análisis semántico que los escritores de

Page 8: Antología Lenguajes Y Autómatas

compiladores usan muy a menudo con buen efectos es la identificación de atributos,o propiedades, de entidades del lenguaje que deben calcularse y escribir ecuacionesde atributos o reglas semánticas, que expresan cómo el cálculo de tales atributosestá relacionado con las reglas gramaticales del lenguaje. Un conjunto así de atributosy ecuaciones se denomina gramática con atributos.Las gramáticas con atributos son más útiles para los lenguajes que obedecen elprincipio de la semántica dirigida por sintaxis, la cual asegura que el contenidosemántico de un programa se encuentra estrechamente relacionado con su sintaxis.Todos los lenguajes modernos tienen esta propiedad. Por desgracia, el escritor decompiladores casi siempre debe construir una gramática con atributos a mano a partirdel manual del lenguaje, ya que rara vez la da el diseñador del lenguaje. Aún peor, laconstrucción de una gramática con atributos puede complicarse innecesariamentedebido a su estrecha adhesión con la estructura sintáctica explícita del lenguaje. Unfundamento mucho mejor para la expresión de los cálculos semánticos es la sintaxisabstracta, como se representa mediante un árbol sintáctico abstracto. Incluso. eldiseñador del lenguaje, también suele dejar al escritor del compilador laespecificacición de la sintaxis abstracta.Los algoritmos para la implementación del análisis semántico tampoco son tanclaramente expresables como los algoritmos de análisis sintáctico. De nuevo, esto sedebe en parte a los mismos problemas que se acaban de mencionar respecto a laespecificación del análisis semántico. No obstante, existe un problema adicionalcausado por la temporización del análisis durante el proceso de compilación. Si elanálisis semántico se puede suspender hasta que todo el análisis sintáctico (y laconstrucción de un árbol sintáctico abstracto) esté completo, entonces la tarea deimplementar el análisis semántico se vuelve considerablemente más fácil y consisteen esencia en la especificación de orden para un recorrido del árbol sintáctico. juntocon los cálculos a realizar cada vez que se encuentra un nodo en el recorrido. Sinembargo, esto implica que el compilador debe ser de paso múltiple. Si. por otra parte,el compilador necesita realizar todas sus operaciones en un solo paso (incluyendo lageneración del código), entonces la implementación del análisis semántico se convierteen mucho más que un proceso a propósito para encontrar un orden correcto y un métodopara calcular la información semántica (suporiiendo que un orden correcto así exista enrealidad). Afortunadamente, la práctica moderna cada vez más permite al escritor decompiladores utilizar pasos múltiples para simplificar los procesos de análisis semántico ygeneración de código.A pesar de este estado algo desordenado del análisis semántico, es muy útil para estudiargramáticas con atributos y cuestiones de especificación. ya que esto redundará en lacapacidad de escribir un código más claro, más conciso y menos proclive a errores paraanálisis semántico, además de permitir una comprensión más fácil de ese código.Por lo tanto, el capítulo comienza con un estudio de atributos y gramáticas con atributos.Continúa con técnicas para implementar los cálculos especificados mediante unagramática con atributos, incluyendo la inferencia de un orden para los cálculos y losrecorridos del árbol que los acompañan. Dos secciones posteriores se concentran en lasáreas principales del análisis semántico: tablas de símbolos y verificación de tipos. Laúltima sección describe un analizador semdntico para el lenguaje de programación TlNY .

Page 9: Antología Lenguajes Y Autómatas

ATRIBUTOS Y GRAMATICAS CON ATRIBUTOSUn atributo es cualquier propiedad de una construcción del lenguaje de programación.Los atributos pueden variar ampliamente en cuanto a la inf«rmación que contienen, sucomplejidad y en particular el tiempo que les torna realizar el proceso detraducci<ín/ejec~icióncu ando pueden ser determinados. Ejemplos típicos de atributos sonEl tipo de <latos de una variable El valor de una expresión La ubicaciún de una variableen la memoria El cbdigo objeto de un procedimiento El número de dígitos significativos enun número Los atributos se pueden csrablecer antes del proceso de compilaciún (oincluso la construcción de un con~pilador).P or ejemplo, el número de dígitos significativoseri un número se puede establecer (o por lo menos dar un valor mínimo) mediante ladefinición de un Ienguaje.Además, los atributos s6lo se pueden determiriar durante la ejecuciúti tiel progrini;~, ti11como el valor de una expresicín (no consiante). o la ubicaci6n de una estructura {le datosdininiicaniente asignada. El proceso (te calcular un atributo y asociar su valor calculadocon la construcciún del lenguaje en cuestión se define corno fijación del atrihuio. Eltiempo que toma el proceso de compilación cuando se presenta la fijación de un atributose enomina tiempo de fijación. Los tiempos de fijación de atributos diferentes varían, eincluso el mismo atributo puede tener tiempos de fijación bastante diferentes de unlenguaje a otro.

Definición de otro autor:

Análisis sintáctico, semántico y generación de código

Como lo hemos mencionado antes, la sintaxis trata con la forma de los programas válidos,mientras que la semántica trata con su significado. Se dice que la sintaxis de un lenguaje esaquella porción del mismo que puede ser descrita de manera adecuada por medio de unaGramática Libre de Contexto (GLC), mientras que la semántica es aquella porción dellenguaje que no puede ser descrita de esta manera.

El análisis semántico y la generación de código intermedio pueden ser descritos entérminos de la anotación o decoración de un árbol sintáctico o árbol de análisis sintáctico(parse tree). Las anotaciones de un árbol sintáctico son llamados “atributos”.

El analizador sintáctico recibe una serie de tokens del analizador léxico y los organiza enun árbol sintáctico. La manera en que estos tokens son organizados está definida por unconjunto de reglas, potencialmente recursivas. Este conjunto de reglas es la gramática librede contexto.

En general, una GLC consiste de:

Un conjunto finito N de símbolos no terminales, Un conjunto finito T de símbolos terminales, Un subconjunto finito P de [(N U T)* - T*] x (N U T)* llamado conjunto de

producciones, y

Page 10: Antología Lenguajes Y Autómatas

Un símbolo inicial σ Є N.

La tarea del analizador sintáctico (parser) es determinar si una cadena de entrada puedederivarse a partir del símbolo inicial, y si es así, cómo puede hacerse. Hay dos manerasbásicas de hacer esto:

Análisis sintáctico descendente (top-down): puede verse como el intento deencontrar la derivación más a la izquierda de un flujo de entrada recorriendo el árbolsintáctico de arriba hacia abajo. Los tokens son analizados de izquierda a derecha.Para manejar la ambigüedad se suele utilizar lo que se conoce como opcióninclusiva, expandiendo los lados derechos de las reglas gramaticales. Losanalizadores LL (Left-to-right, Leftmost derivation) y Recursivos-descendentes sonejemplos de este tipo de análisis.

Análisis sintáctico ascendente (bottom-up): el analizador inicia con la secuencia deentrada e intenta re-escribirla hasta llegar al símbolo inicial. Intuitivamente elanalizador intenta localizar el elemento más básico, después los elementos quecontienen éstos, y así sucesivamente. Los analizadores LR (Left-to-right, Rightmostderivation) son ejemplos de este tipo de analizadores, que también son conocidoscomo Analizadores Desplaza-Reduce (Shift-Reduce).

Analizadores LL vs. LR

El acrónimo LL viene de Left-to-Right, Leftmost Derivation, lo que significa quecuando se encuentra una regla de producción no terminal que contiene componentesno terminales en su parte derecha, el componente no terminal de más a la izquierdaes sustituido por el lado derecho de su respectiva regla. Si esa regla tambiéncontiene componentes no terminales, el proceso se repite.

Debido a este comportamiento, los árboles sintácticos generados por losanalizadores LL tienden a crecer más hacia la izquierda que hacia la derecha. Paratratar de evitar ambigüedades, el analizador siempre lee el siguiente símbolo en lacadena de entrada, y lo llama “look-ahead”. Por otro lado, el analizador LL decidela regla de producción a utilizar, dependiendo de lo que resta por analizar en lacadena de entrada. No mantiene información sobre el progreso del análisis. Si surgealguna ambigüedad que no pueda ser resuelta con el auxilio del símbolo “look-ahead”, el analizador produce un error. Aunque es posible aumentar el número desímbolos “look-ahead”, el problema esencial persiste; además de los símbolos“look-ahead”, no hay otro método para recuperarse de ambigüedades en este tipo deanalizadores.

Los analizadores LR (Left-to-right, Rightmost derivation) también utilizansímbolos “look-ahead”, pero además mantienen información sobre el estado delproceso de análisis. Para este registro utilizan una pila (stack) donde guardaninformación del estado inmediato anterior. Cada regla de producción es consideradaun estado y cada regla que resulta en un símbolo no terminal es considerada una

Page 11: Antología Lenguajes Y Autómatas

transición a otro estado. Esto hace que los analizadores LR sean más resistentes alas ambigüedades que los LL, pero pueden resultar en analizadores que requierenmás recursos (en términos de tiempo de procesamiento y espacio de memoria).

Los analizadores LALR (Look Ahead LR) son una especialización de losanalizadores LR. Pueden manejar más GLC que el LR básico. Es un tipo deanalizador muy popular porque logra un buen balance entre el número degramáticas que puede manejar y su consumo computacional (en términos deprocesador y memoria). Las herramientas Yacc y Bison generan analizadoressintácticos de este tipo.

Ejemplo de análisis sintáctico

Para ilustrar estos conceptos, supongamos que tenemos un lenguaje de expresionesalgebraicas escritas con los símbolos T = {x, y, z, +, *, (, )}, que constituyen los símbolosterminales de la gramática. Los símbolos no-terminales que utilizaremos son E para unaexpresión y T para términos que constan de factores (símbolo no-terminal F), es decir,N={E,T,F}.

Una expresión algebraica puede consistir de un solo término:

E → T

O la suma de una expresión y un término:

E → E + T

Un término puede consistir de un factor, o del producto de un factor y un término:

T → FT → F * T

Un factor puede consistir de una expresión algebraica entre paréntesis o de uno de lossímbolos terminales:

F → ( E )F → xF → yF → z

Estas reglas, también llamadas producciones, definen el conjunto de todas las cadenasválidas de este lenguaje.

Page 12: Antología Lenguajes Y Autómatas

Una expresión válida para este lenguaje es x * y + z * (x + y). El árbol sintácticocorrespondiente a esta expresión es el siguiente:

Figura 1. Árbol sintáctico de la expresión algebraica x * y + z * (x + y)

Gramática de atributos

Cuando describimos un lenguaje por medio de una GLC, no se puede decir nada acerca delos significados de las expresiones. Para el manejo de los significados es común usar unagramática de atributos, la cual asigna un valor a cada símbolo (terminal y no-terminal) dellenguaje. La gramática se incrementa con un conjunto de reglas de producción queespecifican como se relaciona cada símbolo con su valor.

Para ilustrar el uso de las gramáticas de atributos, supongamos la siguiente gramática deexpresiones algebraicas compuesta por constantes y que maneja precedencia yasociatividad:

E → E + TE → E - TE →TT → T * FT → T / FT → FF → -FF → ( E )F → constante

Ahora presentamos la gramática de atributos para este lenguaje de expresiones algebraicas:

Page 13: Antología Lenguajes Y Autómatas

1. E1→ E2 + T» E1.val := suma(E2.val, T.val)2. E1→ E2 - T» E1.val := diferencia(E2.val, T.val)3. E → T» E.val := T.val4. T1→ T2 * F» T1.val := producto(T2.val, F.val)5. T1→ T2 / F» T1.val := cociente(T2.val, F.val)6. T → F» T.val := F.val7. F1→ -F2» F1.val := inverso(F2.val)8. F → ( E )» F.val := E.val9. F → constante» F.val := constante.val

Como vemos, en estas reglas de la gramática de atributos, asignar significados a lassentencias del lenguaje equivale a asignar una función que recibe como parámetros loscomponentes de la sentencia y regresa un valor que se asigna a esa expresión.

Resumen

Hemos visto hasta ahora que el análisis sintáctico y el análisis semántico utilizan algunasherramientas matemáticas para realizar sus funciones: árboles sintácticos y gramáticas deatributos. Estas herramientas nos permiten definir la sintaxis y semántica de un lenguaje ynos preparan para la generación de código intermedio.

UNIDAD 2 Generación decódigo intermedio.Competencia específica de la unidad:

Aplicar las herramientas para desarrollar una máquina virtual que ejecute códigointermedio a partir del código fuente de un lenguaje prototipo.

CONTENIDO TEMATICO

Page 14: Antología Lenguajes Y Autómatas

Código máquinaLa aparición de los lenguajes de alto nivel mejoró la productividad de los programadores alliberarlos de los detalles de bajo nivel de la computadora que estaban programando. Elcompilador es quien se encarga de realizar la conversión del código fuente en lenguaje de altonivel al código máquina de la computadora que ejecutará el programa. Es, por tanto, elcompilador quien ahora maneja los detalles de bajo nivel de la arquitectura a programar. Estoimplica que el desarrollo del compilador requiere del conocimiento de los detalles de laarquitectura de la máquina destino. En este apartado conoceremos la computadora abstracta parala que Tiny traduce sus programas.

3.2.1 La máquina abstracta

En este apartado describimos la computadora para la cual el compilador de Tiny generacódigo objeto. Está diseñada para facilitar la traducción de un lenguaje similar al Pascal auna arquitectura abstracta. Esta computadora es un subconjunto de la computadora Dream(Dream machine) diseñada por Frank DeRemer. Se trata de una computadora orientada apila (stack) sin registros direccionales, por lo que carece de instrucciones como “cargaregistro X con …”; es decir, todas las instrucciones suponen que los datos están en la pila yguardan los resultados en la pila.

Además, se han eliminado algunas restricciones normales en las máquinas reales:

Las instrucciones de ramificación no están limitadas a un determinado rango. Todas las instrucciones tienen el mismo formato, y no dos o tres formatos

diferentes, como en la arquitectura IA32, por ejemplo.

La computadora tiene tres memorias diferentes y separadas entre sí:

De código De datos De direcciones de retorno

Los límites de cada tipo de memoria están indicados por una serie de registros. La siguientefigura ilustra estas memorias y sus registros límite:

Page 15: Antología Lenguajes Y Autómatas

La memoria de código se considera de sólo-lectura. Ningún programa puede saltar (branch)fuera de su área de código, ya que todas sus instrucciones están confinadas al rango dedirecciones limitado por los registros CBR y CLR. Ni el código ni las direcciones deretorno pueden modificarse ni copiarse, debido a que todas las lecturas y escrituras amemoria están restringidas a realizarse entre los registros GBR (Global Base Register) ySTR (Stack Top Register).

En otras palabras, en esta máquina es imposible ejecutar código que se automodifique.

El límite de la memoria disponible está determinado por el registro SLR (Stack LimitRegister). Este registro simula el tamaño limitado de la memoria física de las computadorasreales; sin embargo, para fines del compilador de Tiny, supondremos que la máquina notiene limitación de memoria, es decir, el contenido de SLR es “infinito”.

Todo el direccionamiento de las variables globales y locales es relativo a GBR (GlobalBase Register) o a LBR (Local Base Register), según corresponda. Por tanto, la instrucción“LLV i” (Load Local Value i) significa “coloca en el tope de la pila (push) el valor de la i-ésima palabra del marco local (local frame). Por tanto, i puede verse como un

Page 16: Antología Lenguajes Y Autómatas

desplazamiento (offset) a partir de LBR. La ejecución de esta instrucción ajustará elregistro del tope de la pila (STR). Otro ejemplo es “SGVi” (Storage Global Value i), quesignifica “saca de la pila el valor en el tope (pop) y almacénalo en la i-ésima palabraglobal”. De nuevo, la ejecución de esta instrucción ajustará el STR, e i es el desplazamientorespecto de GBR. Otro ejemplo más es “LIT i” (Literal i), que significa “coloca i en lapila”.

Con el fin de simplificar, asumimos que la ejecución del programa, una vez cargado enmemoria, inicia en la instrucción indicada en CBR; es decir, asumimos que el cargadorcarga el programa a partir de esa localización. La herramienta TWS incluye un intérpreteque hace las veces de la máquina abstracta.

3.2.2 Formato de instrucciones

El formato de las instrucciones de la máquina abstracta es el siguiente:

{etiqueta} [mnemónico de la instrucción] [0, 1 o 2 operandos]

Donde la etiqueta es opcional, además vemos que hay instrucciones que no manejan datos,otras que manejan un sólo dato y otras que manejan dos datos. Es decir, en el conjunto deinstrucciones encontramos instrucciones con 0, 1 o 2 campos de direccionamiento.

3.2.3 Conjunto de instrucciones

Las instrucciones que la máquina abstracta puede ejecutar son las siguientes:

De control del programa

NOP : Hacer nadaHALT : Detenerse (halt)

De transferencia de datos

LIT v : Cargar (Push) la Literal v en Local frame (Lf) de la memoria de datos.LLV i : Cargar valor local (Load Local Value) i en Lf.LGV i : Cargar valor global (Load Local Value) i en Lf.SLV i : Almacena valor local i (Store Local Value i) en Lf.SGV i : Almacena valor global i.LLA i : Cargar Dirección Local i (Load Local Address i) en Lf.LGA i : Cargar Dirección Global i (Load Global Address i) en Lf.POP n : Extrae n valores (Pop n values).DUP : Duplica el tope de la pila.SWAP : Intercambia los dos valores superiores de la pila.

Aritméticas y lógicas

Page 17: Antología Lenguajes Y Autómatas

UOP i : Operación unitaria i (Unary Operation i): const X = Pop Lf.Push (Unop(i,X)) en Lf

BOP i : Operación binaria i: const Xr,Xl = Pop Lf, Pop LfPush (Binop(i,Xl,Xr)) en Lf

De control de flujo

CALL n : Llamada a una subrutina.RTN n : Retorno de rutina.GOTO L : I <- L Salto incondicional a LCOND L M: I <- if Pop Lf = True # Pop Stack. Si el valor es:then L # Verdadero, salta a Lelse M # Falso, salta a M.fi

CODE F : Push F on Lf # Carga el punto de entrada.SOS i : Llamada a la función i del sistema operativoDondeUnop(i,X) significa:case i ofUNOT : not(X)UNEG : -(X)USUCC : X+1UPRED : X-1

Binop(i,Xl,Xr) significa:case i ofBAND : Xl and XrBOR : Xl or XrBPLUS : Xl + XrBMINUS : Xl - XrBMULT : Xl * XrBDIV : Xl div XrBMOD : Xl mod XrBEQ : Xl = XrBNE : Xl <> XrBLE : Xl <= XrBGE : Xl >= XrBLT : Xl < XrBGT : Xl > Xr

Llamadas al sistema

Para simplificar el manejo de los dispositivos de Entrada/Salida suponemos que tenemosdisponibles algunas llamadas al sistema operativo, a las cuales se accede por medio de lainstrucción SOS:

Page 18: Antología Lenguajes Y Autómatas

SOS (Sistema operativo) i significa:

case i ofTRACEX : Trace_Execution <- not TraceExecutionDUMPMEM: Dump_MemoryINPUT : readln(i)Push i on LfINPUTC : readln(ch)Push Ord(ch) on LfOUTPUT : write (Pop Lf)OUTPUTC: write (Chr(Pop(Lf)))OUTPUTL: writelnEOF : if eof(input)then Push True on Lfelse Push False on Lf

Vemos que la máquina abstracta puede ejecutar las cuatro operaciones aritméticas básicas:suma, resta, multiplicación y división, además la operación módulo; también puede ejecutarlas tres operaciones lógicas básicas: NOT, ANDy OR; puede ejecutar saltos condicionales eincondicionales. Cuenta con llamadas al sistema operativo para las operaciones deEntrada/Salida y para funciones de depuración.

Como sabemos, el compilador debe traducir del lenguaje de alto nivel a este conjunto deinstrucciones. Es, por tanto, necesario entender como utilizar este lenguaje ensambladorpara escribir programas en bajo nivel para la máquina abstracta. A continuaciónpresentamos un par de ejemplos de traducción de Tiny al ensamblador de la máquinaabstracta.

Ejemplo 1

Vamos a mostrar la traducción del siguiente programa en Tiny:

Program copy:{ Despliega en pantalla (eco) los primeros 10 números leídos con input }Var count: integer;BeginCount:=1;While( count <= 10) doBeginOutput(read);Count := count + 1;End

End copy.

Page 19: Antología Lenguajes Y Autómatas

El código máquina para este programa se muestra abajo. Obviamente, los comentarios noson generados por el generador de código.

LIT 0 # Espacio para CountLIT 1 # Asigna 1SGV 0 # Count := 1

L2 LGV 0 # Carga CountLIT 10 # Carga 10BOP BLE # POP, Compara. Push resultado T/FCOND L3 L4 # Pop stack, si V, ve a L3, sino, ve a L4.

L3 SOS INPUT # Llamada al SO. Lee y coloca en la pilaSOS OUTPUT # Llamada al SO. Saca de la pila y despliegaSOS OUTPUTL # Despliega un avance de líneaLGV 0 # Carga CountLIT 1 # Carga 1BOP BPLUS # Súmalos y guarda resultado en la pilaSGV 0 # Saca de la pila y almacena en CountGOTO L2 # Regresa a L2

L4 HALT # Salta aquí cuando termines. Deténte.

Ejemplo 2

Con el fin de ayudar al entendimiento de esta máquina estudiaremos otro programaejemplo, escrito en el lenguaje “Medium”, que es el lenguaje intermedio para Tiny:

program fact:var m: integer;function fact(n: integer) : integerbeginIf n > 0 thenfact := n * fact( n – 1 );elsefact := 1;m := m + 1;end;beginm := 0;output( fact( read ), m );end fact.

El código para la máquina abstracta es el siguiente:

LIT 0GOTO L1L2 LLV 1

Page 20: Antología Lenguajes Y Autómatas

LIT 0BOP BGTCOND L3 L4L3 LLV 1LIT 0LLV 1LIT 1BOP BMINUSCODE L2CALL 3BOP BMULTSLV 0GOTO L5L4 LIT 1SLV 0NOPL5 LGV 0LIT 1BOP BPLUSSGV 0LLV 0RTN 1L1 LIT 0SGV 0LIT 0SOS INPUTCODE L2CALL 1SOS OUTPUTLGV 0SOS OUTPUTSOS OUTPUTLHALT

Es muy recomendable que traces con papel y lápiz la ejecución de estos dos programas deejemplo para que entiendas mejor la programación en bajo nivel de la máquina abstracta.

UNIDAD 3Optimización.Competencia específica de la unidad:

Conocer e Identificar los diferentes tipos de optimización que permita eficientar elcódigo intermedio.

Page 21: Antología Lenguajes Y Autómatas

CONTENIDO TEMATICO

Estrategias de optimización

La optimización del código es el proceso de "puesta a punto" (tuning) de la salida de uncompilador con el fin de minimizar o maximizar algún atributo del programa objeto. Escomún que la meta de la optimización sea minimizar el espacio en memoria que ocupa delcódigo o maximizar la velocidad de ejecución.

Una forma de clasificar las estrategias de optimización del código se basa en el alcance dela optimización: desde una sola instrucción (optimización local), hasta un programa entero(optimización global).

Técnicamente hablando es más sencillo implementar estrategias locales que globales,aunque normalmente el beneficio es menor que el obtenido con estrategias globales.

Algunos ejemplos de estrategias de optimización clasificadas por su alcance son:

Optimizaciones locales: Sólo toman en cuenta la información local de una función.Requieren menos tiempo de análisis.

Optimización interprocedural o de programa completo: Requieren analizar elprograma completo. Un ejemplo de estrategia de este tipo es el reemplazo de unallamada a función con el código de la función, lo que reduce la sobrecarga normalde una llamada a función.

Optimización de lazos: Se aplica sólo a las estructuras repetitivas, como for() ywhile(). Este tipo de optimización puede tener un fuerte impacto porque muchosprogramas dedican un buen porcentaje de su tiempo de ejecución a este tipo deinstrucciones.

Además de la clasificación por su alcance, las estrategias de optimización se dividen en doscategorías generales:

Independiente vs. dependiente del lenguaje de programación. La optimizaciónindependiente del lenguaje de programación se basa en el hecho de que muchoslenguajes de programación comparten estructuras comunes. La optimizacióndependiente del lenguaje trata de aprovechar las particularidades de cada lenguajede alto nivel.

Independiente vs. dependiente de la máquina destino. Muchas de las mejoresoptimizaciones se logran explotando las características particulares de la plataformadestino.

Obviamente las características de la plataforma destino también afectan las estrategias deoptimización. Entre estas características tenemos las siguientes:

Page 22: Antología Lenguajes Y Autómatas

Número de registros internos en el CPU. Tipo de procesador: RISC vs. CISC. Número de unidades funcionales: coprocesador numérico o no, pipelining, etcétera.

Para evitar complicar mucho al compilador de Tiny, la herramienta TWS no maneja ningúntipo de optimización; sin embargo, muchos compiladores sí lo hacen, ya que la posibilidadde obtener código optimizado siempre es un atractivo más para cualquier compilador,independientemente del lenguaje a traducir.

Detección de erroresLos errores de programación pueden clasificarse en tres categorías:

Errores de compilación Errores de ejecución Errores lógicos

Errores de compilación

Son errores que aparecen cuando se está compilando el programa y eventualmenteocasionan que se detenga el proceso de traducción.

Muchos de estos errores son causados por equivocaciones de captura, por ejemplo, un maldeletreo de alguna palabra clave, mezcla incorrecta de mayúsculas y minúsculas en losnombres de variables, o la falta de un signo de puntuación, entre otros.

Son los errores más fáciles de corregir porque contamos con la ayuda del compilador.Cuando el compilador detecta un error durante el analizador sintáctico o no puede asignarsignificado a una expresión durante el análisis semántico, genera un mensaje de errormostrando una breve descripción del error y la línea del código fuente donde lo encontró.Normalmente el compilador intenta seguir el proceso de traducción con el fin de detectar lamayor cantidad posible de errores e informarlos al programador para que proceda acorregirlos.Cuando aparecen varios errores de compilación, por lo general sólo el primer error es real,los demás pueden no serlo.

Errores de ejecución

Son errores que aparecen mientras el programa está en ejecución.

Page 23: Antología Lenguajes Y Autómatas

Un ejemplo típico es la división entre cero; por ejemplo, supón que tienes la siguienteexpresión:

velocidad = kilómetros / horas

Si la variable horas = 0 cuando se intente ejecutar la instrucción, la división no puedecalcularse y se genera un error de ejecución.

Errores lógicos

Causan que el programa no funcione correctamente y que arroje resultados equivocados.

En este tipo de errores la compilación termina sin errores y el programa se ejecuta sinerrores de ejecución, pero arroja resultados no esperados, éstos son los más difíciles deencontrar y corregir.

PRACTICA: Agregando la multiplicación al traductorinicialEn este apartado vamos a ilustrar la manera de expandir el lenguaje inicial agregando lamultiplicación de dos enteros. Esto requiere modificar los siguientes componentes deltraductor:

El analizador léxico (lex.tiny) El analizador sintáctico (parse.tiny) El analizador semántico (constrainer) El generador de código (gencode)

Vamos a ver como se realiza este proceso:

Cambios al analizador léxico lex.tiny

Las reglas para las operaciones dentro del analizador léxico son las siguientes:

"+" { returnrule(yytext[0]); }"-" { returnrule(yytext[0]); }

Para agregar el operador "*" se debe agregar la siguiente línea:

"*" { returnrule(yytext[0]); }

Cambios al analizador sintáctico parser.tiny

Page 24: Antología Lenguajes Y Autómatas

A continuación reproducimos la parte del analizador sintáctico que define las operacionesaritméticas:

Expression ->Term->Term LTE Term => "<=";

Term ->Primary->Primary '+' Term => "+";

Primary -> '-' Primary => "-"-> READ => "read"->Name->INTEGER_NUM => "<integer>"-> '(' Expression ')';

Name -> IDENTIFIER => "<identifier>";

Para introducir el operador de la multiplicación, se debe agregar un nuevo productor defactor:

Expression ->Term->Term LTE Term => "<=";

Term ->Primary->Primary '+' Term => "+";

Factor ->Primary->Primary '*' Factor => "*";

Primary -> '-' Primary => "-"-> READ => "read"->Name->INTEGER_NUM => "<integer>"-> '(' Expression ')';

Name -> IDENTIFIER => "<identifier>";

Modificaciones al constrainer

El constrainer consiste de la clase tws::constrainer y del archivo de cabecera nodes.h, quedefinen los nodos del árbol que el constrainer y el generador de código deben recorrer pararealizar su trabajo. El archivo nodes.h contiene las siguientes líneas:

addnode(ProgramNode,"program");addnode(TypesNode, "types");addnode(TypeNode, "type");addnode(DclnsNode ,"dclns");addnode(DclnNode, "dcln");addnode(IntegerTNode,"integer");addnode(BooleanTNode, "boolean");addnode(BlockNode,"block");addnode(AssignNode, "assign");

Page 25: Antología Lenguajes Y Autómatas

addnode(OutputNode, "output");addnode(IfNode ,"if");addnode(WhileNode ,"while");addnode(NullNode , "null");addnode(LENode ,"<=");addnode(PlusNode ,"+");addnode(MinusNode,"-");addnode(ReadNode,"read");addnode(IntegerNode,"<integer>");addnode(IdentifierNode,"<identifier>");

Se debe agregar la siguiente línea para el nodo de la multiplicación:

addnode(MultNode ,"*");

El archivo de la clase tws::constrainer tiene el método expression(), que analiza lasexpresiones en el AST y determina si están bien formadas. A continuación mostramos elfragmento de este método que verifica los nodos "+" y "-":

if ((nodename == PlusNode) or (nodename == MinusNode)){Type1 = expression(T->get_child(0));

if(T->get_degree()==2){Type2 = expression(T->get_child(1));}else{Type2 = TypeInteger;}

if( (Type1 != TypeInteger) or (Type2 != TypeInteger)){error(T);

cout<< "ARGUMENTS OF '+', '-' etc. MUST BE OF TYPE\INTEGER" <<endl;}

returnTypeInteger;}

Para manejar el nuevo nodo de multiplicación "*", se debe agregar el siguiente código almétodo:

if (nodename == MultNode){Type1 = expression(T->get_child(0));Type2 = expression(T->get_child(1));

if( (Type1 != TypeInteger) or (Type2 != TypeInteger)){error(T);

cout<< "ARGUMENTS OF '*', MUST BE OF TYPE\INTEGER" <<endl;

Page 26: Antología Lenguajes Y Autómatas

}returnTypeInteger;}

Modificaciones al generador de código

El código para las expresiones aritméticas es generado en la clase tws::codegenerator, en elmétodo expression(). A continuación mostramos el fragmento de este método que genera elcódigo para el nodo "-":

if (name == MinusNode){expression(T->get_child(0),CurrLabel);if (T->get_degree() == 2){expression(T->get_child(1),NoLabel);codegen(NoLabel,BOPOP,BMINUS);dec_framesize();}else{

codegen(NoLabel,UOPOP,UNEG);}

}

El código para el nodo "*" debe generarse de la siguiente manera:

if (name == MultNode){expression(T->get_child(0),CurrLabel);expression(T->get_child(1),NoLabel);codegen(NoLabel,BOPOP,BMULT);dec_framesize();}

Donde BMULT es la instrucción en ensamblador para la multiplicación.

Recompilando el traductor

Una vez realizados todos los cambios anteriores en sus respectivos archivos fuente, esnecesario recompilar nuestro traductor. Esto lo hacemos por medio de la utilería make, esdecir, estando ubicados en el directorio tws simplemente tecleamos:

make

Probando la multiplicación

El último paso es capturar y compilar un programa que utilice la nueva instrucción, porejemplo:

Page 27: Antología Lenguajes Y Autómatas

{Archivo: mult.tiny }programmulti:var factor1,factor2, producto : integer;begin

factor1 := read;factor2 := read;producto = factor1 * factor2;

output(producto)endmulti.

Recuerda que compilas el programa con la instrucción:

tc mult.tiny

UNIDAD 4 Generación delcódigo objeto.Competencia específica de la unidad:

Utilizar un lenguaje de bajo nivel para traducir el código construido a lenguaje máquinapara su ejecución.

Análisis del código objeto a crear

La función del compilador es traducir un programa escrito en un lenguaje fuente (unlenguaje de alto nivel) a un programa equivalente en lenguaje máquina del procesadordestino. Este programa está escrito en código objeto. En esta sección del Módulo 4 veremoscómo obtener el código objeto que se genera a partir de algunas instrucciones en lenguajefuente.

A manera de recordatorio, a continuación están reproducidas las instrucciones en lenguajeensamblador de la máquina abstracta. Toda instrucción del lenguaje fuente debe traducirsea una o varias de estas instrucciones.

Las instrucciones que la máquina abstracta puede ejecutar son las siguientes:

De control del programa

Page 28: Antología Lenguajes Y Autómatas

NOP : Hacer nadaHALT : Detenerse (halt)

De transferencia de datos

LIT v : Cargar (Push) la Literal v en Local frame (Lf) de la memoria de datos.LLV i : Cargar valor local (Load Local Value) i en Lf.LGV i : Cargar valor global (Load Local Value) i en Lf.SLV i : Almacena valor local i (Store Local Value i) en Lf.SGV i : Almacena valor global i.LLA i : Cargar Dirección Local i (Load Local Address i) en Lf.LGA i : Cargar Dirección Global i (Load Global Address i) en Lf.POP n : Extrae n valores (Pop n values).DUP : DUPlica el tope de la pila.SWAP : Intercambia los 2 valores superiores de la pila.

Aritméticas y lógicas

UOP i : Operación unitaria i (Unary Operation i): const X = Pop Lf.Push (Unop(i,X)) en Lf

BOP i : Operación binaria i: const Xr,Xl = Pop Lf, Pop LfPush (Binop(i,Xl,Xr)) en Lf

De control de flujo

CALL n : Llamada a una subrutina.RTN n : Retorno de rutina.GOTO L : I <- L Salto incondicional a LCOND L M : I <- if Pop Lf = True # Pop Stack. Si el valor es:then L # Verdadero, salta a Lelse M # Falso, salta a M.fi

CODE F : Push F on Lf # Carga el punto de entrada.SOS i : Llamada a la función i del sistema operativo

Para las operaciones aritméticas y lógicas tenemos que:

Unop(i,X) significa:case i ofUNOT : not(X)UNEG : -(X)USUCC : X+1UPRED : X-1

Page 29: Antología Lenguajes Y Autómatas

Binop(i,Xl,Xr) significa:case i ofBAND : Xl and XrBOR : Xl or XrBPLUS : Xl + XrBMINUS : Xl - XrBMULT : Xl * XrBDIV : Xl div XrBMOD : Xl mod XrBEQ : Xl = XrBNE : Xl <> XrBLE : Xl <= XrBGE : Xl >= XrBLT : Xl < XrBGT : Xl > Xr

Llamadas al sistema

Para simplificar el manejo de los dispositivos de Entrada/Salida suponemos que tenemosdisponibles algunas llamadas al sistema operativo, a las cuales se accede por medio de lainstrucción SOS:

SOS i significa:

case i ofTRACEX : Trace_Execution <- not TraceExecutionDUMPMEM: Dump_MemoryINPUT : readln(i)Push i on LfINPUTC : readln(ch)Push Ord(ch) on LfOUTPUT : write (Pop Lf)OUTPUTC: write (Chr(Pop(Lf)))OUTPUTL: writelnEOF : if eof(input)then Push True on Lfelse Push False on Lf

Código generado por el compilador de Tiny

Cuando compilamos un programa de Tiny se generan varios archivos a partir del programafuente; estos archivos son:

_CONS: Creado por el analizador semántico, contiene comentarios sobre elcumplimiento de las restricciones de Tiny.

Page 30: Antología Lenguajes Y Autómatas

_CGEN: Creado por el generador de código, con comentarios sobre la traducción.Contiene además la traducción de las instrucciones del programa fuente,enriquecido con algunos comentarios útiles para entender mejor el proceso detraducción.

_TREE: Creado por el analizador sintáctico, contiene el árbol sintáctico obtenido apartir del programa fuente.

_CODE: Creado por el generador de código, contiene el programa objeto, sincomentarios.

Es importante anotar que estos archivos se sobrescriben cada vez que compilo un programaen Tiny. Esto es útil porque me permite analizar el código generado por el compilador deTiny para el último programa traducido, y se evita el uso inmoderado del espacio en disco.A manera de ejemplo, vamos a ver el código generado por el compilador de Tiny para elprograma de prueba p7, que se muestra a continuación:

program x:beginoutput(3)

end x.

Recuerda que para compilar este programa debes ejecutar el programa Cygwin. Elcomando para compilar este archivo, esta ubicado en el directorio tiny, es:

./tc tests/p7

En la siguiente figura se muestra el resultado de la compilación y ejecución de p7.También se pueden observar los comandos "cd" para posicionarme en el directorio de tiny:

A continuación te muestro el contenido del archivo _CGEN creador por el compilador deTiny:

<<< CODE GENERATOR >>> Processing Node program , Label is<<< CODE GENERATOR >>> Processing Node dclns , Label is<<< CODE GENERATOR >>> Processing Node block , Label is<<< CODE GENERATOR >>> Processing Node output , Label is<<< CODE GENERATOR >>> Processing Node <integer> , Label isLIT 3

Incrementing Framesize to 1SOS OUTPUT

Decrementing Framesize to 0SOS OUTPUTLHALT

Recuerda que el generador de código recorre el árbol sintáctivo generado por el analizadorsintáctico y revisado por el analizador semántico, para ir generando el código objeto.

Page 31: Antología Lenguajes Y Autómatas

Observa que el primer nodo analizado es el nodo program, después el nombre delprograma, que es un nodo decln, posteriormente un nodo block (bloque), cuyo inicio esindicado por el begin, después una instrucción de salida (ouput), que recibe comoparámetro un nodo entero (3, en este caso). Esta instrucción output(3) se traduce por lasinstrucciones lit 3, sos output y sos outputl. Posteriormente, la instrucción end x.que setraduce por halt.

El contenido del archivo _CODE es el siguiente:

LIT 3SOS OUTPUTSOS OUTPUTLHALT

Fácilmente puede verse que es el mismo código objeto que aparece en el archivo _CGEN,pero sin comentario alguno. Este archivo nos muestra el contenido del archivo ejecutableque se "cargará" al intérprete de la máquina abstracta para su ejecución.

Ejemplo del código generado por el compilador de Tiny para una estructuraselectiva

Para ilustrar el código generado por el compilador de Tiny para una estructura selectiva,vamos a analizar brevemente el código generado por el siguiente programa:

program ejemplo2:beginif( 1 <= 2 ) then output(1) else output(2)

end ejemplo2.

El contenido del archivo _CGEN es el siguiente:

<<< CODE GENERATOR >>> Processing Node program , Label is<<< CODE GENERATOR >>> Processing Node dclns , Label is<<< CODE GENERATOR >>> Processing Node block , Label is<<< CODE GENERATOR >>> Processing Node if , Label is<<< CODE GENERATOR >>> Processing Node <= , Label is<<< CODE GENERATOR >>> Processing Node <integer> , Label isLIT 1

Incrementing Framesize to 1

Page 32: Antología Lenguajes Y Autómatas

<<< CODE GENERATOR >>> Processing Node <integer> , Label isLIT 2

Incrementing Framesize to 2BOP BLE

Decrementing Framesize to 1COND L1 L2

Decrementing Framesize to 0<<< CODE GENERATOR >>> Processing Node output , Label is L1<<< CODE GENERATOR >>> Processing Node <integer> , Label is L1L1 LIT 1Incrementing Framesize to 1SOS OUTPUT

Decrementing Framesize to 0SOS OUTPUTLGOTO L3

<<< CODE GENERATOR >>> Processing Node output , Label is L2<<< CODE GENERATOR >>> Processing Node <integer> , Label is L2L2 LIT 2Incrementing Framesize to 1SOS OUTPUT

Decrementing Framesize to 0SOS OUTPUTLNOP

L3 HALT

Observa el orden del recorrido del árbol sintáctivo en el archivo _CGEN:

Node program: Siempre debe iniciar con este nodo. Node dclns: Y continuar con éste, por el nombre del programa. Node block: Inicio del begin. Node if: En este ejemplo, primera instrucción del programa. Node <= : Operador relacional de la condición del if. Node <integer>: Entero 1, etcétera.

El código ejecutable de este programa, que es el contenido del archivo _CODE, es elsiguiente:

LIT 1LIT 2BOP BLECOND L1 L2

L1 LIT 1SOS OUTPUTSOS OUTPUTLGOTO L3

Page 33: Antología Lenguajes Y Autómatas

L2 LIT 2SOS OUTPUTSOS OUTPUTLNOP

L3 HALT

Que realiza las siguientes operaciones:

1. Coloca el número 1 en el tope de la pila (LIT 1).2. Coloca el número 2 en el tope de la pila (LIT 2).3. Realiza la operación binaria (con dos operandos) BOP BLE (Branch if less or equal,

salta si es menor o igual), que compara los dos datos en el tope de la pila.4. Si la condición es verdadera (COND L1 L2), salta a L1, si no salta a L2.5. L1: Coloca el 1 en el tope de la pila (LIT 1) y llama a la función output (SOS

OUTPUT) del SO, para desplegar el tope de la pila, llama a outputl (SOSOUTPUTL), para desplegar un avance de línea y salta a L3 (GOTO L3), con lo quetermina la ejecución del programa.

6. L2: Coloca el 2 en el tope de la pila (LIT 2) y llama a la función output del SO(SOS OUTPUT), para desplegar el tope de la pila, llama a outputl (SOSOUTPUTL), para desplegar un avance de línea, ejecuta nada (NOP) y termina(HALT) la ejecución del programa.

Ejemplo del código generado por el compilador de Tiny para una estructurarepetitiva

Para analizar brevemente el código generado por el compilador de Tiny para una estructurarepetitiva, vamos a revisar brevemente el código generado para el siguiente programa:

program mientras:var i:integer;beginwhile i <= 5 dobeginoutput(i);i := i + 1;end;

end mientras.

El código generado para este programa es el siguiente:

LIT 0L1 LGV 0LIT 5BOP BLECOND L2 L3

Page 34: Antología Lenguajes Y Autómatas

L2 LGV 0SOS OUTPUTSOS OUTPUTLLGV 0LIT 1BOP BPLUSSGV 0GOTO L1

L3 HALT

Donde:

1. LIT 0 es la instrucción que utiliza el compilador de Tiny para definir una variable(en este caso la variable entera i).

2. LGV 0 (que en este ejemplo está etiquetada con L1), es la instrucción para referirsea esa primera variable y cargarla en el tope de la pila.

3. Posteriormente carga el número 5 en el tope de la pila (LIT 5) y compara con laoperación BOP BLE (Salta si menor o igual). Si el contenido de la variable i esmenor o igual a 5, entonces salta a L2, si no salta a L3 (COND L2 L3).

4. L2: Carga i en el tope de la pila (LGV 0), llama a output para que se despliegue enpantalla (SOS OUTPUT) y despliega un "avance de línea" llamando a outputl (SOSOUTPUTL).

5. Carga i en el tope de la pila (LGV 0) y el 1 en el tope de la pila (LIT 1).6. Realiza la operación suma con los dos datos en el tope de la pila y guarda el

resultado en la variable i (BOP BPLUS).7. Salta incondicionalmente a L1 (GOTO L1), que es la verificación de la condición

del while().8. L3: Termina (halt).

Tomando como base estos ejemplos, realiza ahora la actividad correspondiente a estasección del Módulo 4: Diseñar el código que deben generar cada una de las instruccionesque agregarás al compilador de Tiny:

Operación módulo. Operación autoincremento. Operación autodecremento. Estructura for(). Estructura repeat ... until().

Page 35: Antología Lenguajes Y Autómatas

Tarea. Aumentando la gramática del lenguaje tinyInstrucciones: Lee detenidamente estas instrucciones y resuelve los ejercicios que se teindican.

NOTA: En caso de que tengas alguna duda, hazla llegar al facilitador.Ponderación: 15%

Actividad 1

Elabora una investigación documental electrónica y bibliográfica acerca de la definiciónformal de la gramática de los lenguajes de programación, y agrega a la gramática inicialde Tiny las definiciones de las instrucciones:

Módulo Autoincremento Autodecremento Estructura for () Estructura repeat ... until

Para realizar esta actividad:

1. Lee detenidamente los contenidos del Tema 4.1, Proposiciones del lenguaje aimplementar.

1. Con base en la lectura y para reafirmar tus conocimientos y poder continuartus actividades, contesta las preguntas de investigación.

2. ¿Cómo se especifica formalmente la operación módulo (i%j)?3. ¿Cómo se especifica formalmente la operación autoincremento (x++)?4. ¿Cómo se especifica formalmente la operación autodecremento (x--)?5. ¿Cómo se especifica formalmente la estructura for()?6. ¿Cómo se especifica formalmente la estructura repeat ... until()?

Actividad 2

Diseñar el código que deben generar cada una de las instrucciones que agregarás alcompilador de Tiny:

Módulo Autoincremento, Autodecremento, Estructura for() , Estructura repeat ... until

Para realizar esta actividad:

1. Lee detenidamente los contenidos del Tema 4.2, Análisis del código objeto a crear.2. Con base en la lectura y para reafirmar tus conocimientos y poder continuar tus

actividades, contesta las preguntas de investigación.1. ¿Cómo se especifica formalmente la operación módulo (i%j)?

Page 36: Antología Lenguajes Y Autómatas

2. ¿Cómo se especifica formalmente la operación autoincremento (x++)?3. ¿Cómo se especifica formalmente la operación autodecremento (x--)?4. ¿Cómo se especifica formalmente la estructura for()?5. ¿Cómo se especifica formalmente la estructura repeat ... until()?f. Definición formal de la gramática de las instrucciones indicadas.

BIBLIOGRAFIA

1. Aho, Sethi, Ullman. Compiladores Principios, técnicas y herramientasEd.Addison Wesley.2. Lemone Karen A. , Fundamentos de compiladores Cómo traducir allenguaje de computadora, Ed. Compañía Editorial Continental.3. Kenneth C. Louden. Construcción de compiladores Principios y práctica.Ed.Thomson.4. Martin John, Lenguajes formales y teoría de la computación, ED. Mc GrawHill5. Hopcroft John E., Introducción a la Teoría de Autómatas, Lenguajes yComputación, ED. Addison Wesley6. Guerra Crespo. Hector. Compiladores. Ed. Tecnologica didáctica.7. Ronald Mak. Writing compilers and interpreters. Ed. Wiley ComputerPublishing.8. Fischer, LeBlanc. Crafting a compiler with C. Ed. Cummings PublishingCompany, Inc.9. Salas Parrilla, Jesús. Sistemas Operativos y Compiladores. McGraw Hill.10. Beck. Software de Sistemas, Introducción a la programación de Sistemas.Addison-Wesley Iberoamericana.11. Teufel, Schmidt, Teufel. Compiladores Conceptos Fundamentales.Addison-Wesley Iberoamericana.12. C. Louden, Kenneth. Lenguajes de programación Principios y práctica.Thomson.13. Levine Gutiérrez, Guillermo. Computación y programación modernaPerspectiva integral de la informática. Pearson Educación.14. Abel, Peter. Lenguaje ensamblador y programación para PC IBM ycompatibles. Pearson Educación.15. Mak, Ronald. Writing compilers and interpreters. Wiley ComputerPublishing.16. Pittman, Thomas, Peters, James. The art of compiler design Theory andpractice. Prentice Hall.17. Temblay & Sorenson. Compilers Writing. Mc Graw Hill.18. R. Levine, John; Mason, Tony, Brown, Doug. Lex y Yacc. O'Reilly &

Page 37: Antología Lenguajes Y Autómatas

Associates.19. The Lex & Yacc Page, 3-mar-04, 12:45, http://dinosaur.compilertools.net20. A compact guide to lex & Yacc, Thomas Niemann, 3-Mar-04, 12:50,http://epaperpress.com/lexandyacc21. Lex & Yacc HOWTO, Bert Hubert (PowerDNS.COM.BV), 3-Mar-04, 12:55,http://ds9a.nl/lex_yacc22. Flex, 3-mar-04, 13:02, http://www.gnu.org/software/flex/flex.html23. Compiler construction using flex and Bison, Anthony Aaby, 3-mar-04, 13:05,http://cs.wwc.edu/aabyan/464/BooK/24. Flex, version 2.5 A fast scanner generator, Edition 2.5, March 1995, VernPaxson, 3-mar-04, 13:10,http://www.cs.princelon.edu/appel/modern/c/software/flex/flex_toc.html25. Bison. The Yacc-compatible Parser Generator, November 1995, BisonVersion 1.5, Charles Donnelly and Richard Stallman, 3-mar-04, 13:10,http://www.cs.princelon.edu/appel/modern/c/software/bison/bison_toc.html, 13/dic/200926. Bison. http://3d2f.com/programs/30-170-microprocessor-emulator-andassembler-download.shtml, 13/dic/200927. 2/Ago/2005 ,Microprocessor Emulator and Assembler 3.10-k,http://software.intel.com/en-us/articles/all/1/, 24/feb/201028. Intel, 31/dic/2009, Intel® Software Development EmulatorBottom of Form,http://software.intel.com/en‐us/articles/intel‐software‐development‐emulator/,24/feb/2010