GENERACION DE CODIGO INTERMEDIO

July 25, 2017 | Author: Steffi Colmenares Cruz | Category: Compiler, Computer Programming, Areas Of Computer Science, Notation, Software Engineering
Share Embed Donate


Short Description

Descripción: unidad ll: automas 2...

Description

ÍNDICE

UNIDAD 2: GENERACION DE CODIGO INTERMEDIO 2.1 NOTACIONES………………………………………………………………3 2.1.1 PREFIJA…………………………………………………………………….4 2.1.2 INFIJA………………………………………………...…………………….4 2.2.3 POSTFIJA…………………………………………..………………………5 2.2 REPRESENTACIONES DE CÓDIGO INTERMEDIO…….…………….………..5 2.2.1 NOTACIÓN POLACA…………………………………………….…………7 2.2.2 CÓDIGO P……………………………………………….………………...8 2.2.3 TRIPLOS……………………………………………………….…...……..9 2.2.4 CUÁDRUPLOS………………………………………….………………...10 2.3 ESQUEMA DE GENERACIÓN…………………………….……………..…..10 2.3.4 INSTRUCCIONES DE CONTROL …………………..…………………....10 2.3.5 FUNCIONES…………………………………………………….……......11 2.3.6 ESTRUCTURAS……………………….………………………………….12 BIBLIOGRAFIA……………………………………………………………….13 2.- GENERACIÓN DE CÓDIGO INTERMEDIO

El objetivo del código intermedio es reducir el número de programas necesarios para construir traductores, y permitir más fácilmente la transportabilidad de unas máquinas a otras.

1

Después de los análisis sintáctico y semántico, algunos compiladores generan una representación intermedia explicita del programa fuente. Esta representación intermedia debe tener dos propiedades importantes; debe ser fácil de producir y fácil de traducir al programa objeto.

2.1 NOTACIONES Las notaciones sirven de base para expresar sentencias bien definidas. El uso más extendido de las notaciones sirve para expresar operaciones aritméticas. Las expresiones aritméticas se pueden expresar de tres formas distintas: infija, prefija y postfija. La diversidad de notaciones corresponde en que para algunos casos es más sencillo un tipo de notación. 2.1.1 NOTACIÓN PREFIJA

La notación prefija, también conocida como notación de prefijo o notación prefija, es una forma de notación para la lógica, la aritmética, y el álgebra. Su característica distintiva es que coloca los operadores a la izquierda de sus operandos. Si la aridad (es el número de argumentos necesarios para que dicho operador o función se pueda calcular.) de los operadores es fija, el resultado es una sintaxis que carece de paréntesis u otros signos de agrupación, y todavía puede ser analizada sin ambigüedad.

1

2.1.2 NOTACIÓN DE INFIJA

La notación de infijo es la notación común de fórmulas aritméticas y lógicas, en la cual se escriben los operadores entre los operandos en que están actuando (ej. 2 + 2) usando un estilo de infijo. No es tan simple de analizar (parser, es una de las partes de un compilador que transforma su entrada en un árbol de derivación.) por las computadoras, como la notación de prefijo (ej. + 2 2) o la notación de postfijo (ej. 2 2 +), aunque muchos lenguajes de programación la utilizan debido a su familiaridad. En la notación de infijo, a diferencia de las notaciones de prefijo o posfijo, es necesario rodear entre paréntesis a los grupos de operandos y operadores, para indicar el orden en el cual deben ser realizadas las operaciones. En la ausencia de paréntesis, ciertas reglas de prioridad determinan el orden de las operaciones.

2.2.3 POSTFIJA La notación postfija pone el operador al final de los dos operandos, por lo que la expresión queda: ab+5La notación postfija utiliza una estructura del tipo LIFO (Last First Out) pila, la cual es la más utilizada para la implementación. Llamada también polaca inversa, se usa para representar expresiones sin necesidad de paréntesis. La notación postfija pone el operador al final de los dos operandos. Ejemplos:  a*b  ab*  a*(b+c/d)  abcd/+*  a*b+c*d  ab*cd*+

1

Ejemplo Si deseamos representar las expresiones (2+3(3*4))=x y ((2+3)*4)=x en las tres notaciones mencionadas anteriormente seria: (2+3(3*4))=x ((2+3)*4)=x Notación Prefija =+2*34x =*+234x Notación Infija 2+3*4=x (2+3)*4=x

Notación postfija

234*+x=

23+4*x=

2.2 REPRESENTACIÓN DE CÓDIGO INTERMEDIO Estas notaciones simplifican la traducción de nuestro código fuente a nuestro código objeto ya que ahorran y acotan símbolos de la tabla de símbolo. Existen diversos tipos de códigos intermedios que varían en cuanto a su sencillez, lo próximos que están a las maquinas reales y lo fácil que es trabajar con ellos, otros tipos de código intermedio que representan los programas como árboles o grafos y representaciones mixtas que combinan grafos o árboles y representaciones lineales. Generación de Código Intermedio Proceso de Síntesis.  Lenguaje Intermedio  Generación de Código Ventajas del código intermedio.  Facilitar la fase de optimización.  Aumentar la portabilidad del compilador de una máquina a otra.  Se puede utilizar el mismo analizador para diferentes generadores.

Aumentar la portabilidad del compilador de una máquina a otra  Se puede utilizar el mismo analizador para diferentes generadores  Se pueden utilizar optimizadores independientes de la máquina

1

Tipos de representaciones intermedias La representación del código intermedio depende de la máquina objeto: 0-direcciones: código para máquinas de pila (código P). 2-direcciones: códigos para máquinas con operaciones sobre registros de memoria. 3-direcciones: código para máquinas de arquitectura RISC. En todo caso, añade un recorrido descendente adicional para generar el código final.

Propiedades:  Fácil de producir en el análisis semántico.  Fácil de traducir a código máquina real.  Instrucciones simples y concisas, de fácil optimización. Tipos  Árboles de Sintaxis Abstracta.  Notación Polaca Inversa (RPN).  Código P  Códigos de tres direcciones  Cuartetos  Tercetos  Tercetos Indirectos. 2.2.1. NOTACIÓN POLACA La notación polaca es la originada por un Autómata con pila, en la que los operadores siempre preceden a los operandos sobre los que actúan, y que tiene la ventaja de no necesitar paréntesis: Estándar Ejemplo 1: 2 * (3 + 5) Ejemplo 2: 2 * 3 + 5 Polaca Ejemplo 1: * 2 + 3 5 Ejemplo 2: + * 2 3 5

2.2.2 CÓDIGO P

1

Prolog, proveniente del francés Programation et Logique, es un lenguaje de programación lógico e interpretado, bastante popular en el medio de investigación en Inteligencia Artificial. Se trata de un lenguaje de programación ideado a principios de los años 70 en la universidad de Aix-Marseille por los profesores Alain Colmerauer y

Phillipe Roussel. Inicialmente se trataba de un lenguaje totalmente interpretado hasta que, a mediados de los 70, David H.D. Warren desarrolló un compilador capaz de traducir Prolog en un conjunto de instrucciones de una máquina abstracta denominada Warren Abstract Machine, o abreviadamente, WAM. Desde entonces Prolog es un lenguaje semi-interpretado. Prolog se enmarca en el paradigma de los lenguajes lógicos, lo que lo diferencia enormemente de otros lenguajes más populares tales como Fortran, Pascal, C, etc. En todos los mencionados, las instrucciones se ejecutan normalmente en orden secuencial, es decir, una a continuación de otra, en el mismo orden en que están escritas, que sólo varía cuando se alcanza una instrucción de control (un bucle, una instrucción condicional o una transferencia). Los programas en Prolog se componen de cláusulas de Horn que constituyen reglas del tipo “modus ponendo ponens”, es decir, “Si es verdad el antecedente, entonces es verdad el consecuente”. No obstante, la forma de escribir las cláusulas de Horn es al contrario de lo habitual. Primero se escribe el consecuente y luego el antecedente. El antecedente puede ser una conjunción de condiciones que se denomina secuencia de objetivos. Cada objetivo se separa con una coma y puede considerarse similar a una instrucción o llamada a procedimiento de los lenguajes imperativos. En Prolog no existen instrucciones de control. Su ejecución se basa en dos conceptos: la unificación y el backtracking. Gracias a la unificación, cada objetivo determina un subconjunto de cláusulas susceptibles de ser ejecutadas. Cada una de ellas se denomina punto de elección. Prolog selecciona el primer punto de elección y sigue ejecutando el programa hasta determinar si el objetivo es verdadero o falso. En caso de ser falso entra en juego el ‘backtracking’, que consiste en deshacer todo lo ejecutado situando el programa en el mismo estado en el que estaba justo antes de llegar al punto de elección. 2.2.3 TRIPLOS En la historia de los compiladores han sido utilizadas una amplia variedad de representaciones intermedias como lo es la siguiente clase de representación de código intermedio de un árbol de 3 direcciones, 2 para los operandos y una para la ubicación del resultado. Esta clase incluye un amplio número de representaciones diferentes entre las cuales encontramos cuádruplos y triples. La principal diferencia entre estas notaciones y la notación postfija es que ellos incluyen referencias explicitas para los resultados de los cálculos intermedios, mientras que la notación posfija los resultados son implícitos al representarlos en una pila.

1

 La diferencia entre triples y cuádruplos es que con los triples es referenciado el

valor intermedio hacia el número del triple que lo creo, pero en los cuádruplos requiere que ellos tengan nombre implícitos.  Los triples tienen una ventaja obvia de ser más consistente, pero ellos dependen de su posición, y hacen que la optimización presente cambios de código mucho más compleja.  Para evitar tener que introducir nombres temporales en la tabla de símbolos, se hace referencia a un valor temporal según la posición de la proposición que lo calcula. Las propias instrucciones representan el valor del nombre temporal. La implementación se hace mediante registros de solo tres campos (op, arg1, arg2).  En la notación de tripletes se necesita menor espacio y el compilador no necesita generar los nombres temporales. Sin embargo, en esta notación, trasladar una proposición que defina un valor temporal exige que se modifiquen todas las referencias a esa proposición  Una forma de solucionar esto consiste en listar las posiciones a las tripletas en lugar de listar las tripletas mismas. De esta manera, un optimizador podría mover una instrucción reordenando la lista, sin tener que mover las tripletas en sí. 2.2.4 CUÁDRUPLOS. Es una estructura tipo registro con cuatros campos que se llaman: op, arg1, arg2 y resultado. OP tiene un código intermedio. Los operadores unarios como x:=-y no utilizan arg2. Generalmente arg1, arg2 y resultado son valores de tipo puntero y apuntan a una entrada en la tabla de símbolos. Por ejemplo, la proposición de tres direcciones x = y + z se podría representar mediante el cuádruplo (ADD, x,y, z). Las proposiciones con operadores unarios no usan el arg2. Los campos que no se usan se dejan vacíos o un valor NULL. Como se necesitan cuatro campos se le llama representación mediante cuádruplos.

1

2.3 ESQUEMA DE GENERACIÓN. Los esquemas de generación son las estrategias o acciones que se deberán realizarse y tomarse en cuenta en el momento de generar código intermedio. Los esquemas de generación dependen de cada lenguaje. Tomaremos algunos esquemas de generación del lenguaje C.  Esquema de generación de código

2.3.4 INSTRUCCIONES DE CONTROL. En los lenguajes de programación hay estructuras y operadores que permiten controlar el flujo de la ejecución, estos pueden ser ciclos, saltos, condiciones entre otros.

Expresiones booleanas En los lenguajes de programación, las expresiones booleanas tienen dos propósitos principales. Se utilizan para calcular valores lógicos y como expresiones condicionales en proposiciones que alteran el flujo del control, como las proposiciones if-else o do-while. Las expresiones booleanas se componen de los operadores boleanos (and, or y not) aplicados a los elementos que son variables booleanas o expresiones relacionales. Algunos lenguajes permiten expresiones más generales donde se pueden aplicar operadores booleanos, aritméticos y relacionales a expresiones de cualquier tipo, sin diferenciar valores booleanos de aritméticos; si es necesario se realiza una coerción. Saltos En el código de los saltos los operadores lógicos &&, || y ! son traducidos a saltos aunque estos no aparecen realmente en el código. Por ejemplo la expresión: if (x < 100 || x > 200 && x!= y ) x=0; se puede traducir como las siguientes instrucciones:

1

If x < 100 goto L2 If False x > 200 goto L1 If False x != y goto L1 L2: x =0 L1: Si la expresión es verdadera se alcanza la etiqueta L2 y se realiza la asignación en

caso contrario no haría nada. 2.3.5 FUNCIONES Función del Lenguaje, entendemos que es el uso de la lengua que hace un hablante. En simples palabras, las funciones del lenguaje son los diferentes objetivos, propósitos y servicio que se le da al lenguaje al comunicarse, dándose una función del lenguaje por cada factor que tiene éste, en donde la función que prevalece es el factor en donde más se pone énfasis al comunicarse. Diversos lingüistas (Karl Bühler, Roman Jakobson, Michael Halliday…) han propuesto distintas clasificaciones de las funciones del lenguaje: Bühler propuso que existían únicamente tres funciones:  La Representativa (por la cual se trasmiten informaciones objetivamente)  La Expresiva o emotiva (que expresa sentimientos del emisor)  La Conativa, mediante la que se influye en el receptor del mensaje a través de órdenes, mandatos o sugerencias. 2.3.6 ESTRUCTURAS El código intermedio no es el lenguaje de programación de ninguna máquina real, sino que corresponde a una máquina abstracta, que se debe de definir lo más general posible, de forma que sea posible traducir este código intermedio a cualquier máquina real. El objetivo del código intermedio es reducir el número de programas necesarios para construir traductores, y permitir más fácilmente la transportabilidad de unas máquinas a otras. Supóngase que se tienen n lenguajes, y se desea construir traductores entre ellos. Sería necesario construir n*(n-1) traductores. Sin embargo si se construye un lenguaje intermedio, tan sólo son necesarios 2*n traductores. Así por ejemplo un fabricante de compiladores puede construir un compilador para diferentes máquinas objeto con tan sólo cambiar las dos últimas fases de la tarea de síntesis.

1

Aunque un programa fuente se puede traducir directa mente al lenguaje objeto, algunas ventajas de utilizar una forma intermedia independiente de la máquina son:

 Se facilita la redestinación: se puede crear un compilador para una máquina distinta uniendo una etapa final para la nueva máquina a una etapa inicial ya existente.  Se puede aplicar a la representación intermedia un optimizador de código independiente de la máquina.

BIBLIOGRAFÍA

1

Lenguaje y Autómatas II. Unidad VI Generación de Código Intermedio. M.C. Juan Carlos Olivares Rojas. pág. 1-36. Año 2010. Generación de código procesador de lenguaje. Lenguaje y autómata II. Universidad técnica de México pág. 1-28. http://dsc.itmorelia.edu.mx/~jcolivares/courses/ps207a/ps2_u6.pdf.

View more...

Comments

Copyright ©2017 KUPDF Inc.
SUPPORT KUPDF