Está en la página 1de 17

Análisis 

semantico March 13, 2023

Análisis Semántico

Conceptos básicos:

La sintaxis  de un lenguaje de programación es el conjunto de reglas 
formales que especifican la estructura de los programas pertenecientes a 
dicho lenguaje.

La semántica  de un lenguaje de programación es el conjunto de reglas que 
especifican el significado de cualquier sentencia sintácticamente correcta.

El análisis Semántico  de un procesador de lenguaje es la fase encargada de 
detectar la validez semántica de las sentencias aceptadas por el analizador 
sintáctico.
  Fase posterior al análisis sintáctico
  Última fase dentro del proceso de análisis

Por ejemplo:
En el lenguaje C, la sentencia:
superficie = base * altura / 2;

   Sintaxis: = * /Operadores binarios (infijos) y superficie, base, altura y 2; 
elementos básicos de la expresión.

   Semántica: Asociar a superficie el resultado de multiplicar base y altura 
divididos por dos (superficie multiplicar base y altura,divididos por dos, 
superficie de un triángulo)

   Análisis semántico:  Validar que:
1. "superficie", "base" y "altura" sean declarados previamente.
2. La subexpresión de la izquierda de "=" sea una variable declarada de cierto 
tipo tal que soporte los posibles resultados.
3. Los tipos de "base" y "altura" soporten la operación "*".
4. Inferir el tipo del producto y verificar que a éste se le pueda aplicar la 
operación "/".
5. Inferir el tipo de la división y ver si éste es compatible con el tipo de 
"superficie".
Análisis semantico March 13, 2023

1.1 Árboles de expresiones

Los árboles de expresiones representan el código de nivel del lenguaje en forma de datos. 
Los datos se almacenan en una estructura con forma de árbol. Cada nodo del árbol de 
expresión representa una expresión, por ejemplo, una llamada al método o una operación 
binaria, como por ejemplo x < y. 

Ejemplo: a = b + c

Ejemplo: (2+3.5)*4
Análisis semantico March 13, 2023

Ejemplo:

Total=(a)­((10+5)*b)
Análisis semantico March 13, 2023

Ejemplo: (10+8)*10+8

E­> E+T | T
T­> T*F | F
F­> (E) | 10 | 8
Análisis semantico March 13, 2023

Ejemplo:

((a*b)+23)/(5 + 4)
Análisis semantico March 13, 2023

Ejemplo:

((a*b)+23)/(5 + 4)
Análisis semantico March 13, 2023
Gramáticas libres de contexto
Estas gramáticas, conocidas también como gramáticas de tipo 2 o gramáticas independientes
del contexto, son las que generan los lenguajes libres o independientes del contexto. Los 
lenguajes libres del contexto son aquellos que pueden ser reconocidos por un autómata de pila
determinístico o no determinístico.
Es decir, que en el lado izquierdo de una producción pueden aparecer el símbolo distinguido o
un símbolo no terminal y en el lado derecho de una producción cualquier cadena de símbolos
terminales y/o no terminales de longitud mayor o igual que 1.
La gramática puede contener también la producción S­­­>E si el lenguaje que se requiere 
generar contiene la cadena vacía.

Existen cuatro componentes importantes en una descripción gramatical de un lenguaje:

1. Un conjunto finito de símbolos que forma las cadenas del lenguaje que se está definiendo. 
Este conjunto era {0,1} en el ejemplo de los palíndromos que acabamos de ver. Denominamos a 
este conjunto alfabeto terminal o alfabeto de símbolos terminales.

2. Un conjunto finito de variables, denominado también en ocasiones símbolos no terminales o 
categorías sintácticas. Cada variable representa un lenguaje; es decir, un conjunto de cadenas. 
En el ejemplo anterior, sólo había una variable, P, que hemos empleado para representar la 
clase de palíndromos del alfabeto {0,1}.

3. Una de las variables representa el lenguaje que se está definiendo; se denomina símbolo 
inicial. Otras variables representan las clases auxiliares de cadenas que se emplean para definir 
el lenguaje del símbolo inicial. En el ejemplo anterior, la única variable, P, también es el 
símbolo inicial.

4. Un conjunto finito de producciones o reglas que representan la definición recursiva de un 
lenguaje. Cada producción consta de:

a) Una variable a la que define (parcialmente) la producción. Esta variable a menudo se 
denomina cabeza de la producción.

b) El símbolo de producción →.

c) Una cadena formada por cero o más símbolos terminales y variables. Esta cadena, 
denominada cuerpo de la producción, representa una manera de formar cadenas pertenecientes 
al lenguaje de la variable de la cabeza. De este modo, dejamos los símbolos terminales 
invariables y sustituimos cada una de las variables del cuerpo por una cadena que sabemos que 
pertenece al lenguaje de dicha variable.

Los cuatro componentes que acabamos de describir definen una gramática independiente del 
contexto, (GIC), o simplemente una gramática, o en inglés CFG, context­free grammar. 
Representaremos una GIC G mediante sus cuatro componentes, es decir, G = (V,T,P,S), 
donde V es el conjunto de variables, T son los símbolos terminales, P es el conjunto de 
producciones y S es el símbolo inicial.

Ejemplo: 

La siguiente definición describe la sintaxis (simplificada) de una sentencia de asignación
de un lenguaje tipo Pascal:
Análisis semantico March 13, 2023

1.2 Acciones semánticas de un 
analizador sintáctico.

Dependiendo del tipo de sentencias, las acciones semánticas pueden agruparse en: 
• Sentencias de Declaración: completar la sección de tipos de la Tabla de Símbolos. 
• Sentencias “ejecutables”: realizar comprobaciones de tipos entre los operandos 
implicados en una expresión. 
• Funciones y procedimientos: comprobar el número, orden y tipo de los parámetros 
actuales en cada llamada a una función o procedimiento en contraste a su declaración. 
• Identificación de variables: comprobar si el identificador ha sido declarado antes de 
utilizarlo. 
• Etiquetas: comprobar si hay etiquetas repetidas y validación. 
• Constantes: comprobar que no se utilicen en la parte izquierda de una asignación. 
• Conversiones y equivalencias de tipo: verificación. 
• Sobrecarga de operadores y funciones: detectar y solventar.

Otras acciones
Comprobaciones del flujo del control: Las proposiciones que hacen que se abandone 
el flujo del control de una construcción y deba transferirse a otro punto.

Comprobaciones de unicidad: Hay situaciones en los que un objeto solo puede 
definirse una vez exclusivamente. Las etiquetas de una sentencia case no deben 
repetirse, declaraciones de objetos,…
Análisis semantico March 13, 2023

1.3 Comprobaciones de tipos en expresiones

Un lenguaje con comprobación fuerte de tipos es capaz de garantizar que los 
programas se puedan ejecutar sin errores de tipo, por tanto los errores de tipo se 
detectarán siempre en tiempo de compilación.
Como mínimo, ante un error, un comprobador de tipos debe informar de la 
naturaleza y posición del error, y recuperarse para continuar con la 
comprobación del resto del programa a analizar.
OBJETIVO: Asegurar que el tipo de una construcción del programa coincida con 
lo previsto en su contexto.

• Compatibilidad de tipos en las asignaciones
• Operadores aplicados a datos del tipo adecuado
• N° y tipo correcto en los parámetros de funciones

(coerciones)
co

Veamos algunas de las operaciones a tener en cuenta en una 
comprobación de tipos:

• Conversión de Tipos: A veces es necesario transformar el tipo de una 
expresión para utilizar correctamente un operador o para pasar de forma 
adecuada un parámetro a una función.

• Coerción: Es una conversión de tipos que realiza de forma implícita el propio 
compilador. Si es el programador el que realiza la conversión se tratará 
entonces de una conversión explícita.

• Sobrecarga de operadores: La sobrecarga se resuelve determinando el tipo 
de cada una de las expresiones intervinientes en la sobrecarga.

• Funciones polimórficas: Son aquellas que trabajan con argumentos cuyo tipo 
puede cambiar en distintas llamadas a la función.
Análisis semantico March 13, 2023
Análisis semantico March 13, 2023

• La verificación de los tipos de datos se hace asignando el valor de tipo de cada 
una de los componentes léxicos.
• Estos valores se comparan para verificar que los tipos de datos coincidan y sean 
congruentes, de lo contrario no se pueden realizar los cálculos.
Hay situaciones en las cuales se tiene un valor de un tipo dado y se desea 
almacenar ese valor en una variable de un tipo diferente. 
• En algunos tipos es posible almacenar simplemente el valor sin una conversión de 
tipos; lo que se denomina conversión automática. Esto sólo es posible en algún 
lenguaje de programación, si el compilador reconoce que la variable destino tiene la 
suficiente precisión para contener el valor origen. Por ejemplo:
"En Java se puede almacenar un valor byte en una variable int, dado que 
este tipo de datos es de mayor precisión que el primero".

• A esto se le llama ensanchamiento o promoción, dado que el tipo más pequeño 
se ensancha o promociona al tipo compatible más grande. Si por el contrario, se 
desea asignar un valor de variable int a una variable byte se necesita realizar una 
conversión de tipos explícita.
• En algunos casos se puede realizar la conversión pero se pueden perder datos, 
como por ejemplo al pasar un valor flotante a un entero.
Análisis semantico March 13, 2023

1.4 Pila semántica en un 
analizador sintáctico.

La pila semántica es una cantidad de memoria auxiliar que permite 
guardar de manera temporal datos intermedios de manera que se 
rescaten al momento de realizar las comparaciones durante un 
análisis.

Un parser(analizador sintáctico) utiliza durante el análisis una pila, la 
cual se encarga de ir guardando los datos que le permiten realizar las 
diferentes operaciones, como reducción en ciertas partes de código 
así como parte de los elementos de la estructura analizada.

Por lo tanto, para incorporar acciones semánticas a dicha pila en la 
construcción y lectura de un árbol sintáctico, es necesario agregar 
columnas que guarden los atributos de los símbolos que se van 
analizando.

Dichos atributos están ligados directamente a las producciones 
correspondientes en la gramática guiada por atributos y su 
representación en árbol abstracto. 
Las gramáticas de atributos son gramáticas de contexto libre a cuyos símbolos 
(terminales y no terminales) se les asocia un conjunto de atributos semánticos.
Además, se definen reglas semánticas asociadas a las reglas gramaticales que 
determinan/calculan los valores de los atributos

Atributos Semánticos: Representan cualquier tipo de información asociada a los 
símbolos en las producciones.
• Ej.: tipo, valor, secuencia de código generado, punteros a entradas, ...

Reglas gramaticales: Calculan el valor de los atributos en base a los valores 
de los atributos relacionados, símbolos y al contexto.
Además, pueden incluir efectos laterales: emisión mensajes error, generar 
código, ...

Ejemplo de gramática de atributos guiada por sintaxis.

Atributos
Producciones

Reglas

Print((12+4)*5)
Análisis semantico March 13, 2023

Ejemplo 2: (5*(6+8))*D
Análisis semantico March 13, 2023
Análisis semantico March 13, 2023

1.5. Esquema de traducción.

Un esquema de traducción consiste en el uso de una gramática atribuida en 
la que hay intercalados, en el lado derecho de las reglas de producción, 
fragmentos de código en un lenguaje de programación, que implementan 
acciones semánticas. Las acciones semánticas se sitúan a la derecha de los 
símbolos a los que refiere la gramática. Esta regla de situar las acciones 
semánticas después de los símbolos que utilizan dan un orden en la 
ejecución de las mismas.

Una característica fundamental de un ETDS(esquema de traducción dirigida 
por sintaxis) es que la traducción pueda realizarse de una sola pasada y no 
permite herencia de los atributos desde la derecha hacia la izquierda.

Si tenemos una gramática y queremos que sea un ETDS debemos decidir los 
atributos necesarios y asignarlos a los símbolos de la gramática. Luego 
debemos insertar las acciones semánticas necesarias.

Debemos tener en cuenta que se deben cumplir las restricciones de un 
ETDS, es decir.

1­ Si todos los atributos son sintetizados, ponemos las acciones 
semánticas despues de los atributos implicados. Lo mejor es situarlas al final 
de la regla de producción. Para cada atributo sintetizado, siempre hay que 
calcularlo después de que hayan tomado valor todos los demás atributos que 
intervienen en el cálculo.

2­ Si hay atributos heredados:

• Un atributo heredado debe calcularse antes que aparezca el símbolo.
• Un atributo sintetizado no debe usarse antes de que aparezca el 
símbolo.

3­ Una acción semántica no debe referirse a un atributo sintetizado de un 
símbolo que esté a la derecha de la acción.

Ejemplo: Convertir una declaración de variables en C a Pascal.

Pasaremos de:

int x,y;

a esto:

var x,y:integer;

La gramática para la declaración en C de una variable es:

DeclVar ­­­­> TipoVar ListaVar puntocoma
TipoVar ­­­­> entero
ListaVar ­­­­> ListaVar coma nombreVar
ListaVar ­­­­> nombreVar

La forma de hacerlo sería:

DeclVar ­­­­> TipoVar ListaVar puntocoma
   {
     DeclVar.trad="var" + ListaVar.trad + ":" + TipoVar.trad + puntocoma.lexema;
   }
TipoVar ­­­­> entero
   {
     TipoVar.trad="integer";
   }
ListaVar ­­­­> ListaVar1 coma nombreVar
   {
     ListaVar.trad=ListaVar.trad + coma.lexema + nombreVar.lexema;
   }
ListaVar ­­­­> nombreVar
   {
     ListaVar.trad=nombreVar.lexema;   
   }
Análisis semantico March 13, 2023
1.6. Generación de la tabla de símbolos y 
de direcciones.

La fase de análisis semántico obtiene su nombre por requerir información 
relativa al significado del lenguaje, que está fuera del alcance de la 
representatividad de las gramáticas libres de contexto y los principales 
algoritmos existentes de análisis.
La mayoría de los compiladores utilizan una gramática libre de contexto para 
describir la sintaxis del lenguaje y una fase de análisis semántico posterior 
para restringir las sentencias que “semánticamente” no pertenecen al 
lenguaje.

Una vez comprobado que la sentencia es sintácticamente correcta, el analizador 
semántico deberá verificar que el identificador empleado como parte de una 
expresión haya sido declarado previamente. Para llevar a cabo esta tarea, es 
típica la utilización de una estructura de datos adicional denominada tabla de 
símbolos. Ésta poseerá una entrada por cada identificador declarado en el 
contexto que se esté analizando.

Objetivos de la Tabla de Símbolos (TS)

Las Tablas de Símbolos (en adelante TS) son estructuras de datos que 
almacenan toda la información de los identificadores del lenguaje fuente. 
Los objetivos principales de la TS en el proceso de traducción son: 
•  Colaborar con las comprobaciones semánticas. 
•  Facilitar ayuda a la generación de código. 
La información almacenada en la TS depende directamente del tipo de 
elementos del lenguaje específico a procesar y de las características de 
dicho lenguaje. Habitualmente los elementos del lenguaje que requieren 
el uso de la TS son los distintos tipos de identificadores del lenguaje 
(nombres de variables, de objetos, de funciones, de etiquetas, de clases, 
de métodos, etc.).

La información relativa a un elemento del lenguaje se almacena en los 
denominados atributos de dicho elemento. Estos atributos también varían de un 
tipo de lenguaje a otro y de un elemento a otro. Así ejemplos de atributos tales 
como nombre, tipo, dirección relativa en tiempo de ejecución, dimensiones de 
los arrays, número y tipo de los parámetros de procedimientos, funciones y 
métodos, tipos de acceso a los elementos de una clase (public, private, 
protected…), etc. se recogen y se guardan en la TS.

En los traductores y compiladores, las TS existen únicamente en tiempo 
de compilación, aunque en depuración (debug) pueden estar 
almacenadas en disco y dar información en tiempo de ejecución para 
identificar los símbolos que se deseen inspeccionar. 
En los intérpretes contienen información en tiempo de ejecución. 
Las palabras reservadas no están en la TS.

Construcción de la tabla de símbolos
1.  El analizador léxico deberá: 
x Insertar los símbolos detectados en la tabla de símbolos, 
x Crear la tabla de símbolos parcialmente, 
x Señalar la línea del programa fuente en donde aparecen. 
2.  El analizador semántico: 
x Añade los tipos, si procede, a los símbolos que aparecen en la
tabla de símbolos. 
Cuando se hace una implantación de una única pasada, los símbolos son 
insertados y calificados, a nivel semántico y de generación de código, por el 
analizador sintáctico y en el mismo instante que son detectados por el 
analizador léxico y que son pasados al analizador sintáctico.

Operaciones sobre la tabla de símbolos.
x INSERTAR
x CONSULTAR
x MODIFICAR (añadir atributos nuevos) 
El CUANDO y el CÓMO se usan estas operaciones dependen del tipo de 
lenguaje:
Lenguajes con DECLARACIONES DE VARIABLES: 
x Explícitas:
  Declaraciones: sólo INSERTAR. 
  Referencia: sólo CONSULTAR. 
x Implícitas:
  CONSULTAR si no está ya incluida. 
  INSERTAR, en caso contrario. 
  Lenguajes con estructura de BLOQUE : CREAR SUBTABLAS.

Implementación de la tabla de símbolos
La distribución de la información de la tabla de símbolos dependerá de las 
características del lenguaje y de las restricciones establecidas para los símbolos.
Campo dedicado para el símbolo. 
x Formato fijo: Apropiado cuando se establece límite en el número de caracteres 
que forman los símbolos y, además, sea pequeño.
En este caso sólo se dispone de un área fija en la tabla para almacenar el 
símbolo. 
x Formato variable: Se dispone de la tabla de símbolos y de un área auxiliar en 
donde se introducen los símbolos de modo consecutivo. En la TS se sustituye el 
campo dedicado para el nombre del símbolo por un puntero al área auxiliar y un 
entero que indica la longitud del mismo.

Campo “dirección” 
x Lenguajes SIN estructura de Bloque: Se asignan direcciones 
consecutivas según el orden en el que aparecen declaradas. 
x Lenguajes CON estructura de Bloque: Para cada bloque se asigna una 
subtabla, la dirección será consecutiva para cada bloque. 
Se necesitan dos campos básicos:

Se introduce este campo en la TS cuando se declara. Se utiliza este atributo en la 
fase de Generación de código. 
Campo “Tipo” 
Se introduce cuando se identifica una declaración explícita o implícita de una variable. 
Se utiliza para determinar la memoria de almacenamiento y para la comprobación de 
tipos.
Campo Nº de dimensiones / Nº de parámetros 
La realiza el analizador semántico y sirve para delimitar el tamaño de memoria 
necesaria para representar el símbolo. 
(Ejemplo: el tamaño o dimensión de un array; si se trata de una función o 
procedimiento, el número de argumentos que posee y sus tipos para la reserva de 
memoria). 
Campos Lista cruzada de referencia y Puntero de orden 
Son útiles para el programador del traductor con objeto de facilitar el uso de la TS.

Organización de la tabla de símbolos

b)Lenguajes CON estructura de Bloque 
x Una tabla para cada Bloque con estructura de PILA.
x Estructura con apuntadores: Consta de una PILA + Índice (que apunta al inicio 
de las variables pertenecientes a cada bloque).
El índice nos muestra el comienzo y final de un bloque. 
Además de insertar, consultar y modificar (completar la información de un símbolo), 
cuando se trabaja con bloques, se realizan además las operaciones siguientes: 
x Set(Marca de Inicio de bloque).
x Reset(Marca de Fin de bloque).
Análisis semantico March 13, 2023

1.7. Manejo de errores semánticos.

Registros de activación

Marcos de pila

El apuntador de Marco (FP)

Registros

Pase de parámetros

También podría gustarte