4. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 2
Obje6vos Generales
Obje8vos Generales
› 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
5. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
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
6. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 4
Introducción
¿Qué es la semán8ca de un lenguaje?
Analizador léxico
Analizador sintác8co
Analizador
semán8co
Código intermedio
Código final
e · l · i · h · w <WHILE, PR> S
WHILE E DO S
E > E
S
WHILE E DO S
E > E
√ 0000 0011
0000 0011
0100 0001
0100 0000
0001 0010
…
While ( a > b ) do
a := a + 1;
Etapa de análisis Etapa de síntesis
LD a t1
LD b t2
GRT t3 t1 t2
BRZ t3 L1 …
¿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
7. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 5
Introducción
¿Qué es la semán8ca de un lenguaje?
PROGRAM BubbleSort;
CONST MAX = 100;
TYPE TVector = ARRAY [1..MAX] OF INTEGER;
VAR v: TVector;
PROCEDURE ReadVector (VAR v : TVector); ...
PROCEDURE Sort (VAR v : TVector, size : INTEGER);
VAR i, j, tmp : INTEGER;
BEGIN
FOR i := size - 1 DOWNTO 1 DO
FOR j := 1 TO i DO
IF (v[j] > v[j + 1]) THEN
BEGIN
tmp := v[j];
v[j] := v[j + 1];
v[j + 1] := tmp;
END;
END;
BEGIN
ReadVector (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, tipos, variables,
funciones y procedimientos, las
sentencias, expresiones, etc. que
en él aparecen?
8. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 6
Introducción
¿Qué es la semán8ca de un lenguaje?
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ón dirigida por la sintaxis
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 ::= TYPE ID = ARRAY [N..N]
OF Tipo;
9. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 7
Introducción
¿Qué es la semán8ca de un lenguaje?
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ón dirigida por la sintaxis
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
Tipos de acciones
de traducción
semán8ca
Tiempo de compilación (semán8ca está8ca)
Tiempo de ejecución (semán8ca diná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
}
Tema 7
}
Tema 8, 9
10. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 8
Introducción
¿Qué es la semán8ca de un lenguaje?
CONST MAX = 100; R e g i s t r a r M A X c o m o
constante entera de valor
100
Traducción semán8ca Construcción sintac8ca
Tipo Ejemplo Tiempo de compilación Tiempo de ejecución
Declaración de
constantes
TYPE TVector = ARRAY [1..MAX] OF INTEGER;Declaración de
6pos
Registrar TVector como 6po
ARRAY de tamaño 100 y base
INTEGER
VAR v : TVector;Declaración de
variables
Comprobar que TVector
existe como un 6po y
registrar v como una variable
de ese 6po
–
–
–
PROCEDURE Sort (VAR v : TVector); Declaración de
procedimientos
Registrar Sort como un
procedimiento del ámbito en
curso indicando la lista de
6pos de los parámetros.
Crear un nuevo ámbito y
registrar en él v como
variable de 6po TVector
–
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ón dirigida por la sintaxis
11. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 9
Introducción
¿Qué es la semán8ca de un lenguaje?
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ón semán8ca Construcción sintac8ca
Tipo Ejemplo Tiempo de compilación Tiempo de ejecución
Function Sort (VAR v : TVector):INTEGER; Declaración de
funciones
Adicionalmente al caso de
procedimientos registrar que
el 6po de retorno es INTEGER
–
v[j] > v[j + 1] Expresiones Comprobar que v esta
declarado previamente y que
e s d e 6 p o T V e c t o r .
Asegurarse de que las sub-
expresiones son correctas y
de 6pos compa6bles con el
operador mayor que
Generar código para
recuperar de memoria el
valor de las sub-expresiones
y aplicar la comparación
entre ambos con los
operadores del lenguaje de
bajo nivel
Sentencia For FOR j := 1 TO i DO
...
Comprobar que la expresión
1 e i son de 6po INTEGER.
Comprobar que j ha sido
previamente declarada como
una variable de 6po INTEGER
Generar código para
inicializar j a 1. Generar
código de salto para iterar
la ejecución del bloque
dentro de FOR i veces.
Generar código para
actualizar a cada paso el
valor de j a j + 1
Traducción dirigida por la sintaxis
12. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 10
Introducción
¿Qué es la semán8ca de un lenguaje?
Traducción semán8ca Construcción sintac8ca
Tipo Ejemplo Tiempo de compilación Tiempo de ejecución
Sentencia If IF (v[j] > v[j + 1]) THEN
BEGIN
tmp := v[j];
v[j] := v[j + 1];
v[j + 1] := tmp;
END;
Comprobar que la expresión
d e c o m p a r a c i ó n e s
semán6camente correcta
(ver anterior) y comprobar
que su evaluación devuelve
un 6po lógico
Generar código para
evaluar la expresión
durante la ejecución.
Generar código de salto que
ejecute el bloque THEN si la
evaluación da TRUE en
ejecución
Sentencia de
asignación
tmp := v[j]; Comprobar que tmp esta
definido. Comprobar que el
6po de base de v es
compa6ble con el de tmp
Generar código para
evaluar el valor de v[j] y
copiar su valor en la
posición de memoria
apuntada por tmp
Sentencia de
llamada a
procedimiento
sort (v, MAX); Comprobar que Sort esta
declarado como procedi-
miento y que el número,
o r d e n y 6 p o d e l o s
parámetros actuales y
formales coinciden
Generar código para
ges6onar memoria que
permita la ac6vación del
p r o c e d i m i e n t o S o r t .
Generar código de salto
para su ejecució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ón dirigida por la sintaxis
13. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 11
Formalismos para la especificación de traducciones
Especificación de traducciones dirigidas por la sintaxis
Una 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
Formalismos para la especificación de traducciones dirigidas por la sintaxis
I. Definiciones dirigidas por la sintaxis
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. Esquemas de traducción dirigidos por la sintaxis
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
14. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 12
Definiciones dirigidas por la sintaxis
Definiciones dirigidas por la sintaxis
Las 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.
Elementos de las definiciones dirigidas por la sintaxis
declaracion ::= lVariables : tipo
lVariables ::= lVariables1 , ID
lVariables ::= ID
tipo ::= INTEGER ;
tipo ::= REAL ;
lVariables.tipo := tipo.tipo
lVariables1.tipo := lVariables.tipo
<<registrar ID como variable de tipo tipo>>
<<registrar ID como variable de tipo tipo>>
tipo.tipo := “ENTERO”
tipo.tipo := “REAL”
I. Gramá8ca con atributos II. Reglas semán8cas
A 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
<<registrar ID como variable de tipo tipo>>
Reglas semánticasReglas de producción
atributo
Subíndice de
diferenciación
15. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 13
Definiciones dirigidas por la sintaxis
Definiciones dirigidas por la sintaxis
Las 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. Atributos sinte8zados
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
8pos de
atributos II. Atributos heredados
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
16. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 14
Definiciones dirigidas por la sintaxis
Definiciones dirigidas por la sintaxis
Las 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.
Reglas semá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. Reglas de ecuaciones de atributos
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 ||
8pos de
reglas
semán8cas
II. Reglas de acción semá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
<<registrar ID como variable ...>>
No terminal Terminal o
No terminal
asignación
atributo
17. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 15
Definiciones dirigidas por la sintaxis
Definiciones dirigidas por la sintaxis
Las 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.
Grafos de dependencias
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ánticas inducen ciertas
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
Calcular A.a
Calcular C.c
Calcular D.d
Calcular B.b
en cualquier
orden
Calcular después
18. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 16
Definiciones dirigidas por la sintaxis
Definiciones dirigidas por la sintaxis
Las 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.
Grafos de dependencias
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
Algoritmo de cálculo
Para cada producción A ::= X1 X2 ... Xn
Crear un nodo por cada atributo Xi.aj de cada símbolo
Para cada regla semántica de la forma Xi.aj = f (... , Xk.al, ...)
Para cada k y cada l
Crear arco desde Xk.al hasta Xi.aj
Unir todos los grafos resultantes
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
19. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 17
Definiciones dirigidas por la sintaxis
Definiciones dirigidas por la sintaxis
Las 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.
Grafos de dependencias
a, b : INTEGER; declaracion ::= lVariables : tipo
lVariables ::= lVariables1 , ID
lVariables ::= ID
tipo ::= INTEGER ;
tipo ::= REAL ;
lVariables.tipo := tipo.tipo
lVariables1.tipo := lVariables.tipo
<<registrar ID como variable de tipo tipo>>
<<registrar ID como variable de tipo tipo>>
tipo.tipo := “ENTERO”
tipo.tipo := “REAL”
declaración
lVariables tipo
INTEGERID
:
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]
<<registrar ID con tipo>>
<<registrar ID con tipo>>
20. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 18
Definiciones dirigidas por la sintaxis
Definiciones dirigidas por la sintaxis
Las 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ño de definiciones dirigidas por la sintaxis
El 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ón grama8cal
Construya 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ón de una frase representa8va
Seleccione 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ón del árbol de análisis
Construya 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ón de atributos
Defina 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. Grafo de dependencias
Dibuje el grafo de dependencias que debería
producirse para asegurar que la información
fluya adecuadamente. Considere siempre un
procesamiento descendente
VI. Especificación de la definición
Escriba 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
21. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 19
Definiciones dirigidas por la sintaxis
Definiciones dirigidas por la sintaxis
Las 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.
Ejemplo
Se 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 +
FT *
n
n
F
T
n
Ž
E.value [Sintetizado]
T.value [Sintetizado]
F.value [Sintetizado]
n.value [Sintetizado]
E
T
F
E +
FT *
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 + T E.value := E.value + T.value
E ::= E – T E.value := E.value - T.value
E ::= T E.value := T.value
T ::= T * F T.value := T.value * F.value
T ::= T / F T.value := T.value / F.value
T ::= F T.value := F.value
F ::= ( E ) F.value := E.value
F ::= n F.value := n.value
.value
.value
.value
22. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 20
Definiciones dirigidas por la sintaxis
Definiciones dirigidas por la sintaxis
Las 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 ::= D B | 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 ::= D N | 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
23. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 21
Definiciones dirigidas por la sintaxis
Definiciones dirigidas por la sintaxis
Las 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á8cas con atributos por la izquierda
En 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
INTEGERID
:
lVariables ,
ID
.tipo .tipo
.tipo
“ENTERO”
“ENTERO”
“ENTERO”
<<registrar ID con tipo>>
<<registrar ID con tipo>>
24. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 22
Definiciones dirigidas por la sintaxis
Definiciones dirigidas por la sintaxis
Las 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á8cas con atributos por la izquierda
Este 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
Tipos de
traductores
I. Traductores de una sola pasada
II. Traductores de doble pasada
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
25. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 23
Definiciones dirigidas por la sintaxis
Definiciones dirigidas por la sintaxis
Las 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á8cas con atributos por la izquierda
Los 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 , declaracion1 declaracion.tipo = declaracion1.tipo
<<registrar ID con tipo>>
declaracion ::= ID : tipo declaracion.tipo = tipo.tipo
<<registrar ID con tipo>>
tipo ::= INTEGER ; tipo.tipo :=“ENTERO”
tipo ::= REAL ; tipo.tipo := “REAL”
declaración
ID declaración,
.tipo
“ENTERO”
“ENTERO”
a, b : INTEGER;
ID tipo:
INTEGER
<<registrar ID con tipo>>
<<registrar ID con tipo>>
.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
}
26. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 24
Definiciones dirigidas por la sintaxis
Definiciones dirigidas por la sintaxis
Las 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á8cas con atributos por la izquierda
Dados 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
}
27. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 25
Esquemas de traducción dirigidos por la sintaxis
Esquemas de traducción dirigidos por la sintaxis
Las 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
Elementos de las traducciones dirigidas por la sintaxis
I. Gramá8ca con atributos II. Acciones semán8cas
Como 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 :}
28. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 26
Esquemas de traducción dirigidos por la sintaxis
Esquemas de traducción dirigidos por la sintaxis
Las 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. Atributos sinte8zados
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
8pos de
atributos II. Atributos heredados
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
29. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 27
Esquemas de traducción dirigidos por la sintaxis
Esquemas de traducción dirigidos por la sintaxis
Las 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ón semá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
lenguaje de programación
anfitrión del compilador que se
está construyendo
}
Como en las DDS, las acciones
semánticas frecuentemente
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
}
30. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 28
Esquemas de traducción dirigidos por la sintaxis
Esquemas de traducción dirigidos por la sintaxis
Las 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ño de traducciones dirigidas por la sintaxis
Antes 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 := B C {: A.a := f (B.a, C.a) :} D
A:= B C D {: A.a := f (B.a, C.a) :}
A := B C {: D.h := f (B.a, C.a) :} D
A := B {: A.s := f (B.s, C.s) :} C D
A := B C {: 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
31. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 29
Esquemas de traducción dirigidos por la sintaxis
Esquemas de traducción dirigidos por la sintaxis
Las 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ño de traducciones dirigidas por la sintaxis
El 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ón grama8cal
Construya 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ón de una frase representa8va
Seleccione 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ón del árbol de análisis
Construya 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ón de atributos
Defina 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. Grafo de dependencias
Dibuje el grafo de dependencias que debería
producirse para asegurar que la información
fluya adecuadamente. Considere siempre un
procesamiento descendente
VI. Especificación de la traducción
Escriba la traducción dirigida por la sintaxis
ubicando las acciones semánticas de acuerdo a
las restricciones de diseño preliminares
32. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 30
Esquemas de traducción dirigidos por la sintaxis
Esquemas de traducción dirigidos por la sintaxis
Las 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
Ejemplo
E
T E’{: E’.trad := ‘9’ :} {: E.trad := ‘9 5 – 2 +’ :}
num
(9)
{: T.trad := ‘9’ :} - T E’{: E’1.trad := ‘9 5 -’ :} {: E’.trad := ‘9 5 – 2 +’ :}
num
(5)
{: T.trad := ‘5’ :} + T E’{: E’1.trad := ‘9 5 – 2 +’ :} {: E’.trad := ‘9 5 – 2 +’ :}
num
(2)
{: T.trad := ‘2’ :}
ε {: E’.trad := ‘9 5 – 2 +’ :}
33. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 31
Traducción dirigida por la sintaxis en la prác6ca
Esquemas de traducción en la prác8ca
El 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ón de clases No Terminales
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ón de la clase
Para 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
public Expresion extends NonTerminal {
...
}
34. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 32
Traducción dirigida por la sintaxis en la prác6ca
Esquemas de traducción en la prác8ca
El 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ón de clases No Terminales
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ón de constructores
Incluya 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
public Expresion extends NonTerminal {
...
public Expresion () { ... }
public Expresion (Expresion e) {...}
public Expresion (Expresion left,
Expresion right) {...}
}
35. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 33
Traducción dirigida por la sintaxis en la prác6ca
Esquemas de traducción en la prác8ca
El 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ón de clases No Terminales
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ón atributos
Declare 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
public Expresion extends NonTerminal {
List<QuadrupleIF> code;
TypeIF type;
TemporalIF temporal;
...
public List<QuadrupleIF> getCode () {...}
public void setCode (List<QuadrupleIF> code) {...}
public TypeIF getType() {...}
public void setType (TypeIF type) {...}
public TemporalIF getTemporal () {...}
public void setTemporal (TemporalIF temporal) {...}
...
}
36. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 34
Traducción dirigida por la sintaxis en la prác6ca
Esquemas de traducción en la prác8ca
El 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ón de clases No Terminales
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. Sobrescritura de métodos de Object
Java 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.
Recomendamos encarecidamente la
implementación de estos tres métodos puesto
que puede simplificar considerablemente la
construcción del compiladores en fases
subsiguientes
public Expresion extends NonTerminal {
...
long hashcode () {
return 67 * 67 * code.hashcode() +
67 * type.hashcode() + temporal.hascode();
}
boolean equals (Object o) {
if (!(o instanceof Expresion)) return false;
else { Expression e = (Expresion) o;
return e.code.equals(this.code) &&
e.type.equals(this.type) &&
e.temporal.equals(this.temporal); }
}
public String toString () {...}
}
37. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 35
Traducción dirigida por la sintaxis en la prác6ca
Esquemas de traducción en la prác8ca
El 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ón de No Terminales en cup
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
38. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 36
Traducción dirigida por la sintaxis en la prác6ca
Esquemas de traducción en la prác8ca
El 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ón del esquema de traducción en cup
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:e1 MAS expresion:e2
{: Expresion e = new Expresion (e1, e2);
<<comprobación de tipos sobre e1 y e2>>
<<generación de código para e1 + 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
39. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 37
Traducción dirigida por la sintaxis en la prá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
Desarrollo paso a paso
La 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
40. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 38
Bibliograna
Material de estudio
Bibliografía básica
Construcción de compiladores: principios y práctica
Kenneth C. Louden International Thomson Editores,
2004 ISBN 970-686-299-4
41. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semán8co. Traducción dirigida por la sintaxis
6 - 39
Bibliograna
Material de estudio
Bibliografí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
43. Javier Vélez Reyes jvelez@lsi.uned.es
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
44. Javier Vélez Reyes jvelez@lsi.uned.es
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
45. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 4
Introducción
Análisis semán8co
La 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
El analizador semántico va
comprobando la coherencia
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
Analizador
semán8co
SWhile
WHILE E DO S
E > E
SWhile
WHILE E DO S
E > E
ü ü
ü ü
ü
46. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 5
Introducción
Conceptos esenciales
Los 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
CONST MAX = 10;
TYPE TVector = ARRAY [1..10] OF REAL;
VAR v, w : TVector;
i : INTEGER;
PROCEDURE Leer (VAR m: TVector);
VAR i : INTEGER;
FUNCTION Validar (VAR v: INTEGER): INTEGER;
BEGIN
Validar := v mod 10;
END;
BEGIN
FOR i := 1 TO 10 DO
m [i] := Validar (Read (i));
END;
END;
FUNCTION suma (m, n: TVector) : TVector;
VAR i : INTEGER;
vSuma : TVector;
BEGIN
WHILE (i < MAX) DO
vSuma [i] := m[i] + n[i];
INC (i);
END;
suma := vSuma;
END;
BEGIN
Leer (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
47. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 6
Introducción
Conceptos esenciales
Los 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
CONST MAX = 10;
TYPE TVector = ARRAY [1..10] OF REAL;
VAR v, w : TVector;
i : INTEGER;
PROCEDURE Leer (VAR m: TVector);
VAR i : INTEGER;
FUNCTION Validar (VAR v: INTEGER): INTEGER;
BEGIN
Validar := v mod 10;
END;
BEGIN
FOR i := 1 TO 10 DO
m [i] := Validar (Read (i));
END;
END;
FUNCTION suma (m, n: TVector) : TVector;
VAR i : INTEGER;
vSuma : TVector;
BEGIN
WHILE (i < MAX) DO
vSuma [i] := m[i] + n[i];
INC (i);
END;
suma := vSuma;
END;
BEGIN
Leer (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
48. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 7
Introducción
Conceptos esenciales
Los 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
Ámbitos de declaración y alcance de visibilidad
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 lenguajes estilo C,
además de las funciones y el
ámbito global, cualquier
bloque de sentencias acotado
entre llaves constituye un
ámbito de declaración nuevo
CONST MAX = 10;
TYPE TVector = ARRAY [1..10] OF REAL;
VAR v, w : TVector;
i : INTEGER;
PROCEDURE Leer (VAR m: TVector);
VAR i : INTEGER;
FUNCTION Validar (VAR v: INTEGER): INTEGER;
BEGIN
Validar := v mod 10;
END;
BEGIN
FOR i := 1 TO 10 DO
m [i] := Validar (Read (i));
END;
END;
FUNCTION suma (m, n: TVector) : TVector;
VAR i : INTEGER;
vSuma : TVector;
BEGIN
WHILE (i < MAX) DO
vSuma [i] := m[i] + n[i];
INC (i);
END;
suma := vSuma;
END;
BEGIN
Leer (v);
Leer (w);
v := suma (v, w);
END.
49. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 8
Introducción
Conceptos esenciales
Los 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
Anidamiento de á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
CONST MAX = 10;
TYPE TVector = ARRAY [1..10] OF REAL;
VAR v, w : TVector;
i : INTEGER;
PROCEDURE Leer (VAR m: TVector);
VAR i : INTEGER;
FUNCTION Validar (VAR v: INTEGER): INTEGER;
BEGIN
Validar := v mod 10;
END;
BEGIN
FOR i := 1 TO 10 DO
m [i] := Validar (Read (i));
END;
END;
FUNCTION suma (m, n: TVector) : TVector;
VAR i : INTEGER;
vSuma : TVector;
BEGIN
WHILE (i < MAX) DO
vSuma [i] := m[i] + n[i];
INC (i);
END;
suma := vSuma;
END;
BEGIN
Leer (v);
Leer (w);
v := suma (v, w);
END.
Regla de anidamiento más cercano
ámbitonivel0
ámbitonivel1ámbitonivel1
ámbitonivel2
50. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 9
Introducción
¿Qué es la comprobación de 8pos?
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álisis semán8co
Generación código
intermedio
S
WHILE E DO S
E > E
S
WHILE E DO S
E > E
√
LD a t1
LD b t2
GRT t3 t1 t2
BRZ t3 L1 …
I. Comprobaciones está8cas
II. Comprobaciones diná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
Tipos de comprobaciones semán8cas
Tema 7
}
Tema 8-9
}
51. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 10
Introducción
Tipos de comprobaciones semán8cas está8cas
I. Ges8ón de declaraciones
III. Inferencia de 8pos
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ón de 8pos
Comprueba 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é es la comprobación de 8pos?
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
CONST MAX = 10;
TYPE TVector = ARRAY [1..10] OF REAL;
VAR v, w : TVector;
i : INTEGER;
PROCEDURE Leer (VAR m: TVector);
Validar := v mod 10;
WHILE (i < MAX) DO ...
v := suma (v, w);
CONST MAX = 10;
52. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 11
Sistemas de 6pos
¿Qué es el sistema de 8pos?
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
Niveles de 8pificación
El 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
Niveles de
8pificación
Lenguajes fuertemente 8pificados
Lenguajes débilmente 8pificados
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
53. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 12
Sistemas de 6pos
¿Qué es el sistema de 8pos?
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
Expresiones de 8pos
Para 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
54. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 13
Sistemas de 6pos
Elementos de un sistema de 8pos
La 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
Tipos primi8vos
Expresión de 8pos Tipo
Byte
Integer
Word
Real
Double
Boolean
Char
String
Representación numérica corta sin signo
Representación numérica con signo
Representación numérica larga sin signo
Representación flotante corta con signo
Representación flotante larga con signo
Representación lógica
Representación de carácter
Representación de cadena
Descripción Rango
0 a 255
-32768 a 32767
0 a 65535
2.9E-39 a 1.7E38
5.0E-324 a 1.7E308
False, True
ASCII
-
ENTERO
ENTERO
ENTERO
REAL
REAL
LOGICO
CARÁCTER
CADENA
Operaciones
+ – * / mod = > < <>
+ – * / mod = > < <>
+ – * / mod = > < <>
+ – * / = > < <>
+ – * / = > < <>
AND OR XOR NOT
-
-
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
55. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 14
Sistemas de 6pos
Elementos de un sistema de 8pos
La 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
Constructores de 8pos
Expresión de 8pos Ejemplo
TVector = ARRAY [1..10] OF INTEGER Representa una formación lineal de
elementos de un mismo 6po de base
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 = RECORD BEGIN
X: INTEGER;
Y: INTEGER
END;
Representa una estructura de datos
cons6tuida por una colección de
campos con nombre de dis6nto 6po
RECORD ( (X x ENTERO) x (Y x ENTERO) )
^ TPunto Representa un puntero a un área de
memoria reservada para almacenar
datos de un determinado 6po de base
POINTER (TPunto)
TConjunto = SET OF INTEGER Representa un conjunto no ordenado
de elemento de un mismo 6pos de
datos de base
SET (ENTERO)
56. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 15
Sistemas de 6pos
Elementos de un sistema de 8pos
La 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
Constructores de 8pos
Expresión de 8pos Ejemplo
FUNCTION suma (m, n: TVector):
Tvector;
Representa una declaración de función
con parámetros y 6po de retorno
definido
Descripción
(Tvector x TVector) " 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
PROCEDURE Leer ( n: TVector); Representa una declaración de
procedimiento con parámetros
definidos
(Tvector) " TVector
(INTEGER; INTEGER) Representa una tupla de datos
cons6tuida por una colección ordenada
de datos de dis6nto 6po
(ENTERO) x (ENTERO)
TPalos = (OROS, COPAS,
ESPADAS, BASTOS);
Representa una colección de e6quetas
que se comportan como constantes
simbólicas de valor numérico
ENUM (OROS, COPAS, ESPADAS, BASTOS)
57. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 16
Sistemas de 6pos
Elementos de un sistema de 8pos
La 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
Constructores de 8pos
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
Ejercicios
Una 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 = RECORD
BEGIN
nombre: STRING;
edad : INTEGER;
END;
FUNCTION mayor (a, b: INTEGER): INTEGER;
FUNCTION ordenar (p: TPEntero) : TPEntero;
TLista = RECORD
BEGIN
vector: ARRAY [1..10] OF INTEGER;
longitud: INTEGER;
END;
TTabla = ARRAY [1..100] OF ^TLista;
TCjtoTablas = SET OF ^TTabla;
58. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 17
Sistemas de 6pos
Elementos de un sistema de 8pos
La 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
Equivalencia de 8pos
De 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. Equivalencia nominal
TYPE
T1 = ARRAY [1..10] OF INTEGER;
T2 = ARRAY [1..10] OF INTEGER;
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
No equivalente
Equivalente
No equivalente
Equivalente
No Equivalente
Equivalente
No equivalente
Equivalente
T1 T2 T3
59. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 18
Sistemas de 6pos
Elementos de un sistema de 8pos
La 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
Equivalencia de 8pos
De 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. Equivalencia estructural
TYPE
T1 = ARRAY [1..10] OF INTEGER;
T2 = ARRAY [1..10] OF INTEGER;
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 aplicació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
60. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 19
Sistemas de 6pos
Elementos de un sistema de 8pos
La 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
Equivalencia de 8pos
De 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. Equivalencia estructural
boolean equivale (TypeIF s, TypeIF t) {
if (s == t) return true;
if ((s == ARRAY (s1, s2) && t == ARRAY (t1,t2)) ||
(s == (s1 x s2) && t == (t1 x t2)) ||
(s == (s1 " s2) && t == (t1 " t2)))
return equivale (s1,t1) && equivale (t2, t2);
if ((s == Pointer (s1) && t == Pointer (t1)) ||
(s == Set (s1) && t == Set (t1))
return equivale (s1,t1);
return false
}
Se dice que dos tipos de datos son
estructuralmente equivalentes si son el
mismo tipo básico o están formadas
mediante la aplicación del mismo
constructor de tipos sobre expresiones de
tipos estructuralmente equivalentes
Ojo con las definiciones de
tipos recursivos
}
61. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 20
Sistemas de 6pos
Elementos de un sistema de 8pos
La 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ón de 8pos sobre operadores
La 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. Sobrecarga de operadores
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 Fortran La 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
62. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 21
Sistemas de 6pos
Elementos de un sistema de 8pos
La 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ón de 8pos sobre operadores
La 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. Compa8bilidad de 8pos
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 C La 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
operados a través de un operador
sobrecargado
63. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 22
Sistemas de 6pos
Elementos de un sistema de 8pos
La 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ón de 8pos sobre operadores
La 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ón de 8pos
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 C La compatibilidad de tipos permite operar
expresiones de tipos diferentes 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
64. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 23
Sistemas de 6pos
Elementos de un sistema de 8pos
La 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ón de 8pos sobre operadores
La 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
...
Byte Integer Word Real Double Boolean Char String …
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
65. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 24
Sistemas de 6pos
Elementos de un sistema de 8pos
La 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ón de 8pos sobre subprogramas
La 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
TYPE TVector = ARRAY [1..10] OF INTEGER
TMatriz = ARRAY [1..10][1..5] OF INTEGER
VAR v, w: Tvector; m, n : TMatriz;
PROCEDURE sumar (v, w: TVector; VAR r:TVector); ...
PROCEDURE sumar (m, n: TMatriz; VAR r:TMatriz); ...
}
66. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 25
Construcción de comprobadores de 6pos en la prác6ca
¿Qué es un comprobador de 8pos?
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:e1 MAS expresion:e2
{: t1 = <<recuperar tipo de e1>>
t2 = <<recuperar tipo de e2>>
<<Comprobar la compatibilidad de t1 y t2 para +>>
No: <<Error semántico>>
si: <<otras acciones semá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
}
67. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 26
Construcción de comprobadores de 6pos en la prác6ca
Artefactos de un comprobador de 8pos
Antes 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
68. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 27
Construcción de comprobadores de 6pos en la prác6ca
Artefactos de un comprobador de 8pos
Antes 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
Tipos primi8vos y constructores de 8pos
Las 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
- String name
- ScopeIF scope
+ String getName ()
+ void setName (String name)
+ ScopeIF getScope ()
+ void setScope (ScopeIF scope)
+ int getSize()
+ boolean equals ()
+ 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
Propiedad name y scope
Equivalencia de 8pos
Para 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
Sobrescritura de métodos de Object
Igualmente se recomienda la implementación de los
métodos hashcode y toString heredados de clase
Object. Consulte tema 6 para obtener detalles
69. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 28
Construcción de comprobadores de 6pos en la prác6ca
Artefactos de un comprobador de 8pos
Antes 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
Tipos primi8vos y constructores de 8pos
Las 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
TypeEnum TypeSet TypePointer TypeProcedure
- String name
- ScopeIF scope
- int size
TypeArray
- String name
- ScopeIF scope
- int min
- int max
- TypeIF base
- String name
- Map <String, TypeIF> fields
- ScopeIF scope
- String name
- TypeIF base
- ScopeIF scope
- String name
- List <String> values
- ScopeIF scope
- String name
- ScopeIF scope
- TypeIF base
- String name
- List <TypeIF> parameters
- ScopeIF scope
TypeFunction
- TypeIF rType
- ScopeIF scope
- String name
- Map <String, TypeIF> baseFields
- Map <String, Map<String, TypeIF>> variants
- ScopeIF scope
70. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 29
Construcción de comprobadores de 6pos en la prác6ca
Artefactos de un comprobador de 8pos
Antes 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ímbolos
Las 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
- String name
- TypeIF type
- ScopeIF scope
+ String getName ()
+ void setName (String name)
+ ScopeIF getScope ()
+ void setScope (ScopeIF scope)
+ TypeIF getType ()
+ void setType (TypeIF type)
+ boolean equals ()
+ 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
Propiedad name y scope
Propiedad Tipo
De 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
Sobrescritura de métodos de Object
Igualmente se recomienda la implementación de los
métodos hashcode y toString heredados de clase
Object. Consulte tema 6 para obtener detalles
71. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 30
Construcción de comprobadores de 6pos en la prác6ca
Artefactos de un comprobador de 8pos
Antes 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ímbolos
Las 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
SymbolProcedure SymbolConstant SymbolParameter SymbolVariable
- String name
- TypeIF type
- ScopeIF scope
- Integer address
- String name
- TypeIF type
- ScopeIF scope
- String name
- TypeIF type
- ScopeIF scope
- String name
- TypeIF type
- Number value
- ScopeIF scope
SymbolFunction
- String name
- TypeIF Type
- ScopeIF scope
Al igual que en el caso de los tipos, estas
definiciones serán potencialmente
extendidas cuando avancemos en la
construcción del compilador
}
72. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 31
Construcción de comprobadores de 6pos en la prác6ca
Artefactos de un comprobador de 8pos
Antes 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
Gestor de errores semán8cos y trazabilidad
Cuando 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
+ void semantiDebug (String message)
+ void semanticInfo (String message)
+ void semanticWarn (String message)
+ void semanticError (String message)
+ void semanticFatal (String message)
exp ::= exp:e1 MAS exp:e2 {:
TypeIF t1 = <<obtener tipo e1>>
TypeIF t2 = <<obtener tipo e2>>
semanticErrorManager.semanticDebug (“Tipo de e1:” + t1);
semanticErrorManager.semanticDebug (“Tipo de e2:” + t2);
if (t1.isCompatible (t2, TypeIF.MAS)) {
...
} else semanticErrorManager.semanticFatalError (“tipos incompatibles”);
:}
73. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 32
Construcción de comprobadores de 6pos en la prác6ca
Artefactos de un comprobador de 8pos
Antes 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
Tablas de 8pos
Una 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
Private ScopeIF scope;
private Map <String, TypeIF> tTable;
public TypeTable (ScopeIF scope) {
this.scope = scope;
tTable = new HashMap<String, TypeIF> ();
}
public TypeIF getType (String id) {
return tTable.get (id);
}
public void addType (TypeIF type) {
String id = type.getName ();
addType (id, type); }
TypeTable (continúa)
public void addType (String id, TypeIF type){
type.setScope (this.scope);
tTable.put (id, type);
}
public boolean containsType (String id) {
return tTable.containsKey (id);
}
public boolean containsType (TypeIF type) {
String id = type.getName ();
return containsType (id);
}
...
74. Javier Vélez Reyes jvelez@lsi.uned.es
Análisis semántico. Comprobación de tipos
7 - 33
Construcción de comprobadores de 6pos en la prác6ca
Artefactos de un comprobador de 8pos
Antes 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
Tablas de símbolos
Una 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
Private ScopeIF scope;
private Map <String, SymbolIF> sTable;
public SymbolTable() {
sTable = new HashMap<String, SymbolIF> ();
}
public SymbolIF getSymbol (String id) {
return sTable.get (id);
}
public void addSymbol (SymbolIF symbol) {
String id = symbol.getName ();
addSymbol (id, symbol);
}
SymbolTable(continúa)
public void addSymbol (String id, SymbolIF symbol){
symbol.setScope (this.scope);
sTable.put (id, symbol);
}
public boolean containsSymbol (String id) {
return sTable.containsKey (id);
}
public boolean containsSymbol (SymbolIF symbol) {
String id = symbol.getName ();
return containsSymbol (id);
}
...