Compiladores. Guía 10 1 Tema: Generación de código intermedio Objetivos Específicos Conocer las características y principal función de un generador de código. Analizar el funcionamiento, entrada y salida de un generador de código de un compilador. Implementar un generador de código para el lenguaje MUSIM. Material y Equipo Facultad: Ingeniería Escuela: Computación Asignatura: Compiladores Guía de Laboratorio Nº 10. Computadora con programa Dev C++ Introducción Teórica En esta guía se abordarán los conceptos pertenecientes al componente de generación de código, se implementara un generador de código en lenguaje C++ para el compilador del lenguaje MUSIM. Generación de código. La entrada para el generador de código consta de la representación intermedia del programa fuente producida por la etapa inicial junto con la información de la tabla de símbolos que se utilizan para determinar las direcciones de los objetos de datos durante la ejecución denotados por los hombres de la representación intermedia. Representaciones lineales: Tercetos Cuartetos Máquinas a pila Representaciones arborescentes: Árboles de análisis sintácticos Grafos dirigidos a cíclicos
2 Compiladores. Guía 10 Programas objeto: La salida del generador de código es un código preparado y adaptado para ser ejecutado, directa, o indirectamente, en una arquitectura específica. La adaptación consiste en aprovechar al máximo las características de la máquina para optimizar la ejecución en tiempo y en memoria. Lenguaje de máquina absoluto: El programa se coloca en una posición fija de memoria y se ejecuta inmediatamente. Un programa pequeño se puede compilar y ejecutar rápidamente pero demanda ubicaciones específicas de memoria. Lenguaje de máquina reubicable: Un programa reubicable permite que los subprogramas se compilen por separado. Los módulos se cargan y enlazan mediante un montador o enlazador. Se gana flexibilidad al poder compilar subrutinas por separado y llamarlas desde otros módulos. Si la máquina objeto no maneja reubicación automática el compilador debe proporcionar al montador información para que enlace los segmentos del programa. Lenguaje Ensamblador: El lenguaje ensamblador facilita el proceso de generación de código (se utilizan instrucciones simbólicas y macros). A cambio debe producirse un ensamblado tras la generación de código. Esto es útil en arquitecturas con poca memoria. Administración de la Memoria: Uno de los propósitos de la generación de código final es la traducir la representación simbólica en código intermedio de etiquetas y objetos de datos (variables, temporales, parámetros, etc.) a direcciones reales en el mapa físico de memoria.
Compiladores. Guía 10 3 Asignación de Registros: Las instrucciones que operan con registros son más cortas y rápidas. Realizar un uso eficiente de los registros es fundamental para generar buen código. Selección de instrucciones: La generación de código intermedio debe tener en cuenta el juego de instrucciones de la máquina destino. Las traducciones a código objeto debe ser, además de correcta, eficiente. Procedimiento En esta guía vamos a implementar el generador de código para nuestro mini proyecto del compilador MUSIM a ENSAMPOCO, para ello crearemos dos archivos en C++, uno de cabecera o extensión.h y uno de desarrollo extensión.cpp. Primero debe buscar su proyecto de este compilador creado en la guía 6 de analizador sintáctico. Abra el programa Dev C++ y abra el respectivo archivo de proyecto que tiene creado previamente (poseerá una extensión de archivo.dev ).
4 Compiladores. Guía 10 Posteriormente, añada al proyecto digite el siguiente código: un archivo fuente. Luego genera.h #ifndef GENERA_H #define GENERA_H #include <stdio.h> #include <iostream.h> #include <stdlib.h> class GeneraCodigo char *nombrefichero; // Nombre del fichero objeto de salida FILE *salida; // Fichero objeto de salida public: GeneraCodigo(char *unnombrefichero); ~GeneraCodigo(); void code(); void pushc(char constante); void pusha(char direccion); void load(); void store(); void neg(); void add(); void mul(); void div(); void mod(); void input(char direccion); void output(char direccion); void end(); ; #endif Al terminar deberá guardar el archivo con el nombre genera.h. A continuación agregara al proyecto otro archivo fuente. Dentro de este escribirá las definiciones de la clase declarada en el archivo anterior. Digite el siguiente codigo:
Compiladores. Guía 10 5 genera.cpp #include "genera.h" GeneraCodigo::GeneraCodigo(char *unnombrefichero) if ((salida=fopen(unnombrefichero,"w"))==null) cout<<"no se puede crear el fichero"<<unnombrefichero<<endl; exit(-3); GeneraCodigo::~GeneraCodigo(void) fclose(salida); void GeneraCodigo::code() cout<<".code"<<endl; fputs(".code\n",salida); void GeneraCodigo::pushc(char constante) cout<<"pushc "<<constante<<endl; fputs("pushc ",salida); fputc(constante,salida); fputc('\n',salida); void GeneraCodigo::pusha(char direccion) cout<<"pusha "<<direccion<<endl; fputs("pusha ",salida); fputc(direccion,salida); fputc('\n',salida); void GeneraCodigo::load() cout<<"load"<<endl; fputs("load\n",salida); void GeneraCodigo::store() cout<<"store"<<endl; fputs("store\n",salida);
6 Compiladores. Guía 10 void GeneraCodigo::neg() cout<<"neg"<<endl; fputs("neg\n",salida); void GeneraCodigo::add() cout<<"add"<<endl; fputs("add\n",salida); void GeneraCodigo::mul() cout<<"mul"<<endl; fputs("mul\n",salida); void GeneraCodigo::div() cout<<"div"<<endl; fputs("div\n",salida); void GeneraCodigo::mod() cout<<"mod"<<endl; fputs("mod\n",salida); void GeneraCodigo::input(char direccion) cout<<"input "<<direccion<<endl; fputs("input ",salida); fputc(direccion,salida); fputc('\n',salida); void GeneraCodigo::output(char direccion) cout<<"output "<<direccion<<endl; fputs("output ",salida); fputc(direccion,salida); fputc('\n',salida); void GeneraCodigo::end() cout<<"end"<<endl; fputs("end\n",salida); Posteriormente, guarde el archivo con el nombre genera.cpp. Luego proceda a compilar el proyecto.
Compiladores. Guía 10 7 Análisis de resultados Vamos a integrar el generador de código al analizador sintáctico de la guía 6. Para ello dentro del analizador sintáctico, cree un objeto de la clase de generación de código y en los procedimientos que corresponda, llamar a las operaciones del generador de código que genere el código adecuado. Ahora coloque el siguiente archivo de texto en la misma carpeta para compilarlo. Corresponde a un pequeño programa en MUSIM/0. prueba.txt M R a; R b; c = a + b; W c; Pruebe su compilador sobre el archivo indicado. Investigación complementaria Investigue la generación de código ensamblador (asm) INTEL con Dev C++. Investigue las características y ventajas de los compiladores de una y varias pasadas. Bibliografía http://en.wikipedia.org/wiki/code_generation_%28compiler %29 Cuadernos didácticos. Conceptos básicos de procesadores de lenguaje. Juan Manuel Cueva Lovelle. Oviedo, Diciembre 1998.
8 Compiladores. Guía 10 Guía 10: Generación de código Hoja de cotejo: 10 Alumno: Máquina No: Docente: GL: Fecha: EVALUACION CONOCIMIENTO Del 20 al 30% % 1-4 5-7 8-10 Nota Conocimie nto deficient e de los fundament os teóricos Conocimiento y explicación incompleta de los fundamentos teóricos Conocimiento completo y explicación clara de los fundamentos teóricos APLICACIÓN DEL CONOCIMIENTO Del 40% al 60% ACTITUD Del 15% al 30% TOTAL 100% No tiene actitud proactiva. Actitud propositiva y con propuestas no aplicables al contenido de la guía. Tiene actitud proactiva y sus propuestas son concretas.