1 Compilación, pereza y expresiones let(rec) 2 Compilando un programa Describiremos un compilador para la máquina minimal usando un conjunto de esquemas.

Slides:



Advertisements
Presentaciones similares
Diseño y análisis de algoritmos
Advertisements

Compiladores e intérpretes Análisis Sintáctico III
Curso de Java Capitulo 7: Conceptos sobre poo Profesor:
III - Gestión de memoria
Pilas y Colas Fundamentos Estructuras de Datos (Programación 2)
1 La máquina G. 2 Introducción G: Una implementación de lenguajes funcionales basada en compilación (Augustsson y Johnsson, Chalmers, 1987). Instanciación.
MATRIZ DE CHEQUEO DE PARIDAD
Investigación de Operaciones II
SISTEMA DE NACIMIENTOS MANUAL DEL USUARIO. El objetivo del presente manual es servir de guía al usuario final para interactuar con el Sistema, permitiéndole.
Reducción de grafos Qué es reducción normal de grafos? Ejemplo:
Chequeo e inferencia de tipos
1 Agregando primitivas 2 Introducción Ahora presentaremos cómo agregar operaciones primitivas a la máquina G. Entenderemos como operaciones primitivas.
Combinadores SK.
Informática II Prof. Dr. Gustavo Patiño MJ
PROGRAMACION DE Pilas o Stacks y Colas
Teoría de lenguajes y compiladores
Tema 3. Optimización de Código
La estructura básica de los programas en java, algo a tener en cuenta y que debemos recordar siempre es el archivo debe llevar el nombre de la clase con.
CI TEORIA semana 8 Subprogramas o funciones Definición de funciones.

Introducción a Java II.
MICROSOFT EXCEL TUTORIAL
Cont. Arbol Binario de Búsqueda (2). Sobre los recorridos Las versiones recursivas de los recorridos son costosas debido a la gran cantidad de llamadas.
COLAS, IMPLEMENTACIÓN A PARTIR DE LISTAS Y PARA PILAS
APLICACIONES DE PILAS Estructuras de Datos.
Tema 6: Clases Antonio J. Sierra.
Answering Queries Using Views (Levy, Mendelzon, Sagiv, Srivastava) Javier López C.
Complejidad Problemas NP-Completos
Práctica 7 AOC. Gestión de la pila Una pila es una estructura de datos caracterizada por que el último dato que se almacena es el primero que se obtiene.
Semana 5 Subprogramas..
Índice. Revisando conceptos acerca de la memoria.

Estructura de Datos y Algoritmos
Clase 10: Estructuras de datos y arreglos.
Extensiones sintácticas Revisaremos formas especiales que son sintácticamente equivalentes a patrones que son expresables en términos de formas básicas.
Concatenación en PHP Programación en Internet II.
Tema 10.3: Asignación de Espacio No Contiguo. Tema 10.3: 2 Silberschatz, Galvin and Gagne ©2005 Fundamentos de los Computadores (ITT, Sist. Electr.),
GUIA PARA LA EVALUACION DE PROYECTOS APROBADOS P3E 2004 Contenido Alcance Ingreso al SIIAU WEB- P3e. Ingreso a la aplicación Selección de proyecto que.
(Organización y Manejo de Archivos)
Asignación de Espacio No Contiguo
Material de apoyo Unidad 4 Estructura de datos
Tipos de Datos. Entrada-Salida.. La entrada-salida (I/O) le permite a un programa comunicarse con el mundo exterior. Esta comunicación puede realizarse.
TRABAJANDO CON CVS. Importar archivos al servidor CVS Una importación de archivos o directorios es crear una copia de ellos en el repositorio de nuestro.
APRENDIZ: SANDRA L. CAICEDO C. ORDEN: 20194
Compiladores e intérpretes
1 Samba: Un lenguaje funcional perezoso Presentación del lenguaje: qué es un programa Samba definiciones locales abstracciones lambda Tipos inductivos:
Estructura de Datos M.C. José Andrés Vázquez Flores FCC/BUAP
1 Agregando estructuras de datos. 2 Introducción Ahora extenderemos a la máquina G para poder manipular estructuras de datos. En esta versión el objetivo.
UCLA – DAC M. Sc. Jorge E. Hernández H.
Punteros Recomendado: 1. Nivelación Funciones
Ecuaciones Algebraicas
1 Las máquinas TIM y Spineless-Tagless G. 2 TIM: La máquina de tres instrucciones En principio TIM parece ser una máquina de reducción de grafos muy diferente.
INTRODUCCION A LA PROGRAMACION
Estructura de Datos..
PROGRAMACION DE Pilas o Stacks
MIA - Grupo 5 Unidad 2.
Objetivos del tema. Hemos visto lo que es la estructura de un programa, los datos, que esos datos en realidad se convierten en variables de distinto.
 Las funciones son un conjunto de instrucciones que realizan una tarea específica. En general toman unos valores de entrada, llamados parámetros y proporcionan.
PROGRAMACION DE Pilas o Stacks y Colas
MEMORIA DINÁMICA.
PUNTEROS. Los punteros son de amplia utilización en programación y muchos lenguajes permiten la manipulación directa o indirecta de los mismos. Su razón.
¿Cómo programar un Botón para agregar registros a una base de datos?
ARRAYS Y COLECCIONES DE DATOS. ARRAYS Arrays – Matriz – Vector Elemento del lenguaje que nos permite agrupar un conjunto de valores del mismo tipo, y.
LE, EI, Profesor Ramón Castro Liceaga UNIVERSIDAD LATINA (UNILA) V. GESTIÓN DE TIPOS Y GENERACIÓN DE CÓDIGOS.
Listas Dinámicas.
Programación orientada a objetos La programación orientada a objetos o POO (OOP según sus siglas en inglés) es un paradigma de programación que usa objetos.
Métodos en Java. Estructura de un programa en Java ► La relación con la vida misma la podemos ver en el siguiente comentario: Imaginemos que dos clases.
:: Prof. Yeniffer Peña Programación I Programación Orientada a Objetos Presentación.
Prof. Manuel B. Sánchez.  El origen del término polimorfismo es simple: proviene de las palabras griegas poly (muchos) y morphos (forma) multiforme.
Omar Herrera Caamal Rigoberto Lizárraga Luis Cetina Luna.
Transcripción de la presentación:

1 Compilación, pereza y expresiones let(rec)

2 Compilando un programa Describiremos un compilador para la máquina minimal usando un conjunto de esquemas de compilación. Cada supercombinador será compilado con el esquema SC, el que a su vez está definido en función de un esquema R, que es el que efectivamente genera código-G. Este esquema genera una secuencia de instrucciones que respeta el esquema visto en la clase pasada: primero la secuencia de instrucciones para instanciar el cuerpo del supercombinador, y luego las instrucciones Slide y Unwind. El grafo del cuerpo será generado por la función C.

3 Compilando un programa (2) SC [d] es el código-G generado para la definición d de un supercombinador: SC [f x 1... x n = e ] = R [ e ] [ x 1  x n  n  n R [ e ] genera código que instancia la expresión e en environment , para un supercombinador de aridad n, y luego procede a desplegar el stack: R [ e ]  n = C [ e ]  ++ [Slide n + 1, Unwind]

4 Compilando un programa (3) Finalmente, C [e ] r genera código que construye el grafo de la expresión e en environment , dejando un puntero al resultado en el tope del stack: C [ f ]  = [Pushglobal f] f supercombinador C [ x ]  = [Push (  x) ] x variable local C [ i ]  = [Pushint i] i es un número C [ f e ]  = C [ e ]  ++ C [ f ]  [Mkap] donde  +n x = (  x) + n

5 Un ejemplo de compilación Veamos ahora como ejemplo el código que se genera para el combinador K. Comenzaremos evaluando la expresión: SC [ “K”, [“x”, “y”], Evar “x”] Un paso de reducción nos da: R [Evar “x”] [ x |-> 0... y |-> 1 ] 2 y uno más C [Evar “x”] [ x |-> 0... y |-> 1 ] ++ [Slide 3, Unwind]

6 Un ejemplo de compilación Para compilar el cuerpo del supercombinador efectuamos un lookup de x, que está en el tope del stack. Entonces generamos código para hacer una copia del tope del stack usando la instrucción Push 0. [Push 0, Slide 3, Unwind]

7 Una máquina lazy Introducimos ahora un pequeño cambio a la máquina para poder hacerla perezosa, ya que hasta ahora la máquina no sobreescribe la raíz del redex antes de efectuar el unwinding. Si éste estuviera compartido evaluaciones podrían ser repetidas. En la nueva máquina lo que haremos será sobreescribr la raíz de la expresión original con un nodo de indirección, el que apuntará a la nueva instancia construída. El efecto es que la máquina “recuerda” el valor calculado. Para eso introduciremos las instrucciones Update y Pop.

8 Una máquina lazy Hasta ahora el código para cada supercombinador termina con la secuencia [Slide n + 1, Unwind], donde n es la aridad del SC. Para capturar la noción de actualización reemplazaremos esta secuencia con [Update n, Pop n, Unwind] La instrucción Update se encarga de sobreescribir la raíz del redex. La instrucción Pop se usa para remover los argumentos del stack que ya no son necesarios.

9 Una máquina e n e f e 1 e e Antes de ejecutar Slide (n+1) Después

10 Una máquina e n e f e 1 e f e i) Antes de Update n ii) Después de Update n # e iii) Después de Pop n

11 Update, Pop y Unwind Update n : i a : a 0 :... : a n : s h m => i a 0 :... : a n : s h[a n :NInd a] m Pop n : i a 0 :... : a n-1 : s h m => i s h m El efecto de Update n es sobreescribir el n+1 -ésimo item del stack con un nodo de indirección al item en el tope. Pop n simplemente remueve n items del stack. [Unwind] a 0 : s h[a 0 :NInd a] m => [Unwind] a : s h m

12 Modificación al esquema R Para que el compilador se comporte como hemos especificado, ahora debemos introducir una primer modificación al esquema de compilación R: R [ e ] genera código que instancia la expresión e en environment , para un supercombinador de aridad n, y luego procede a desplegar el stack: R [ e ]  n = C [ e ]  ++ [Update n, Pop n, Unwind]

13 Expresiones let(rec) Ahora extenderemos al compilador y la máquina que hemos construído para que aceptan expresiones let(rec) en el cuerpo de un supercombinador. Estas expresiones son definidas en el tipo Expr a por el constructor ELet, que toma como argumentos un boolean que indica si las definiciones son recursivas o no, las definiciones y la expresión en que las definiciones serán usadas. Antes de efectuar la extensión, definiremos una forma más eficiente de acceder a las variables del stack.

14 Acceso a argumentos Supongamos que el proceso de unwinding ha encontrado un nodo f de SC y que éste toma n argumentos. En la máquina que estamos considerando, el stack luciría de la e n e f e

15 Acceso a argumentos (2) En la nueva versión de la máquina el stack se verá modificado como e f e2e2 Los n elementos al tope del stack ahora apuntan directa- mente a las expresiones e 1...e n. El punto importante es que aho- ra tenemos acceso rápido a las variables. Esto mejora la eficien- cia de acceso a las expresiones que sustituirán a los paráme- tros formales. Notar puntero a raíz.

16 Modificación de instrucciones Una vez que elegimos modificar el stack también tendremos que modificar algunas de las instrucciones. Las afectadas son las instrucciones Push y Unwind. La instrucción Push no necesitará más mirar “a través de los nodos de aplicación”. Push n : i a 0 :... : a n : s h m => i a n : a 0 :... : a n : s h m

17 Modificación de instrucciones (2) La otra modificación requerida es que Unwind debe reacomodar el stack. Este reacomodamiento es requerido siempre que un SC con suficientes argumentos es localizado al tope del stack. La nueva regla de transición para Unwind es: [Unwind] a 0 :... : a n : s h[a 0 :NGlobal n c, m a 1 : NAp a 0 a´ 1... a n : NAp a n-1 a´ n ] => c a´ 1 :... : a´ n : a n : s h m

18 Variables localmente ligadas Retornamos a la implementación de expresiones let(rec), considerando primero el caso no recursivo. Las variables x 1... x n en la expresión let x 1 = e 1... x n = e n in e pueden ser tratadas de la misma forma que lo son los argumentos a combinadores, una vez que las expresiones e 1... e n han sido creadas. Es decir accedemos a las variables x 1... x n por medio de offsets en el stack, usando el environment para registrar su posición. Supongamos que el código para construír las definiciones locales es Code. La siguiente secuencia de acciones será entonces necesaria:

19 Variables localmente ligadas (2) e1e1 enen e1e1 enen e e Inicialmente Después de Code Después de construír e Al final

20 Variables localmente ligadas (3) Como hemos agregado n nuevas variables en el stack, esto debe ser considerado en el esquema de compilación. El código para construír las ligaduras locales (Code) simplemente construirá el código de cada e i dejando las direcciones de esas piezas de grafo en el stack. Luego de construír el cuerpo de la expresión e, el que puede usar cualquiera de las x i, los punteros a las expresiones e i deben ser removidos del stack. Esto se logrará haciendo uso de una instrucción Slide. La situación con definiciones locales recursivas es más complicado, ya que cada una de las e i debe ser compilada de tal forma que todas las variables x i estén en alcance.

21 Variables localmente ligadas (4) Para lograr esto último se crearán nodos vacíos en el grafo dejando además punteros a ellos en el stack. Luego cada expresión e i es compilada usando el mismo mapeo de variables que el usado en el caso no recursivo. Al final de cada código compilado para las expresiones pondremos un Update, cuya función será sobreescribir el nodo vacío con la pieza correspondiente de grafo. Esto último lo lograremos usando una nueva instrucción, Alloc n, la que creará n nodos vacíos (que serán representados con el símbolo ?). El proceso que se ilustra a continuación deberá ser repetido hasta que cada una de las e i sea procesada. El código para e es compilado en forma similar al caso no recursivo.

22 Variables localmente ligadas (5) ? ? ? ? e1e1 Alloc n Después de construír e 1 # ? e1e1 Después de actualizar e 1 Inicialmente

23 Alloc Para esta versión de la máquina entonces necesitaremos agregar la instrucción Alloc, que crea n lugares en el heap. Usaremos estos lugares para marcar donde guardaremos las expresiones ligadas en las definiciones. Estos nodos son inicialmente creados como nodos de indirección que apuntan a una dirección ilegal de heap: hNull (esto no importa ya que esos nodos serán sobreescritos). Alloc n : i s h m => i a 1 :... : a n : s h [a 1 : Nind hNull m... a n : Nind hNull]

24 Modificación del esquema C C [ let x 1 = e 1 ;... ; x n = e n in e ]  = C [ e 1 ]    C [ e n ]   n  ++ C [ e ]  ’ ++ [Slide n]  ’ =   n [ x 1 |-> n-1,..., x n |-> 0] C [ let rec x 1 = e 1 ;... ; x n = e n in e ]  = [Alloc n] ++ C [ e 1 ]  ’ ++ [Update n-1] C [ e n ]  ’ ++ [Update 0] C [ e ]  ’ ++ [Slide n]  ’ =   n [ x 1 |-> n-1,..., x n |-> 0]

25 Compilando Y Y f = letrec x = f x in x SC [ “Y”, [“f “], ELet True [( “x”, EAp (Evar “f”) (Evar “x”))] (Evar “x”) ] R [ELet True [( “x”, EAp (Evar “f”) (Evar “x”))] (Evar “x”) ] [(“f “, 0)] 1 C [ELet True [( “x”, EAp (Evar “f”) (Evar “x”))] (Evar “x”) ] [(“f “, 0)] ++ [Update 1, Pop 1, Unwind] [Alloc 1] ++ C [EAp (Evar “f”) (Evar “x”)] p ++ [Update 0] ++ C [Evar “x”] p ++ [Slide 1] ++ [Update 1, Pop 1, Unwind] where p = [(“x”, 0), (“f “, 1)]

26 Compilando Y (2) [Alloc 1] ++ [Push 0, Push 2, Mkap] ++ [Update 0] ++ [Push 0] ++ [Slide 1] ++ [Update 1, Pop 1, Unwind]