Generación de Código Intermedio
1. Introducción a la Generación de Código Intermedio
La generación de código intermedio constituye una fase esencial en el proceso de compilación, actuando como un nexo crucial entre las etapas de análisis del código fuente (front-end) y la síntesis del código objeto (back-end).1 Su principal objetivo radica en facilitar la portabilidad y la optimización del código final.1 Al introducir una representación intermedia, se permite que un mismo front-end, encargado del análisis léxico, sintáctico y semántico del lenguaje fuente, pueda ser utilizado con múltiples back-ends, cada uno adaptado a una arquitectura de máquina diferente.3 De manera similar, un back-end específico para una arquitectura puede ser reutilizado con diferentes front-ends de lenguajes fuente diversos. Este enfoque modular reduce significativamente la complejidad de construir compiladores completos para cada combinación de lenguaje y máquina.
Además de la portabilidad, el código intermedio proporciona una base uniforme sobre la cual se pueden aplicar diversas técnicas de optimización, cuyo fin es mejorar el rendimiento del programa objeto generado, independientemente de la arquitectura de destino.3 Esta representación abstracta, al estar desvinculada de las particularidades de una máquina específica, permite identificar y aplicar transformaciones que mejoran la eficiencia del código en términos de velocidad de ejecución, uso de memoria o consumo de energía. En la fase de síntesis, el generador de código, encargado de producir el código objeto final, puede operar de manera más sencilla al asumir un número ilimitado de registros o al dirigirse a una máquina virtual abstracta definida por el código intermedio.3 Finalmente, el código intermedio también puede servir como una base para la implementación de herramientas de depuración y análisis estático, facilitando la comprensión y el mantenimiento del código.7
Si bien la introducción de una etapa de generación de código intermedio añade un paso adicional en el proceso de compilación, lo que podría implicar un aumento en el tiempo total de compilación 3, los beneficios que aporta en términos de portabilidad, optimización y modularidad del compilador generalmente compensan este costo. La complejidad inherente a la traducción directa desde un lenguaje de alto nivel a las diversas arquitecturas de máquina hace que la introducción de una representación intermedia sea una estrategia valiosa. Al separar la lógica del lenguaje de los detalles específicos del hardware, se simplifica el desarrollo y el mantenimiento del compilador. Asimismo, esta representación uniforme facilita la aplicación de optimizaciones que mejoran el rendimiento del programa final, independientemente de la arquitectura en la que se ejecute.
1.2. Diferentes Niveles de Representación Intermedia
Las representaciones de código intermedio pueden clasificarse en función de su proximidad al lenguaje fuente o al lenguaje máquina.3
Alto Nivel: Las representaciones de alto nivel mantienen una estrecha relación con la estructura del lenguaje fuente. Un ejemplo común de este nivel es el Árbol de Sintaxis Abstracta (AST).3 Estas representaciones son particularmente útiles para realizar optimizaciones basadas en la semántica del lenguaje de programación.
Bajo Nivel: Las representaciones de bajo nivel, en contraste, se acercan más a las características del lenguaje máquina. El código de tres direcciones es un ejemplo típico de este nivel.3 Estas representaciones son más adecuadas para la asignación de registros y la aplicación de optimizaciones que dependen de las particularidades de la arquitectura del hardware.
La elección del nivel de representación intermedia está intrínsecamente ligada a los objetivos específicos del compilador. Un compilador que priorice la capacidad de ejecutar el mismo código en múltiples plataformas y la aplicación de optimizaciones que se centran en la lógica del programa podría optar por una representación de alto nivel. Por otro lado, un compilador diseñado para maximizar el rendimiento en una arquitectura de hardware particular podría inclinarse por una representación de bajo nivel. Es importante destacar que algunos compiladores avanzados incluso emplean una combinación de múltiples representaciones intermedias en diferentes fases del proceso de compilación, aprovechando las ventajas de cada nivel para lograr una mayor eficiencia y rendimiento.4
2. Notaciones para Expresiones
Las expresiones, un componente fundamental de los lenguajes de programación, pueden representarse de diversas maneras durante la fase de generación de código intermedio. Las tres notaciones principales son la prefija, la infija y la postfija.29
2.1. Notación Prefija (o Polaca)
En la notación prefija, el operador se coloca antes de sus respectivos operandos.29 Esta notación elimina la necesidad de utilizar paréntesis para especificar el orden en el que se deben realizar las operaciones, ya que la posición del operador indica directamente cuáles son las operaciones a llevar a cabo. Algunos ejemplos ilustrativos son:
La expresión infija a + b se representa en notación prefija como + a b.
La expresión infija a * (b + c) se convierte a la notación prefija como * a + b c.
La expresión infija a * b + c * d se expresa en notación prefija como + * a b * c d.La principal ventaja de la notación prefija radica en su capacidad para definir una estructura jerárquica implícita. El primer símbolo de la expresión siempre indica la operación principal, y los símbolos que le siguen son sus operandos. Estos operandos, a su vez, pueden ser expresiones representadas también en notación prefija, lo que establece una estructura recursiva que define de manera inequívoca el orden en el que se deben evaluar las operaciones.
2.2. Notación Infija
La notación infija es la forma estándar en la que los programadores suelen escribir las expresiones en los lenguajes de programación.29 En esta notación, el operador se sitúa entre los operandos a los que se aplica. Ejemplos comunes incluyen a + b, a * (b + c) y a * b + c * d. Aunque la notación infija resulta intuitiva y familiar para los humanos, presenta una complejidad inherente para los compiladores debido a la necesidad de reglas de precedencia de operadores (como la multiplicación antes de la adición) y el uso de paréntesis para alterar o hacer explícito el orden de evaluación. Esta complejidad motiva la necesidad de convertir las expresiones infijas a otras notaciones intermedias que faciliten su procesamiento.
2.3. Notación Postfija (o Polaca Inversa)
En la notación postfija, también conocida como notación polaca inversa, el operador se coloca después de sus operandos.29 Esta característica elimina la necesidad de utilizar paréntesis para determinar el orden de las operaciones. Algunos ejemplos de conversión de expresiones infijas a postfijas son:
La expresión infija a + b se representa en notación postfija como a b +.
La expresión infija a * (b + c) se convierte a la notación postfija como a b c + *.
La expresión infija a * b + c * d se expresa en notación postfija como a b * c d * +.Una de las principales ventajas de la notación postfija es que facilita la evaluación de expresiones mediante el uso de pilas.29 El algoritmo para evaluar una expresión en notación postfija utilizando una pila es el siguiente:
Se examina el siguiente símbolo de la expresión postfija.
Si el símbolo es un operando (ya sea un identificador o una constante), se introduce en la pila.29
Si el símbolo es un operador diádico (binario), se aplican las siguientes acciones:
Se extraen (desapilan) los dos operandos situados en la parte superior de la pila. Es importante notar que el primer operando desapilado es el segundo operando de la operación, y el segundo operando desapilado es el primer operando.
Se aplica el operador a estos dos operandos en el orden correcto.
El resultado de la operación se vuelve a introducir (apilar) en la pila.
Si el símbolo es un operador monádico (unario), se aplica el operador al operando situado en la parte superior de la pila, y se sustituye este por el resultado de la operación.29La notación postfija resulta especialmente útil en la implementación de compiladores e intérpretes, así como en calculadoras, debido a su estructura simplificada que permite una evaluación eficiente utilizando una pila. La ausencia de paréntesis y de reglas de precedencia de operadores simplifica el análisis sintáctico y la generación de código.
3. Representaciones de Código Intermedio
Durante la fase de compilación, el código fuente se transforma en diversas representaciones intermedias antes de la generación final del código objeto. Estas representaciones facilitan la optimización y la adaptación a diferentes arquitecturas.
3.1. Notación Polaca
El término "notación polaca" se utiliza generalmente para referirse a las notaciones prefija y postfija, aunque históricamente se asocia más con la notación prefija.29 Ambas formas de notación polaca se emplean para representar expresiones matemáticas y lógicas sin la necesidad de utilizar paréntesis, lo que elimina la ambigüedad en el orden de las operaciones.29 En la notación polaca, los identificadores (variables y constantes) aparecen en el mismo orden en que lo hacen en la expresión infija original.29 La diferencia principal radica en la posición de los operadores: en la notación prefija, el operador precede a sus operandos, mientras que en la notación postfija, el operador sigue a sus operandos.29 La notación polaca, tanto en su variante prefija como postfija, ofrece una representación lineal y no ambigua de las expresiones, lo que la convierte en una forma adecuada para la manipulación y evaluación por parte de los compiladores.
3.2. Código P
El Código P constituye un ejemplo temprano de código intermedio diseñado con el objetivo de lograr la independencia de la plataforma.29 Se trata de un código de máquina abstracto, es decir, un conjunto de instrucciones definido para una máquina virtual hipotética, en lugar de para una arquitectura física específica.7 Los programas compilados a Código P no se ejecutan directamente en el hardware, sino que requieren de una máquina P virtual para su interpretación o traducción posterior, a menudo mediante un intérprete o un compilador Just-In-Time (JIT).7
Una de las principales ventajas del Código P es su portabilidad. El mismo código P puede ser ejecutado en cualquier plataforma para la cual se haya implementado un intérprete o un traductor a código nativo.7 Además, el Código P a menudo resulta en un tamaño de código más pequeño en comparación con el código máquina nativo para la misma funcionalidad.32 Otra ventaja es que la naturaleza interpretada del Código P permite la realización de ciertas comprobaciones en tiempo de ejecución, lo que puede contribuir a una mayor seguridad y robustez del software.32 Sin embargo, una desventaja importante es que el rendimiento de los programas ejecutados mediante Código P puede ser más lento que el de los programas compilados directamente a código máquina nativo, debido a la sobrecarga de la interpretación o la traducción adicional.29 El Código P representó una solución significativa en las primeras etapas de la informática para abordar el desafío de la portabilidad del software.
3.3. Triplos
Los triplos constituyen una representación de código intermedio en la que cada instrucción se representa mediante una tupla de tres elementos: un operador y hasta dos operandos.29 En esta representación, los resultados intermedios de las operaciones no se almacenan en variables temporales con nombre explícito, sino que se referencian implícitamente mediante su posición o índice dentro de la secuencia de triplos generada.4
Por ejemplo, la expresión infija a * b + c podría traducirse a la siguiente secuencia de triplos:
(*, a, b)
(+,(1), c)En este ejemplo, el primer triplo representa la multiplicación de a y b. El resultado de esta operación, en lugar de ser asignado a una variable temporal, se referencia en el segundo triplo mediante el índice (1), indicando que se utiliza el resultado de la primera operación como uno de los operandos de la suma con c.
Una variación de esta representación son los triplos indirectos. En este esquema, se utiliza una lista o tabla adicional que contiene punteros o referencias a los triplos, especificando el orden en el que deben ejecutarse las operaciones.4 Esta forma indirecta resulta especialmente útil para la optimización de código, ya que permite la reordenación de las operaciones simplemente modificando el orden de los punteros en la tabla de triplos indirectos, sin necesidad de alterar los triplos en sí. Los triplos ofrecen una representación compacta del código intermedio, particularmente ventajosa para la optimización, ya que la referencia implícita a los resultados intermedios facilita la manipulación del orden de las operaciones. Los triplos indirectos extienden esta capacidad de optimización al separar la representación de las operaciones de su secuencia de ejecución.
3.4. Cuádruplos
Los cuádruplos son una representación de código intermedio similar a los triplos, con la diferencia fundamental de que incluyen un campo adicional para almacenar el resultado de la operación de manera explícita.4 Cada cuádruplo se representa típicamente como una tupla de cuatro elementos: (operador, operando1, operando2, resultado). En este formato, operando1 y operando2 son los operandos de la operación especificada por operador, y resultado es la variable temporal donde se almacena el resultado de la operación.
Considerando la misma expresión infija a * b + c del ejemplo anterior, su representación mediante cuádruplos sería la siguiente:
(*, a, b, t1)
(+ , t1, c, t2)En este caso, t1 y t2 son variables temporales generadas por el compilador para almacenar los resultados intermedios. El primer cuádruplo representa la multiplicación de a y b, con el resultado almacenado en t1. El segundo cuádruplo toma t1 y c como operandos, realiza la suma y almacena el resultado en t2.
La inclusión de un campo de resultado explícito en los cuádruplos facilita la optimización del código, ya que cada resultado intermedio tiene un nombre único y explícito que puede ser utilizado en operaciones posteriores.29 En comparación con los triplos, donde los resultados se referencian por su posición, los cuádruplos pueden resultar más sencillos de leer y manipular en algunas fases de la optimización, ya que el seguimiento de los valores intermedios se realiza a través de sus nombres temporales.
4. Esquemas de Generación de Código Intermedio
La generación de código intermedio es un proceso dirigido por la sintaxis, donde las construcciones del lenguaje fuente se traducen a una representación intermedia siguiendo un conjunto de reglas semánticas asociadas a las producciones gramaticales.
4.1. Variables y Constantes
En el proceso de generación de código intermedio, las variables y las constantes se representan de manera distinta. Las variables se referencian a través de entradas en la tabla de símbolos.7 La tabla de símbolos es una estructura de datos mantenida por el compilador que almacena información esencial sobre cada identificador utilizado en el programa fuente, incluyendo su nombre, tipo de dato, ámbito y dirección de memoria. La dirección de memoria asignada a una variable puede ser relativa al inicio de un bloque de datos específico (como una función o un bloque de código) o puede ser una dirección absoluta en la memoria, dependiendo de las características del lenguaje y de la etapa del proceso de compilación.46
Por otro lado, las constantes se representan directamente en el código intermedio utilizando su valor literal, o también pueden ser almacenadas en la tabla de símbolos.29 A diferencia de las variables, el valor de una constante es conocido y no cambia durante la ejecución del programa, lo que permite al compilador realizar optimizaciones basadas en estos valores fijos. La tabla de símbolos juega un papel fundamental en la gestión tanto de variables como de constantes, sirviendo como un repositorio centralizado de información que el compilador utiliza en diversas fases, desde el análisis semántico hasta la generación de código. La elección entre representar una constante directamente en el código intermedio o a través de la tabla de símbolos puede depender de factores como el tamaño de la constante, su frecuencia de uso y las estrategias de optimización empleadas por el compilador.
4.2. Expresiones Aritméticas y Lógicas
La traducción de expresiones aritméticas y lógicas a código intermedio implica la generación de una secuencia de operaciones elementales, donde los resultados intermedios de estas operaciones se almacenan utilizando variables temporales.29 El orden en que se generan estas operaciones está determinado por la precedencia de los operadores (por ejemplo, la multiplicación y la división tienen mayor precedencia que la adición y la sustracción) y por el uso de paréntesis en la expresión original, que pueden alterar el orden de evaluación predeterminado.
Consideremos un ejemplo en notación infija: a = b * c + d. Para traducir esta expresión a triplos, el compilador podría generar la siguiente secuencia: primero, se realiza la multiplicación de b y c, cuyo resultado se almacena implícitamente en la posición (1). Luego, se suma este resultado con d, almacenándose el nuevo resultado implícitamente en la posición (2). Finalmente, se asigna el valor de la posición (2) a la variable a. En el caso de los cuádruplos, la misma expresión podría traducirse de manera similar, pero utilizando variables temporales explícitas, como t1 para el resultado de b * c y t2 para el resultado de t1 + d, asignándose finalmente t2 a a. Este proceso de descomposición de expresiones complejas en una serie de operaciones más simples, utilizando variables temporales para guardar los resultados parciales, es fundamental para la generación de código intermedio que pueda ser fácilmente procesado por las fases posteriores del compilador.
4.3. Instrucciones de Asignación
La generación de código intermedio para una instrucción de asignación implica dos pasos principales: primero, se debe generar código para evaluar la expresión que se encuentra en el lado derecho de la asignación. Este proceso sigue los esquemas de generación definidos para las expresiones aritméticas y lógicas, tal como se describió en la sección anterior.1 El resultado de la evaluación de esta expresión se almacena típicamente en una variable temporal generada por el compilador. Segundo, se genera una instrucción de código intermedio que realiza la asignación propiamente dicha, es decir, que copia el valor de la variable temporal a la ubicación de memoria asociada con la variable que se encuentra en el lado izquierdo de la instrucción de asignación. La ubicación de memoria de la variable de destino se obtiene consultando la tabla de símbolos, donde se almacena esta información.
Consideremos un ejemplo en notación infija: x := y + 5. Para generar cuádruplos para esta instrucción, el compilador podría primero generar un cuádruplo para la suma de y y 5, almacenando el resultado en una variable temporal, por ejemplo, t1. Luego, generaría un segundo cuádruplo para asignar el valor de t1 a la variable x. Este proceso asegura que la expresión en el lado derecho se evalúe completamente antes de que su valor sea asignado a la variable de destino.
4.4. Instrucciones de Control
La traducción de las instrucciones de control, como las condicionales y los bucles, a código intermedio requiere la manipulación del flujo de ejecución del programa. Esto se logra mediante el uso de etiquetas para marcar puntos específicos en el código intermedio y la generación de instrucciones de salto condicional e incondicional para transferir el control entre estas etiquetas.
- Condicionales (if-else): Para una instrucción condicional como if E then I1 else I2, el compilador primero genera código para evaluar la expresión condicional E y almacena el resultado en una variable temporal, digamos t1.1 A continuación, se genera una instrucción de salto condicional, como (TRZ, siguiente_cuádruplo_I1, t1, ) en el caso de cuádruplos, que indica que si t1 (el resultado de E) es falso (cero), el control debe saltar a la primera instrucción del código intermedio correspondiente a la parte else (I2). Si t1 es verdadero, la ejecución continúa secuencialmente con el código para la parte then (I1). Después del código para I1, se genera un salto incondicional para evitar la ejecución de I2. El código para I2 comienza en una etiqueta específica, y la ejecución continúa desde allí si la condición E fue falsa. Finalmente, puede haber una etiqueta después de I2 a la que salta la instrucción después de I1.
- Bucles (while, for): Los bucles se traducen de manera similar, utilizando etiquetas y saltos condicionales e incondicionales para implementar la repetición de un bloque de código mientras se cumpla una determinada condición. Para una instrucción while E do I, se genera una etiqueta al inicio del bucle. Luego, se genera código para evaluar la condición E. Si la condición es falsa, se realiza un salto para salir del bucle a una etiqueta situada después del código para el cuerpo del bucle (I). Si la condición es verdadera, se ejecuta el código para el cuerpo del bucle (I), seguido de un salto incondicional de vuelta a la etiqueta del inicio del bucle para evaluar la condición nuevamente.
4.5. Funciones
La traducción de la definición y la llamada de funciones a código intermedio implica varios aspectos, incluyendo el manejo de los argumentos y los valores de retorno.1
- Definición de Funciones: Cuando se traduce la definición de una función, el compilador puede crear un nuevo bloque de código intermedio que representa el cuerpo de la función. Este bloque puede tener su propia tabla de símbolos local para gestionar las variables declaradas dentro de la función. El manejo de los argumentos implica determinar si se pasan por valor (se copia el valor del argumento) o por referencia (se pasa la dirección de memoria del argumento). El código intermedio debe incluir instrucciones para recibir estos argumentos y almacenarlos en ubicaciones accesibles dentro del ámbito de la función. Para el valor de retorno, se reserva un espacio o se utiliza una variable temporal donde la función puede almacenar el resultado antes de retornar al punto de llamada.
- Llamada a Funciones: La traducción de una llamada a una función implica generar código para preparar los argumentos que se van a pasar a la función. Esto puede incluir la evaluación de expresiones y la copia de valores a ubicaciones específicas (registros o memoria) según la convención de llamada del lenguaje o la arquitectura. A continuación, se genera una instrucción de código intermedio para invocar la función, transfiriendo el control al inicio del bloque de código intermedio correspondiente a la función llamada. Si la función devuelve un valor, el código intermedio también debe incluir instrucciones para recuperar este valor de retorno, que a menudo se maneja a través de una variable temporal en el ámbito del llamante.
4.6. Estructuras (arrays, registros, etc.)
La traducción del acceso a los elementos de las estructuras de datos, como arrays y registros, a código intermedio se realiza mediante cálculos de direcciones basados en desplazamientos.1
- Arrays: Para acceder a un elemento específico de un array, el compilador debe calcular la dirección de memoria de ese elemento. Esto generalmente implica multiplicar el índice del elemento (o una combinación de índices en el caso de arrays multidimensionales) por el tamaño de cada elemento en el array. El resultado de esta multiplicación se suma a la dirección base del array (la dirección de memoria del primer elemento) para obtener la dirección del elemento deseado. El código intermedio generado incluirá estas operaciones aritméticas para calcular la dirección efectiva del elemento del array al que se está accediendo.
- Registros (o Estructuras): Los registros son estructuras de datos que contienen campos de diferentes tipos. En la traducción del acceso a un campo específico de un registro, el compilador utiliza un desplazamiento fijo. Cada campo dentro de un registro se almacena en una posición de memoria específica, determinada por su desplazamiento desde la dirección base del registro (la dirección de memoria donde comienza el registro). Cuando se accede a un campo de un registro, el compilador genera código intermedio que suma este desplazamiento fijo a la dirección base del registro para obtener la dirección de memoria del campo al que se está accediendo. La información sobre los desplazamientos de los campos dentro de un registro se almacena en la tabla de símbolos.
Conclusión
La generación de código intermedio es una fase fundamental en el proceso de compilación que facilita la portabilidad y optimización del código. A través de diversas notaciones y representaciones, el compilador transforma el código fuente en una forma más manejable para las etapas posteriores. La elección de la notación y la representación del código intermedio influye directamente en la eficiencia del proceso de compilación y en la calidad del código objeto final. Los esquemas de generación para las diferentes construcciones del lenguaje, desde variables y constantes hasta funciones y estructuras, demuestran la complejidad y la riqueza de esta etapa del diseño de compiladores.
Obras citadas
Overview of Intermediate Code Generation - Bhopal - LNCT, fecha de acceso: abril 29, 2025, https://lnct.ac.in/wp-content/uploads/2020/04/CS-603-C-Compiler-Design-Unit-4.pdf
What is the role of an intermediate code generator in a compiler? - TutorChase, fecha de acceso: abril 29, 2025, https://www.tutorchase.com/answers/a-level/computer-science/what-is-the-role-of-an-intermediate-code-generator-in-a-compiler
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 - CSE IITM, fecha de acceso: abril 29, 2025, https://www.cse.iitm.ac.in/~rupesh/teaching/compiler/aug15/schedule/5-ir.pdf
35. INTERMEDIATE CODE GENERATION INTRODUCTION || BENEFITS || COMPILER DESIGN - YouTube, fecha de acceso: abril 29, 2025, https://www.youtube.com/watch?v=Pd9dqUiQ_Lk
Need for Intermediate Code and Code Optimization | GeeksforGeeks, fecha de acceso: abril 29, 2025, https://www.geeksforgeeks.org/need-for-intermediate-code-and-code-optimization/
Intermediate representation - Wikipedia, fecha de acceso: abril 29, 2025, https://en.wikipedia.org/wiki/Intermediate_representation
Why do we use intermediate representations / languages? - Musing Mortoray, fecha de acceso: abril 29, 2025, https://mortoray.com/why-we-use-intermediate-representations/
Mastering Intermediate Code Generation In Compiler Design - Bgi Bhopal, fecha de acceso: abril 29, 2025, https://bgibhopal.com/mastering-intermediate-code-generation-in-compiler-design/
Intermediate Representations, Part 1 - jahan's blog, fecha de acceso: abril 29, 2025, https://soliloq.uy/2020/01/intermediate-representations-part-1/
What is Intermediate Code? — Limeup, fecha de acceso: abril 29, 2025, https://limeup.io/glossary/intermediate-code/
What is the purpose of code optimization at intermediate phase in compiler? [closed], fecha de acceso: abril 29, 2025, https://stackoverflow.com/questions/33184269/what-is-the-purpose-of-code-optimization-at-intermediate-phase-in-compiler
What are the pros and cons of intermediate representation (IR) in compiler construction? - Reddit, fecha de acceso: abril 29, 2025, https://www.reddit.com/r/Compilers/comments/xhe1ys/what_are_the_pros_and_cons_of_intermediate/
Intermediate Code Generation in Compiler Design - Testbook.com, fecha de acceso: abril 29, 2025, https://testbook.com/gate/intermediate-code-generation-in-compiler-design-notes
Lab 6: Intermediary Code — TDDB44 Compiler Construction documentation - IDA.LiU.SE, fecha de acceso: abril 29, 2025, https://www.ida.liu.se/~TDDB44/laboratories/instructions/lab6.html
Intermediate Representation - Communications of the ACM, fecha de acceso: abril 29, 2025, https://cacm.acm.org/practice/intermediate-representation/
Types of Intermediate Code Representation - Tutorialspoint, fecha de acceso: abril 29, 2025, https://www.tutorialspoint.com/what-is-types-of-intermediate-code-representation
Intermediate Representations, fecha de acceso: abril 29, 2025, https://cs.lmu.edu/~ray/notes/ir/
Intermediate Representations, fecha de acceso: abril 29, 2025, https://web.stanford.edu/class/archive/cs/cs143/cs143.1128/handouts/230%20Intermediate%20Rep.pdf
duohub.ai, fecha de acceso: abril 29, 2025, https://duohub.ai/glossary/t/triples#:~:text=Triples%20are%20fundamental%20structures%20in,relationship)%2C%20and%20an%20object.
Optimize Options (Using the GNU Compiler Collection (GCC)), fecha de acceso: abril 29, 2025, https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
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
Intermediate Code Generation in Compiler Design - BYJU'S, fecha de acceso: abril 29, 2025, https://byjus.com/gate/intermediate-code-generation-in-compiler-design-notes/
Global Optimisation, fecha de acceso: abril 29, 2025, https://people.bath.ac.uk/masjap/Notes/C73/section3_12.html
Representation of Intermediate Code Generation- a Compiler - Journal of Emerging Technologies and Innovative Research, fecha de acceso: abril 29, 2025, https://www.jetir.org/papers/JETIR1806056.pdf
Peephole Optimization in Compiler Design | GeeksforGeeks, fecha de acceso: abril 29, 2025, https://www.geeksforgeeks.org/peephole-optimization-in-compiler-design/
If register has no effect on good compilers, but makes your code faster for bad compilers, is there any reason not to indiscriminately put register in front of all eligible variables? : r/C_Programming - Reddit, fecha de acceso: abril 29, 2025, https://www.reddit.com/r/C_Programming/comments/19b27rd/if_register_has_no_effect_on_good_compilers_but/
What is Intermediate Code Generation - Tutorialspoint, fecha de acceso: abril 29, 2025, https://www.tutorialspoint.com/what-is-intermediate-code-generation
Capítulo 5. Análisis semántico, fecha de acceso: abril 29, 2025, http://arantxa.ii.uam.es/~alfonsec/docs/compila5.htm
Intermediate Representation (IR), fecha de acceso: abril 29, 2025, https://courses.grainger.illinois.edu/cs426/fa2022/Notes/5ir.pdf
Intermediate Representations, fecha de acceso: abril 29, 2025, https://www.cs.cornell.edu/courses/cs4120/2022sp/notes/ir/
The p-code system, fecha de acceso: abril 29, 2025, https://www.unige.ch/medecine/nouspikel/ti99/psystem.htm
P-code machine - Wikipedia, fecha de acceso: abril 29, 2025, https://en.wikipedia.org/wiki/P-code_machine
p-code intermediate assembler language, fecha de acceso: abril 29, 2025, https://bitsavers.trailing-edge.com/pdf/stanford/sel_techReports/TN148_P-Code_AsmLang_PAIL-4_Mar78.pdf
basponccollege.org, fecha de acceso: abril 29, 2025, https://basponccollege.org/LMS/EMaterial/Science/Comp/PMM/CCBYPMM.pdf
Three address code in Compiler - GeeksforGeeks, fecha de acceso: abril 29, 2025, https://www.geeksforgeeks.org/three-address-code-compiler/
Lecture 24: Intermediate code generation 24.1 Introduction - KR Chowdhary, fecha de acceso: abril 29, 2025, https://www.krchowdhary.com/compiler/lt18.pdf
Intermediate Representations - CSE IIT KGP, fecha de acceso: abril 29, 2025, https://cse.iitkgp.ac.in/~goutam/bbsCompiler/lect/lect10.pdf
(Intermediate) Code Generation : r/Compilers - Reddit, fecha de acceso: abril 29, 2025, https://www.reddit.com/r/Compilers/comments/16lct7u/intermediate_code_generation/
How are "indirect triples" more advantageous than "quadruples" in the intermediate representation of source program - Stack Overflow, fecha de acceso: abril 29, 2025, https://stackoverflow.com/questions/66922138/how-are-indirect-triples-more-advantageous-than-quadruples-in-the-intermedia
Intermediate Code Generation| Quadruples, Triples| Compiler Design - YouTube, fecha de acceso: abril 29, 2025, https://www.youtube.com/watch?v=8wPBYp0toiM
Intermediate Code Generation - CSE IIT KGP, fecha de acceso: abril 29, 2025, https://cse.iitkgp.ac.in/~bivasm/compiler_notes/TAC_v3.pdf
Lecture 9 – Semantic Analysis and Intermediate Code Generation - Compiler Construction, fecha de acceso: abril 29, 2025, https://home.adelphi.edu/~siegfried/cs372/372l9.pdf
Topic 7 - Intermediate Code Generation, fecha de acceso: abril 29, 2025, https://www.cs.kent.edu/~batcher/CS453111/topic7.html
3 Address Code | Quadruple | Triples | Compiler Design - YouTube, fecha de acceso: abril 29, 2025, https://www.youtube.com/watch?v=o5Y2eHeJsr8
Tema 5 Tabla de Símbolos, fecha de acceso: abril 29, 2025, http://www.lcc.uma.es/~galvez/ftp/tci/tictema5.pdf
Generación de la tabla de símbolos - YouTube, fecha de acceso: abril 29, 2025, https://www.youtube.com/watch?v=yoBba5GxcUU
www.cartagena99.com, fecha de acceso: abril 29, 2025, https://www.cartagena99.com/recursos/alumnos/apuntes/ININF2_M4_U5_T2.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
Reverse Polish Notation Parser - 101 Computing, fecha de acceso: abril 29, 2025, https://www.101computing.net/reverse-polish-notation/
5 Control flow | Advanced R - Hadley Wickham, fecha de acceso: abril 29, 2025, https://adv-r.hadley.nz/control-flow.html
3.4: Loop Optimizations - Engineering LibreTexts, fecha de acceso: abril 29, 2025, https://eng.libretexts.org/Bookshelves/Computer_Science/Programming_and_Computation_Fundamentals/High_Performance_Computing_(Severance)/03%3A_Programming_and_Tuning_Software/3.04%3A_Loop_Optimizations
Loop Optimizations: interpreting the compiler optimization report - Johnny's Software Lab, fecha de acceso: abril 29, 2025, https://johnnysswlab.com/loop-optimizations-interpreting-the-compiler-optimization-report/
Hydra: Generalizing Peephole Optimizations with Program Synthesis - cs.utah.edu, fecha de acceso: abril 29, 2025, https://users.cs.utah.edu/~regehr/generalization-oopsla24.pdf
Peephole optimizations in C++ and C# | Egor Bogatov — Developer at Microsoft, fecha de acceso: abril 29, 2025, https://egorbo.com/peephole-optimizations.html
Compiler Optimization Effects on Register Collisions - CORE, fecha de acceso: abril 29, 2025, https://core.ac.uk/download/219380352.pdf
Compiler-Driven Power Optimizations in the Register File of Processor-Based Systems - DROPS, fecha de acceso: abril 29, 2025, https://drops.dagstuhl.de/storage/16dagstuhl-seminar-proceedings/dsp-vol05141/DagSemProc.05141.4/DagSemProc.05141.4.pdf
c++ - Is it bad practice to write code that relies on compiler optimizations?, fecha de acceso: abril 29, 2025, https://softwareengineering.stackexchange.com/questions/359027/is-it-bad-practice-to-write-code-that-relies-on-compiler-optimizations
Code Optimization in Compiler Design | GeeksforGeeks, fecha de acceso: abril 29, 2025, https://www.geeksforgeeks.org/code-optimization-in-compiler-design/
Compiler Design - Code Optimization - Tutorialspoint, fecha de acceso: abril 29, 2025, https://www.tutorialspoint.com/compiler_design/compiler_design_code_optimization.htm
Optimizing compiler - Wikipedia, fecha de acceso: abril 29, 2025, https://en.wikipedia.org/wiki/Optimizing_compiler
Program Analysis Tools, fecha de acceso: abril 29, 2025, https://www.cs.odu.edu/~zeil/cs350/latest/Public/analysis/index.html
Data flow analysis in Compiler | GeeksforGeeks, fecha de acceso: abril 29, 2025, https://www.geeksforgeeks.org/data-flow-analysis-compiler/
How do I generate a data flow graph with clang or other tools? - Stack Overflow, fecha de acceso: abril 29, 2025, https://stackoverflow.com/questions/20456962/how-do-i-generate-a-data-flow-graph-with-clang-or-other-tools
How was dataflow analysis performed before SSA? - Retrocomputing Stack Exchange, fecha de acceso: abril 29, 2025, https://retrocomputing.stackexchange.com/questions/9093/how-was-dataflow-analysis-performed-before-ssa
UNIT – V - Compiler Design – SCS1303 - Sathyabama, fecha de acceso: abril 29, 2025, https://www.sathyabama.ac.in/sites/default/files/course-material/2020-11/Unit-5.pdf
Issues in the design of a code generator | GeeksforGeeks, fecha de acceso: abril 29, 2025, https://www.geeksforgeeks.org/issues-in-the-design-of-a-code-generator
Compiler Design Code Generation - Tutorialspoint, fecha de acceso: abril 29, 2025, https://www.tutorialspoint.com/compiler_design/compiler_design_code_generation.htm
UNIT-VIII, fecha de acceso: abril 29, 2025, https://jkmaterials.yolasite.com/resources/materials/CompilerDesign/UNIT-VIII.pdf
Introduction to Code Generation in Compiler | E-Learning-Modules4Engg, fecha de acceso: abril 29, 2025, http://elearningmodules4engg.blogspot.com/2017/12/introduction-to-code-generation-in.html
Difference Between Source Code and Object Code | GeeksforGeeks, fecha de acceso: abril 29, 2025, https://www.geeksforgeeks.org/difference-between-source-code-and-object-code/
Object file - Wikipedia, fecha de acceso: abril 29, 2025, https://en.wikipedia.org/wiki/Object_file
I have a confusion when differentiating between Source code, Object code, Assembly code, and Machine code - Stack Overflow, fecha de acceso: abril 29, 2025, https://stackoverflow.com/questions/49031020/i-have-a-confusion-when-differentiating-between-source-code-object-code-assemb
Register Allocations in Code Generation | GeeksforGeeks, fecha de acceso: abril 29, 2025, https://www.geeksforgeeks.org/register-allocations-in-code-generation/
Lesson 8: Code Generation | BTU, fecha de acceso: abril 29, 2025, https://btu.edu.ge/wp-content/uploads/2023/08/Lesson-8_-Code-Generation.pdf
How do modern compilers choose which variables to put in registers?, fecha de acceso: abril 29, 2025, https://langdev.stackexchange.com/questions/4325/how-do-modern-compilers-choose-which-variables-to-put-in-registers
Register Allocation explained in detail? : r/Compilers - Reddit, fecha de acceso: abril 29, 2025, https://www.reddit.com/r/Compilers/comments/1ghzinn/register_allocation_explained_in_detail/
Compiler code generation--register allocation inside conditional blocks - Stack Overflow, fecha de acceso: abril 29, 2025, https://stackoverflow.com/questions/3766030/compiler-code-generation-register-allocation-inside-conditional-blocks
Register allocation - CS Courses Overview, fecha de acceso: abril 29, 2025, https://courses.cs.cornell.edu/cs4120/2023sp/notes.html?id=regalloc
How do modern compilers choose which variables to put in registers? - Hacker News, fecha de acceso: abril 29, 2025, https://news.ycombinator.com/item?id=43048073
How does compiler know if a variable is spilled in code generation? - Stack Overflow, fecha de acceso: abril 29, 2025, https://stackoverflow.com/questions/74933611/how-does-compiler-know-if-a-variable-is-spilled-in-code-generation
Object code - Wikipedia, fecha de acceso: abril 29, 2025, https://en.wikipedia.org/wiki/Object_code
What is Assembly Language? - GeeksforGeeks, fecha de acceso: abril 29, 2025, https://www.geeksforgeeks.org/what-is-assembly-language/
Assembly Language as Object Code - Department of Computer Science, fecha de acceso: abril 29, 2025, https://www.cs.tufts.edu/~nr/cs257/archive/douglas-jones/asm-as-object-code.pdf
Data Structures Tutorial - GeeksforGeeks, fecha de acceso: abril 29, 2025, https://www.geeksforgeeks.org/data-structures/
Loop Optimizations: how does the compiler do it? - Johnny's Software Lab, fecha de acceso: abril 29, 2025, https://johnnysswlab.com/loop-optimizations-how-does-the-compiler-do-it/
Compiler optimization techniques - IBM, fecha de acceso: abril 29, 2025, https://www.ibm.com/docs/en/aix/7.1?topic=tuning-compiler-optimization-techniques
Global Optimization, fecha de acceso: abril 29, 2025, https://web.stanford.edu/class/archive/cs/cs143/cs143.1128/lectures/15/Slides15.pdf
Optimizing Memory Accesses Using Advanced Compile-Time Memory Disambiguation Techniques - IMPACT, fecha de acceso: abril 29, 2025, http://impact.crhc.illinois.edu/shared/Papers/ctftech-impact.pdf
Compilers - What Every Programmer Should Know About Compiler Optimizations, Part 2, fecha de acceso: abril 29, 2025, https://learn.microsoft.com/en-us/archive/msdn-magazine/2015/may/compilers-what-every-programmer-should-know-about-compiler-optimizations-part-2
"Compiler Optimization Effects on Register Collisions" by Jonathan S. Tan, fecha de acceso: abril 29, 2025, https://digitalcommons.calpoly.edu/theses/1841/
www.mathworks.com, fecha de acceso: abril 29, 2025, https://www.mathworks.com/help/ecoder/ug/create-stack-usage-profile-for-generated-code.html#:~:text=Under%20certain%20conditions%2C%20compilers%20can,uses%20the%20red%20zone%20directly.
CMSC 430 Introduction to Compilers Data Flow Analysis Applications and Implementations, fecha de acceso: abril 29, 2025, https://www.cs.umd.edu/class/fall2018/cmsc430/slides/08-data-flow-cil.pdf
Comentarios
Publicar un comentario