0% encontró este documento útil (0 votos)
436 vistas10 páginas

Generación de Código Intermedio en Compiladores

1) El documento presenta información sobre la generación de código intermedio en un compilador. 2) Explica que el código intermedio permite separar la parte dependiente del lenguaje fuente de la parte dependiente de la máquina objetivo. 3) Describe algunas formas de representar el código intermedio, incluyendo notación polaca, código P, árboles sintácticos y código de tres direcciones.

Cargado por

Hecsali Salinas
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
436 vistas10 páginas

Generación de Código Intermedio en Compiladores

1) El documento presenta información sobre la generación de código intermedio en un compilador. 2) Explica que el código intermedio permite separar la parte dependiente del lenguaje fuente de la parte dependiente de la máquina objetivo. 3) Describe algunas formas de representar el código intermedio, incluyendo notación polaca, código P, árboles sintácticos y código de tres direcciones.

Cargado por

Hecsali Salinas
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd

TECNOLÓGICO NACIONAL DE MÉXICO

INSTITUTO TECNOLÓGICO DE POCHUTLA


ASIGNATURA:

LENGUAJES Y AUTÓMATAS II

TEMA:

2.- GENERACIÓN DE CÓDIGO INTERMEDIO.

ACTIVIDAD T2-02:

EJERCICIOS.

ALUMNO (A):

PASTOR SEBASTIÁN JOSÉ HERNÁNDEZ


ANA CRISTINA CRUZ VALENCIA
HECSALI SALINAS CORTÉS
JAVIER SANTIAGO MONJARAZ

CARRERA:

INGENIERÍA EN SISTEMAS COMPUTACIONALES

DOCENTE:

M.I. JOSÉ LUIS FUENTES ORTIZ

San Pedro Pochutla, Oaxaca, a 22 de septiembre de 2020


Introducción.

La parte que depende sólo del lenguaje fuente (etapa inicial o front-end) y la parte que
depende sólo del lenguaje objeto (etapa final o back-end).

 Etapa inicial: corresponde con la parte de análisis (léxico, sintáctico y


semántico).
 Etapa final: corresponde con la parte de síntesis (generación de código).

La etapa inicial traduce un programa fuente a una representación intermedia a partir de


la cual la etapa final genera el código objeto.
De esta forma, los detalles que tienen que ver con las características del lenguaje
objeto (código ensamblador, código máquina absoluto o relocalizarle, . . . ), la
arquitectura de la máquina (número de registros, modos de direccionamiento, tamaño
de los tipos de datos, memoria cache, ...), el entorno de ejecución (estructura de
registros y memoria de la máquina donde se va a ejecutar el programa . . . ) y el
sistema operativo se engloban en la etapa final y se aíslan del resto.

La generación de código es la tarea más complicada de un compilador. Las ventajas de


utilizar esta representación intermedia, independiente de la máquina en la que se va a
ejecutar el programa, son: Se puede crear un compilador para una nueva máquina
distinta uniendo la etapa final de la nueva máquina a una etapa inicial ya existente. Se
facilita la redestinación.
Generación de Código Intermedio

 Si un compilador traduce el idioma de origen a su ordenador de destino sin


tener la opción de generar código intermedio, a continuación, en cada nueva
máquina, una nativa del compilador completo es necesario.
 Código Intermedio elimina la necesidad de un nuevo compilador completo para
cada máquina de la sección de análisis mismo de todos los compiladores.
 La segunda parte del compilador, síntesis, se modifica de acuerdo a la máquina
de destino.
 Es más fácil de aplicar las modificaciones del código fuente para mejorar
rendimiento del código mediante la aplicación de técnicas de optimización
código el código intermedio.

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:
 Se utiliza principalmente para la representación de expresiones aritméticas.
 Expresión a notación polaca inversa.

Algoritmo

 Representa la expresión en forma de árbol sintáctico.


 Recorrer el árbol en postorden,
Ventajas y desventajas de la notación polaca:

 Generación de código: simple, no utiliza registros.


 Optimización: es difícil de reordenar ya que hay que considerar el contenido de la
pila.
 Interpretación rápida: es muy fácil de interpretar ya que solo necesita una pila.
 Transportable: si, ya que todos los procesadores implementan una pila.

Código P

Un tipo de lenguaje interpretado. idiomas P-código son una especie de híbrido, que
caen entre lenguajes compilados y lenguajes interpretados de la manera que se
ejecuten. Al igual que un lenguaje interpretado, la programación del P-código se
convierte en una forma binaria de forma automática cuando se ejecuta, en lugar de
tener que ser compilado. Sin embargo, a diferencia de un lenguaje compilado el archivo
binario ejecutable se almacena en seudocódigo, no en lenguaje de máquina. Además,
a diferencia de un lenguaje interpretado, el programa no tiene que ser convertida a
binario cada vez que se ejecute. Después de que se convierte en P-código la primera
vez, la versión seudocódigo se utiliza para cada ejecución adicionales.

Código P (y por tanto sus programas) tienden a ser más lento que los lenguajes
compilados y programas, pero más rápido que lenguajes interpretados, y por lo general
tienen autorización para algunas funciones del sistema operativo de bajo nivel, pero no
el acceso directo al hardware. No requieren compiladores a veces costosos, a menudo
se incluyen junto con los sistemas operativos, y algunos lenguajes de código p-son más
fáciles de programar que lenguajes compilados.

Ejemplos de lenguas Pcode son Java, Python y REXX / REXX objetos.


En el modelo de compilación análisis-síntesis, el front-end traduce el programa fuente
en una representación de código intermedio, y el back-end traduce esta representación
en código final.
 Permite crear fácilmente un compilador para diferentes maquinas
 La representación intermedia puede ser optimizada por un optimizador
independiente del código final

Lenguajes Intermedios:
 Arboles de Sintaxis
 Código de tres direcciones

Representación intermedia
Códigos intermedios puede ser representado en una variedad de formas y tienen sus
propios beneficios.

 Alto nivel IR - Alto nivel de representación de código intermedio está muy cerca
de la lengua de origen. Pueden ser fácilmente generados desde el código
fuente y podemos aplicar fácilmente modificaciones de código para mejorar el
rendimiento. Pero para optimización de la máquina destino, es menos preferido.
 Bajo Nivel IR - Este es cerca de la máquina de destino, lo que lo hace
adecuado para registro y asignación de memoria, un conjunto de instrucciones
selección, etc. es bueno para optimizaciones dependientes de la máquina.

Código intermedio puede ser específica para cada idioma (p. ej., código de bytes de
Java) o independiente de la lengua (tres-código de dirección).
Código de Tres Direcciones
Es una manera linear de representar un grafo de sobrexpresiones en donde los
nombres explícitos corresponden a los nodos interiores del grafo (figura 3), muy útil
principalmente a la hora de optimizar. Las instrucciones se representan utilizando
cuando mucho un solo operador en la parte derecha de la expresión, es decir, una
expresión del tipo "x+y*z" se representaría de la manera "t1=y*z y t2=x+t1".

El código de tres direcciones se basa en 2 conceptos principalmente en 2 conceptos:


direcciones e instrucciones.

• Nombres: los nombres que se usan en el programa pueden aparecer también en el


código de 3 direcciones, aunque a la hora de implementar se usara un puntero o su
entrada en la tabla de símbolos.

• Una constante: el compilador tiene que poder interactuar con muchos tipos de
constantes. Las instrucciones más básicas pueden definirse de la siguiente manera:

• x=y'op'z, donde 'op' es un operador binario aritmético o una expresión lógica.

• x='op'y, donde 'op' es una operación unaria.

• x=y, donde a x se le asigna el valor de y

• goto L, la instrucción con la etiqueta L se ejecutará.

• if x goto L o if false goto L, se ejecutaría la instrucción con la etiqueta L dependiendo


de si x es verdadero o falso.

• if x relop y goto L, se ejecutaría la instrucción L dependiendo del operador relacional


que se le aplique a x y y

• param x y call p,n, donde param x indica que x es un parámetro. call llama un
procedimiento p con un número de parámetros n.

En el diseño del código intermedio, es necesario escoger un buen conjunto de


operadores. Se Usando el código de 3 direcciones, el compilador puede representar
código intermedio y ayudarse en la implementación más optima del código final.
Las direcciones se pueden definir como: deben tener los suficientes operadores para
satisfacer las instrucciones del lenguaje, y que a su vez sean cercanos al lenguaje de
máquina. Sin embargo, si se crean demasiadas instrucciones, el optimizados y el
generador de código tendrán que trabajar más para generar el código final.

Una proposición de código de 3-direcciones se puede implantar como una estructura


tipo registro con campos para el operador, los operandos y el resultado. La
representación final será entonces una lista enlazada o un vector de proposiciones.
Hay dos formas principales de implementar el código de tres direcciones:

Cuádruplas.

Una cuádrupla es una estructura tipo registro con cuatro campos que se llaman (op,
result, arg1, arg2).
El campo op contiene un código interno para el operador.

Estructura con 4 campos: operador, operando1, operando2, resultado.

Por ejemplo:

la proposición de tres direcciones x = y + z se podría representar mediante la cuádrupla


(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ádruplas.

Ejemplo 2.

(A+B) *(C+D)-E
+, A, B, T1
+, C, D, T2
*, T1, T2, T3
-, T3, E, T4

Las cuádruplas facilitan la aplicación de muchas optimizaciones, pero hay que tener un
algoritmo para la reutilización de las variables temporales (reutilización de registros del
procesador).

Tripletas.

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. Lo cual supone un inconveniente a la hora de optimizar el código,
pues a menudo es necesario cambiar proposiciones de lugar.

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í.

Estructura con 3 campos: operador, operando1, operando2. Los resultados temporales


se referencian por la posición en que fueron calculados

Ejemplo:

W * X + (Y + Z)
1. *, W, X
2. +, Y, Z
3. +, (1), (2)

Control de flujo:

IF X>Y THEN Z=X ELSE Z=Y+1


1. >, X, Y
2. Saltar si falso, (1), 5
3. =, Z, X
4. Saltar,, 7
5. +, Y, 1
6. =, Z, (5)

Problema:

La optimización supone mover tripletas y hay que recalcular las referencias.


Código de tres dimensiones (instrucciones comunes).

Instrucciones de Asignación:
x := y op z (op es un operador binario, aritmético o lógico)
x := op y (op es un operador unario: menos, conversión)
x := y

Asignaciones Indexadas: x := y[i]


x[i] := y

Apuntadores: x := &y (asigna la dirección de y)


x := *y (y es un apuntador)
*x := y (x es un apuntador)

Saltos:
Incondicional: goto L
Condicional: if x rel-op y goto L

Llamado a procedimientos y retorno:


param x1
param x2
....
param xn
call p n
return y

EJEMPLO:

a := 2 * x + 10;
while a <= p + 2 do
j := p[i*2+4]
end
j := j + 1
EJEMPLO:

Generador de código intermedio recibe la entrada de su predecesor, analizador


semántico, en la forma de un árbol de sintaxis anotado. Árbol de sintaxis que luego se
puede convertir en una representación lineal, por ejemplo, postfix notación. Código
intermedio tiende a ser código independiente de la máquina. Por lo tanto, generador de
código supone que tiene número ilimitado de almacenamiento en memoria (registro)
para generar el código

a = b + c * d;

El generador de código intermedio, tratar de dividir esta expresión en sub-expresiones


y, a continuación, generar el código correspondiente.

r1 = c * d;
r2 = b + r1;
r3 = r2 + r1;
a = r3

R que se utilizan como registros en el programa de destino.

Bibliografía:
https://www.tutorialspoint.com/es/compiler_design/compiler_design_intermediate_code_generations.htm
http://www.hopelchen.tecnm.mx/principal/sylabus/fpdb/recursos/r97354.PDF
http://cic.puj.edu.co/wiki/lib/exe/fetch.php?media=materias:compi:comp_sesion21_2008-1.pdf
http://www.di-mare.com/adolfo/cursos/2008-1/pp-GenCodInterMed.pdf
https://raknarrok.blogspot.com/2011/05/r-epresentacion-de-codigo-intermedio.html
http://itpn.mx/recursosisc/7semestre/leguajesyautomatas2/Unidad%20II.pdf

También podría gustarte