Compiladores. Guía 9 1 Facultad: Ingeniería Escuela: Computación Asignatura: Compiladores Tema: Generación de código Contenido 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/3. 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/3. Material y Equipo Guía de Laboratorio Nº 9. Computadora con programa Dev C++ Introducción Teórica Generación de código. Guía 3 Entrada al generador de código: La entrada para el generador de código consta de la Guía 4 representación intermedia del programa fuente producida por la etapa inicial junto con la información de la tabla de fía 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. 2 Compiladores. Guía 9 • Representaciones lineales: Tercetos Cuartetos. Máquinas a pila. • Representaciones arborescentes: Árboles de análisis sintácticos. Grafos dirigidos a cíclicos. 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 9 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 baserrrg En esta guía vamos a implementar el generador de código para nuestro proyecto del compilador MUSIM/3 a ENSAMPOCO, para Guíacrearemos 3 ello un archivo en C++ de cabecera o extensión “.h” que contendrá la clase que corresponderá a nuestro generador de código. Guía 4 Primero debe buscar su proyecto de este compilador actualizado con el analizador semántico de la guía anterior fía 4 Compiladores. Guía 9 (procedimiento guía 8). Abra el programa “Dev C++” y abra el respectivo archivo de proyecto que tiene creado previamente (poseerá una extensión de archivo “.dev”). Posteriormente, añada al proyecto un archivo fuente. Luego digite el siguiente código: genera.h #ifndef GENERA_H #define GENERA_H #include <stdio.h> #include <iostream> #include <stdlib.h> using namespace std; 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 *tipo,char direccion); void load(char *tipo); void store(char *tipo); void neg(char *tipo); void add(char *tipo); void mul(char *tipo); void div(char *tipo); void mod(char *tipo); void input(char *tipo,char direccion); void output(char *tipo,char direccion); void end(); void abs(char *tipo); void data(); void declaracion(char tipo, char *id); void i2tof(); void itof(); void ipushc(char *constante); void exp(char *tipo); void sin(char *tipo); void tan(char *tipo); }; GeneraCodigo::GeneraCodigo(char *unNombreFichero) { if ((salida=fopen(unNombreFichero,"w"))==NULL) { Compiladores. Guía 9 5 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); fputs(constante,salida); fputs("\n",salida); } void GeneraCodigo::pusha(char *tipo,char direccion) { cout<<tipo<<"PUSHA "<<direccion<<endl; fputs(tipo,salida); fputs("PUSHA ",salida); fputc(direccion,salida); fputc('\n',salida); } void GeneraCodigo::load(char *tipo) { cout<<tipo<<"LOAD"<<endl; fputs(tipo,salida); fputs("LOAD\n",salida); } void GeneraCodigo::store(char *tipo) { cout<<tipo<<"STORE"<<endl; fputs(tipo,salida); fputs("STORE\n",salida); } void GeneraCodigo::neg(char *tipo) { cout<<tipo<<"NEG"<<endl; fputs(tipo,salida); fputs("NEG\n",salida); } el 6 Compiladores. Guía 9 void GeneraCodigo::add(char *tipo) { cout<<tipo<<"ADD"<<endl; fputs(tipo,salida); fputs("ADD\n",salida); } void GeneraCodigo::mul(char *tipo) { cout<<tipo<<"MUL"<<endl; fputs(tipo,salida); fputs("MUL\n",salida); } void GeneraCodigo::div(char *tipo) { cout<<tipo<<"DIV"<<endl; fputs(tipo,salida); fputs("DIV\n",salida); } void GeneraCodigo::mod(char *tipo) { cout<<tipo<<"MOD"<<endl; fputs(tipo,salida); fputs("MOD\n",salida); } void GeneraCodigo::input(char *tipo,char direccion) { cout<<tipo<<"INPUT "<<direccion<<endl; fputs(tipo,salida); fputs("INPUT ",salida); fputc(direccion,salida); fputc('\n',salida); } void GeneraCodigo::output(char *tipo,char direccion) { cout<<tipo<<"OUTPUT "<<direccion<<endl; fputs(tipo,salida); fputs("OUTPUT ",salida); fputc(direccion,salida); fputc('\n',salida); } void GeneraCodigo::end() { cout<<"END"<<endl; fputs("END\n",salida); } void GeneraCodigo::abs(char *tipo) { Compiladores. Guía 9 7 cout<<tipo<<"ABS"<<endl; fputs(tipo,salida); fputs("ABS\n",salida); } void GeneraCodigo::data() { cout<<".DATA"<<endl; fputs(".DATA\n",salida); } void GeneraCodigo::declaracion(char tipo, char *id){ switch (tipo) { case 'I': cout<<"INT "<<id<<endl; fputs("INT ",salida); fputs(id,salida); fputs("\n",salida); break; case 'F': cout<<"FLOAT "<<id<<endl; fputs("FLOAT ",salida); fputs(id,salida); fputs("\n",salida); break; case 'C': cout<<"CHAR "<<id<<endl; fputs("CHAR ",salida); fputs(id,salida); fputs("\n",salida); break; default: cout<<"Tipo desconocido error\n"; exit(-(100)); } } void GeneraCodigo::i2tof() { cout<<"I2TOF"<<endl; fputs("I2TOF\n",salida); } void GeneraCodigo::itof() { cout<<"ITOF"<<endl; fputs("I2TOF\n",salida); } void GeneraCodigo::ipushc(char *constante) { cout<<"IPUSHC "<<constante<<endl; 8 Compiladores. Guía 9 fputs(constante,salida); fputs("\n",salida); } void GeneraCodigo::exp(char *tipo) { cout<<tipo<<"EXP"<<endl; fputs(tipo,salida); fputs("EXP\n",salida); } void GeneraCodigo::sin(char *tipo) { cout<<tipo<<"SIN"<<endl; fputs(tipo,salida); fputs("SIN\n",salida); } void GeneraCodigo::tan(char *tipo) { cout<<tipo<<"TAN"<<endl; fputs(tipo,salida); fputs("TAN\n",salida); } #endif Posteriormente, guarde el archivo con el nombre “genera.h”. Luego proceda a compilar el proyecto. Análisis de resultados Proceda a integrar el analizador sintáctico y analizador semántico al generador de código presentado anteriormente para terminar la parte de traducción correspondiente al compilador de MUSIM/3 desarrollado durante varias de las prácticas de laboratorio. Aun nos resta añadir al proyecto la interfaz principal del compilador. A continuación en el archivo “ppal.cpp” de su proyecto escriba el siguiente código, el cual sustituirá el contenido anterior; recuerde que al haber adaptado e integrado tanto el analizador semántico como el generador de código con el analizador sintáctico, su parámetros de instanciación han cambiado y ahora incluyen el archivo de salida del resultado de la compilación, es decir el código en lenguaje objeto. ppal.cpp /* Compiladores. Guía 9 9 Compilador de MUSIM/3 */ #include <cstdlib> #include <iostream> #include <string.h> #include <stdlib.h> #include "sintacti.h" using namespace std; int main (int argc, char *argv[]) { int traza; char fuente[40]={'\0'}; char objeto[40]={'\0'}; char d; bool correcto=false; do{ cout<<"Compilador MUSIM/3-EMSAMPOCO/0 Versión 3.0"<<endl; cout<<" -Fich_fuente (MUSIM/3):"<<endl; fflush(stdin); gets(fuente); cout<<" -Fich_objeto:"<<endl; fflush(stdin); gets(objeto); if((fuente!='\0')) { traza=1; correcto=true; } else { cout<<"Datos erroneos, Desea salir del programa?s/n: "; cin>>d; if(d=='s') break; } }while(!correcto); if (!correcto) { cout<<"Saliendo de la aplicacion..."<<endl; } else { Sintactico sintactico(fuente,objeto,traza); } system("pause"); 10 Compiladores. Guía 9 return 0; } Ahora coloque el siguiente archivo de texto en la misma carpeta para compilarlo. Corresponde a un pequeño programa en MUSIM/3. prueba.txt M{ I a; I b; F c; F d; R a; R b; c=a+b; d=a-b; W c; W d; }. Pruebe su compilador sobre el archivo indicado. Investigación complementaria Realice un cuadro resumen de las principales instrucciones de lenguaje ensamblador 8086, que incluya su descripción, forma de uso y un ejemplo por cada uno de ellos. Mínimo 15 instrucciones. 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. Compiladores. Guía 9 11 9 1 Hoja de cotejo: Guía 9: Generación de código Docente: Tema: Presentación del programa 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