# data[].attributes.body
Es una extensión de la gramática formal que define un lenguaje, pero incluye acciones semánticas o información extra que ayudan a generar código.

Se utiliza principalmente en compiladores, donde no solo interesa si el programa es sintácticamente correcto, sino qué debe hacer cada instrucción.

# data[].attributes.body
Inventada por Jan Łukasiewicz en 1920 para simplificar la lógica proposicional y las expresiones matemáticas.

El operador se coloca antes de los operandos, por ejemplo: + 3 4 en vez de 3 + 4.

Elimina la necesidad de paréntesis en expresiones de aridad fija, lo que facilita el análisis automático.

Se utiliza en lenguajes como LISP y en sistemas de lógica formal.

Ejemplo: La expresión infija ((15 / (7 - (1 + 1))) 3) - (2 + (1 + 1)) se convierte en polaca como - / 15 - 7 + 1 1 3 + 2 + 1 1.

En lógica, cada operador tiene una letra específica: Negación (N), Conjunción (K), Disyunción (A), etc..

# data[].attributes.body
Son combinaciones de constantes, variables y operadores aritméticos que producen un valor numérico.

Operadores comunes: +, -, *, /, % (mod).

Se pueden anidar, usando paréntesis para indicar prioridad.

Ejemplo complejo:

resultado = (a + b) * (c - d) / e

En un compilador, cada expresión aritmética puede traducirse a código de tres direcciones o instrucciones intermedias, para facilitar la evaluación paso a paso.

# data[].attributes.body
Sirve para almacenar el valor de una expresión en una variable.

Sintaxis general:

variable = expresión

La asignación puede involucrar tipos de datos complejos, no solo números: arreglos, registros, objetos.

Ejemplo:

total = precio * cantidad + impuesto

# data[].attributes.body
Los operandos van antes del operador, por ejemplo: 3 4 + en vez de 3 + 4.

Elimina los paréntesis y la prioridad de operadores se determina por el orden de aparición.

Muy utilizada en calculadoras científicas (como las HP) y en lenguajes de programación basados en pila.

Ejemplo: La expresión infija (4 + 8) / (1 + 3) se convierte en RPN como 4 8 + 1 3 + /.

Facilita la evaluación de expresiones mediante algoritmos de pila, lo que simplifica el diseño de compiladores y parsers.

# data[].attributes.body
Evalúa a verdadero (true) o falso (false).

Se construye con operadores relacionales (<, >, ==, !=, >=, <=) y lógicos (&&, ||, !).

Ejemplo:

(edad > 18 && ingreso > 10000) || esAdmin

En compilación, las expresiones booleanas a menudo controlan saltos condicionales: si la expresión es verdadera, se salta a un bloque de código; si no, se sigue otro camino.

# data[].attributes.body
Es un lenguaje intermedio usado en compiladores, especialmente en Pascal.

Permite que los programas sean portables y ejecutados en diferentes plataformas mediante una máquina virtual.

El P-Code no se ejecuta directamente en el hardware, sino que es interpretado, lo que facilita la depuración y portabilidad.

Fue clave para la expansión de Pascal en la educación y la industria.

Ejemplo: asignación a = b + c puede representarse como:

LOD b
LOD c
ADD
STO a

# data[].attributes.body
Estructura de tres campos: operador, argumento 1, argumento 2.

El resultado se asocia a la posición del triplo en la lista, no a una variable temporal explícita.

Ahorra espacio, pero dificulta la optimización porque las referencias dependen de la posición.

Ejemplo: a = b + c → (+, b, c)

Cuando hay expresiones más largas, los resultados intermedios se usan como variables temporales:

t1 = b + c → (+, b, c)
a = t1 * d → (*, t1, d)

# data[].attributes.body
Consiste en convertir una asignación de alto nivel a instrucciones más simples que la máquina o el compilador pueden entender.

Se usa el código de tres direcciones: cada operación intermedia se almacena en una variable temporal.

Esta forma facilita optimización y análisis de dependencias entre variables.

Ejemplo:

total = a + b * c

Traducción a código de tres direcciones:

t1 = b * c
t2 = a + t1
total = t2

# data[].attributes.body
Modifican el flujo de ejecución del programa.

Tipos principales:

Condicionales: if, if-else, switch

Bucles: while, for, do-while

Saltos: goto, break, continue

Permiten que un programa no ejecute instrucciones de forma lineal, sino según condiciones o repeticiones.

# data[].attributes.body
Son marcadores dentro del código que permiten referirse a un punto específico para saltos.

Son útiles en código intermedio o ensamblador.

Ejemplo:

L1:
  x = x + 1
  goto L2
L2:
  print(x)

En compiladores, las etiquetas se usan para generar saltos condicionales e incondicionales.

# data[].attributes.body
Definición: Es un código temporal generado por el compilador que no depende del hardware específico, pero tampoco es el código fuente original.

Propósito: Facilita la optimización, análisis y traducción a distintos lenguajes o máquinas.

Tipos comunes:

Three-Address Code (TAC): Cada instrucción tiene máximo tres direcciones (operando1, operando2, resultado).

Ejemplo: t1 = B * C; t2 = A + t1

Pseudocódigo: Expresiones simplificadas fáciles de analizar.

Ventaja: Separar la traducción del lenguaje fuente de la generación de código máquina.

# data[].attributes.body
Fases detalladas:

1. Análisis léxico: Convierte el código en tokens (identificadores, operadores, literales).

2. Análisis sintáctico (parsing): Verifica que los tokens siguen la gramática del lenguaje.

3. Análisis semántico: Comprueba tipos de datos, existencia de variables, coherencia lógica.

4. Generación de código intermedio: Traduce expresiones a un código fácil de manipular.

5. Optimización de código: Mejora eficiencia, reduce instrucciones redundantes.

6. Generación de código final: Convierte en ensamblador o código máquina específico del hardware.

Ejemplo práctico:
Código fuente: x = a + b * c;

Intermedio (TAC):

t1 = b * c
x = a + t1

# data[].attributes.body
Incondicional (goto): el flujo siempre salta a la etiqueta indicada.

Condicional (if ... goto): salta solo si la condición es verdadera.

Ejemplo de salto condicional:

if x > 0 goto L1

Esto significa: si x es mayor que 0, la ejecución continúa en la etiqueta L1; si no, sigue la instrucción siguiente.

# data[].attributes.body
Cómo funciona: El operador va antes de los operandos.

Ventaja: No requiere paréntesis para definir prioridad.

Ejemplo:

Infijo: (A + B) * C

Prefijo: * + A B C

Uso: Computadoras y calculadoras de pila, compiladores.

# data[].attributes.body
Cómo funciona: Operador entre los operandos (lo usamos normalmente).

Problema: Debe usar paréntesis para definir orden de ejecución.

Ejemplo: A + B * C

Multiplicación tiene mayor precedencia, entonces se hace B * C primero.

Uso: Lenguajes de programación humanos y diarios.

# data[].attributes.body
Cómo funciona: Operador después de los operandos.

Ventaja: Fácil de evaluar con pila sin necesidad de paréntesis.

Ejemplo:

Infijo: (A + B) * C

Postfijo: A B + C *

Evaluación:

Leer de izquierda a derecha:

1. Apila operandos hasta encontrar operador

2. Aplica operador sobre los últimos operandos

3. Coloca resultado de nuevo en la pila

# data[].attributes.body
Es cuando un programa ejecuta un bloque de código predefinido (función o procedimiento).

Permite modularizar y reutilizar código.

Ejemplo:

resultado = calcularPromedio(a, b, c)

En compilación se manejan mediante:

Stack para pasar parámetros y guardar retorno.

Instrucciones CALL y RETURN en código intermedio o ensamblador.

# data[].attributes.body
Son formas de organizar información más avanzadas que variables simples.

Ejemplos:

Arreglos/matrices: secuencias de elementos del mismo tipo (int nums[10])

Registros/structs: colecciones de campos (struct Persona {nombre, edad})

Listas enlazadas, pilas, colas: estructuras dinámicas para manejar datos de forma flexible

Árboles y grafos: estructuras jerárquicas o de relación para representar datos complejos

En traducción de programas, estas estructuras requieren manejo especial en memoria y a veces código intermedio adicional.

# data[].attributes.body
Variante donde los operandos son referencias a otras posiciones de memoria o variables temporales.

Ejemplo: si t1 almacena b + c, entonces el siguiente triplo puede usar t1 en lugar de recalcular.

Permite reutilizar resultados intermedios y evita duplicación de cálculos.

# data[].attributes.body
Similar a triplos, pero con un campo extra para el resultado: (operador, op1, op2, resultado).

Ejemplo: a = b + c → (+, b, c, t1) donde t1 almacena el resultado antes de asignarlo a a.

Facilita la lectura y depuración del código intermedio y es más eficiente para optimización.

Ejemplo: Para a = b + c:

+, b, c, t1

=, t1, -, a

# data[].attributes.body
Permiten mover y optimizar instrucciones fácilmente gracias a las variables temporales explícitas.

Son la estructura más utilizada en compiladores modernos para optimización.

Facilitan la depuración y el análisis del código generado.

Permite optimización y genera código más directo para la máquina.

# data[].attributes.body
Guardan resultados intermedios durante la evaluación de expresiones.

Ejemplo: para (b + c) d, t1 = b + c y luego t2 = t1 d.

Reducen recalculos y facilitan la traducción de expresiones largas a código máquina.

Espacios de memoria generados automáticamente por el compilador para almacenar resultados intermedios.

Permiten realizar cálculos complejos paso a paso sin perder información.

Son esenciales en estructuras como los cuádruplos y triplos indirectos.

# 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
Permite asociar acciones a reglas de la gramática.

Mientras se analiza la expresión, se generan triplos, cuádruplos y variables temporales automáticamente.

Ejemplo: si la regla es E → E1 + T, el SDT puede generar un triplo t = E1 + T.

Hace que la traducción de código sea estructurada y modular.

Permite generar código intermedio y verificar propiedades semánticas del programa al mismo tiempo.

Es clave en la construcción de compiladores modernos.

# data[].attributes.body
Calculados desde los hijos hacia la raíz en un árbol de sintaxis.

Permiten que los resultados intermedios suban en el árbol y se combinen.

Ejemplo: en (b + c) d, el nodo + calcula t1 = b + c, que luego usa el nodo para t2 = t1 * d.

Esencial para evaluar expresiones y generar código intermedio de manera ordenada y eficiente.

# data[].attributes.body
Determina qué operación se realiza primero.

Ejemplo en C/C++:

1. () → paréntesis

2. * / % → multiplicación, división, módulo

3. + - → suma y resta

4. = → asignación

Importancia: Evita resultados incorrectos si no usamos paréntesis.

A + B C ≠ (A + B) C

# data[].attributes.body
Representación jerárquica de una expresión o programa.

Nodos internos: operadores

Hojas: operandos o literales

Facilita análisis, optimización y generación de código.

# data[].attributes.body
Preorden: visitar nodo → hijo izquierdo → hijo derecho

Inorden: hijo izquierdo → nodo → hijo derecho

Postorden: hijo izquierdo → hijo derecho → nodo

Ejemplo con AST de A + B * C:

        +
       / \
      A   *
         / \
        B   C

Preorden: + A * B C

Inorden: A + B * C

Postorden: A B C * +

# data[].attributes.body
Infijo → Postfijo: Usar pila para operadores y respetar precedencia.

Infijo → Prefijo: Similar, pero se procesa de derecha a izquierda.

Postfijo → Infijo: Se puede reconstruir con una pila de expresiones.

Ejemplo práctico:

Infijo: A + B * C

Postfijo: A B C * +

Prefijo: + A * B C

# data[].attributes.body
Determina el orden de operaciones cuando hay operadores con la misma precedencia.

Puede ser izquierda → derecha o derecha → izquierda.

Ejemplo:

a - b - c → izquierda → derecha → (a - b) - c

a ^ b ^ c → derecha → izquierda → a ^ (b ^ c)