Compiladores. Guía 1 1 Facultad: Ingeniería Escuela: Computación Asignatura: Compiladores Tema: Introducción a compiladores y MUSIM/0 Contenido En esta guía se presenta una breve introducción a los conceptos básicos que se utilizan en el ámbito de los compiladores y se familiarizara al alumno con el lenguaje al cual se le desarrollará un compilador a lo largo de las prácticas. Objetivos Específicos Entender los conceptos básicos de compiladores. Conocer los lenguajes que se utilizaran siguientes prácticas. en las Material y Equipo Guía de Laboratorio Nº 1. Computadora con DevC++ Introducción Teórica Lenguajes de Programación Guía 3 La programación de computadoras se realiza en los llamados lenguajes de programación, éstos posibilitan la comunicación entre Guía 4el programador y la computadora, a través de un conjunto de instrucciones u órdenes especificadas por el lenguaje. fía Un lenguaje de programación puede definirse como “una notación formal para describir algoritmos o funciones que serán ejecutados por el ordenador”. Según su grado de independencia de la maquina, los lenguajes de programación se clasifican en: 2 Compiladores. Guía 1 Lenguaje maquina: Es la notación que entiende directamente el ordenador, por eso sus instrucciones están escritas con código binario. El repertorio de sus instrucciones, así como la estructura de estas, están ligadas directamente a la arquitectura de la maquina. Lenguaje ensamblador: es esencialmente una versión simbólica de un lenguaje maquina. Cada código de operación se indica por un código simbólico. Por ejemplo ADD para adición y MUL para multiplicación. Lenguajes de nivel medio: tienen algunas de las características de los lenguajes de bajo nivel (por ejemplo acceso directo a posiciones de memoria), añadidas a posibilidades de manejo de estructuras de control y de datos de lenguajes de alto nivel. Lenguajes de alto nivel: facilitan la escritura de programas con estructuras de datos complejas, la utilización de bloques, y procedimientos o subrutinas. Dentro de estos lenguajes destacan un tipo de lenguajes, denominados lenguajes orientados a objetos, que permiten definir tipos abstractos de datos. Lenguajes de orientados a problemas concretos: se utilizan para la resolución de problemas en un campo específico. Procesadores de lenguaje Procesadores de lenguajes es el nombre genérico que reciben todas las aplicaciones informáticas en las cuales uno de los datos fundamentales de entrada es un lenguaje. La definición anterior afecta una gran variedad de herramientas software, entre las cuales tenemos: Traductores: Es un programa que procesa un texto fuente y genera un texto objeto Ensamblador: Si el lenguaje fuente es el lenguaje ensamblador y el lenguaje objeto es el lenguaje maquina, entonces al traductor se le llama ensamblador. Compiladores: Un traductor que transforma texto fuente de lenguajes de alto nivel a lenguajes de bajo nivel se le denomina compilador. Intérprete: Son programas que simplemente ejecutan las instrucciones que se encuentran en el texto fuente. Traductores Como ya se menciono, un traductor es un programa que procesa un texto fuente y genera un texto objeto. El traductor está escrito en lenguaje de implementación (LI) o también Compiladores. Guía 1 3 denominado lenguaje host. El texto fuente está escrito en lenguaje fuente (LF), por ejemplo un lenguaje de alto nivel. El texto objeto está escrito en lenguaje objeto (LO), por ejemplo un lenguaje de máquina, ensamblador u otro lenguaje de alto nivel. Se suele utilizar la notación T, la cual se muestra en la siguiente figura La notación T también se puede representar de forma abreviada como: LFLILO. Estructura general de un traductor Todas las fases de un traductor se pueden agrupar en dos áreas: el análisis del programa fuente y su síntesis en el correspondiente programa objeto. El análisis consiste en verificar la corrección del programa fuente, para lo cual se descompone el programa fuente en trozos elementales o unidades mínimas sintácticas denominadas componentes léxicos o tokens. Los tokens se pueden agrupar para comprobar su disposición correcta en las distintas construcciones y sentencias del lenguaje a analizar (análisis sintáctico y semántico). Comprobándose de esta forma la validez sintáctica y semántica del programa fuente. En caso contrario se emiten los errores oportunos (manejo de errores). La información también se utiliza durante la fase de análisis (por ejemplo ara comprobar si una variable se intentó declarar dos veces). La tarea de síntesis tiene por objeto la generación del código del lenguaje objeto. En el caso particular de los compiladores suele incluirse también la generación de código intermedio, como un medio para garantizar la transportabilidad entre distintas maquina objeto o como método para poder utiliza el mismo back-end, entre compiladores de lenguajes diferentes. La generación de código intermedia se apoya directamente en la información recogida en la tabla de símbolos durante la fase de análisis. La generación de código para la máquina objeto definitiva tan solo se apoya en el código intermedio. También es necesario un tratamiento de errores para la fase de síntesis. 4 Compiladores. Guía 1 La siguiente figura muestra las fases de un traductor: Procedimiento MUSIM/0 Guía 3 Los componentes léxicos o tokens que conforman el lenguaje son los4 siguientes: Guía fía Identificadores, que están compuestos por a-z. Constantes numéricas Operadores: +,-,*,/, solo son nombres de variables y una única letra minúscula de rango de un solo digito, de rango 0-9. y %. Compiladores. Guía 1 5 Símbolo de asignación: = (igual). Paréntesis: ( y ). Separador de sentencias: ; (punto y coma). Indicadores de principio y fin de bloque: { y }. Palabras reservadas que están formadas por una letra mayúscula. Tan solo son tres: R (lectura), W(escritura) y M (programa principal). Puede observarse que este lenguaje solo permite tres tipos de sentencias: lectura, asignación y escritura. Tiene un solo tipo de datos: entero. Las variables están formadas por una única letra minúscula, y las constantes son de un dígito. Tiene cinco operadores +(adición), -(diferencia), *(producto), /(división entera), y %(modulo). Se permite el uso de paréntesis. Ejemplo 1: M { R R c W } a; b; = a + b; c; Analicemos lo que hace este programa: “R a” y “R b” indica que le leen las variables a y b. “c = a + b” indica que en la variable c se asignara el resultado de la suma de a y b. “W c” indica que se escribirá la variable c. En pocas palabras, este programa leerá dos variables, las sumara y finalmente mostrará el resultado en pantalla. 6 Compiladores. Guía 1 Ejercicio 1 M { R a; R b; R c; p = (a + b + c)/3; W p; } Describa lo que hace el programa anterior según las definiciones del lenguaje: _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ Ejercicio 2 M { R R r W } a; b; = (a * a) + (b * b); r; Describa lo que hace el programa anterior: _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ Ejercicio 3 Escriba un programa en MUSIM/0 que lea un número, calcule y muestre en pantalla cuanto es ese número elevado al cubo. _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ Compiladores. Guía 1 7 Ejercicio 4 Escriba un programa en MUSIM/0 que lea 5 números, calcule y muestre en pantalla: la suma, promedio y multiplición de los 5 números. _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ Ejercicio 5 Escriba un programa en MUSIM/0 que lea un número y determine si este es par o impar. Si es par deberá mostrar 0 en pantalla, mientras que si es impar deberá mostrar 1 _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ ENSAMPOCO/0 Como lenguaje objeto se utiliza un lenguaje intermedio que es un pequeño ensamblador, que se denomina ENSAMPOCO/0. Este ensamblador trabaja sobre una maquina abstracta, en este caso particular es una máquina de pila. La maquina tendrá una memoria de 26 celdas cuyas direcciones se nombrarán con las letras de la ‘a’ a la ‘z’, y una pila LIFO donde se realizarán las operaciones aritméticas. A continuación se describe distintas instrucciones. la forma de trabajo de las Instrucción Descripción .CODE Indica el comienzo del código. PUSHC Coloca una constante en la pila. El operando es una constante. PUSHA Coloca en la pila la dirección de una variable. El operando es una variable, dado que las direcciones se denominan con el nombre de las variables. LOAD Asume que el último valor insertado en la pila es una dirección. Esta dirección es extraída de la pila y en su lugar se pone el valor ubicado en dicha dirección. No tiene operando. 8 Compiladores. Guía 1 STORE NEG ADD MUL DIV MOD INPUT OUTPUT END Usa los dos últimos elementos de la pila. Uno es la dirección de una celda y memoria y el otro el valor a almacenar en dicha celda. El último elemento de la pila es el valor y el otro la dirección. Después de ejecutada la instrucción, los dos elementos implicados son extraídos de la pila, dejándolos en el mismo lugar. No tiene operando. Cambia el signo del último valor introducido en la pila, dejándolo en el mismo lugar. No tiene operando. Cambia el signo del último valor introducido en la pila, dejándolo en el mismo lugar. No tiene operando. Opera con los dos últimos elementos introducidos en la pila, extrayéndolos y dejando en su lugar el producto. Por tanto la pila habrá disminuido en un elemento. No tiene operando. Opera con los dos últimos elementos introducidos en la pila, extrayendo primero el denominador y después el numerador y dejando en su lugar la división entera. Por tanto la pila habrá disminuido en un elemento. No tiene operando. Opera con los dos últimos elementos introducidos en la pila, extrayendo primero el denominador y después el numerador y dejando en su lugar el modulo. Por tanto, la pila habrá disminuido en un elemento. No tiene operando. Toma el valor del buffer de entrada, en este caso el teclado, y lo coloca en la dirección asignada a la variable. La pila no sufre cambios. Toma el valor de la dirección indicada y lo lleva al buffer de salida, en este caso la pantalla. La pila no sufre cambios. Indica el fin de programa. Ejemplo 3 A continuación se muestran un programa fuente en MUSIM/0, y su traducción al código intermedio ENSAMPOCO/0 Compiladores. Guía 1 9 Código en MUSIM/0 M { R R z W } a; b; = a + b; z; Traducción a ENSAMPOCO/0 .CODE INPUT a INPUT b PUSHA z PUSHA a LOAD PUSHA b LOAD ADD STORE OUTPUT z END Ejercicio 6 Traducir el siguiente código en MUSIM/0 A ENSAMPOCO/0 M { R a; R b; z = a + b - 2; W z; } Traducción a ENSAMPOCO/0 _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ 10 Compiladores. Guía 1 Ejercicio 7 Traducir el siguiente código en MUSIM/0 a ENSAMPOCO/0 M{ R a; R b; R c; q = (a * a) + (b * b) + (c * c); W q; } _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ _____________________________________________________________ Análisis de resultados Lenguaje Micro C o C-: El lenguaje Micro C es un subconjunto pequeño del lenguaje de programación C. Como referencia utilice el Apéndice A “Proyecto de Compilador” del libro Construcción de Compiladores de Kenneth C. Louden, el cual define al lenguaje de programación denominado C Minus o C-. Micro-C es un lenguaje case sensitive, es decir que el compilador de este lenguaje trata a las letras mayúsculas y minúsculas como caracteres diferentes. Los comentarios y caracteres ignorados. Los comentarios son secuencias de carácter incluido dentro de par de secuencias de /*…*/ pareados. Los comentarios pueden extender sobre varias líneas, pero los comentarios anidados Compiladores. Guía 1 11 no se reconocen, es decir que el primer encontrado */ dentro de un comentario lo cierra. Otros caracteres ignorados incluyen el newline, la tabulación horizontal, el CR, y el espacio blanco. Tokens Las secuencias de caracteres encerrados dentro de dos apóstrofes (') son símbolos terminales. Cualquier otra secuencia de caracteres denota el nombre de una clase léxica, por ejemplo: En secciones posteriores léxicas siguientes: utilizaremos las definiciones • letra = ' _ ' | ' a ' | ' b ' |... | ' z ' | ' A ' | ' B ' |... | ' Z ' • dígito = ' 0 ' | ' 1 ' |... | ' 9 ' Observe que el carácter tratando como una letra. underscore o guion bajo (_) es Identificadores: Un identificador es una secuencia finita de letras y de dígitos que comienzan con una letra. Los identificadores pueden ser de cualquier longitud, sin embargo, los identificadores sin diferencia en sus primeros 8 caracteres correspondientes se consideran iguales. • Identificador = (letra) (letra | dígito) *. Constantes numéricas Un integer_constant es una secuencia de dígitos (no debe comenzar con un 0, a menos que sea el número 0). • integer_constant = digit+ Una constante numérica se debe separar de un identificador o de una palabra clave. Constantes de carácter. Un chat_constant se define como una comilla simple de apertura (“”), un carácter ASCII extendido imprimible y una comilla simple de cierre. 12 Compiladores. Guía 1 Strings Constantes. Una constante de string es una secuencia de los caracteres incluidos dentro de dos comillas dobles ("). Una constante de string puede incluir la secuencia \” que representa un carácter de comillas doble en la secuencia en la cual ocurre, tal que no termina el string. La secuencia \n representa el carácter del NEWLINE, mientras que la secuencia \ \ representa el carácter del backslash y se puede incluir en un string también. Una secuencia consistente de un backslash seguido por cualquier carácter a excepción de 'n', '\ ', o ' " ' es ilegal. Por consiguiente, un string constante no debe extenderse más allá del extremo de la línea. Un par de /*…*/ dentro de un string constante no se trata como comentario. Operadores • add_op = ' + ' | ' - ' • mul_op = ' * ' | '/' • eq_op = ' = = ' | '! = ' • rel_op = ' < ' | ' < = ' | ' > = ' | ' > ' Ejercicio 8 Desarrollar en el IDE DevC++ utilizando el lenguaje Micro C. los ejercicios 3, 4 y 5 Investigación complementaria a) Escribir un programa fuente en MICRO C que lea una temperatura en grados Celsius, lo convierta a temperatura absoluta y este resultado lo muestre en pantalla. b) Escribir un programa en MICRO C que calcule el factorial de un número. c) Investigar que es léxico y en qué consiste el análisis léxico de un traductor. Bibliografía Cueva, J. (1998). Conceptos básicos de procesadores de lenguaje. Universidad de Oviedo, España. Compiladores. Guía 1 13 Guía 1: Introducción compiladores y MUSIM/0 a Hoja de cotejo: Docente: Tema: Presentación del programa Alumno : 1 1 MáquinaMáquina No: No: Máquina No: Alumno: Docente: GL: GL: Fecha: Docente: GL: a EVALUACION % CONOCIMIENTO Del 20 al 30% APLICACIÓN DEL CONOCIMIENTO Del 40% al 60% 1-4 5-7 8-10 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 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