You are on page 1of 33

Compiladores

Generación de código intermedio

Análisis – Síntesis
• En el modelo de análisis y síntesis de un
compilador, el frontend analiza el fuente
del programa, generando código
intermedio
• Este código intermedio es utilizado por la
etapa de backend para generar el código
objeto

Análisis – Síntesis

• El código intermedio, actúa como pivote
entre ambas etapas del compilador

Análisis – Síntesis • El objetivo principal es determinar – Las diferentes representaciones intermedias – El control de tipos realizado estáticamente en esta etapa – La generación del código intermedio propiamente dicha .

Tipos de representaciones • Tenemos dos grandes tipos de representaciones • Representaciones de árbol – Árboles sintácticos • Representaciones lineales – Código de tres direcciones .

los nodos son cargados con información. en forma de atributos • Que atributos? Dependerá del tipo de traduccion que se realizara posteriormente . Árboles Sintácticos • Son construidos durante el proceso de parsing • Los nodos del árbol representan construcciones del lenguaje de programación • A medida que el análisis progresa.

esta es la forma preferida . Código de tres direcciones • Es una secuencia de pasos elementales en un programa • Por ejemplo: – Sumar 2 valores y guardarlo en un tercero – tmp = x + y • No tiene una estructura jerárquica • Si se debe realizar optimizaciones sobre el codigo.

es cuando se realizan los controles de tipo • Estos controles. Controles de tipo • En este momento. se denominan “chequeos estáticos” – Estáticos = Hecho por el compilador • El objetivo es detectar la mayor cantidad de errores de tipado antes de ejecutar el programa .

con un esquema de traducción • En su forma mas general: . Árboles Sintácticos • Pueden ser construidos utilizando las técnicas de traducción dirigida por la sintaxis. por ejemplo.

uno para el árbol de expr. y otro para el árbol de stmt . Árboles Sintácticos • Los árboles sintácticos pueden ser construidos para cualquier construcción del lenguaje • Por ejemplo: while (expr) { stmt } • El árbol sintáctico para la sentencia while – Tiene un nodo con el operador while – Dos hijos.

Árboles Sintácticos while Árbol Árbol para expr para stmt .

Un ejemplo .

Un ejemplo .

la cual tiene dos subclases. se crea una subclase correspondiente – Las acciones de la gramática crean estos nodos al reconocer las sentencias . Representando sentencias • Implementamos un conjunto de clases para representar el árbol sintáctico • La clase Node es la clase base. Expr para expresiones y Stmt para sentencia • La gramática se extiende con un atributo “n” para almacenar nodos del árbol sintáctico – Para cada tipo de sentencia.

Representando sentencias • Para cada tipo de sentencia del lenguaje. definimos un operador en el árbol sintáctico • En la regla que detecta una producción. se crea dicho nodo .

ambos usan el mismo nodo . interesa representar un conjunto de sentencias. agrupadas • Formamos una lista de sentencias • En el caso de una sentencia de tipo bloque. Representando bloques • En el caso de un bloque.

Representando bloques .

siempre en el lado derecho de la instrucción. tenemos como máximo un operador • Por ejemplo: x+y×z • Se traduce en: – t1 = y × z – t2 = x + t1 . Código de 3 direcciones • En las instrucciones del código de 3 direcciones.

Código de 3 direcciones • Este código esta basado en 2 conceptos. direcciones e instrucciones • Una dirección puede ser – Un nombre. por ejemplo una variable o un procedimiento – Una constante – Un temporal generado por el compilador. por ejemplo al descomponer una expresión .

z son direcciones • Asignaciones de la forma x = op y – op es un operador unario – x. Instrucciones disponibles • Asignaciones de la forma x = y op z – op es un operador binario – x. y. y son direcciones . y son direcciones • Instrucciones de copia de la forma x = y – x.

Instrucciones disponibles • Saltos incondicionales de la forma goto L – La próxima ejecución. es la instrucción etiquetada con L • Saltos condicionales de la forma if x goto L o if false x goto L – La próxima ejecución. se ejecuta la instrucción siguiente al salto . es la instrucción etiquetada con L – En caso contrario.

Instrucciones disponibles • Saltos condicionales de la forma if x oprel y goto L – La próxima ejecución. > . como <. es la instrucción etiquetada con L – oprel es un operador relacional.

n para llamadas a funciones . funciones y retornos de datos – param x para indicar el pasaje de un parámetro – call p. Instrucciones disponibles • Llamadas a procedimientos.n para llamadas a procedimientos – y = call p.

x2.….xn) se traduce en: – param x1 – param x2 –… – param xn – call p. la llamada p(x1. n . Instrucciones disponibles • Por ejemplo.

Instrucciones disponibles • Instrucciones de copia indexadas de la forma x = y[i] o x[i] = y • Asignaciones de punteros de la forma x = &y. *x = y . x = *y.

while (a[i] < v) . Un ejemplo • Consideremos la sentencia – do i = i+1. • Podemos usar etiquetas o posiciones: .

entonces la traducción al código objeto es mas sencilla . es crucial en el diseño de la forma intermedia • El conjunto de operadores debe ser suficientemente rico para implementar las operaciones en el lenguaje de alto nivel • Si los operadores se aproximan a las instrucciones de maquina. Operadores • La elección de operadores.

Cuadruplos • Es una estructura de datos que permite representar código de tres direcciones • Tiene cuatro campos: op. arg1. arg2 y result • Las diferentes instrucciones mapean los componentes de la instrucción en la estructura de datos .

Cuadruplos .

Cuadruplos • Las instrucciones que utilizan operadores unarios. no usan arg2 ni result • Los saltos condicionales e incondicionales colocan la etiqueta en el campo result . no utilizan el campo arg2 • Los operadores como param.

op. arg1 y arg2 • Debido a que el campo result se utiliza para resultados temporales. lo que hace un triple es referenciar a la instrucción donde se realiza el calculo . Triples • Un triple es una estructura que optimiza un poco los cuadruplos • Utilizan tres campos.

Triples .

ya que siempre se utilizan los nombres de los elementos referencias (y no el índice) . Triples • Existe cierta ventaja de los triples (en algunas plataformas) en temas de consumo de espacio • Sin embargo. los cuadruplos permiten realizar movimientos de código sin problemas de referencia.