analisis semantico uam 08 09arantxa.ii.uam.es/.../analisis_semantico_uam_08_09.pdfuna variable de...

51
Prácticas de Procesadores de Lenguaje 2008-2009 1 Análisis semántico Notación Objetivo del análisis semántico Pasos para la construcción de un analizador semántico Análisis semántico con Bison Definición de los atributos semánticos Nivel de indirección en ALFA Declaración y unicidad de los identificadores Descripción general Gestión de ámbitos Inserción en la tabla de símbolos y unicidad Variables globales y locales Introducción Esquema general de la acción semántica de la producción 106 Propagación de las características de la declaración a las variables de la lista Acciones semánticas de las producciones 5, 6, 7 y 8 Acciones semánticas de las producciones 10, 11 y 12 Acciones semánticas de las producciones 13 y 14 Acciones semánticas de las producciones 15 y 16 Acción semántica de la producción 17 Ejemplo 1 Ejemplo 2 Acción semántica adecuada al ámbito de la variable Índice Marina de la Cruz Alfonso Ortega Prácticas de Procesadores de Lenguaje 2008-2009 2 Análisis semántico Parámetros de función Funciones Comprobación de la declaración de identificadores previa a su uso Comprobaciones semánticas en las expresiones aritméticas Comprobación de tipos Comprobación de niveles de indirección Implementación Comprobaciones semánticas en las expresiones lógicas Comprobación de tipos Comprobación de niveles de indirección Implementación Comprobaciones semánticas en las expresiones de comparación Comprobación de tipos Comprobación de niveles de indirección Implementación Comprobaciones semánticas para las constantes Introducción Implementación Índice

Upload: ngocong

Post on 29-Oct-2018

221 views

Category:

Documents


0 download

TRANSCRIPT

Prácticas de Procesadores de Lenguaje 2008-2009 1

Análisis semántico

� Notación� Objetivo del análisis semántico� Pasos para la construcción de un analizador semántico� Análisis semántico con Bison� Definición de los atributos semánticos� Nivel de indirección en ALFA� Declaración y unicidad de los identificadores

� Descripción general� Gestión de ámbitos� Inserción en la tabla de símbolos y unicidad

� Variables globales y locales� Introducción� Esquema general de la acción semántica de la producción 106� Propagación de las características de la declaración a las variables de la lista� Acciones semánticas de las producciones 5, 6, 7 y 8� Acciones semánticas de las producciones 10, 11 y 12� Acciones semánticas de las producciones 13 y 14� Acciones semánticas de las producciones 15 y 16� Acción semántica de la producción 17� Ejemplo 1� Ejemplo 2� Acción semántica adecuada al ámbito de la variable

Índice Marina de la Cruz

Alfonso Ortega

Prácticas de Procesadores de Lenguaje 2008-2009 2

Análisis semántico

� Parámetros de función� Funciones� Comprobación de la declaración de identificadores previa a su uso� Comprobaciones semánticas en las expresiones aritméticas

� Comprobación de tipos� Comprobación de niveles de indirección� Implementación

� Comprobaciones semánticas en las expresiones lógicas� Comprobación de tipos� Comprobación de niveles de indirección� Implementación

� Comprobaciones semánticas en las expresiones de comparación� Comprobación de tipos� Comprobación de niveles de indirección� Implementación

� Comprobaciones semánticas para las constantes� Introducción� Implementación

Índice

Prácticas de Procesadores de Lenguaje 2008-2009 3

Análisis semántico

� Comprobaciones semánticas para otras expresiones� Introducción� Implementación

� Comprobaciones semánticas en sentencias de asignación� Comprobación de tipos� Comprobación de niveles de indirección� Implementación

� Comprobaciones semánticas relativas a punteros� Reserva y liberación de memoria� Acceso al contenido apuntado

� Comprobaciones semánticas para vectores� Comprobación del tamaño� Comprobaciones en el indexado de vectores de una dimensión� Comprobaciones para vectores de dos dimensiones

� Comprobaciones semánticas para conjuntos� Comprobación del tamaño� Comprobaciones para la operación de unión� Comprobaciones para la operación de intersección� Comprobaciones para la operación de inserción

Índice

Prácticas de Procesadores de Lenguaje 2008-2009 4

Análisis semántico

� Comprobaciones semánticas para otras expresiones� Introducción� Implementación

� Comprobaciones semánticas en sentencias de asignación� Comprobación de tipos� Comprobación de niveles de indirección� Implementación

� Comprobaciones semánticas relativas a punteros� Reserva y liberación de memoria� Acceso al contenido apuntado

� Comprobaciones semánticas para vectores� Comprobación del tamaño� Comprobaciones en el indexado de vectores de una dimensión� Comprobaciones para vectores de dos dimensiones

� Comprobaciones semánticas para conjuntos� Comprobación del tamaño� Comprobaciones para la operación de unión� Comprobaciones para la operación de intersección

� Comprobaciones semánticas para las condiciones� Comprobaciones para la sentencia iterativa� Comprobaciones para la sentencia switch

Índice

Prácticas de Procesadores de Lenguaje 2008-2009 5

Análisis semántico

� Comprobaciones para sentencias de entrada� Comprobaciones para sentencias de salida� Otras comprobaciones semánticas

Índice

Prácticas de Procesadores de Lenguaje 2008-2009 6

Notación

� En este documento, la representación de las producciones de la gramática del lenguaje de programación ALFA se ajusta a la notación propia de Bison con las siguientes particularidades:

� Los símbolos no terminales se representan en minúsculas� Los símbolos terminales se representan con TOK_ …� Los símbolos terminales de un carácter se representan encerrados entre comillas simples

Prácticas de Procesadores de Lenguaje 2008-2009 7

Objetivo del análisis semántico

� La semántica del lenguaje forma parte de la especificación del mismo. Normalmente la semántica de un lenguaje se describe de manera informal.

� El objetivo del análisis semántico es comprobar si la semántica del programa que se estácompilando cumple las especificaciones de la semántica del lenguaje fuente. Algunas de estas comprobaciones son:

� comprobación de tipos en sentencias de asignación� comprobación de tipos en operaciones aritmético-lógicas� comprobación de tipos en las sentencias condicionales� comprobación de la declaración de las variables antes de su uso� comprobación de unicidad de identificadores� comprobación del indexado de vectores

� Para realizar el análisis semántico se utilizan gramáticas de atributos, que básicamente, son gramáticas independientes del contexto en las que los símbolos tienen asignados atributos o valores semánticos. Hay dos tipos de atributos:

� sintetizados: corresponden al no terminal de la parte izquierda de una regla. Se calculan a partir de los atributos de los símbolos de la parte derecha de la regla.

� heredados: corresponden a los símbolos de la parte derecha de la regla. Se construyen a partir de los atributos de los símbolos de ambas partes de la regla.

Prácticas de Procesadores de Lenguaje 2008-2009 8

Pasos para la la construcción de un analizador semántico

� Elaborar una lista completa de las comprobaciones semánticas que va a realizar el compilador. Estas comprobaciones se extraen de la especificación del lenguaje. Por ejemplo:

� si el lenguaje permite mezcla de tipos en expresiones, las comprobaciones semánticas son diferentes que si el lenguaje no permite la mezcla de tipos.

� si el lenguaje permite la utilización de variables sin previa definición de las mismas, las comprobaciones semánticas son diferentes que si el lenguaje requiere la definición previa de una variable antes de su uso.

� Definir los atributos necesarios para implementar las comprobaciones semánticas especificadas en el punto anterior.

� Definir si los atributos son heredados o sintetizados.

� Definir el modo en que se calculan los valores de los atributos.

� Si es necesario, transformar la gramática y ajustar el analizador sintáctico.

Prácticas de Procesadores de Lenguaje 2008-2009 9

Análisis semántico con Bison

� El analizador semántico se incorpora al analizador sintáctico construido con Bison insertando en las acciones de las reglas las comprobaciones propias del análisis semántico (posteriormente también se incorporará la generación de código en las acciones de las reglas)

� Por ejemplo, para comprobar la restricción semántica que dice: “En las expresiones lógicas sólo pueden aparecer datos de tipo boolean”, habría que implementar acciones semánticas del siguiente tipo:

1. comprobar que las dos

expresiones de la parte derecha

son de tipo boolean (consultando

el atributo correspondiente)

2. asignar a la expresión de la parte

izquierda el tipo boolean (cálculo de

un atributo sintetizado)

/* generación de código */

}

exp: exp TOK_AND exp {

Prácticas de Procesadores de Lenguaje 2008-2009 10

Análisis semántico con Bison

� Los pasos para la construcción del analizador semántico con Bison son:

� La lista de las comprobaciones semánticas: se deduce de la especificación del lenguaje.

� Los atributos necesarios se deducen a partir de las comprobaciones semánticas que haya que hacer (ver lista anterior). El tipo de los atributos se define mediante la directiva %union dentro del fichero de especificación de Bison.

� Los atributos son sintetizados.Esta restricción viene impuesta porque el tipo de analizador sintáctico que genera Bison es ascendente LALR(1).Si la gramática de atributos que se diseña para implementar el análisis semántico requiere atributos heredados, hay que definir un mecanismo para incorporar el cálculo de dichos atributos en el analizador ascendente generado por Bison.

� El cálculo de los atributos se realiza en las acciones asociadas a las reglas.

� El acceso a los atributos se realiza a través de las pseudovariables $$, $1, $2, ...

Prácticas de Procesadores de Lenguaje 2008-2009 11

Definición de los atributos semánticos

� Los atributos semánticos son los atributos de los símbolos en el árbol de análisis sintáctico.

� Tienen que permitir la realización de las comprobaciones semánticas y la generación de código.

Descripción de la semántica del

lenguaje

Lista de comprobaciones

semánticasAtributos

semánticos

� En la implementación del compilador de ALFA se pueden utilizar los siguientes atributos:� Lexema de los identificadores� Valor numérico de las constantes numéricas enteras� Tipo de las expresiones� Nivel de indirección de las expresiones

NOTA: La elección de los atributos no es única, existen distintas alternativas.

Prácticas de Procesadores de Lenguaje 2008-2009 12

Definición de los atributos semánticos

� Los atributos semánticos de los terminales lo proporciona (calcula) el analizador léxico de la siguiente manera:

� los identificadores tiene como valor semántico su lexema.� las constantes enteras tienen como valor semántico su valor numérico.� las constantes reales tienen como valor semántico su lexema (por razones que se explicarán

en la generación de código)

� Los atributos semánticos de los no terminales se calculan en el proceso de análisis sintáctico. Cada vez que se reduce una producción, se pueden calcular los atributos semánticos del símbolo no terminal de la parte izquierda de la producción.

Prácticas de Procesadores de Lenguaje 2008-2009 13

Definición de los atributos semánticos

� En Bison, los atributos semánticos se define con la declaración %union en el fichero de especificación.

� La declaración %union de Bison se transforma en una definición de tipo union de C. Este tipo de datos de C sólo permite el uso de uno de sus campos, y no es válido para símbolos con múltiples atributos. Por ejemplo, el no terminal “acceso” requiere un atributo para el tipo y otro para el nivel de indirección. Para permitir la multiplicidad de atributos, se puede definir en la declaración %union un sólo campo (atributos) cuyo tipo (tipo_atributos) sea un tipo definido como struct con tantos campos como sea necesario para contemplar todos los casos posibles de valores semánticos de cualquier símbolo del lenguaje (terminal o no terminal).

NOTA: El tipo “tipo_atributos” se puede definir en un fichero de cabecera aparte.

Prácticas de Procesadores de Lenguaje 2008-2009 14

Definición de los atributos semánticos

� En la declaración %union del fichero alfa.y, se define un sólo campo, atributos, cuyo tipo sea tipo_atributos(definido en el fichero alfa.h).

� Se cualifican con <atributos> las declaraciones %token de los símbolos terminales que tienen valor semántico.

� Se añaden las correspondientes declaraciones %type para los no terminales que tengan atributos semánticos.

%{

#include “alfa.h”

...

%}

%union

{

tipo_atributos atributos;

}

%token <atributos> TOK_IDENTIFICADOR

%token <atributos> TOK_CONSTANTE_ENTERA

%token <atributos> TOK_CONSTANTE_REAL

/* resto de los tokens sin valor */

/* semántico */

%type <atributos> exp

%type <atributos> acceso

%type <atributos> comparacion

/* resto de los no terminales */

/* con atributos semánticos */

...

%%

...

%%

...

alfa.y

Prácticas de Procesadores de Lenguaje 2008-2009 15

Definición de los atributos semánticos

� En el fichero alfa.h se define el tipo tipo_atributos como un struct con los siguientes campos :

� lexema: para identificadores y constantes reales.

� valor_entero: para constantes enteras.� tipo: para comprobación de tipos básicos.� direcciones: para comprobación del nivel

de indirección.

#ifndef _ALFA_H

#define _ALFA_H

#define MAX_LONG_ID 50

#define MAX_TAMANIO_VECTOR 64

...

/* otros defines */

typedef struct

{

char lexema[MAX_LONG_ID+1];

int valor_entero;

int tipo;

int direcciones;

}tipo_atributos;

#endif

alfa.h

� El fichero alfa.l se modifica para que el analizador léxico actualice los atributos semánticos de los terminales.

Prácticas de Procesadores de Lenguaje 2008-2009 16

Nivel de indirección en ALFA

� En el lenguaje de programación ALFA, el nivel de indirección de un dato es el número de accesos a memoria necesarios para obtener el valor del dato.

� Una constante (entera o lógica) tiene un nivel de indirección igual a 0.

� Una variable de clase escalar tiene un nivel de indirección igual a 1.Por ejemplo, las variables x y b definidas como:

int x;boolean b;

Valor entero xx

MEMORIA

Valor lógico bb

MEMORIA

Prácticas de Procesadores de Lenguaje 2008-2009 17

Nivel de indirección en ALFA

� Una variable de clase puntero tiene un nivel de indirección igual a 1 más el número de asteriscos que aparecen en su declaración.Por ejemplo, de las siguientes declaraciones, se deduce que la variable px tiene un nivel de indirección igual a 2, y la variable ppb tiene un nivel de indirección igual a 3:

int *px;boolean **ppb;

Valor entero x

px dir2

dir2

MEMORIA

Valor lógico b

dir2 dir3

dir3

dir2ppb

MEMORIA

Prácticas de Procesadores de Lenguaje 2008-2009 18

Nivel de indirección en ALFA

� Los elementos de las variables de clase vector de una o dos dimensiones y los elementos de las variables de clase conjunto tienen un nivel de indirección igual a 1 (como las variables de clase escalar)

� El acceso (*) a un dato tiene un nivel de indirección una unidad menos que el nivel de indirección del dato accedido. Por ejemplo, si se define la variable ppx como:

int **ppx;

� la expresión de acceso *ppx tiene un nivel de indirección igual a 2� la expresión de acceso **ppx tiene un nivel de indirección igual a 1

� La operación de obtención de la dirección (&) de un dato tiene un nivel de indirección una unidad más que el nivel de indirección del dato. Por ejemplo, si se define la variable ppx como:

int **ppx;

� la expresión &ppx tiene un nivel de indirección igual a 4

Prácticas de Procesadores de Lenguaje 2008-2009 19

Declaración y unicidad de los identificadores

� Descripción de la semántica: los identificadores tienen que ser declarados antes de sus uso y deben ser únicos en su ámbito. Es decir:

� Las variables (globales y locales) debe ser declaradas antes de su uso y además ser únicas en su ámbito de declaración.

� Las funciones deben ser declaradas antes de su uso y ser únicas en su ámbito de declaración.� Los parámetros formales de las funciones son tratados como variables locales de la función y

como tales deben ser únicos en su ámbito de declaración. Son declarados implícitamente antes de su uso ya que aparecen en la cabecera de la función.

� Comprobaciones semánticas: se necesitan varias acciones diferentes:� En la declaración de una variable/función/parámetro hay que comprobar que no existe dentro de

su ámbito otra variable/función/parámetro con el mismo identificador antes de registrarla en el sistema (es decir, guardarla en la tabla de símbolos)

� En la aparición de una variable/función/parámetro hay que comprobar que previamente ha sido declarada.

Descripción general

Prácticas de Procesadores de Lenguaje 2008-2009 20

Declaración y unicidad de los identificadores

� La gestión de ámbitos anidados se puede implementar utilizando una pila de tablas de símbolos con el funcionamiento estudiado en las clases teóricas.

� En la compilación, es necesario realizar las siguientes acciones:

� Antes de la primera declaración del programa fuente se debe inicializar la tabla de símbolos. Este proceso de inicialización implica apilar una tabla de símbolos vacía correspondiente al ámbito principal (se le puede dar el nombre “main” o cualquier otro). La inicialización se puede realizar en uno de los dos puntos siguientes:

� En el programa principal antes de invocar a la función de análisis sintáctico.

� En la producción del axioma antes de la sección de declaraciones. En cualquiera de los puntos ••••

programa: •••• TOK_MAIN •••• ‘{‘ •••• declaraciones funciones sentencias ‘}’

Se crea un nuevo no terminal y se añade una producción lambda en cuya acción semántica se inicializa la tabla de símbolos. Por ejemplo:

programa: inicioTabla TOK_MAIN ‘{‘ declaraciones funciones sentencias ‘}’inicioTabla: {

/* Acciones de inicialización de la tabla de símbolos */}

Gestión de ámbitos

Prácticas de Procesadores de Lenguaje 2008-2009 21

Declaración y unicidad de los identificadores

� En la declaración de una función hay que abrir un nuevo ámbito, el correspondiente a la función.

� Al terminar la compilación, liberar los recursos de la tabla de símbolos. Se puede hacer en:� El programa principal, cuando termina la función de análisis sintáctico.� En el fichero de especificación Bison. En este caso habría que contemplar las dos posibles finalizaciones de la

función de análisis, con error o sin error. Si no hay error se puede hacer la liberación en la producción del axioma, al final de la misma. Si hay error se podría hacer en la función yyerror.

Gestión de ámbitos

Prácticas de Procesadores de Lenguaje 2008-2009 22

Declaración y unicidad de los identificadores

� Las declaraciones de variables globales y locales se ajustan a la sintaxis definida por las siguientes producciones de la gramática de ALFA:

� (1) programa : TOK_MAIN ‘{‘ declaraciones funciones sentencias ‘}’� (2) declaraciones : declaracion� (3) |declaracion declaraciones

� (4) declaracion : clase identificadores ‘;’

� (18) identificadores : identificador� (19) identificadores : identificador ‘,’ identificadores

� (22) funcion : TOK_FUNCTION tipo identificador ‘(‘ parametros_funcion ‘)’‘{‘ declaraciones_funcion sentencias ‘}’

� (28) declaraciones_funcion : declaraciones� (29) |

� (106) identificador : TOK_IDENTIFICADOR

Inserción en la tabla de símbolos y unicidad

Prácticas de Procesadores de Lenguaje 2008-2009 23

Declaración y unicidad de los identificadores

� Los parámetros de las funciones se ajustan a la sintaxis definida por las siguientes producciones de la gramática de ALFA:

� (22) funcion : TOK_FUNCTION tipo identificador ‘(‘ parametros_funcion ‘)’‘{‘ declaraciones_funcion sentencias ‘}’

� (23) parametros_funcion : parametro_funcion resto_parametros_funcion� (24) |� (25) resto_parametros_funcion> : ‘;’ parametro_funcion resto_parametros_funcion � (26) |� (27) parametro_funcion : tipo identificador� (106) identificador : TOK_IDENTIFICADOR

� La declaración de funciones tiene la siguiente sintaxis:

� (22) funcion : TOK_FUNCTION tipo identificador ‘(‘ parametros_funcion ‘)’‘{‘ declaraciones_funcion sentencias ‘}’

� (106) identificador : TOK_IDENTIFICADOR

Inserción en la tabla de símbolos y unicidad

Prácticas de Procesadores de Lenguaje 2008-2009 24

Declaración y unicidad de los identificadores

� Del estudio de las producciones relacionadas con la declaración de variables globales y locales, parámetros y funciones, se puede deducir que cada vez que se realiza una declaración se reduce la producción siguiente:

� (106) identificador : TOK_IDENTIFICADOR

Por lo tanto, parece que el punto adecuado para insertar los identificadores de las variables globales y locales, parámetros y funciones en la tabla de símbolos es la acción semántica de la producción 106. No obstante, veremos que es más adecuado utilizar esta producción (la 106) únicamente para variables locales y globales, y usar otros mecanismos para la inserción de los identificadores de parámetros y funciones.

Inserción en la tabla de símbolos y unicidad

Prácticas de Procesadores de Lenguaje 2008-2009 25

Declaración y unicidad de los identificadores

� Independientemente del punto seleccionado para la inserción de un identificador en la tabla de símbolos, es necesario disponer en dicho punto de toda la información asociada al identificador, como por ejemplo:

� lexema� categoría� clase� tipo� nivel de indirección� dimensión (1 ó 2) en el caso de vectores� número de elementos en el caso de vectores de una dimensión� número de filas y columnas en el caso de vectores de dos dimensiones� posición de variable local� posición de parámetro� etc

� En el momento de la inserción en la tabla de símbolos se debe comprobar la unicidad de los identificadores.

Inserción en la tabla de símbolos y unicidad

Prácticas de Procesadores de Lenguaje 2008-2009 26

Declaración y unicidad de los identificadores

� Los objetivos del análisis semántico en el procesamiento de la declaración de identificadores son los siguientes:

� Insertar en la tabla de símbolos cada identificador de variable global o local, parámetro o función con su correspondiente información asociada.

� Controlar la unicidad de identificadores (haciendo uso de la tabla de símbolos)

� Para la inserción de cualquier identificador es necesario definir:� El punto en el que se realiza la inserción.� Los mecanismos que permiten disponer en ese punto de la información asociada al identificador.

� Se distinguirán tres casos diferentes:� Inserción de identificadores de variables globales y locales.� Inserción de identificadores de parámetros de funciones.� Inserción de identificadores de funciones.

Inserción en la tabla de símbolos y unicidad

Prácticas de Procesadores de Lenguaje 2008-2009 27

Variables globales y locales

� El punto adecuado para insertar los identificadores de variables globales y locales en la tabla de símbolos es la acción semántica de la producción 106.

(106) identificador : TOK_IDENTIFICADOR

� El esquema general de la acción semántica se muestra en la siguiente figura.

� La búsqueda se realiza en el ámbito donde se efectúa la inserción, es decir, el ámbito actual.

Introducción

Prácticas de Procesadores de Lenguaje 2008-2009 28

Variables globales y locales

Existe

Buscar en la tabla de símbolos (ámbito actual) el identificador $1.lexema

Mostrar mensaje de error semántico“Identificador $1.lexema duplicado”

Terminar con error

Insertar el identificador en la tabla de símbolos con los siguientes valores

clave = $1.lexemacategoría = la que tenga (ver siguientes transparencias)tipo = el que tenga (ver siguientes transparencias)clase = la que tenga (ver siguientes transparencias)nivel de indirección = el que tenga (ver siguientes transparencias)dimensión = la que tenga (ver siguientes transparencias)número de filas = las que tenga (ver siguientes transparencias)número de columnas = el que tenga (ver siguientes transparencias)etc

SINO

(106) identificador : TOK_IDENTIFICADOR

Esquema general de la acción semántica de la producción 106

Prácticas de Procesadores de Lenguaje 2008-2009 29

Variables globales y locales

� Una declaración de variables globales o locales en ALFA puede ser, por ejemplo:

int X, Y, Z;

en la que se declara que las variables X, Y y Z tienen las siguientes características:� Son de tipo entero.� Son de clase escalar.� Tienen nivel de indirección igual a 1.

� Otra declaración podría ser:

array boolean [8] A1, A2;

en la que se declara que las variables A1 y A2 tienen las siguientes características:� Son de clase vector de una dimensión.� El tipo base de los vectores es el tipo lógico y el nivel de indirección igual a 1 (sintácticamente no

se permite mayor nivel de indirección en los elementos de los vectores)� El tamaño de los vectores es 8.

Propagación de las características de la declaración a las variables de la lista

Prácticas de Procesadores de Lenguaje 2008-2009 30

Variables globales y locales

� Una declaración de variables de tipo puntero sería, por ejemplo:

float **** pf5, pd5;

en la que se declara que las variables pf5 y pd5 tienen las siguientes características:� Son de clase puntero.� Son de tipo real.� Tienen nivel de indirección igual a 5.

� Las características o propiedades de una declaración de variables globales o locales son las siguientes:

� clase (ESCALAR, PUNTERO, VECTOR, CONJUNTO)� tipo (INT, FLOAT, BOOLEAN)� nivel de indirección (>=1)� dimensión (1 ó 2) en el caso de vectores� número de elementos en el caso de vectores de una dimensión� número de filas y columnas en el caso de vectores de dos dimensiones� capacidad máxima en el caso de conjuntos� posición de variable local

Propagación de las características de la declaración a las variables de la lista

Prácticas de Procesadores de Lenguaje 2008-2009 31

Variables globales y locales

� La producción correspondiente a una línea declarativa de variables globales o locales es la siguiente:

(4) declaracion: clase identificadores ‘;’

Como puede observarse, se realiza en primer lugar la reducción del no terminal clase y posteriormente la reducción del no terminal identificadores. Por lo tanto se puede deducir que:

� Durante la reducción del no terminal clase se establecen las características de la declaración.� El no terminal identificadores tiene que “heredar” del no terminal clase las características de la

declaración.

� Debido a que la herencia de atributos no es compatible con el análisis ascendente, es necesario establecer un mecanismo para implementar dicha herencia. El mecanismo más sencillo es el uso de variables globales, una para cada atributo heredado. A continuación se describen dichas variables.

Propagación de las características de la declaración a las variables de la lista

Prácticas de Procesadores de Lenguaje 2008-2009 32

Variables globales y locales

� Una variable global, tipo_actual, para propagar el tipo de la declaración. Esta variable se actualiza con el valor correspondiente (INT, FLOAT o BOOLEAN) en las siguientes producciones:

� (10) tipo : TOK_INT� (11) tipo : TOK_BOOLEAN� (12) tipo : TOK_FLOAT

� Una variable global, direcciones_actual, para propagar el nivel de indirección de la declaración. El valor de esta variable se actualiza en las siguientes producciones:

� (10) tipo : TOK_INT Se inicializa a 1� (11) tipo : TOK_BOOLEAN Se inicializa a 1� (12) tipo : TOK_FLOAT Se inicializa a 1� (13) clase_puntero : tipo ‘*’ Se incrementa en 1� (14) clase_puntero : clase_puntero ‘*’ Se incrementa en 1

Propagación de las características de la declaración a las variables de la lista

Prácticas de Procesadores de Lenguaje 2008-2009 33

Variables globales y locales

� Una variable global, clase_actual, para propagar la clase de la declaración. Esta variable se actualiza con el valor correspondiente (ESCALAR, PUNTERO, VECTOR o CONJUNTO) en las siguientes producciones:

� (5) clase : clase_escalar� (6) clase : clase_puntero� (7) clase : clase_vector� (8) clase : clase_conjunto

� Una variable global, dimension_actual, para propagar la dimensión de la declaración. Esta variable sólo tiene significado en declaraciones de vectores, y su valor se establece en las siguientes producciones:

� (15) clase_vector : TOK_ARRAY tipo ‘[‘ constante_entera ‘]’� (16) clase_vector : TOK_ARRAY tipo ‘[‘ constante_entera ‘,’ constante_entera ‘]’

Propagación de las características de la declaración a las variables de la lista

Prácticas de Procesadores de Lenguaje 2008-2009 34

Variables globales y locales

� Una variable global, tamanio_vector_actual para uso exclusivo en declaraciones de vectores de una dimensión. Permite propagar el tamaño del mismo. Esta variable se actualiza en la siguiente producción:

� (15) clase_vector : TOK_ARRAY tipo ‘[‘ constante_entera ‘]’

� Una variable global, filas_vector_actual para uso exclusivo en declaraciones de vectores de dos dimensiones. Permite propagar el número de filas del mismo. Esta variable se actualiza en la producción:

� (16) clase_vector : TOK_ARRAY tipo ‘[‘ constante_entera ‘,’ constante_entera ‘]’

� Una variable global, columnas_vector_actual, para propagar, el número de columnas en declaraciones de vectores de dos dimensiones. Esta variable se actualiza en la producción:

� (16) clase_vector : TOK_ARRAY tipo ‘[‘ constante_entera ‘,’ constante_entera ‘]’

Propagación de las características de la declaración a las variables de la lista

Prácticas de Procesadores de Lenguaje 2008-2009 35

Variables globales y locales

� Una variable global, capacidad_conjunto_actual, para propagar la capacidad máxima en declaraciones de conjuntos. Esta variable se actualiza en la producción:

� (17) clase_conjunto : TOK_SET TOK_OF constante_entera

� Una variable global, pos_variable_local_actual, para propagar la posición de una variable local en declaraciones correspondientes a variables locales. Esta variable se debe inicializar antes de la sección declarativa de una función, y se incrementará cada vez que se procese la declaración de una variable local, es decir, en la producción 106:

� (106) identificador : TOK_IDENTIFICADOR

� En resumen, el valor de las variables globales se establece en las acciones semánticas de las producciones adecuadas, según se ha explicado en los párrafos anteriores, con el objetivo de disponer de esos valores en las reducciones correspondientes a los identificadores que aparecen en la lista de variables de la declaración (ver ejemplos)

Propagación de las características de la declaración a las variables de la lista

Prácticas de Procesadores de Lenguaje 2008-2009 36

Variables globales y locales

Acciones semánticas de las producciones 5, 6, 7 y 8

clase: clase_escalar{

clase_actual = ESCALAR;}| clase_puntero{

clase_actual = PUNTERO;}| clase_vector{

clase_actual = VECTOR;}| clase_conjunto{

clase_actual = CONJUNTO;};

Prácticas de Procesadores de Lenguaje 2008-2009 37

Variables globales y locales

Acciones semánticas de las producciones 10, 11 y 12

tipo: TOK_INT{

tipo_actual = INT;direcciones_actual = 1;

}| TOK_BOOLEAN{

tipo_actual = BOOLEAN;direcciones_actual = 1;

}| TOK_FLOAT{

tipo_actual = FLOAT;direcciones_actual = 1;

};

Prácticas de Procesadores de Lenguaje 2008-2009 38

Variables globales y locales

Acciones semánticas de las producciones 13 y 14

clase_puntero: tipo ‘*'{

direcciones_actual++;}

| clase_puntero ‘*'{

direcciones_actual++;};

Prácticas de Procesadores de Lenguaje 2008-2009 39

Variables globales y locales

Acciones semánticas de las producciones 15 y 16

clase_vector: TOK_ARRAY tipo ‘[‘ constante_entera ‘]’{

dimension_actual = 1;tamanio_vector_actual = $4.valor_entero;if ((tamanio_vector_actual < 1 ) || (tamanio_vector_actual > MAX_TAMANIO_VECTOR ))

{MOSTRAR MENSAJE ERROR SEMÁNTICOTERMINAR CON ERROR

}}

| TOK_ARRAY tipo ‘[‘ constante_entera ‘,’ constante_entera ‘]’{

dimension_actual = 2;filas_vector_actual = $4.valor_entero;columnas_vector_actual = $6.valor_entero;if ((filas_vector_actual< 1 ) || (filas_vector_actual > MAX_FILAS_VECTOR ))

{MOSTRAR MENSAJE ERROR SEMÁNTICOTERMINAR CON ERROR

}if ((columnas_vector_actual < 1 ) || (columnas_vector_actual > MAX_COLUMNAS_VECTOR ))

{MOSTRAR MENSAJE ERROR SEMÁNTICOTERMINAR CON ERROR

}};

Prácticas de Procesadores de Lenguaje 2008-2009 40

Variables globales y locales

Acción semántica de la producción 17

clase_conjunto: TOK_SET TOK_OF constante_entera{

capacidad_conjunto_actual = $3.valor_entero;if ((capacidad_conjunto_actual < 1 ) ||

(capacidad_conjunto_actual > MAX_CAPACIDAD_CONJUNTO )){

MOSTRAR MENSAJE ERROR SEMÁNTICOTERMINAR CON ERROR

}}

;

Prácticas de Procesadores de Lenguaje 2008-2009 41

Variables globales y locales

Ejemplo 1

� La declaración int X, Y; se analiza como se muestra en la figura

declaraciones

clase identificadores

TOK_INT(int)

identificador , identificadores

;

declaracion

TOK_IDENTIFICADOR(X)

identificador

3

4

7

8

9

5

6

clase_escalar

tipo1

2

Orden de reducción#

Inserción en la tabla de símbolos

TOK_IDENTIFICADOR(Y)

ÁRBOL DE ANÁLISISPRODUCCIONES IMPLICADAS

(2) declaraciones : declaracion(4) declaracion : clase identificadores ‘;’(5) clase : clase_escalar(9) clase_escalar : tipo(10) tipo : TOK_INT(18) identificadores : identificador(19) identificadores : identificador ‘,’ identificadores(106) identificador : TOK_IDENTIFICADOR

VARIABLES GLOBALES

direcciones_actual 1

tipo_actual TIPO_ENTERO

clase_actual ESCALAR

1

1

3 4 5

4 5

4 5

Escritura de la variable

Lectura de la variable

Prácticas de Procesadores de Lenguaje 2008-2009 42

Variables globales y locales

Ejemplo 2

� La declaración boolean *A; se analiza como se muestra en la figura.

declaraciones

clase identificadores

TOK_BOOLEAN(boolean)

identificador

;

declaracion

TOK_IDENTIFICADOR(A)

3

4

5

6

7

clase_puntero

tipo1

2

ÁRBOL DE ANÁLISISPRODUCCIONES IMPLICADAS

(2) declaraciones : declaracion(4) declaracion : clase identificadores ‘;’(6) clase : clase_puntero(11) tipo : TOK_BOOLEAN(13) clase_puntero : tipo ‘*’(18) identificadores : identificador(106) identificador : TOK_IDENTIFICADOR

VARIABLES GLOBALES

*

direcciones_actual 1

tipo_actual TIPO_LOGICO

clase_actual PUNTERO

1

1

3 4

4

4

2 direcciones_actual 2 4

Escritura de la variable

Lectura de la variable

Orden de reducción#

Inserción en la tabla de símbolos

Prácticas de Procesadores de Lenguaje 2008-2009 43

Variables globales y locales

� En la acción semántica de la producción 106, se requiere un mecanismo que permita saber si se está realizando la inserción de una variable local o una variable global ya que el tratamiento es ligeramente diferente.

� Inserción de variable global:� Se comprueba que el identificador no exista en el ámbito actual. Si existiera, se genera un mensaje de

error semántico y se termina el proceso de compilación con error.� Si el identificador no existe en el ámbito actual, se realiza la inserción utilizando los valores

almacenados en las variables globales (tipo_actual, clase_actual, etc)

� Inserción de variable local:� Se comprueba que el identificador no exista en el ámbito actual. Si existiera, se genera un mensaje de

error semántico y se termina el proceso de compilación con error.� Se comprueba que la clase de la variable local sea escalar. Si no es así se genera un mensaje de

error semántico y se termina el proceso de compilación con error.� Si no hay error semántico se realiza la inserción sin olvidar el uso de la variable global

pos_variable_local_actual.� Se incrementa en uno el valor de las siguientes variables globales:

� pos_variable_local_actual� num_variables_locales_actual (esta variable almacena el número de variables locales de una función)

Se asume que estas variables son correctamente inicializadas (consultar documentación de la gestión de identificadores de funciones)

Acción semántica adecuada al ámbito de la variable

Prácticas de Procesadores de Lenguaje 2008-2009 44

Parámetros de función

� Para procesar la inserción de los identificadores de parámetros se diseña una nueva producción específica de la siguiente manera:

idpf : TOK_IDENTIFICADOR

La acción semántica de esta nueva producción se estructura así:� Se comprueba que el identificador no exista en el ámbito actual (el de la función). Si existiera, se

genera un mensaje de error semántico y se termina el proceso de compilación con error.� Si no hay error semántico se realiza la inserción sin olvidar el uso de la variable global

pos_parametro_actual.� Se incrementa en uno el valor de las siguientes variables globales:

� pos_parametro_actual� num_parametros_actual (esta variable almacena el número de parámetros de una función)

Se asume que estas variables son correctamente inicializadas (consultar documentación de la gestión de identificadores de funciones)

� Por último, es necesario modificar la producción 27 para mantener la coherencia con la nueva producción. La regla 27 quedaría de la siguiente manera:

(27) parametro_funcion : tipo idpf

Prácticas de Procesadores de Lenguaje 2008-2009 45

Funciones

� La inserción de los identificadores de funciones en la tabla de símbolos puede resolverse con el esquema de acciones que se marcan en la siguiente producción:

(22) funcion : TOK_FUNCTION tipo TOK_IDENTIFICADOR �‘(‘ parametros_funcion ‘)’ ‘{‘ declaraciones_funcion �sentencias ‘}’ �

� La situación de las acciones en puntos intermedios de la producción sugiere la modificación de la gramática original de la siguiente manera:

fn_name : TOK_FUNCTION tipo TOK_IDENTIFICADOR �fn_declaration : fn_name ‘(‘ parametros_funcion ‘)’ ‘{‘ declaraciones_funcion �funcion : fn_declaration sentencias ‘}’ �

Prácticas de Procesadores de Lenguaje 2008-2009 46

Funciones

� La primera producción añadida a la gramática es:

fn_name : TOK_FUNCTION tipo TOK_IDENTIFICADOR �

� La acción del punto � implica las siguientes tareas:� Buscar el identificador en el ámbito actual (el exterior a la función). Generar un error semántico si ya

existe y terminar el proceso de compilación con error.� Si no ha habido error, abrir un ámbito nuevo. Esta operación implica:

� insertar el identificador de la función en el ámbito actual (el exterior a la función)� crear un nuevo ámbito (el de la función) e insertar en él el identificador de la función.

En este punto la información disponible acerca del identificador de la función se reduce al tipo de retorno de la misma. En los otros puntos marcados se completará esa información.

� Inicializar las siguientes variables globales:� num_variables_locales_actual = 0� pos_variable_local_actual = 1� num_parametros_actual = 0� pos_parametro_actual = 0

� Propagar a la parte izquierda de la regla el lexema del identificador de la función para su posterior uso en la acción del punto marcado como �.

Prácticas de Procesadores de Lenguaje 2008-2009 47

Funciones

� La segunda producción añadida a la gramática es la siguiente:

fn_declaration : fn_name ‘(‘ parametros_funcion ‘)’ ‘{‘ declaraciones_funcion �

� En la regla se puede observar que después de procesar el nombre de la función como consecuencia de la reducción del nuevo no terminal fn_name, se reducen los no terminales correspondientes a los parámetros de la función y a sus variables locales.

� La gestión de los identificadores de los parámetros y las variables locales se realiza como ya se ha expuesto anteriormente.

� En el punto � ya se conoce el número de parámetros de la función, y es necesario actualizar en ese punto dicha información en la tabla de símbolos del ámbito actual para poder permitir el control semántico de dicha propiedad en las llamadas recursivas (si las hubiera)

Prácticas de Procesadores de Lenguaje 2008-2009 48

Funciones

� La acción del punto � implica las siguientes tareas:� Acceder al identificador de la función en el ámbito actual (el de la función) y actualizar la información

correspondiente al número de parámetros.El acceso al identificador se puede realizar haciendo uso del lexema guardado como atributo del no terminal fn_name que se propagó en la acción �.

� Propagar a la parte izquierda de la regla el lexema del identificador de la función para su posterior uso en la acción del punto marcado como �.

Prácticas de Procesadores de Lenguaje 2008-2009 49

Funciones

� La inserción en la gramática de los dos nuevos símbolos fn_name y fn_declaration hace que la producción 22 de la gramática original quede modificada de la siguiente manera:

funcion : fn_declaration sentencias ‘}’ �

� La acción del punto � implica las siguientes tareas:� Cerrar el ámbito de la función.� Acceder al identificador de la función en el ámbito actual (el exterior a la función) y actualizar la

información correspondiente al número de parámetros.El acceso al identificador se puede realizar haciendo uso del lexema guardado como atributo del no terminal fn_declaration que se propagó en la acción �.

Prácticas de Procesadores de Lenguaje 2008-2009 50

Comprobación de la declaración de identificadores previa a su uso

� Cada vez que se accede a un identificador hay que comprobar si se ha declaradopreviamente.

� Para comprobar si un identificador ha sido declarado, simplemente se busca en la tabla de símbolos. Si la búsqueda termina con existo significa que el identificador ha sido declarado y que en la compilación de su declaración se insertó en la tabla de símbolos. Es importante no olvidar que la búsqueda se debe realizar en el ámbito actual y en todos los ámbitos que lo engloban.

� Las producciones de la gramática que reflejan el uso de identificadores son aquellas pertenecientes a la sección de sentencias en las que aparece el no terminal “identificador”.

� La producción del no terminal “identificador” (la número 106) ya está reservada para realizar la inserción de identificadores en la tabla de símbolos. Por lo tanto, es necesario sustituir en las producciones de la gramática que reflejan el uso de identificadores la aparición del no terminal “identificador” por el terminal TOK_IDENTIFICADOR.

Prácticas de Procesadores de Lenguaje 2008-2009 51

Comprobación de la declaración de identificadores previa a su uso

� Algunas de las producciones que se tienen que modificar son las siguientes:

� (43) asignacion : TOK_IDENTIFICADOR ‘=‘ exp................................� (46) asignacion : TOK_IDENTIFICADOR ‘=‘ TOK_MALLOC� (47) asignacion : TOK_IDENTIFICADOR ‘=‘ ‘&’ TOK_IDENTIFICADOR................................� (48) elemento_vector : TOK_IDENTIFICADOR ‘[‘ exp ‘]’� (49) elemento_vector : TOK_IDENTIFICADOR ‘[‘ exp ‘,’ exp ‘]’................................� (53) bucle : TOK_FOR ‘(‘ TOK_IDENTIFICADOR ‘=‘ exp ‘;’ exp ‘)’ ‘{‘ sentencias ‘}’................................� (54) lectura : TOK_SCANF TOK_IDENTIFICADOR................................� (57) escritura : TOK_CPRINTF TOK_IDENTIFICADOR................................� etc

Prácticas de Procesadores de Lenguaje 2008-2009 52

Comprobaciones semánticas en las expresiones aritméticas

� Descripción de la semántica: En las expresiones aritméticas sólo pueden aparecer datos de tipo numérico, es decir, int o float. Si en una expresión aritmética aparecen operandos de distinto tipo, siempre se promocionarán a float todos los operandos de tipo int. Y el tipo asignado a la expresión en su conjunto será float.

� Comprobaciones semánticas: hay que comprobar que los operandos son de tipo int o float en las siguientes producciones y asignar el tipo correspondiente a la expresión resultante:

� (72) exp : exp ‘+’ exp� (73) exp : exp ‘-’ exp� (74) exp : exp ‘/’ exp� (75) exp : exp ‘*’ exp� (76) exp : ‘-’ exp

Comprobación de tipos

Prácticas de Procesadores de Lenguaje 2008-2009 53

Comprobaciones semánticas en las expresiones aritméticas

� Descripción de la semántica: No está permitida la aritmética de punteros.

� Comprobaciones semánticas: hay que comprobar que los operandos tienen un nivel de indirección igual a 0 ó 1 las siguientes producciones:

� (72) exp : exp ‘+’ exp� (73) exp : exp ‘-’ exp� (74) exp : exp ‘/’ exp� (75) exp : exp ‘*’ exp� (76) exp : ‘-’ exp

Comprobación de niveles de indirección

Prácticas de Procesadores de Lenguaje 2008-2009 54

Comprobaciones semánticas en las expresiones aritméticas

� En la producciones correspondientes a expresiones aritméticas, las tareas que realiza el analizador semántico son:

� Realizar las comprobaciones adecuadas en cada producción. Si alguna comprobación no es correcta se genera un error semántico y se termina la compilación con error.

� Calcular (propagar) los atributos correspondientes.

� En la producción correspondiente a la suma de expresiones:

(72) exp : exp ‘+’ exp

Se comprueba que:� Las dos expresiones son de tipo entero o tipo real, accediendo a través de $1.tipo y $3.tipo.� El nivel de indirección de ambas expresiones es 0 ó 1.

Se calculan los atributos:� El tipo del símbolo de la parte izquierda es entero si las dos expresiones de la parte derecha son de

tipo entero ($$.tipo = INT)� El tipo del símbolo de la parte izquierda es real si alguna de las expresiones de la parte derecha es

de tipo real ($$.tipo = FLOAT)� El nivel de indirección del símbolo de la parte izquierda es 0 ($$.direcciones = 0)

Implementación

Prácticas de Procesadores de Lenguaje 2008-2009 55

Comprobaciones semánticas en las expresiones aritméticas

� En las producciones correspondientes a las demás operaciones aritméticas se realizan las mismas comprobaciones y cálculo de atributos:

� (73) exp: exp ‘-’ exp� (74) exp: exp ‘/’ exp� (75) exp: exp ‘*’ exp

� En la producción correspondiente al menos unario:

(76) exp : ‘-’ exp

Como sólo existe un operando, sólo es necesario comprobar que el nivel de indirección de la expresión de la parte derecha de la regla es 0 ó 1, y que su tipo es entero o real.

Se calculan los atributos:� El tipo del símbolo de la parte izquierda es igual al tipo de la expresión de la parte derecha ($$.tipo =

$2.tipo)� El nivel de indirección del símbolo de la parte izquierda es 0 ($$.direcciones = 0)

Implementación

Prácticas de Procesadores de Lenguaje 2008-2009 56

Comprobaciones semánticas en las expresiones lógicas

� Descripción de la semántica: En las expresiones lógicas sólo pueden aparecer datos de tipo boolean. El tipo de una expresión lógica es de tipo boolean.

� Comprobaciones semánticas: hay que comprobar que los operandos son de tipo boolean en las siguientes producciones y asignar el tipo correspondiente a la expresión resultante:

� (77) exp : exp TOK_AND exp� (78) exp : exp TOK_OR exp� (79) exp : ‘!’ exp

Comprobación de tipos

Prácticas de Procesadores de Lenguaje 2008-2009 57

Comprobaciones semánticas en las expresiones lógicas

� Descripción de la semántica: Las expresiones lógicas no están permitidas sobre datos de clase puntero (esta descripción no aparece de forma explícita en el enunciado de la práctica)

� Comprobaciones semánticas: hay que comprobar que los operandos tienen un nivel de indirección igual a 0 ó 1 las siguientes producciones:

� (77) exp : exp TOK_AND exp� (78) exp : exp TOK_OR exp� (79) exp : ‘!’ exp

Comprobación de niveles de indirección

Prácticas de Procesadores de Lenguaje 2008-2009 58

Comprobaciones semánticas en las expresiones lógicas

� En las producciones correspondientes a expresiones lógicas, las tareas que realiza el analizador semántico son:

� Realizar las comprobaciones adecuadas en cada producción. Si alguna comprobación no es correcta se genera un error semántico y se termina el proceso de compilación con error.

� Calcular (propagar) los atributos correspondientes.

� En la producciones correspondientes a las operaciones de conjunción y disyunción de expresiones:

(77) exp : exp TOK_AND exp(78) exp : exp TOK_OR exp

Se comprueba que:� Las dos expresiones son de tipo lógico, accediendo a través de $1.tipo y $3.tipo.� El nivel de indirección de ambas expresiones es 0 ó 1.

Se calculan los atributos:� El tipo del símbolo de la parte izquierda es lógico ($$.tipo = BOOLEAN)� El nivel de indirección del símbolo de la parte izquierda es 0 ($$.direcciones = 0)

Implementación

Prácticas de Procesadores de Lenguaje 2008-2009 59

Comprobaciones semánticas en las expresiones lógicas

� En la producción correspondiente a la negación lógica:

(79) exp : ‘!’ exp

Sólo es necesario comprobar que el tipo de la expresión de la parte derecha es boolean y que su nivel de indirección es 0 ó 1.

Se calculan los atributos:� El tipo del símbolo de la parte izquierda es lógico ($$.tipo = BOOLEAN)� El nivel de indirección del símbolo de la parte izquierda es 0 ($$.direcciones = 0)

Implementación

Prácticas de Procesadores de Lenguaje 2008-2009 60

Comprobaciones semánticas en las expresiones de comparación

� Descripción de la semántica: Las comparaciones sólo pueden operar con datos de tipo numérico, int o float, siendo el resultado de la comparación de tipo boolean.

� Comprobaciones semánticas: hay que comprobar que los elementos comparados son de tipo numérico en las siguientes producciones y asignar el tipo correspondiente a la expresión resultante:

� (93) comparacion : exp TOK_IGUAL exp� (94) comparacion : exp TOK_DISTINTO exp� (95) comparacion : exp TOK_MENORIGUAL exp� (96) comparacion : exp TOK_MAYORIGUAL exp� (97) comparacion : exp ‘<‘ exp� (98) comparacion : exp ‘>’ exp

Comprobación de tipos

Prácticas de Procesadores de Lenguaje 2008-2009 61

Comprobaciones semánticas en las expresiones de comparación

� Descripción de la semántica: No está permitida la comparación de punteros.

� Comprobaciones semánticas: hay que comprobar que los elementos comparados tienen un nivel de indirección igual a 0 ó 1 las siguientes producciones:

� (93) comparacion : exp TOK_IGUAL exp� (94) comparacion : exp TOK_DISTINTO exp� (95) comparacion : exp TOK_MENORIGUAL exp� (96) comparacion : exp TOK_MAYORIGUAL exp� (97) comparacion : exp ‘<‘ exp� (98) comparacion : exp ‘>’ exp

Comprobación de niveles de indirección

Prácticas de Procesadores de Lenguaje 2008-2009 62

Comprobaciones semánticas en las expresiones de comparación

� En todas las producciones correspondientes a las comparaciones de expresiones, las únicas tareas que realiza el analizador semántico son:

Comprobar que,� Las dos expresiones son de tipo numérico, accediendo a través de $1.tipo y $3.tipo.� El nivel de indirección de ambas expresiones es 0 ó 1 accediendo a través de $1.direcciones y

$3.direcciones.

Calcular los atributos:� El tipo del símbolo de la parte izquierda es lógico ($$.tipo = BOOLEAN)� El nivel de indirección del símbolo de la parte izquierda es 0 ($$.direcciones = 0)

� Las producciones en las que se implementan las comprobaciones semánticas son:� (93) comparacion : exp TOK_IGUAL exp� (94) comparacion : exp TOK_DISTINTO exp� (95) comparacion : exp TOK_MENORIGUAL exp� (96) comparacion : exp TOK_MAYORIGUAL exp� (97) comparacion : exp ‘<‘ exp� (98) comparacion : exp ‘>’ exp

Implementación

Prácticas de Procesadores de Lenguaje 2008-2009 63

Comprobaciones semánticas para las constantes

� Todas las producciones relacionadas con las constantes sean del tipo que sean únicamente incorporan cálculo (propagación) de atributos. La semántica de ALFA no exige la realización de comprobaciones semánticas para las constantes.

� Las producciones relacionadas con las constantes son las siguientes:� (99) constante : constante_logica� (100) constante : constante_entera� (101) constante : constante_real� (102) constante_logica : TOK_TRUE� (103) constante_logica : TOK_FALSE� (104) constante_entera : TOK_CONSTANTE_ENTERA� (105) constante_real : TOK_CONSTANTE_REAL

Introducción

Prácticas de Procesadores de Lenguaje 2008-2009 64

Comprobaciones semánticas para las constantes

� En la producción que se reduce cuando el analizador morfológico identifica en la entrada una constante entera, se realiza la siguiente propagación de atributos:

(104) constante_entera: TOK_CONSTANTE_ENTERA{

$$.tipo = INT;$$.direcciones = 0;$$.valor_entero = $1.valor_entero;

};

� En la producción que se reduce cuando el analizador morfológico identifica en la entrada una constante real, se realiza la siguiente propagación de atributos:

(105) constante_real: TOK_CONSTANTE_REAL{

$$.tipo = FLOAT;$$.direcciones = 0;

};

Implementación

Prácticas de Procesadores de Lenguaje 2008-2009 65

Comprobaciones semánticas para las constantes

� Las producciones que se reducen cuando el analizador morfológico identifica en la entrada una constante booleana, contienen la siguiente propagación de atributos:

(102) constante_logica: TOK_TRUE{

$$.tipo = BOOLEAN;$$.direcciones = 0;

};

(103) constante_logica: TOK_FALSE{

$$.tipo = BOOLEAN;$$.direcciones = 0;

};

Implementación

Prácticas de Procesadores de Lenguaje 2008-2009 66

Comprobaciones semánticas para las constantes

� Por último, las producciones intermedias que representan que una constante es entera, real o lógica, tienen el siguiente cálculo de atributos:

(99) constante : constante_logica{

$$.tipo = $1.tipo;$$.direcciones = $1.direcciones;

}(100) constante : constante_entera

{$$.tipo = $1.tipo;$$.direcciones = $1.direcciones;

}(101) constante : constante_real

{$$.tipo = $1.tipo;$$.direcciones = $1.direcciones;

};

Implementación

Prácticas de Procesadores de Lenguaje 2008-2009 67

Comprobaciones semánticas para otras expresiones

� El no terminal exp tiene varias producciones además de las relativas a expresiones aritméticas y lógicas cuyas comprobaciones semánticas ya han sido descritas. Estas producciones son:

� (80) exp: TOK_IDENTIFICADOR� (81) exp: constante� (82) exp: ‘(‘ exp ‘)’� (83) exp: ‘(‘ comparacion ‘)’� (84) exp: acceso� (85) exp: elemento_vector� (86) exp: TOK_SIZE ‘(‘ TOK_IDENTIFICADOR ‘)’� (87) exp: TOK_CONTAINS ‘(‘ exp ‘,’ TOK_IDENTIFICADOR ‘)’� (88) exp: TOK_IDENTIFICADOR ‘(‘ lista_expresiones ‘)’

� Las comprobaciones semánticas de cada una de las producciones se describe a continuación.

Introducción

Prácticas de Procesadores de Lenguaje 2008-2009 68

Comprobaciones semánticas para otras expresiones

� En la producción siguiente:

(80) exp : TOK_IDENTIFICADOR

Se comprueba que:� El identificador ($1.lexema) existe en la tabla de símbolos (en cualquiera de los ámbitos abiertos). Si

el identificador no existe, se genera un error semántico y se termina el proceso de compilación con error.

� El identificador no es ni de categoría función (es decir, es una variable o un parámetro), ni de clase vector o conjunto (es decir, es un escalar o un puntero)

Se calculan los atributos:� El tipo del símbolo exp de la parte izquierda ($$.tipo) se establece haciendo uso de la información

almacenada en la tabla de símbolos para el identificador de la parte derecha de la producción.� El nivel de indirección del símbolo exp ($$.direcciones) también se establece a partir de la

información recuperada de la tabla de símbolos.

Implementación

Prácticas de Procesadores de Lenguaje 2008-2009 69

Comprobaciones semánticas para otras expresiones

� Las producciones (81) a (85) únicamente contienen en su acción semántica las siguientes instrucciones para propagar atributos:

� $$.tipo = $1.tipo en las producciones 81, 84 y 85.� $$.tipo = $2.tipo en las producciones 82 y 83.� $$.direcciones = $1.direcciones en las producciones 81, 84 y 85.� $$.direcciones = $2.direcciones en las producciones 82 y 83.

� En la producción relativa al tamaño de un conjunto:

(86) exp: TOK_SIZE ‘(‘ TOK_IDENTIFICADOR ‘)’

Se comprueba que:� El identificador ($3.lexema) existe en la tabla de símbolos (en cualquiera de los ámbitos abiertos). Si

el identificador no existe, se genera un error semántico y se termina el proceso de compilación con error.

� El identificador es de clase conjunto.

Se calculan los atributos:� El tipo del símbolo de la parte izquierda exp ($$.tipo) se establece a IN T. � El nivel de indirección del símbolo exp ($$.direcciones) se iguala a 0.

Implementación

Prácticas de Procesadores de Lenguaje 2008-2009 70

Comprobaciones semánticas para otras expresiones

� La producción 87 define la sintaxis de la función de pertenencia de conjuntos:

(87) exp: TOK_CONTAINS ‘(‘ exp ‘,’ TOK_IDENTIFICADOR ‘)’

� La descripción de la semántica de la función de pertenencia de conjuntos dice que:� La expresión tiene que ser de tipo int.� El conjunto tiene que estar declarado.� La condición de pertenencia de una expresión a un conjunto es de tipo boolean.

� Por lo tanto, en la acción semántica de la regla 87 se comprueba que:� El identificador ($5.lexema) existe en la tabla de símbolos (en cualquiera de los ámbitos abiertos). Si

el identificador no existe, se genera un error semántico y se termina el proceso de compilación con error.

� El identificador es de clase conjunto.� La expresión es de tipo int y con nivel de indirección 0 ó 1.

� Y se calculan los atributos:� El tipo del símbolo de la parte izquierda exp ($$.tipo) se establece a BOOLEAN. � El nivel de indirección del símbolo exp ($$.direcciones) se iguala a 0.

Implementación

Prácticas de Procesadores de Lenguaje 2008-2009 71

Comprobaciones semánticas para otras expresiones

� La producción 88 define la sintaxis de la llamada a una función:

(88) exp: TOK_IDENTIFICADOR ‘(‘ lista_expresiones ‘)’

� La descripción de la semántica es la siguiente:� En las sentencias de llamadas a funciones, sólo es necesario comprobar la corrección del número de

argumentos. No es necesario realizar ninguna comprobación de la correspondencia de tipos.� En las llamadas a funciones, no se puede escribir, en un parámetro, una llamada a otra función.

� En primer lugar, se comprueba que el identificador existe en la tabla de símbolos y además tiene categoría de función.

Implementación

Prácticas de Procesadores de Lenguaje 2008-2009 72

Comprobaciones semánticas para otras expresiones

� Para comprobar la corrección del número de argumentos es necesario un mecanismo que permita “contar” el número de elementos de la lista de expresiones para poder compararlo con el número de parámetros con el que se definió la función y que está almacenado en la tabla de símbolos.

� Un posible mecanismo sería usar una variable global num_parametros_llamada_actual para contar el número de parámetros de la llamada. La inicialización a 0 de esta variable se haría antes de comenzar a procesar el no terminal lista_expresiones, y se incrementaría en 1 cada vez que se procesara uno de los elementos de la lista.

� Para comprobar que no haya una llamada a función en el lugar de un parámetro, se puede utilizar otra variable global en_explist que se inicialice a 1 antes de procesar el no terminal lista_expresiones. Y posteriormente, en cualquier llamada a función se comprobará que en_explist no sea 1. Por último, al terminar la llamada a función se reseteará a 0 esta variable.

Implementación

Prácticas de Procesadores de Lenguaje 2008-2009 73

Comprobaciones semánticas para otras expresiones

� Agrupando todas las tareas necesarias para implementar la semántica de la llamadas a funciones, se deduce que hay dos puntos en los que se ubican las acciones:

(88) exp: TOK_IDENTIFICADOR � ‘(‘ lista_expresiones ‘)’ �

� Se modifica la gramática para situar la acción del punto � al final de una producción, añadiendo la siguiente regla:

idf_llamada_funcion : TOK_IDENTIFICADOR �

Por lo tanto, la producción 88 de la gramática original ahora quedaría de la siguiente manera:

(88) exp: idf_llamada_funcion ‘(‘ lista_expresiones ‘)’ �

Implementación

Prácticas de Procesadores de Lenguaje 2008-2009 74

Comprobaciones semánticas para otras expresiones

� La acción del punto � implica las siguientes tareas:� Buscar el identificador en la tabla de símbolos. Generar un error semántico si no existe y terminar el

proceso de compilación con error.� Comprobar que el identificador es de categoría función.� Como después del identificador empieza la lista de expresiones correspondiente a los parámetros de la

llamada, hay que comprobar que la variable en_explist no valga 1 para asegurar que la actual llamada a función no es un parámetro de llamada a función.

� Inicializar a 0 la variable num_parametros_llamada_actual.� Inicializar a 1 la variable en_explist ya que después del identificador empieza la lista de expresiones

correspondiente a los parámetros de la llamada.� Propagar el lexema del identificador ya que se va a necesitar en el punto �.

� La acción del punto � implica las siguientes tareas:� Comprobar que el número de parámetros de la llamada es correcto comparando el valor de la variable

global num_parametros_llamada_actual con la información almacenada en la tabla de símbolos.� Resetear a 0 la variable en_explist.� El tipo del símbolo de la parte izquierda exp ($$.tipo) se iguala al tipo de retorno de la función que está

almacenado en la tabla de símbolos.� El nivel de indirección del símbolo exp ($$.direcciones) se iguala a 0.

Implementación

Prácticas de Procesadores de Lenguaje 2008-2009 75

Comprobaciones semánticas para otras expresiones

� Por último, sólo faltaría decidir los puntos en los que se debe actualizar la variable global num_parametros_llamada_actual. Las producciones indicadas para ello son las siguientes:

(89) lista_expresiones: exp resto_lista_expresiones(91) resto_lista_expresiones: ‘,’ exp resto_lista_expresiones

En ambas producciones únicamente hay que realizar la acción:

num_parametros_llamada_actual++

Implementación

Prácticas de Procesadores de Lenguaje 2008-2009 76

Comprobaciones semánticas en sentencias de asignación

� Descripción de la semántica: Para que una sentencia de asignación sea válida, los tipos de dato de la parte izquierda y derecha deben ser iguales.

� Comprobaciones semánticas: hay que comprobar que son iguales los tipos de dato de la parte izquierda y derecha de la asignación en las siguientes producciones:

� (43) asignacion : TOK_IDENTIFICADOR ‘=‘ exp� (44) asignacion : elemento_vector ‘=‘ exp� (45) asignacion : acceso ‘=‘ exp� (47) asignacion : TOK_IDENTIFICADOR ‘=‘ ‘&’ TOK_IDENTIFICADOR

� En la producción (46) asignacion : TOK_IDENTIFICADOR ‘=‘ TOK_MALLOCno procede la comprobación de tipos ya que la parte izquierda puede ser de tipo INT, FLOAT o BOOLEAN. La restricción semántica en este caso está relacionada con la clase (la parte izquierda tiene que ser de clase puntero)

Comprobación de tipos

Prácticas de Procesadores de Lenguaje 2008-2009 77

Comprobaciones semánticas en sentencias de asignación

� Descripción de la semántica: Para que una sentencia de asignación sea válida, las partes izquierda y derecha de la asignación deben tener el mismo nivel de indirección, o bien, la parte derecha un nivel de indirección igual a 0 y la parte izquierda igual a 1.

� Comprobaciones semánticas: hay que comprobar que ambas partes de la asignación tienen el mismo nivel de indirección, o bien, la parte derecha un nivel de indirección igual a 0 y la parte izquierda igual a 1, en las siguientes producciones:

� (43) asignacion : TOK_IDENTIFICADOR ‘=‘ exp� (44) asignacion : elemento_vector ‘=‘ exp

En esta producción, la parte izquierda de la asignación siempre tiene un nivel de indirección igual a 1, y por lo tanto, la parte derecha sólo puede tener un nivel de indirección igual a 0 ó 1.

� (45) asignacion : acceso ‘=‘ exp� (47) asignacion : TOK_IDENTIFICADOR ‘=‘ ‘&’ TOK_IDENTIFICADOR

� En la producción (46) asignacion : TOK_IDENTIFICADOR ‘=‘ TOK_MALLOCla comprobación semántica consiste en verificar que la parte izquierda tiene un nivel de indirección superior a 1, es decir, que es de clase puntero.

Comprobación de niveles de indirección

Prácticas de Procesadores de Lenguaje 2008-2009 78

Comprobaciones semánticas en sentencias de asignación

� La primera producción corresponde a la asignación de una expresión a un identificador:

(43) asignacion: TOK_IDENTIFICADOR ‘=‘ exp

Se comprueba que:� El identificador existe en la tabla de símbolos.� El identificador no es de categoría función (es decir es una variable o un parámetro) y no es de

clase vector ni de clase conjunto (es decir, es un escalar o un puntero)� Los tipos de ambas partes de la asignación son iguales.� El nivel de indirección de ambas partes coincide, o bien, el nivel de indirección de la parte

izquierda es 1 y el de la parte derecha 0.

No hay propagación de atributos, no es necesario.

Implementación

Prácticas de Procesadores de Lenguaje 2008-2009 79

Comprobaciones semánticas en sentencias de asignación

� La segunda producción corresponde a la asignación de una expresión a un elemento de un vector:

(44) asignacion: elemento_vector ‘=‘ exp

Se comprueba que:� Los tipos de ambas partes de la asignación son iguales.� El nivel de indirección de la expresión es 0 ó 1.

No hay propagación de atributos, no es necesario.

Implementación

Prácticas de Procesadores de Lenguaje 2008-2009 80

Comprobaciones semánticas en sentencias de asignación

� La producción correspondiente a la asignación de una expresión a un objeto de tipo acceso:

(45) asignacion: acceso ‘=‘ exp

Se comprueba que:� Los tipos de ambas partes de la asignación son iguales.� El nivel de indirección de ambas partes coincide, o bien, el nivel de indirección de la parte

izquierda es 1 y el de la parte derecha 0.

No hay propagación de atributos, no es necesario.

Implementación

Prácticas de Procesadores de Lenguaje 2008-2009 81

Comprobaciones semánticas en sentencias de asignación

� La producción relativa a la reserva de memoria:

(46) asignacion: TOK_IDENTIFICADOR ‘=‘ TOK_MALLOC

Se comprueba que:� El identificador existe en la tabla de símbolos.� El identificador es de clase puntero.

No hay propagación de atributos, no es necesario.

Implementación

Prácticas de Procesadores de Lenguaje 2008-2009 82

Comprobaciones semánticas en sentencias de asignación

� La última producción de asignación:

(47) asignacion: TOK_IDENTIFICADOR ‘=‘ ‘&’ TOK_IDENTIFICADOR

Se comprueba que:� Los dos identificadores existen en la tabla de símbolos.� El identificador de la parte izquierda de la asignación es de clase puntero.� El identificador de la parte derecha de la asignación es de clase escalar o de clase puntero.� Los dos identificadores tienen el mismo tipo base.� El nivel de indirección del identificador de la parte izquierda de la asignación es una unidad

superior al nivel de indirección del identificador de la parte derecha.

Implementación

Prácticas de Procesadores de Lenguaje 2008-2009 83

Comprobaciones semánticas relativas a punteros

� Descripción de la semántica: La palabras reservadas del lenguaje malloc y free se utilizan respectivamente para asignar a un puntero memoria y para liberarla.

� Comprobaciones semánticas:� Las comprobaciones semánticas relacionadas con la reserva de memoria se especifican en la

descripción de las comprobaciones semánticas en sentencias de asignación ya que, la reserva de memoria sólo puede aparecer en una sentencia de asignación.

� En la liberación de memoria se comprueba que el identificador implicado se declaró previamente como una variable de clase puntero. La producción de liberación de memoria es la siguiente:

(58) liberacion : TOK_FREE TOK_IDENTIFICADOR

Reserva y liberación de memoria

Prácticas de Procesadores de Lenguaje 2008-2009 84

Comprobaciones semánticas relativas a punteros

� Descripción de la semántica: El concepto de “acceso al contenido apuntado” requiere la existencia de un “objeto apuntador”, es decir, de una variable de tipo puntero.

� Comprobaciones semánticas: las comprobaciones semánticas relacionadas con el acceso al contenido apuntado se realizan en las siguientes producciones:

� (59) acceso : ‘*’ TOK_IDENTIFICADOR

Se comprueba que:� el identificador ha sido declarado, es decir, está en la tabla de símbolos.� el identificador es de clase puntero.� se propagan adecuadamente los atributos de tipo y direcciones.

� (60) acceso : ‘*’ acceso

Se comprueba que:� el acceso de la parte derecha de la regla tiene en su atributo direcciones un valor superior a 1.� se propagan adecuadamente los atributos de tipo y direcciones.

Acceso al contenido apuntado

Prácticas de Procesadores de Lenguaje 2008-2009 85

Comprobaciones semánticas para vectores

� Descripción de la semántica: El tamaño de los vectores de una dimensión no podráexceder nunca el valor de 64. Esta misma restricción se aplica a cada una de las dimensiones de los vectores de dos dimensiones.

� Comprobaciones semánticas: hay que comprobar que el tamaño declarado para un vector no excede el límite permitido (64 para cada dimensión). También hay que comprobar que el tamaño declarado para cada dimensión es mayor que 0 (esta restricción no se especifica explícitamente en la descripción de la semántica del lenguaje). Estas comprobaciones se pueden realizar las siguientes producciones:

� (15) clase_vector : TOK_ARRAY tipo ‘[‘ constante_entera ‘]’� (16) clase_vector : TOK_ARRAY tipo ‘[‘ constante_entera ‘,’ constante_entera ‘]’

(VER EPÍGRAFE “Acciones semánticas de las producciones 15 y 16” )

Comprobación del tamaño

Prácticas de Procesadores de Lenguaje 2008-2009 86

Comprobaciones semánticas para vectores

� Descripción de la semántica: Para indexar los elementos de un vector de una dimensión se utiliza la cadena “[exp]”a continuación del nombre del vector. Los corchetes deberán contener en su interior una expresión de tipo int. En ningún caso podrá aparecer en el lugar de la expresión que encierran los corchetes una variable de tipo puntero, aunque sí el acceso al contenido de dicha variable, siempre que dicho contenido sea de tipo int.

� Comprobaciones semánticas: la producción indicada para comprobar la semántica descrita es la siguiente:

� (48) elemento_vector : TOK_IDENTIFICADOR ‘[‘ exp ‘]’

Las comprobaciones que hay que realizar son:

� El identificador que aparece ($1.lexema) existe en la tabla de símbolos y además corresponde a la declaración de un vector de una dimensión.

� La expresión que actúa como índice es de tipo INT ($3.tipo == INT)� La expresión que actúa como índice tiene un nivel de indirección igual a 0 ó 1 ($3.direcciones <2)

Comprobaciones en el indexado de vectores de una dimensión

Prácticas de Procesadores de Lenguaje 2008-2009 87

Comprobaciones semánticas para vectores

� Descripción de la semántica: Los corchetes deberán contener en su interior una expresión de tipo int, con un valor entre 0 y el tamaño definido para el vector menos 1 (ambos incluidos)

� Comprobaciones semánticas: en una operación de indexado de un vector de una dimensión, la comprobación de que el valor del índice está dentro del rango permitido sólo se puede realizar en tiempo de ejecución, no en tiempo de compilación. Para implementar esta restricción semántica se genera el código ensamblador adecuado para realizar la validación del valor del índice en tiempo de ejecución. La producción indicada para la generación del código es:

� (48) elemento_vector : TOK_IDENTIFICADOR ‘[‘ exp ‘]’

Comprobaciones en el indexado de vectores de una dimensión

Prácticas de Procesadores de Lenguaje 2008-2009 88

Comprobaciones semánticas para vectores

� Descripción de la semántica: Las restricciones semánticas para vectores de dos dimensiones son similares a las correspondientes a los vectores de una dimensión.

� Comprobaciones semánticas: la producción indicada para comprobar la semántica es la siguiente:

� (49) elemento_vector : TOK_IDENTIFICADOR ‘[‘ exp ‘,’ exp ‘]’

Las comprobaciones que hay que realizar son:

� El identificador que aparece corresponde a la declaración de un vector de dos dimensiones.� Las expresiones que actúan como índices son de tipo INT.� Las expresiones que actúan como índices tienen un nivel de indirección igual a 0 ó 1.� En tiempo de compilación se genera el código ensamblador adecuado para comprobar en tiempo

de ejecución que los valores de los índices no exceden los rangos permitidos.

Comprobaciones para vectores de dos dimensiones

Prácticas de Procesadores de Lenguaje 2008-2009 89

Comprobaciones semánticas para conjuntos

� Descripción de la semántica: El tamaño mínimo de un conjunto es 1, y el tamaño máximo es 64 elementos.

� Comprobaciones semánticas: hay que comprobar que el tamaño declarado para un conjunto está dentro de los límites permitidos (1 y 64) Ésta comprobación se puede realizar en la siguiente producción:

� (17) clase_conjunto : TOK_SET TOK_OF constante_entera

(VER EPÍGRAFE “Acción semántica de la producción 17” )

Comprobación del tamaño

Prácticas de Procesadores de Lenguaje 2008-2009 90

Comprobaciones semánticas para conjuntos

� Descripción de la semántica: Los tres identificadores tienen que haber sido declarados como conjuntos. El primero de los conjuntos (el que almacenará el resultado) debe tener una capacidad máxima mayor o igual que la suma de las capacidades máximas de los operandos.

� Comprobaciones semánticas: se realizan en la producción:

� (68) operacion_conjunto : TOK_UNION ‘(‘ TOK_IDENTIFICADOR ‘,’ TOK_IDENTIFICADOR ‘,’TOK_IDENTIFICADOR ‘)’

Se comprueba que:� Los tres identificadores ($3.lexema, $5.lexema y $7.lexema) existen en la tabla de símbolos y

además son de clase conjunto.� La capacidad del primer conjunto es mayor o igual que la suma de las capacidades de los conjuntos

segundo y tercero.

Comprobaciones para la operación de unión

Prácticas de Procesadores de Lenguaje 2008-2009 91

Comprobaciones semánticas para conjuntos

� Descripción de la semántica: Los tres identificadores tienen que haber sido declarados como conjuntos. El primero de los conjuntos (el que almacenará el resultado) debe tener una capacidad máxima mayor o igual que el mínimo de las capacidades máximas de los operandos.

� Comprobaciones semánticas: se realizan en la producción:

� (69) operacion_conjunto : TOK_INTERSECTION ‘(‘ TOK_IDENTIFICADOR ‘,’ TOK_IDENTIFICADOR ‘,’ TOK_IDENTIFICADOR ‘)’

Se comprueba que:� Los tres identificadores ($3.lexema, $5.lexema y $7.lexema) existen en la tabla de símbolos y además son

de clase conjunto.� La capacidad del primer conjunto es mayor o igual que el mínimo de las capacidades de los conjuntos

segundo y tercero.

Comprobaciones para la operación de intersección

Prácticas de Procesadores de Lenguaje 2008-2009 92

Comprobaciones semánticas para conjuntos

� Descripción de la semántica: La expresión tiene que ser de tipo entero y el conjunto tiene que estar declarado. Aunque no aparece de manera explícita en la descripción de la semántica, parece razonable que el nivel de indirección de la expresión sea 1ó 0 ya que no existen conjuntos de punteros.

� Comprobaciones semánticas: se realizan en la producción:

� (70) operacion_conjunto : TOK_ADD ‘(‘ exp ‘,’ TOK_IDENTIFICADOR ‘)’

Se comprueba que:� El identificador ($5.lexema) existe en la tabla de símbolos y además es de clase conjunto.� El tipo de la expresión es INT y su nivel de indirección 0 ó 1.

Comprobaciones para la operación de inserción

Prácticas de Procesadores de Lenguaje 2008-2009 93

Comprobaciones semánticas para conjuntos

� Descripción de la semántica: En la descripción de la semántica no hay una mención explícita, pero es evidente que la operación de vaciado (limpieza) de un conjunto debe operar sobre un conjunto.

� Comprobaciones semánticas: se realizan en la producción:

� (71) operacion_conjunto : TOK_CLEAR ‘(‘ TOK_IDENTIFICADOR ‘)’

Se comprueba que:� El identificador ($3.lexema) existe en la tabla de símbolos y además es de clase conjunto.

Comprobaciones para la operación de borrado

Prácticas de Procesadores de Lenguaje 2008-2009 94

Comprobaciones semánticas para las condiciones

� Descripción de la semántica: Las expresiones que aparecen como condiciones en las sentencias if, if-else y while deben ser de tipo boolean.

� Comprobaciones semánticas: hay que comprobar que las condiciones de los bucles while y de las sentencias condicionales son de tipo boolean. Aunque no aparece de manera explícita en la descripción de la semántica, parece razonable que el nivel de indirección de las condiciones sea 0 ó 1.Las producciones implicadas en la comprobación de esta restricción semántica son las siguientes:

� (50) condicional : TOK_IF ‘(‘ exp ‘)’ ‘{‘ sentencias ‘}’� (51) condicional : TOK_IF ‘(‘ exp ‘)’ ‘{‘ sentencias ‘}’ TOK_ELSE ‘{‘ sentencias ‘}’� (52) bucle : TOK_WHILE ‘(‘ exp ‘)’ ‘{‘ sentencias ‘}’

Las comprobaciones se realizan sobre el no terminal exp que es el que representa la condición.

Prácticas de Procesadores de Lenguaje 2008-2009 95

Comprobaciones semánticas para las condiciones

� Modificación de la gramática: los puntos adecuados para realizar las comprobaciones sobre el símbolo exp se sitúan después de él y antes del no terminal sentencias. Por ejemplo, para la sentencia condicional simple, los puntos posibles son los indicados con {acción} :

� (50) condicional : TOK_IF ‘(‘ exp {acción} ‘)’ ‘{‘ sentencias ‘}’� (50) condicional : TOK_IF ‘(‘ exp ‘)’ {acción} ‘{‘ sentencias ‘}’� (50) condicional : TOK_IF ‘(‘ exp ‘)’ ‘{‘ {acción} sentencias ‘}’

Una vez elegido el punto, para poder situar la acción semántica al final de la regla, sería necesario modificar la gramática. Por ejemplo si se elige el primer punto, la gramática se manipula de la siguiente manera:

� Se añade un nuevo símbolo no terminal if_exp para situar la acción semántica al final de una regla:

if_exp : TOK_IF ‘(‘ exp {acción}

� La producción original (50) quedaría de la siguiente manera:

(50) condicional : if_exp ‘)’ ‘{‘ sentencias ‘}’

Prácticas de Procesadores de Lenguaje 2008-2009 96

Comprobaciones semánticas para las condiciones

� En la nueva regla,

if_exp : TOK_IF ‘(‘ exp {acción}

Se comprueba que:� La expresión es de tipo boolean, es decir, $3.tipo == BOOLEAN� La expresión tiene un nivel de indirección igual a 0 ó 1, por ejemplo, $3.direcciones < 2.

� Se aplica el mismo razonamiento para la sentencias if-else y while.

Prácticas de Procesadores de Lenguaje 2008-2009 97

Comprobaciones semánticas para la sentencia iterativa

� Descripción de la semántica: El identificador que aparece después del paréntesis que sigue a la palabra reservada for tiene que ser declarado de tipo int y con un nivel de indirección igual a 1. Las dos expresiones que aparecen en la parte derecha de la regla deben ser de tipo int y con nivel de indirección no superior a 1.

� Comprobaciones semánticas: La producción implicada en las comprobaciones semánicas es:

� (53) bucle : TOK_FOR ‘(‘ TOK_IDENTIFICADOR ‘=‘ exp ‘;’ exp ‘)’ ‘{‘ sentencias ‘}’

y el punto adecuado se sitúa entre el segundo símbolo exp y el no terminal sentencias. Para situar la acción al final de una regla se modifica la gramática de la siguiente manera:

� Se añade un nuevo símbolo no terminal for_id_exp_exp:

for_id_exp_exp : TOK_FOR ‘(‘ TOK_IDENTIFICADOR ‘=‘ exp ‘;’ exp ‘)’ ‘{‘ {acción}

� La producción original (53) quedaría de la siguiente manera:

(53) bucle : for_id_exp_exp sentencias ‘}’

Prácticas de Procesadores de Lenguaje 2008-2009 98

Comprobaciones semánticas para la sentencia iterativa

� En la nueva regla,

for_id_exp_exp : TOK_FOR ‘(‘ TOK_IDENTIFICADOR ‘=‘ exp ‘;’ exp ‘)’ ‘{‘ {acción}

Se comprueba que:� El identificador ($3.lexema) existe en la tabla de símbolos, y es de clase escalar y de tipo INT.� La primera expresión es de tipo INT ($5.tipo == INT) y su nivel de indirección no es superior a 1

($5.direcciones<2)� La segunda expresión es de tipo INT ($7.tipo == INT) y su nivel de indirección no es superior a 1

($7.direcciones<2)

Prácticas de Procesadores de Lenguaje 2008-2009 99

Comprobaciones semánticas para la sentencia switch

� Descripción de la semántica: La expresión que aparece encerrada entre paréntesis detrás de la palabra reservada switch debe ser de tipo int y con nivel de indirección 0 ó 1.

� Comprobaciones semánticas: La producción implicada en las comprobaciones semánticas es:� (62) seleccion : TOK_SWITCH ‘(‘ exp ‘)’ ‘{‘ casos_seleccion ‘}’

y el punto adecuado se sitúa entre el símbolo exp y el no terminal casos_seleccion. En ese punto se comprueba que:

� La expresión es de tipo INT.� La expresión tiene nivel de indirección 0 ó 1.

Prácticas de Procesadores de Lenguaje 2008-2009 100

Comprobaciones para sentencias de entrada

� Descripción de la semántica: Las operación de entrada scanf se efectúa sobre elementos de clase escalar que pueden ser identificadores o elementos de vector.

� Comprobaciones semánticas: Las dos producciones de entrada de datos son:

� (54) lectura : TOK_SCANF TOK_IDENTIFICADOR� (55) lectura : TOK_SCANF elemento_vector

Solamente es necesario realizar comprobaciones semánticas en la primera regla. Se comprueba que:

� El identificador ($2.lexema) existe en la tabla de símbolos, y es de clase escalar.

Prácticas de Procesadores de Lenguaje 2008-2009 101

Comprobaciones para sentencias de salida

� Descripción de la semántica: La operación de escritura printf trabaja con expresiones cuyo nivel de indirección no sea superior a 1, es decir, no se permite la escritura de punteros. La operación de salida cprintf trabaja sobre colecciones (conjuntos o vectores)

� Comprobaciones semánticas: La producción correspondiente a la operación de escritura printf es la siguiente:

� (56) escritura : TOK_PRINTF exp

En esta producción se comprueba únicamente que el nivel de indirección de la expresión no sea superior a 1, es decir, $2.direcciones<2.

La operación de salida cprintf se ajusta a la sintaxis de la regla:� (57) escritura : TOK_CPRINTF TOK_IDENTIFICADOR

En esta producción se comprueba que el identificador ($2.lexema) existe en la tabla de símbolos y que además es de clase vector o de clase conjunto.

Prácticas de Procesadores de Lenguaje 2008-2009 102

Otras comprobaciones semánticas

� En la descripción de la semántica de ALFA proporcionada en el enunciado de la práctica sólo se mencionan los aspectos más relevantes. Además de éstos, hay un conjunto de restricciones semánticas que también deben estar presentes en el compilador de ALFA, como por ejemplo:

� Una sentencia de retorno de función solamente debe aparecer en el cuerpo de una función.� En el cuerpo de una función obligatoriamente tiene que aparecer al menos una sentencia de

retorno.� En una sentencia de retorno el tipo de la expresión debe de coincidir con el tipo de retorno de la

función y además con nivel de indirección 0 ó 1.� etc