Análisis Semántico
1. Introducción al Análisis Semántico
El análisis semántico constituye la tercera fase esencial en el proceso de compilación, sucediendo al análisis léxico y al análisis sintáctico.2 Esta etapa toma como entrada el árbol sintáctico generado por el analizador sintáctico.4 Su objetivo primordial es verificar la corrección semántica del programa fuente y recopilar información sobre los tipos de datos que serán cruciales en las fases posteriores de generación de código.6 En esencia, el análisis semántico se encarga de asegurar que el programa tenga un sentido lógico y que las operaciones que se realizan sean válidas para los tipos de datos involucrados.7
El análisis semántico actúa como un puente fundamental entre el código que es sintácticamente correcto y el código que es lógicamente sólido, garantizando que el programa posea una interpretación coherente. Esto resulta crítico dado que un programa puede ser gramaticalmente impecable, pero aun así contener errores en su significado, como desajustes de tipos o el uso de variables no declaradas. La labor del análisis semántico consiste en dotar de un significado coherente a lo que se ha realizado en el análisis sintáctico.8 Sin esta fase, el compilador podría generar código para operaciones sin sentido, lo que conduciría a errores en tiempo de ejecución o a un comportamiento incorrecto del programa.
Las funciones principales del análisis semántico son diversas y críticas para la correcta compilación. Una de las más importantes es la verificación de tipos, que consiste en asegurar que cada operador en el programa se aplique a operandos de los tipos permitidos por la especificación del lenguaje fuente.6 Además, se verifica que las estructuras de datos como los arrays tengan definido correctamente su tamaño.6 Otra función esencial es comprobar que todos los identificadores utilizados en el programa, ya sean variables o funciones, hayan sido declarados previamente antes de su uso.9 En términos generales, el análisis semántico se encarga de verificar la consistencia del programa fuente con la definición del lenguaje en el que está escrito.10
El análisis semántico va más allá de la mera estructura del código para comprender su intención y asegurar que se adhiere a las reglas del lenguaje de programación en lo referente al significado y al uso adecuado de los elementos del lenguaje. Esta detección proactiva de errores en tiempo de compilación mejora significativamente la fiabilidad y la robustez del ejecutable final. Mientras que el análisis sintáctico confirma la correcta disposición de las palabras clave y los símbolos, el análisis semántico profundiza en si estas disposiciones forman una instrucción con sentido de acuerdo con las reglas del lenguaje. Por ejemplo, una instrucción como int x = "hello"; podría ser sintácticamente válida en algunos lenguajes de tipado flexible, pero sería señalada como un error semántico en lenguajes de tipado fuerte debido a la incompatibilidad de tipos.
2. Árboles de Expresiones
Los árboles de expresiones representan el código a nivel del lenguaje en forma de datos, almacenados en una estructura con forma de árbol.1 Cada nodo dentro de este árbol representa una expresión, que puede ser una llamada a un método o una operación binaria, entre otras.1 Estos árboles son particularmente útiles para la evaluación de expresiones matemáticas, el análisis sintáctico y el diseño de compiladores.13
La estructura jerárquica que proporcionan los árboles de expresiones para la representación de las expresiones simplifica enormemente su análisis y manipulación por parte del compilador. Esta estructura arbórea refleja de manera natural el orden en que deben realizarse las operaciones y las relaciones existentes entre los operandos y los operadores.
En la construcción de un árbol de expresiones, las hojas del árbol se etiquetan exclusivamente con operandos, que pueden ser tanto variables como constantes.1 Por otro lado, los nodos internos del árbol se etiquetan con operadores.1 Una característica fundamental de estos árboles es que su estructura preserva la precedencia de los operadores, asegurando que el orden de las operaciones se mantenga intacto.13
Consideremos algunos ejemplos para ilustrar la construcción de árboles de expresiones. Para la expresión (a + b) * c / d, el árbol de expresiones resultante tendría la siguiente estructura 1:
En este árbol, el nodo raíz es el operador de división /, que es la última operación que se realiza según el orden de las operaciones. Sus hijos son la subexpresión (a + b) * c, representada por el nodo *, y el operando d, que es un nodo hoja. El hijo izquierdo de * es la subexpresión a + b, representada por el nodo +, cuyos hijos son los operandos a y b, ambos nodos hoja. El hijo derecho de * es el operando c, también un nodo hoja.
Otro ejemplo es la expresión a - 4 + c.9 La construcción de este árbol se puede realizar paso a paso. Primero, se crea un nodo hoja para el identificador a. Luego, se crea un nodo hoja para el número 4. A continuación, se crea un nodo interno para el operador -, cuyo hijo izquierdo es el nodo de a y cuyo hijo derecho es el nodo de 4. Después, se crea un nodo hoja para el identificador c. Finalmente, se crea un nodo interno para el operador +, cuyo hijo izquierdo es el nodo de la subexpresión a - 4 y cuyo hijo derecho es el nodo de c.
La expresión a + a * (b - c) + (b - c) * d ilustra el concepto de grafos acíclicos dirigidos (DAGs) para representar subexpresiones comunes.9 En un DAG, la subexpresión (b - c) aparecería representada una sola vez, con ambos operadores de multiplicación (* con a y * con d) apuntando al mismo nodo. Esto se logra mediante la reutilización de la estructura creada previamente para la subexpresión común.
La manera en que se construye un árbol de expresiones tiene un impacto directo en cómo el compilador puede posteriormente recorrer y procesar la expresión para realizar comprobaciones semánticas y generar el código. Los DAGs, al identificar y fusionar subexpresiones comunes, pueden conducir a un código más eficiente al evitar cálculos redundantes. En la expresión (b - c) aparece dos veces. En un árbol de expresiones estándar, esta subexpresión estaría representada por dos subárboles idénticos. Un DAG la representaría solo una vez, con ambos nodos padre apuntando al mismo subárbol, lo que ahorraría memoria y potencialmente tiempo de cálculo.
El recorrido de un árbol de expresiones en diferentes órdenes da como resultado diferentes formas de la expresión original.1 Un recorrido en preorden produce la forma prefija de la expresión. En el ejemplo (a + b) * c / d, la forma prefija sería / * + a b c d. Un recorrido en inorden produce la forma infija de la expresión, pero sin paréntesis. Para el mismo ejemplo, la forma infija sería a + b * c / d. Finalmente, un recorrido en postorden genera la forma postfija de la expresión. Para el ejemplo, la forma postfija sería a b + c * d /. Estas diferentes formas de representación de expresiones son cruciales para diversas etapas de la compilación. La notación postfija, por ejemplo, se utiliza a menudo para una evaluación eficiente mediante el uso de una pila. El compilador puede internamente cambiar entre estas representaciones según sea necesario para diferentes tareas. Al generar código máquina, el compilador a menudo necesita evaluar las expresiones en un orden específico. La notación postfija se presta de forma natural a la evaluación basada en pilas, donde los operandos se apilan y los operadores luego desapilan el número requerido de operandos para realizar la operación.
3. Acciones Semánticas de un Analizador Sintáctico
Las acciones semánticas son operaciones que realiza el analizador sintáctico durante la fase de análisis sintáctico.1 Estas acciones van más allá de la simple verificación de la gramática y contribuyen a la construcción de la representación semántica del programa.1 Generalmente, se integran estrechamente con el proceso de análisis sintáctico en la compilación dirigida por la sintaxis.1
Las acciones semánticas vinculan de manera intrínseca la estructura sintáctica del código con su interpretación semántica, permitiendo al compilador realizar comprobaciones y construir representaciones de forma simultánea al análisis sintáctico, lo que mejora la eficiencia del proceso. En lugar de construir un árbol sintáctico completo y luego recorrerlo para el análisis semántico, el compilador puede realizar acciones (como la verificación de tipos o las actualizaciones de la tabla de símbolos) a medida que reconoce las estructuras gramaticales, lo que hace que el proceso sea más integrado.
Entre las acciones semánticas típicas que realiza un analizador sintáctico se encuentran el acceso a la tabla de símbolos para recuperar información sobre los identificadores, como su tipo y ámbito.1 También se lleva a cabo la verificación de tipos para asegurar que los operandos utilizados en las expresiones sean compatibles con los operadores que se les aplican.1 Además, el analizador sintáctico a menudo comienza el proceso de generación de código produciendo código intermedio.1 Otra responsabilidad clave es la generación de mensajes de error cuando se detectan errores semánticos.1 En muchos casos, las acciones semánticas también incluyen la construcción del Árbol de Sintaxis Abstracta (AST) 1 y la gestión de declaraciones y ámbitos.8 Estas acciones son fundamentales para asegurar la validez semántica del programa y prepararlo para la fase de generación de código. La tabla de símbolos juega un papel central en muchas de estas acciones, actuando como un depósito de información sobre las entidades del programa. Cuando el analizador encuentra una variable en una expresión, se puede activar una acción semántica para buscar el tipo de la variable en la tabla de símbolos. Esta información se utiliza luego en otra acción semántica para verificar si el tipo es compatible con el operador que se está utilizando.
4. Análisis Detallado de la Comprobación de Tipos
La comprobación de tipos es un proceso crítico en el diseño de compiladores que asegura que cada operación en un programa se alinee con las reglas de declaración de tipos del lenguaje.16 Esta verificación ayuda a prevenir errores al asegurar que las variables y funciones se usen consistentemente según sus tipos definidos.16 La comprobación de tipos puede realizarse de forma estática o dinámica.16
La comprobación de tipos estática se realiza en tiempo de compilación, antes de que el programa se ejecute.16 Los lenguajes que implementan la comprobación de tipos estática verifican estrictamente los tipos de las variables y las expresiones antes de la ejecución del programa.17 Esto significa que si una variable se declara de un tipo (por ejemplo, entero), el compilador no permitirá que se use con datos de otro tipo (por ejemplo, cadena) sin una conversión explícita. Esta implementación estricta ayuda a detectar errores de tipo al principio del proceso de desarrollo, previniendo posibles errores en tiempo de ejecución y asegurando que las operaciones se realicen en tipos de datos compatibles. Ejemplos de lenguajes fuertemente tipados con comprobación de tipos estática incluyen Ada, Java, C, Haskell y Pascal.17 Estos lenguajes a menudo se denominan seguros en cuanto a tipos porque pueden detectar errores durante la compilación y la ejecución, evitando así la generación de resultados incorrectos.
En contraste, la comprobación de tipos dinámica se realiza en tiempo de ejecución, mientras el programa se está ejecutando.16 Los lenguajes que utilizan la comprobación de tipos dinámica ofrecen más flexibilidad en el uso de los tipos de datos.17 No realizan la verificación de tipos durante la compilación; en cambio, las comprobaciones de tipos ocurren mientras el programa está en funcionamiento. Esto permite un comportamiento más dinámico, donde el tipo de una variable podría no conocerse hasta el tiempo de ejecución. Sin embargo, esta flexibilidad tiene el costo de encontrar potencialmente errores de tipo durante la ejecución del programa. Ejemplos de lenguajes con comprobación de tipos dinámica incluyen Javascript, Scheme, Groovy, Perl y PHP.17
La elección entre la comprobación de tipos estática y dinámica representa una compensación entre la detección temprana de errores y la flexibilidad en tiempo de ejecución. El tipado estático generalmente conduce a un código más robusto, mientras que el tipado dinámico puede ofrecer ciclos de desarrollo más rápidos en algunos casos. En un lenguaje de tipado estático como Java, si se intenta asignar una cadena a una variable entera, el compilador señalará inmediatamente un error. En un lenguaje de tipado dinámico como Python, este error solo se detectaría cuando se ejecuta esa línea de código.
Las reglas de tipado se basan en la información sobre las construcciones sintácticas del lenguaje, el concepto de tipos y las reglas para asignar tipos a las construcciones del lenguaje.18 Estas reglas aseguran que el tipo de una construcción coincida con lo que se espera en su contexto.18 Algunos ejemplos de reglas de tipado incluyen la compatibilidad de operadores, los tipos de argumentos de funciones y las operaciones de estructuras de datos.18 Estas son las especificaciones formales que el verificador de tipos utiliza para determinar la validez del uso de tipos en el programa. Estas reglas son específicas de cada lenguaje de programación y definen qué operaciones están permitidas en diferentes tipos de datos. Una regla de tipado común podría establecer que los operandos del operador de suma + deben ser ambos enteros o ambos números de punto flotante. Si un operando es un entero y el otro es un booleano, esta regla se violaría, lo que llevaría a un error de tipo.
Una expresión de tipo denota el tipo de una construcción del lenguaje.18 Los tipos básicos comunes incluyen Integer, Real, Char, Boolean, Void y Error.17 Los constructores de tipos permiten formar tipos complejos a partir de otros más simples, como Array, Products, Records, Pointers y Functions.17 Las expresiones de tipo proporcionan una forma para que el compilador represente y razone sobre los diferentes tipos utilizados en un programa, incluyendo tanto los tipos primitivos como los tipos más complejos definidos por el usuario. Esto permite que el compilador realice un análisis de tipos sofisticado. Cuando el compilador encuentra una declaración de array como int arr1, representa el tipo de arr utilizando una expresión de tipo como array(10, integer), que indica un array de 10 enteros.
El manejo de errores de tipo implica la detección y el reporte de violaciones de las reglas de tipado.18 Los ejemplos de errores de tipo incluyen aplicar un operador aritmético a un booleano, usar un número real como índice de un array o llamar a una función con un número o tipo incorrecto de argumentos.18 El manejo de errores de tipo también puede involucrar coerciones, que son conversiones implícitas de tipos.17 Además, los compiladores deben manejar la sobrecarga y el polimorfismo.17 Un manejo eficaz de los errores de tipo es crucial para proporcionar retroalimentación informativa al programador, ayudándole a identificar y corregir los problemas relacionados con los tipos en su código. Las coerciones a veces pueden resolver automáticamente los desajustes de tipos, pero el compilador debe manejar estos casos con cuidado. Si un programa intenta sumar un entero y un número de punto flotante, el compilador podría convertir implícitamente el entero a un flotante antes de realizar la suma. Sin embargo, si intenta sumar un entero y una cadena, esto probablemente resultaría en un error de tipo porque no hay una conversión implícita significativa.
5. El Papel de la Pila Semántica
Una pila semántica es una estructura de datos que almacena información semántica asociada con operandos y operadores durante el análisis sintáctico.19 Se utiliza para la verificación de tipos, la evaluación de expresiones y otras tareas de análisis semántico.21 Esta pila contiene registros semánticos con atributos como tipos de datos y valores 21, y su funcionamiento se guía por las reglas semánticas del lenguaje.21
La pila semántica actúa como un mecanismo de almacenamiento temporal que permite al compilador mantener el contexto semántico a medida que analiza el código, lo que le permite realizar comprobaciones y evaluaciones basadas en las reglas semánticas del lenguaje. Al analizar una expresión, a medida que el analizador encuentra operandos y operadores, empuja información sobre sus tipos y valores a la pila semántica. Cuando se encuentra un operador, el compilador puede desapilar los operandos necesarios de la pila para realizar la verificación de tipos o evaluar una parte de la expresión.
Consideremos algunos ejemplos de la operación de la pila semántica. Para evaluar una expresión como ((1+2)*4)+3 21, el analizador sintáctico podría construir primero un árbol sintáctico. Luego, el analizador semántico utilizaría la pila semántica para evaluar la expresión. El documento menciona dos posibles órdenes de recorrido (IDR y RID) para crear la pila desde el árbol sintáctico.21 El orden IDR (In-order, Depth-first, Right-to-left) procesa primero el operador, seguido del operando derecho y luego el operando izquierdo. El orden RID (Right-to-left, In-order, Depth-first) procesa primero el operando derecho, seguido del operando izquierdo y luego el operador. Los criterios para evaluar la expresión utilizando la pila semántica difieren según cómo se creó la pila.21 Para la pila creada con IDR, se espera tener un operador y dos operandos en la parte superior de la pila para la evaluación. Si esta condición no se cumple, la pila se recorre hasta que se cumpla, la pila se actualiza y la misma regla se aplica recursivamente hasta que la pila esté vacía. Para la pila creada con RID, se espera tener dos operandos y un operador en la parte superior de la pila para la evaluación. De manera similar a IDR, si la condición no se cumple, la pila se recorre, se actualiza y la regla se aplica recursivamente hasta que la pila esté vacía.
El comportamiento de la pila semántica está estrechamente ligado a la estrategia de análisis sintáctico y al orden en que el analizador procesa la entrada. Diferentes órdenes de recorrido pueden conducir a diferentes configuraciones de pila y enfoques de evaluación. Para la expresión 1 + 2 * 3, utilizando un recorrido en postorden y una pila semántica, los números 1, 2 y 3 se apilarían primero. Luego, cuando se encuentra el operador *, se desapilarían 2 y 3, se multiplicarían y el resultado (6) se volvería a apilar. Finalmente, cuando se encuentra +, se desapilarían 1 y 6 y se sumarían, dando como resultado 7.
6. Esquemas de Traducción
Los esquemas de traducción son un método utilizado en la compilación para especificar cómo se evalúan los atributos de una gramática durante el proceso de análisis sintáctico.23 Esencialmente, aumentan las reglas de sintaxis de una gramática con acciones, que son fragmentos de código que se ejecutan en puntos específicos durante el análisis sintáctico para calcular los valores de los atributos o realizar otras operaciones relacionadas con la traducción.23
Un esquema de traducción combina reglas de sintaxis con acciones semánticas.23 Estas acciones están incrustadas dentro de las reglas de sintaxis, y la posición de la acción dentro de la regla determina cuándo se ejecuta durante el análisis sintáctico. Un esquema de traducción proporciona una implementación más concreta de las definiciones dirigidas por la sintaxis (SDDs).23 Mientras que una SDD especifica qué valores de atributos deben calcularse y las relaciones entre ellos utilizando reglas semánticas asociadas con las producciones de la gramática, un esquema de traducción especifica cuándo y en qué orden deben tener lugar estos cálculos incrustando acciones dentro de las reglas gramaticales.23
El material de investigación no enumera explícitamente diferentes tipos de esquemas de traducción.24 Se centra en cómo se utilizan para la traducción dirigida por la sintaxis, particularmente para realizar acciones semánticas durante el análisis sintáctico.24 El proceso implica construir un árbol de análisis sintáctico (ignorando inicialmente las acciones), agregar nodos de acción y luego realizar un recorrido en preorden para ejecutar las acciones.24 Los ejemplos a menudo involucran la evaluación de expresiones aritméticas y la generación de notación postfija.24
Aunque los tipos específicos pueden no estar formalmente definidos en los fragmentos proporcionados, la colocación de acciones semánticas (al final de una producción para atributos sintetizados en el análisis ascendente, o antes/después de los no terminales para atributos heredados/sintetizados en el análisis descendente) crea efectivamente diferentes patrones de traducción. En el análisis ascendente, una acción al final de una regla se ejecuta cuando el analizador reduce el lado derecho al lado izquierdo. Esto es natural para calcular atributos sintetizados, que dependen de los atributos de los hijos. En el análisis descendente, la colocación de acciones antes de un no terminal permite el cálculo de atributos heredados que se pasan a los hijos.
7. Gestión de la Tabla de Símbolos y la Tabla de Direcciones
La tabla de símbolos es una estructura de datos utilizada por el compilador para almacenar los atributos asociados con los símbolos (identificadores) utilizados en el programa.26 Estos atributos pueden incluir el tipo, valor, dirección de memoria, ámbito y número de línea del símbolo.26 Los identificadores se insertan en la tabla de símbolos a medida que son reconocidos por el analizador léxico o sintáctico.26 La gestión del ámbito es crucial para manejar los bloques anidados.26 La tabla de símbolos debe ser capaz de manejar diferentes tipos de declaraciones, como constantes, tipos, variables, funciones y clases.26 Se utiliza para realizar comprobaciones semánticas, como verificar si un identificador ha sido declarado antes de ser utilizado.26 La eficiencia de las operaciones en la tabla de símbolos, como la inserción y la búsqueda, es crítica, y a menudo se utilizan tablas hash para lograr un rendimiento eficiente.26 La tabla de símbolos actúa como un repositorio central de información sobre los identificadores del programa, esencial para diversas fases de la compilación. Su gestión eficiente, especialmente en lo que respecta al ámbito, es crucial para interpretar correctamente el programa. Cuando el compilador encuentra una variable, necesita conocer su tipo para asegurarse de que se utiliza correctamente. También necesita conocer su ámbito para determinar si el uso actual es válido. La tabla de símbolos proporciona esta información a través de mecanismos de búsqueda eficientes.
Las direcciones de memoria de las variables generalmente se almacenan dentro de la tabla de símbolos.26 Estas direcciones pueden ser relativas o absolutas, dependiendo de la etapa de compilación y de la plataforma de destino.37 Para los lenguajes con estructuras de bloques, las direcciones pueden ser relativas al inicio del bloque de datos.28 Si bien el usuario pregunta por una "tabla de direcciones", la funcionalidad de mapear los identificadores a sus ubicaciones de memoria generalmente está integrada dentro de la tabla de símbolos. La asignación de estas direcciones es un paso crucial en la preparación del programa para su ejecución. Una vez que el compilador conoce el tamaño y el tipo de cada variable, puede asignar memoria para ellas. Esta información de asignación, incluida la dirección de memoria inicial, se almacena en la tabla de símbolos, vinculando el identificador a su ubicación en tiempo de ejecución.
La tabla de símbolos almacena la dirección de memoria o el desplazamiento asignado a cada variable.31 Esta información se utiliza durante la generación de código para acceder a las variables en tiempo de ejecución.26 La tabla de símbolos actúa como el enlace central entre los identificadores utilizados en el código fuente y sus correspondientes ubicaciones de memoria en el ejecutable generado. Este mapeo es esencial para la correcta ejecución del programa. Cuando el compilador genera una instrucción para acceder a una variable, busca el nombre de la variable en la tabla de símbolos para encontrar su dirección de memoria asignada y utiliza esta dirección en el código máquina generado.8. Manejo Efectivo de Errores Semánticos
Los errores semánticos indican inconsistencias lógicas o violaciones de las reglas de significado del lenguaje, incluso si el código es sintácticamente correcto.41 Algunos tipos comunes de errores semánticos incluyen desajustes de tipos (por ejemplo, asignar un flotante a un entero sin conversión explícita) 41, variables no declaradas (usar una variable sin declaración previa) 41, tipos de operandos incompatibles para un operador 41, uso incorrecto de identificadores reservados 44 y un número o tipos incorrectos de argumentos en las llamadas a funciones.18 La detección y el reporte de estos errores son cruciales para guiar al programador a escribir código correcto. El código int x = "hello"; es sintácticamente válido en términos de su estructura (declaración seguida de asignación). Sin embargo, semánticamente, es incorrecto porque se está intentando asignar un valor de cadena a una variable entera.
Los errores semánticos a menudo se detectan mediante la verificación de la tabla de símbolos.46 El compilador debe informar la naturaleza y la posición del error 19 y debe recuperarse de los errores para continuar verificando el resto del programa.15 Los mensajes de error deben ser claros, precisos e informativos.15 A veces, se puede asumir un tipo (basado en el contexto o un tipo universal) para evitar errores en cascada.46 La calidad del reporte de errores impacta significativamente la experiencia del usuario con el compilador. Un buen compilador no solo detecta errores, sino que también proporciona suficiente información para que el programador los comprenda y corrija fácilmente. La recuperación de errores también es importante para encontrar múltiples errores en una sola pasada de compilación. Cuando se utiliza una variable no declarada, el compilador idealmente debería informar el número de línea y el nombre de la variable que no se declaró. También podría hacer una suposición sobre su tipo para continuar el análisis y potencialmente encontrar otros errores.Obras citadas
itpn.mx, fecha de acceso: abril 29, 2025, http://itpn.mx/recursosisc/7semestre/leguajesyautomatas2/Unidad%20I.pdf
Compiladores - Análisis Semántico - YouTube, fecha de acceso: abril 29, 2025, https://www.youtube.com/watch?v=qsf8cXzX708
¿Qué es un compilador? - Términos y Definiciones de Ciberseguridad - VPN Unlimited, fecha de acceso: abril 29, 2025, https://www.vpnunlimited.com/es/help/cybersecurity/compiler
cursocompiladoresuaeh.blogspot.com, fecha de acceso: abril 29, 2025, http://cursocompiladoresuaeh.blogspot.com/2010/11/unidad-vi-analisis-semantico.html#:~:text=El%20an%C3%A1lisis%20sem%C3%A1ntico%20utiliza%20como,preparar%20la%20generaci%C3%B3n%20de%20c%C3%B3digo.
Análisis Semántico en Procesadores de Lenguaje - Universidad de Oviedo, fecha de acceso: abril 29, 2025, https://www.reflection.uniovi.es/ortin/publications/semantico.pdf
Compilador - Wikipedia, la enciclopedia libre, fecha de acceso: abril 29, 2025, https://es.wikipedia.org/wiki/Compilador
Qué es un Compilador: Principales Funciones - IMMUNE, fecha de acceso: abril 29, 2025, https://immune.institute/blog/que-es-un-compilador/
ANÁLISIS SEMÁNTICO FUNCIONES PRINCIPALES ACCIONES SEMÁNTICAS - Biblioteca Central de la Universidad Nacional del Santa, fecha de acceso: abril 29, 2025, http://biblioteca.uns.edu.pe/saladocentes/doc_abrir_publicacion.asp?id_archivo=189&archivo=sesion_iii_3u___analisis_semantico.pdf
Presentación de PowerPoint - Revista Electrónica UVM, fecha de acceso: abril 29, 2025, https://revistav.uvm.edu.ve/articulos/7u6ru7Presentaci%23U00f3n%20expo%20compiladores.pdf
Analizador semántico - Compiladores, fecha de acceso: abril 29, 2025, https://compiladores1.webnode.mx/abre-tu-mente/
Unidad I - Ánalisis semántico - Lenguajes y Autómatas II - SITE123, fecha de acceso: abril 29, 2025, https://5e344735705b1.site123.me/unidad-i-%C3%81nalisis-sem%C3%A1ntico
Arboles de Expresiones | PDF | Compilador | Lenguaje de programación - Scribd, fecha de acceso: abril 29, 2025, https://es.scribd.com/document/670382708/ARBOLES-DE-EXPRESIONES
Expression Tree in Data Structure: Properties, Construction with Examples - NxtWave, fecha de acceso: abril 29, 2025, https://www.ccbp.in/blog/articles/expression-tree-in-data-structure
Expression Tree in Data Structure: A Comprehensive Guide - Hero Vired, fecha de acceso: abril 29, 2025, https://herovired.com/learning-hub/topics/expression-tree-in-data-structure/
1.2.- Acciones semánticas de un analizador sintáctico - Lenguajes y ..., fecha de acceso: abril 29, 2025, https://5e344735705b1.site123.me/unidad-i-%C3%81nalisis-sem%C3%A1ntico/12-acciones-sem%C3%A1nticas-de-un-analizador-sint%C3%A1ctico
Comprobación de Tipos - Coinmetro, fecha de acceso: abril 29, 2025, https://coinmetro.com/es-es/glossary/type-checking
www.cartagena99.com, fecha de acceso: abril 29, 2025, https://www.cartagena99.com/recursos/alumnos/apuntes/ININF2_M4_U5_T4.pdf
4.4 Tipos de Datos y Verificación de Tipos - CIDECAME UAEH, fecha de acceso: abril 29, 2025, http://cidecame.uaeh.edu.mx/lcc/mapa/PROYECTO/libro32/44__tipos_de_datos_y_verificacin_de_tipos.html
UNIDAD VI.-Análisis semántico. - Contenido de Compiladores, fecha de acceso: abril 29, 2025, http://cursocompiladoresuaeh.blogspot.com/2010/11/unidad-vi-analisis-semantico.html
verificacion de tipos de expresiones - Cesar Soto - Prezi, fecha de acceso: abril 29, 2025, https://prezi.com/tg0cntteevfa/verificacion-de-tipos-de-expresiones/
enlinea.zacatecas.tecnm.mx, fecha de acceso: abril 29, 2025, https://enlinea.zacatecas.tecnm.mx/mod/resource/view.php?id=4365
Capítulo 5. Análisis semántico, fecha de acceso: abril 29, 2025, http://arantxa.ii.uam.es/~alfonsec/docs/compila5.htm
www.ulpgc.es, fecha de acceso: abril 29, 2025, http://www.ulpgc.es/descargadirecta.php?codigo_archivo=36903
enlinea.zacatecas.tecnm.mx, fecha de acceso: abril 29, 2025, https://enlinea.zacatecas.tecnm.mx/mod/resource/view.php?id=4366
notes/dev_notes/Compiler_2_SimpleSyntax_Directed_Translator.md at master - GitHub, fecha de acceso: abril 29, 2025, https://github.com/mebusy/notes/blob/master/dev_notes/Compiler_2_SimpleSyntax_Directed_Translator.md
www.cartagena99.com, fecha de acceso: abril 29, 2025, https://www.cartagena99.com/recursos/alumnos/apuntes/ININF2_M4_U5_T2.pdf
1.5 y 1.6 Esquema de traducción y generacuón de tabla.pptx - SlideShare, fecha de acceso: abril 29, 2025, https://es.slideshare.net/slideshow/1-5-y-1-6-esquema-de-traduccion-y-generacuon-de-tabla-pptx/271058160
Tema 5 Tabla de Símbolos, fecha de acceso: abril 29, 2025, http://www.lcc.uma.es/~galvez/ftp/tci/tictema5.pdf
1.6.-Generacion de Tabla de Simbolos y de Direcciones | PDF | Compilador - Scribd, fecha de acceso: abril 29, 2025, https://es.scribd.com/document/310535260/1-6-Generacion-de-Tabla-de-Simbolos-y-de-Direcciones
Lección 1: Tablas de Símbolos - Universidad de Zaragoza, fecha de acceso: abril 29, 2025, http://webdiis.unizar.es/~neira/12048/12048%20tablas%20de%20simbolos.pdf
Symbol Table in Compiler | GeeksforGeeks, fecha de acceso: abril 29, 2025, https://www.geeksforgeeks.org/symbol-table-compiler/
Symbol table - Wikipedia, fecha de acceso: abril 29, 2025, https://en.wikipedia.org/wiki/Symbol_table
Compiler Design - Symbol Table - Tutorialspoint, fecha de acceso: abril 29, 2025, https://www.tutorialspoint.com/compiler_design/compiler_design_symbol_table.htm
Lecture 3 - The Symbol Table - Compiler Construction, fecha de acceso: abril 29, 2025, https://home.adelphi.edu/~siegfried/cs372/372l3.pdf
c++ - What is a symbol table? - Stack Overflow, fecha de acceso: abril 29, 2025, https://stackoverflow.com/questions/69112/what-is-a-symbol-table
SYMBOL TABLE DESIGN AND RUNTIME STORAGE MANAGEMENT | Collegenote, fecha de acceso: abril 29, 2025, https://collegenote.net/notes/attachment/symbol-table-design-and-run-time-storage-management-165
¿Cómo funcionan las tablas de símbolos en tiempo de ejecución? : r/Compilers - Reddit, fecha de acceso: abril 29, 2025, https://www.reddit.com/r/Compilers/comments/heh9qm/how_do_symbol_tables_work_at_runtime/?tl=es-419
How do symbol tables work at runtime? : r/Compilers - Reddit, fecha de acceso: abril 29, 2025, https://www.reddit.com/r/Compilers/comments/heh9qm/how_do_symbol_tables_work_at_runtime/
compiler construction - storage of address of variable in memory - Stack Overflow, fecha de acceso: abril 29, 2025, https://stackoverflow.com/questions/27843228/storage-of-address-of-variable-in-memory
Symbol Table Section - Linker and Libraries Guide, fecha de acceso: abril 29, 2025, https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-79797.html
Errores Semanticos | PDF | Compilador | Lenguaje de programación, fecha de acceso: abril 29, 2025, https://es.scribd.com/document/350852662/errores-semanticos
4.5 Errores Semánticos - CIDECAME UAEH, fecha de acceso: abril 29, 2025, http://cidecame.uaeh.edu.mx/lcc/mapa/PROYECTO/libro32/45__errores_semnticos.html
Manejo de Errores Semánticos by GABRIEL STOYKO MARTINEZ GARCIA on Prezi, fecha de acceso: abril 29, 2025, https://prezi.com/p/gdofl4qdwonk/manejo-de-errores-semanticos/
Semantic Analysis in Compiler Design | GeeksforGeeks, fecha de acceso: abril 29, 2025, https://www.geeksforgeeks.org/semantic-analysis-in-compiler-design/
Type Checking in Compiler Design | GeeksforGeeks, fecha de acceso: abril 29, 2025, https://www.geeksforgeeks.org/type-checking-in-compiler-design/
Capitulo 6. - Angelfire, fecha de acceso: abril 29, 2025, https://www.angelfire.com/mac/michelo0/Tema6.html
3.1.1 Manejo de los Errores Sintácticos - CIDECAME UAEH, fecha de acceso: abril 29, 2025, http://cidecame.uaeh.edu.mx/lcc/mapa/PROYECTO/libro32/311_manejo_de_los_errores_sintcticos.html
Intermediate Code Generation in Compiler Design | GeeksforGeeks, fecha de acceso: abril 29, 2025, https://www.geeksforgeeks.org/intermediate-code-generation-in-compiler-design/
Intermediate Code Generation in Compiler Design - Tutorialspoint, fecha de acceso: abril 29, 2025, https://www.tutorialspoint.com/compiler_design/compiler_design_intermediate_code_generations.htm
Chapter 6 - Intermediate-Code Generation, fecha de acceso: abril 29, 2025, https://bjpcjp.github.io/pdfs/compiler-theory/CPTT-ch06-intermediate-codegen.pdf
UNIT-III Compiler Design – SCS1303 - Sathyabama, fecha de acceso: abril 29, 2025, https://www.sathyabama.ac.in/sites/default/files/course-material/2020-11/Unit-3.pdf
Chapter 6 Semantic Analysis & Intermediate Code Generation, fecha de acceso: abril 29, 2025, https://courses.minia.edu.eg/Attach/Comp404Lec6.pdf
Topic 7 - Intermediate Code Generation, fecha de acceso: abril 29, 2025, https://www.cs.kent.edu/~batcher/CS453111/topic7.html
UNIT – III INTERMEDIATE CODE GENERATION - Sathyabama, fecha de acceso: abril 29, 2025, https://www.sathyabama.ac.in/sites/default/files/course-material/2020-11/unit3.pdf
unit iv – intermediate code generation & syntax directed, fecha de acceso: abril 29, 2025, https://gacbe.ac.in/pdf/ematerial/18MCS25E-U4.pdf
Intermediate Code Generation - CSE IIT KGP, fecha de acceso: abril 29, 2025, https://cse.iitkgp.ac.in/~bivasm/compiler_notes/TAC_v3.pdf
COMS W4115 Programming Languages and Translators Lecture 16: Translating Statements into Three-Address Code March 25, 2015 - CS@Columbia, fecha de acceso: abril 29, 2025, http://www.cs.columbia.edu/~aho/cs4115/Lectures/15-03-25.html
Three Address Code in Compiler Design example - YouTube, fecha de acceso: abril 29, 2025, https://m.youtube.com/watch?v=8MHbgpE29Os
Comentarios
Publicar un comentario