stringtranslate.com

Generación de código (compilador)

En informática , la generación de código es parte de la cadena de procesos de un compilador y convierte la representación intermedia del código fuente en una forma (por ejemplo, código de máquina ) que el sistema de destino puede ejecutar fácilmente.

Los compiladores sofisticados suelen realizar múltiples pasadas por varias formas intermedias. Este proceso de varias etapas se utiliza porque muchos algoritmos para la optimización del código son más fáciles de aplicar uno a la vez, o porque la entrada a una optimización depende del procesamiento completo realizado por otra optimización. Esta organización también facilita la creación de un único compilador que puede apuntar a múltiples arquitecturas, ya que solo la última de las etapas de generación de código (el backend ) necesita cambiar de un objetivo a otro. (Para obtener más información sobre el diseño del compilador, consulte Compilador ).

La entrada al generador de código normalmente consiste en un árbol de análisis o un árbol de sintaxis abstracta . [1] El árbol se convierte en una secuencia lineal de instrucciones, generalmente en un lenguaje intermedio como el código de tres direcciones . Las etapas posteriores de la compilación pueden denominarse o no "generación de código", dependiendo de si implican un cambio significativo en la representación del programa. (Por ejemplo, un paso de optimización de mirilla probablemente no se denominaría "generación de código", aunque un generador de código podría incorporar un paso de optimización de mirilla).

Tareas principales

Además de la conversión básica de una representación intermedia a una secuencia lineal de instrucciones de máquina, un generador de código típico intenta optimizar el código generado de alguna manera.

Las tareas que normalmente forman parte de la fase de "generación de código" de un compilador sofisticado incluyen:

La selección de instrucciones generalmente se lleva a cabo mediante un recorrido recursivo de postorden en el árbol de sintaxis abstracta, comparando configuraciones de árbol particulares con plantillas; por ejemplo, el árbol W := ADD(X,MUL(Y,Z))podría transformarse en una secuencia lineal de instrucciones generando recursivamente las secuencias para t1 := Xy t2 := MUL(Y,Z)y luego emitiendo la instrucción ADD W, t1, t2.

En un compilador que utiliza un lenguaje intermedio, puede haber dos etapas de selección de instrucciones: una para convertir el árbol de análisis en código intermedio y una segunda fase mucho más tarde para convertir el código intermedio en instrucciones del conjunto de instrucciones de la máquina de destino. Esta segunda fase no requiere atravesar el árbol; se puede hacer de forma lineal y, por lo general, implica una simple sustitución de las operaciones del lenguaje intermedio con sus correspondientes códigos de operación . Sin embargo, si el compilador es en realidad un traductor de idiomas (por ejemplo, uno que convierte Java a C++ ), entonces la segunda fase de generación de código puede implicar la construcción de un árbol a partir del código intermedio lineal.

Generación de código en tiempo de ejecución

Cuando la generación de código se produce en tiempo de ejecución , como en la compilación justo a tiempo (JIT), es importante que todo el proceso sea eficiente con respecto al espacio y al tiempo. Por ejemplo, cuando se interpretan y utilizan expresiones regulares para generar código en tiempo de ejecución, a menudo se genera una máquina de estados finitos no determinista en lugar de una determinista, porque normalmente la primera se puede crear más rápidamente y ocupa menos espacio de memoria que la segunda. A pesar de que generalmente genera código menos eficiente, la generación de código JIT puede aprovechar la información de perfiles que solo está disponible en tiempo de ejecución.

Conceptos relacionados

La tarea fundamental de recibir información en un idioma y producir resultados en un idioma no trivialmente diferente puede entenderse en términos de las operaciones transformacionales centrales de la teoría del lenguaje formal . En consecuencia, algunas técnicas que se desarrollaron originalmente para su uso en compiladores han llegado a emplearse también de otras maneras. Por ejemplo, YACC (Yet Another Compiler-Compiler ) toma información en formato Backus-Naur y la convierte en un analizador en C. Aunque se creó originalmente para la generación automática de un analizador para un compilador, yacc también se usa a menudo para automatizar la escritura de código que debe modificarse cada vez que se cambian las especificaciones. [3]

Muchos entornos de desarrollo integrados (IDE) admiten alguna forma de generación automática de código fuente , a menudo utilizando algoritmos comunes con los generadores de código compilador, aunque normalmente menos complicados. (Ver también: Transformación de programas , Transformación de datos ).

Reflexión

En general, un analizador de sintaxis y semántica intenta recuperar la estructura del programa a partir del código fuente, mientras que un generador de código utiliza esta información estructural (por ejemplo, tipos de datos ) para producir código. En otras palabras, el primero agrega información mientras que el segundo pierde parte de la información. Una consecuencia de esta pérdida de información es que la reflexión se vuelve difícil o incluso imposible. Para contrarrestar este problema, los generadores de código suelen incorporar información sintáctica y semántica además del código necesario para la ejecución.

Ver también

Referencias

  1. ^ Steven Muchnick; Muchnick y asociados (15 de agosto de 1997). Implementación de diseño de compilador avanzado . Morgan Kaufman. ISBN 978-1-55860-320-2. codigo de GENERACION.
  2. ^ Ah, Alfred V.; Ravi Sethi; Jeffrey D. Ullman (1987). Compiladores: principios, técnicas y herramientas . Addison-Wesley. pag. 15.ISBN _ 0-201-10088-6.
  3. ^ Generación de código: la verdadera lección de los rieles. Artima.com (16 de marzo de 2006). Recuperado el 10 de agosto de 2013.