procesadores de lenguajes i

252
Procesadores de Lenguajes Ingeniería Técnica superior de Ingeniería Informá8ca Departamento de Lenguajes y Sistemas informá6cos Javier Vélez Reyes [email protected] Departamento de Lenguajes Y Sistemas Informá6cos UNED Universidad Nacional de Educación a Distancia Grado en Ingeniería Informática

Upload: javier-velez-reyes

Post on 21-Mar-2017

76 views

Category:

Education


9 download

TRANSCRIPT

Page 1: Procesadores de Lenguajes I

ProcesadoresdeLenguajesIngenieríaTécnicasuperiordeIngenieríaInformá8ca

DepartamentodeLenguajesySistemasinformá6cos

JavierVé[email protected]

DepartamentodeLenguajesYSistemasInformá6cosUNED

UniversidadNacionaldeEducaciónaDistancia

Grado en Ingeniería Informática

Page 2: Procesadores de Lenguajes I

Procesad

oresdeLengua

jes

IngenieríaTécnicasu

perio

rdeIngenieríaIn

form

á8ca

Departam

entodeLenguajesy

Sistem

asinform

á6cos

JavierVé[email protected]á?cosUNED

ParteIIIEtapadesíntesis

Page 3: Procesadores de Lenguajes I

ProcesadoresdeLenguajesIngenieríaTécnicasuperiordeIngenieríaInformá8ca

DepartamentodeLenguajesySistemasinformá6cos

JavierVé[email protected]

DepartamentodeLenguajesYSistemasInformáAcosUNED

6Análisissemán*coITraduccióndirigidaporlasintaxis

Page 4: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 2

Obje6vosGenerales

Obje8vosGenerales

›  Aprender qué es la semántica de un lenguaje de programación

›  Entender cómo funciona la semántica operacional y distinguirla de otros tipos de semántica

›  Aprender cómo se inyecta información semántica en una gramática

›  Aprender el principio de traducción dirigido por la sintaxis

›  Conocer las gramáticas con atributos y las reglas y acciones semánticas

›  Aprender a distinguir los diferentes tipos de atributos que existen

›  Aprender a construir y analizar grafos de dependencia

›  Aprender a identificar compiladores de simple y doble pasada

›  Conocer los distintos tipos de formalismos de traducción que existen

›  Aprender a especificar definiciones dirigidas por la sintaxis

›  Aprender a especificar esquemas de traducción dirigidos por la sintaxis

Page 5: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 3

Índice

Índice

›  Introducción

›  Formalismos para la especificación de traducciones

›  Definiciones dirigidas por la sintaxis

›  Reglas semánticas

›  Atributos

›  Grafos de dependencia

›  Diseño de definiciones dirigidas por la sintaxis

›  Gramáticas con atributos por la izquierda

›  Esquemas de traducción dirigidas por la sintaxis

›  Acciones semánticas

›  Atributos

›  Diseño de esquemas de traducción

›  Traducción dirigida por la sintaxis en la práctica

›  Bibliografía

Page 6: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 4

Introducción

¿Quéeslasemán8cadeunlenguaje?

Analizad

orléxico

Analizad

orsintác8co

Analizad

or

semán

8co

Códigointerm

edio

Códigofina

l

e·l·i·h·w <WHILE,PR> S

WHILEEDOS

E>E

S

WHILEEDOS

E>E

√ 0000001100000011010000010100000000010010…

While(a>b)doa:=a+1;

Etapa de análisis Etapa de síntesis

LDat1LDbt2GRTt3t1t2BRZt3L1…

¿Cómo es el lenguaje? Las dos primeras fases conceptuales de un compilador atienden a responder la pregunta de cómo es un lenguaje en términos de su estructura sintáctica y sus elementos léxicos constituyentes

¿Qué es el lenguaje? Las tres fases subsiguientes tratan de dar un significado único, preciso y computable a cada construcción del lenguaje de manera que el programador sepa definir programas semánticamente útiles y coherentes

Tema 2 Tema 3 - 5 Tema 6 - 7 Tema 8 - 9 Tema 10 - 11

Page 7: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 5

Introducción

¿Quéeslasemán8cadeunlenguaje?

PROGRAMBubbleSort;CONSTMAX=100;TYPETVector=ARRAY[1..MAX]OFINTEGER;VARv:TVector;PROCEDUREReadVector(VARv:TVector);...PROCEDURESort(VARv:TVector,size:INTEGER);VARi,j,tmp:INTEGER;BEGINFORi:=size-1DOWNTO1DOFORj:=1TOiDOIF(v[j]>v[j+1])THENBEGINtmp:=v[j];v[j]:=v[j+1];v[j+1]:=tmp;END;END;BEGINReadVector(v);sort(v,MAX);END.

El análisis sintáctico de un código fuente comprueba que la secuencia de tokens llegada desde el analizador léxico se corresponde con la esperada de acuerdo a las prescripciones gramaticales y se obtiene como resultado un árbol de análisis sintáctico. Hemos obtenido por tanto una secuencia correcta de tokens pero nada sabemos acerca de qué significado intencional subyace a la misma

}

Sabemos comprobar que este código fuente corresponde a un programa en Pascal de acuerdo a la gramática del lenguaje. Pero, ¿que significan la declaración de constantes, t ipos, variables, funciones y procedimientos, las sentencias, expresiones, etc. que en él aparecen?

Page 8: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 6

Introducción

¿Quéeslasemán8cadeunlenguaje?Es necesario definir computacionalmente la semántica de un lenguaje para que el compilador sepa interpretar cada posible código fuente del mismo. La forma más sencilla de hacer esto es asociar a cada posible construcción gramatical ciertas reglas que permitan traducirla en términos computables. Esto sólo es posible si se cumple el principio de traducción dirigido por la sintaxis

Traduccióndirigidaporlasintaxis

El significado de una construcción de un lenguaje está directamente

relacionado con su estructura sintáctica según se representa en su árbol de

análisis

Es decir, el significado de cada construcción gramatical, representada típicamente por un no terminal, solo debe depender de los elementos que aparecen en la parte derecha de sus reglas de producción

La lectura práctica que debe hacerse de este principio es que para establecer la semántica de un lenguaje es suficiente con hacerlo sobre cada una de sus reglas de producción de manera independiente. Esto a su vez se consigue estableciendo una traducción de los elementos de la parte derecha de la regla a una representación con un significado computable específico

DeclaraciónTipo::=TYPEID=ARRAY[N..N]

OFTipo;

Page 9: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 7

Introducción

¿Quéeslasemán8cadeunlenguaje?Es necesario definir computacionalmente la semántica de un lenguaje para que el compilador sepa interpretar cada posible código fuente del mismo. La forma más sencilla de hacer esto es asociar a cada posible construcción gramatical ciertas reglas que permitan traducirla en términos computables. Esto sólo es posible si se cumple el principio de traducción dirigido por la sintaxis

Traduccióndirigidaporlasintaxis

El significado de una construcción de un lenguaje está directamente

relacionado con su estructura sintáctica según se representa en su árbol de

análisis

Las traducciones con significado computacional especifico a las que antes hacíamos referencia se pueden clasificar en 2 grandes grupos dependiendo del momento en que se aplican dentro del ciclo de compilación

Tiposdeaccionesdetraducciónsemán8ca

Tiempodecompilación(semán8caestá8ca)

Tiempodeejecución(semán8cadinámica)

Las traducciones en tiempo de compilación son acciones que se aplican sobre los artefactos del compilador y que tienen efecto durante el proceso de compilación

Las traducciones en tiempo de ejecución son acciones dirigidas a generar código ejecutable en tiempo de compilación para que se apliquen durante la ejecución del programa compilado

}

Tema7

}

Tema8,9

Page 10: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 8

Introducción

¿Quéeslasemán8cadeunlenguaje?

CONSTMAX=100; R e g i s t r a r M A X c om oconstante entera de valor100

Traducciónsemán8caConstrucciónsintac8ca

Tipo Ejemplo Tiempodecompilación Tiempodeejecución

Declaracióndeconstantes

TYPETVector=ARRAY[1..MAX]OFINTEGER; Declaraciónde6pos

Registrar TVector como 6poARRAYdetamaño100ybaseINTEGER

VARv:TVector; Declaracióndevariables

Comprobar que TVectorexiste como un 6po yregistrarvcomounavariabledeese6po

PROCEDURESort(VARv:TVector);Declaracióndeprocedimientos

Registrar Sort como unprocedimientodelámbitoencurso indicando la lista de6pos de los parámetros.Crear un nuevo ámbito yregistrar en él v comovariablede6poTVector

Es necesario definir computacionalmente la semántica de un lenguaje para que el compilador sepa interpretar cada posible código fuente del mismo. La forma más sencilla de hacer esto es asociar a cada posible construcción gramatical ciertas reglas que permitan traducirla en términos computables. Esto sólo es posible si se cumple el principio de traducción dirigido por la sintaxis

Traduccióndirigidaporlasintaxis

Page 11: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 9

Introducción

¿Quéeslasemán8cadeunlenguaje?Es necesario definir computacionalmente la semántica de un lenguaje para que el compilador sepa interpretar cada posible código fuente del mismo. La forma más sencilla de hacer esto es asociar a cada posible construcción gramatical ciertas reglas que permitan traducirla en términos computables. Esto sólo es posible si se cumple el principio de traducción dirigido por la sintaxis

Traducciónsemán8caConstrucciónsintac8ca

Tipo Ejemplo Tiempodecompilación TiempodeejecuciónFunctionSort(VARv:TVector):INTEGER;Declaraciónde

funcionesAdicionalmente al caso deprocedimientos registrar queel6poderetornoesINTEGER

v[j]>v[j+1]Expresiones Comprobar que v estadeclaradopreviamenteyquee s d e 6 p o T V e c t o r .Asegurarse de que las sub-expresiones son correctas yde 6pos compa6bles con eloperadormayorque

Gene r a r c ód i go p a r arecuperar de memoria elvalordelassub-expresionesy aplicar la comparaciónent re ambos con lo soperadores del lenguaje debajonivel

SentenciaFor FORj:=1TOiDO...

Comprobar que la expresión1 e i son de 6po INTEGER.Comprobar que j ha sidopreviamentedeclaradacomounavariablede6poINTEGER

Gene r a r c ód i go p a r ainicializar j a 1. Generarcódigo de salto para iterarla ejecución del bloquedentro de FOR i veces.Gene r a r c ód i go p a r aactualizar a cada paso elvalordejaj+1

Traduccióndirigidaporlasintaxis

Page 12: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 10

Introducción

¿Quéeslasemán8cadeunlenguaje?

Traducción semán8caConstrucciónsintac8ca

Tipo Ejemplo Tiempodecompilación Tiempodeejecución

SentenciaIf IF(v[j]>v[j+1])THENBEGINtmp:=v[j];v[j]:=v[j+1];v[j+1]:=tmp;END;

Comprobar que la expresiónd e c o m p a r a c i ó n e ssemán6camente correcta(ver anterior) y comprobarque su evaluación devuelveun6pológico

Gene r a r c ód i go p a r ae v a l u a r l a e x p r e s i óndurante la e jecuc ión .GenerarcódigodesaltoqueejecuteelbloqueTHENsilaevaluación da TRUE enejecución

Sentenciadeasignación

tmp:=v[j]; Comprobar que tmp estadefinido. Comprobar que el6po de base de v e scompa6bleconeldetmp

Gene r a r c ód i go p a r aevaluar el valor de v[j] ycopiar su valor en lapos i c i ón de memor i aapuntadaportmp

Sentenciadellamadaa

procedimiento

sort(v,MAX); Comprobar que Sort estadeclarado como procedi-miento y que el número,o r d e n y 6 p o d e l o sparámetros ac tua les yformalescoinciden

Gene r a r c ód i go p a r ages6onar memoria quepermita la ac6vación delp r o c e d im i e n t o S o r t .Generar código de saltoparasuejecución

Es necesario definir computacionalmente la semántica de un lenguaje para que el compilador sepa interpretar cada posible código fuente del mismo. La forma más sencilla de hacer esto es asociar a cada posible construcción gramatical ciertas reglas que permitan traducirla en términos computables. Esto sólo es posible si se cumple el principio de traducción dirigido por la sintaxis

Traduccióndirigidaporlasintaxis

Page 13: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 11

Formalismosparalaespecificacióndetraducciones

EspecificacióndetraduccionesdirigidasporlasintaxisUna vez entendido el proceso de traducción dirigida por la sintaxis que nos permite conferir semántica a las construcciones de un lenguaje, necesitamos mecanismos formales y tecnológicos para especificar dicha traducción de manera precisa

Formalismosparalaespecificacióndetraduccionesdirigidasporlasintaxis

I.Definicionesdirigidasporlasintaxis

Las definiciones dirigidas por la sintaxis son un mecanismo de alto nivel que permite expresar la semántica asociada a las construcciones de un lenguaje en términos de una colección de reglas semánticas asociadas a cada regla de producción gramatical

II.Esquemasdetraduccióndirigidosporlasintaxis

Los esquemas de traducción dirigidos por la sintaxis permiten insertar, entre los símbolos gramaticales de la parte derecha de las reglas de producción, acciones semánticas cuyo propósito es realizar cierta traducción de carácter semántico. La ventaja de esta aproximación es que aquí se prescribe el momento exacto de la compilación en el que cada acción es ejecutada n

E

E

+ E

{:�:} n {:�:}

{:�:}

R1. E ::= E + E , Rs1

R2. E ::= n , Rs2

Page 14: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 12

Definicionesdirigidasporlasintaxis

DefinicionesdirigidasporlasintaxisLas definiciones dirigidas por la sintaxis (DDS) son un formalismo de alto nivel que permite asociar a cada regla de producción gramatical una regla semántica descrita, principalmente, en términos de una transformación de ciertos atributos asociados a cada no terminal de la gramática.

Elementosdelasdefinicionesdirigidasporlasintaxis

declaracion::=lVariables:tipo

lVariables::=lVariables1,ID

lVariables::=ID

tipo::=INTEGER;

tipo::=REAL;

lVariables.tipo:=tipo.tipo

lVariables1.tipo:=lVariables.tipo

<<registrarIDcomovariabledetipotipo>>

<<registrarIDcomovariabledetipotipo>>

tipo.tipo:=“ENTERO”

tipo.tipo:=“REAL”

I.Gramá8caconatributos II.Reglassemán8casA cada no terminal se asocian un conjunto de atributos para contener determinada información semántica que será utilizada en otras reglas de producción

declaracion[]

lVariables[tipo]

tipo[tipo]

Las reglas semánticas se encargan de transferir la información de unos atributos a otros y aplican acciones de traducción de carácter semántico

lVariables1.tipo:=lVariables.tipo

<<registrarIDcomovariabledetipotipo>>

Reglas semánticas Reglas de producción

atributo

Subíndice de diferenciación

Page 15: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 13

Definicionesdirigidasporlasintaxis

DefinicionesdirigidasporlasintaxisLas definiciones dirigidas por la sintaxis (DDS) son un formalismo de alto nivel que permite asociar a cada regla de producción gramatical una regla semántica descrita, principalmente, en términos de una transformación de ciertos atributos asociados a cada no terminal de la gramática.

Atributos

Un atributo es un espacio de información con tipificación implícita que sirve

para albergar una característica propia del proceso de traducción y que

puede ser transferida a otras producciones gramaticales para que pueda

ser utilizada desde allí por sus reglas semánticas

I.Atributossinte8zados

Se dice que un atributo es sintetizado si su valor es calculado exclusivamente a partir de atributos de los símbolos gramaticales de la parte derecha de sus reglas de producción. El carácter sintetizado de un atributo se mantiene a lo largo de toda la gramática

8posdeatributos II.Atributosheredados

Se dice que un atributo es heredados si su valor es calculado a partir de atributos de los símbolos gramaticales de las regla de producción en que aparece o de los antecedentes de las misma. El carácter heredado de un atributo se mantiene a lo largo de toda la gramática

A.a:=f(B.b,C.c,D.D)

A

B C D b c d

a

B.b:=f(A.a,C.c,D.D)

A

B C D b c d

a

Page 16: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 14

Definicionesdirigidasporlasintaxis

DefinicionesdirigidasporlasintaxisLas definiciones dirigidas por la sintaxis (DDS) son un formalismo de alto nivel que permite asociar a cada regla de producción gramatical una regla semántica descrita, principalmente, en términos de una transformación de ciertos atributos asociados a cada no terminal de la gramática.

Reglassemán8cas

Una regla semántica es una expresión formal asociada a una regla de

producción que permite definir la semántica de la construcción gramatical

asociada a la misma en términos de los símbolos de la regla de producción

I.Reglasdeecuacionesdeatributos

Las reglas de ecuaciones de atributos se utilizan para copiar, mover o transformar la información soportada por los atributos asociados a los símbolos de una regla hacia los atributos asociados a los símbolos no terminales de otra u otras reglas. Para concatenar valores de tipo cadena se usa el operador ||

8posdereglas

semán8cas

II.Reglasdeacciónsemán8ca

Las reglas de acción semántica son instrucciones o pseudo-insstrucciones que se utilizan para provocar algún efecto semántico sobre la traducción. Dado sus posibles efectos colaterales deben ser evitadas en la medida de lo posible.

lVariables1.tipo:=lVariables.tipo

<<registrarIDcomovariable...>>

No terminal Terminal o No terminal

asignación

atributo

Page 17: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 15

Definicionesdirigidasporlasintaxis

DefinicionesdirigidasporlasintaxisLas definiciones dirigidas por la sintaxis (DDS) son un formalismo de alto nivel que permite asociar a cada regla de producción gramatical una regla semántica descrita, principalmente, en términos de una transformación de ciertos atributos asociados a cada no terminal de la gramática.

Grafosdedependencias

Un grafo de dependencias refleja, sobre un árbol de análisis sintáctico las

dependencias entre los atributos gramaticales establecidas en virtud de las

reglas semánticas que les asignan valor

La aplicación de las ecuaciones de atributos de las reglas semánt icas inducen cier tas dependencias entre los mismos. En efecto, si un atributo se calcula a partir de otros, es natural pensar que existe una dependencia del primero para con los segundos. Esta dependencia se dibuja en el grafo como un arco de cada uno de los segundos al primero

B.b:=f(A.a,C.c,D.D)

A

B C D b c d

a

El grafo de dependencias se utiliza para expresar gráficamente el orden en que deben ser calculados los atributos y por ende inducen un orden de aplicación de las regla semánticas. En efecto, si un atributo se calcula a partir de otros es natural pensar que antes de calcular el primeros necesario calcular los segundos

CalcularA.a

CalcularC.c

CalcularD.d

CalcularB.b

en cualquier orden

Calcular después

Page 18: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 16

Definicionesdirigidasporlasintaxis

DefinicionesdirigidasporlasintaxisLas definiciones dirigidas por la sintaxis (DDS) son un formalismo de alto nivel que permite asociar a cada regla de producción gramatical una regla semántica descrita, principalmente, en términos de una transformación de ciertos atributos asociados a cada no terminal de la gramática.

Grafosdedependencias

Un grafo de dependencias refleja, sobre un árbol de análisis sintáctico las

dependencias entre los atributos gramaticales establecidas en virtud de las

reglas semánticas que les asignan valor

Algoritmodecálculo

ParacadaproducciónA::=X1X2...XnCrearunnodoporcadaatributoXi.ajdecadasímbolo

ParacadareglasemánticadelaformaXi.aj=f(...,Xk.al,...)

Paracadakycadal

CreararcodesdeXk.alhastaXi.aj

Unirtodoslosgrafosresultantes

B.b:=f(A.a,C.c,D.D)

A

B C D b c d

a

A.a:=f(B.b,C.c,D.D)A

B C D b c d

a

Page 19: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 17

Definicionesdirigidasporlasintaxis

DefinicionesdirigidasporlasintaxisLas definiciones dirigidas por la sintaxis (DDS) son un formalismo de alto nivel que permite asociar a cada regla de producción gramatical una regla semántica descrita, principalmente, en términos de una transformación de ciertos atributos asociados a cada no terminal de la gramática.

Grafosdedependenciasa,b:INTEGER;declaracion::=lVariables:tipo

lVariables::=lVariables1,ID

lVariables::=ID

tipo::=INTEGER;

tipo::=REAL;

lVariables.tipo:=tipo.tipo

lVariables1.tipo:=lVariables.tipo

<<registrarIDcomovariabledetipotipo>>

<<registrarIDcomovariabledetipotipo>>

tipo.tipo:=“ENTERO”

tipo.tipo:=“REAL”declaración

lVariables tipo

INTEGER ID

:

lVariables ,

ID

.tipo.tipo

.tipo

“ENTERO”“ENTERO”

“ENTERO”

El grafo de dependencias pone de manifiesto que para registrar las variables a y b es necesario recuperar la información de tipo extraída de la regla tipo ::= INTEGER y moverla sobre el árbol de análisis sintáctico hasta las reglas con ID. Para ello se utiliza el atributo tipo en cada no terminal y las reglas semánticas adjuntas

}

lVariables.tipo[Heredado]tipo.tipo[sintetizado]

<<registrarIDcontipo>>

<<registrarIDcontipo>>

Page 20: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 18

Definicionesdirigidasporlasintaxis

DefinicionesdirigidasporlasintaxisLas definiciones dirigidas por la sintaxis (DDS) son un formalismo de alto nivel que permite asociar a cada regla de producción gramatical una regla semántica descrita, principalmente, en términos de una transformación de ciertos atributos asociados a cada no terminal de la gramática.

DiseñodedefinicionesdirigidasporlasintaxisEl diseño de definiciones dirigidas por la sintaxis es un ejercicio complejo que requiere realizarse cuidadosa y sistemáticamente. A continuación proporcionamos un procedimiento orientativo que puede ayudar a alcanzar más fácilmente este objetivo

I.Especificacióngrama8calConstruya la gramática sobre la cual desea articular la definición dirigida por la sintaxis. Asegúrese de que esta gramática es correcta y no ambigua

II.Seleccióndeunafraserepresenta8vaSeleccione una frase del lenguaje. Asegúrese de que es lo suficientemente compleja como para que implique visitar al menos una vez cada regla gramatical

III.ConstruccióndelárboldeanálisisConstruya el árbol de análisis sintáctico asociado a dicha frase. Asegúrese de que existe al menos una instancia de cada regla

IV.SeleccióndeatributosDefina los atributos semánticos que requerirá su definición en cada símbolo gramatical y caracterícelos como sintetizados o heredados. Esto último se puede postergar para el final

V.GrafodedependenciasDibuje el grafo de dependencias que debería producirse para asegurar que la información fluya adecuadamente. Considere siempre un procesamiento descendente

VI.EspecificacióndeladefiniciónEscriba las reglas semánticas necesarias , con el nivel de abstracción oportuno, para garantizar que se satisface el grafo de dependencias. Incluya las reglas de acción pertinentes

Page 21: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 19

Definicionesdirigidasporlasintaxis

DefinicionesdirigidasporlasintaxisLas definiciones dirigidas por la sintaxis (DDS) son un formalismo de alto nivel que permite asociar a cada regla de producción gramatical una regla semántica descrita, principalmente, en términos de una transformación de ciertos atributos asociados a cada no terminal de la gramática.

EjemploSe pretende construir una calculadora que permita escribir expresiones aritméticas y calcular su valor asociado

E::=E+T|E–T|T

T::=T*F|T/F|F

F::=(E)|n

� � 2+3*5�

E

T

F

E +

F T *

n

n F

T

n

E.value[Sintetizado]T.value[Sintetizado]F.value[Sintetizado]n.value[Sintetizado]

E

T

F

E +

F T *

n F

T

n

.value

n

.value

.value

.value

.value

.value

.value

.value

2

2

2

3

15

5

53

3

2=17

E::=E+TE.value:=E.value+T.value

E::=E–TE.value:=E.value-T.value

E::=TE.value:=T.value

T::=T*FT.value:=T.value*F.value

T::=T/FT.value:=T.value/F.value

T::=FT.value:=F.value

F::=(E)F.value:=E.value

F::=nF.value:=n.value

.value

.value

.value

Page 22: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 20

Definicionesdirigidasporlasintaxis

DefinicionesdirigidasporlasintaxisLas definiciones dirigidas por la sintaxis (DDS) son un formalismo de alto nivel que permite asociar a cada regla de producción gramatical una regla semántica descrita, principalmente, en términos de una transformación de ciertos atributos asociados a cada no terminal de la gramática.

Ejercicios

E::=E+T|E–T|T

T::=T*F|T/F|F

F::=(E)|n

A continuación se muestra una gramática de operadores no ambigua. Especifique sobre ella una DDS para pasar expresiones aritméticas infijas a notación postfija

La siguiente gramática corresponde a la declaración de variables es Pascal. Especifique sobre ella una DDS para traducir dichas declaraciones a sintaxis C

declaracion::=lVariables:tipo

lVariables::=lVariables1,ID

lVariables::=ID

tipo::=INTEGER;

tipo::=REAL;

B::=DB|D

D::=0|1

La siguiente gramática representa números binarios. Defina una DDS que traduzca cualquier binario colocando todos los 0 delante y todos los 1 detrás. Por ejemplo 01101 se traduce a 00111

N::=DN|D

D::=0|1|2|3|4

5|6|7

La siguiente gramática se utiliza para representar números en octal. Constrúyase una DDS para obtener su traducción equivalente en base 10

Page 23: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 21

Definicionesdirigidasporlasintaxis

DefinicionesdirigidasporlasintaxisLas definiciones dirigidas por la sintaxis (DDS) son un formalismo de alto nivel que permite asociar a cada regla de producción gramatical una regla semántica descrita, principalmente, en términos de una transformación de ciertos atributos asociados a cada no terminal de la gramática.

Gramá8casconatributosporlaizquierdaEn algunas ocasiones, las definiciones dirigidas por la sintaxis imponen un orden de evaluación de las reglas semánticas contrario al orden natural en el que el analizador sintáctico va consumiendo tokens de la cadena de entrada y construyendo el árbol de análisis sintáctico. En concreto el problema surge cuando aparecen dependencias que fluyen de derecha a izquierda dentro del grafo

a,b:INTEGER;

declaracion::=lVariables:tipo

lVariables::=lVariables1,ID

lVariables::=ID

tipo::=INTEGER;

tipo::=REAL;

declaración

lVariables tipo

INTEGER ID

:

lVariables ,

ID

.tipo.tipo

.tipo

“ENTERO”“ENTERO”

“ENTERO”

<<registrarIDcontipo>>

<<registrarIDcontipo>>

Page 24: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 22

Definicionesdirigidasporlasintaxis

DefinicionesdirigidasporlasintaxisLas definiciones dirigidas por la sintaxis (DDS) son un formalismo de alto nivel que permite asociar a cada regla de producción gramatical una regla semántica descrita, principalmente, en términos de una transformación de ciertos atributos asociados a cada no terminal de la gramática.

Gramá8casconatributosporlaizquierdaEste tipo de definiciones son conflictivas ya que las dependencias de derecha a izquierda exigen dejar pendiente el cálculo de un atributo y avanzar el procesamiento sintáctico hasta alcanzar la regla que calcula el atributo del que depende para posteriormente completar el primero en una segunda pasada. Esto obliga a hacer la siguiente clasificación

Tiposdetraductores

I.Traductoresdeunasolapasada

II.Traductoresdedoblepasada

Los traductores sin dependencias de derecha a izquierda consiguen articular el cálculo de los atributos semánticos a medida que construyen el árbol de análisis sintáctico con lo que generan compiladores eficientes que recorren el árbol una sola vez

Los traductores con dependencias de derecha a izquierda deben postergar el cálculo de algunos atributos hasta que se conozca el valor de todos aquellos de los que depende. Este tipo de compiladores deben construir el árbol de análisis sintáctico y realizar una segunda pasada para calcular los atributos pendientes

declaración

lVariables tipo : .tipo.tipo

declaración

tipo lVariables .tipo.tipo

Gramática Pascal

Gramática C

L

J

Page 25: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 23

Definicionesdirigidasporlasintaxis

DefinicionesdirigidasporlasintaxisLas definiciones dirigidas por la sintaxis (DDS) son un formalismo de alto nivel que permite asociar a cada regla de producción gramatical una regla semántica descrita, principalmente, en términos de una transformación de ciertos atributos asociados a cada no terminal de la gramática.

Gramá8casconatributosporlaizquierdaLos traductores de doble pasada empeoran notablemente el rendimiento del compilador. Por lo tanto es deseable que las definiciones dirigidas por la sintaxis no presenten dependencias de derecha a izquierda. De se así pueden aplicarse transformaciones gramaticales para intentar invertir la polaridad de las dependencias favorablemente

declaracion::=ID,declaracion1declaracion.tipo=declaracion1.tipo

<<registrarIDcontipo>>

declaracion::=ID:tipodeclaracion.tipo=tipo.tipo

<<registrarIDcontipo>>

tipo::=INTEGER;tipo.tipo:=“ENTERO”

tipo::=REAL;tipo.tipo:=“REAL”

declaración

ID declaración ,

.tipo

“ENTERO”

“ENTERO”

a,b:INTEGER;

ID tipo :

INTEGER

<<registrarIDcontipo>>

<<registrarIDcontipo>>

.tipo

“ENTERO”

El árbol de análisis sintáctico ahora no fuerza la existencia de dependencias de derecha a izquierda puesto que para procesar la frase de declaración es prescriptivo alcanzar el tipo

}

Page 26: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 24

Definicionesdirigidasporlasintaxis

DefinicionesdirigidasporlasintaxisLas definiciones dirigidas por la sintaxis (DDS) son un formalismo de alto nivel que permite asociar a cada regla de producción gramatical una regla semántica descrita, principalmente, en términos de una transformación de ciertos atributos asociados a cada no terminal de la gramática.

Gramá8casconatributosporlaizquierdaDados los problemas que presentan las dependencias de derecha a izquierda debemos buscar gramáticas que no induzcan este tipo ordenamiento semántico. A estas gramáticas se les conoce por el nombre de gramáticas con atributos por la izquierda

Una gramática con atributos por la izquierda es una gramática de atributos

en la que cada atributo heredado Xi.h de una regla de producción de la

forma A ::= X1 … Xi … Xn, solo depende de los atributos X1 a Xi-1 o los

atributos heredados de A

A

X1 X2 X3

La información fluye de arriba abajo, de de abajo a arriba y de izquierda a derecha pero nunca de derecha a izquierda

}

Page 27: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 25

Esquemasdetraduccióndirigidosporlasintaxis

EsquemasdetraduccióndirigidosporlasintaxisLas definiciones dirigidas por la sintaxis son formalismos abstractos de traducción de alto nivel y por tanto adolecen de un mecanismo para indica el momento exacto en el que cada regla semántica debe ejecutarse. Una versión computacional que soluciona este problema son los esquemas de traducción dirigidos por la sintaxis

Elementosdelastraduccionesdirigidasporlasintaxis

I.Gramá8caconatributos II.Accionessemán8casComo en las definiciones dirigidas por la sintaxis, los esquemas de traducción también se construyen sobre gramáticas con atributos

E[trad]

E’[trad]

T[trad]

num[lexema]

Las acciones semánticas se insertan entre los símbolos gramaticales de la parte derecha de cada regla y, cuando se visitan durante la construcción del árbol de análisis sintáctico, realizan los traducciones semánticas pertinentes

E::=T{:E’.trad:=T.trad:}E’{:E.trad:=E’.trad:}

E’::=+T{:E’1.trad:=E’.trad||T.trad||“+”:}E’1{:E’.trad:=E’1.trad:}

E’::=-T{:E’1.trad:=E’.trad||T.trad||“-”:}E’1{:E’.trad:=E’1.trad:}

E’::=ε{:E’.trad:=E’.trad:}

T::=num{:T.trad:=num.lexema:}

Reglas de producción Subíndice de diferenciación

Acción semántica

Atributo

E::=T{:E’.trad:=T.trad:}

E’{:E.trad:=E’.trad:}

Page 28: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 26

Esquemasdetraduccióndirigidosporlasintaxis

EsquemasdetraduccióndirigidosporlasintaxisLas definiciones dirigidas por la sintaxis son formalismos abstractos de traducción de alto nivel y por tanto adolecen de un mecanismo para indica el momento exacto en el que cada regla semántica debe ejecutarse. Una versión computacional que soluciona este problema son los esquemas de traducción dirigidos por la sintaxis

Atributos

Un atributo es un espacio de información con tipificación explícita que sirve

para albergar una característica propia del proceso de traducción y que

puede ser transferida a otras producciones gramaticales para que pueda

ser utilizada desde allí por sus reglas semánticas

I.Atributossinte8zados

Se dice que un atributo es sintetizado si su valor es calculado exclusivamente a partir de atributos de los símbolos gramaticales de la parte derecha de sus reglas de producción. El carácter sintetizado de un atributo se mantiene a lo largo de toda la gramática

8posdeatributos II.Atributosheredados

Se dice que un atributo es heredados si su valor es calculado a partir de atributos de los símbolos gramaticales de las regla de producción en que aparece o de los antecedentes de las misma. El carácter heredado de un atributo se mantiene a lo largo de toda la gramática

A.a:=f(B.b,C.c,D.D)

A

B C D b c d

a

B.b:=f(A.a,C.c,D.D)

A

B C D b c d

a

Page 29: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 27

Esquemasdetraduccióndirigidosporlasintaxis

EsquemasdetraduccióndirigidosporlasintaxisLas definiciones dirigidas por la sintaxis son formalismos abstractos de traducción de alto nivel y por tanto adolecen de un mecanismo para indica el momento exacto en el que cada regla semántica debe ejecutarse. Una versión computacional que soluciona este problema son los esquemas de traducción dirigidos por la sintaxis

Acciónsemán8ca

Una acción semántica es un fragmento de código ejecutable, insertado en

algún punto de la parte derecha de una regla de producción, encargado de

realizar cierta lógica de traducción a partir de la información soportada por

los atributos de los símbolos gramaticales de dicha regla

E::=T{:E’.trad:=T.trad:}E’{:E.trad:=E’.trad:}

Cada acción semántica se inserta en el lugar adecuado para que sea ejecutada en el momento preciso durante la construcción del árbol de análisis sintáctico

}

El contenido de la acción se expresa, frecuentemente, en el l engua je de p rogramac ión anfitrión del compilador que se está construyendo

}

Como en las DDS, las acciones semánt icas f recuentemente r e a l i z a n o p e r a c i o n e s d e manipulación de atributos pero también puede llevar acabo operaciones con potenciales efectos colaterales

}

Page 30: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 28

Esquemasdetraduccióndirigidosporlasintaxis

EsquemasdetraduccióndirigidosporlasintaxisLas definiciones dirigidas por la sintaxis son formalismos abstractos de traducción de alto nivel y por tanto adolecen de un mecanismo para indica el momento exacto en el que cada regla semántica debe ejecutarse. Una versión computacional que soluciona este problema son los esquemas de traducción dirigidos por la sintaxis

DiseñodetraduccionesdirigidasporlasintaxisAntes de dar un procedimiento orientativo para la construcción de esquemas de traducción dirigidos por la sintaxis es preciso conocer ciertas restricciones de diseño de los mismos relacionadas con el lugar adecuado donde deben ubicarse las acciones semánticas

}  Si existen atributos sintetizados colocar la acción semántica después de todos los símbolos implicados o al final de la producción

}  Si existen atributos heredados deben calcularse antes de que aparezca el símbolo en la parte derecha

}  Un atributo sintetizado no debe usarse antes de que aparezca el símbolo en la parte derecha

A:=BC{:A.a:=f(B.a,C.a):}D

A:=BCD{:A.a:=f(B.a,C.a):}

A:=BC{:D.h:=f(B.a,C.a):}D

A:=B{:A.s:=f(B.s,C.s):}CD

A:=BC{:A.s:=f(B.s,C.s):}D

}  Si existen acciones con efectos laterales deben situarse en el punto exacto de la parte derecha de la regla en la que deberían evaluarse. Hay que verificar que no utilizan atributos de símbolos situados a la derecha de dicho punto

Page 31: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 29

Esquemasdetraduccióndirigidosporlasintaxis

EsquemasdetraduccióndirigidosporlasintaxisLas definiciones dirigidas por la sintaxis son formalismos abstractos de traducción de alto nivel y por tanto adolecen de un mecanismo para indica el momento exacto en el que cada regla semántica debe ejecutarse. Una versión computacional que soluciona este problema son los esquemas de traducción dirigidos por la sintaxis

DiseñodetraduccionesdirigidasporlasintaxisEl diseño de esquemas de traducción dirigidos por la sintaxis es un ejercicio complejo que requiere realizarse cuidadosa y sistemáticamente. A continuación proporcionamos un procedimiento orientativo que puede ayudar a alcanzar más fácilmente este objetivo

I.Especificacióngrama8calConstruya la gramática sobre la cual desea articular la traducción dirigida por la sintaxis. Asegúrese de que esta gramática es correcta y no ambigua

II.Seleccióndeunafraserepresenta8vaSeleccione una frase del lenguaje. Asegúrese de que es lo suficientemente compleja como para que implique visitar al menos una vez cada regla gramatical

III.ConstruccióndelárboldeanálisisConstruya el árbol de análisis sintáctico asociado a dicha frase. Asegúrese de que existe al menos una instancia de cada regla

IV.SeleccióndeatributosDefina los atributos que requerirá su esquema de traducción en cada símbolo gramatical y caracterícelos como sintetizados o heredados. Esto último se puede postergar para el final

V.GrafodedependenciasDibuje el grafo de dependencias que debería producirse para asegurar que la información fluya adecuadamente. Considere siempre un procesamiento descendente

VI.EspecificacióndelatraducciónEscriba la traducción dirigida por la sintaxis ubicando las acciones semánticas de acuerdo a las restricciones de diseño preliminares

Page 32: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 30

Esquemasdetraduccióndirigidosporlasintaxis

EsquemasdetraduccióndirigidosporlasintaxisLas definiciones dirigidas por la sintaxis son formalismos abstractos de traducción de alto nivel y por tanto adolecen de un mecanismo para indica el momento exacto en el que cada regla semántica debe ejecutarse. Una versión computacional que soluciona este problema son los esquemas de traducción dirigidos por la sintaxis

EjemploE

T E’ {:E’.trad:=‘9’:} {:E.trad:=‘95–2+’:}

num (9)

{:T.trad:=‘9’:} - T E’ {:E’1.trad:=‘95-’:} {:E’.trad:=‘95–2+’:}

num (5)

{:T.trad:=‘5’:} + T E’ {:E’1.trad:=‘95–2+’:} {:E’.trad:=‘95–2+’:}

num (2)

{:T.trad:=‘2’:} ε {:E’.trad:=‘95–2+’:}

Page 33: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 31

Traduccióndirigidaporlasintaxisenlaprác6ca

Esquemasdetraducciónenlaprác8caEl siguiente paso para construir el compilador es articular en cup un esquema de traducción dirigido por la sintaxis. Esta herramienta ya provee un mecanismo para llevar esto a cabo. A continuación damos la secuencia de pasos que deben realizarse

ImplementacióndeclasesNoTerminales

Consúltese el documento directrices de implementación

La implementación de esquemas de traducción en cup parte de la implementación de una clase para cada no terminal. Estas clases son contenedores para los atributos semánticos que serán utilizados posteriormente

I.ConstruccióndelaclasePara implementar la clase asociada a cada no terminal recomendamos que se utilice el mismo nombre que se usó para nombrarlo en cup, eliminando caracteres extraños y siguiendo los criterios de nombrado de Java. Si lo cree conveniente créese un script para automatizar la construcción de estas clases con un esqueleto vacío. Además considere la posibilidad de extender de una clase base para factorizar cierto código común a todas las clases de no terminales Todas estas clases deben implementarse en el paquete nonTerminal

publicExpresionextendsNonTerminal{

...

}

Page 34: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 32

Traduccióndirigidaporlasintaxisenlaprác6ca

Esquemasdetraducciónenlaprác8caEl siguiente paso para construir el compilador es articular en cup un esquema de traducción dirigido por la sintaxis. Esta herramienta ya provee un mecanismo para llevar esto a cabo. A continuación damos la secuencia de pasos que deben realizarse

ImplementacióndeclasesNoTerminales

Consúltese el documento directrices de implementación

La implementación de esquemas de traducción en cup parte de la implementación de una clase para cada no terminal. Estas clases son contenedores para los atributos semánticos que serán utilizados posteriormente

II.ImplementacióndeconstructoresIncluya en cada clase tantos constructores como resulten necesarios. Recomendamos definir un constructor por defecto sin argumentos y otros que reciban como argumentos otras clases de no terminales necesarias, de acuerdo al análisis de dependencias del esquema de traducción dirigido por la sintaxis Considere la posibilidad de centralizar la lógica común de cada constructor en uno de los constructores de manera que el resto delegue en ellos

publicExpresionextendsNonTerminal{

...

publicExpresion(){...}

publicExpresion(Expresione){...}

publicExpresion(Expresionleft,

Expresionright){...}

}

Page 35: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 33

Traduccióndirigidaporlasintaxisenlaprác6ca

Esquemasdetraducciónenlaprác8caEl siguiente paso para construir el compilador es articular en cup un esquema de traducción dirigido por la sintaxis. Esta herramienta ya provee un mecanismo para llevar esto a cabo. A continuación damos la secuencia de pasos que deben realizarse

ImplementacióndeclasesNoTerminales

Consúltese el documento directrices de implementación

La implementación de esquemas de traducción en cup parte de la implementación de una clase para cada no terminal. Estas clases son contenedores para los atributos semánticos que serán utilizados posteriormente

III.ImplementaciónatributosDeclare como variables privadas de clase cada uno de los atributos que contendrá el no terminal de la clase que está implementando. Para cada atributo implemente dos métodos de acceso público. una operación consultora con prefijo get y otra modificadora con prefijo set. Considere esta tarea como un proceso de refinamiento sucesivo que se irá completando cuando tenga claro qué atributos es necesario incluir en cada clase no terminal a tenor del esquema de traducción que está articulando

publicExpresionextendsNonTerminal{

List<QuadrupleIF>code;

TypeIFtype;

TemporalIFtemporal;

...

publicList<QuadrupleIF>getCode(){...}

publicvoidsetCode(List<QuadrupleIF>code){...}

publicTypeIFgetType(){...}

publicvoidsetType(TypeIFtype){...}

publicTemporalIFgetTemporal(){...}

publicvoidsetTemporal(TemporalIFtemporal){...}

...

}

Page 36: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 34

Traduccióndirigidaporlasintaxisenlaprác6ca

Esquemasdetraducciónenlaprác8caEl siguiente paso para construir el compilador es articular en cup un esquema de traducción dirigido por la sintaxis. Esta herramienta ya provee un mecanismo para llevar esto a cabo. A continuación damos la secuencia de pasos que deben realizarse

ImplementacióndeclasesNoTerminales

Consúltese el documento directrices de implementación

La implementación de esquemas de traducción en cup parte de la implementación de una clase para cada no terminal. Estas clases son contenedores para los atributos semánticos que serán utilizados posteriormente

IV.SobrescriturademétodosdeObjectJava impone, normativamente, que la imple-mentación de cualquier clase debe incluir la sobreescritura de 3 métodos: hashcode, para devolver una representación numérica única del objeto; equals, para comparar un objeto con otro y toString para devolver una cadena que contenga inforrmación sobre el estado del problema. R e c o m e n d a m o s e n c a r e c i d a m e n t e l a implementación de estos tres métodos puesto que puede simplificar considerablemente la construcción del compiladores en fases subsiguientes

publicExpresionextendsNonTerminal{

...

longhashcode(){

return67*67*code.hashcode()+

67*type.hashcode()+temporal.hascode();

}

booleanequals(Objecto){

if(!(oinstanceofExpresion))returnfalse;

else{Expressione=(Expresion)o;

returne.code.equals(this.code)&&

e.type.equals(this.type)&&

e.temporal.equals(this.temporal);}

}

publicStringtoString(){...}}

Page 37: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 35

Traduccióndirigidaporlasintaxisenlaprác6ca

Esquemasdetraducciónenlaprác8caEl siguiente paso para construir el compilador es articular en cup un esquema de traducción dirigido por la sintaxis. Esta herramienta ya provee un mecanismo para llevar esto a cabo. A continuación damos la secuencia de pasos que deben realizarse

TipificacióndeNoTerminalesencup

Consúltese el documento directrices de implementación

Una vez construidas todas las clases de los no terminales que conforman nuestra especificación gramatical en cup, es necesario indicar a esta herramienta que, durante el proceso de construcción del árbol de análisis sintáctico, debe considerar cada no terminal como un objeto de la clase correspondiente. Esto se hace alterando la sección de declaración de no terminales mediante su tipificación

Se incluye el nombre de la

clase entre nonTerminal y el

nombre del no terminal.

Asegúrese de haber importado

nonTerminal

Page 38: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 36

Traduccióndirigidaporlasintaxisenlaprác6ca

Esquemasdetraducciónenlaprác8caEl siguiente paso para construir el compilador es articular en cup un esquema de traducción dirigido por la sintaxis. Esta herramienta ya provee un mecanismo para llevar esto a cabo. A continuación damos la secuencia de pasos que deben realizarse

Implementacióndelesquemadetraducciónencup

Consúltese el documento directrices de implementación

En cup, la implementación de esquemas de traducción dirigidos por la sintaxis permite utilizar solamente atributos sintetizados. Cada regla de producción debe tener una acción semántica que construya un objeto de la clase no terminal del antecedente, asigne valor a sus atributos, y, como última instrucción, lo asigne a RESULT. Esto hará que dicho objeto se copie al no terminal del antecedente para que sea consultado en otras reglas

expresion::=expresion:e1MASexpresion:e2

{:Expresione=newExpresion(e1,e2);

<<comprobacióndetipossobree1ye2>>

<<generacióndecódigoparae1+e2>>

...

RESULT=e;:}

Uso de constructor

Acciones semánticas

Asignación de reducción

Al hacer esta asignación el objeto en la expresión de la parte derecha del igual se asigna como contenedor de información del no terminal del antecedente. Asegúrese de que el tipo de esta expresión es compatible con el declarado en la sección de no terminales para el antecedente

Nombramiento de símbolos gramaticales

Page 39: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 37

Traduccióndirigidaporlasintaxisenlaprác6ca

1.  Implementación de las clases java que representan los no terminales

1.  Hacerlos heredar de la clase NonTerminal

2.  Implementar constructores y constructores por copia

3.  Sobrescribir métodos heredados de la clase Object

4.  Considere la posibilidad de automatizar el proceso con script

2.  Tipificación de cada no terminal en Cup

1.  Declare el tipo – clase java – de cada no terminal de cup

2.  Considere la posibilidad de hacer jerarquías de clases

3.  Pruebe a implementar algún esquema de traducción sencillo de prueba

1.  Implemente una prueba para comprobar la propagación de información en cup

2.  Tenga en cuenta siempre que cada acción introducida semánticas pueden generar nuevos conflictos

Los atributos de los no terminales aún no son conocidos por lo tanto es imposible implementar sus métodos de acceso

DesarrollopasoapasoLa construcción de esta fase del compilador consiste en la preparación de la infraestructura de artefactos necesaria para articular los esquemas de traducción dirigida por la sintaxis tal y como se ha descrito con anterioridad. A continuación damos un generación de los pasos principales a dar

En Cup A ::= B {: <<acción>> :} C se traduce a A ::= B M C; M ::= {:<<acción>>:} lo cual puede llegar a generar nuevos conflictos en ocasiones

Page 40: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 38

Bibliograna

MaterialdeestudioBibliografía básica

Construcción de compiladores: principios y práctica

Kenneth C. Louden International Thomson Editores,

2004 ISBN 970-686-299-4

Page 41: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisissemán8co.Traduccióndirigidaporlasintaxis

6 - 39

Bibliograna

MaterialdeestudioBibliografía complementaria

Compiladores: Principios, técnicas y herramientas.

Segunda Edición Aho, Lam, Sethi, Ullman

Addison – Wesley, Pearson Educación, México 2008

Diseño de compiladores. A. Garrido, J. Iñesta, F. Moreno

y J. Pérez. 2002. Edita Universidad de Alicante

Page 42: Procesadores de Lenguajes I

ProcesadoresdeLenguajesIngenieríaTécnicasuperiordeIngenieríaInformá8ca

DepartamentodeLenguajesySistemasinformá6cos

JavierVé[email protected]

DepartamentodeLenguajesYSistemasInformáAcosUNED

7Análisissemán*coIIComprobacióndeApos

Page 43: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 2

Obje6vos

Obje8vos

›  Aprender qué es la comprobación de tipos

›  Entender qué es un sistema de tipos

›  Conocer los elementos constituyentes de un sistema de tipos

›  Conocer qué es una expresión de tipos

›  Aprender a escribir expresiones de tipos

›  Aprender las diferencias entre comprobación estática y dinámica

›  Entender qué es la equivalencia de tipos

›  Aprender las diferencias entre los distintos tipos de equivalencia de tipos

›  Entender qué es y como funciona la conversión de tipos

›  Entender qué es la sobrecarga y qué tipos de sobrecarga existen

›  Aprender a implementar un comprobador de tipos

›  Conocer las principales estructuras de datos y artefactos necesarios

Page 44: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 3

Índice

Índice

›  Introducción

›  Símbolos

›  Tipos

›  Ámbitos de declaración

›  El sistema de tipos

›  ¿Qué es el sistema de tipos?

›  Tipos primitivos

›  Constructores de tipos

›  Equivalencia de tipos

›  Verificación de tipos sobre operadores

›  Verificación de tipos sobre subprogramas

›  Construcción de un comprobador de tipos

›  Qué es un comprobador de tipos

›  Artefactos de un comprobador de tipos

›  Apertura de ámbito inicial

›  Declaración de constantes

›  Declaración de tipos

›  Declaración de variables

›  Declaración de subprogramas

›  Expresiones

›  Sentencias

›  Cierre de ámbitos

›  Temas avanzados de un comprobador de tipos

›  Inferencia de tipos

›  Sobrecarga de subprogramas

›  Recuperación de errores semánticos

›  Desarrollo paso a paso

›  Bibliografía

Page 45: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 4

Introducción

Análisissemán8coLa fase de análisis semántico tiene por objetivo analizar los componentes del árbol de análisis sintáctico que representan el programa con el fin de comprobar que se respetan ciertas reglas semánticas que dan un significado coherente a las construcciones del lenguaje

E l a n a l i z a d o r s e m á n t i c o v a c o m p r o b a n d o l a c o h e r e n c i a semántica del árbol de análisis sintáctico según se va construyendo

Foco de atención

Las responsabilidades son…

›  Registrar declaraciones

›  Inferir tipos

›  Comprobar tipos

›  Comprobar corrección semántica

Analizadorsemán8co

SWhile

WHILEEDOS

E>E

SWhile

WHILEEDOS

E>E

ü ü

ü ü

ü

Page 46: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 5

Introducción

ConceptosesencialesLos lenguajes modernos se articulan a partir de una estructura de bloques donde se pueden hacer declaraciones que luego serán referenciadas a lo largo del programa

CONSTMAX=10;TYPETVector=ARRAY[1..10]OFREAL;VARv,w:TVector;i:INTEGER;PROCEDURELeer(VARm:TVector);VARi:INTEGER;FUNCTIONValidar(VARv:INTEGER):INTEGER;BEGINValidar:=vmod10;END;BEGINFORi:=1TO10DOm[i]:=Validar(Read(i));END;END;FUNCTIONsuma(m,n:TVector):TVector;VARi:INTEGER;vSuma:TVector;BEGINWHILE(i<MAX)DOvSuma[i]:=m[i]+n[i];INC(i);END;suma:=vSuma;END;BEGINLeer(v);Leer(w);v:=suma(v,w);END.

Símbolos

Un símbolo de un programa es cualquier elemento con

nombre que el programador haya establecido como

válido dentro de él a través de una declaración

El ejercicio de creación de un programa consiste en la declaración de una colección de símbolos con nombres que representan entidades semánticas utilizadas a lo largo del código

El tipo de símbolos que pueden declararse en un p r o g r a m a e s u n a característica propia del lenguaje. No obstante puede identificarse ciertos tipos de símbolos recurrentes tales como constantes, variables, funciones, procedimientos o parámetros

Algunos lenguajes permiten elidir la declaración de los símbolos y utilizan reglas de inferencia para determinar los símbolos que son utilizados a lo largo del programa

Page 47: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 6

Introducción

ConceptosesencialesLos lenguajes modernos se articulan a partir de una estructura de bloques donde se pueden hacer declaraciones que luego serán referenciadas a lo largo del programa

Tipos

Un tipo es un descriptor semántico que permite cualificar

al símbolo al que está vinculado de manera que

condiciona su interpretación semántica y restringe las

operaciones que se pueden realizar sobre él

Cada símbolo del lenguaje lleva asociado un tipo. El tipo de un símbolo se utiliza para proporcionar información al compilador de cómo debe tratar semánticamente al mismo y qué operaciones debe permitir realizar sobre él

CONSTMAX=10;TYPETVector=ARRAY[1..10]OFREAL;VARv,w:TVector;i:INTEGER;PROCEDURELeer(VARm:TVector);VARi:INTEGER;FUNCTIONValidar(VARv:INTEGER):INTEGER;BEGINValidar:=vmod10;END;BEGINFORi:=1TO10DOm[i]:=Validar(Read(i));END;END;FUNCTIONsuma(m,n:TVector):TVector;VARi:INTEGER;vSuma:TVector;BEGINWHILE(i<MAX)DOvSuma[i]:=m[i]+n[i];INC(i);END;suma:=vSuma;END;BEGINLeer(v);Leer(w);v:=suma(v,w);END.

Todo lenguaje dispone de una colección de tipos primitivos y t a m b i é n d e c i e r t o s mecanismos semánticos para construir nuevos tipos a partir d e o t r o s p r e v i a m e n t e definidos

En aquellos lenguajes donde la tipificación no es explícita los símbolos adquieren un tipo tan pronto como sea posible aplicando reglas de inferencia de tipos

Page 48: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 7

Introducción

ConceptosesencialesLos lenguajes modernos se articulan a partir de una estructura de bloques donde se pueden hacer declaraciones que luego serán referenciadas a lo largo del programa

Ámbitosdedeclaraciónyalcancedevisibilidad

Un ámbito es un bloque acotado sintácticamente dentro

del cual los símbolos allí declarados tienen vigencia

Cada símbolo se declara dentro de un bloque acotado por ciertas construcciones sintácticas. Se entiende que dentro de dicho bloque la declaración tiene vigencia y puede ser utilizada mientras que fuera no existe y pueden declararse otros símbolos incluso aunque compartan el mismo nombre

En lenguajes estilo Pascal las construcciones sintácticas que representan creaciones de nuevos ámbitos, a parte del global, son únicamente la declaración de funciones y procedimientos

En lengua jes es t i l o C , además de las funciones y el ámbito global, cualquier bloque de sentencias acotado entre llaves constituye un ámbito de declaración nuevo

CONSTMAX=10;TYPETVector=ARRAY[1..10]OFREAL;VARv,w:TVector;i:INTEGER;PROCEDURELeer(VARm:TVector);VARi:INTEGER;FUNCTIONValidar(VARv:INTEGER):INTEGER;BEGINValidar:=vmod10;END;BEGINFORi:=1TO10DOm[i]:=Validar(Read(i));END;END;FUNCTIONsuma(m,n:TVector):TVector;VARi:INTEGER;vSuma:TVector;BEGINWHILE(i<MAX)DOvSuma[i]:=m[i]+n[i];INC(i);END;suma:=vSuma;END;BEGINLeer(v);Leer(w);v:=suma(v,w);END.

Page 49: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 8

Introducción

ConceptosesencialesLos lenguajes de programación articulan la definición de programas a través de la declaración de símbolos convenientemente tipificados que luego son referenciados a lo largo del código

Anidamientodeámbitos

Dadas varias declaraciones diferentes para el mismo

nombre en distintos ámbitos anidados, la declaración que

se aplica a una referencia es aquélla que se encuentre

en el bloque anidado más próximo a la misma

Cuando dos ámbitos se encuentran sintácticamente anidados uno dentro de otro, desde el más interno tienen visibilidad todas las declaraciones de símbolos realizadas en el ámbito más externo. Si dentro del ámbito interno se declara un nuevo símbolo con el mismo nombre que un símbolo en el ámbito externo, la declaración que pasa a tener vigencia es la realizada dentro del ámbito interno. Esto es cierto para cualquier nivel de anidamiento

CONSTMAX=10;TYPETVector=ARRAY[1..10]OFREAL;VARv,w:TVector;i:INTEGER;PROCEDURELeer(VARm:TVector);VARi:INTEGER;FUNCTIONValidar(VARv:INTEGER):INTEGER;BEGINValidar:=vmod10;END;BEGINFORi:=1TO10DOm[i]:=Validar(Read(i));END;END;FUNCTIONsuma(m,n:TVector):TVector;VARi:INTEGER;vSuma:TVector;BEGINWHILE(i<MAX)DOvSuma[i]:=m[i]+n[i];INC(i);END;suma:=vSuma;END;BEGINLeer(v);Leer(w);v:=suma(v,w);END.

Regladeanidamientomáscercano

ámbi

to n

ivel

0

ámbi

to n

ivel

1

ámbi

to n

ivel

1

ámbi

to n

ivel

2

Page 50: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 9

Introducción

¿Quéeslacomprobaciónde8pos?La labor de comprobación de tipos consiste en conferir a las construcciones sintácticas del lenguaje la semántica de tipificación que acabamos de describir y en realizar todo tipo de comprobaciones de dicha índole. Por su naturaleza, sin embargo, ésta se encuentra repartida entre la fase de análisis semántico y la generación de código intermedio

Análisissemán8co

Generacióncódigointermedio

S

WHILEEDOS

E>E

S

WHILEEDOS

E>E

LDat1LDbt2GRTt3t1t2BRZt3L1…

I.Comprobacionesestá8cas

II.Comprobacionesdinámicas

Las comprobaciones estáticas recogen el compendio de todas aquellas tareas de carácter semántico que, por su naturaleza, pueden ser realizadas directamente durante la fase de compilación mediante el uso de los artefactos y mecanismos propios de dicha fase. Este tipo de comprobaciones son beneficiosas puesto que confieren seguridad a la ejecución del programa

Las comprobaciones dinámicas son aquellas que no se realizan durante la fase de compilación y se delegan al momento de la ejecución del programa. Ello requiere generar código ejecutable específicamente diseñado para realizar tales comprobaciones. Los lenguajes con una carga excesiva de comprobaciones dinámicas generan programas más largos, lentos e inseguros en ejecución

Tiposdecomprobacionessemán8casTema 7

}

Tema 8-9

}

Page 51: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 10

Introducción

Tiposdecomprobacionessemán8casestá8cas

I.Ges8óndedeclaraciones

III.Inferenciade8pos

Se encarga de registrar todas las declaraciones realizadas por el programador a lo largo de los distintos ámbitos. Esta tarea implica el registro de tipos y la comprobación de que no se produce ninguna colisión de nombres con los identificadores de otras declaraciones

En lenguajes sin tipificación de variables o con sobrecarga se aplican tareas de inferencia de tipos en el nivel gramatical de las expresiones para resolver el tipo de datos de la expresión resultante en función del contexto de evaluación

II.Verificaciónde8posComprueba la compatibilidad de tipos de todas las expresiones del código fuente recuperando la información durante la gestión de declaraciones. Además se asegura de que no existe en el programa ninguna referencia a ningún símbolo no declarado

¿Quéeslacomprobaciónde8pos?La labor de comprobación de tipos consiste en conferir a las construcciones sintácticas del lenguaje la semántica de tipificación que acabamos de describir y en realizar todo tipo de comprobaciones de dicha índole. Por su naturaleza, sin embargo, ésta se encuentra repartida entre la fase de análisis semántico y la generación de código intermedio

CONSTMAX=10;TYPETVector=ARRAY[1..10]OFREAL;VARv,w:TVector;i:INTEGER;PROCEDURELeer(VARm:TVector);

Validar:=vmod10;WHILE(i<MAX)DO...v:=suma(v,w);

CONSTMAX=10;

Page 52: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 11

Sistemasde6pos

¿Quéeselsistemade8pos?El documento que recoge toda la información relativa a la tipificación de un lenguaje de programación, desde sus tipos primitivos, hasta sus tipos estructurados pasando por sus reglas de combinación operacional, recibe el nombre de sistema de tipos

El sistema de tipos de un lenguaje es una especificación de alto nivel que

describe de forma precisa el conjunto de reglas y restricciones semánticas de

tipificación que se aplican sobre las construcciones sintácticas del lenguaje

Nivelesde8pificaciónEl sistema de tipos de un lenguaje condiciona, de manera directa, la seguridad de los programas en tiempo de ejecución. En efecto, cuantas más comprobaciones se hagan en tiempo de compilación, menor será la probabilidad de fallo en ejecución. El nivel de construcción del sistema de tipos permite clasificar a los lenguajes en 2 categorías

Nivelesde8pificación

Lenguajesfuertemente8pificados

Lenguajesdébilmente8pificados

La tipificación fuerte implica un nivel de construcción elevado y es propia de lenguajes de programación seguros como Pascal, Ada o Modula

La tipificación débil implica pocas restricciones en el sistema de tipos y delega la mayor parte de la comprobación al tiempo de ejecución. Es propia de lenguajes de scripting como Groovy o Javascript

Page 53: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 12

Sistemasde6pos

¿Quéeselsistemade8pos?El documento que recoge toda la información relativa a la tipificación de un lenguaje de programación, desde sus tipos primitivos, hasta sus tipos estructurados pasando por sus reglas de combinación operacional, recibe el nombre de sistema de tipos

Expresionesde8posPara definir el sistema de tipos de un lenguaje de manera formal, sistemática e independientemente de las sintaxis propia del mismo se utilizan expresiones de tipos. Cada tipo primitivo tiene una expresión de tipo asociada. Cada constructor de tipo tiene también una expresión de tipo. Cada tipo definido mediante la composición de constructores de tipos y tipos primitivos tiene a su vez una expresión de tipos

Una expresión de tipos es un mecanismo formal utilizado por los sistemas

de tipos para representar el tipo de una construcción sintáctica propia del

lenguaje

El sistema de tipos de un lenguaje es una especificación de alto nivel que

describe de forma precisa el conjunto de reglas y restricciones semánticas de

tipificación que se aplican sobre las construcciones sintácticas del lenguaje

Page 54: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 13

Sistemasde6pos

Elementosdeunsistemade8posLa descripción del sistema de tipos de un lenguaje de programación se articula, fundamentalmente, mediante la definición de los tipos primitivos y constructores compuestos, sus reglas de composición, las operaciones permitidas sobre cada uno de ellos y el tipo de resultado que provocan

Tiposprimi8vos

Expresiónde8posTipo

Byte

Integer

Word

Real

Double

Boolean

Char

String

Representaciónnuméricacortasinsigno

Representaciónnuméricaconsigno

Representaciónnuméricalargasinsigno

Representaciónflotantecortaconsigno

Representaciónflotantelargaconsigno

Representaciónlógica

Representacióndecarácter

Representacióndecadena

Descripción Rango

0a255

-32768a32767

0a65535

2.9E-39a1.7E38

5.0E-324a1.7E308

False,True

ASCII

-

ENTERO

ENTERO

ENTERO

REAL

REAL

LOGICO

CARÁCTER

CADENA

Operaciones

+–*/mod=><<>

+–*/mod=><<>

+–*/mod=><<>

+–*/=><<>

+–*/=><<>

ANDORXORNOT

-

-

Los tipos primitivos de un lenguaje determinan la colección de tipos de datos originales que el lenguaje pone a disposición del programador para componer estructuras de datos más complejas. La variedad de tipos primitivas es una característica propia del lenguaje pero en general se distinguen cuatro categorías: ordinales, reales, lógicos y de carácter

Page 55: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 14

Sistemasde6pos

Elementosdeunsistemade8posLa descripción del sistema de tipos de un lenguaje de programación se articula, fundamentalmente, mediante la definición de los tipos primitivos y constructores compuestos, sus reglas de composición, las operaciones permitidas sobre cada uno de ellos y el tipo de resultado que provocan

Constructoresde8pos

Expresiónde8posEjemplo

TVector=ARRAY[1..10]OFINTEGER Representa una formación lineal deelementosdeunmismo6podebase

Descripción

ARRAY(1..10,ENTERO)

Los constructores de tipos son mecanismos sintácticos del lenguaje que permiten combinar otras construcciones de tipos, primitivos o compuestos, para generar estructuras más complejas. Los tipos así generados se llaman tipos complejos, tipos compuestos o tipos definidos por el usuario

TPunto=RECORDBEGINX:INTEGER;Y:INTEGEREND;

Representa una estructura de datoscons6tuida por una colección decamposconnombrededis6nto6po

RECORD((XxENTERO)x(YxENTERO))

^TPunto Representa un puntero a un área dememoria reservada para almacenardatosdeundeterminado6podebase

POINTER(TPunto)

TConjunto=SETOFINTEGER Representa un conjunto no ordenadode elemento de un mismo 6pos dedatosdebase

SET(ENTERO)

Page 56: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 15

Sistemasde6pos

Elementosdeunsistemade8posLa descripción del sistema de tipos de un lenguaje de programación se articula, fundamentalmente, mediante la definición de los tipos primitivos y constructores compuestos, sus reglas de composición, las operaciones permitidas sobre cada uno de ellos y el tipo de resultado que provocan

Constructoresde8pos

Expresiónde8posEjemplo

FUNCTIONsuma(m,n:TVector):Tvector;

Representaunadeclaraciónde funcióncon parámetros y 6po de retornodefinido

Descripción

(TvectorxTVector)"TVector

Los constructores de tipos son mecanismos sintácticos del lenguaje que permiten combinar otras construcciones de tipos, primitivos o compuestos, para generar estructuras más complejas. Los tipos así generados se llaman tipos complejos, tipos compuestos o tipos definidos por el usuario

PROCEDURELeer(n:TVector); Representa una declaración deprocedimiento con parámetrosdefinidos

(Tvector)"TVector

(INTEGER;INTEGER) Representa una tupla de datoscons6tuidaporunacolecciónordenadadedatosdedis6nto6po

(ENTERO)x(ENTERO)

TPalos=(OROS,COPAS,ESPADAS,BASTOS);

Representa una colección de e6quetasque se comportan como constantessimbólicasdevalornumérico

ENUM(OROS,COPAS,ESPADAS,BASTOS)

Page 57: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 16

Sistemasde6pos

Elementosdeunsistemade8posLa descripción del sistema de tipos de un lenguaje de programación se articula, fundamentalmente, mediante la definición de los tipos primitivos y constructores compuestos, sus reglas de composición, las operaciones permitidas sobre cada uno de ellos y el tipo de resultado que provocan

Constructoresde8posLos constructores de tipos son mecanismos sintácticos del lenguaje que permiten combinar otras construcciones de tipos, primitivos o compuestos, para generar estructuras más complejas. Los tipos así generados se llaman tipos complejos, tipos compuestos o tipos definidos por el usuario

EjerciciosUna vez que se conoce la expresión de tipos de los principales tipos del lenguaje y de los constructores de tipos pueden construirse las expresiones de tipos para diferentes tipos definidos por el usuario

TPEntero=^INTEGER;TMatriz=ARRAY[1..3][1..6];TPersona=RECORDBEGINnombre:STRING;edad:INTEGER;END;FUNCTIONmayor(a,b:INTEGER):INTEGER;FUNCTIONordenar(p:TPEntero):TPEntero;

TLista=RECORDBEGINvector:ARRAY[1..10]OFINTEGER;longitud:INTEGER;END;TTabla=ARRAY[1..100]OF^TLista;TCjtoTablas=SETOF^TTabla;

Page 58: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 17

Sistemasde6pos

Elementosdeunsistemade8posLa descripción del sistema de tipos de un lenguaje de programación se articula, fundamentalmente, mediante la definición de los tipos primitivos y constructores compuestos, sus reglas de composición, las operaciones permitidas sobre cada uno de ellos y el tipo de resultado que provocan

Equivalenciade8posDe cara a realizar comprobaciones estáticas, resulta interesante definir la equivalencia entre dos tipos complejos del lenguaje. Esta definición puede formularse en términos del nombre que reciben sendos tipos dentro del código o entre las expresiones de tipos subyacentes. Esto permite distinguir entre dos formas de entender la equivalencia lo cual es una característica intrínseca del lenguaje

I.Equivalencianominal

TYPET1=ARRAY[1..10]OFINTEGER;T2=ARRAY[1..10]OFINTEGER;T3=T1

Se dice que dos tipos de datos T1 y T2 son

nominalmente equivalentes si responden a

una misma entrada dentro del registro de

tipos realizado por el compilador durante la

gestión de declaraciones T1

T2

T3

Equivalente

Noequivalente

Equivalente

Noequivalente

Equivalente

NoEquivalente

Equivalente

Noequivalente

Equivalente

T1 T2 T3

Page 59: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 18

Sistemasde6pos

Elementosdeunsistemade8posLa descripción del sistema de tipos de un lenguaje de programación se articula, fundamentalmente, mediante la definición de los tipos primitivos y constructores compuestos, sus reglas de composición, las operaciones permitidas sobre cada uno de ellos y el tipo de resultado que provocan

Equivalenciade8posDe cara a realizar comprobaciones estáticas, resulta interesante definir la equivalencia entre dos tipos complejos del lenguaje. Esta definición puede formularse en términos del nombre que reciben sendos tipos dentro del código o entre las expresiones de tipos subyacentes. Esto permite distinguir entre dos formas de entender la equivalencia lo cual es una característica intrínseca del lenguaje

II.Equivalenciaestructural

TYPET1=ARRAY[1..10]OFINTEGER;T2=ARRAY[1..10]OFINTEGER;T3=T1

Se dice que dos tipos de datos son

estructuralmente equivalentes si son el

mismo tipo básico o están formadas

mediante la apl icación del mismo

constructor de tipos sobre expresiones de

tipos estructuralmente equivalentes T1

T2

T3

Equivalente

Equivalente

Equivalente

Equivalente

Equivalente

Equivalente

Equivalente

Equivalente

Equivalente

T1 T2 T3

Page 60: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 19

Sistemasde6pos

Elementosdeunsistemade8posLa descripción del sistema de tipos de un lenguaje de programación se articula, fundamentalmente, mediante la definición de los tipos primitivos y constructores compuestos, sus reglas de composición, las operaciones permitidas sobre cada uno de ellos y el tipo de resultado que provocan

Equivalenciade8posDe cara a realizar comprobaciones estáticas, resulta interesante definir la equivalencia entre dos tipos complejos del lenguaje. Esta definición puede formularse en términos del nombre que reciben sendos tipos dentro del código o entre las expresiones de tipos subyacentes. Esto permite distinguir entre dos formas de entender la equivalencia lo cual es una característica intrínseca del lenguaje

II.Equivalenciaestructural

booleanequivale(TypeIFs,TypeIFt){

if(s==t)returntrue;

if((s==ARRAY(s1,s2)&&t==ARRAY(t1,t2))||

(s==(s1xs2)&&t==(t1xt2))||

(s==(s1"s2)&&t==(t1"t2)))

returnequivale(s1,t1)&&equivale(t2,t2);

if((s==Pointer(s1)&&t==Pointer(t1))||

(s==Set(s1)&&t==Set(t1))

returnequivale(s1,t1);

returnfalse

}

Se dice que dos tipos de datos son

estructuralmente equivalentes si son el

mismo tipo básico o están formadas

mediante la apl icación del mismo

constructor de tipos sobre expresiones de

tipos estructuralmente equivalentes

Ojo con las definiciones de tipos recursivos }

Page 61: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 20

Sistemasde6pos

Elementosdeunsistemade8posLa descripción del sistema de tipos de un lenguaje de programación se articula, fundamentalmente, mediante la definición de los tipos primitivos y constructores compuestos, sus reglas de composición, las operaciones permitidas sobre cada uno de ellos y el tipo de resultado que provocan

Verificaciónde8possobreoperadoresLa mayoría de operadores de un lenguaje de programación pueden operarse satisfactoriamente sobre un subconjunto de tipos primitivos del lenguaje. Esto desencadena una serie de conceptos tan interrelacionados entre si que conviene abordarlos conjuntamente

I.Sobrecargadeoperadores

2+3

4.2+3.8

En estos ejemplos en Pascal puede verse como el sistema de tipos del lenguaje, define el operador suma de forma sobrecargada ya que puede ser evaluado en el contexto de 2 subexpresiones de tipo entero o tipo flotante, entre otros. Otros lenguajes, como Fortran utilizan por el contrario operadores diferentes

S e d i c e q u e u n o p e r a d o r e s t á

sobrecargado cuando se puede utilizar

para operar sobre un subconjunto de tipos

de datos primitivos del lenguaje

2+3

4.2+.3.8

}

Pascal FortranLa capacidad de poder utilizar un mismo operador para articular diferentes operaciones en función de los tipos de datos involucrados se llama sobrecarga de operadores. Es frecuente sobrecargar los operadores aritméticos y relacionales de un lenguaje

Page 62: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 21

Sistemasde6pos

Elementosdeunsistemade8posLa descripción del sistema de tipos de un lenguaje de programación se articula, fundamentalmente, mediante la definición de los tipos primitivos y constructores compuestos, sus reglas de composición, las operaciones permitidas sobre cada uno de ellos y el tipo de resultado que provocan

Verificaciónde8possobreoperadoresLa mayoría de operadores de un lenguaje de programación pueden operarse satisfactoriamente sobre un subconjunto de tipos primitivos del lenguaje. Esto desencadena una serie de conceptos tan interrelacionados entre si que conviene abordarlos conjuntamente

II.Compa8bilidadde8pos

2+3.5

4.2*3

En los ejemplos en Pascal puede verse como los operadores sobrecargados suma (+) y producto (*) definen los tipos entero y real como compatibles entre sí, mientras que en C resultan compatibles el tipo carácter, entero y flotante con respecto a los mismos operadores

Se dice que dos tipos son compatibles

entre si, con respecto a un operador, si son

equivalentes o si se pueden operar

satisfactoriamente a través de dicho

operador

‘a’+3.5

4.2*3

}

Pascal CLa capacidad de sobrecarga de los operadores de un lenguaje, introduce el concepto de compatibilidad de tipos, que se aplica cuando dichos tipos pueden ser satisfactoriamente o p e r a d o s a t r a v é s d e u n o p e r a d o r sobrecargado

Page 63: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 22

Sistemasde6pos

Elementosdeunsistemade8posLa descripción del sistema de tipos de un lenguaje de programación se articula, fundamentalmente, mediante la definición de los tipos primitivos y constructores compuestos, sus reglas de composición, las operaciones permitidas sobre cada uno de ellos y el tipo de resultado que provocan

Verificaciónde8possobreoperadoresLa mayoría de operadores de un lenguaje de programación pueden operarse satisfactoriamente sobre un subconjunto de tipos primitivos del lenguaje. Esto desencadena una serie de conceptos tan interrelacionados entre si que conviene abordarlos conjuntamente

III.Coerciónde8pos

2+3.5

4.2*3

En los ejemplos de Pascal ambas operaciones operan entre reales y por tanto los operandos enteros se convierten a real. Igual ocurre con la primera expresión en C que convierte el carácter ‘a’ a entero y de ahí a flotante para poder operarse. Estas conversiones se llaman implícitas. Sin embargo la ultima fuerza a convertir el flotante a entero con perdida de información. Esta conversión es explícita

La coerción de tipos es el proceso

mediante el cual el sistema de tipos

convierte la subexpresión menos restrictiva

hacia la más restrictiva cuando ambas son

de distinto tipo

‘a’+3.5

(int)4.2*3

}

Pascal CLa compatibilidad de tipos permite operar expresiones de t ipos d i ferentes pero comúnmente fuerza conversiones de tipo hacia el tipo más restrictivo. Este efecto recibe el nombre de conversión o coerción de tipos

Page 64: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 23

Sistemasde6pos

Elementosdeunsistemade8posLa descripción del sistema de tipos de un lenguaje de programación se articula, fundamentalmente, mediante la definición de los tipos primitivos y constructores compuestos, sus reglas de composición, las operaciones permitidas sobre cada uno de ellos y el tipo de resultado que provocan

Verificaciónde8possobreoperadoresLa mayoría de operadores de un lenguaje de programación pueden operarse satisfactoriamente sobre un subconjunto de tipos primitivos del lenguaje. Esto desencadena una serie de conceptos tan interrelacionados entre si que conviene abordarlos conjuntamente

Byte

Integer

Word

Real

Double

Error

Error

Error

Byte

Integer

Word

Real

Double

Boolean

Char

String

...

ByteIntegerWordRealDoubleBooleanCharString…

Integer

Integer

Word

Real

Double

Error

Error

Error

Word

Word

Word

Real

Double

Error

Error

Error

Real

Real

Real

Real

Double

Error

Error

Error

Double

Double

Double

Double

Double

Error

Error

Error

Error

Error

Error

Error

Error

Error

Error

Error

+

Error

Error

Error

Error

Error

Error

Error

Error

Error

Error

Error

Error

Error

Error

Error

Error

operador

tipos

Coerción o error

Matriz de compatibilidad para el operador + Constructores

de tipos

Page 65: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 24

Sistemasde6pos

Elementosdeunsistemade8posLa descripción del sistema de tipos de un lenguaje de programación se articula, fundamentalmente, mediante la definición de los tipos primitivos y constructores compuestos, sus reglas de composición, las operaciones permitidas sobre cada uno de ellos y el tipo de resultado que provocan

Verificaciónde8possobresubprogramasLa sobrecarga es un término que puede ser igualmente aplicado sobre los procedimientos y funciones declarados en un programa. Esto permite soportar diferentes implementaciones de un mismo subprograma con igual identificador pero diferente, número, tipo u orden de parámetros formales en su declaración. La implementación invocada dependerá de los tipos aplicados en la expresión de llamada

El procedimiento de suma está sobrecargado. La sobrecarga de subprogramas es más propia de lenguajes orientados a objetos que de lenguajes estructurados. En ese contexto se llama polimorfismo

La sobrecarga de subprogramas es la capacidad de un lenguaje de

permitir la declaración de varios procedimientos o funciones con el mismo

nombre pero distinto, número, tipo u orden de parámetros formales

TYPETVector=ARRAY[1..10]OFINTEGER

TMatriz=ARRAY[1..10][1..5]OFINTEGER

VARv,w:Tvector;m,n:TMatriz;

PROCEDUREsumar(v,w:TVector;VARr:TVector);...

PROCEDUREsumar(m,n:TMatriz;VARr:TMatriz);...

}

Page 66: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 25

Construccióndecomprobadoresde6posenlaprác6ca

¿Quéesuncomprobadorde8pos?Una vez descritas las responsabilidades y características de un sistema de tipos, es preciso implementarlo en la practica a través de los mecanismos proporcionados por los esquemas de traducción dirigidos por la sintaxis. A la parte de un compilador que implementa el sistema de tipos se le llama comprobador de tipos

Un comprobador de tipos es la parte del compilador que se encarga de

implementar el sistema de tipos del lenguaje a través de mecanismos de

traducción dirigida por la sintaxis

expresion::=expresion:e1MASexpresion:e2

{:t1=<<recuperartipodee1>>

t2=<<recuperartipodee2>>

<<Comprobarlacompatibilidaddet1yt2para+>>

No:<<Errorsemántico>>

si:<<otrasaccionessemánticas>>

:}

Ejemplo

En el caso de las expresiones es necesario recuperar el tipo de cada subexpresión y comprobar su compatibilidad con respecto al operador que las combina. Si no son compatibles se emite un mensaje de error semántico

}

Page 67: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 26

Construccióndecomprobadoresde6posenlaprác6ca

Artefactosdeuncomprobadorde8posAntes de comenzar con la descripción de la implementación del comprobador de tipos para cada parte de la gramática de un lenguaje es necesario presentar la colección de artefactos que serán utilizados dentro de la misma. A continuación describimos aquellos que aparecen en el framework de soporte

ScopeManager

SymbolTable Scope TypeTable

Consúltese el documento directrices de implementación

SymbolIF TypeIF

SymbolBase TypeBase

SymbolConstant

SymbolVariable SymbolFunction

SymbolProcedure

SymbolParameter

TypeSimple

TypeRecord

TypeUnion

TypeArray

TypeEnum

TypeSet

TypePointer

TypeProcedure

TypeFunction

SemanticErrorManager

Page 68: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 27

Construccióndecomprobadoresde6posenlaprác6ca

Artefactosdeuncomprobadorde8posAntes de comenzar con la descripción de la implementación del comprobador de tipos para cada parte de la gramática de un lenguaje es necesario presentar la colección de artefactos que serán utilizados dentro de la misma. A continuación describimos aquellos que aparecen en el framework de soporte

Consúltese el documento directrices de implementación

Tiposprimi8vosyconstructoresde8posLas clases que implementan el interfaz TypeIF representan los tipos primitivos del lenguaje y cada uno de los constructores de tipos del mismo. El primer paso es determinar los atributos y métodos necesarios para caracterizarlos (entendemos que los nombres de cada clase son autoexplicativos)

TypeBase

- Stringname- ScopeIFscope

+StringgetName()

+voidsetName(Stringname)

+ScopeIFgetScope()

+voidsetScope(ScopeIFscope)

+intgetSize()

+booleanequals()

+hashcode()

+toString()

Todos los tipos contienen un nombre y un ámbito de declaración por tanto pueden factorizarse en la clase abstracta TypeBase e implementar sendos métodos de consulta y modificación

Propiedadnameyscope

Equivalenciade8posPara mantener limpio el código del esquema de traducción en Cup se recomienda implementar la equivalencia de tipos – nominal o estructural – en este método

SobrescriturademétodosdeObjectIgualmente se recomienda la implementación de los métodos hashcode y toString heredados de clase Object. Consulte tema 6 para obtener detalles

Page 69: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 28

Construccióndecomprobadoresde6posenlaprác6ca

Artefactosdeuncomprobadorde8posAntes de comenzar con la descripción de la implementación del comprobador de tipos para cada parte de la gramática de un lenguaje es necesario presentar la colección de artefactos que serán utilizados dentro de la misma. A continuación describimos aquellos que aparecen en el framework de soporte

Consúltese el documento directrices de implementación

Tiposprimi8vosyconstructoresde8posLas clases que implementan el interfaz TypeIF representan los tipos primitivos del lenguaje y cada uno de los constructores de tipos del mismo. El primer paso es determinar los atributos y métodos necesarios para caracterizarlos (entendemos que los nombres de cada clase son autoexplicativos)

TypeSimple

TypeRecord

TypeUnion

TypeEnumTypeSet TypePointerTypeProcedure

- Stringname- ScopeIFscope- intsize

TypeArray

- Stringname- ScopeIFscope- intmin- intmax- TypeIFbase

- Stringname- Map<String,TypeIF>fields- ScopeIFscope

- Stringname- TypeIFbase- ScopeIFscope

- Stringname- List<String>values- ScopeIFscope

- Stringname- ScopeIFscope- TypeIFbase

- Stringname- List<TypeIF>parameters- ScopeIFscope

TypeFunction

- TypeIFrType- ScopeIFscope

- Stringname- Map<String,TypeIF>baseFields- Map<String,Map<String,TypeIF>>variants- ScopeIFscope

Page 70: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 29

Construccióndecomprobadoresde6posenlaprác6ca

Artefactosdeuncomprobadorde8posAntes de comenzar con la descripción de la implementación del comprobador de tipos para cada parte de la gramática de un lenguaje es necesario presentar la colección de artefactos que serán utilizados dentro de la misma. A continuación describimos aquellos que aparecen en el framework de soporte

Consúltese el documento directrices de implementación

SímbolosLas clases que implementan la interfaz SymbolIF representan símbolos que han sido declarados por el usuario programador dentro del lenguaje. Para cada tipo de símbolo también conviene identificar los atributos propios que lo caracterizan de manera preliminar

SymbolBase

- Stringname- TypeIFtype- ScopeIFscope

+StringgetName()

+voidsetName(Stringname)

+ScopeIFgetScope()

+voidsetScope(ScopeIFscope)

+TypeIFgetType()

+voidsetType(TypeIFtype)

+booleanequals()

+hashcode()

+toString()

Todos los símbolos contienen un nombre y un ámbito de declaración por tanto pueden factorizarse en la clase abstracta SymbolBase e implementar sendos métodos de consulta y modificación

Propiedadnameyscope

PropiedadTipoDe forma similar, todos los símbolos declarados tienen un tipo, ya sea declarado explícitamente o inferido luego el tipo es otra propiedad que puede factorizarse en esta clase

SobrescriturademétodosdeObjectIgualmente se recomienda la implementación de los métodos hashcode y toString heredados de clase Object. Consulte tema 6 para obtener detalles

Page 71: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 30

Construccióndecomprobadoresde6posenlaprác6ca

Artefactosdeuncomprobadorde8posAntes de comenzar con la descripción de la implementación del comprobador de tipos para cada parte de la gramática de un lenguaje es necesario presentar la colección de artefactos que serán utilizados dentro de la misma. A continuación describimos aquellos que aparecen en el framework de soporte

Consúltese el documento directrices de implementación

SímbolosLas clases que implementan la interfaz SymbolIF representan símbolos que han sido declarados por el usuario programador dentro del lenguaje. Para cada tipo de símbolo también conviene identificar los atributos propios que lo caracterizan de manera preliminar

SymbolProcedureSymbolConstant SymbolParameterSymbolVariable

- Stringname- TypeIFtype- ScopeIFscope- Integeraddress

- Stringname- TypeIFtype- ScopeIFscope

- Stringname- TypeIFtype- ScopeIFscope

- Stringname- TypeIFtype- Numbervalue- ScopeIFscope

SymbolFunction

- Stringname- TypeIFType- ScopeIFscope

Al igual que en el caso de los tipos, estas def in ic iones serán potencia lmente extendidas cuando avancemos en la construcción del compilador

}

Page 72: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 31

Construccióndecomprobadoresde6posenlaprác6ca

Artefactosdeuncomprobadorde8posAntes de comenzar con la descripción de la implementación del comprobador de tipos para cada parte de la gramática de un lenguaje es necesario presentar la colección de artefactos que serán utilizados dentro de la misma. A continuación describimos aquellos que aparecen en el framework de soporte

Consúltese el documento directrices de implementación

Gestordeerroressemán8cosytrazabilidadCuando se detecta un error semántico durante el proceso de compilación, el comprobador de tipos debe emitir un mensaje de error. El gestor de errores proporciona métodos para informar de errores recuperables y no recuperables así como para trazar la ejecución del comprobador semántico

SemanticErrorManager

+voidsemantiDebug(Stringmessage)

+voidsemanticInfo(Stringmessage)

+voidsemanticWarn(Stringmessage)

+voidsemanticError(Stringmessage)

+voidsemanticFatal(Stringmessage)

exp::=exp:e1MASexp:e2{:

TypeIFt1=<<obtenertipoe1>>

TypeIFt2=<<obtenertipoe2>>

semanticErrorManager.semanticDebug(“Tipodee1:”+t1);

semanticErrorManager.semanticDebug(“Tipodee2:”+t2);

if(t1.isCompatible(t2,TypeIF.MAS)){

...

}elsesemanticErrorManager.semanticFatalError(“tiposincompatibles”);

:}

Page 73: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 32

Construccióndecomprobadoresde6posenlaprác6ca

Artefactosdeuncomprobadorde8posAntes de comenzar con la descripción de la implementación del comprobador de tipos para cada parte de la gramática de un lenguaje es necesario presentar la colección de artefactos que serán utilizados dentro de la misma. A continuación describimos aquellos que aparecen en el framework de soporte

Consúltese el documento directrices de implementación

Tablasde8posUna tabla de tipos es una estructura de datos de tabla hash donde se registran todas las declaraciones de tipos realizadas por el usuario programador en un determinado ámbito

TypeTable

PrivateScopeIFscope;

privateMap<String,TypeIF>tTable;

publicTypeTable(ScopeIFscope){

this.scope=scope;

tTable=newHashMap<String,TypeIF>();

}

publicTypeIFgetType(Stringid){

returntTable.get(id);

}

publicvoidaddType(TypeIFtype){

Stringid=type.getName();

addType(id,type);}

TypeTable(continúa)

publicvoidaddType(Stringid,TypeIFtype){

type.setScope(this.scope);

tTable.put(id,type);

}

publicbooleancontainsType(Stringid){

returntTable.containsKey(id);

}

publicbooleancontainsType(TypeIFtype){

Stringid=type.getName();

returncontainsType(id);

}

...

Page 74: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 33

Construccióndecomprobadoresde6posenlaprác6ca

Artefactosdeuncomprobadorde8posAntes de comenzar con la descripción de la implementación del comprobador de tipos para cada parte de la gramática de un lenguaje es necesario presentar la colección de artefactos que serán utilizados dentro de la misma. A continuación describimos aquellos que aparecen en el framework de soporte

Consúltese el documento directrices de implementación

TablasdesímbolosUna tabla de símbolos es una estructura de datos de tabla hash donde se registran todas las declaraciones (no tipos) realizadas por el usuario programador en un determinado ámbito

SymbolTable

PrivateScopeIFscope;

privateMap<String,SymbolIF>sTable;

publicSymbolTable(){

sTable=newHashMap<String,SymbolIF>();

}

publicSymbolIFgetSymbol(Stringid){

returnsTable.get(id);

}

publicvoidaddSymbol(SymbolIFsymbol){

Stringid=symbol.getName();

addSymbol(id,symbol);

}

SymbolTable(continúa)

publicvoidaddSymbol(Stringid,SymbolIFsymbol){

symbol.setScope(this.scope);

sTable.put(id,symbol);

}

publicbooleancontainsSymbol(Stringid){

returnsTable.containsKey(id);

}

publicbooleancontainsSymbol(SymbolIFsymbol){

Stringid=symbol.getName();

returncontainsSymbol(id);

}

...

Page 75: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 34

Construccióndecomprobadoresde6posenlaprác6ca

Artefactosdeuncomprobadorde8posAntes de comenzar con la descripción de la implementación del comprobador de tipos para cada parte de la gramática de un lenguaje es necesario presentar la colección de artefactos que serán utilizados dentro de la misma. A continuación describimos aquellos que aparecen en el framework de soporte

Consúltese el documento directrices de implementación

ÁmbitosdedeclaraciónEl ámbito es un artefacto que representa un ámbito de declaración dentro de un programa. Estructuralmente es un contenedor que mantiene una referencia a la tabla de símbolos y la tabla de tipos asociada con dicho ámbito

Scope

- Stringname- intid- intlevel- symbolTable- typeTable

+StringgetName()

+intgetId()

+intgetLevel()

+SymbolTableIFgetSymbolTable()

+TypeTableIFgetTypeTable()

Nombredelámbito

En bloques con nombre, como procedimientos y funciones, contiene el nombre del bloque

Iden8ficadordeámbitoCada ámbito dispone de un identificador único asignado, correlativamente, por construcción

NiveldeanidamientodelámbitoEl nivel de anidamiento indica el grado de profundidad en el que se encuentra el bloque sintáctico asociado al ámbito comenzando por 0 para el ámbito global

Tabladesímbolosy8pos

Cada ámbito contiene una referencia a una tabla de símbolos y otra de t ipos inicialmente vacía asignadas por construcción

Page 76: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 35

Construccióndecomprobadoresde6posenlaprác6ca

Artefactosdeuncomprobadorde8posAntes de comenzar con la descripción de la implementación del comprobador de tipos para cada parte de la gramática de un lenguaje es necesario presentar la colección de artefactos que serán utilizados dentro de la misma. A continuación describimos aquellos que aparecen en el framework de soporte

Consúltese el documento directrices de implementación

GestordeámbitosEl gestor de ámbitos es un artefacto que mantiene una relación de todos los ámbitos creados durante el proceso de compilación. Este objeto es una única instancia en el compilador y sirve para gestionar la búsqueda de símbolos y tipos a través de los ámbitos activos

ScopeManager

+voidopenScope()

+voidopenScope(Stringname)

+voidcloseScope()

+ScopeIFgetCurrentScope()

+ScopeIFgetScope(intlevel)

+List<ScopeIF>getAllScopes()

+SymbolIFsearchSymbol()

+TypeIFsearchType()

+booleancontainsSymbol(Stringid)

+booleanContainsType(Stringid)

Crea un nuevo ámb i to , anónimo o con nombre. Aplicable cuando se entra en un bloque Cierra un ámbito. Aplicable

cuando se abandona un bloque Recupera el último ámbito abierto o aquél en cierto nivel d e p r o f u n d i d a d d e l o s actualmente abiertos

Recupera todos los ámbitos creados (abiertos o cerrados) d u r a n t e e l p r o c e s o d e compilación. Útil en la generación de código final Busca símbolos o tipos a lo

largo de los ámbitos activos, comenzando por e l más reciente y avanzando en la jerarquía de ámbitos padre

Indica si un símbolo o tipo se encuentra declarado dentro de algún ámbito activo

Page 77: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 36

Construccióndecomprobadoresde6posenlaprác6ca

Artefactosdeuncomprobadorde8posAntes de comenzar con la descripción de la implementación del comprobador de tipos para cada parte de la gramática de un lenguaje es necesario presentar la colección de artefactos que serán utilizados dentro de la misma. A continuación describimos aquellos que aparecen en el framework de soporte

Consúltese el documento directrices de implementación

GestordeámbitosLa manera de gestionar los ámbitos activos es a través de una pila de ámbitos interna. Cada operación openScope crea un nuevo objeto Scope y lo apila sobre la pila. Cada operación closeScope, saca el ámbito de la cima de la pila

CONSTMAX=10;TYPETVector=ARRAY[1..10]OFREAL;VARv,w:TVector;i:INTEGER;...

FUNCTIONValidar(VARv:INTEGER):INTEGER;BEGINValidar:=vmod10;END;...

ScopeManager

Global[0]

Ejemplo

...PROCEDURELeer(VARm:TVector);VARi:INTEGER;...

ScopeManager

Global[0]

Leer[1]

ScopeManager

Global[0]

Leer[1]

Validar[2]

� � �

Page 78: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 37

Construccióndecomprobadoresde6posenlaprác6ca

Artefactosdeuncomprobadorde8posAntes de comenzar con la descripción de la implementación del comprobador de tipos para cada parte de la gramática de un lenguaje es necesario presentar la colección de artefactos que serán utilizados dentro de la misma. A continuación describimos aquellos que aparecen en el framework de soporte

Consúltese el documento directrices de implementación

GestordeámbitosLa manera de gestionar los ámbitos activos es a través de una pila de ámbitos interna. Cada operación openScope crea un nuevo objeto Scope y lo apila sobre la pila. Cada operación closeScope, saca el ámbito de la cima de la pila

...BEGINFORi:=1TO10DOm[i]:=Validar(Read(i));END;END;

ScopeManager

Ejemplo...FUNCTIONsuma(m,n:TVector):TVector;VARi:INTEGER;vSuma:TVector;BEGIN...

ScopeManager

Global[0]

suma[1]

...BEGINLeer(v);Leer(w);v:=suma(v,w);END.

ScopeManager

Global[0]Global[0]

Leer[1]

� � �

Page 79: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 38

Construccióndecomprobadoresde6posenlaprác6ca

Implementacióndeuncomprobadorde8possencilloencupUna vez conocidos los artefactos necesarios para implementar un comprobador de tipos, podemos describir la forma del esquema de traducción para cada sección de una gramática. En nuestros ejemplos utilizaremos una estilo Pascal aunque es fácilmente trasladable a C. Como cup no admite atributos heredados la solución propuesta se verá someramente condicionada por este hecho

Aperturadelámbitoinicialprogram::=cabeceracuerpo;

cabecera::=PROGRAMID:idPYC{:

Stringname=id.getLexema();

scopeManager.openScope(name);

//InsertartodoslosTypeSimpleenlaTT

:};

cuerpo::=declaracionesbSentencias;{:

scopeManager.closeScope();:}

declaraciones::=bConstantes

bTipos

bVariables

dSubprogramas;

bConstantes::=CONSTdConstantes|;

bTipos::=TYPEdTipos|;

bVariables::=VARdVariables|;

dConstantes::=dConstantesdConstante

|dConstante;

dConstante::=ID:idIGUALrNumero:rn{:

ScopeIFscope=scopeManager.getCurrentScope();

SymbolTablesTable=scope.getSymbolTable();

Stringname=id.getLexema();

Objectvalue=rn.getValue();

if(sTable.containsSymbol(name)){

semanticErrorManager.semanticFatalError(...);

}else{

TypeIFtype;

if(valueinstanceofInteger)type=TypeSimple.ENTERO;

if(valueinstanceofFloat)type=TypeSimple.REAL;

if(valueinstanceofBoolean)type=TypeSimple.LOGICO;

SymbolConstantsC=newSymbolConstant(name,value,type);

sTable.add(sC);

:};

rNumero::=NUM:n{:

RESULT=newRNumero(n.getValue());:}

Declaracióndeconstantes

Page 80: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 39

Construccióndecomprobadoresde6posenlaprác6ca

Una vez conocidos los artefactos necesarios para implementar un comprobador de tipos, podemos describir la forma del esquema de traducción para cada sección de una gramática. En nuestros ejemplos utilizaremos una estilo Pascal aunque es fácilmente trasladable a C. Como cup no admite atributos heredados la solución propuesta se verá someramente condicionada por este hecho

Declaracióndeconstantes Declaraciónde8pos|ID:id{:

Stringname=id.getLexema();

if(scopeManager.containsSymbol(name)){

SymbolIFs=scopeManager.searchSymbol(name);

if(sinstanceofSymbolConstant){

SymbolConstantsC=(SymbolConstant)s;

Objectvalue=sC.getValue();

RESULT=newRNumero(value);

}else

semanticErrorManager.semanticFatalError(...);

}else

semanticErrorManager.semanticFatalError(...);

:};

dTipos::=dTiposdTipo

|dTipo;

dTipo::=ID:idIGUALtipo:t{:

Stringname=id.getLexema();

TypeIFtype=t.getType();

type.setName(name);

ScopeIFscope=scopeManager.getCurrentScope();

TypeTableIFtTable=scope.getTypeTable();

tTable.addType(name,type);

:};

tipo::=dArray:t{:RESULT=newTipo(t.getType());:}

|dRecord:t{:RESULT=newTipo(t.getType());:}

|rTipo:t{:RESULT=newTipo(t.getType());:};

rTipo::=INTEGER{:RESULT=newRTipo(TypeSimple.ENTERO);:}

|REAL{:RESULT=newRTipo(TypeSimple.REAL);:}

Implementacióndeuncomprobadorde8possencilloencup

Page 81: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 40

Construccióndecomprobadoresde6posenlaprác6ca

Una vez conocidos los artefactos necesarios para implementar un comprobador de tipos, podemos describir la forma del esquema de traducción para cada sección de una gramática. En nuestros ejemplos utilizaremos una estilo Pascal aunque es fácilmente trasladable a C. Como cup no admite atributos heredados la solución propuesta se verá someramente condicionada por este hecho

Declaraciónde8pos Declaraciónde8pos|ID:id{:

Stringname=id.getLexema();

if(scopeManager.containsType(name)){

TypeIFtype=scopeManager.searchType(name);

RESULT=newRtipo(type);

}else

semanticErrorManager.semanticFatalError(...);

:}

dArray::=ARRAYrArray:tPYC{:

RESULT=newdArray(t.getType());

:};

rArray::=CIrNumero::n1DDrNumero:n2CDrArray:t

{:Objectmin=n1.getValue();

Objectmax=n2.getValue();

TypeIFtBase=t.getType();

TypeIFtArray=newTypeArray(min,max,tBase);

RESULT=newRArray(tArray);:}

|OFrTipo:t{:RESULT=newRArray(t.getType());:};

dRecord::=RECORDBEGINbCampos:tEND{:

RESULT=newDRecord(t.getTypeRecord());

:};

bCampos::=bCampos:t1lCampos:t2PYC{:

TypeRecordtR1=t1.getTypeRecord();

TypeRecordtR2=t2.getTypeRecord();

TypeRecordtR=newTypeRecord();

if(tr2.constainsSome(tR1))semanticErrorManager.semanti...

else{tR.addAllFields(tR1);

tR.addAllFields(tR2);

RESULT=newBCampos(tR);}

:}

|lCampos:t{:

TypeRecordtR=t.getTypeRecord();

RESULT=newBCampos(tR);:};

:};

Implementacióndeuncomprobadorde8possencilloencup

Page 82: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 41

Construccióndecomprobadoresde6posenlaprác6ca

Una vez conocidos los artefactos necesarios para implementar un comprobador de tipos, podemos describir la forma del esquema de traducción para cada sección de una gramática. En nuestros ejemplos utilizaremos una estilo Pascal aunque es fácilmente trasladable a C. Como cup no admite atributos heredados la solución propuesta se verá someramente condicionada por este hecho

Declaraciónde8pos DeclaracióndevariableslCampos::=ID:idDPrTipo:t{:

Stringname=id.getLexema();

TypeIFtype=t.getType();

TypeRecordtR=newTypeRecord();

tR.addField(name,type);

RESULT=newLCampos(tR,type);

:}

|ID:idCOMAlCampos:t{:

Stringname=id.getLexema();

TypeRecordtR=t.getTypeRecord();

if(!(tR.containsField(name))){

TypeIFtype=t.getType();

tR.addField(name,type);

}else

semanticErrorManager.semanticFatalError(...);

:}

dVariables::=dVariablesdVariable

|dVariable;

dVariable::=ID:idDPrTipo:t{:

Stringname=id.getLexema();

TypeIFtype=t.getType();

ScopeIFscope=scopeManager.getCurrentScope();

SymbolTablesTable=scope.getSymbolTable();

if(!(sTable.containsSymbol(name))){

SymbolVariablesV=newSymbolVariable(name,type);

sTable.addSymbol(name,sV);

RESULT=newDVariables(type);

}elsesemanticErrorManager.semanticFatalError(...);

:}

|ID:idCOMAdVariables:t{:

<<igualqueenlareglaanterior>>

:};

Implementacióndeuncomprobadorde8possencilloencup

Page 83: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 42

Construccióndecomprobadoresde6posenlaprác6ca

Una vez conocidos los artefactos necesarios para implementar un comprobador de tipos, podemos describir la forma del esquema de traducción para cada sección de una gramática. En nuestros ejemplos utilizaremos una estilo Pascal aunque es fácilmente trasladable a C. Como cup no admite atributos heredados la solución propuesta se verá someramente condicionada por este hecho

Declaracióndesubprogramas DeclaracióndesubprogramasdSubprogramas::=dSubprogramasdSubprograma|;

dSubprograma::=dProcedimiento|dFuncion;

dProcedimiento::=pCabeceracuerpo;

dFuncion::=fCabeceracuerpo;

fCabecera::=FUNCTIONID:idPIpFormales:pfsPDDP

rTipo:t{:Stringname=id.getLexema();

if((!scopeManager.containsSymbol(name))&&

(scopeManager.containsType(name))){

ScopeIFpScope=scopeManager.getCurrentScope();

SymbolTableIFpsTable=pScope.getSymbolTable();

TypeTableIFptTable=pScope.getTypeTable();

TypeFunctiontF=newTypeFunction(name);

SymbolFunctionsF=newSymbolFunction(name,tF);

ScopeIFscope=scopeManager.openScope(name);

SymbolTableIFsTable=scope.getSymbolTable();

for(SymbolParameterp:pfs.getParameters()){

p.setScope(scope);sTable.addSymbol(p);

tF.addParameterType(p.getType());}

tF.setReturnType(t.getType());

ptTable.addType(name,tF);

psTable.addSymbol(name,sF);

}elsesemanticErrorManager.semanticFatalError(...);:}

pFormales::=lPFormales:lpf{:

List<SymbolParameter>lp=lpf.getParameters();

RESULT=newPFormales(lp);

:}

|{:RESULT=newpFormales();:};

lPFormales::=lPFormales:lpfPYCdPFormales:dpf{:

List<SymbolParameter>lp=dpf.getParameters();

lpf.addAllParameters(lp);

RESULT=lpf;

:}|dPFormales:dpf{:

List<SymbolParameter>lp=dpf.getParameters();

RESULT=newLPFormales(lp);:};

Implementacióndeuncomprobadorde8possencilloencup

Page 84: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 43

Construccióndecomprobadoresde6posenlaprác6ca

Una vez conocidos los artefactos necesarios para implementar un comprobador de tipos, podemos describir la forma del esquema de traducción para cada sección de una gramática. En nuestros ejemplos utilizaremos una estilo Pascal aunque es fácilmente trasladable a C. Como cup no admite atributos heredados la solución propuesta se verá someramente condicionada por este hecho

Declaracióndesubprogramas ExpresionesdPFormales::=ID:idPDrTipo:tPYC{:

Stringn=id.getLexema();

TypeIFtype=t.getType();

SymbolParametersp=newSymbolParameter(n,type);

RESULT=newDPFormales(sp,type);

:}

|ID:idCOMAdPFormales:dpf{:

Stringn=id.getLexema();

TypeIFtype=dpf.getType();

SymbolParametersp=newSymbolParameter(n,type);

dpf.addParameter(sp,type);

RESULT=dpf;

:};

pCabecera::=FUNCTIONID:idPIpFormales:pfsPD{:

<<igualqueenfCabeceraperosintipode

retornoeinsertandounSymbol/TypeProcedure

envezdeunSymbol/TypeFunction>>:};

exp::=exp:e1MASexp:e2{:

TypeIFt1=e1.getType();

TypeIFt2=e2.getType();

if(t1.isCompatible(t2,TypeSimple.MAS)){

TypeIFt=t1.cast(t2,TypeSimple.MAS);

RESULT=newExp(t);

}elsesemanticErrorManager.semanticFatalError(...);

:}

|expMENOSexp{:...:}

|expPORexp{:...:}

|expDIVexp{:...:}

|rNumero:rn{:

Objectvalue=rn.getValue();

TypeIFtype;

if(valueinstanceofInteger)type=TypeSimple.ENTERO;

if(valueinstanceofFloat)type=TypeSimple.REAL;

RESULT=newExp(type);:}

Implementacióndeuncomprobadorde8possencilloencup

Page 85: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 44

Construccióndecomprobadoresde6posenlaprác6ca

Una vez conocidos los artefactos necesarios para implementar un comprobador de tipos, podemos describir la forma del esquema de traducción para cada sección de una gramática. En nuestros ejemplos utilizaremos una estilo Pascal aunque es fácilmente trasladable a C. Como cup no admite atributos heredados la solución propuesta se verá someramente condicionada por este hecho

Expresiones Expresiones|PIexp:ePD{:

TypeIFtype=e.getType();

RESULT=newExp(type);

:}

|fCall:fc{:

TypeIFtype=fc.getType();

RESULT=newExp(type);

:}

|referencia:ref{:

TypeIFtype=ref.getType();

RESULT=newExp(type);

:}

referencia::=ID:id{:

Stringname=id.getLexema();

if(scopeManager.contains(name)){

SymbolIFsId=scopeManager.searchSymbol(name);

TypeIFtype=sId.getType();

RESULT=newReferencia(type);

}elseSemanticErrorManager.semanticFactalError(...);

:}

|referencia:rPTOID:id{:

Stringname=id.getLexema();

TypeIFrType=r.getType();

if(rTypeinstanceofTypeRecord){

TypeRecordtRec=(TypeRecord)rType;

if(tRec.containsField(name)){

TypeinnerType=tRec.getType(name);

RESULT=newReferencia(innerType);

}elseSemanticErrorManager.semanticFactalError(...);

}elseSemanticErrorManager.semanticFactalError(...);

:}

Implementacióndeuncomprobadorde8possencilloencup

Page 86: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 45

Construccióndecomprobadoresde6posenlaprác6ca

Una vez conocidos los artefactos necesarios para implementar un comprobador de tipos, podemos describir la forma del esquema de traducción para cada sección de una gramática. En nuestros ejemplos utilizaremos una estilo Pascal aunque es fácilmente trasladable a C. Como cup no admite atributos heredados la solución propuesta se verá someramente condicionada por este hecho

Expresiones Expresiones|referencia:rCIexp:eCD{:

TypeIFeType=e.getType();

if(eType.equals(TypeIF.ENTERO)){

TyperType=r.getType();

if(rTypeinstanceofTypeArray){

TypeArrayarrayType=(TypeArray)rType;

TypeinnerType=arrayType.getBaseType();

RESULT=newReference(innerType);

}elseSemanticErrorManager.semanticFatal...;

}elseSemanticErrorManager.semanticFatal...;

:}

fCall::=ID:idPIpActuales:paPD{:

Stringname=id.getLexema();

if(scopeManager.containsSymbol(name)){

SymbolIFs=scopeManager.searchSymbol(name);

if(sinstanceofSymbolFunction){

SymbolFunctionsf=(SymbolFunction)s;

TypeFunctiontF=sF.getType();

List<TypeIF>aParams=pa.getParameterTypes();

List<TypeIF>fParams=tF.getParameters();

if(aParams.equals(fParams)){

TypeIFreturnType=tF.getReturnType();

RESULT=newFcall(returnType);

}elseSemanticErrorManager.semanticFatalError(...);

}elseSemanticErrorManager.semanticFatalError(...);

}elseSemanticErrorManager.semanticFatalError(...);

:};

pActuales::=pActuales:paCOMAexp:e{:

TypeIFtype=e.getType();

pa.addParameterType(type);

RESULT=pa;

:}

|exp:e{:TypeIFtype=e.getType();

RESULT=newPActuales(type);:};

Implementacióndeuncomprobadorde8possencilloencup

Page 87: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 46

Construccióndecomprobadoresde6posenlaprác6ca

Una vez conocidos los artefactos necesarios para implementar un comprobador de tipos, podemos describir la forma del esquema de traducción para cada sección de una gramática. En nuestros ejemplos utilizaremos una estilo Pascal aunque es fácilmente trasladable a C. Como cup no admite atributos heredados la solución propuesta se verá someramente condicionada por este hecho

Sentencias Sentenciascuerpo::=BEGINlSentenciasENDPYC;

lSentencias::=lSentenciassentencia|;

sentencia::=sentenciaIf|

sentenciaWhile|

sentenciaAsignacion|

pCall|

cuerpo;

sentenciaIf::=IFPIexp:ePDTHENsentencia

ELSEsentencia{:

TypeIFtype=e.getType();

if(!(typeinstanceofTypeSimple.LOGICO))

semanticErrorManager.semanticFatalError(...);

:}

SentenciaWhile::=WHILEPIexp:ePDDOsentencia{:

<<igualquesentenciaIf>>

:}

sentenciaAsignación::=referencia:rIGUALexp:ePYC{:

TypeIFeType=e.getType();

TypeIFrType=r.getType();

if(rTypeinstanceofTypeFunction||//ReturnPascal

rTypeinstanceofTypeProcedure){

rType=rType.getReturnType();

ScopeIFcurrentScope=scopeManager.getCurrentScope();

if(!r.getScope().equals(currentScope))

semanticErrorManager.semanticFatalError(...);

}

if(!(rType.isCompatible(eType,TypeIF.IGUAL)))

semanticErrorManager.semanticFatalError(...);

:}

pCall::=ID:idPIpActuales:paPDPYC;{:

<<igualquefCall>>

:}

Implementacióndeuncomprobadorde8possencilloencup

Page 88: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 47

Construccióndecomprobadoresde6posenlaprác6ca

Una vez esbozado el esquema de traducción en cup para un comprobador de tipos sencillo sobre una gramática estilo Pascal, estamos en disposición de tratar algunos temas avanzados de interés que discutimos a continuación

Inferenciade8pos

Temasavanzadosdeuncomprobadorde8pos

La inferencia de tipos es el proceso por el cual un comprobador de tipos infiere el tipo de una construcción gramatical a partir de su contexto. Esto es especialmente útil en lenguajes sin tipificación explícita

Ejemplo I

dConstante::=ID:idIGUALnumero:n{:

...

Stringname=id.getLexema();

Objectvalue=n.getValue();

TypeIFtype;

if(valueinstanceofInteger)type=TypeSimple.ENTERO;

if(valueinstanceofFloat)type=TypeSimple.REAL;

if(valueinstanceofBoolean)type=TypeSimple.LOGICO;

SymbolConstantsC=newSymbolConstant(name,value,type);

sTable.add(sC);

:};

dConstante

ID numero = (3.5)

El caso más sencillo de inferencia de tipos se produce en la dec larac ión de constantes. En efecto, el tipo de la constante no se declara explícitamente sino que se infiere del valor asignado a la misma en la declaración

}

Page 89: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 48

Construccióndecomprobadoresde6posenlaprác6ca

Una vez esbozado el esquema de traducción en cup para un comprobador de tipos sencillo sobre una gramática estilo Pascal, estamos en disposición de tratar algunos temas avanzados de interés que discutimos a continuación

Inferenciade8pos

Temasavanzadosdeuncomprobadorde8pos

La inferencia de tipos es el proceso por el cual un comprobador de tipos infiere el tipo de una construcción gramatical a partir de su contexto. Esto es especialmente útil en lenguajes sin tipificación explícita

Ejemplo II

exp::=ID:id{:

Stringname=id.getLexema();

if(!scopeManager.containsSymbol(name)){

ScopeIFscope=scopeManager.getCurrentScope();

SymbolTablesTable=scope.getSymbolTable();

SymbolVariablesV=newSymbolVariable();

sv.setTypes(TypeSimple.ALL);

sTable.addSymbol(name,sV);

}

RESULT=newExp(sV,TypeSimple.ALL);

:}

exp

exp exp +

En el caso de lenguajes sin tipificación, la construcción sintáctica infiere que los únicos posibles valores para ID son los numéricos, descartando Boolean, Char y String

}

(3.5) {Real}

numero ID {Byte, Word, Integer, Real, Double}

Page 90: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 49

Construccióndecomprobadoresde6posenlaprác6ca

Una vez esbozado el esquema de traducción en cup para un comprobador de tipos sencillo sobre una gramática estilo Pascal, estamos en disposición de tratar algunos temas avanzados de interés que discutimos a continuación

Inferenciade8pos

Temasavanzadosdeuncomprobadorde8pos

La inferencia de tipos es el proceso por el cual un comprobador de tipos infiere el tipo de una construcción gramatical a partir de su contexto. Esto es especialmente útil en lenguajes sin tipificación explícita

Ejemplo II

exp::=exp:e1MASexp:e2{:

TypeIFt1=e1.getTypes();

TypeIFt2=e2.getTypes();

t1.removeIncompatibles(t2,TypeIF.MAS);

t2.removeIncompatibles(t1,typeIF.MAS);

SymbolVariablee1Var=e1.getVariable();

SymbolVariablee2Var=e2.getVariable();

if(e1Var!=null)e1Var.setTypes(t1);

if(e2Var!=null)e1Var.setTypes(t2);

if(t1.isEmpty()||t2.isEmpty)semanticErrorManager...;

else{Typestypes=newTypes(t1);

types.addAllTypes(t2);

RESULT=newExp(types);}

:}

exp

exp exp +

En el caso de lenguajes sin tipificación, la construcción sintáctica infiere que los únicos posibles valores para ID son los numéricos, descartando Boolean, Char y String

}

(3.5) {Real}

numero ID {Byte, Word, Integer, Real, Double}

Page 91: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 50

Construccióndecomprobadoresde6posenlaprác6ca

Una vez esbozado el esquema de traducción en cup para un comprobador de tipos sencillo sobre una gramática estilo Pascal, estamos en disposición de tratar algunos temas avanzados de interés que discutimos a continuación

Temasavanzadosdeuncomprobadorde8pos

SobrecargadesubprogramasComo ya se comentó anteriormente, existen lenguajes que dan soporte a la sobrecarga de subprogramas. Es decir permiten declarar varias versiones de funciones o procedimiento con igual nombre pero distinto numero, tipo u orden de parámetros. La implementación de esta capacidad se estudiará para funciones ya que para procedimientos resulta similar

En la declaración… fCabecera::=FUNCTIONID:idPIpFormales:pfsPDDP

rTipo:t{:

Stringname=id.getLexema();

TypeIFt=<<tipoparaestaversióndelafunción>>

TypeFunctiontFun=<<buscareltipoporname>>

tFun.addSignature(t);

...

:}

fCall::=ID:idPIpActuales:paPD{:

Stringname=id.getLexema();

if(scopeManager.containsSymbol(name)){

TypeIFt=scopeManager.searchType(name);

if(tinstanceofTypeFunction){

TypeFunctiontF=(TypeFunction)t;

List<List<TypeIF>>signatures=tF.getSignatures();

for(<<cadasignatura>>){

<<procedercomoantescomprobandoquealguna

signaturaencajaconlallamadaactual>>

}

}

}

Ahora cada TypeFunction contiene una colección de signaturas (una lista interna de lo que antes era TypeFunction). Al declarar una nueva función ha de añadirse a la lista

}

En la invocación…

Page 92: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 51

Construccióndecomprobadoresde6posenlaprác6ca

Una vez esbozado el esquema de traducción en cup para un comprobador de tipos sencillo sobre una gramática estilo Pascal, estamos en disposición de tratar algunos temas avanzados de interés que discutimos a continuación

Temasavanzadosdeuncomprobadorde8pos

Recuperacióndeerroressemán8cosLa recuperación de errores semánticos es algo menos frecuente que la de errores sintácticos. Sin embargo es posible realizarlo mediante una extensión conveniente del esquema de traducción dirigido por la sintaxis. En concreto se utilizan para expresiones y sentencias dos nuevos valores para el atributo de tipo: error y correcto.

sentencia

IF THEN exp

Boolean = tipo. exp

sentencia

exp >

true 4

.tipo = ENTERO

.tipo = Correcto .tipo = error

.tipo = error

Los errores se almacenan como formas de tipo y se van acumulando para indicar qué partes del árbol de análisis sintáctico contiene error

}

Page 93: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 52

Construccióndecomprobadoresde6posenlaprác6ca

1.  Implementación de artefactos en código abierto

1.  Implementación de la tabla de símbolos

2.  Implementación de la tabla de tipos

3.  Implementación de todas las clases TypeIF necesarias

4.  Implementación de todas las clases SymbolIF necesarias

5.  Incorporación de atributos y constructores necesarios en cada no terminal

2.  Implementación de las acciones semánticas del comprobador de tipos

1.  Acciones para declaraciones

2.  Acciones para expresiones

3.  Acciones para sentencia

3.  Prueba del comprobador de tipos

1.  Ejecutar finalTestCase

2.  Comprobar en la traza el estado de cada tabla de símbolos y tipo

3.  Comprobar que se emiten los mensajes de error semántica ante códigos incorrectos

Se debe reflexionar cuida-dosamente acerca de qué atributos son necesarios para caracterizar cada tipo y símbolo del lenguaje y cada elemento no gramatical

DesarrollopasoapasoLa fase de análisis semántico requiere de la implementación del comprador de tipos del lenguaje que siga las directrices del sistema de tipos del lenguaje. En esta última sección hemos descrito cómo se implementa un comprobador de tipos sencillos. Ahora damos la secuencia de pasos a realizar

Page 94: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 53

Bibliograta

MaterialdeestudioBibliografía básica

Construcción de compiladores: principios y práctica

Kenneth C. Louden International Thomson Editores,

2004 ISBN 970-686-299-4

Page 95: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Análisis semántico. Comprobación de tipos

7 - 54

Bibliograta

MaterialdeestudioBibliografía complementaria

Compiladores: Principios, técnicas y herramientas.

Segunda Edición Aho, Lam, Sethi, Ullman

Addison – Wesley, Pearson Educación, México 2008

Diseño de compiladores. A. Garrido, J. Iñesta, F. Moreno

y J. Pérez. 2002. Edita Universidad de Alicante

Page 96: Procesadores de Lenguajes I

ProcesadoresdeLenguajesIngenieríaTécnicasuperiordeIngenieríaInformá8ca

DepartamentodeLenguajesySistemasinformá6cos

JavierVé[email protected]

DepartamentodeLenguajesYSistemasInformáAcosUNED

8GeneracióndecódigointermedioISentenciasyexpresiones

Page 97: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 2

Obje6vos

Obje8vos

›  Aprender en qué consiste la generación de código intermedio

›  Aprender qué es el código intermedio

›  Conocer los distintos tipos de lenguajes intermedios

›  Valorar la importaría de realizar una buena elección del lenguaje intermedio

›  Conocer cómo son los lenguajes intermedios lineales

›  Entender el significado de las variables temporales en el código intermedio lineal

›  Entender el significado de las etiquetas en el código intermedio lineal

›  Aprender a construir esquemas de traducción para generar código intermedio

›  Conocer los artefactos computacionales que son necesarios para darles soporte

›  Aprender a generar código intermedio para expresiones

›  Aprender a generar código intermedio para sentencias de control

Page 98: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 3

Índice

Índice

›  Introducción

›  Qué es el código intermedio

›  La fase de generación de código intermedio

›  El código intermedio como punto de desacoplamiento

›  Lenguajes intermedios

›  Representaciones jerárquicas de código intermedio

›  Representaciones lineales de código intermedio

›  Generación de código intermedio en la práctica

›  Artefactos para la generación de código intermedio

›  Generación de código intermedio para expresiones

›  Generación de código intermedio para sentencias

›  Desarrollo paso a paso

›  Bibliografía

Page 99: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 4

Introducción

¿Quéeselcódigointermedio?Una vez superadas todas las fases de análisis del código fuente, el compilador debe ser capaz de generar una representación simbólica del programa lo más aproximada a los potenciales lenguajes objetivos al que se va a traducir el mismo pero lo suficientemente distante de éstos como para garantizar su aplicabilidad en distintas arquitecturas físicas finales

El código intermedio es una representación abstracta del programa cercana a

los lenguajes objetivos potenciales pero independiente de cualquier

consideración específica de una arquitectura física concreta

I.Independenciadelentornodeejecución II.Independenciadeljuegodeinstrucciones

La independencia del entorno de ejecución se refiere al hecho de que el código intermedio debe ser agnóstico del modelo de organización de memoria, el número, tipo y propósito de registros, etc. Esto implica que todas las referencias a datos en código intermedio siguen haciéndose a través de símbolos registrados o generados durante el proceso de compilación

El código intermedio de un programa es una abstracción establecida a través de un compromiso de consenso entre los equipos dedicados al análisis de lenguajes y los dedicados a la síntesis. Esto significa que la colección de operadores disponibles en un código intermedio se debe mantener independiente y equidistante de cualquier lenguaje y juego de instrucciones propio de una arquitectura física real para garantizar la traducción a distintos códigos finales

Page 100: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 5

Introducción

LafasedegeneracióndecódigointermedioLa fase de generación de código intermedio se encarga de traducir el programa a una representación de código intermedio para que luego ésta pueda ser transformada en las fases subsiguientes a un código ejecutable en una determinada arquitectura física

›  Expertos en lenguajes

›  Independencia de arquitectura

›  Dependencia de lenguaje

›  Optimización de lenguajes

Analizad

orléxico

Analizad

orsintác8co

Analizad

or

semán

8co

Códigointerm

edio

Códigofina

l

e·l·i·h·w <WHILE,PR> S

WHILEEDOS

E>E

S

WHILEEDOS

E>E

√ 0000001100000011010000010100000000010010…

While(a>b)doa:=a+1;

Etapa de análisis Etapa de síntesis

›  Expertos en arquitecturas

›  Dependencia de arquitectura

›  Independencia de lenguaje

›  Optimización de ejecución

LDat1LDbt2GRTt3t1t2BRZt3L1…

Page 101: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 6

Introducción

ElcódigointermediocomopuntodedesacoplamientoEl código intermedio permite multiplexar los esfuerzos de desarrollo de los equipos de análisis de lenguajes y de síntesis de manera que se pueden crear M x N compiladores distintos a partir de M especificaciones y N traducciones a arquitecturas físicas reales

Analizadorléxico

Analizadorsintác8co

Analizadorsemán8co

Códigointermedio

While(a>b)doa:=a+1;

Equi

po d

e Le

ngua

je

Op8mizaciónCódigointermedio

Códigofinal

Analizadorléxico

Analizadorsintác8co

Analizadorsemán8co

Códigointermedio

Op8mizaciónCódigointermedio

Códigofinal

LDat1LDbt2GRTt3t1t2BRZt3L1…

Equi

po d

e ar

quite

ctur

a Pascal C

Intel Solaris

Código intermedio

M

N

while(a>b)a++;

Page 102: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 7

Lenguajesintermedios

LenguajesintermediosEl primer paro para la generación de código intermedio consiste en el diseño de un lenguaje intermedio que permita representar de forma fiel y suficientemente abstracta los programas de un compilador. Existen distintas alternativas que describiremos a continuación

Lengua

jesintermed

ios

I.Representacionesjerárquicas

II.Representacioneslineales

Las representaciones jerárquicas de código intermedio reflejan los programas de un lenguaje como una estructura relacional de nodos y arcos entre nodos. Estas representaciones son aconsejables para tareas de análisis y transformación pero no para sintetizar ejecutables en una arquitectura física real

I.IArbolessintác8cosabstractos

I.IGrafosdirigidosacíclicos

Son una representación similar a los árboles de análisis sintácticos donde los artefactos semánticamente superfluos se omiten y los no terminales se sustituyen por operadores

Cuando los nodos de un árbol sintáctico abstracto son referenciados por más de un padre surgen los grafos dirigidos acíclicos

Las representaciones lineales de código intermedio codifican un programa como una secuencia de instrucciones de bajo nivel abstractas próximas al lenguaje ensamblador. Este tipo de lenguajes resultan más apropiados para la etapa de síntesis puesto que se encuentran más cercanas a la estructura típica los lenguajes objetivos más comunes

II.ILenguajesdetercetosotripletas

II.IILenguajesdecuartetosocuádruplas

En los lenguajes de tercetos cada operación tiene hasta dos operandos de entrada y uno de salida que se sobrescribe sobre alguno de los de entrada

En los lenguajes de cuartetos cada operación tiene hasta 2 operandos de entrada y uno independiente de salida para el resultado

Focodeatención

}

Page 103: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 8

Lenguajesintermedios

RepresentacionesjerárquicasLas representaciones jerárquicas describen el código fuente de un programa como una colección de nodos relacionados entre sí a través de arcos con el mismo nivel de abstracción que lo hacen los árboles de análisis sintáctico

Árbolessintác8cosabstractos

while(a>b)doa++

SWhile

WHILE ( E ) DO S

E > E

while(a>b)doa++

WHILE

> ++

ID ID ID

Los arboles sintácticos abstractos representan el código fuente de un programa de acuerdo a una estructura jerárquica de forma similar a como lo haces los árboles de análisis sintáctico. En estas representaciones no obstante se omiten todos tipo de símbolos semánticamente superfluos y se eliden los no terminales que dan información sobre el proceso de derivación gramatical

transformación

Árbol de análisis sintáctico Código intermedio

›  Apto para análisis semántico

›  Apto para procesos de transformación

›  Inadecuado para la etapa de síntesis

›  Representación excesivamente abstracta

Page 104: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 9

Lenguajesintermedios

RepresentacionesjerárquicasLas representaciones jerárquicas describen el código fuente de un programa como una colección de nodos relacionados entre sí a través de arcos con el mismo nivel de abstracción que lo hacen los árboles de análisis sintáctico

Grafosdirigidosacíclicos

a:=b*c+b*c

Asignación

ID

a:=b*c+b*c

:=

Los arboles dir igidos acícl icos realizan una representación del código fuente en forma de grafo. El método constructivo es similar al de los árboles sintácticos con la diferencia de que aquí se reutilizan los nodos que reflejen la misma estructura én aras a resultar más eficiente su representación en memoria

transformación

Árbol de análisis sintáctico Código intermedio

›  Apto para análisis semántico

›  Apto para procesos de transformación

›  Inadecuado para la etapa de síntesis

›  Representación excesivamente abstracta

:= E

E E +

E E * E E *

+

*

ID ID

ID

Page 105: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 10

Lenguajesintermedios

RepresentacioneslinealesLas representaciones lineales suponen un secuenciamiento de la información codificada en los árboles de análisis sintácticos en forma de una colección de instrucciones abstractas de bajo nivel pero manteniendo las referencias simbólicas introducidas por el programador. Para articular el proceso de secuenciamiento se utilizan varios elementos como operandos de dichas instrucciones que serán utilizados en lo venidero a lo largo del tema

I.Valoresliterales II.Variables

En numerosas ocasiones las operaciones de código intermedio utilizan operandos que representan valores literales enteros con o sin signo. La fase de traducción a código final se encarga posteriormente de traducir esos valores a la representación numérica correspondiente utilizada por la arquitectura

Muchos de los símbolos declarados por el programador, tales como constantes, variables globales o locales y parámetros, son referidos de forma general dentro del código intermedio como operandos de tipo ‘variable’

Los valores literales utilizados como

operandos en las operaciones de los

lenguajes de código intermedio lineales

representan valores enteros con signo

Las variables de código intermedio

representan las constantes, variables

globales o locales y parámetros declarados

por el programador a lo largo del código

fuente

Page 106: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 11

Lenguajesintermedios

RepresentacioneslinealesLas representaciones lineales suponen un secuenciamiento de la información codificada en los árboles de análisis sintácticos en forma de una colección de instrucciones abstractas de bajo nivel pero manteniendo las referencias simbólicas introducidas por el programador. Para articular el proceso de secuenciamiento se utilizan varios elementos como operandos de dichas instrucciones que serán utilizados en lo venidero a lo largo del tema

III.Variablestemporales IV.E8quetasdecódigo

El secuenciamiento de expresiones complejas requiere del almacenamiento temporal de los resultados parciales de las subexpresiones en espacios de memoria específ icamente reservados para ello. Los elementos de código intermedio que se utilizan para referencias esas direcciones se l laman variables temporales

Muchas de las sentencias de un lenguaje de alto nivel (control de flujo, invocación de subprogramas, etc.) requieren insertar etiquetas en el código final para luego realizar saltos a ellas. La forma de referirse a estas etiquetas en código intermedio es mediante las etiquetas de código

Una variable temporal es la representación

simbólica en código intermedio de un

espacio de memoria destinado a almacenar

un resultado parcial de alguna expresión

Una etiqueta de código es una referencia de

código intermedio a una zona de memoria

donde comienza cierta porción de código

final

Page 107: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 12

Lenguajesintermedios

RepresentacioneslinealesLas representaciones lineales suponen un secuenciamiento de la información codificada en los árboles de análisis sintácticos en forma de una colección de instrucciones abstractas de bajo nivel pero manteniendo las referencias simbólicas introducidas por el programador. A continuación describimos los 2 tipos de representaciones lineales

LenguajesdetercetosLas representaciones de código intermedio basadas en tercetos están formados por una secuencia de instrucciones constituida por 3 elementos: un código de operación, un operando de entrada y otro de entrada y salida para almacenar el resultado

›  Apto para la etapa de síntesis

›  Representación cercana al lenguaje objetivo

›  Complejidad en la traducción de construcciones

ADD x y

El código de operación es un acrónimo que representa el tipo de operación que se aplican entre los operandos del terceto

Código de operación

Los operandos identifican los elementos sobre los que se efectúa la operación referida por el código de operación. Pueden ser valores literales, variables, variables temporales o etiquetas

Operandos

En los lenguajes de tercetos uno de los operandos hace de almacén para el resultado de la operación lo que supone que el operando de entrada se pierde tras su ejecución

Resultado

Page 108: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 13

Lenguajesintermedios

RepresentacioneslinealesLas representaciones lineales suponen un secuenciamiento de la información codificada en los árboles de análisis sintácticos en forma de una colección de instrucciones abstractas de bajo nivel pero manteniendo las referencias simbólicas introducidas por el programador. A continuación describimos los 2 tipos de representaciones lineales

LenguajesdetercetosLas representaciones de código intermedio basadas en tercetos están formados por una secuencia de instrucciones constituida por 3 elementos: un código de operación, un operando de entrada y otro de entrada y salida para almacenar el resultado

›  Apto para la etapa de síntesis

›  Representación cercana al lenguaje objetivo

›  Complejidad en la traducción de construcciones

a:=b*c

Asignación

ID

a:=b*c

transformación

Árbol de análisis sintáctico

Código intermedio

:= E

E E *

ID ID

(a)

(b) (c)

LOADt0bLOADt1cMULt1t0STOREt1a

t0!bt1!ct1!t1*t0t1"a

Page 109: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 14

Lenguajesintermedios

RepresentacioneslinealesLas representaciones lineales suponen un secuenciamiento de la información codificada en los árboles de análisis sintácticos en forma de una colección de instrucciones abstractas de bajo nivel pero manteniendo las referencias simbólicas introducidas por el programador. A continuación describimos los 2 tipos de representaciones lineales

LenguajesdecuartetosLas representaciones de código intermedio basadas en cuartetos están formados por una secuencia de instrucciones constituida por 4 elementos: un código de operación, dos operando de entrada y otro de salida para almacenar el resultado

›  Apto para la etapa de síntesis

›  Representación cercana al lenguaje objetivo

›  Mayor sencillez en la traducción de construcciones

ADD x y z

El código de operación es un acrónimo que representa el tipo de operación que se aplican entre los operandos del terceto

Código de operación

Los operandos identifican los elementos sobre los que se efectúa la operación referida por el código de operación. Pueden ser valores literales, variables, variables temporales o etiquetas

Operandos

En los lenguajes de cuartetos el almacén para el resultado de la operación es un operando de salida independiente lo que supone que no hay perdida de información tras la ejecución de la operación

Resultado

Page 110: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 15

Lenguajesintermedios

RepresentacioneslinealesLas representaciones lineales suponen un secuenciamiento de la información codificada en los árboles de análisis sintácticos en forma de una colección de instrucciones abstractas de bajo nivel pero manteniendo las referencias simbólicas introducidas por el programador. A continuación describimos los 2 tipos de representaciones lineales

Lenguajesdecuartetos

a:=b*c

Asignación

ID

a:=b*c

transformación

Árbol de análisis sintáctico

Código intermedio

:= E

E E *

ID ID

(a)

(b) (c)

LOADt0bLOADt1cMULt2t1t0STOREt2a

t0!bt1!ct2!t1*t0t2"a

Las representaciones de código intermedio basadas en cuartetos están formados por una secuencia de instrucciones constituida por 4 elementos: un código de operación, dos operando de entrada y otro de salida para almacenar el resultado

›  Apto para la etapa de síntesis

›  Representación cercana al lenguaje objetivo

›  Mayor sencillez en la traducción de construcciones

Page 111: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 16

Generacióndecódigointermedioenlaprác6ca

ArtefactosparalageneracióndecódigointermedioLa generación de código intermedio se realiza a través de la definición de accesos semánticas en los esquemas de traducción gramaticales. Para llevar esto a cabo, el framework de desarrollo proporciona una colección de artefactos que conviene conocer

ScopeManager

TemporalTable Scope SymbolTable

Create>

SymbolIF

Label

Temporal Value

Variable

TypeTable TypeIF

Quadruple

LabelFactory

TemporalFactoryCreate>

Referenceto>

IntermediateCodeBuilder Create> <uses

OperandIF

Page 112: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 17

Generacióndecódigointermedioenlaprác6ca

ArtefactosparalageneracióndecódigointermedioLa generación de código intermedio se realiza a través de la definición de accesos semánticas en los esquemas de traducción gramaticales. Para llevar esto a cabo, el framework de desarrollo proporciona una colección de artefactos que conviene conocer

CuádruplasLas cuádruplas son el elemento central de la arquitectura. Representan cada una de las operaciones atómicas que pueden ser referenciadas dentro del código intermedio para que surtan cierto efecto o realicen cierto cálculo a partir de los operandos

Quadruple

+StringgetOperation()

+voidsetOperation()

+OperandIFgetFirstOperand()

+voidsetFirstOperand(OperandIFo)

+OperandIFgetSecondOperand()

+voidsetSecondOperand(OperandIFo)

+OperandIFgetResult()

+voidsetResult(OperandIFo)

Los objetos de tipo Quadruple se utilizan para representar operaciones atómicas del código intermedio. Una cuadrupla está formado por un código de operación, un operando opcional resultado y a lo sumo dos operandos de entrada también opcionales. En efecto, en función del tipo de operación el numero de operandos puede variar. Puede haber instrucciones con ningún operando ni resultado, como HALT. Puede haber otras con un sólo operando como los saltos del tipo BR L. O puede haber instrucciones con un resultado y dos operandos como en la suma ADD t3 t1 t2.

}

Page 113: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 18

Generacióndecódigointermedioenlaprác6ca

ArtefactosparalageneracióndecódigointermedioLa generación de código intermedio se realiza a través de la definición de accesos semánticas en los esquemas de traducción gramaticales. Para llevar esto a cabo, el framework de desarrollo proporciona una colección de artefactos que conviene conocer

Variables,temporales,valoresye8quetasLos operandos sobre los que operan las cuádruplas son de uno de cuatro tipos: variables, variables temporales, valores literales enteros y etiquetas. Dentro de la arquitectura existe una clase abierta para representar cada uno de estos tipos que el alumno debe carácter con atributos

Variable

- Stringname- ScopeIFscope- BooleanisGlobal

Temporal

- Stringname- ScopeIFscope- Integeraddress

Label

- Stringname- ScopeIFscope

Value

- Integervalue

Page 114: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 19

Generacióndecódigointermedioenlaprác6ca

ArtefactosparalageneracióndecódigointermedioLa generación de código intermedio se realiza a través de la definición de accesos semánticas en los esquemas de traducción gramaticales. Para llevar esto a cabo, el framework de desarrollo proporciona una colección de artefactos que conviene conocer

TabladetemporalesLos temporales que se van generando a medida que el compilador procesa las expresiones del lenguaje deben almacenarse en una tabla de temporales asociada a cada ámbito. Este es un aspecto importante para las fases posteriores. El artefacto TemporalTable gestiona los temporales de un ámbito

TemporalTable

- ScopeIFscope- List<TemporalIF>temporals

+ScopeIFgetScope()

+TemporalTable(ScopeIFscope)

+List<TemporalIF>getTemporals()

+voidaddTemporal(TemporalIFtemporal)

+booleancontainsTemporal(TemporalIFtemporal)

Cada tabla de temporales se crea de forma automática asociada a un ámbito cuando este es abierto a través del gestor de ámbitos. Por tanto existe una tabla de temporales para cada ámbito. La responsabilidad de este artefacto es gest ionar la colección de temporales generados durante el proceso de compilación del bloque sintáctico asociado al ámbito. Los métodos addTemporal y getTemporals sirven para registrar y tener acceso a los temporales respectivamente y son de utilidad en ésta y en las fases posteriores de generación de código final

}

Page 115: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 20

Generacióndecódigointermedioenlaprác6ca

ArtefactosparalageneracióndecódigointermedioLa generación de código intermedio se realiza a través de la definición de accesos semánticas en los esquemas de traducción gramaticales. Para llevar esto a cabo, el framework de desarrollo proporciona una colección de artefactos que conviene conocer

Factoríasdee8quetasytemporalesAunque la construcción de temporales y etiquetas puede realizarse haciendo uso directo de los constructores en sendas clases, el framework proporciona dos tipos de factorías cuyo uso para construir objetos de estas clases resulta recomendable por las ventajas que ello supone

TemporalFactory

+TemporalFactory(ScopeIFscope)

+TemporalIFcreate(Stringname)

+TemporalIFcreate()

LabelFactory

+LabelFactory(ScopeIFscope)

+LabelIFcreate(Stringname)

+LabelIFcreate()

La factoría de temporales es un artefacto asociado a un ámbito pasado como argumento en el constructor que se utiliza para crear temporales. El primer método create construye un temporal con nombre propio y lo registra automáticamente en la tabla de temporales. La diferencia del segundo create, es que éste método construye el temporal con un nombre autogenerado que garantiza la unicidad dentro del ámbito

}

La factoría de etiquetas es un que se utiliza para crear etiquetas. El primer método create construye una etiqueta con nombre propio. La diferencia del segundo create, es que éste método construye la etiqueta con un nombre autogenerado que garantiza la unicidad

}

Page 116: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 21

Generacióndecódigointermedioenlaprác6ca

ArtefactosparalageneracióndecódigointermedioLa generación de código intermedio se realiza a través de la definición de accesos semánticas en los esquemas de traducción gramaticales. Para llevar esto a cabo, el framework de desarrollo proporciona una colección de artefactos que conviene conocer

IntermediateCodeBuilderLa construcción de las cuádruplas que componen el código intermedio puede realizarse por invocación de sus constructores de clase. No obstante, resulta más sencillo y económico utilizar instancias de IntermediateCodeBuilder para realizar esta labor

IntermediateCodeBuilder

+voidaddQuadruple(Stringop,r)

+voidaddQuadruple(Stringop,r,o1)

+voidaddQuadruple(Stringop,r,o1,o2)

+voidaddQuadruple(QuadrupleIFq)

+voidaddQuadruples(List<QuiadrupleIF>code)

+List<QuadrupleIF>create()

Las operaciones addQuadruple se encargan de insertar un nuevo cuarteto dentro de la lista interna de código intermedio. Sin embargo su semántica depende del tipo y formato de los operandos

}

}

Primero se instancia el code builder pasándole como argumento de constructo el ámbito. Después se utilizan los métodos addQuadruple para ir acumulando cuartetos internamente. Al finalizar la acción semántica el código se obtiene invocando el método create ()

›  Si es de tipo OperandIF se inserta tal cual

›  Si es de tipo int se crea un Value y se inserta

›  Si es de tipo String

›  Si comienza por “L_” se crea Label y se inserta

›  Si comienza por “T_” se crea Temporal y se inserta

›  Sino se busca en TS’s, se crea Variable y se inserta

Page 117: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 22

Generacióndecódigointermedioenlaprác6ca

DiseñodellenguajeintermedioAntes de proceder con la generación de código intermedio es necesario determinar el juego de instrucciones (cuartetos) que será empleado. Estudie para ello el/los lenguajes objetivos finales

Cuarteto Descripción

NOP

ADDxyz

SUBxyz

MULxyz

DIVxyz

MODxyz

INCxy

DECxy

NEGxy

GRxyz

EQxyz

LSxyz

ANDxyz

ORxyz

XORxyz

Nada

x:=y+z

x:=y–z

x:=y*z

x:=y/z

x:=y%z

x:=y+1

x:=y–1

x:=–y

x:=(y>z)?1:0

x:=(y==z)?1:0

x:=(y<z)?1:0

x:=y&&z

x:=y||z

x:=y^z

Cuarteto Descripción

NOTxy

BRL

BRTxL

BRFxL

INLL

MVxy

MVPxy

MVAxy

STPxy

STAxy

PUSHx

POPx

CALLf

RETx

HALT

x:=!y

SaltoaL

Six,saltoaL

Si!x,saltoaL

InsertarL:

x:=y

x:=*y

x:=&y

*x:=y

&x:=y

*SP:=x;SP++

x:=*SP;SP--

Llamadaafunciónf

Retornodefconvalorx

Stop

Page 118: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 23

Generacióndecódigointermedioenlaprác6ca

GeneracióndecódigointermedioenCupUna vez que conocemos los artefactos proporcionados por el framework para la fase de generación de código y diseñado un lenguaje de código intermedio apropiado, estamos en disposición de articular dicha generación dentro del esquema de traducción dirigida por la sintaxis de cup

Expresiones Expresionesexp::=exp:e1MASexp:e2{:

Expe=newExp();

<<comprobacióndetiposdee1ye2>>

ScopeIFscope=scopeManager.getCurrentScope();

TemporalFactorytF=newTemporalFactory(scope);

IntermediateCodeBuildercb=new…Builder(scope)

TemporalIFtemp1=e1.getTemporal();

TemporalIFtemp2=e2.getTemporal();

TemporalIFtemp=tF.create();

cb.addQuadruples(e1.getCode());

cb.addQuadruples(e2.getCode());

cb.addQuadruple(“ADD”,temp,temp1,temp2);

e.setTemporal(temp);

e.setCode(cb.create());

RESULT=e

:}

exp::=exp:e1MENOSexp:e2{:...:}

exp::=exp:e1PORexp:e2{:...:}

...

exp::=exp:e1ANDexp:e2{:...:}

exp::=exp:e1ORexp:e2{:...:}

exp::=NOTexp:e1{:...

ScopeIFscope=scopeManager.getCurrentScope();

TemporalFactorytF=newTemporalFactory(scope);

IntermediateCodeBuildercb=new…Builder(scope)

TemporalIFtemp1=e1.getTemporal();

TemporalIFtemp=tF.create();

cb.addQuadruples(e1.getCode());

cb.addQuadruple(“NOT”,temp,temp1);

e.setTemporal(temp);

e.setCode(cb.create());

RESULT=e:}

Page 119: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 24

Generacióndecódigointermedioenlaprác6ca

GeneracióndecódigointermedioenCupUna vez que conocemos los artefactos proporcionados por el framework para la fase de generación de código y diseñado un lenguaje de código intermedio apropiado, estamos en disposición de articular dicha generación dentro del esquema de traducción dirigida por la sintaxis de cup

Expresiones Expresionesexp::=PIexp:e1PD{:

RESULT=e1;

:}

exp::=rNumero:rn{:

Expe=newExp();

Integervalue=rn.getValue();

<<Comprobacióndetipos>>

ScopeIFscope=scopeManager.getCurrentScope();

TemporalFactorytF=newTemporalFactory(scope);

IntermediateCodeBuildercb=new…Builder(scope);

TemporalIFtemp=tF.create();

cb.addQuadruple(“MV”,temp,value);

e.setTemp(temp);

e.setCode(cb.create()):

RESULT=e;

:}

exp::=MENOSexp:e1{:

Expe=newExp();

<<comprobacióndetiposdee1ye2>>

ScopeIFscope=scopeManager.getCurrentScope();

TemporalFactorytF=newTemporalFactory(scope);

IntermediateCodeBuildercb=new…Builder(scope)

TemporalIFtemp1=e1.getTemporal();

TemporalIFtemp=tF.create();

cb.addQuadruples(e1.getCode());

cb.addQuadruple(“NEG”,temp,temp1);

e.setTemporal(temp);

e.setCode(cb.create());

RESULT=e;

:}

Page 120: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 25

Generacióndecódigointermedioenlaprác6ca

GeneracióndecódigointermedioenCupUna vez que conocemos los artefactos proporcionados por el framework para la fase de generación de código y diseñado un lenguaje de código intermedio apropiado, estamos en disposición de articular dicha generación dentro del esquema de traducción dirigida por la sintaxis de cup

Expresiones Referenciasexp::=referencia:r{:

Expe=newExp();

e.setType(r.getType());

ScopeIFscope=scopeManager.getCurrentScope();

TemporalFactorytF=newTemporalFactory(scope);

IntermediateCodeBuildercb=new…Builder(scope);

TemporalIFrTemp=r.getTemporal();

TemporalIFtemp=tF.create();

cb.addQuadruples(r.getCode());

cb.addQuadruple(“MVP”,temp,rTemp);

e.setTemp(temp);

e.setCode(cb.create()):

RESULT=e;

:}

referencia::=ID:id{:

Referenciar=newReferencia();

Stringname=id.getLexema();

<<Comprobacióndetipos>>

ScopeIFscope=scopeManager.getCurrentScope();

TemporalFactorytF=newTemporalFactory(scope);

IntermediateCodeBuildercb=new…Builder(scope);

TemporalIFtemp=tF.create();

SymbolVariablesV=scopeManager.searchSymbol(name);

Variablevar=newVariable(name,sV.getScope());

cb.addQuadruple(“MVA”,temp,var);

referencia.setTemporal(temp);

referencia.setCode(cb.create());

RESULT=referencia;

:}

Page 121: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 26

Generacióndecódigointermedioenlaprác6ca

GeneracióndecódigointermedioenCupUna vez que conocemos los artefactos proporcionados por el framework para la fase de generación de código y diseñado un lenguaje de código intermedio apropiado, estamos en disposición de articular dicha generación dentro del esquema de traducción dirigida por la sintaxis de cup

ReferenciasaelementosdeArraysreferencia::=ID:id{:

Referenciar=newReferencia();

Stringname=id.getLexema();

<<Comprobacióndetipos>>

ScopeIFscope=scopeManager.getCurrentScope();

TemporalFactorytF=newTemporalFactory(scope);

IntermediateCodeBuildercb=new…Builder(scope);

TemporalIFtemp=tF.create();

TemporalIFtempI=tF.create();

cb.addQuadruple(“MVA”,temp,name);

cb.addQuadruple(“MV”,tempI,0);

referencia.setTemporal(temp);

referencia.setTemporalIndex(tempI);

referencia.setCode(cb.create());

RESULT=referencia;

:}

D1

V[i][j][k]

i

D2

D3

k

V

&v+ix(D2xD3xsize)

+jx(D3xsize)

+kxsize

size

t1:=0

t2:=t1xD1+i

t3:=t2xD2+j

t4:=t3xD3+k

t5:=&v+t4xsize

=

j

Page 122: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 27

Generacióndecódigointermedioenlaprác6ca

GeneracióndecódigointermedioenCupUna vez que conocemos los artefactos proporcionados por el framework para la fase de generación de código y diseñado un lenguaje de código intermedio apropiado, estamos en disposición de articular dicha generación dentro del esquema de traducción dirigida por la sintaxis de cup

ReferenciasaelementosdeArraysreferencia::=referencia:rCIexp:eCD{:

Referenciarn=newReferencia();

<<comprobacióndetipos>>

TypeIFrType=r.getType();

intrDim=rType.getMax()–rType.getMin()+1;

TemporalFactoryIFtF=newTemporalFactory(scope);

TemporalIFrTemp=r.getTemporal();

TemporalIFrTempI=r.getTemporalIndex();

TemporalIFeTemp=e.getTemporal();

TemporalIFrnTempI=tF.create();

IntermadiateCodeBuildercb=new…Builder(scope);

cb.addQuadruples(e.getCode());

cb.addQuadruples(r.getCode());

cb.addQuadruple(“MUL”,rnTempI,rTempI,rDim);

cb.addQuadruple(“ADD”,rnTempI,rnTempI,eTemp);

rn.setType(rType.getBaseType());

rn.setTemporal(rTemp);rn.setTemporalIndex(rnTempI);

r.setCode(cb.create());RESULT=rn;:}

D1

V[i][j][k]

i

D2

D3

k

V

&v+ix(D2xD3xsize)

+jx(D3xsize)

+kxsize

size

t1:=0

t2:=t1xD1+i

t3:=t2xD2+j

t4:=t3xD3+k

t5:=&v+t4xsize

=

j

Page 123: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 28

Generacióndecódigointermedioenlaprác6ca

GeneracióndecódigointermedioenCupUna vez que conocemos los artefactos proporcionados por el framework para la fase de generación de código y diseñado un lenguaje de código intermedio apropiado, estamos en disposición de articular dicha generación dentro del esquema de traducción dirigida por la sintaxis de cup

ReferenciasaelementosdeArraysexp::=referencia:r{:

Expe=newExp();

<<comprobacióndetipos>>

ScopeIFscope=scopeManager.getCurrentScope();

TemporalFactoryIFtF=newTemporalFactory(scope);

TemporalIFrTemp=r.getTemporal();

TemporalIFrTempI=r.getTemporalIndex();

TemporalIFeTemp=tF.create();

TypeIFrType=r.getType();

intrSize=rType.getSize();

IntermadiateCodeBuildercb=new…Builder(scope);

cb.addQuadruples(r.getCode());

cb.addQuadruple(“MUL”,eTemp,rTempI,rSize);

cb.addQuadruple(“ADD”,eTemp,eTemp,rTemp);

cb.addQuadruple(“MVP”,eTemp,eTemp);

e.setTemporal(eTemp);

e.setCode(cb.create());

RESULT=e;:}

D1

V[i][j][k]

i

D2

D3

k

V

&v+ix(D2xD3xsize)

+jx(D3xsize)

+kxsize

size

t1:=0

t2:=t1xD1+i

t3:=t2xD2+j

t4:=t3xD3+k

t5:=&v+t4xsize

=

j

Page 124: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 29

Generacióndecódigointermedioenlaprác6ca

GeneracióndecódigointermedioenCupUna vez que conocemos los artefactos proporcionados por el framework para la fase de generación de código y diseñado un lenguaje de código intermedio apropiado, estamos en disposición de articular dicha generación dentro del esquema de traducción dirigida por la sintaxis de cup

Referenciaacamposderegistro Referenciaacamposderegistroreferencia::=referencia:rPUNTOID:id{:

Referenciarn=newReferencia();

Stringname=id.getLexema();

<<comprobacióndetipos>>

ScopeIFscope=scopeManager.getCurrentScope();

TemporalFactorytF=newTemporalFactory(scope);

TemporalIFrTemp=r.getTemporal();

TemporalIFrTempI=r.getTemporalIndex();

TemporalIFrTempO=tF.create();

IntermediateCodeBuildercb=new…Builder(scope);

cb.addQuadruples(r.getCode());

TypeRecordrType=r.getType();

intidOffset=rType.getOffset(name);

cb.addQuadruple(“MV”,rTempO,idOffset);

rn.setTemporal(rTemp);

rn.setTemporalIndex(rTempI);

rn.setTemporalOffset(rTempO);

rn.serCode(cb.create());RESULT=rn;:}

expr::=referencia:r{:

Expe=newExp();

<<comprobacióndetipos>>

ScopeIFscope=scopeManager.getCurrentScope();

TemporalFactoryIFtF=newTemporalFactory(scope);

TemporalIFrTemp=r.getTemporal();

TemporalIFrTempI=r.getTemporalIndex();

TemporalIFrTempO=r.getTemporalOffset();

TemporalIFeTemp=tF.create();

TypeIFrType=r.getType();

intrSize=rType.getSize();

IntermadiateCodeBuildercb=new…Builder(scope);

cb.addQuadruples(r.getCode());

cb.addQuadruple(“MUL”,eTemp,rTempI,rSize);

cb.addQuadruple(“ADD”,eTemp,eTemp,rTemp);

cb.addQuadruple(“ADD”,eTemp,eTemp,rTempO);

cb.addQuadruple(“MVP”,eTemp,eTemp);

e.setTemporal(eTemp);e.setCode(cb.create());RESULT=e;:}

Page 125: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 30

Generacióndecódigointermedioenlaprác6ca

GeneracióndecódigointermedioenCupUna vez que conocemos los artefactos proporcionados por el framework para la fase de generación de código y diseñado un lenguaje de código intermedio apropiado, estamos en disposición de articular dicha generación dentro del esquema de traducción dirigida por la sintaxis de cup

Sentenciaasignación SentenciaIfsentenciaAsignacion::=referencia:rIGUALexp:e{:

SentenciaAsignacionsa=newSAsignacion();

<<comprobacióndetipos>>

ScopeIFscope=scopeManager.getCurrentScope();

TemporalFactoryIFtF=newTemporalFactory(scope);

TemporalIFeTemp=e.getTemporal();

TemporalIFrTemp=r.getTemporal();

TemporalIFrTempI=r.getTemporalIndex();

TemporalIFrTempO=r.getTemporalOffset();

TemporalIFtemp=tF.create();

IntermediateCodeBuildercb=new…Builder(scope);

cb.addQuadruples(e.getCode());

cb.addQuadruples(r.getCode());

cb.addQuadruple(“MUL”,temp,rTempI,rSize);

cb.addQuadruple(“ADD”,temp,temp,rTemp);

cb.addQuadruple(“ADD”,temp,temp,rTempO);

cb.addQuadruple(“STP”,temp,eTemp);

sa.setCode(cb.create());RESULT=sa;:}

sentenciaIF::=IFPIexp:ePDs:s1ELSEs:s2{:

SentenciaIfsIf=newSIf();

<<comprobacióndetipos>>

ScopeIFscope=scopeManager.getCurrentScope();

LabelFactoryIFlF=newLabelFactory(scope);

LabelIFl1=lF.create();

LabelIFl2=lF.create();

TemporalIFeTemp=e.getTemporal();

IntermadiateCodeBuildercb=new…Builder(scope);

cb.addQuadruples(e.getCode());

cb.addQuadruple(“BRF”,eTemp,l1);

cb.addQuadruples(s1.getCode());

cb.addQuadruple(“BR”,l2);

cb.addQuadruple(“INL”,l1);

cb.addQuadruples(s2.getCode());

cb.addQuadruple(“INL”,l2);

sIF.setCode(cb.create());

RESULT=sIF;:}

Page 126: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 31

Generacióndecódigointermedioenlaprác6ca

GeneracióndecódigointermedioenCupUna vez que conocemos los artefactos proporcionados por el framework para la fase de generación de código y diseñado un lenguaje de código intermedio apropiado, estamos en disposición de articular dicha generación dentro del esquema de traducción dirigida por la sintaxis de cup

SentenciaWhile SentenciaForsentenciaWhile::=WHILEPIexp:ePDs:s1{:

SentenciaWhilesWhile=newSWhile();

<<comprobacióndetipos>>

ScopeIFscope=scopeManager.getCurrentScope();

LabelFactoryIFlF=newLabelFactory(scope);

LabelIFl1=lF.create();

LabelIFl2=lF.create();

TemporalIFeTemp=e.getTemporal();

IntermadiateCodeBuildercb=new…Builder(scope);

cb.addQuadruple(“INL”,l1);

cb.addQuadruples(e.getCode());

cb.addQuadruple(“BRF”,eTemp,l2);

cb.addQuadruples(s1.getCode());

cb.addQuadruple(“BR”,l1);

cb.addQuadruple(“INL”,l2);

sWhile.setCode(cb.create());

RESULT=sWhile;:}

sentenciaFor::=FORsAsignacion:saTOexp:eDOs:s1{:

SentenciaForsFor=newSFor();

<<comprobacióndetipos>>

ScopeIFscope=scopeManager.getCurrentScope();

LabelFactoryIFlF=newLabelFactory(scope);

LabelIFl1=lF.create();

LabelIFl2=lF.create();

TemporalIFeTemp=e.getTemporal();

IntermadiateCodeBuildercb=new…Builder(scope);

cb.addQuadruples(sa.getCode());

cb.addQuadruple(“INL”,l1);

cb.addQuadruples(e.getCode());

cb.addQuadruple(“BRF”,eTemp,l2);

cb.addQuadruples(s1.getCode());

cb.addQuadruple(“BR”,l1);

cb.addQuadruple(“INL”,l2);

sFor.setCode(cb.create());

RESULT=sFor;:}

Page 127: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 32

Generacióndecódigointermedioenlaprác6ca

1.  Diseñar un lenguaje intermedio

-  Identificar todas las operaciones necesarias y asignarles un acrónimo y semántica

-  Tomar como referencia el lenguaje objeto de la arquitectura real

-  Comenzar por un juego sencillo e ir refinándolo bajo demanda

2.  Implementar las clases necesarias del framework

-  Caracterizar mediante atributos los operandos: Variable, Temporal, Label, Value

-  Incluir atributos necesarios a cada no terminal (Expresión, Sentencias, Referencias, …)

-  Considerar revisar la definición de otros artefactos: TypeIF, …

3.  Implementar las acciones semánticas que generan código intermedio

-  Código intermedio para expresiones, referencias, sentencias…

-  Incorporar este código al del comprobador de tipos implementado en la fase anterior

4.  Probar el código intermedio

-  Ejecutar el finalTestCase

-  semanticErrorManager.debug en reglas para que imprima el código intermedio generado

DesarrollopasoapasoLa fase de generación de código intermedio requiere de la implementación de acciones semánticas en el esquema de traducción dirigidas a producir un código lineal cercano al código objeto pero independiente de una arquitectura física real. A continuación se resumen los pasos recomendados para esta fase

Page 128: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 33

BibliograYa

MaterialdeestudioBibliografía básica

Construcción de compiladores: principios y práctica

Kenneth C. Louden International Thomson Editores,

2004 ISBN 970-686-299-4

Page 129: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Sentenciasyexpresiones

8 - 34

BibliograYa

MaterialdeestudioBibliografía complementaria

Compiladores: Principios, técnicas y herramientas.

Segunda Edición Aho, Lam, Sethi, Ullman

Addison – Wesley, Pearson Educación, México 2008

Diseño de compiladores. A. Garrido, J. Iñesta, F. Moreno

y J. Pérez. 2002. Edita Universidad de Alicante

Page 130: Procesadores de Lenguajes I

ProcesadoresdeLenguajesIngenieríaTécnicasuperiordeIngenieríaInformá8ca

DepartamentodeLenguajesySistemasinformá6cos

JavierVé[email protected]

DepartamentodeLenguajesYSistemasInformáAcosUNED

9GeneracióndecódigointermedioIIAcAvacióndesubprogramas

Page 131: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 2

Obje6vos

Obje8vos

›  Conocer qué es la activación de un subprograma

›  Entender que son y aprender a diseñar registros de activación

›  Entender que son el entorno de ejecución de una máquina

›  Conocer los diferentes tipos de entornos e ejecución

›  Entender la diferentes capacidades de los mismos

›  Aprender a implementar la secuencia de llamada y retorno de un subprograma

›  Entender la relación entre la activación de un subprograma y el enlace de datos

›  Conocer los distintos mecanismos de paso de parámetros a un subprograma

›  Aprender a acceder a los datos en tiempo de ejecución

›  Referencias locales

›  Referencias no locales

›  Aprender a implementar procedimientos declarados de forma anidada

Page 132: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 3

Índice

Índice

›  Introducción

›  Activación de subprogramas

›  ¿Qué es la activación de un subprograma?

›  Tipos de activaciones

›  Árboles de activación

›  El registro de activación

›  El registro de activación y los entornos de ejecución

›  Secuencias de llamada y retorno

›  Enlace de nombres

›  Mecanismos de paso de parámetros

›  Acceso a datos en tiempo de ejecución

›  Activación de subprogramas en la práctica

›  Bibliografía

Page 133: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 4

Introducción

IntroducciónEn el tema anterior vimos como puede generarse código intermedio para las sentencias e instrucciones de un lenguaje estructurado de alto nivel. Resta por saber cómo puede gestionarse la invocación de subprogramas para dar soporte a la modularización de código basada en abstracciones funcionales y procedimentales que soportan este tipo de lenguajes. A este respecto destacan dos aspectos principales

Invocación de subprogramas

I. Activación de subprogramas

II. Enlace de datos

Cuando un subprograma llamante invoca a otro llamado, se dice que se produce una activación de éste último. En este punto, la principal preocupación es mantener la cadena de invocaciones para saber devolver en cada caso el retorno a la siguiente introducción justo detrás de la invocación del llamado dentro del código del llamante. Los escenarios más complejos se dan en lenguajes recursivos donde puede haber varias invocaciones de la misma función solapadas en el tiempo

Además los símbolos que representan objetos de datos dentro del código fuente – variables, parámetros, temporales – deben ser convenientemente enlazados con posiciones de memoria para que sean direccionados en tiempo de ejecución. En este sentido es importante advertir la complejidad de los lenguajes recursivos en los cuales un símbolo tendrá siempre un enlace de datos potencialmente distinto dentro de cada activación del subprograma que lo contiene

Page 134: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 5

Introducción

IntroducciónAunque conceptualmente diferentes, estos dos aspectos se encuentran estrechamente relacionados entre sí. En efecto, la activación de subprogramas requiere gestionar memoria para dar soporte al enlace de datos pero también para recordar la dirección de retorno a la que debe saltar tras la activación. Por su parte cada enlace de un objeto de datos puede ser potencialmente distinto en cada activación a un subprograma. En este sentido es conveniente realizar las siguientes asociaciones

I. Declaración de subprograma I. Activación de subprograma El compilador visita el cuerpo del subprogramapararealizarlacomprobaciónde6posygeneraruncódigoobjeto

El código objeto generado en la llamadapreparaunespaciodememoriaparages6onarlaejecucióndelsubprograma

II. Declaración de variable II. Enlaces de datos Ladeclaracióndevariablesyparámetroslanzaelcomprobador de 6pos y las registra comosímbolosdelprograma

Para cada var iable y parámetro delsubprogramasereservaespacioenmemoriayseges6onasuacceso

III. Ámbitos de declaración III. Tiempo de vida de los enlaces Elámbitodedeclaraciónestableceelalcancedevisibilidadque6eneelsímbolodeclaradodentrodelcódigofuente

El ámbito de declaración determina el 6empoque permanece accesible enmemoria el datoasociadoalsímbolo

Tiem

podecompilación

Tiem

podeejecución

Page 135: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 6

Ac6vacióndesubprogramas

¿Quéeslaac8vacióndeunsubprograma?El proceso de invocación de un subprograma conlleva una serie de acciones semánticas para gestionar su ejecución. Durante el tiempo de ejecución, a este proceso se le conoce por el nombre de activación del subprograma. Este concepto debe separarse claramente del proceso de compilación que se produce en tiempo de compilación

La activación de un subprograma enmarca el

lapso de tiempo durante la ejecución que dicho

subprograma permanece en ejecución y por tanto

utiliza un espacio reservado en memoria

PROGRAMcribaEratostenes;CONSTMAX=200;TYPETVector=ARRAY[1..MAX]OFInteger;VARp:TVector; PROCEDUREgCandidatos(VARc:TVector;n:Integer);VARi:Integer;BEGINFORi:=1TOnDOc[i]:=i;END;FUNCTIONcPrimos(VARc:TVector;n,d:Integer;):^TVector;VARr:TVector;PROCEDUREcribar(VARc,r:TVector;n,d:Integer);VARi,j:Integer; BEGINj:=1;FORi:=1TOnDOIF(c[i]>iANDc[i]modd<>0)THENBEGINr[j]:=i;j:=j+1;END;END;BEGINIF(d>SQRT(n))THENcPrimos:=c;ELSEBEGINcribar(c,r,n,d);cPrimos:=cPrimos(r,n,d+1);END;END; BEGINgCandidatos(p,100);p:=cPrimos(p,100,2);END.

En este punto el programa del programaexisten en memoria una acAvación delprogramaprincipal,y2decPrimos

}

Page 136: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 7

Ac6vacióndesubprogramas

Tiposdeac8vaciónDependiendo de la aparición de las invocaciones a subprogramas dentro del código fuente, es posible distinguir diferentes tipos de activaciones. Esta clasificación es importante porque, como veremos, su soporte condiciona la gestión del entorno de ejecución y distingue la madurez de los lenguajes

Tipo

s de

ac

tivac

ión

Activaciones no solapantes

Activaciones solapantes

Dos activaciones se dice que son no solapantes cuando no coinciden en ningún instante dentro del tiempo de ejecución

f(x,y);

g(y,z);

Dos activaciones se dice que son solapantes o anidadas cuando el tiempo de una de ellas concurre con el de la otra

f(x,y){...}

g(y,z){...

f(y,z);

}

No recursivas

Recursivas

Dos activaciones solapantes son no recursivas si corresponden a subprogramas diferentes no recursivos

Dos activaciones solapantes son recursivas si corresponden a subprogramas recursivos

Recursividad directa Dos activaciones solapantes son recursivas directas si refieren al mismo subprograma

f(x){...

f(x-1);

}

Recursividad indirecta Dos activaciones solapantes son recursivas indirectas si una refiere a un subprograma y la de éste al del primero

f(x){g(x-1);}

g(x){f(x-1);}

Page 137: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 8

Ac6vacióndesubprogramas

Árbolesdeac8vaciónLas activaciones sucesivas que se producen a lo largo del tiempo de ejecución de un programa pueden representarse como un árbol que se va construyendo de izquierda a derecha según avanza la ejecución. Cada nodo representa la activación de un subprograma y sus hijos, las activaciones que éste desencadena

Un árbol de activación es una estructura jerárquica que representa el conjunto

de activación que se producen durante la ejecución de un programa. Cada

nodo se corresponde con una activación y contiene un hijo por cada

activación anidada dentro de ésta. El orden de los hijos marca el orden de las

activaciones no solapantes

P

a1 a2 a3

a11 a12

El nodo raíz hace referencia a la activación correspondiente al programa principal

Cada nodo corresponde a una act ivación solapante con la activación representada por el nodo padre

Nodo padre

Nodo raíz

El orden en que aparecen los hermanos corresponde con el orden secuencial en que se producen las activaciones no solapantes entre si

Nodos hermanos

Page 138: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 9

Ac6vacióndesubprogramas

Árbolesdeac8vaciónLas activaciones sucesivas que se producen a lo largo del tiempo de ejecución de un programa pueden representarse como un árbol que se va construyendo de izquierda a derecha según avanza la ejecución. Cada nodo representa la activación de un subprograma y sus hijos, las activaciones que éste desencadena

El recorrido en preorden del árbol de activación determina las llamadas a subprogramas que se van sucediendo a la largo de la ejecución del programa. En rojo se marcan los parámetros de salida

gCandidatos([1,2,3,4,5,6,7,8,9,10],10) cPrimos([1,2,3,4,5,6,7,8,9,10],10,2):[1,2,3,5,7]

cribar([1,2,3,4,5,6,7,8,9,10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

Ejemplo

}

Page 139: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 10

Ac6vacióndesubprogramas

Elregistrodeac8vaciónCada activación necesita de un espacio en memoria donde gestionar todos los datos relativos a la misma (valor de retorno, dirección de retorno, parámetros actuales, variables locales, temporales, etc.). A ese espacio de memoria se le conoce con el nombre de registro de activación y su propósito es servir de vehículo de información entre el llamador y el llamante

El registro de activación de un subprograma hace referencia al espacio físico

de memoria que es reservado para almacenar todos los datos relativos a la

activación de la misma

EjemploRA

gCandidatos([1,2,3,4,5,6,7,8,9,10],10) cPrimos([1,2,3,4,5,6,7,8,9,10],10,2):[1,2,3,5,7]

cribar([1,2,3,4,5,6,7,8,9,10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

RA

RA

RA

RA

RA RA

Page 140: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 11

Ac6vacióndesubprogramas

Elregistrodeac8vaciónylosentornosdeejecuciónEl entorno de ejecución hace referencia a la gestión por el compilador de la memoria dentro de la arquitectura física y determina dónde alojar el registro de cada activación en memoria. Esto, como es natural, condiciona considerablemente las capacidades para articular distintos tipos de activaciones de subprogramas

El entorno de ejecución viene dado por la estructura de memoria incluidos los

registros de la máquina y la forma de gestionarla que permite desarrollar

adecuadamente el proceso de ejecución de un programa

Memoria

¿De qué capacidad de memoria se dispone? ¿Cuál es el tamaño de página? ¿Qué espacio máximo reserva el sistema operativo para cada proceso? ¿Con cuantos bits se direcciona la máquina? ¿Cuál es el ancho de palabra?...

Registros¿De cuan tos reg is t ros se dispone? ¿Qué ancho de palabra t i e n e n ? ¿ E x i s t e r e g i s t r o acumulador? ¿Qué estructura tiene el registro de estado? ¿Existen punteros de pila?...

Juegodeinstrucciones¿De cuantos modos de direccionamiento se dispone? ¿Cuánto es el máximo de offset para el desplazamiento relativo? ¿Qué ancho de palabra tienen las instrucciones?...

Page 141: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 12

Ac6vacióndesubprogramas

Elregistrodeac8vaciónylosentornosdeejecuciónEl entorno de ejecución hace referencia a la gestión por el compilador de la memoria dentro de la arquitectura física y determina dónde alojar el registro de cada activación en memoria. Esto, como es natural, condiciona considerablemente las capacidades para articular distintos tipos de activaciones de subprogramas

Tipos de entornos de ejecución

I. Entornos de ejecución estáticos [Fortran 77]

II. Entornos de ejecución basados en pila [Pascal, C/C++]

III. Entornos de ejecución dinámicos [Java, SmallTalk, Lisp]

En los entornos de ejecución estáticos todas las activaciones de un mismo subprograma coinciden en memoria (existe un único RA por cada subprograma). Esto permite conocer en tiempo de compilación cada direccionamiento pero imposibilita las activaciones recursivas

En los entornos de ejecución dinámicos, cada activación distinta dispone de un RA propio gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

En los entornos de compilación completamente dinámicos los datos de las activaciones son gestionados en una zona de memoria de reserva dinámica llamada montículo o heap. Esto permite que los datos pueda sobrevivir al tiempo de vida de la activación que los generó

Page 142: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 13

Ac6vacióndesubprogramas

Entornodeejecuciónestá8coEn los entornos de ejecución estáticos todas las activaciones de un mismo subprograma coinciden en memoria. Es decir, existe un único registro de activación por cada subprograma, incluido el programa principal (si es que éste no se incluye en la zona de datos estáticos). Esto permite conocer en tiempo de compilación cada direccionamiento pero imposibilita las activaciones recursivas

OrganizacióndelamemoriaZonadecódigo

Zonadedatosestáticos

Memorialibre

Montículo

I. Zona de código Lazonadecódigocomienzaenlaposición0. Allí se almacena la traducción enbinario del programa. Cada funcióndispone de una e6queta al comienzo decuerpo de la función para ar6cular elsalto. Los puntos [n] indican posicionesde retorno que serán proporcionadas alprograma llamante para que sepa ladirecciónalaquedeberetornar

PROGRAMcribaEratostenes;CONSTMAX=200;TYPETVector=ARRAY[1..MAX]OFInteger;VARp:TVector;PROCEDUREgCandidatos(VARc:TVector;n:Integer);VARi:Integer;BEGIN...END;FUNCTIONcPrimos(VARc:TVector;n,d:Integer;):^TVector;VARr:TVector;PROCEDUREcribar(VARc,r:TVector;n,d:Integer);VARi,j:Integer; BEGIN...END;BEGIN...cribar(c,r,n,d);[3]cPrimos:=cPrimos(r,n,d+1);[4]...END;

BEGINgCandidatos(p,100);[1]p:=cPrimos(p,100,2);[2]END.

Page 143: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 14

Ac6vacióndesubprogramas

Entornodeejecuciónestá8coEn los entornos de ejecución estáticos todas las activaciones de un mismo subprograma coinciden en memoria. Es decir, existe un único registro de activación por cada subprograma, incluido el programa principal (si es que éste no se incluye en la zona de datos estáticos). Esto permite conocer en tiempo de compilación cada direccionamiento pero imposibilita las activaciones recursivas

Organizacióndelamemoria

II. Zona de datos estáticos Lazonadedatosestá6cossiguealcódigo.Allí se ubican todas las variablesdeclaradas en el ámbito global delprograma.Avecesestazonaseomiteysemuevelasvariablesglobalesalregistrodeac6vacióndelafunciónprincipal(C,C++).De esta manera, las variables globales ylasvariableslocalesdelprogramaprincipalpasan a estar almacenadas en el registrode ac6vación de la función principal,alojadaenlamemorialibre

Zonadecódigo

Zonadedatosestáticos

Memorialibre

Montículo

PROGRAMcribaEratostenes;CONSTMAX=200;TYPETVector=ARRAY[1..MAX]OFInteger;VARp:TVector;PROCEDUREgCandidatos(VARc:TVector;n:Integer);VARi:Integer;BEGIN...END;FUNCTIONcPrimos(VARc:TVector;n,d:Integer;):^TVector;VARr:TVector;PROCEDUREcribar(VARc,r:TVector;n,d:Integer);VARi,j:Integer; BEGIN...END;BEGIN...cribar(c,r,n,d);cPrimos:=cPrimos(r,n,d+1);...END;

BEGINgCandidatos(p,100);p:=cPrimos(p,100,2);END.

Page 144: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 15

Ac6vacióndesubprogramas

Entornodeejecuciónestá8coEn los entornos de ejecución estáticos todas las activaciones de un mismo subprograma coinciden en memoria. Es decir, existe un único registro de activación por cada subprograma, incluido el programa principal (si es que éste no se incluye en la zona de datos estáticos). Esto permite conocer en tiempo de compilación cada direccionamiento pero imposibilita las activaciones recursivas

Organizacióndelamemoria

III. Memoria libre El siguiente espacio de memoria seconsidera libre. En el se almacenan losregistrosdeac6vacióndecadafunción.Eneste 6po de entornos existe un únicoregistro de ac6vación para cadasubprograma declarado en el códigofuente. Cada ac6vación de subprogramau6liza su registro de ac6vación paraalmacenarlosdatosnecesariosdurantesuejecución. El programa principal puededisponer de un registro de ac6vaciónpropioonotenerlo,yges6onartodossusdatosenlazonaestá6cadedatos.Avecesestazonaylaanteriorseentremezclanenunasola

Zonadecódigo

Zonadedatosestáticos

Memorialibre

Montículo

PROGRAMcribaEratostenes;CONSTMAX=200;TYPETVector=ARRAY[1..MAX]OFInteger;VARp:TVector;PROCEDUREgCandidatos(VARc:TVector;n:Integer);VARi:Integer;BEGIN...END;FUNCTIONcPrimos(VARc:TVector;n,d:Integer;):^TVector;VARr:TVector;PROCEDUREcribar(VARc,r:TVector;n,d:Integer);VARi,j:Integer; BEGIN...END;BEGIN...cribar(c,r,n,d);cPrimos:=cPrimos(r,n,d+1);...END;

BEGINgCandidatos(p,100);p:=cPrimos(p,100,2);END.

Page 145: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 16

Ac6vacióndesubprogramas

Entornodeejecuciónestá8coEn los entornos de ejecución estáticos todas las activaciones de un mismo subprograma coinciden en memoria. Es decir, existe un único registro de activación por cada subprograma, incluido el programa principal (si es que éste no se incluye en la zona de datos estáticos). Esto permite conocer en tiempo de compilación cada direccionamiento pero imposibilita las activaciones recursivas

Organizacióndelamemoria

IV. Montículo La úl6ma zona de datos de la memoriareservada al proceso se conoce con elnombredemonQculooheap.Estazonaseu6liza para ges6onar la reserva de datosdinámicos y también, en algunoscompiladores el paso por referenciaforzada de estructuras de datosdemasiado pesadas para pasar por valor.Loslenguajesdeorientaciónaobjetosporejemplo, u6lizan esta estrategia parapasar siempre por referencia los objetoscomoparámetros(vermásadelante)

Zonadecódigo

Zonadedatosestáticos

Memorialibre

Montículo

PROGRAMcribaEratostenes;CONSTMAX=200;TYPETVector=ARRAY[1..MAX]OFInteger;VARp:TVector;PROCEDUREgCandidatos(VARc:TVector;n:Integer);VARi:Integer;BEGIN...END;FUNCTIONcPrimos(VARc:TVector;n,d:Integer;):^TVector;VARr:TVector;PROCEDUREcribar(VARc,r:TVector;n,d:Integer);VARi,j:Integer; BEGIN...END;BEGIN...cribar(c,r,n,d);cPrimos:=cPrimos(r,n,d+1);...END;

BEGINgCandidatos(p,100);p:=cPrimos(p,100,2);END.

Page 146: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 17

Ac6vacióndesubprogramas

Entornodeejecuciónestá8co

Diseñodelregistrodeac8vación

En los entornos de ejecución estáticos todas las activaciones de un mismo subprograma coinciden en memoria. Es decir, existe un único registro de activación por cada subprograma, incluido el programa principal (si es que éste no se incluye en la zona de datos estáticos). Esto permite conocer en tiempo de compilación cada direccionamiento pero imposibilita las activaciones recursivas

Valorderetorno

Direcciónderetorno

Parámetrosactuales

Variableslocales

Variablestemporales

Estadodelamáquina

Nombre del campo Escritor Lector Descripción

Valor de retorno

Llamado

Llamante

En funciones, almacena el valor devuelto por la función tras la invocación

Dirección de retorno

llamante

llamado

Se establece la dirección de código a la que debe saltar el llamado tras su invocación

Parámetros actuales llamante llamado Proporciona los parámetros actuales

Estado de la máquina

Llamante

Llamado

Contiene el estado de la máquina (copia de los registros) antes de la llamada para restaurarlos tras su invocación

Variables locales llamado llamado Contiene el valor de las variables locales

Variables temporales llamado llamado Contiene el valor de las variables temporales

Page 147: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 18

Ac6vacióndesubprogramas

Entornodeejecuciónestá8co

Direcciónretorno

Parámetros

Variableslocales

Temporales

Valorretorno

Direcciónretorno

Parámetros

Variableslocales

Temporales

Direcciónretorno

Parámetros

Variableslocales

Temporales

Ejemplo

Se omite el estado de la máquina por simplicidad

gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

En los entornos de ejecución estáticos todas las activaciones de un mismo subprograma coinciden en memoria. Es decir, existe un único registro de activación por cada subprograma, incluido el programa principal (si es que éste no se incluye en la zona de datos estáticos). Esto permite conocer en tiempo de compilación cada direccionamiento pero imposibilita las activaciones recursivas

RAg

Cand

idat

os

RAc

riba

rRA

cPr

imos

Memorialibre

p=[1,…,10]

Datosestáticos

Page 148: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 19

Ac6vacióndesubprogramas

Entornodeejecuciónestá8co

Ejemplo

Se omite el estado de la máquina por simplicidad

En los entornos de ejecución estáticos todas las activaciones de un mismo subprograma coinciden en memoria. Es decir, existe un único registro de activación por cada subprograma, incluido el programa principal (si es que éste no se incluye en la zona de datos estáticos). Esto permite conocer en tiempo de compilación cada direccionamiento pero imposibilita las activaciones recursivas

gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes RAg

Cand

idat

os

RAc

riba

rRA

cPr

imos

Memorialibre

p=[1,…,10]

Datosestáticos

Page 149: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 20

Ac6vacióndesubprogramas

Entornodeejecuciónestá8co

[1]

p=[1…10]

i=10

temporales

Ejemplo

Se omite el estado de la máquina por simplicidad

En los entornos de ejecución estáticos todas las activaciones de un mismo subprograma coinciden en memoria. Es decir, existe un único registro de activación por cada subprograma, incluido el programa principal (si es que éste no se incluye en la zona de datos estáticos). Esto permite conocer en tiempo de compilación cada direccionamiento pero imposibilita las activaciones recursivas

gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes RAg

Cand

idat

os

RAc

riba

rRA

cPr

imos

Memorialibre

p=[1,…,10]

Datosestáticos

Page 150: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 21

Ac6vacióndesubprogramas

Entornodeejecuciónestá8co

[1]

p=[1…10]

i=10

<<temporales>>

?

[2]

c=[1…10]n=10,d=2

r=?

<<temporales>>

Ejemplo

Se omite el estado de la máquina por simplicidad

En los entornos de ejecución estáticos todas las activaciones de un mismo subprograma coinciden en memoria. Es decir, existe un único registro de activación por cada subprograma, incluido el programa principal (si es que éste no se incluye en la zona de datos estáticos). Esto permite conocer en tiempo de compilación cada direccionamiento pero imposibilita las activaciones recursivas

gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes RAg

Cand

idat

os

RAc

riba

rRA

cPr

imos

Memorialibre

p=[1,…,10]

Datosestáticos

Page 151: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 22

Ac6vacióndesubprogramas

Entornodeejecuciónestá8co

RAg

Cand

idat

os

RAc

riba

rRA

cPr

imos

Memorialibre

[1]

p=[1…10]

i=10

<<temporales>>

?

[2]

c=[1…10]n=10,d=2

r=?

<<temporales>>

[3]

c=[1…10],n=10r=[1,2,3,5,7,9],d=2

i=10,j=5

<<temporales>>

Ejemplo

Se omite el estado de la máquina por simplicidad

En los entornos de ejecución estáticos todas las activaciones de un mismo subprograma coinciden en memoria. Es decir, existe un único registro de activación por cada subprograma, incluido el programa principal (si es que éste no se incluye en la zona de datos estáticos). Esto permite conocer en tiempo de compilación cada direccionamiento pero imposibilita las activaciones recursivas

p=[1,…,10]

Datosestáticos

gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

Page 152: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 23

Ac6vacióndesubprogramas

Entornodeejecuciónestá8co

[1]

p=[1…10]

i=10

<<temporales>>

?

[4]

c=[1,2,3,5,7,9]n=10,d=3

r=?

<<temporales>>

[3]

c=[1…10],n=10r=[1,2,3,5,7,9],d=2

i=10,j=5

<<temporales>>

Ejemplo

Se omite el estado de la máquina por simplicidad

En los entornos de ejecución estáticos todas las activaciones de un mismo subprograma coinciden en memoria. Es decir, existe un único registro de activación por cada subprograma, incluido el programa principal (si es que éste no se incluye en la zona de datos estáticos). Esto permite conocer en tiempo de compilación cada direccionamiento pero imposibilita las activaciones recursivas

gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

Ventajas Inconvenientes I.   Sencillez de direccionamiento.

DisponerdeunRA porsubprogramasimplificaenormementelages6óndelentorno

II.   Direccionamiento está8co. Todas lasdirecciones de memoria pueden serconocidasen6empodecompilación

I.   No se soporta la recursividad. Lasac6vaciones recursivas no existen yaqueexisteunRAparacadafunciónyno para cada ac6vación en curso loque provoca que los datos sesobrescriban

RAg

Cand

idat

os

RAc

riba

rRA

cPr

imos

Memorialibre

p=[1,…,10]

Datosestáticos

Page 153: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 24

Ac6vacióndesubprogramas

Organizacióndelamemoria

I. Zona de código Lazonadecódigocomienzaenlaposición0.Allísealmacenalatraducciónenbinariodel programa. Cada función dispone deunae6quetaalcomienzodecuerpode lafunciónparaar6cularelsalto. Lospuntos[n] indican posiciones de retorno queserán proporcionadas al programallamante para que sepa la dirección a laquedeberetornar

EntornodeejecuciónbasadoenpilaEn los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Zonadecódigo

Zonadedatosestáticos

Piladememoria

Montículo

PROGRAMcribaEratostenes;CONSTMAX=200;TYPETVector=ARRAY[1..MAX]OFInteger;VARp:TVector;PROCEDUREgCandidatos(VARc:TVector;n:Integer);VARi:Integer;BEGIN...END;FUNCTIONcPrimos(VARc:TVector;n,d:Integer;):^TVector;VARr:TVector;PROCEDUREcribar(VARc,r:TVector;n,d:Integer);VARi,j:Integer; BEGIN...END;BEGIN...cribar(c,r,n,d);[3]cPrimos:=cPrimos(r,n,d+1);[4]...END;

BEGINgCandidatos(p,100);[1]p:=cPrimos(p,100,2);[2]END.

Page 154: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 25

Ac6vacióndesubprogramas

Organizacióndelamemoria

II. Zona de datos estáticos Lazonadedatosestá6cossiguealcódigo.Allí se ubican todas las variablesdeclaradas en el ámbito global delprograma.Avecesestazonaseomiteysemuevelasvariablesglobalesalregistrodeac6vacióndelafunciónprincipal(C,C++).De esta manera, las variables globales ylasvariableslocalesdelprogramaprincipalpasan a estar almacenadas en el registrode ac6vación de la función principal,alojadaenlamemorialibre

EntornodeejecuciónbasadoenpilaEn los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Zonadecódigo

Zonadedatosestáticos

Piladememoria

Montículo

PROGRAMcribaEratostenes;CONSTMAX=200;TYPETVector=ARRAY[1..MAX]OFInteger;VARp:TVector;PROCEDUREgCandidatos(VARc:TVector;n:Integer);VARi:Integer;BEGIN...END;FUNCTIONcPrimos(VARc:TVector;n,d:Integer;):^TVector;VARr:TVector;PROCEDUREcribar(VARc,r:TVector;n,d:Integer);VARi,j:Integer; BEGIN...END;BEGIN...cribar(c,r,n,d);cPrimos:=cPrimos(r,n,d+1);...END;

BEGINgCandidatos(p,100);p:=cPrimos(p,100,2);END.

Page 155: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 26

Ac6vacióndesubprogramas

Organizacióndelamemoria

III. Pila de memoria El siguiente espacio de memoria seges6onacomounapiladedatos.Lacimade la pila suele apuntarse en un registrogeneral de índice (IX, IY) o mediante unregistroespecificollamadopunterodepila(SP)opunterodemarco(FP).Lapilacrecehacia el monQculo según se va llenando.En ella se apilan los registros de cadaac6vación en curso. En este 6po deentornos existen un RA por cadaac6vación diferente. Esto obliga a hacerdireccionamiento rela6vo al SP peropermite ac6vaciones recursivas. ElprogramaprincipalpuededisponerdeunRAoresidirenlazonaestá6ca

EntornodeejecuciónbasadoenpilaEn los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Zonadecódigo

Zonadedatosestáticos

Piladememoria

Montículo

PROGRAMcribaEratostenes;CONSTMAX=200;TYPETVector=ARRAY[1..MAX]OFInteger;VARp:TVector;PROCEDUREgCandidatos(VARc:TVector;n:Integer);VARi:Integer;BEGIN...END;FUNCTIONcPrimos(VARc:TVector;n,d:Integer;):^TVector;VARr:TVector;PROCEDUREcribar(VARc,r:TVector;n,d:Integer);VARi,j:Integer; BEGIN...END;BEGIN...cribar(c,r,n,d);cPrimos:=cPrimos(r,n,d+1);...END;

BEGINgCandidatos(p,100);p:=cPrimos(p,100,2);END.

Page 156: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 27

Ac6vacióndesubprogramas

Organizacióndelamemoria

IV. Montículo La úl6ma zona de datos de la memoriareservada al proceso se conoce con elnombredemonQculooheap.Estazonaseu6liza para ges6onar la reserva de datosdinámicos y también, en algunoscompiladores el paso por referenciaforzada de estructuras de datosdemasiado pesadas para pasar por valor.Loslenguajesdeorientaciónaobjetosporejemplo, u6lizan esta estrategia parapasar siempre por referencia los objetoscomo parámetros. El monQculo crecedesde el final hacia la pila. Cuando see n c u e n t r a n s e p r o d u c e u ndesbordamientodepilaomonQculo

EntornodeejecuciónbasadoenpilaEn los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Zonadecódigo

Zonadedatosestáticos

Piladememoria

Montículo

PROGRAMcribaEratostenes;CONSTMAX=200;TYPETVector=ARRAY[1..MAX]OFInteger;VARp:TVector;PROCEDUREgCandidatos(VARc:TVector;n:Integer);VARi:Integer;BEGIN...END;FUNCTIONcPrimos(VARc:TVector;n,d:Integer;):^TVector;VARr:TVector;PROCEDUREcribar(VARc,r:TVector;n,d:Integer);VARi,j:Integer; BEGIN...END;BEGIN...cribar(c,r,n,d);cPrimos:=cPrimos(r,n,d+1);...END;

BEGINgCandidatos(p,100);p:=cPrimos(p,100,2);END.

Page 157: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 28

Ac6vacióndesubprogramas

EntornodeejecuciónbasadoenpilaEn los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Valorderetorno

Direcciónderetorno

Parámetrosactuales

Variableslocales

Variablestemporales

Estadodelamáquina

Nombre del campo Escritor Lector Descripción

Valor de retorno

Llamado

Llamante

En funciones, almacena el valor devuelto por la función tras la invocación

Dirección de retorno

llamante

llamado

Se establece la dirección de código a la que debe saltar el llamado tras su invocación

Parámetros actuales llamante llamado Proporciona los parámetros actuales

Estado de la máquina

Llamante

Llamado

Contiene el estado de la máquina (copia de los registros) antes de la llamada para restaurarlos tras su invocación

Variables locales llamado llamado Contiene el valor de las variables locales

Variables temporales llamado llamado Contiene el valor de las variables temporales

Enlacedecontrol

Enlace de control

Llamante

Llamado

Contiene un puntero al Registro de activación del subprograma llamante

Diseñodelregistrodeac8vación

Page 158: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 29

Ac6vacióndesubprogramas

Entornodeejecuciónbasadoenpila

Ejemplo

Se omite el estado de la máquina por simplicidad

En los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Piladememoria

p=[1,…,10]

Datosestáticos

gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

SP <<temporales>>

Page 159: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 30

Ac6vacióndesubprogramas

Entornodeejecuciónbasadoenpila

Ejemplo

Se omite el estado de la máquina por simplicidad

En los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Piladememoria

p=[1,…,10]

Datosestáticos

FP

RAg

Cand

idat

os[1]

<<EnlaceControl>>

p=[1…10]

i=10

<<temporales>>

SP

<<temporales>>

gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

Page 160: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 31

Ac6vacióndesubprogramas

Entornodeejecuciónbasadoenpila

Ejemplo

Se omite el estado de la máquina por simplicidad

En los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Piladememoria

p=[1,…,10]

Datosestáticos

FP

SP

<<temporales>>

RAc

Prim

os

?

[2]

<<EnlaceControl>>

c=[1…10]n=10,d=2

r=?

<<temporales>>gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

Page 161: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 32

Ac6vacióndesubprogramas

Entornodeejecuciónbasadoenpila

Ejemplo

Se omite el estado de la máquina por simplicidad

En los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Piladememoria

p=[1,…,10]

Datosestáticos

FP

SP

<<temporales>>

RAc

Prim

os

?

[2]

<<EnlaceControl>>

c=[1…10]n=10,d=2

r=?

<<temporales>>

RAc

riba

r

[3]

<<EnlaceControl>>

c=[1…10],n=10r=[1,2,3,5,7,9],d=2

i=10,j=5

<<temporales>>

gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

Page 162: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 33

Ac6vacióndesubprogramas

Entornodeejecuciónbasadoenpila

Ejemplo

Se omite el estado de la máquina por simplicidad

En los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Piladememoria

p=[1,…,10]

Datosestáticos

FP

SP

<<temporales>>

RAc

Prim

os

?

[2]

<<EnlaceControl>>

c=[1…10]n=10,d=2

r=?

<<temporales>>

RAc

Prim

os

?

[4]

<<EnlaceControl>>

c=[1,2,3,5,7,9]n=10,d=3

r=?

<<temporales>>

gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

Page 163: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 34

Ac6vacióndesubprogramas

Entornodeejecuciónbasadoenpila

Ejemplo

Se omite el estado de la máquina por simplicidad

En los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Piladememoria

FP

SP

RAc

Prim

os

?

[4]

<<EnlaceControl>>

c=[1,2,3,5,7,9]n=10,d=3

r=?

<<temporales>>

RAc

riba

r

[3]

<<EnlaceControl>>

c=[1,2,3,5,7,9],n=10,d=3r=[1,2,3,5,7]

i=10,j=3

<<temporales>>

gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

Page 164: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 35

Ac6vacióndesubprogramas

Entornodeejecuciónbasadoenpila

Ejemplo

Se omite el estado de la máquina por simplicidad

En los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Piladememoria

FP

SP

RAc

Prim

os

?

[4]

<<EnlaceControl>>

c=[1,2,3,5,7,9]n=10,d=3

r=?

<<temporales>>

RAc

Prim

os

^[1,2,3,5,7]

[4]

<<EnlaceControl>>

c=[1,2,3,5,7]n=10,d=4

r=[1,2,3,5,7]

<<temporales>>

gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

Page 165: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 36

Ac6vacióndesubprogramas

Entornodeejecuciónbasadoenpila

Ejemplo

Se omite el estado de la máquina por simplicidad

En los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Piladememoria

FP

SP

RAc

Prim

os

^[1,2,3,5,7]

[4]

<<EnlaceControl>>

c=[1,2,3,5,7,9]n=10,d=3

r=[1,2,3,5,7]

<<temporales>>

^[1,2,3,5,7]

[4]

<<EnlaceControl>>

c=[1,2,3,5,7]n=10,d=4

r=[1,2,3,5,7]

<<temporales>>

gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

Page 166: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 37

Ac6vacióndesubprogramas

Entornodeejecuciónbasadoenpila

Ejemplo

Se omite el estado de la máquina por simplicidad

En los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Piladememoria

FP

SP

RAc

Prim

os

^[1,2,3,5,7]

[4]

<<EnlaceControl>>

c=[1,2,3,5,7,9]n=10,d=3

r=[1,2,3,5,7]

<<temporales>>

^[1,2,3,5,7]

[4]

<<EnlaceControl>>

c=[1,2,3,5,7]n=10,d=4

r=[1,2,3,5,7]

<<temporales>>

Estepunteroapuntaaunazonadememorialibrequeenelfuturocontendráotrosdatos

sensiblesquenosonelresultado

}

gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

Ventajas I.   Soportealarecursividad.Aldisponer

de un RA diferente para ac6vacióndis6nta, se hace posible que existanvarias invocaciones en curso de unmismo subprograma lo que permitesoportarlarecursividad

I.   Complejidad de direccionamiento. Losdireccionamientos son rela6vos a FP y portanto no conocidos en 6empo decompilación

II.   Referencias suspendidas. Si una funcióndevuelve un puntero a una zona dememoria dentro de su RA, este punteroapuntaauna zona insegura trasfinalizar laac6vaciónyliberarseelRA.Ejemplo:

Inconvenientes

int*f(){intx;return&x;}

Page 167: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 38

Ac6vacióndesubprogramas

Organizacióndelamemoria

I. Zona de código Lazonadecódigocomienzaenlaposición0.Allísealmacenalatraducciónenbinariodel programa. Cada función dispone deunae6quetaalcomienzodecuerpode lafunciónparaar6cularelsalto. Lospuntos[n] indican posiciones de retorno queserán proporcionadas al programallamante para que sepa la dirección a laque debe retornar. En algunos lenguajescomoLisp,inclusoestazonaseubicaenelmonQculo lo que permite que el propioprogramasemodifiqueasimismoduranteel6empodeejecución

EntornodeejecucióndinámicoEn los entornos de compilación completamente dinámicos los datos de las activaciones son gestionados en una zona de memoria de reserva dinámica llamada montículo o heap. Esto permite que los datos puedan sobrevivir al tiempo de vida de la activación que los generó de manera que se evita el problema de las referencias suspendidas

Zonadecódigo

Montículo

PROGRAMcribaEratostenes;CONSTMAX=200;TYPETVector=ARRAY[1..MAX]OFInteger;VARp:TVector;PROCEDUREgCandidatos(VARc:TVector;n:Integer);VARi:Integer;BEGIN...END;FUNCTIONcPrimos(VARc:TVector;n,d:Integer;):^TVector;VARr:TVector;PROCEDUREcribar(VARc,r:TVector;n,d:Integer);VARi,j:Integer; BEGIN...END;BEGIN...cribar(c,r,n,d);[3]cPrimos:=cPrimos(r,n,d+1);[4]...END;

BEGINgCandidatos(p,100);[1]p:=cPrimos(p,100,2);[2]END.

Page 168: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 39

Ac6vacióndesubprogramas

Organizacióndelamemoria

II. Montículo E n l o s e n t o r n o s d e e j e c u c i ó ncompletamente dinámicos, el monQculono solamente se u6liza para reservarmemoria dinámica ges6onada porpunterossinoquetambiénseu6lizaparaalojar los registrosdecadaac6vación.Deesta forma, al finalizar la ac6vación, losdatosdelamismasiguenestandovigentespara el llamante. En estos escenarios seimplementan agentes encargados deliberarlamemoriacuandoyanadielosusaque se llaman recolectores debasura. Enjava por ejemplo, los parámetros a unmétodo se ges6onan de esta forma y elrecolector de basura libera el espacio enmemoriasolotrascomprobarqueningunavariable del programa apunta ya a eseobjetoyportantoresultainaccesible

EntornodeejecucióndinámicoEn los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

PROGRAMcribaEratostenes;CONSTMAX=200;TYPETVector=ARRAY[1..MAX]OFInteger;VARp:TVector;PROCEDUREgCandidatos(VARc:TVector;n:Integer);VARi:Integer;BEGIN...END;FUNCTIONcPrimos(VARc:TVector;n,d:Integer;):^TVector;VARr:TVector;PROCEDUREcribar(VARc,r:TVector;n,d:Integer);VARi,j:Integer; BEGIN...END;BEGIN...cribar(c,r,n,d);cPrimos:=cPrimos(r,n,d+1);...END;

BEGINgCandidatos(p,100);p:=cPrimos(p,100,2);END.

Zonadecódigo

Montículo

Page 169: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 40

Ac6vacióndesubprogramas

EntornodeejecucióndinámicoEn los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Valorderetorno

Direcciónderetorno

Parámetrosactuales

Variableslocales

Variablestemporales

Estadodelamáquina

Nombre del campo Escritor Lector Descripción

Valor de retorno

Llamado

Llamante

En funciones, almacena el valor devuelto por la función tras la invocación

Dirección de retorno

llamante

llamado

Se establece la dirección de código a la que debe saltar el llamado tras su invocación

Parámetros actuales llamante llamado Proporciona los parámetros actuales

Estado de la máquina

Llamante

Llamado

Contiene el estado de la máquina (copia de los registros) antes de la llamada para restaurarlos tras su invocación

Variables locales llamado llamado Contiene el valor de las variables locales

Variables temporales llamado llamado Contiene el valor de las variables temporales

Enlacedecontrol

Enlace de control

Llamante

Llamado

Contiene un puntero al Registro de activación del subprograma llamante

Diseñodelregistrodeac8vación

El registro de acAvación es idénAco al de los entornos basados en pila. Ladiferenciaresideenellugardealojamientodelosmismos,suAempodevidaylaspolíAcasdeliberacióndememoriaimplementadasenelmonQculo

}

Page 170: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 41

Ac6vacióndesubprogramas

Entornodeejecucióndinámicos

Ejemplo

Se omite Los campos de registros por ser similar al caso anterior

En los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Montículo

p=[1,…,10]

Datosestáticos

gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

RAcribaEratostene

Page 171: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 42

Ac6vacióndesubprogramas

Entornodeejecucióndinámicos

Ejemplo

Se omite Los campos de registros por ser similar al caso anterior

En los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Montículo

p=[1,…,10]

Datosestáticos

RAcribaEratostene

RAgCandidatos

gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

Page 172: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 43

Ac6vacióndesubprogramas

Entornodeejecucióndinámicos

Ejemplo

Se omite Los campos de registros por ser similar al caso anterior

En los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Montículo

p=[1,…,10]

Datosestáticos

RAcribaEratostene

RAgCandidatos

RAcPrimos

Como no hay variables referenciandoningún dato de este RA el gestor dememoria lo señala para reuAlizar esteespaciosiesnecesario

} û

gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

Page 173: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 44

Ac6vacióndesubprogramas

Entornodeejecucióndinámicos

Ejemplo

Se omite Los campos de registros por ser similar al caso anterior

En los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Montículo

p=[1,…,10]

Datosestáticos

RAcribaEratostene

RAgCandidatos

RAcPrimos

û

RAcribar

gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

Page 174: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 45

Ac6vacióndesubprogramas

Entornodeejecucióndinámicos

Ejemplo

Se omite Los campos de registros por ser similar al caso anterior

En los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Montículo

p=[1,…,10]

Datosestáticos

RAcribaEratostene

RAgCandidatos

RAcPrimos

û

RAcribar

RAcPrimos

û Como no hay variables referenciandoningún dato de este RA el gestor dememoria lo señala para reuAlizar esteespaciosiesnecesario

}

gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

Page 175: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 46

Ac6vacióndesubprogramas

Entornodeejecucióndinámicos

Ejemplo

Se omite Los campos de registros por ser similar al caso anterior

En los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Montículo

p=[1,…,10]

Datosestáticos

RAcribaEratostene

RAgCandidatos

RAcPrimos

û

RAcribar

RAcPrimos

û

RAcribar

r

gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

Page 176: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 47

Ac6vacióndesubprogramas

Entornodeejecucióndinámicos

Ejemplo

Se omite Los campos de registros por ser similar al caso anterior

En los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Montículo

p=[1,…,10]

Datosestáticos

RAcribaEratostene

RAgCandidatos

RAcPrimos

û

RAcribar

RAcPrimos

û

RAcribarû RAcPrimos

r

r gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

Page 177: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 48

Ac6vacióndesubprogramas

Entornodeejecucióndinámicos

Ejemplo

Se omite Los campos de registros por ser similar al caso anterior

En los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Montículo

p=[1,…,10]

Datosestáticos

RAcribaEratostene

RAgCandidatos

RAcPrimos

û

RAcribar

RAcPrimos

û

RAcribarû RAcPrimos

r

r Como hay una referencia r desde el RAcPrimosanterior,elregistrodeacAvaciónreferidonoseliberadelamemoria

gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

Page 178: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 49

Ac6vacióndesubprogramas

Entornodeejecucióndinámicos

Ejemplo

Se omite Los campos de registros por ser similar al caso anterior

En los entornos de ejecución dinámicos, cada activación distinta dispone de un registro de activación propio, gestionado a través de una pila. Esto complica la gestión de memoria ya que no todos los enlaces de datos son conocidos en tiempo de compilación pero permite la articulación de activaciones recursivas

Montículo

p=[1,…,10]

Datosestáticos

RAcribaEratostene

RAgCandidatos

RAcPrimos

û

RAcribar

RAcPrimos

û

RAcribarû RAcPrimos

r

r Como hay una referencia r desde el RAcPrimosanterior,elregistrodeacAvaciónreferidonoseliberadelamemoria

gCandidatos([1,...10],10) cPrimos([1,...10],10,2):[1,2,3,5,7]

cribar([1,...10],[1,2,3,5,7,9],10,2) cPrimos([1,2,3,5,7,9],10,3):[1,2,3,5,7]

cribar([1,2,3,5,7,9],[1,2,3,5,7],10,3) cPrimos([1,2,3,5,7],4):[1,2,3,5,7]

cribaEratostenes

Ventajas I.   Soportealarecursividad.Aldisponer

de un RA diferente para ac6vacióndis6nta, se hace posible que existanvarias invocaciones en curso de unmismo subprograma lo que permitesoportarlarecursividad

II.   Soporteareferenciassuspendidas.Seevita la aparición de referenciassuspendidas ya que los RA persistenen el monQculo más allá del 6empode ac6vación del subprograma,mientrassenecesitensusdatos

I.   Complejidad de direccionamiento. Losdireccionamientos son rela6vos a puteroscomo ocurre en los escenarios basados enpilaconloquenopuedenserconocidosen6empodecompilación

II.   Complejidad en la ges8ón dememoria. Escomplicado idear algoritmos eficaces yeficientes para la recolección de basura. Elproblema de se centra en 3 aspectos: 1)sabercuándoconvieneac6varel recolectordebasura,2)reconocerlabasuray3)lucharcontralafragmentacióndelmonQculo

Inconvenientes

Page 179: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 50

Enlacesdenombres

EnlacesdenombresComo se ha visto en la sección anterior, la gestión de las activaciones de subprogramas no solamente trata con la gestión de la memoria, en distintos tipos de entornos, para articular la ejecución de los mismos sino también con idear una estrategia para asociar cada nombre simbólico del código fuente – variables globales, locales, parámetros y temporales – a una posición conocida de memoria. A este proceso se le conoce con el nombre de enlace de nombres

El enlace de nombres es el proceso que tiene lugar durante la activación de

un subprograma mediante el cual se asigna una posición de memoria física

real a cada objeto de datos del programa compilado – variables, parámetros y

temporales

Objeto de datos Espacio en memoria Valor

Variables globales

p

Variables locales

i,j,...

Parámetros

n,d,...

Variables globales

/1000

Variables locales

#15[.FP],#16[.FP],...

Parámetros

#20[.FP],#21[.FP],...

Losdireccionamientossolosonejemplosynocorrespondenaunanálisisdetallado

Variables globales

/1000

Variables locales

10,5,...

Parámetros

10,3,...

Enlace de datos Estado en ejecución

Page 180: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 51

Enlacesdenombres

Enlacesdenombresy8posdeentornosdeejecuciónEl tipo de entorno de ejecución que se implante para la activación de subprogramas condiciona directamente la naturaleza de los enlaces de datos. En efecto, el soporte a la recurrencia por parte del entorno determina la cardinalidad de los enlaces. En entornos sin soporte cada nombre de datos en código dispone de un único espacio en memoria. En entornos con soporte a la recurrencia sin embargo cada nombre puede referenciar en memoria varios espacios en memoria

FUNCTIONcPrimos(VARc:TVector;n,d:Integer;):^TVector;VARr:TVector;PROCEDUREcribar(VARc,r:TVector;n,d:Integer);VARi,j:Integer; BEGIN...END;BEGIN...cribar(c,r,n,d);cPrimos:=cPrimos(r,n,d+1);...END;

Piladememoria

SP

<<temporales>>

RAc

Prim

os

?

[2]

<<EnlaceControl>>

c=[1…10]n=10,d=2

r=?

<<temporales>>

RAc

Prim

os

?

[4]

<<EnlaceControl>>

c=[1,3,5,7,9]n=10,d=3

r=?

<<temporales>>

2. En un entorno de ejecución basados en pila elnombre d, referencia dos espacios de memoriaubicados en registros de acAvación diferentes quealmacenanvaloresdisAntos

¿Cuántos enlaces de datos manAene el parámetro ddurantelaacAvacióncPrimos([1,3,5,7,9],10,3):[1,5,7]?

Pregunta:

Respuesta:

Page 181: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 52

Enlacesdenombres

MecanismosdepasodeparámetrosAnteriormente se ha visto cómo los parámetros son enlazados a espacios de memoria dentro de los registros de activación de cada subprograma. Sin embargo no se ha discutido cómo se mantiene la relación entre cada parámetro formal y su correspondiente argumento actual. En esta sección presentamos 3 mecanismos para llevar esto a cabo. Asumiremos en adelante un entorno basado en pila

Mecanismosdepasodeparámetros

I.Pasodeparámetrosporvalor(entrada)

II.Pasodeparámetrosporreferencia(salidaoentrada/salida)

Enelpasodeparámetrosporvalor,alac6varelsubprogramaserealizaunacopiadesdelaposicióndememoriadonderesideelargumentoactual(RAdelllamante)aunaposiciónenelRAdelllamado.Durantelaac6vaciónsetrabajaconestacopia.Alfinalizarlamismanose copia el valor el valor en el RA del llamado al RA del llamante con lo que, tras laac6vación,elvalordelargumentonoseveafectado

Enelpasodeparámetrosporreferencia,alac6varelsubprogramasecopiaenelRAdelllamadounpunterohacia ladireccióndememoriadonderesideelargumentoactual(RAdelllamante).Durantelaac6vaciónsetrabajaconestepunteroresolviendoencadaaccesola indirección.Como resultado, al finalizar lamismaelRAdel llamante con6eneel valormodificadodelargumentoactual

III.Pasodeparámetrosporcopia–referencia(salidaoentrada/salida)

Enelpasodeparámetrosporcopia–referencia,seprocededeformasimilaralpaso porvalor. El argumento actual se copia desde el RA del llamante a un espacio en el RA delllamado Durante la ac6vación se trabaja con esta copia. Al finalizar está el valoralmacenadoenelespacioreservadoparaelparámetroenelRAdelllamadodecopiaalRAdonderesideelargumentoactualenelllamanteconloqueéstesevemodificado

Page 182: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 53

Enlacesdenombres

PasodeparámetrosporvalorEn el paso de parámetros por valor, al activar el subprograma se realiza una copia desde la posición de memoria donde reside el argumento actual (RA del llamante) a una posición en el RA del llamado. Durante la activación se trabaja con esta copia. Al finalizar la misma no se copia el valor el valor en el RA del llamado al RA del llamante con lo que, tras la activación, el valor del argumento no se ve afectado

cPrimos([1,...10],10,2):[1,5,7]

cPrimos([1,3,5,7,9],10,3):[1,5,7]

...,n=10,d=3

FUNCTIONcPrimos(VARc:TVector;n,d:Integer;):^TVector;VARr:TVector;PROCEDUREcribar(VARc,r:TVector;n,d:Integer);VARi,j:Integer; BEGIN...END;BEGIN...cribar(c,r,n,d);cPrimos:=cPrimos(r,n,d+1);...END;

Piladememoria

SP

<<temporales>>

?

[2]

<<EnlaceControl>>

c=[1…10]n=10,d=2

r=?

t5=d+1=3

RAcPrimos

?

[4]

<<EnlaceControl>>

c=[1,3,5,7,9]n=10,d=3

r=?

<<temporales>>

Copi

arn

RAcPrimos

Copiart5endSe copian los argumentos actuales en elespacioreservadoenelRAencursoparacada parámetro formal. Durante laacAvación se uAlizan estas posiciones dememoria

}

Page 183: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 54

Enlacesdenombres

PasodeparámetrosporreferenciaEn el paso de parámetros por referencia, al activar el subprograma se copia en el RA del llamado un puntero hacia la dirección de memoria donde reside el argumento actual (RA del llamante). Durante la activación se trabaja con este puntero resolviendo en cada acceso la indirección. Como resultado, al finalizar la misma el RA del llamante contiene el valor modificado del argumento actual

cPrimos([1,...10],10,2):[1,5,7]

cPrimos([1,3,5,7,9],10,3):[1,5,7]

...,n=10,d=3

FUNCTIONcPrimos(VARc:TVector;VARn,d:Integer;):^TVector;VARr:TVector;PROCEDUREcribar(VARc,r:TVector;n,d:Integer);VARi,j:Integer; BEGIN...END;BEGIN...cribar(c,r,n,d);cPrimos:=cPrimos(r,n,d+1);...END;

Piladememoria

SP

<<temporales>>

?

[2]

<<EnlaceControl>>

c=[1…10]n=10,d=2

r=?

t5=d+1=3

RAcPrimos

Refe

renc

iaa

n

RAcPrimos

Referenciaat5Se copian referencias a los argumentosactualesenelespacioreservadoenelRAen curso para cada parámetro formal.Durante la acAvación se resuelven lasindirecciones para acceder al RA delllamante

?

[4]

<<EnlaceControl>>

c=[1,3,5,7,9]n=^n,d=^t5

r=?

<<temporales>>

}

ParaesteejemploforzaremospasoporreferenciaaunquesemánAcamenteresulteinválido

Page 184: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 55

Enlacesdenombres

Pasodeparámetrosporcopia–valorEn el paso de parámetros por valor – copia, se procede de forma similar al paso por valor. El argumento actual se copia desde el RA del llamante a un espacio en el RA del llamado Durante la activación se trabaja con esta copia. Al finalizar está el valor almacenado en el espacio reservado para el parámetro en el RA del llamado de copia al RA donde reside el argumento actual en el llamante con lo que éste se ve modificado

cPrimos([1,...10],10,2):[1,5,7]

cPrimos([1,3,5,7,9],10,3):[1,5,7]

...,n=10,d=3

FUNCTIONcPrimos(VARc:TVector;VARn,d:Integer;):^TVector;VARr:TVector;PROCEDUREcribar(VARc,r:TVector;n,d:Integer);VARi,j:Integer; BEGIN...END;BEGIN...cribar(c,r,n,d);cPrimos:=cPrimos(r,n,d+1);...END;

Piladememoria

SP

<<temporales>>

?

[2]

<<EnlaceControl>>

c=[1…10]n=10,d=2

r=?

t5=d+1=3

RAcPrimos

RAcPrimos

Secopianlosargumentosactualesenelespacio reservado en el RA en cursoparacadaparámetroformal.DurantelaacAvaciónseuAlizanestasposicionesdememorias

?

[4]

<<EnlaceControl>>

c=[1,3,5,7,9]n=10,d=3

r=?

<<temporales>>

} I.Fasedecopia

II.FasedecopiaTras la acAvación se copian los valoresal RA del llamante para que surtanefectolasmodificaciones

Copi

arn

Co

piar

n Copiart5end

Copiardent5Paraesteejemploforzaremospasoporreferencia

aunquesemánAcamenteresulteinválido

Page 185: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 56

Enlacesdenombres

Accesoadatosen8empodeejecuciónComo hemos visto, los datos de un programa fuente se distribuyen en memoria de acuerdo al tipo de entorno de ejecución que se implante. Desde esta perspectiva, en un programa de estructura de bloques con capacidad de declaración anidada de subprogramas puedes distinguirse tres tipos de referencias a elementos de datos

I. Referencias globales

Las referencias globales 6enen un direccionamiento absoluto que apunta alárea está6ca de datos donde residen y son fácilmente accesibles desdecualquier ámbito del programa. Desde el ámbito A11 – y por tanto desdecualquieradesusRA–gesunareferenciaglobalalavariableg

PROGRAMP;VARg:INTEGER;PROCEDUREAVARn:INTEGER;PROCEDUREA1PROCEDUREA11VARl:INTEGER;BEGINg:=1;l:=2;n:=3END;PROCEDUREA12BEGIN;A11;END;BEGINA12;END;PROCEDUREA2BEGINA1;END;PROCEDUREA3BEGINA2;END;BEGINA3;END;BEGINA;END;

II. Referencias locales

Lasreferenciaslocalessealojanenelregistrosdeac6vacióndelsubprogramadonde están declarados. Para acceder a estos datos se u6liza undireccionamiento rela6vo al puntero demarco (FP) que apunta al RAdondereside el dato. Desde el ámbito A11, la referencia l es local y apunta a lavariablelocall.

II. Referencias no locales

Enprogramasconestructuradebloquesanidados(Pascal,Modula-2,Ada),lasreferenciasno localesserefierenavariables localesaalgúnámbitoaccesibledesde los RA de los hijos según la regla de anidamiento del ámbito máscercano.EnA11,lareferencianesnolocalyaqueestádefinidalocalmenteenelámbitoA,accesibledesdeéste

Page 186: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 57

Enlacesdenombres

ReferenciasglobalesLas referencias globales tienen un direccionamiento absoluto que apunta al área estática de datos donde residen y son fácilmente accesibles desde cualquier ámbito del programa. Desde el ámbito A11 – y por tanto desde cualquiera de sus RA – g es una referencia global a la variable g

Piladememoria

RAP

<<EnlaceControl>>

g

Datosestáticos

RAA

<<EnlaceControl>>

n

RAA3

<<EnlaceControl>>

RAA1

<<EnlaceControl>>

RAA12

<<EnlaceControl>>

PROGRAMP;VARg:INTEGER;PROCEDUREAVARn:INTEGER;PROCEDUREA1PROCEDUREA11VARl:INTEGER;BEGINg:=1;l:=2;n:=3END;PROCEDUREA12BEGIN;A11;END;BEGINA12;END;PROCEDUREA2BEGINA1;END;PROCEDUREA3BEGINA2;END;BEGIN...

RAA11

<<EnlaceControl>>

l

Dire

ccio

nami

ento

ab

solu

to

La variable global g pretende referenciarse desde el ámbito (RA) del subprograma A11. En este caso la dirección de memoria es absoluta y conocida en tiempo de compilación con lo que e l d i r ecc i onam ien to se r ea l i za referenciando en el código final la dirección de memoria donde reside g. E s t e m o d o d e d i r e c c i o n a m i e n t o e s exactamente el mismo para todos los datos estáticos independientemente del ámbito (RA) desde el cual se produzca la referencia. Suponiendo que g resida en la posición 1000 de memoria la instrucción será del estilo:

}

MOVE/1000#1

RAA2

<<EnlaceControl>>

Page 187: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 58

Enlacesdenombres

ReferenciaslocalesLas referencias locales se alojan en el registros de activación del subprograma donde están declarados. Para acceder a estos datos se utiliza un direccionamiento relativo al puntero de marco (FP) que apunta al RA donde reside el dato. Desde el ámbito A11, la referencia l es local y apunta a la variable local l

PROGRAMP;VARg:INTEGER;PROCEDUREAVARn:INTEGER;PROCEDUREA1PROCEDUREA11VARl:INTEGER;BEGINg:=1;l:=2;n:=3END;PROCEDUREA12BEGIN;A11;END;BEGINA12;END;PROCEDUREA2BEGINA1;END;PROCEDUREA3BEGINA2;END;BEGIN...

Dire

ccio

nami

ento

re

lati

vo

La variable local l pretende referenciarse desde el mismo ámbito (RA) del subprograma A11 donde ha sido declarada. En este caso la dirección de memoria es relativa al puntero de marco (FP) y por tanto no es conocida en tiempo de compilación con lo que el direccionamiento se realiza referenciando en el código final el desplazamiento relativo sobre FP donde se encuentra el dato dentro del RA de A11. Este modo de direccionamiento es exactamente el mismo para todos variables locales, parámetros y temporales que se encuentran alojados en el RA del subprograma en curso (A11). Suponiendo que l tenga un desplazamiento 2 con respecto a FP la instrucción será del estilo:

}

MOVE#2[.FP]#1

Piladememoria

RAP

<<EnlaceControl>>

g

Datosestáticos

RAA

<<EnlaceControl>>

n

RAA3

<<EnlaceControl>>

RAA1

<<EnlaceControl>>

RAA12

<<EnlaceControl>>

RAA11

<<EnlaceControl>>

l

RAA2

<<EnlaceControl>>

Page 188: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 59

Enlacesdenombres

ReferenciasnolocalesEn programas con estructura de bloques anidados (Pascal, Modula-2, Ada), las referencias no locales se refieren a variables locales a algún ámbito accesible desde los RA de los hijos según la regla de anidamiento del ámbito más cercano. En A11, la referencia n es no local ya que está definida localmente en el ámbito A, accesible desde éste

PROGRAMP;VARg:INTEGER;PROCEDUREAVARn:INTEGER;PROCEDUREA1PROCEDUREA11VARl:INTEGER;BEGINg:=1;l:=2;n:=3END;PROCEDUREA12BEGIN;A11;END;BEGINA12;END;PROCEDUREA2BEGINA1;END;PROCEDUREA3BEGINA2;END;BEGIN...

La variable local n, declarada en el ámbito (RA) A pretende referenciarse desde el ámbito (RA) A11. En este caso ha de buscarse la dirección de memoria donde ésta reside partiendo desde el RA de A11 hasta encontrarla recorriendo hacia atrás todos los RA de los ámbitos actualmente activos (A11, A1, A, P). Para ello, necesitamos rediseñar la estructura de los registros con un nuevo enlace que mantenga la estructura de anidamiento para realizar la búsqueda. A ese enlace se le llama enlace de acceso

}

Piladememoria

RAP

Control Acceso

g

Datosestáticos

RAA

Control Acceso

n

RAA3

Control Acceso

RAA1

Control Acceso

RAA12

Control Acceso

RAA11

Control Acceso

l

RAA2

Control Acceso

Page 189: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 60

Enlacesdenombres

ReferenciasnolocalesEn programas con estructura de bloques anidados (Pascal, Modula-2, Ada), las referencias no locales se refieren a variables locales a algún ámbito accesible desde los RA de los hijos según la regla de anidamiento del ámbito más cercano. En A11, la referencia n es no local ya que está definida localmente en el ámbito A, accesible desde éste

Piladememoria

RAP

Control Acceso

g

Datosestáticos

RAA

Control Acceso

n

RAA3

Control Acceso

RAA1

Control Acceso

RAA12

Control Acceso

RAA11

Control Acceso

l

RAA2

Control Acceso

Nombre del campo Escritor Lector Descripción

Valor de retorno

Llamado

Llamante

En funciones, almacena el valor devuelto por la función tras la invocación

Dirección de retorno

llamante

llamado

Se establece la dirección de código a la que debe saltar el llamado tras su invocación

Parámetros actuales llamante llamado Proporciona los parámetros actuales

Estado de la máquina

Llamante

Llamado

Contiene el estado de la máquina (copia de los registros) antes de la llamada para restaurarlos tras su invocación

Variables locales llamado llamado Contiene el valor de las variables locales

Variables temporales llamado llamado Contiene el valor de las variables temporales

Enlace de control

Llamante

Llamado

Contiene un puntero al Registro de activación del subprograma llamante

Diseñodelregistrodeac8vación

Enlace de acceso

Llamante

Llamado

Contiene un puntero al Registro de activación del subprograma anidante (padre)

Page 190: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 61

Enlacesdenombres

ReferenciasnolocalesEn programas con estructura de bloques anidados (Pascal, Modula-2, Ada), las referencias no locales se refieren a variables locales a algún ámbito accesible desde los RA de los hijos según la regla de anidamiento del ámbito más cercano. En A11, la referencia n es no local ya que está definida localmente en el ámbito A, accesible desde éste

Piladememoria

RAP

Control Acceso

g

Datosestáticos

RAA

Control Acceso

n

RAA3

Control Acceso

RAA1

Control Acceso

RAA12

Control Acceso

RAA11

Control Acceso

l

RAA2

Control Acceso

TécnicaI.EncadenamientodeaccesosPROGRAMP;VARg:INTEGER;PROCEDUREAVARn:INTEGER;PROCEDUREA1PROCEDUREA11VARl:INTEGER;BEGINg:=1;l:=2;n:=3END;PROCEDUREA12BEGIN;A11;END;BEGINA12;END;PROCEDUREA2BEGINA1;END;PROCEDUREA3BEGINA2;END;BEGIN...

� Una vez establecida una nueva cadena de enlaces de acceso para marcar la relación de anidamiento de cada RA, puede recorrerse ésta hacia atrás para encontrar la referencia buscada. Conocidos los niveles de ámbito de la referencia y la declaración, su diferencia marcan el numero de saltos hacia atrás que hay que producir. A esta técnica se le conoce como encadenamiento de accesos

Numerodesaltos=�-�

Page 191: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 62

Enlacesdenombres

ReferenciasnolocalesEn programas con estructura de bloques anidados (Pascal, Modula-2, Ada), las referencias no locales se refieren a variables locales a algún ámbito accesible desde los RA de los hijos según la regla de anidamiento del ámbito más cercano. En A11, la referencia n es no local ya que está definida localmente en el ámbito A, accesible desde éste

Piladememoria

RAP

Control Acceso

g

Datosestáticos

RAA

Control Acceso

n

RAA3

Control Acceso

RAA1

Control Acceso

RAA12

Control Acceso

RAA11

Control Acceso

l

RAA2

Control Acceso

TécnicaII.DisplayPROGRAMP;VARg:INTEGER;PROCEDUREAVARn:INTEGER;PROCEDUREA1PROCEDUREA11VARl:INTEGER;BEGINg:=1;l:=2;n:=3END;PROCEDUREA12BEGIN;A11;END;BEGINA12;END;PROCEDUREA2BEGINA1;END;PROCEDUREA3BEGINA2;END;BEGIN...

� El problema del encadenamiento de accesos es que se pueden llegar a generar demasiados saltos. La técnica del display consiste en mantener en todo momento en memoria un vector con el valor de los enlaces de acceso para cada nivel de anidamiento. Es decir, display [i] = FP del ámbito i. Ahora acceder a n, consiste en consultar display [n]. Cada vez que se crear un RA se apunta en el display el valor del FP. El espacio de EC en el RA se utiliza para salvaguardar el valor antiguo y restaurarlo tras la activación

A A1 A12

3 4 5

A A1 A12

3 4 5

A A1 A11

3 4 5 Antes Durante Después

RAA11

Control A12

Page 192: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 63

Ac6vacióndesubprogramasenlaprác6ca

Ac8vacióndesubprogramasDesde un punto de vista práctico la activación de subprogramas se articula en 2 puntos dentro de la gramática. Durante la invocación se articula la secuencia de llamada y durante el retorno, la secuencia de retorno. A continuación describimos cada uno de los pasos que deben realizar estas secuencias

Entornoestá6co

Secuenciadellamada Secuenciaderetorno

Entornode

pila

EndeclaraciónreservarespacioparaRARealizarcomprobacionessemán6casVolcarcódigoparaevaluarlasexpresionesdeparámetrosAlmacenarPCenladirecciónderetornodelRAAlmacenarregistrodeestadoenelRAAlmacenarparámetrosenelRAInicializara0cadavariablelocalInicializara0cadavariabletemporalGenerarinstruccióndesaltoincondicional

SiesfunciónalmacenarvalorderetornoenRASiesprocedimientoalmacenarvalorderetornopordefectoRestaurarinformaciónenelregistrodeestadoRestablecerPCconladirecciónderetornoGenerarinstruccióndesaltoincondicional

CrearunnuevoRAenlapilatamañoRealizarcomprobacionessemán6casVolcarcódigoparaevaluarlasexpresionesdeparámetrosAlmacenarPCenladirecciónderetornodelRAAlmacenarregistrodeestadoenelRAAlmacenarparámetrosenelRAInicializara0cadavariablelocalInicializara0cadavariabletemporalGenerarinstruccióndesaltoincondicional

SiesfunciónalmacenarvalorderetornoenRASiesprocedimientoalmacenarvalorderetornopordefectoRestaurarinformaciónenelregistrodeestadoRestablecerPCconladirecciónderetornoDestruirelRAdelllamadoGenerarinstruccióndesaltoincondicional

fCall::=ID:idPIpActuales:paPD sentenciaAsignación::=referencia:rIGUALexp:ePYC

}

Focodeatención

Page 193: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 64

Ac6vacióndesubprogramasenlaprác6ca

SecuenciadellamadaDesde un punto de vista práctico la activación de subprogramas se articula en 2 puntos dentro de la gramática. Durante la invocación se articula la secuencia de llamada y durante el retorno, la secuencia de retorno. A continuación describimos el esquema de traducción

SecuenciadellamadafCall::=ID:idPIpActuales:paPD{:

Stringname=id.getLexema();

<<comprobacióndetipos>>

SymbolIFs=scopeManager.searchSymbol(name);

if(sinstanceofSymbolFunction){

SymbolFunctionsf=(SymbolFunction)s;

List<TypeIF>fParams=tF.getParameters();

IntermediateCodeBuildercb=new…Builder(scope);

cb.addQuadruples(pa.getCode());

Variablef=newVariable(name,scope);

cb.addQuadruple(“CALL”,f);

}elsesemanticErrorManager.semanticError(...);

:}

Lasecuenciadellamadamenoselpasodeparámetrosseencapsula en CALL f puesto que es dependiente delentorno. El tamaño del RA es calculado a parAr delnúmero de v. locales, temporales y parámetros que sonconocidosconsultandoSymbolFuncion/SymbolProcedure

}

pActuales::=pActuales:paCOMAexp:e{:

pa.addParameterType(e.getType());

IntermediateCodeBuildercb=new…Builder(scope);

cb.addQuadruples(pa.getCode());

cb.addQuadruple(e.getCode());

cb.addQuadruple(“PARAM”,e.getTemporal());

pa.setCode(cb.create());

RESULT=pa;

:}

|exp:e{:

TypeIFtype=e.getType();

IntermediateCodeBuildercb=new…Builder(scope);

cb.addQuadruples(e.getCode());

cb.addQuadruple(“PARAM”,e.getTemporal());

RESULT=newPActuales(type,cb.create());:};

Primero, por cada parámetro actual se vuelca el códigointermedio que lo evalúa y se incluye una cuádruplaPARAMparacargarloenlacimadelapilacomopartedelnuevoRAquesevaaconstruir

}

Page 194: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 65

Ac6vacióndesubprogramasenlaprác6ca

SecuenciaderetornoDesde un punto de vista práctico la activación de subprogramas se articula en 2 puntos dentro de la gramática. Durante la invocación se articula la secuencia de llamada y durante el retorno, la secuencia de retorno. A continuación describimos el esquema de traducción

SecuenciaderetornosentenciaAsignacion::=referencia:rIGUALexp:e{:

SentenciaAsignacionsa=newAsignación();

<<comprobaciónsemántica>>

if(rTypeinstanceofTypeFunction||

rTypeinstanceofTypeProcedure){

<<comprobaciónsemántica>>

IntermediateCodeBuildercb=new…Builder(scope);

TemporalIFeTemp=e.getTemporal();

List<QuadrupleIF>eCode=e.getCode();

cb.addQuadruples(eCode);

cb.addQuadruple(“RET”,eTemp)

sa.setCode(cb.create());

}

else<<generaciónasignaciónnormal>>

...

RESULT=sa;

:}

En lenguajes esAlo PASCAL como el que estamosuAlizando este curso para ilustrar la construcción decompiladores el retorno del subprograma se expresamedianteuna sentenciadeasignación cuya referenciaala izquierda del igual coincide con el nombre delsubprograma.Poresoelretornodebediferenciarsedelaasignación normal mediante una construccióncondicional.Otros lenguajes (C/C++, Java,…)uAlizarunaconstrucción gramaAcal propia para realizar el retorno(sentenciareturn)

}

Aligualqueanteselretornodelafunciónrequieretratarcon elementos propios del entorno de ejecución y portanto la secuencia de retorno se encapsula en lainstrucción RET para que se realice en la fase detraducciónacódigofinal

}

Page 195: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 66

Ac6vacióndesubprogramasenlaprác6ca

1.  Determinación del entorno de ejecución

1.  Modelo estático para lenguajes no recursivos

2.  Modelo basado en pila para lenguajes recursivos

3.  Modelo dinámico para lenguajes orientados a objetos

2.  Diseño del registro de activación

1.  Incluir Enlace de Control para entornos basados en pila o dinámicos

2.  Incluir enlace de acceso para lenguajes de bloques andantes

3.  Implementar secuencia de llamada y retorno

1.  En entornos estáticos el espacio para el RA se reserva 1 vez durante la declaración

2.  En entornos a pila o dinámicos se reserva un RA en la secuencia de llamada

3.  En entornos a pila o dinámicos se libera el RA en la secuencia de retorno

4.  Probar los resultados

1.  Invocar a IntermediateCodeFactory.create () desde la regla del axioma

2.  Observar el fichero .ens generado

DesarrollopasoapasoLa activación de subprogramas es, con seguridad, una de las tareas de traducción más complejas y elaboradas en la construcción de compiladores, especialmente para entornos de ejecución basados en pila y con referencias no locales. A continuación damos la secuencia de pasos a realizar

Page 196: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 67

Bibliograna

MaterialdeestudioBibliografía básica

Construcción de compiladores: principios y práctica

Kenneth C. Louden International Thomson Editores,

2004 ISBN 970-686-299-4

Page 197: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigointermedio.Ac8vacióndesubprogramas

9 - 68

Bibliograna

MaterialdeestudioBibliografía complementaria

Compiladores: Principios, técnicas y herramientas.

Segunda Edición Aho, Lam, Sethi, Ullman

Addison – Wesley, Pearson Educación, México 2008

Diseño de compiladores. A. Garrido, J. Iñesta, F. Moreno

y J. Pérez. 2002. Edita Universidad de Alicante

Page 198: Procesadores de Lenguajes I

ProcesadoresdeLenguajesIngenieríaTécnicasuperiordeIngenieríaInformá8ca

DepartamentodeLenguajesySistemasinformá6cos

JavierVé[email protected]

DepartamentodeLenguajesYSistemasInformáAcosUNED

1 GeneracióndecódigofinalTraducciónacódigoobjeto0

Page 199: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 2

Obje6vos

Obje8vos

›  Entender la relación de proximidad entre código intermedio y código objeto

›  Entender en qué consiste el proceso de generación de código final

›  Aprender los pasos que es necesario dar para llevarlo cabo con éxito

›  Entender las implicaciones del entorno de ejecución en el proceso

›  Tipo de arquitectura de ejecución y juego de instrucciones

›  Mapa de memoria y modos de direccionamiento

›  Conocer los diferentes tipo de arquitectura de ejecución que existen

›  Conocer los diferentes modos de direccionamiento que existen

›  Aprender a implementar un generador de código objetos eficaz

›  Aprender a separar los aspectos dependientes e independientes del entorno

›  Adquirir una visión crítica acerca del proceso de construcción de generadores de código

›  Advertir la naturaleza potencialmente ineficiente del proceso de generación de código

›  Motivar y justificar el estudio de técnicas de optimización de código

Page 200: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 3

Índice

Índice

›  Introducción

›  Resolución de referencias simbólicas

›  Modos de direccionamiento

›  Modos de direccionamiento & entornos de ejecución

›  Traducción al juego de instrucciones

›  Máquinas a pila

›  Máquinas con registro acumulador

›  Máquinas con código de tercetos

›  Máquinas con código de cuartetos

›  Generación de código final en la práctica

›  Bibliografía

Page 201: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 4

Introducción

Generacióndecódigofinal

El generador de código intermedio toma una a una las instrucciones de código intermedio y las traduce a código ejecutable

Foco de atención

Generacióndecódigofinal

MVat1MVbt2GRTt3t1t2BRZt3L1…

0000001100000011010000010100000000010010…

La fase de generación de código final tiene por objeto traducir la secuencia de instrucciones de código intermedio en una colección de instrucciones ejecutables y direccionables en una arquitectura física específica. Las condiciones arquitectónicas del entorno de ejecución van a condicionar considerablemente este proceso de traducción

Los lenguaje de código intermedio utilizado conviene que se acerquen estructuralmente lo máximo posible a l j u e g o d e instrucciones de la arqui tectura final para que el p r o c e s o d e traducción sea lo m á s d i r e c t o posible

Page 202: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 5

Introducción

FlujosdegeneracióndecódigofinalLa generación de código ejecutable de un código fuente puede hacerse a través de varios flujos o rutas de traducción. Lo más frecuente es que la traducción se haga directamente al código objeto final. Sin embargo algunos compiladores ofrecen la opción de generar código ensamblador de la máquina objeto que posteriormente es ensamblado

If(a>b)then

a=a-b;

else

b=b+1;

MOVEt1a

MOVEt2b

CMPt1t2

BZE1

SUBt3t1t2

MOVEat3

MOVEt4#1

ADDt5t2t4

MOVEbt5

E1:

LD#20[.IX]/100

LD#21[.IX]#12[.IX]

CMP#20[.IX]#21[.IX]

BZE1

SUB#22[.IX]#20[.IX]#21[.IX]

LD/100#22[.IX]

LD#23[.IX]#1

ADD#24[.IX]#21[.IX]#23[.IX]

LD#21[.IX]#24[.IX]

E1:

000000011001010001100100

000000011001010110001100

001000111001010010010101

001011000000110000101100

00000101100101101001010010010101

000000010110010010010110

000000011001011000000001

00000100100101111001010110010110

000000011001010110010111

�Traduccióndirectaacódigofinal

�Traducciónacódigoensamblador

�Traducciónacódigofinal

Foco de atención Nosotrostraduciremosnuestrocódigoaensambladoryacabaremosahí

}

Page 203: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 6

Introducción

PartesdelageneracióndecódigofinalDurante el procedo de traducción de código intermedio a código final aparecen dos problemas principales a los que hay que hacer frente relacionados con el entorno de ejecución. En primer lugar, es necesario asociar cada objeto de datos a un direccionamiento en memoria. En segundo lugar, se requiere adaptar las cuádruplas al juego de instrucciones de la arquitectura física.

Generación de código final

I. Resolución de referencias simbólicas Los objetos de datos que de manera simbólica aparecen referenciados como operandos dentro del código intermedio deben ser traducidos a posiciones físicas de memoria. Aquí la naturaleza del tipo de datos (variable global, local, parámetro o temporal) y el modelo de entorno seleccionado en el capítulo anterior condicionan considerablemente esta tarea ya que los modos de direccionamiento se ven directamente afectados

II. Traducción al juego de instrucciones Para convertir un programa de código intermedio en código final es necesario establecer una relación de traducción de cada cuádrupla en su equivalente en el juego de instrucciones de la arquitectura final ya que la traducción de cada una es independiente de las demás. Por lo general, cada cuádrupla genera varias instrucciones de código objeto. Cuanto más cercanos, estructural y semánticamente hablando, se encuentren estos lenguajes más directa será la traducción

Page 204: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 7

Resolucióndereferenciassimbólicas

ResolucióndereferenciassimbólicasLa segunda parte del proceso de generación de código objeto a partir de código intermedio consiste en expresar cara referencia simbólica a un objeto de datos del programa – variable local, global, parámetro o temporal – como un espacio en memoria conocido bien en tiempo de compilación o reservado dinámicamente en tiempo de ejecución

MOVEt1a

MOVEt2b

CMPt1t2

BZE1

SUBt3t1t2

MOVEat3

MOVEt4#1

ADDt5t2t4

MOVEbt5

E1:

LD#20[.IX]/100

LD#21[.IX]#12[.IX]

CMP#20[.IX]#21[.IX]

BZE1

SUB#22[.IX]#20[.IX]#21[.IX]

LD/100#22[.IX]

LD#23[.IX]#1

ADD#24[.IX]#21[.IX]#23[.IX]

LD#21[.IX]#24[.IX]

E1:

Direccionamientoenmemoria

Códigointermedio Códigofinal

Tanto el mapa de memoria como los modos dedireccionamiento disponibles para cada operacióndentro del juego de instrucciones del entorno deejecución objeAvo condicionan esta segunda partedelprocesodetraducciónacódigofinal

Mapadememoria&modosdedireccionamiento

Page 205: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 8

Resolucióndereferenciassimbólicas

ModosdedireccionamientoPor norma general existen una colección de modos de direccionamiento distintos que se utilizan en diferentes contextos. Es frecuente que una instrucción no soporte cualquier modo de direccionamiento sino solo un subconjunto de ellos, lo que puede influir directamente en el proceso de traducción a código objeto. A continuación revisamos los principales modos de direccionamiento

I.Inmediato II.Directoaregistro III.DirectoamemoriaEl direccionamiento inmediato esaquel en el que el operando formapartelapropiainstruccióndecódigoejecutable.Seexpresaanteponiendo#alvalordeloperando

ADDR1#3

El direccionamiento directo aregistropermitedireccionarunvalorqueestáalmacenadoenunode losregistros del entorno de ejecuciónobjeAvo

ADDR1#3

El direccionamiento inmediato amemoria opera con un valoralmacenado en una direcciónabsoluta de memoria. Se uAliza /pararepresentarlo

ADDR1/1000

IV.Indirecto V.Rela8voaregistro VI.Rela8voacontadordeprogramaEl direccionamiento indirecto operacon el valor almacenado en ladirección de memoria apuntada enelregistrodado.Seponeentre[]elnombredelregistro

ADDR1[R3]

El direccionamiento relaAvo aregistro permite expresar unadirección de desplazamiento sobrelabasedelvalor dememoriaenunregistro

ADDR1#3[SP]

UAlizado en las instrucciones desalto,estedireccionamientoexpresaun direccionamiento relaAvo alregistro contador de programa. Seusa$yseomiteelregistro

BR$3

Page 206: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 9

Resolucióndereferenciassimbólicas

Modosdedireccionamiento&EntornosdeejecuciónComo hemos dicho, el tipo de entorno de ejecución puede condicionar los modos de direccionamiento disponibles en el juego de instrucciones. Pero, a tenor de lo estudiado en el tema anterior sobre activación de subprogramas, merece a su vez reflexionar qué modos de direccionamiento podes necesitas para cada tipo de objeto de datos en función del tipo de entorno disponible

Está6co

D.Inmedeiato D.Directoamemoria D.Rela6voaregistro

ValoresLiterales

VariablesglobalesVariableslocalesParámetrosTemporales

-

Depila ValoresLiterales

Variablesglobales

VariableslocalesParámetrosTemporales

Dinámico ValoresLiterales

Variablesglobales

VariableslocalesParámetrosTemporales

Page 207: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 10

Resolucióndereferenciassimbólicas

Modosdedireccionamiento&EntornosdeejecuciónComo hemos dicho, el tipo de entorno de ejecución puede condicionar los modos de direccionamiento disponibles en el juego de instrucciones. Pero, a tenor de lo estudiado en el tema anterior sobre activación de subprogramas, merece a su vez reflexionar qué modos de direccionamiento podes necesitas para cada tipo de objeto de datos en función del tipo de entorno disponible

Ejemplo

MOVEt1a

MOVEt2b

CMPt1t2

BZE1

SUBt3t1t2

MOVEat3

MOVEt4#1

ADDt5t2t4

MOVEbt5

E1:

LD#20[.IX]/100

LD#21[.IX]#12[.IX]

CMP#20[.IX]#21[.IX]

BZE1

SUB#22[.IX]#20[.IX]#21[.IX]

LD/100#22[.IX]

LD#23[.IX]#1

ADD#24[.IX]#21[.IX]#23[.IX]

LD#21[.IX]#24[.IX]

E1:

RA

Memorialibre

Valorretorno

Direcciónretorno

EnlaceControl

Parámetros…

Variableslocales…b…

…t1t2t3t4t5…

a

Datosestáticos

/100:

.IX

.IX+12

.IX+20

Direccionamientoenmemoria

Enunentornodeejecuciónbasadoenpila, lasvariablesglobalesseresuelvencon direccionamiento directo a memoria ya que su dirección es conocida enAempodecompilación.Para lasvariables locales,parámetrosytemporalesseuAliza direccionamiento relaAvo a registro ya que la memoria se reservadinámicamenteenAempodeejecuciónyladireccióndependedelestadodelapilaencadamomentoexpresándoseenbasealpunterodemarco(.IX)

}

Page 208: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 11

Traducciónaljuegodeinstrucciones

TraducciónaljuegodeinstruccionesEl primer paso para articular el proceso de generación de código final es establecer la relación de traducción de cada operación de código intermedio en su equivalente o equivalentes en el entorno de ejecución objetivo. El juego de instrucciones de la arquitectura física determina como se produce esta traducción

MOVEt1a

MOVEt2b

CMPt1t2

BZE1

SUBt3t1t2

MOVEat3

MOVEt4#1

ADDt5t2t4

MOVEbt5

E1:

LD#20[.IX]/100

LD#21[.IX]#12[.IX]

CMP#20[.IX]#21[.IX]

BZE1

SUB#22[.IX]#20[.IX]#21[.IX]

LD/100#22[.IX]

LD#23[.IX]#1

ADD#24[.IX]#21[.IX]#23[.IX]

LD#21[.IX]#24[.IX]

E1:

Traduccióndeoperaciones

Códigointermedio Códigofinal

Lasoperacionesdeljuegodeinstruccionesdela arquitectura `sica objeAvo determina elprocesode traducción.Noenvano, se tratadeexpresar lasemánAcadecadacuádruplaen términos de la expresividad ofrecida porel lenguaje máquina del entorno deejecución

Juegodeinstrucciones

Page 209: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 12

Traducciónaljuegodeinstrucciones

TraducciónaljuegodeinstruccionesEl tipo de arquitectura del entorno de ejecución para el cual se está generando el código final condiciona directamente la anatomía del mismo. En efecto, los recursos de la máquina suelen condicionar la estructura y prestaciones del juego de instrucciones con lo que la traducción puede ser muy diferente de una máquina a otra

Generacióndecódigofinal

Representacionesjerárquicas

Representacioneslineales

Árbolessintác9cos Grafossintác9cos Tercetos Cuartetos

Elcódigointermediotambiéndebeser cuidadosamente elegido parafacilitar la traducción en funcióndecómoseaelcódigofinal

Máquinasapila Máquinasconregistroacumulador

Máquinasconcódigodetercetos

Máquinasconcódigodecuartetos

Segúnelnúmerodeoperandosdelas instrucciones las arquitecturassepuedenclasificaren4Apos

0 1 2 3

Page 210: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 13

Traducciónaljuegodeinstrucciones

TiposdearquitecturasMsicasEl tipo de arquitectura del entorno de ejecución para el cual se está generando el código final condiciona directamente la anatomía del mismo. En efecto, los recursos de la máquina suelen condicionar la estructura y prestaciones del juego de instrucciones con lo que la traducción puede ser muy diferente de una máquina a otra

I.MáquinasapilaLas máquinas a pila disponen de una pila de operandos donde realizan todas las operaciones propias de la unidad aritmético lógica. Para operar una operación aritmética, por ejemplo, primero se meten los operandos en la pila – uno o dos según sea unaria o binaria la operación – y después se aplica el operador que extrae de la pila el número de operandos que requiere e inserta el resultado en la cima

ADDabc TraducciónCódigointermedio Códigofinal

PUSHbPUSHCADDPOPa

b b

c

b+c

PUSHbPUSHCADDPOPa

Las operaciones de código intermedio setraducenainstruccionescon0operandosyaque estos son extraídos de la pila. Tan sololas operaciones PUSH y POP conAenen unargumento

}

En una traza de la ejecución puede versecomolapiladeoperandossevacargandodedatosyvaciandosegúnseoperansobreellasoperaciones

}

Page 211: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 14

Traducciónaljuegodeinstrucciones

TiposdejuegosdeinstruccionesEl tipo de arquitectura del entorno de ejecución para el cual se está generando el código final condiciona directamente la anatomía del mismo. En efecto, los recursos de la máquina suelen condicionar la estructura y prestaciones del juego de instrucciones con lo que la traducción puede ser muy diferente de una máquina a otra

II.MáquinasconregistroacumuladorLas máquinas con registro acumulador disponen, a parte de otros recursos, de un registro especial llamado registro acumulador contra el que se realizan todas las operaciones de la unidad aritmético lógica. Cuando se desea hacer una operación binaria uno de los datos aparece como operando de la operación mientras que el otro se carga en el acumulador y funciona como operando implícito

ADDabc TraducciónCódigointermedio Códigofinal

LDcADDbSTa

c b+c b+c

LDcADDbSTa

Las operaciones de código intermedio setraducenainstruccionescon1operandosyaqueelotrosehacargadopreviamenteenelregistro acumulador y funciona comooperando implícito. La traducción es mássencillaysintéAcaquelaanterior

}

En la traza de ´de ejecución de estatraducción se observa como el registroacumulador se uAliza de operando implícitoydealmacénderesultados.Cuandosecargael valor final en a, no se borra delacumulador por si hace falta parainstruccionessubsiguientes

}

Page 212: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 15

Traducciónaljuegodeinstrucciones

TiposdejuegosdeinstruccionesEl tipo de arquitectura del entorno de ejecución para el cual se está generando el código final condiciona directamente la anatomía del mismo. En efecto, los recursos de la máquina suelen condicionar la estructura y prestaciones del juego de instrucciones con lo que la traducción puede ser muy diferente de una máquina a otra

III.MáquinasconcódigodetercetosEn las máquinas con código de tercetos las operaciones del juego de instrucción disponen a lo sumo de dos operandos sobre los cuales realizar la operación. Frecuentemente el primero de ellos se utiliza como argumento de entrada y salida donde se almacena el resultado final. Si no se quieren perder los resultados de los operandos hay que hacer una salvaguarda previa de datos

ADDabc TraducciónCódigointermedio Códigofinal

LDabADDac

LDabADDac

Las operaciones de código intermedio setraducenainstruccionescon2operandosyaque se asume que el primero de ellostambién representa el lugar donde debealmacenarseelvalor resultante tras realizarlaoperación

}

Enesta trazadeejecución seobserva comoparaevitarperderelvalor“b”queresideenb se mueve preliminarmente ésta a a yposteriormente se aplica la operación desumasobrelosoperandosaycdejandoenelprimeroelresultado

}

- b cabc

b b cabc

b+c b cabc

Page 213: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 16

Ges6óndeljuegodeinstrucciones

TiposdejuegosdeinstruccionesEl tipo de arquitectura del entorno de ejecución para el cual se está generando el código final condiciona directamente la anatomía del mismo. En efecto, los recursos de la máquina suelen condicionar la estructura y prestaciones del juego de instrucciones con lo que la traducción puede ser muy diferente de una máquina a otra

IV.MáquinasconcódigodecuartetosEs poco frecuente encontrar máquinas con un juego de instrucciones basado en cuartetos. No obstante lo abordaremos aquí por motivos de completitud. En las máquinas de cuartetos la las cuádruplas de código intermedio tienen una traducción directa a las instrucciones de la arquitectura final. Esta semejara simplifica considerablemente el proceso

ADDabc TraducciónCódigointermedio Códigofinal

ADDabc

ADDabc

EnesteApodeentornos lasoperacionesdeljuego de instrucciones disponen del mismonúmerodeoperandosquelacuádrupla(alosumo2operandosdeentraday1desalida).Esto hace que el proceso de traducción secentre en generar el acrónimo de laoperaciónadecuado

}

Enestatrazadeejecuciónselaoperacióndesumaserealizadirectamenteconunaúnicainstrucción en ensamblador. Esto es posibledebidoaquelosoperacionesnodestruyenelvalor de los argumentos de entrada tras laoperación

}

- b cabc

b+c b cabc

Page 214: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 17

Generacióndecódigoobjetoenlaprác6ca

ElentornodeejecuciónENS-2001La práctica consiste en implementar un compilador con soporte a la invocación recursiva de subprogramas que genere código objeto para la máquina virtual ENS2001. En esta sección presentaremos este problema, describiremos la máquina objetivo y discutiremos la forma de proceder para implementar la generación de código final

Consúltese el manual de usuario de ENS-2001

If(a>b)then

a=a-b;

else

b=b+1;

LD#20[.IX]/100

LD#21[.IX]#12[.IX]

CMP#20[.IX]#21[.IX]

BZE1

SUB#22[.IX]#20[.IX]#21[.IX]

LD/100#22[.IX]

LD#23[.IX]#1

ADD#24[.IX]#21[.IX]#23[.IX]

LD#21[.IX]#24[.IX]

E1:

TraducciónacódigoensambladorENS2001

ENS2001

MOVEt1a

MOVEt2b

CMPt1t2

BZE1

SUBt3t1t2

MOVEat3

MOVEt4#1

ADDt5t2t4

MOVEbt5

E1:

Generacióndecódigointermedio

Entornovirtualdedepuración

SetratadeunentornodeejecuciónbasadoenPilayunaarquitecturavirtualconunentornodesimulaciónqueatodoslosefectosjuegaelpapeldeunaarquitectura`sicareal }

Page 215: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 18

Generacióndecódigoobjetoenlaprác6ca

ElentornodeejecuciónENS-2001ENS-2001 es una máquina virtual desarrollada con fines educativos que dispone de todos los elementos típicos de una arquitectura Von Newman estándar y sirve de marco de simulación para la generación de un código final ejecutable y depurable dentro de un entorno visual independiente de plataforma. A continuación describimos sus elementos

Consúltese el manual de usuario de ENS-2001

Memoria

CPU

UC

ALU(CA2)

Busdememoria

0

Busdedatos16bits

Registros

A R0 R1 R2 R3 R4

R5 R6 R7 R8 R9

H S P V C

PC SP

IX IY

16bits65535

Z

Visióngeneral

SR

Page 216: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 19

Generacióndecódigoobjetoenlaprác6ca

ElentornodeejecuciónENS-2001ENS-2001 es una máquina virtual desarrollada con fines educativos que dispone de todos los elementos típicos de una arquitectura Von Newman estándar y sirve de marco de simulación para la generación de un código final ejecutable y depurable dentro de un entorno visual independiente de plataforma. A continuación describimos sus elementos

Consúltese el manual de usuario de ENS-2001

A

R0 R9

Registros

...

RegistroAcumulador

Registrosgenerales

PC ContadordePrograma

SP Punterodepila

IX IY Registrosdeíndice

H

S

P

V

C

Z

SR

Regi

stro

sde

est

ado

Flagdecero(0)

Flagdeacarreo(1)

Flagdedesbordamiento(2)

Flagdeparidad(3)

Flagdesigno(4)

Flagdeparada(5)

Memoriaymodosdedireccionamiento

Memoria

0

65535

Pila(configurable)

D.Inmediato:#1D.Directoaregistro:.R3D.Directoamemoria:/1000D.Indirecto:[.R3]D.RelativaaReg.Índice:#3[.IX]#3[.IY]D.RelativoaPC:$3

Page 217: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 20

Generacióndecódigoobjetoenlaprác6ca

ElentornodeejecuciónENS-2001ENS-2001 es una máquina virtual desarrollada con fines educativos que dispone de todos los elementos típicos de una arquitectura Von Newman estándar y sirve de marco de simulación para la generación de un código final ejecutable y depurable dentro de un entorno visual independiente de plataforma. A continuación describimos sus elementos

Consúltese el manual de usuario de ENS-2001

Juegodeinstrucciones

Page 218: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 21

Generacióndecódigoobjetoenlaprác6ca

GeneracióndecódigoobjetoComo estudiamos en las secciones anteriores la generación de código objeto se hace en dos fases consecutivas. Primero deben resolverse todas las referencias simbólicas a objetos de datos en direcciones de memoria real y después realizar el proceso de traducción de operaciones teniendo en cuenta el juego de instrucciones disponibles en el entorno de ejecución

I.ResolucióndereferenciassimbólicasEn los entornos basados en pila, el direccionamiento de variables globales es a posiciones absolutas de memoria (direccionamiento directo a memoria) y el del resto es relativo a puntero de marco (.IX). En esta fase debe asignarse una dirección a cada uno de los objetos de datos para cada ámbito

program::=axiom:a{:

intgAddress=0,lOffset=0;

List<ScopeIF>scopes=scopeManager.getAllScopes();

for(ScopeIFscope:scopes){

List<SymbolIF>symbols=scope.getSymbolTable().getSymbols();

for(SymbolIFs:symbols){

if(sinstanceofSymbolVariable)

if(scope.getLevel()==0)

s.setAddress(gAddress+=s.getType().getSize());

elses.setAddress(lOffset+=s.getType().getSize());

}

List<TemporalIF>tempotals=scope.getTemporallTable().getTemporals();

for(TemporalIFt:temporals)

t.setAddress(lOffset+=t.getsize());:}

Aunqueexistenotrasestrategias,lomáscómodoesalojarla zona de datos estáAcos (variables globales)comenzandoen laposición0dememoriay luegoubicarel código. Aquí asumiremos que para el programaprincipal existe un RA propio lo que permite untratamiento relaAvo a .IX. Recuérdese como Variable yTemporalAenenunatributoAddress:

}

Temporal

- Stringname- ScopeIFscope- Integeraddress-Integersize

SymbolVariable

- Stringname- TypeIFtype- ScopeIFscope- IntegerAddress

Page 219: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 22

Generacióndecódigoobjetoenlaprác6ca

GeneracióndecódigoobjetoComo estudiamos en las secciones anteriores la generación de código objeto se hace en dos fases consecutivas. Primero deben resolverse todas las referencias simbólicas a objetos de datos en direcciones de memoria real y después realizar el proceso de traducción de operaciones teniendo en cuenta el juego de instrucciones disponibles en el entorno de ejecución

II.TraducciónaljuegodeinstruccionesUna vez que se ha asignado una dirección a cada objeto de datos sólo resta escribir cada instrucción con el acrónimo adecuado y cada operando con la sintaxis de direccionamiento propia del ensamblador de ENS-2001 en función del valor del atributo dirección y el tipo de objeto

program::=axiom:a{:

...continua

IntermediateCodeBuildercb=newIntegermediateCodeBuilder(scope);

cb.addQuadruple(“DATA”,gAddress);

cb.addQuadruples(a.getCode());

finalCodeFactory.create(cb.create());

syntaxErrorManager.syntaxInfo("Parsingproccessended.");

:}

Antesdeprocedercon latraducciónacódigofinalse insertapordelanteuna instrucciónDATAqueseencarga de reservar espacio en memoria para lasvariables globales que fueron contabilizadas engAddressenladiaposiAvaanterior.TantogAddresscomo lAddress fueron incrementadas en ladiaposiAva anterior con el tamaño del Apo delobjeto de datos. En ENS-2001 todos los Apossimples pesan 1 palabra enmemoria, los arrays 1palabraporcadaelementoylosregistros1palabraporcadacampo

}

Page 220: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 23

Generacióndecódigoobjetoenlaprác6ca

GeneracióndecódigoobjetoComo estudiamos en las secciones anteriores la generación de código objeto se hace en dos fases consecutivas. Primero deben resolverse todas las referencias simbólicas a objetos de datos en direcciones de memoria real y después realizar el proceso de traducción de operaciones teniendo en cuenta el juego de instrucciones disponibles en el entorno de ejecución

II.TraducciónaljuegodeinstruccionesUna vez que se ha asignado una dirección a cada objeto de datos sólo resta escribir cada instrucción con el acrónimo adecuado y cada operando con la sintaxis de direccionamiento propia del ensamblador de ENS-2001 en función del valor del atributo dirección y el tipo de objeto

program::=axiom:a{:

...continua

IntermediateCodeBuildercb=…

cb.addQuadruple(“DATA”,gAddress);

cb.addQuadruples(a.getCode());

finalCodeFactory.create(cb.create());

syntaxErrorManager.syntaxInfo(“…");

:}

Loqueelestudiantenove…ExecutionEnvironmente=…

publiccreate(List<QuadrupleIF>qs){

for(Quadrupleq:qs){

buffer.append(e.translate(q));

<<volcaraficheroelbuffer>>}

}

publicclassENS2001Environment{

publicStringtranslate(QuadrupleIFq){

returnq.toString();

}

}crea

te

invoke

Page 221: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 24

Generacióndecódigoobjetoenlaprác6ca

GeneracióndecódigoobjetoComo estudiamos en las secciones anteriores la generación de código objeto se hace en dos fases consecutivas. Primero deben resolverse todas las referencias simbólicas a objetos de datos en direcciones de memoria real y después realizar el proceso de traducción de operaciones teniendo en cuenta el juego de instrucciones disponibles en el entorno de ejecución

II.TraducciónaljuegodeinstruccionesUna vez que se ha asignado una dirección a cada objeto de datos sólo resta escribir cada instrucción con el acrónimo adecuado y cada operando con la sintaxis de direccionamiento propia del ensamblador de ENS-2001 en función del valor del atributo dirección y el tipo de objeto

program::=axiom:a{:

...continua

IntermediateCodeBuildercb=…

cb.addQuadruple(“DATA”,gAddress);

cb.addQuadruples(a.getCode());

finalCodeFactory.create(cb.create());

syntaxErrorManager.syntaxInfo(“…");

:}

Loqueelestudiantenove…ExecutionEnvironmente=…

publiccreate(List<QuadrupleIF>qs){

for(Quadrupleq:qs){

buffer.add(e.translate(q));

<<volcaraficherobuffer>>}

}

publicclassENS2001Environment{

publicStringtranslate(QuadrupleIFq){

returnq.toString();

}

}crea

te

invoke

Esta implementacióndummy del metro detraducción solo hace unecodelacuádrupla.Aquídebe implementarse latraducción (operación ydireccionamiento)

if(q.getOperation.equals(“ADD”)){

StringBufferb=newStringBuffer();

Stringo1=translate(q.getFirstOperand());

Stringo2=translate(q.getSecondOperand());

Stringr=translate(q.getResult());

b.append(“LD”+“.A”+o1+“\n”);

b.append(“ADD”+r+“”+o2);

returnb.toString();}...

Page 222: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 25

Generacióndecódigoobjetoenlaprác6ca

GeneracióndecódigoobjetoComo estudiamos en las secciones anteriores la generación de código objeto se hace en dos fases consecutivas. Primero deben resolverse todas las referencias simbólicas a objetos de datos en direcciones de memoria real y después realizar el proceso de traducción de operaciones teniendo en cuenta el juego de instrucciones disponibles en el entorno de ejecución

II.TraducciónaljuegodeinstruccionesUna vez que se ha asignado una dirección a cada objeto de datos sólo resta escribir cada instrucción con el acrónimo adecuado y cada operando con la sintaxis de direccionamiento propia del ensamblador de ENS-2001 en función del valor del atributo dirección y el tipo de objeto

program::=axiom:a{:

...continua

IntermediateCodeBuildercb=…

cb.addQuadruple(“DATA”,gAddress);

cb.addQuadruples(a.getCode());

finalCodeFactory.create(cb.create());

syntaxErrorManager.syntaxInfo(“…");

:}

Loqueelestudiantenove…ExecutionEnvironmente=…

publiccreate(List<QuadrupleIF>qs){

for(Quadrupleq:qs){

buffer.add(e.translate(q));

<<volcaraficherobuffer>>}

}

publicclassENS2001Environment{

publicStringtranslate(QuadrupleIFq){

returnq.toString();

}

}crea

te

invoke

La traducción de losoperandos puede dele-garse, por convenienciaen un método privadoquerealice la traducciónde direccionamientoadecuada en función des i e l o p e r a n do e svariableglobalodeotroApo

privateStringtranslate(OperandIFo){

if(oinstanceofVariable){

Variablev=(Variable)o;

if(v.isGlobal())return“/”+o.getAddress();

}

return“#”+o.getAddress+“[.IX]”;

}

}

Page 223: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 26

Generacióndecódigoobjetoenlaprác6ca

1.  Implementar un método de consulta del tamaño de tipos

1.  Implementar getSize () en temporales. Delegar en Ens2001Environment. Devuelve 1.

2.  Implementar getSize () en Variables. Delega en type.getSize () que delega en Ens2001Environment

1.  Para tipos primitivos devuelve 1

2.  Para arrays de dimensión N devuelve N

3.  Para registros, la suma del tamaño de cada campo

2.  Implementar la resolución de referencias simbólicas a direcciones de memoria

3.  Articular el proceso de traducción de cuádruplas dentro del método translate

1.  Implementar con una batería de sentencias condicionales L

2.  Idear un objeto translator con método translate e implementar 1 subclase por cuádrupla J

4.  Probar el código final generado

1.  Ejecutar el código en program ::= axioma (descomentarlo)

2.  Observar los resultados en el fichero de salida .ens

DesarrollopasoapasoLa generación de código objeto da por finalizado el desarrollo de la construcción de un compilador completamente operativo. A grandes rasgos, el se puede resumir el conjunto de pasos necesarios para realizar esta fase en los siguientes puntos:

Page 224: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 27

BibliograOa

MaterialdeestudioBibliografía básica

Construcción de compiladores: principios y práctica

Kenneth C. Louden International Thomson Editores,

2004 ISBN 970-686-299-4

Page 225: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Generacióndecódigofinal.Traducciónacódigoobjeto

10 - 28

BibliograOa

MaterialdeestudioBibliografía complementaria

Compiladores: Principios, técnicas y herramientas.

Segunda Edición Aho, Lam, Sethi, Ullman

Addison – Wesley, Pearson Educación, México 2008

Diseño de compiladores. A. Garrido, J. Iñesta, F. Moreno

y J. Pérez. 2002. Edita Universidad de Alicante

Page 226: Procesadores de Lenguajes I

ProcesadoresdeLenguajesIngenieríaTécnicasuperiordeIngenieríaInformá8ca

DepartamentodeLenguajesySistemasinformá6cos

JavierVé[email protected]

DepartamentodeLenguajesYSistemasInformáAcosUNED

1Estrategiasdeop-mización

OpAmizacióndecódigointermedioycódigoobjeto1

Page 227: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 2

Obje6vos

Obje8vos

›  Entender que es la optimización de código

›  Entender que son las transformaciones y qué tipos existen

›  Aprender las fases en las que pueden aplicarse transformaciones de código

›  Estudiar las principales transformaciones independientes del entorno de ejecución

›  Conocer el ámbito de aplicación de estas transformaciones (locales vs. globales)

›  Conocer los tipos de transformaciones independientes del entorno

›  Aquellas que preservan la estructura del grafo/bloque

›  Aquellas que no preservan la estructura del grafo/bloque

›  Estudiar las principales transformaciones dependientes del entorno de ejecución

›  Aprender a medir el coste de ejecución de un programa

›  Aprender a seleccionar instrucciones para la traducción a código final

›  Aprender a seleccionar direccionamientos para la traducción a código final

›  Adquirir una actitud crítica sobre las técnicas de optimización de código intermedio y final

Page 228: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 3

Índice

Índice

›  Introducción

›  Transformaciones independientes del entorno de ejecución

›  Grafos de flujo, bloques básicos y DGA

›  Transformaciones que preservan la estructura

›  Transformaciones que no preservan la estructura

›  Transformaciones dependientes del entorno de ejecución

›  Selección de instrucciones para la traducción

›  Selección del lugar de almacenamiento para la traducción

›  Bibliografía

Page 229: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 4

Introducción

¿Quéeslaop8mizacióndecódigo?La generación de código, típicamente realizada en 2 fases a través del código intermedio, provoca frecuentemente código ejecutable que aunque correcto resulta torpe y poco eficiente desde el punto de vista del tamaño o del tiempo que tarda éste en ejecutarse. Esto suele ser debido a que el alcance de visibilidad del compilador en estas fases es a nivel de cuádrupla. Conviene así, aplicar ciertas estrategias de optimización sobre el código resultante

La optimización del código es el proceso mediante el cual se aplican ciertas

transformaciones de código para conseguir que un programa ejecutable sea más eficiente

en tiempo de ejecución y / o compacto en memoria

x:=y+z

MVt0yMVt1zADDt2t0t1MVxt2

Sabiendo que…

a:=b+cd:=a+e

MVt0bMVt1cADDt2t0t1MVat2MVt3aMVt4eADDt5t3t4MVdt5

traduce

Entonces…

traduce MVt0bMVt1cADDt2t0t1MVat2MVt4eADDt5t2t4MVdt5

MVt0bMVt1cADDt2t0t1MVat2MVt0eADDt1t2t0MVdt1

Tr.#1 Tr.#2

Page 230: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 5

Introducción

¿Quéesunatransformacionesdecódigo?Como acabamos de describir, el proceso de optimización de código se basa en la aplicación de una colección de transformaciones sobre el mismo. Los compiladores actuales tienen implementadas una serie de estas transformaciones de mayor o menor nivel de complejidad que persiguen algún determinado objetivo de mejora sobre el código final

Una transformación de código es una reescritura del programa que tiene por objeto obtener

una versión funcionalmente equivalente del mismo y mejorada con respecto a algún criterio

de calidad

De acuerdo a esto, las transformaciones de código que suelen implementar los compiladores se pueden caracterizar a partir de 3 premisas fundamentales. A continuación describimos brevemente cada una de ellas en detalle

I. Preservación del significado

Las transformaciones que seaplican sobre un determinadocódigo deben preservar en todomomento la semánAca delmismo.UnaopAmizaciónnodebecambiar el resultado producidopara ciertos datos de entrada nicausarunerrorparalosmismos

II. Mejora de la calidad

Toda transformación aplicadasobre un determinado códigodebe suponer una mejoramensurable sobre algún criteriodecalidad,Ppicamenteexpresadoen compactación de código oAempodeejecución

III. Aplicabilidad

Unatransformaciónrealizadasobreun determinado código debe serantetodoaplicablecomotécnicademejoradentrodelcompilador.Estoimplicaqueelordendecomplejidadde su aplicación no debe ser muysuperior al propio del proceso decompilación

Page 231: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 6

Introducción

Obje8vosdelastransformacionesdecódigoLa aplicación de las transformaciones de optimización de código pueden perseguir distintos propósitos. En términos generales es posible distinguir entre optimización del tiempo de ejecución y optimización del tamaño en memoria del programa ejecutable. Contrariamente a lo que pueda parecer, no obstante, estos dos tipos de transformaciones están estrechamente relacionadas entre sí puesto que cuanto más compacto es un programa más rápida suele resultar su ejecución. La explicación de este hecho se estudiará a lo largo de este capítulo

Objetivos de las transformaciones

de código

I. Optimización del tiempo de ejecución El propósito de este tipo de transformaciones es lograr una mejora – no necesariamente óptima – del tiempo que tarda el código final en ser ejecutado sobre determinada arquitectura final. Este tipo de transformaciones son las de aplicación más frecuente

II. Optimización del tamaño del programa ejecutable Las transformaciones para la optimización del tamaño, tienen por objetivo mejorar la compactación del programa final ejecutable en memoria de manera que ocupen menos espacio. Este tipo de transformaciones son menos frecuentes ya que la capacidad actual de las memorias no es un recurso escaso

Focodeatención

}

Page 232: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 7

Introducción

SeleccióndelastransformacionesdecódigoLas transformaciones de optimización de código que existen actualmente reconocidas realizan un determinado cambio dentro del código sobre el que se aplican bajo la hipótesis de que tendrán un impacto suficiente sobre la eficiencia del programa objetivo. Sin embargo, ¿cómo se puede medir de manera objetiva dicha eficiencia?

Estrategias de selección de

transformaciones de código

I. Análisis del peor caso Ante toda falta de información de cómo un programa ejecutable va a ser ejecutado, el optimizador de código debe ponerse en el peor caso y realizar las asunciones de uso peores para escoger las transformaciones que va a aplicar. A esta estrategia se le conoce por el nombre de estimación conservadora de la ejecución y es de aplicación frecuente

II. Análisis estadístico Cuando el equipo que desarrolla el compilador sabe del tipo de programas que se van a programar y dispone de datos estadísticos sobre los escenarios de ejecución más frecuentes, puede guiar la selección de las técnicas de transformación de código en función de estos datos. A este tipo de compiladores se les conoce como compiladores de rendimiento y su existencia suele ser reducida y focalizada a determinados dominios dado lo irrealista de la asunción de existencia de estadísticas de uso

Focodeatención

}

Page 233: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 8

Introducción

FasesdeaplicacióndelastransformacionesdecódigoLas transformaciones de código toman un código de entrada y reescriben el mismo con el ánimo de mejorar su calidad. Cabe preguntarse cuando deben ser aplicadas dichas transformaciones. En realidad existen transformaciones destinadas a ser aplicadas en cada una de las fases del proceso de compilación. Diferentes compiladores escogen unas u otras

Analizad

orléxico

Analizad

orsintác8co

Analizad

orse

mán

8co

Códigointerm

edio

Códigofina

l

e·l·i·h·w <WHILE,PR> S

WHILEEDOS

E>E

S

WHILEEDOS

E>E

√ LDat1LDbt2GRTt3t1t2BRZt3L1…

0000001100000011010000010100000000010010…

While(a>b)doa:=a+1;

En algunos lenguajesc omo C o C + + l a sdirecAvasde compilaciónse resuelven a nivel decódigo fuente transfor-mando este es unaversión simplificada ymásopAmadelmismo

}

En la mayoría de loslenguajes la incorpo-ración y propagaciónde constantes serrealizan en la fase deanálisissintácAcos

}

A lguno s l e ngua j e sgeneran errores decódigo inalcanzabledetectable en esta fasepara evitar que elespacio en memoria yAempo de la ejecuciónseamayordelnecesario

} Tras la generación decód igo i n te rmed io seobAene una representacióndel programa que permitehace r un aná l i s i s detransformaciones inde-pendientes del entorno deejecución

}

Tras la generación decódigo final se aplicantransformaciones que vandirigidas a mejorar lacalidad teniendo en cuentalos recursos y prestacionesdelentornodeejecución

}

Focodeatención}

Page 234: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 9

Introducción

TiposdetransformacionesdecódigoCon todo lo establecido hasta este punto, ya es posible hacer una distinción tipológica entre dos clases principales de transformaciones. A lo largo de este capítulo nos centraremos en desarrollar en profundidad cada una de ellas, la primera centrada en el código intermedio y la segunda en el código final

Tipos de transformaciones

de código

I. Transformaciones independientes del entorno de ejecución

Las transformaciones independientes del entorno de ejecución son aquellas que se aplican sobre las fases anteriores a la generación de código final. La ventaja de estas transformaciones es que su aplicación tiene efecto independientemente del tipo de entorno de ejecución objetivo que se utilice para ejecutar el programa. Nosotros centraremos especialmente nuestra atención en aquellas transformaciones de este grupo que se aplican sobre el código intermedio

II. Transformaciones dependientes del entorno de ejecución Al contrario que las anteriores, estas transformaciones se aplican sobre el código final una vez generado. Se basan en un conocimiento profundo de las prestaciones, funcionamiento y estructura interna del entorno de ejecución objetivo donde va a ejecutarse el programa. Naturalmente, el éxito de aplicación de estas transformaciones está potencialmente limitado al entorno objetivo

Page 235: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 10

Transformacionesindependientesdelentornodeejecución

Grafosdeflujo,bloquesbásicosyDGAPara aplicar transformaciones de optimización sobre el código intermedio es conveniente representar el mismo en forma de un grafo de flujo compuesto por arcos y bloques básicos. Un bloque básico es una secuencia de instrucciones de saltos. Los arcos representan los saltos entre bloques

ProgramfactorialVARi,r:Integer;beginr:=1;i:=1;whilei<=5beginr:=r*i;i:=i+1;end;end.

MVr1MVi1E1:CMPi5BZFE2MVt0rMVt1iMULt2t0t1MVrt2MVt3iMVt41ADDt5t3t4MVit5BRE1;E2:HALT

MVr1MVi1

B0

E1:CMPi5BZFE2

B1

MVt0rMVt1iMULt2t0t1MVrt2MVt3iMVt41ADDt5t3t4MVit5BRE1

B2

E2:HALT B4

Método de construcción

›  Todobloquecomienzaporunlíder

›  Laprimeracuádruplaesunlíder

›  Eldes6nodeunsaltoesunlíder

›  Elsiguienteaunsaltoesunlíder

›  Seconstruyenlosbloques

›  Seincluyeellíder

›  Seincluyenlascuádruplasdetrásdellíder

›  Seconectanlosbloques

›  SiBsigueaAseponeunarcodeAaB

›  SihayunsaltodeBaCseponeunarcodeBaC

Page 236: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 11

Transformacionesindependientesdelentornodeejecución

Grafosdeflujo,bloquesbásicosyDGAPara aplicar transformaciones de optimización sobre el código intermedio es conveniente representar el mismo en forma de un grafo de flujo compuesto por arcos y bloques básicos. Un bloque básico es una secuencia de instrucciones de saltos. Los arcos representan los saltos entre bloques

MVr1MVi1

B0

E1:CMPi5BZFE2

B1

MVt0rMVt1iMULt2t0t1MVrt2MVt3iMVt41ADDt5t3t4MVit5BRE1

B2

E2:HALT B4

Transformaciones locales

Transformaciones globales }

}

Lastransformaciones locales,otransformacionesaniveldebloque, consistenen rescriturasde lascuádruplas de un bloque dirigidas a mejorar lacalidaddelmismo.EsteApodetransformacionessuelen ser de sencillas puesto que su ámbito deaplicaciónestáconfinadoaunpequeñogrupodeinstrucciones sin interferencias del resto debloques

Lastransformacionesglobales,otransformaciones a nivel degrafo, alcanzan el cuerpo detodo el procedimiento. Estastransformaciones son másdelicadas ya hay que tener encuenta cualquier efecto que lamodificacióndeunbloquepuedatenerenotrosbloques

Page 237: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 12

Transformacionesindependientesdelentornodeejecución

Grafosdeflujo,bloquesbásicosyDGAPara aplicar transformaciones de optimización sobre el código intermedio es conveniente representar el mismo en forma de un grafo de flujo compuesto por arcos y bloques básicos. Un bloque básico es una secuencia de instrucciones de saltos. Los arcos representan los saltos entre bloques

ADDabcSUBbadADDcdbSUBdad

Bn También es frecuente representar los bloques de un grafo de flujo, de manera independiente mediante un grafo dirigido acíclico (GDA). En esta representación los nodos hoja del grafo representan los operandos, los nodos intermedios las operaciones que se realizan sobre otros nodos y adjuntan los objetos de datos que las contienen. En el ejemplo adjunto por ejemplo el GDA seria el siguiente

+

b c

[a]

-

d

[b,d]

+[c]La construcción del GDA de un bloquepuede hacerse uAlizando dosdiccionarios. En uno se guardan losoperandos y en otro los nodosintermedios.Cuandohandereferirselosnodoshojaseusaelprimerdiccionario.Cuandosetratadecálculosintermediosse usa el segundo, que devuelve unsubárboldelgrafo representandodichocomputo

}

}

Lasinstruccionesdemovimientod e d a t o s o p e r a c i ó n d easignación desde un operandodeorigenaunodedesAno

Page 238: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 13

Transformacionesindependientesdelentornodeejecución

CatálogodetransformacionesIndependientemente del alcance – local o global – que tengan las transformaciones de optimización, es posible dividir las mismas en dos grandes grupos según repercutan en el grafo de flujo que representa el subprograma sometido a análisis de optimización. De esta manera es posible establecer el siguiente catálogo de transformaciones independientes del entorno de ejecución que utilizaremos de índice de referencia durante el resto de la sección

Transformaciones locales Transformaciones globales

- Eliminación de subexpresiones comunes

- Eliminación de código inactivo

- Renombramiento de variables temporales

- Intercambio de cuádruplas independientes

- Transformaciones algebraicas

- Reducción de la intensidad

- Propagación de constantes

No

pres

erva

n es

truc

tura

Pr

eser

van

estr

uctu

ra - Eliminación de subexpresiones comunes globales

- Propagación de copias

- Traslado de código

- Eliminación de variables de inducción

Noalteranlaestructuradelgrafodeflujo

Alteranlaestructuradelgrafodeflujo

}

}

I

II

III

IV

Page 239: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 14

Transformacionesindependientesdelentornodeejecución

I.TransformacioneslocalesquepreservanlaestructuraLas transformaciones locales que preservan la estructura del grafo de flujo constituyen reglas de reescritura sencillas que articulan mejoras probadas sobre el tiempo de ejecución y o el tamaño del código ejecutable. En concreto destacan 4 transformaciones dentro de esta categoría

Eliminación de subexpresiones comunes Eliminación de código innecesario

Cuando en un b loque aparecen dossubexpresiones asignadas a dos o más objetosde datos, se puede generar un temporal paraalmacenar el computo y asignar después todoslosobjetosaesetemporal

ADDabcSUBbadADDcdbSUBdad

Bn ADDabcSUBbadADDcdbMVdb

Bn

+

b c

[a]

-

d

[b,d]

+[c]

La eliminación de de código inaccesible oinnecesario permite aumentar la eficiencia delprograma. Los GDA ayudan a idenAficar dichocódigo. En efecto, todas las cimas (nodos sinpadre) que no tengan variables acAvas puedeneliminarsesinefectoscolaterales

ADDabcSUBbbdSUBccdADDebc

BnSUBbbdSUBccdADDebc

Bn

b c d

+ - +

+

[a] [b] [c]

[e]

Page 240: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 15

Transformacionesindependientesdelentornodeejecución

I.TransformacioneslocalesquepreservanlaestructuraLas transformaciones locales que preservan la estructura del grafo de flujo constituyen reglas de reescritura sencillas que articulan mejoras probadas sobre el tiempo de ejecución y o el tamaño del código ejecutable. En concreto destacan 4 transformaciones dentro de esta categoría

Renombramiento de variables temporales Intercambio de cuádruplas independientes

Todas las ocurrencias de una variable temporaldeunbloque puedesusAtuirseporotrasinqueelloafectealresultado

Dos cuádruplas independientes puedenintercambiar su orden de ejecución sin que esoafectealresultadofinaldelaejecución.Hayquecomprobar que la segunda cuádrupla noconAene por operandos el resultado calculadoporlaprimera

MVt0bMVt1cADDt2t0t1MVat2MVt3eADDt4t2t3MVdt4

Bn MVt0bMVt1cADDt2t0t1MVat2MVt7eADDt8t2t7MVdt8

Bn

b

t0

c

t1

e

t3

+[t2,a]

+[t4,d]

ADDabcSUBbbdSUBccdADDebc

Bn ADDabcSUBccdSUBbbdADDebc

Bn

b c d

+ - +

+

[a] [b] [c]

[e]

Page 241: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 16

Transformacionesindependientesdelentornodeejecución

II.TransformacioneslocalesquenopreservanlaestructuraLas transformaciones locales que no preservan la estructura del grafo de flujo son reglas de reescritura que producen cambios dentro del GDA que representa el bloque y suponen mejoras probadas sobre el tiempo de ejecución y o el tamaño del código ejecutable. En concreto destacan 3 transformaciones

Algebraicas

Algunasvecesesconvenienterealizaruna construcción algebraica máselaboradaparaexpresarelcódigodeotra manera semánAcamenteequivalente

MVab ADDab0

x:=x+0:=0+xx:=x-0x:=1*x:=x*1x:=x/1

b

a +[a]

b 0

Reducción de la intensidad

Estas transformaciones son unsubconjunto de las anteriores y seaplican para reducir los ciclos decómputo que requeriría el calculooriginal

MULax2 ADDaxx

X^2:=x*x2*x:=x+2X/2:=x*.5

+[a]

x x

*[a]

2 x

Propagación de constantes

Para las expresiones constantes,formadas exclusivamente porliterales y constantes simbólicas, esposible calcular en Aempo decompilación su valor y susAtuirlo.HayquetenerencuentaprecedenciayasociaAvidad

MULt023ADDt1t05MVat1

MVa11

+[t1,a]

5

*[t0]

2 3 11

a

Page 242: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 17

Transformacionesindependientesdelentornodeejecución

III.TransformacionesglobalesquepreservanlaestructuraLas transformaciones globales que preservan la estructura del grafo de flujo son reglas de reescritura que producen cambios de los bloques del grafo pero que no alteran la relación de dependencia de control de flujo que existe entre ellas. En concreto destacan 2 transformaciones

Eliminación de subexpresiones comunes Propagación de copias

Las subexpresiones comunes también puedenidenAficarse a lo largo de varios bloques de ungrafodeflujo.Esunamejoraeliminarlas

...MVabc...

B1

Es posible eliminar cuádruplas de reasignacióndelaformaMVxyporpropagacióndelvalordeyentodaslasocurrenciasfuturasdex

...ADDebcADDf2e...

Bn

...ADDabc...

B1

...MVeaADDf2e...

Bn

...MVabc...

B1

...MVeaADDf2e...

Bn

...MVabc...

B1

...ADDf2a...

Bn

Page 243: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 18

Transformacionesindependientesdelentornodeejecución

IV.TransformacionesglobalesquenopreservanlaestructuraLas transformaciones globales que no preservan la estructura del grafo de flujo son reglas de reescritura que producen cambios en la estructura relacional entre bloques que establece el grafo de flujo. En concreto destacan 2 transformaciones

Traslado de código Eliminación de variables de inducción

Eltrasladodecódigoconsisteenpromocionaruntrozo de código de un bloque para ubicarlo enalguna parte de un bloque anterior. Laextraccióndeinvariantesdebucleesunejemplo

MVi1 B1

Sobre losbuclesesposibleeliminarvariablesdeinducción aplicando sencillas transformacionesalgebraicasyrealizandotrasladosdecódigo

LSt0uvBRTE1t0

B2

MVin B1

E1:MVi2INCu

B3

DECvEQt1v20

B4

MVi1MVi2

B1

LSt0uvBRTE1t0

B2

E1:INCu

B3

DECvEQt1v20

B4

INCiMULt0i4...

Bn

B1MVinMULt04i

INCiADDt0t04...

Bn

Page 244: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 19

Transformacionesdependientesdelentornodeejecución

TransformacionesdependientesdelentornodeejecuciónEl coste de ejecución de un programa puede expresarse proporcionalmente en términos del coste de cada una de sus operaciones. Para calcular el coste de una operación hay que tener en cuenta el coste de su ejecución y sumarlo al coste de traer dicha operación de la memoria a la unidad central de proceso. En este sentido, las transformaciones dependientes del entorno de ejecución van dirigidas a mejorar el tiempo de ejecución y / o la compactación del programa ejecutable dentro de una arquitectura específica, teniendo en cuenta su estructura interna y recursos disponibles. En general pueden distinguirse dos tipos de transformaciones

Tipos de transformaciones dependientes del

entorno de ejecución

I. Selección de instrucciones para la traducción Como cada entorno de ejecución dispone de su propio juego de instrucciones, es conveniente escoger cuidosamente que operación u operaciones van a emplearse para traducir cada cuádrupla de código intermedio a código final

II. Selección de direccionamiento para la traducción Cada modo de direccionamiento tiene un coste asociado a la recuperación de datos desde la memoria. Las transformaciones de direccionamiento buscan optimizar el uso de recursos de manera que se deseche, en la medida de lo posible, direccionamientos pesados a favor de direccionamientos ágiles

Page 245: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 20

Transformacionesdependientesdelentornodeejecución

SeleccióndeinstruccionesparalatraducciónCada entorno de ejecución dispone de un juego de instrucciones propio que está adaptado a la optimización de determinados escenarios de ejecución hipotéticamente recurrentes. Las transformaciones dependientes del entorno nos ayudan a seleccionar, para una arquitectura concreta, qué instrucción de código final debe ser empleada en cada caso para traducir una cuádrupla de código intermedio

Arquitecturas VAX

Las arquitecturas VAX Aenen unainstrucciónespecificadeincremento-comparación-ramificación para darsoporte ágil a la implementación debucles

Arquitecturas CISC

Las arquitecturas CISC (ComplexInstrucAonSetComputer)constandeun completo juego de instruccionesque pueden realizar operacionescomplejas con múlAples modos dedireccionamiento

Arquitecturas RISC

Las arquitecturas RISC (ReducedInstrucAon Set Computer) disponende1 juegoreducidode instruccionesmuy ágiles donde solo operacionesde carga y almacenamiento Aenendireccionamientoamemoria

ADDa1

MOVE.R0aADD.R0#1MOVEa.R0

Ejemplo

INCa

CuantomáslargasealatraducciónacódigofinalmayorseráelcostedealmacenamientoenmemoriayelAempodeejecución

}

Si el entorno de ejecución dispone de unainstrucción explícita para realizar laoperación que deseamos hacer debemosaprovecharla puesto que serámás eficientequeotrastraduccionesequivalente

}

Page 246: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 21

Transformacionesdependientesdelentornodeejecución

SeleccióndeldireccionamientoparalatraducciónEl coste de ejecutar cada operación del juego de instrucciones de un entorno de ejecución es un valor que puede asumirse constante sin perdida de generalidad. No obstante a ese coste es necesario añadir el de traer de la memoria cada operando, en lo que los modos de direccionamiento tienen un impacto directo. De esta manera si T es el tiempo global de ejecución de una operación O, k el tiempo que tarda en ejecutarse por la unidad central de proceso y Tcarga el tiempo de carga de un operando puede asumirse que para una operación de dos operandos se tiene que

T(O)=k+TCarga(O.operando1)+TCarga(O.operando2)

Direccionamiento Ejemplo Coste InmediatoDirectoaregistroDirectoamemoriaIndirectoRelativaaReg.ÍndiceRelativoaPC

#1.R3/1000[.R3]#3[.IX]#5[.IY]$3

001111

L a e s t r a t e g i a d e s e l e c c i ó n d edireccionamientos para almacenar losobjetos de datos va dirigida por buscardireccionamientos de coste 0 (registros)frente a direccionamientos de mayor coste(memoria). En este senAdo el número deregistros de la máquina Aene un impactodirectoenelAempodeejecución

}

DadoquenosetratademedirelAempoentérminosabsolutossinolaescalabilidaddelproblema,elvalorrealdelaconstanteken la fórmula anterior es prescindible y puede decirse que elAempo de ejecución es proporcional al direccionamiento de lainstrucción

}

Page 247: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 22

Transformacionesdependientesdelentornodeejecución

SeleccióndeldireccionamientoparalatraducciónComo acabamos de ver, en la medida de lo posible hay que tratar de asignar un direccionamiento a registro a aquellos objetos de datos más referenciados durante el programa dejando los menos referidos en memoria. Para llevar esto a la práctica deben gestionarse los lugares donde reside cada objeto y esto se hace definiendo descriptores de registro y memoria para el entorno de ejecución

Descriptor de registro

Descriptor de memoria

El descriptor de un registro indica la colección de objetos de datos – variables globales o locales, parámetros o temporales – que dicho reg is t ro mant iene en la ac tua l idad. Naturalmente si es más de uno es porque todos ellos comparten el mismo valor

Un descriptor de registro indica la colección de

objetos de datos que está almacenando en un

momento concreto dentro del tiempo de

ejecución

Los descriptores de memoria indican las posiciones de memoria o registros donde cada objeto se encuentra almacenado cada objeto de datos en un momento determinado dentro del tiempo de ejecución. Naturalmente un objeto puede estar en dos o más posiciones distintas

Un descriptor de memoria indica los lugares de

la memoria donde un objeto de datos está

almacenado incluyendo los registros del entorno

de ejecución

Page 248: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 23

Transformacionesdependientesdelentornodeejecución

SeleccióndeldireccionamientoparalatraducciónComo acabamos de ver, en la medida de lo posible hay que tratar de asignar un direccionamiento a registro a aquellos objetos de datos más referenciados durante el programa dejando los menos referidos en memoria. Para llevar esto a la práctica deben gestionarse los lugares donde reside cada objeto y esto se hace definiendo descriptores de registro y memoria para el entorno de ejecución

Descriptor de registro

Descriptor de memoria

El descriptor de un registro indica la colección de objetos de datos – variables globales o locales, parámetros o temporales – que dicho reg is t ro mant iene en la ac tua l idad. Naturalmente si es más de uno es porque todos ellos comparten el mismo valor

Los descriptores de memoria indican las posiciones de memoria o registros donde cada objeto se encuentra almacenado cada objeto de datos en un momento determinado dentro del tiempo de ejecución. Naturalmente un objeto puede estar en dos o más posiciones distintas

Las técnicas de opAmización en este puntocons i s t en en s e l e c c i ona r s i emprepreferentemente un registro a una posicióndememoriacomolugardealmacenamientodandoprioridadaaquellosobjetosqueseanmásreferenciados.ParasaberelnúmerodereferenciassepuedeusarelGDAdelbloque

}

}

Asimismo es necesario saber aplicarmovimientos de datos hacia la memoriapara conseguir liberar los registros puestoquesonun recurso limitadodelentornodeejecución

+[a,b]

x 1

*[x,c]

Page 249: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 24

Transformacionesdependientesdelentornodeejecución

SeleccióndeldireccionamientoparalatraducciónComo acabamos de ver, en la medida de lo posible hay que tratar de asignar un direccionamiento a registro a aquellos objetos de datos más referenciados durante el programa dejando los menos referidos en memoria. Para llevar esto a la práctica deben gestionarse los lugares donde reside cada objeto y esto se hace definiendo descriptores de registro y memoria para el entorno de ejecución

Ejemplo

E:MULt2fxMVft2SUBt3x1MVxt3EQt4x0BRFE

*[f,t2]

f x

==[t4]

1 0

-[x,t3]

C.Intermedio C.Final

E:MULt2fxMVft2SUBt3x1MVxt3EQt4x0BRFE

E:MOVE.R0/1001MOVE.R1/1000MUL.R0.R1

C.Intermedio C.Final

D.Memoria

x/1000f/1001t2-t3-t4-1#10#0

D.Registro

.R0-

.R1-

.R2-

.R3-

.R4-

.R5-

D.Memoria

x/1000,.R1f/1001t2.R0t3-t4-1#10#0

D.Registro

.R0f,t2

.R1x

.R2-

.R3-

.R4-

.R5-

Page 250: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 25

Transformacionesdependientesdelentornodeejecución

SeleccióndeldireccionamientoparalatraducciónComo acabamos de ver, en la medida de lo posible hay que tratar de asignar un direccionamiento a registro a aquellos objetos de datos más referenciados durante el programa dejando los menos referidos en memoria. Para llevar esto a la práctica deben gestionarse los lugares donde reside cada objeto y esto se hace definiendo descriptores de registro y memoria para el entorno de ejecución

Ejemplo

E:MULt2fxMVft2SUBt3x1MVxt3EQt4x0BRFE

*[f,t2]

f x

==[t4]

1 0

-[x,t3]

C.Intermedio C.Final

E:MULt2fxMVft2SUBt3x1MVxt3EQt4x0BRFE

E:MOVE.R0/1001MOVE.R1/1000MUL.R0.R1MOVE.R2#1SUB.R1.R2MOVE.R3#0CMP.R1.R3BZE

C.Intermedio C.Final

E:MOVE.R0/1001MOVE.R1/1000MUL.R0.R1MOVE.R2#1SUB.R1.R2

D.Memoria

x/1000,.R1f/1001t2.R0t3.R1t4-1#10#0

D.Registro

.R0f,t2

.R1x,t3

.R21

.R3-

.R4-

.R5-

D.Memoria

x/1000,.R1f/1001t2.R0t3.R1t4-1#10#0

D.Registro

.R0f,t2

.R1x,t3

.R21

.R30

.R4-

.R5-

Page 251: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 26

Bibliogra^a

MaterialdeestudioBibliografía básica

Construcción de compiladores: principios y práctica

Kenneth C. Louden International Thomson Editores,

2004 ISBN 970-686-299-4

Page 252: Procesadores de Lenguajes I

Javier Vélez Reyes [email protected]

Estrategiasdeop8mización.Códigointermedioycódigofinal

11 - 27

Bibliogra^a

MaterialdeestudioBibliografía complementaria

Compiladores: Principios, técnicas y herramientas.

Segunda Edición Aho, Lam, Sethi, Ullman

Addison – Wesley, Pearson Educación, México 2008

Diseño de compiladores. A. Garrido, J. Iñesta, F. Moreno

y J. Pérez. 2002. Edita Universidad de Alicante