Compiladores. Guía 10 1 Facultad: Ingeniería Escuela: Computación Asignatura: Compiladores 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 Guía de Laboratorio Nº 10. Computadora con programa Dev C++ Introducción Teórica Guía 3 guía se abordarán los conceptos pertenecientes al En esta componente de generación de código, se implementara un Guía 4 generador de código en lenguaje C++ para el compilador del lenguaje MUSIM. fía 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 Guía 3 guía vamos a implementar el generador de código para En esta nuestro mini proyecto del compilador MUSIM a ENSAMPOCO, para Guía 4 ello crearemos dos archivos en C++, uno de cabecera o extensión “.h” y uno de desarrollo extensión “.cpp”. fía 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 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); } el 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 10 1 Hoja de cotejo: Guía 10: Generación de código Docente: Máquina No: Máquina No: Alumno: Máquina No: GL: Alumno: Docente: GL: Docente: GL: Fecha: a EVALUACION % 1-4 5-7 8-10 CONOCIMIENTO Del 20 al 30% 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% 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. ACTITUD Del 15% al 30% TOTAL 100% Nota