Problemas en el diseño de un generador de código

El generador de código convierte la representación intermedia del código fuente en una forma que la máquina puede ejecutar fácilmente. Se espera que un generador de código genere el código correcto. El diseño del generador de código debe hacerse de tal manera que pueda implementarse, probarse y mantenerse fácilmente. 

El siguiente problema surge durante la fase de generación de código: 

  • Entrada al generador de código : la entrada al generador de código es el código intermedio generado por el front-end, junto con la información en la tabla de símbolos que determina las direcciones de tiempo de ejecución de los objetos de datos indicados por los nombres en la representación intermedia. Los códigos intermedios se pueden representar principalmente en cuádruples, triples, triples indirectos, notación Postfix, árboles sintácticos, DAG, etc. ha tenido lugar y los operadores de conversión de tipos se han insertado donde sea necesario.
  • Programa de destino: El programa de destino es la salida del generador de código. La salida puede ser lenguaje de máquina absoluto, lenguaje de máquina reubicable o lenguaje ensamblador.
    • El lenguaje de máquina absoluto como salida tiene la ventaja de que se puede colocar en una ubicación de memoria fija y se puede ejecutar de inmediato.
    • El lenguaje de máquina reubicable como salida permite que los subprogramas y las subrutinas se compilen por separado. Los módulos de objetos reubicables pueden vincularse entre sí y cargarse mediante un cargador de vinculación. Pero hay un gasto adicional de vinculación y carga.
    • El lenguaje ensamblador como salida facilita la generación de código. Podemos generar instrucciones simbólicas y utilizar las macrofacilidades de los ensambladores para generar código. Y necesitamos un paso de ensamblaje adicional después de la generación del código.
  • Gestión de la memoria: el front-end y el generador de código realizan la asignación de los nombres en el programa fuente a las direcciones de los objetos de datos. Un nombre en las tres instrucciones de dirección se refiere a la entrada de la tabla de símbolos para el nombre. Luego, a partir de la entrada de la tabla de símbolos, se puede determinar una dirección relativa para el nombre.
  • Selección de instrucciones: seleccionar las mejores instrucciones mejorará la eficiencia del programa. Incluye las instrucciones que deben ser completas y uniformes. Las velocidades de instrucción y los lenguajes de la máquina también juegan un papel importante cuando se considera la eficiencia. Pero si no nos importa la eficiencia del programa de destino, la selección de instrucciones es sencilla. Por ejemplo, las declaraciones de tres direcciones respectivas se traducirían a la última secuencia de código como se muestra a continuación:
P:=Q+R
S:=P+T

MOV Q, R0
ADD R, R0
MOV R0, P
MOV P, R0
ADD T, R0
MOV R0, S

Aquí la cuarta declaración es redundante ya que el valor de P se carga nuevamente en esa declaración que acaba de almacenarse en la declaración anterior. Conduce a una secuencia de código ineficiente. Una representación intermedia dada se puede traducir en muchas secuencias de código, con diferencias de costo significativas entre las diferentes implementaciones. Se necesita un conocimiento previo del costo de la instrucción para diseñar buenas secuencias, pero la información precisa sobre el costo es difícil de predecir.

  • Problemas de asignación de registros: el uso de registros hace que los cálculos sean más rápidos en comparación con los de la memoria, por lo que la utilización eficiente de los registros es importante. El uso de registros se subdivide en dos subproblemas:
  1. Durante la asignación de registros, seleccionamos solo el conjunto de variables que residirán en los registros en cada punto del programa.
  2. Durante una fase posterior de asignación de registros, se selecciona el registro específico para acceder a la variable.
  3. Orden de evaluación: el generador de código decide el orden en que se ejecutará la instrucción. El orden de los cálculos afecta la eficiencia del código de destino. Entre muchos órdenes computacionales, algunos requerirán solo menos registros para contener los resultados intermedios. Sin embargo, elegir el mejor orden en el caso general es un problema NP-completo difícil.
  4. Enfoques de los problemas de generación de código: el generador de código siempre debe generar el código correcto. Es fundamental debido a la cantidad de casos especiales a los que se puede enfrentar un generador de código. Algunos de los objetivos de diseño del generador de código son:
    • Correcto
    • Fácilmente mantenible
    • Comprobable
    • Eficiente

Publicación traducida automáticamente

Artículo escrito por Aditya_04 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *