Está en la página 1de 30

TECNOLÓGICO NACIONAL DE MÉXICO INSTITUTO TECNOLÓGICO DE ACAPULCO

INGENIERÍA EN SISTEMAS COMPUTACIONALES

LENGUAJE Y AUTOMATAS II

UNIDAD 1: ÁNALISIS SEMÁNTICO

ACTIVIDADES DE LA UNIDAD I

PROFESOR:
BEDOLLA SOLANO SILVESTRE

INTEGRANTES DE EQUIPO:
SÁNCHEZ JIMÉNEZ ISAAC DANIEL..................17320983

DÍAZ CORTÉS ANGEL ALBERTO.....................17320830

DE LOS SANTOS TELIS JESÚS LEONARDO 17320829

MOLINA DEMETRÍO EDWIN MACARIO..........17320922

HORARIO: 2:00 – 3:00 AULA: R7SA

7° SEMESTRE

FECHA: 02/OCTUBRE/2020

1
ÍNDICE
Introducción....................................................................................................................3
Desarrollo.......................................................................................................................5
Actividad 1. Elabora 3 ejercicios y detecta el error semántico............................................................5
Actividad 2. Diseña y selecciona información sobre la construcción de un analizador semántico..................................9
Actividad 3. Reconocer el manejo de tipos en las expresiones y el uso de operadores....................13
Actividad 4. Establecer las reglas para la conversión de tipos (casting) en expresiones...................15
Actividad 5. Agregar acciones semánticas a la estructura de la gramática........................................17
Actividad 6. Manipular la tabla de conversión de símbolos y de errores y direcciones.....................21
Actividad 7. Integrar equipos de trabajo para la construcción de un analizador semántico.24
Conclusiones................................................................................................................29
Bibliografía...................................................................................................................30
Introducción

En esta unidad, la cual es la primera se verá el proceso de la compilación se


desglosa en dos partes: la parte que depende solo del lenguaje fuente (etapa inicial)
y la parte que depende solo del lenguaje objeto (etapa final). La etapa inicial traduce
un programa fuente a una representación intermedia a partir de la cual la etapa final
genera el código objeto. De esta forma, los detalles que tienen que ver con las
características del lenguaje objeto (código ensamblador, código maquina absoluto o
relocalizable), la arquitectura de la maquina (número de registros, modos de
direccionamiento, tamaño de los tipos de datos, memoria cache), el entorno de
ejecución (estructura de registros y memoria de la máquina donde se va a ejecutar el
programa) y el sistema operativo se engloban en la etapa final y se aíslan del resto.

El código intermedio es un código abstracto independiente de la máquina para la que


se generará el código objeto. El código intermedio ha de cumplir dos requisitos
importantes: ser fácil de producir a partir del análisis sintáctico, y ser fácil de traducir
al lenguaje objeto.

¿Qué es un compilador?
Un compilador son programas de computadoras que traducen un lenaguaje a otro.
Un compilador toma como su entrada un programa escrito en su lenguaje fuente y
produce un programa equivalente escrito en su lenguaje objetivo. (Ilustración 1)

Ilustración 1. Función del compilador


¿Qué es un analizador semántico?
La semántica de un programa determina su comportamiento durante el tiempo de
ejecución, pero la mayoría de los lenguajes de programación tiene características
que se pueden determinar antes de la ejecución e incluso no se pueden expresar de
manera adecuada como sintaxis y analizador sintáctico.

Error de semántica
Un error semántico se produce cuando la sintaxis del código es correcta, pero la
semántica o significado no es el que se pretendía. La construcción obedece las
reglas del lenguaje, y por ello el compilador o intérprete no detectan los errores
semánticos. Los compiladores e intérpretes sólo se ocupan de la estructura del
código que se escribe, y no de su significado. (Ilustración 2)

Ilustración 2. Ejemplo de error en la semántica


Desarrollo

Actividad 1. Elabora 3 ejercicios y detecta el error semántico


Este programa esta echo en el lenguaje C# donde en mi código me muestra el error
siguiente donde no puedo combinar valores enteros con cadenas (Ilustración 1)

Ilustración 3, Error de semántica en el código

Dónde al momento de compilar el programa, aparece la siguiente ventana que dice


que no puedo usar una variable de tipo entero donde debe ir variable de tipo cadena
(Ilustración 2)

Ilustración 4. Compilación del programa

5
Entonces me dirijo a ese apartado y cambio mi variable de tipo int a variable string
para que se compile bien, y vemos que a la hora de compilar ya no marcara el error.
(Ilustración 3)

Ilustración 5. Ejecución del código ya corregido

Ejercicio 2
El programa a continuación este hecho en el lenguaje de programación JAVA, la
función de tal programa es realizar una conversión de grados °F (Fahrenheit) a °C
(Celsius).

Ilustración 6. Ejecución del código

6
Sin embargo, al momento de compilar el programa nos muestra un error semántico.
El error semántico que nos muestra se debe a que a la variable a la que hemos
llamado f le hemos asignado un tipo de dato float, y a la otra variable que hemos
llamado c le hemos asignado el tipo de dato int. Específicamente, el error se debe a
que hemos intentado asignar un flotador a una variable de tipo entero.

Ilustración 7. Se muestra el error semántico

Para que podamos compilar el programa sin ningún problema sería asignar a las
variables tipos de datos igual, en este, en ambas variables les asignaremos el tipo de
dato entero y como se muestra a continuación no tendremos ningún problema.
Ejercicio 3

Otro ejemplo es la pérdida de precisión durante una conversión: A veces se puede


aplicar fundición incorrectamente. Por ejemplo, echando un float, un int funciona bien,
pero en la pérdida de la parte decimal del número.
Actividad 2. Diseña y selecciona información sobre la construcción
de un analizador semántico.

Analizador semántico
Este es el ejemplo del analizador semántico, aquí mostrara los tipos de errores
semánticos que se generan de una tabla de símbolos que contiene el nombre de las
variables que declaran o que le asignan un valor de acuerdo a su tipo de datos con la
que fue definido.
 Esta es la interfaz del programa.
a) texto de archivo: que es donde vamos a poner el programa a analizar.
b) tabla de símbolos: donde saldrá el tipo de datos que es cada uno.
c) código convertido: es básicamente donde saldrá el resultado del programa,
pero convertido a Basic.
d) lista de errores sintácticos y semánticos: aquí se mostrará los errores que el
analizador haya encontrado.
e) Generar tabla análisis lexico: este botón generara la “tabla de símbolos”.
f) Limpiar: es para borrar los datos analizados.

 Aquí tenemos el ejemplo que es básicamente un error de tipo semántico.


Cuando damos en “generar tabla analisis lexico” nos arroja los tipos de simbolos que
detecta, y tambien nos da los errores que encontro al momento de analizar los datos,
emn este caso lo encontro en la linea 9, el cual dice que en la linea 10 esta declarada
la letra A como tipo string, pero arriba esta declarada como tipo int, y por eso nos da
ese error semantico.

 Como podemos observar ya corregimos el error y por lo tanto ya no marca.


 Ya que no tenemos ningún error, le damos en la opción de “traducir a programa”

 Y nos va a mandar el código convertido de ese programa, ya analizado


correctamente
Actividad 3. Reconocer el manejo de tipos en las expresiones y el
uso de operadores

Analizador semántico
El analizador semántico detecta la validez semántica de las sentencias aceptadas
por el analizador sintáctico. El analizador semántico suele trabajar simultáneamente
al analizador sintáctico y en estrecha cooperación.

Tipos de expresiones en la semántica

Expresión aritmética: Son aquellos que hacen uso de operadores aritméticos

Ejemplo:

15+20+14 = 49, 78-20= 50

Expresiones relacionales: El resultado de estas expresiones siempre será


verdadero o falso

Ejemplo:

3 < 15 Verdadero, 3 <= 2 Falso

Expresiones lógicas: Solo hacen uso de operadores lógicos

Ejemplo:

23 < 53 y 80>26 Verdadero

Aquí se cumple con lo que es la comparación, donde indica que el “53” es mayor que
“23” y donde el “80” es mayor que “26” así que cumple con la regla.

Expresiones alfanuméricas: En estas expresiones se puede hacer el uso de la


concatenación para poder unir variables con variables y enteros con enteros.

Ejemplo:

String suma1= 4, String suma2 = 17;

Donde la concatenación funciona de la siguiente manera: System.out.println


(“suma1=”+suma2); donde el resultado de esta concatenación será 21.
Expresiones de asignación: Son usadas para asignar valores a variables o
constantes

Ejemplo:

String Materia = “Lenguaje y autómatas”;, String Unidad = “Analizador semántico”;

Operadores

 Booleano: Un byte, o (false), 1 (true)


 Carácter: Un byte, ASCII Java: dos bytes, UNICODE
 Entero: Dos bytes
 Real: Coma fija, como flotante
 Tipo cadena
Actividad 4. Establecer las reglas para la conversión de tipos
(casting) en expresiones

Cuando los operandos de cada operación binaria asociados a un operador son de


distinto tipo, el compilador los convierte a un tipo común. Existen reglas que rigen
estas conversiones, y aunque pueden cambiar ligeramente de un compilador a otro,
en general serán más o menos así:

Cualquier tipo entero pequeño como char o short es convertido a int o unsigned
int.En este punto cualquier pareja de operandos será int (con o sin signo), long, long
long, double, float o long double.

1. Si un operando es de tipo long double, el otro se convertirá a long double.


2. Si un operando es de tipo double, el otro se convertirá a double.
3. Si un operando es de tipo float, el otro se convertirá a float.
4. Si un operando es de tipo unsigned long long, el otro se convertirá a unsigned
long long.
5. Si un operando es de tipo long long, el otro se convertirá a long long.
6. Si un operando es de tipo unsigned long, el otro se convertirá a unsigned long.
7. Si un operando es de tipo long, el otro se convertirá a long.
8. Si un operando es de tipo unsigned int, el otro se convertirá a unsigned int.
9. Llegados a este punto ambos operandos son int.
Por ejemplo: Escribiremos expresiones numéricas en que no todas son del mismo
tipo:

Char n;
Int a, b, c, d;
Float r, s, t;
a= 10;
b = 100;
r=1000;
c=a+b; caso 9, ambas son int
s=r+a; caso 3, a se convierte a float
d=r+b; caso 3, b se convierte a float
d=n+a+r; caso 1, n se convierte a int, la operación resultante corresponde al caso 3, el
resultado (n+a) se convierte a float
t = r+a s +c; caso 3, a se convierte a float, caso 4 (r+a) y s son float, caso 4, c se
convierte a float.

También se aplica conversión de tipos en las asignaciones, cuando la variable


receptora es de distinto tipo que el resultado de la expresión de la derecha. En el
caso de las asignaciones, cuando la conversión no implica pérdida de precisión, se
aplican las mismas reglas que para los operandos, estas conversiones se conocen
también como promoción de tipos. Cuando hay pérdida de precisión, las
conversiones se conocen como democión de tipos. El compilador normalmente emite
un aviso o advertencia, cuando se hace una democión implícita, es decir cuando hay
una democión automática.
Actividad 5. Agregar acciones semánticas a la estructura de la
gramática

El lenguaje empleado para especificar las acciones semánticas recibe el nombre de


metalenguaje. Realmente, ni la notación de especificación de las reglas semánticas,
ni la especificación de los tipos (dominios) de los atributos, son intrínsecos al
concepto de gramática atribuida [Scott00].
En ocasiones, las gramáticas atribuidas que emplean un metalenguaje que permite la
utilización de funciones que tengan efectos colaterales son denominadas definiciones
dirigidas por sintaxis definiciones atribuidas.
Esquemas de traducción dirigidos por la sintaxis
Nuestro objetivo es especificar una serie de acciones que se realizarán durante el
análisis de la entrada y tener un mecanismo que nos permita obtener la información
necesaria para realizar estas acciones. Para esto añadimos a las gran áticas dos
elementos nuevos:
 Acciones intercaladas en las reglas.
 Atributos asociados a los no terminales de la gran ática.
Acciones intercaladas en las reglas
Supongamos que tenemos el no terminal (A) que deriva dos partes diferenciadas y
queremos que se escriba el mensaje “Cambio de parte” tras analizarse la primera.
Podemos describir esto de forma sencilla si aumentamos nuestra gran ática
incluyendo la acción en la parte derecha de la regla de (A):
(A) → (Parte1) {escribe (“Cambio de parte”);} (Parte2)
Podemos entender esta regla extendida como la receta: “analiza la primera parte,
una vez encontrada, escribe el mensaje y después analiza la segunda parte”.
Otros elementos de las acciones
Como habrás comprobado, no hemos definido ningún lenguaje formal para escribir
las acciones. Asumiremos que se emplean construcciones corrientes de los
algoritmos tales como condicionales o bucles. También haremos referencia en ellos a
subrutinas y a variables. Las variables las interpretaremos como variables locales a
la regla que estamos analizando o como variables globales si lo indicamos
explícitamente.
Un recurso muy útil son los atributos que contienen listas. Por ejemplo, para una
declaración de variables del tipo:
(DecVariables) → (Listalds) : (Tipo)
(Listalds) → id, (Listalds) | id
Podemos hacer lo siguiente:

(DeclVariables) → (ListaIds):(Tipo)
{para v en (ListaIds).l hacer: declara_var(v, hTipoi.t) fin para}
(ListaIds) → id,(ListaIds)1 {(ListaIds).l:= concat( [id.lexema],
(ListaIds)1.l)}
(ListaIds) → id {(ListaIds).l:= [id.lexema]}
Con lo que hemos visto, podemos decir que un esquema de traducción consta de:
 Una gramática incontextual que le sirve de soporte.
 Un conjunto de atributos asociados a los símbolos terminales y no terminales.
 Un conjunto de acciones asociadas a las partes derechas de las reglas.
Dividimos los atributos en dos grupos:
 Atributos heredados.
 Atributos sintetizados.
Sea (A) → (X1)…(Xn) una producción de nuestra gramática. Exigiremos
qué: Las acciones de la regla calculen todos los atributos sintetizados de
(A).
Las acciones situadas a la izquierda de (Xi) calculen todos los atributos heredados de
(Xi).
Ninguna acción haga referencia a los atributos sintetizados de los no terminales
situados a su derecha en la producción.
Las dos últimas reglas nos permitirán integrar las acciones semánticas en los
analizadores descendentes recursivos. Cuando se emplean, se dice que el esquema
de traducción está basado en una gramática L-atribuida. La L indica que el análisis y
evaluación de los atributos se pueden hacer de izquierda a derecha.
La interpretación de las acciones como sentencias que se ejecutan al pasar el
análisis por ellas permite implementar los esquemas de traducción de manera
sencilla. Para ello se modifica la implementación del analizador recursivo
descendente correspondiente a la gramática original de la siguiente manera:
 Los atributos heredados del no terminal (A) se interpretan como parámetros
de entrada de la función Analiza_A.
 Los atributos sintetizados del no terminal (A) se interpretan como parámetros
de salida de la función Analiza_A.
 Las acciones semánticas, una vez traducidas al lenguaje de programación
correspondiente, se insertan en la posición correspondiente según su orden
en la parte derecha donde aparecen.
En la práctica, es frecuente que, si el lenguaje de programación (como C) no permite
devolver más de un valor, los atributos sintetizados del no terminal se pasen por
referencia.
El análisis semántico se realiza después del sintáctico y es más difícil de formalizar
que éste. Se trata de determinar el tipo de los resultados intermedios, comprobar que
los argumentos que tiene un operador pertenecen al conjunto de los operadores
posibles, y si son compatibles entre sí, es decir, comprobará que el significado de lo
que se va leyendo es válido. El análisis semántico utiliza como entrada el árbol
sintáctico detectado para comprobar restricciones de tipo y otras limitaciones
semánticas y preparar la generación de código.
La salida “teórica” de la fase de análisis semántico sería un árbol semántico.
Consiste en un árbol sintáctico en el que cada una de sus ramas ha adquirido el
significado que debe tener. En el caso de los operadores polimórficos (un único
símbolo con varios significados), el análisis semántico determina cuál es el aplicable.
Por ejemplo, consideremos la siguiente sentencia de asignación: A := B + C.

Ejemplo
En Pascal, el signo “+” sirve para sumar enteros y reales, concatenar cadenas de
caracteres y unir conjuntos. El análisis semántico debe comprobar que B y C sean de
un tipo común o compatible y que se les pueda aplicar dicho operador. Si B y C son
enteros o reales los sumará, si son cadenas las concatenará y si son conjuntos
calculará su unión.

Dependiendo del tipo de sentencias, las acciones semánticas pueden agruparse en:

Acción semántica Descripción


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.

Funciones y procedimientos Comprobar el número, orden y tipo de


los parámetros actuales en cada
llamada a una función o procedimiento.
Identificación de variables Comprobar si un 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.

Actividad 6. Manipular la tabla de conversión de símbolos y de


errores y direcciones

La tabla de símbolos es una estructura de datos que contiene toda la información


relativa a cada identificador que aparece en el programa fuente. Los identificadores
pueden ser de variables, tipos de datos, funciones, procedimientos, etc...
Evidentemente cada lenguaje de programación tiene unas características propias
que se reflejan en la tabla de símbolos.
Cada elemento de la estructura de datos que compone la tabla de símbolos está
formado al menos por el identificador y sus atributos. Los atributos son la información
relativa de cada identificador. Los atributos habituales son:
 Especificación del identificador. variable, tipo de datos, función,
procedimiento, etc...
 Tipo. en el caso de variables será el identificador de tipo (real, entero,
carácter, cadena de caracteres, o un tipo definido previamente). En el caso de
las funciones puede ser el tipo devuelto por la función. Los procedimientos se
pueden marcar como funciones que no devuelven nada (void).
 Dimensión o tamaño. Puede utilizarse el tamaño total que ocupa una variable
en bytes, o las dimensiones. Así en el caso de variables simples se coloca la
dimensión cero, para los arrays la dimensión del array, en el caso de
estructuras (struct) o registros (record) el número de campos o miembros, en
el caso de funciones o procedimientos se puede almacenar el número de
parámetros, etc.
 Dirección de comienzo para generar el código objeto. En el código
máquina no hay nombre de identificadores, tan sólo direcciones de memoria
para datos (static, stack, y heap) o para código (usadas por los procedimientos
y funciones).
 Listas de información adicional. Contienen información de tamaño variable,
por ejemplo: los tipos de los campos o miembros de las estructuras o
registros, los tipos de los parámetros de estructuras o uniones.
Los atributos pueden variar de unos lenguajes a otros, debido a las características
propias de cada lenguaje y a la metodología de desarrollo del traductor.
La tabla de símbolos se crea por cooperación del análisis léxico y el análisis
sintáctico. El análisis léxico proporciona la lista de los identificadores, y el análisis
sintáctico permite rellenar los atributos correspondientes a cada identificador. El
analizador semántico también puede rellenar algún atributo.
El analizador semántico y el generador de código obtienen de la tabla de símbolos la
información necesaria para realizar su tarea.
Las operaciones fundamentales que se realizan en la tabla de símbolos son la
inserción y búsqueda de información. En algunos lenguajes de programación también
se realizan las operaciones set y reset que activan y desactivan los identificadores
locales respectivamente. Dada la cantidad de veces que se accede a la tabla de
símbolos es necesario que la estructura de datos que alberga la información, y los
algoritmos de acceso sean optimizados al máximo. En general se utilizan métodos
hash para el manejo de las tablas de símbolos.
Las tablas de símbolos constituyen el recipiente donde se almacena toda la
información relativa al programa fuente en tiempo de compilación y por tanto se
destruyen una vez finalizada la traducción. Tan sólo hay una excepción en el caso de
que se activen opciones de depuración (debugging), en ese caso los compiladores
graban en fichero la tabla de símbolos para poder dar información de los
identificadores usados en el programa fuente en tiempo de ejecución. Los fabricantes
de compiladores incluyen para esos casos información de la tabla de símbolos que
emplean.
En general en la Tabla de símbolos (TS a partir de ahora) se realizan dos
operaciones: la inserción y la búsqueda.
En C la operación de inserción se realiza cuando se procesa una declaración.
Hay dos posibilidades: que la TS esté ordenada (o sea, nombres de variables por
orden alfabético) o que no esté ordenada.
Si está ordenada, entonces la operación de inserción llama a un procedimiento de
búsqueda para encontrar el lugar donde colocar los atributos del identificador a
insertar, por lo que en este caso la inserción lleva tanto tiempo como la búsqueda. En
cambio, si no está ordenada la TS, la inserción se simplifica mucho, aunque se
complica la búsqueda, pues debe examinar toda la tabla.
En la búsqueda, se detectan los identificadores que no hayan sido declarados
previamente, emitiendo un mensaje de error.
 ejemplo en lenguaje C: Undefined símbolo 'x', si es una variable que desea
usarse, pero no se declaró.
En la inserción, se detectan identificadores que ya han sido declarados previamente,
emitiendo un mensaje de error
 ejemplo en C: multipledeclarationfor 'x' si x ya estaba en TS.
Un nombre puede indicar varios objetos distintos, quizás incluso en el mismo bloqueo
o procedimiento.
Actividad 7. Integrar equipos de trabajo para la construcción de un
analizador semántico.

Análisis semántico
Se compone de un conjunto de rutinas independientes, llamadas por los analizadores
morfológico y sintáctico.
El análisis semántico utiliza como entrada el árbol sintáctico detectado por el análisis
sintáctico para comprobar restricciones de tipo y otras limitaciones semánticas y
preparar la generación de código.
En compiladores de un solo paso, las llamadas a las rutinas semánticas se realizan
directamente desde el analizador sintáctico y son dichas rutinas las que llaman al
generador de código. El instrumento más utilizado para conseguirlo es la gramática
de atributos.
En compiladores de dos o más pasos, el análisis semántico se realiza
independientemente de la generación de código, pasándose información a través de
un archivo intermedio, que normalmente contiene información sobre el árbol
sintáctico en forma linealizada (para facilitar su manejo y hacer posible su
almacenamiento en memoria auxiliar).
En cualquier caso, las rutinas semánticas suelen hacer uso de una pila (la pila
semántica) que contiene la información semántica asociada a los operandos (y a
veces a los operadores) en forma de registros semánticos.
Propagación de atributos
Sea la expresión
int a,b,c;
a/(b+c^2)
El árbol sintáctico es:
/

| |
a +
| |
b ^

| |
c 2
De la instrucción declarativa, la tabla de símbolos y el analizador morfológico
obtenemos los atributos de los operandos:
/

| |
a +
int
| |
b ^
int
| |
c 2
int int
Propagando los atributos obtenemos:
/ int

| |
a + int
int
| |
b ^ int
int
| |
c 2
int int
Si la expresión hubiera sido
a/(b+c^-2)
El árbol sintáctico sería el mismo, sustituyendo 2 por -2. Sin embargo, la propagación
de atributos sería diferente:
/ real

| |
a + real
int ---------
| |
b ^ real
int ---------
| |
c -2
int int
En algún caso podría llegar a producirse error (p.e. si / representara sólo la división
entera).
Si la expresión hubiera sido
int a,b,c,d;
a/(b+c^d)
El árbol sintáctico sería el mismo, sustituyendo 2 por d. Sin embargo, la propagación
de atributos sería incompleta:
/ {int,real}

| |
a + {int,real}
int
| |
b ^ {int,real}
int
| |
c d
int int
El analizador semántico podría reducir los tipos inseguros al tipo máximo (real) o
utilizar un tipo interno nuevo (ej. arit={int,real}, una unión).
Lo anterior es un ejemplo de propagación bottom-up. La propagación top-down
también es posible: lo que se transmite son las restricciones y los tipos de las hojas
sirven de comprobación. Por ejemplo, si la división sólo puede ser entera,
transmitimos hacia abajo la restricción de que sus operandos sólo pueden ser
enteros. Al llegar a d, esa restricción se convierte en que d debe ser positiva. Si no lo
es, error.
La implantación de todos los casos posibles de operación con tipos mixtos podría ser
excesivamente cara. En su lugar, se parte de operaciones relativamente simples (ej.
int+int, real+real) y no se implementan las restantes (ej. int+real, real+int), añadiendo
en su lugar operaciones monádicas de cambio de tipo (ej. int->real).
Esta decisión puede introducir ambigüedades. Por ejemplo, sea el programa
real a;
int b,c;
a:=b+c
El árbol sintáctico es:
:=

| |
a +
real
| |
b c
int int
Existen dos conversiones posibles:
:= real := real

| | | |
a + real a + int
real --------- real ---------
| | ||
b c b c
int int int int
El problema es que no tenemos garantía de que los dos procedimientos sean
equivalentes. El segundo puede dar overflow, la primera pérdida de precisión. La
definición del lenguaje debe especificar estos casos.
Las transformaciones posibles se pueden representar mediante un grafo cuyos
nodos son los tipos de datos y cada arco indica una transformación. Dado un
operando de tipo A que se desea convertir al tipo B, se trata de encontrar una
cadena de arcos que pase de A a B en el grafo anterior. Podría haber varios grafos,
cada uno de los cuales se aplicará en diferentes condiciones, por ejemplo, uno para
las asignaciones, otro para las expresiones, etc.
Conclusiones
Es difícil el prever todos los posibles errores semánticos, por lo que es igual de
complicado el generar el código correspondiente.

Otra actividad que se nos complico fue la implementación de casting en nuestro


compilador. Aunque al final logramos revisar e implementar dicha función usando las
tablas de contenido generado previamente.

La mayoría de los errores semánticos pueden ser detectados mediante la revisión de


la tabla de símbolos. Al hacerlo, evitamos la producción de un mensaje de error cada
vez que se use la variable no definida.
Bibliografía
Louden, K. (2004). Construcción de un compilador principios y práctica . México.

c, p. e. (s.f.). conversión de tipos (casting). webcindario. Microsoft. (08 de marzo de


2017). microsoft.com. Obtenido de
https://docs.microsoft.com/enus/dotnet/csharp/programming-guide/types/casting-and-
type-conversions

También podría gustarte