Documentos de Académico
Documentos de Profesional
Documentos de Cultura
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, contextfree 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