# data[].attributes.body
La compilación es un proceso dividido en varias fases. Entre las más importantes están el análisis léxico, que convierte caracteres en tokens; el análisis sintáctico, que construye el árbol sintáctico; el análisis semántico, que verifica reglas del lenguaje y tipos; la generación del código intermedio, y finalmente la optimización y generación del código máquina. Cada fase transforma la representación del programa y prepara la información para la siguiente etapa.

# data[].attributes.body
El código intermedio es una representación abstracta de un programa, que se encuentra entre el código fuente y el código máquina. Su función principal es actuar como un puente para facilitar la optimización, análisis y posterior generación código específico para distintas máquinas. Se genera durante la compilación en una forma que es independiente del hardware para mejorar la portabilidad. Un ejemplo común es el código de tres direcciones, donde cada instrucción contiene un operador y dos operandos, y produce un resultado temporal. Esta abstracción también puede ser conocida como bytecode y es empleado en muchas máquinas virtuales que interpretan o traducen dinámicamente el código intermedio a código máquina para su ejecución final.

# data[].attributes.body
La notación prefija (o notación polaca) coloca el operador antes de sus operandos, por ejemplo, "+ A B".

# data[].attributes.body
La notación infija es la forma común con el operador entre operandos, por ejemplo, "A + B".

# data[].attributes.body
La precedencia de operadores es un conjunto de reglas que define el orden en el que se deben evaluar los diferentes operadores (como +, -, , /, ^) en una expresión que no tiene paréntesis. Estas reglas son esenciales para que una expresión ambigua como 3 + 5 2 tenga un único significado. En este caso, la multiplicación tiene una precedencia mayor que la suma, por lo que se evalúa primero (5 2), y luego el resultado se suma a 3, dando 13. Sin estas reglas, no habría una forma clara de determinar si la expresión significa (3 + 5) 2 = 16 o 3 + (5 * 2) = 13, lo que llevaría a resultados inconsistentes en los lenguajes de programación y en las calculadoras.

# data[].attributes.body
La notación postfija (o notación polaca inversa) coloca el operador después de sus operandos, por ejemplo, "A B +".

# data[].attributes.body
es la regla que determina el orden de evaluación cuando en una expresión aparecen varios operadores con la misma precedencia. Mientras que la precedencia resuelve conflictos entre operadores diferentes (como + y *), la asociatividad resuelve conflictos entre operadores iguales. La asociatividad puede ser de izquierda a derecha o de derecha a izquierda. Por ejemplo, la resta y la división suelen ser asociativas por la izquierda, lo que significa que la expresión 8 - 3 - 1 se evalúa como (8 - 3) - 1 = 4. Si fuera asociativa por la derecha, se evaluaría como 8 - (3 - 1) = 6, lo cual no es intuitivo. En cambio, la potenciación (^) suele ser asociativa por la derecha, por lo que 2 ^ 3 ^ 2 se interpreta como 2 ^ (3 ^ 2) = 512 y no como (2 ^ 3) ^ 2 = 64.

# data[].attributes.body
Consiste en transformar expresiones entre notaciones infija, prefija y postfija, para que sean más sencillas de evaluar o representar internamente. Normalmente, se usa un algoritmo basado en pilas para manejar precedencia y asociatividad de operadores al convertir notaciones.

# data[].attributes.body
AST, por sus siglas en inglés es una representación en forma de árbol de la estructura sintáctica de un código fuente o una expresión. Cada nodo del árbol denota una construcción (como un operador, un identificador o un valor literal) que ocurre en el texto, pero omite detalles no esenciales como los paréntesis y los delimitadores. Por ejemplo, para la expresión (3 + 5) 2, el AST tendría un nodo raíz ; su hijo izquierdo sería un nodo + con los hijos 3 y 5, y su hijo derecho sería el nodo 2. El AST es fundamental en los compiladores e intérpretes, ya que captura la esencia lógica del código y sirve como base para el análisis semántico y la generación de código.

# data[].attributes.body
son algoritmos para visitar todos los nodos de un árbol de manera sistemática, y son cruciales para analizar o transformar un AST. Existen tres órdenes principales: Preorden (raíz, hijo izquierdo, hijo derecho), que procesa primero la operación y luego los operandos, útil para copiar árboles o generar notación polaca. Inorden (hijo izquierdo, raíz, hijo derecho), que, al aplicarse a un AST, reproduce (casi siempre) la expresión original con notación infija, aunque puede requerir paréntesis. Finalmente, Postorden (hijo izquierdo, hijo derecho, raíz), que procesa primero los operandos y luego la operación, siendo la base para la evaluación de expresiones y la generación de código de máquina o notación polaca inversa.

# data[].attributes.body
El Código P (P-Code) es una representación intermedia de bajo nivel que utiliza una máquina virtual basada en pila para ejecutar instrucciones. Fue popularizado por el compilador de Pascal de Niklaus Wirth.

Características principales:

Máquina basada en pila

Independiente del hardware

Conjunto de instrucciones simple

Ventajas:

Facilita la portabilidad del código

Simplifica el diseño del compilador

Permite optimizaciones a nivel intermedio

Ejemplo:

LIT 2 ; cargar literal 2 en la pila

LIT 3 ; cargar literal 3

OPR + ; sumar los dos valores en la pila

# data[].attributes.body
también conocida como notación de prefijo, es una forma de escribir expresiones matemáticas donde el operador se coloca antes que sus operandos. Esta notación fue ideada por el lógico polaco Jan Łukasiewicz y tiene la gran ventaja de que no requiere paréntesis para definir el orden de las operaciones, ya que el orden es inherente a la posición de los operadores. Por ejemplo, la expresión infija (3 + 5) 2 se escribe en notación polaca como + 3 5 2. Para evaluarla, se busca el primer operador (*) y se aplica a los dos siguientes elementos, que a su vez pueden ser operandos simples o subexpresiones (+ 3 5). Esta notación es la base del recorrido en preorden de un AST.

# data[].attributes.body
o notación de posfijo, es el reverso de la notación polaca: el operador se coloca después de sus operandos. Popularizada por las calculadoras Hewlett-Packard, su principal ventaja es que es extremadamente fácil de evaluar usando una pila (stack). Por ejemplo, la expresión infija (3 + 5) 2 se escribe en RPN como 3 5 + 2 . La evaluación se realiza leyendo de izquierda a derecha: al encontrar un operando se apila, y al encontrar un operador se desapilan los dos operandos superiores, se realiza la operación y el resultado se vuelve a apilar. Esta notación corresponde directamente al recorrido en postorden de un Árbol de Sintaxis Abstracta (AST).

# data[].attributes.body
Los triplos son una representación intermedia que consiste en registros de tres campos: operador, operando1 y operando2. Cada triplo representa una operación básica.

Estructura -> (operador, operando1, resultado)

Características:

Omite variables temporales explícitas: El resultado de un Triplo se refiere implícitamente por su posición (su número de instrucción).

Ejemplo: Para a:=b∗c, el Triplo podría ser ( *, b, c). Si este es el triplo (1), el resultado de la multiplicación se referencia como (1).

Ventaja: Más compacto y consistente que los cuádruplos al no requerir nombrar temporales.

Desventaja: Dificulta la optimización y reordenación de código, ya que mover una instrucción cambia su referencia numérica.

# data[].attributes.body
Los triplos indirectos mejoran los triplos tradicionales añadiendo una tabla de punteros que permite referenciar las instrucciones indirectamente, facilitando la reorganización del código.

Estructura:

Tabla de triplos: Contiene las operaciones (operador, op1, op2)

Tabla de punteros: Referencias a las posiciones de los triplos

Funcionamiento: El orden de ejecución se da por la lista de apuntadores, no por la posición física de los Triplos.

Ventaja: Permite la reordenación libre de las subexpresiones (optimización) sin tener que reescribir los Triplos que hacen referencia a los resultados intermedios. Solo se reordenan los apuntadores en la lista.

# data[].attributes.body
Consiste en convertir expresiones del tipo a = b + c a un código intermedio más simple, que generalmente utiliza instrucciones de tres direcciones (TAC). Este formato descompone la operación en pasos elementales que son más fáciles de analizar, optimizar y finalmente traducir a código máquina.

# data[].attributes.body
Los cuádruplos son una representación intermedia de cuatro campos: operador, operando1, operando2 y resultado. Proporcionan una representación clara y explícita de las operaciones.

Características:

Claridad: Cada operación es completamente explícita

Variables temporales: Utiliza variables temporales para resultados intermedios

Fácil traducción: Directa conversión a código de máquina

Ejemplo: Para a:=b∗c, el Cuádruplo podría ser (*, b, c, t1).

# data[].attributes.body
1. Simplicidad conceptual

Representación directa de operaciones de tres direcciones

Fácil comprensión y manipulación por parte del programador

2. Facilidad de optimización

Eliminación de código muerto: Fácil identificación de variables no utilizadas

Propagación de constantes: Simplifica el reemplazo de valores constantes

Análisis de flujo de datos: Permite seguimiento eficiente de dependencias

3. Traducción directa

Mapeo uno a uno: Cada cuádruplo se traduce fácilmente a instrucciones de máquina

Generación de código: Proceso sistemático y predecible

Asignación de registros: Facilita la gestión de registros del procesador

4. Independencia del lenguaje fuente

Representación universal para diferentes lenguajes de programación

Facilita el desarrollo de compiladores multi-lenguaje

5. Debugging y análisis

Formato legible para depuración del compilador

Facilita el análisis estático del código

# data[].attributes.body
Las variables temporales son identificadores generados automáticamente por el compilador para almacenar resultados intermedios de expresiones complejas durante la traducción a código intermedio.

Propósito:

Simplificación: Descomponen expresiones complejas en operaciones básicas

Optimización: Permiten reutilización de cálculos intermedios

Traducción: Facilitan la generación de código de máquina

Características:

Generación automática: El compilador las crea usando convenciones como t1, t2, t3...

Alcance limitado: Generalmente tienen vida corta dentro de bloques básicos

Tipo específico: Mantienen el tipo de dato del resultado que almacenan

Ejemplo: En la expresión a=b∗c+d, se descompondría usando temporales:

1. t1 = b * c

2. t2 = t1 + d

3. a = t2

# data[].attributes.body
Son instrucciones que determinan cómo fluye la ejecución del programa. Se usan para implementar estructuras como condicionales (if…else), ciclos (for, while) o cambios de flujo mediante saltos (goto). En el código intermedio, estas instrucciones se expresan como combinaciones de saltos condicionales, incondicionales y etiquetas. Gracias a esto, el compilador puede representar cualquier estructura de control de alto nivel de manera uniforme y precisa.

# data[].attributes.body
Las etiquetas son identificadores simbólicos que marcan posiciones específicas en el código intermedio. Sirven como puntos de referencia para los saltos condicionales e incondicionales, de modo que el compilador sepa hacia dónde transferir el control del programa. Su uso es fundamental en la representación de bucles y condicionales.

# data[].attributes.body
Los saltos permiten alterar el orden secuencial normal de un programa:

Saltos incondicionales (goto): llevan siempre el control hacia una etiqueta determinada, sin importar condiciones.

Saltos condicionales: dependen de una evaluación lógica, por ejemplo: if x < y goto L1.

Estos elementos son esenciales para implementar estructuras de decisión y ciclos, ya que conectan las etiquetas que representan los diferentes caminos posibles dentro del programa.

# data[].attributes.body
Una llamada a función en código intermedio representa la ejecución de una subrutina, lo cual incluye varios pasos:

1. Evaluar y preparar los argumentos que se van a pasar.

2. Crear el marco de activación (stack frame) con información de la llamada.

3. Saltar a la dirección donde inicia la función.

4. Regresar al punto de llamada con el valor obtenido.

# data[].attributes.body
Son aquellas que van más allá de los tipos de datos primitivos (enteros, flotantes, caracteres) y permiten manejar información estructurada, como arreglos, registros (structs), objetos o punteros. En el código intermedio, trabajar con estas estructuras se traduce en operaciones de memoria como accesos a índices, desplazamientos o referencias. Por ejemplo, el acceso A[i] puede convertirse en una suma de la dirección base más un desplazamiento calculado.
Esto facilita que el compilador pueda manipular datos complejos de una forma estándar y preparar su traducción eficiente a código máquina.

# data[].attributes.headline
Esquema de traducción dirigida por sintaxis (SDT)

# data[].attributes.subject
Esquema de traducción dirigida por sintaxis (SDT)

# data[].attributes.body
Un SDT es un mecanismo en el que a una gramática se le agregan acciones semánticas dentro de sus producciones. Estas acciones permiten traducir, generar código o realizar verificaciones al mismo tiempo que se hace el análisis sintáctico. Es muy usado en compiladores para convertir código fuente en representaciones intermedias.

# data[].attributes.body
Son aquellos atributos que se calculan a partir de los atributos de los hijos de un nodo en el árbol de derivación. Es decir, la información “sube” en el árbol. Ejemplo: en una expresión aritmética, el valor de un nodo E → E1 + T se puede calcular sumando los atributos de E1 y T.

# data[].attributes.body
Es una gramática a la que se le agrega un nuevo símbolo inicial y una nueva producción. Se usa principalmente en algoritmos de análisis sintáctico (como LR o SLR) para marcar de forma clara el inicio y final de la derivación, facilitando la construcción de autómatas.

# data[].attributes.body
Una expresión aritmética es una combinación de operandos (números o variables) y operadores (+, -, , /) que permiten realizar cálculos. En compiladores, su gramática define la precedencia y asociatividad de operadores, asegurando que se evalúe correctamente (ejemplo: a + b c).

# data[].attributes.body
Es una expresión que se compone de valores lógicos (verdadero/falso) y operadores lógicos como AND (∧), OR (∨) y NOT (¬). Se usa en estructuras de control (if, while) para tomar decisiones en los programas.

# data[].attributes.body
Es una construcción que permite guardar un valor en una variable. Generalmente se representa con el operador = (ejemplo: x = a + b;). En traducción dirigida por sintaxis, se genera código para evaluar la expresión y almacenar el resultado en la dirección asociada a la variable.