Tema 6: Generación de código (parte 2) Procesamiento de Lenguajes Dept de Lenguajes y Sistemas Informáticos Universidad de Alicante Procesamiento de Lenguajes Tema 6: Generación de código (parte 2) 1 / 13 Generación de código para funciones Caso simple: lenguajes sin recursividad Compilar un programa con funciones implica: Compilar el código de la función Compilar las llamadas a la función El código generado para una función tiene una etiqueta/dirección de comienzo Los argumentos tienen posiciones fijas de memoria (como las variables globales), y el valor de retorno (el que devuelve la función) también y las variables locales, y la dirección de retorno (posición del programa a la que vuelve cuando termina la función) Procesamiento de Lenguajes Tema 6: Generación de código (parte 2) 2 / 13
Registro de activación de una función Al conjunto de valores formado por: valor de retorno dirección de retorno argumentos variables locales variables temporales se le llama Registro de activación (Activation record, frame) En un lenguaje que no permita la recursividad, en un momento dado solamente hay una instancia de cada función ejecutándose, luego el registro de activación puede (y debe) tener una dirección de memoria fija y conocida por el compilador Procesamiento de Lenguajes Tema 6: Generación de código (parte 2) 3 / 13 Ejemplo 1 (sin recursividad) int incrementa(int a) int res; res = a + 1; return res; L1 mov dir(a) tmp1 mov #1 tmp2 mov tmp1 A addi tmp2 mov A tmp3 mov tmp3 dir(res) ; secuencia de retorno mov dir(res) tmp1 mov tmp1 valor_retorno mov direccion_retorno A jmp @A 87 valor de retorno 88 dirección de retorno 89 a 90 res 91 tmp1 92 tmp2 93 tmp3 Procesamiento de Lenguajes Tema 6: Generación de código (parte 2) 4 / 13
Ejemplo 1 (sin recursividad) int incrementa(int a) int res; res = a + 1; return res; L1 mov 89 91 mov #1 92 mov 91 A addi 92 mov A 93 mov 93 90 ; secuencia de retorno mov 90 91 mov 91 87 mov 88 A jmp @A 87 valor de retorno 88 dirección de retorno 89 a 90 res 91 tmp1 92 tmp2 93 tmp3 Procesamiento de Lenguajes Tema 6: Generación de código (parte 2) 4 / 13 Ejemplo 1 (sin recursividad) Código de la llamada n = 7; b = incrementa(n); mov #7 tmp1 mov tmp1 dir(n) ; secuencia de llamada mov dir(n) tmp1 ; cálculo de los parámetros mov tmp1 89 ; cargar el primer parámetro mvetq L7 88 ; guardar dirección de retorno jmp L1 L7 mov 87 tmp2 ; coger valor de retorno mov tmp2 dir(b) Procesamiento de Lenguajes Tema 6: Generación de código (parte 2) 5 / 13
Generación de código para funciones Caso general: lenguajes con recursividad Si el lenguaje permite la recursividad, un registro de activación estático (con dirección de memoria fija) no sirve Ejemplo: int factorial(int n) if (n<=1) return 1; else return factorial(n-1)*n; factorial(5) factorial(4)*5 factorial(3)*4 factorial(2)*3 factorial(1)*2 Cada instancia (llamada) debe tener su propio registro de activación las direcciones de memoria de argumentos, variables locales, etc, no son estáticas Procesamiento de Lenguajes Tema 6: Generación de código (parte 2) 6 / 13 Registro de activación en un lenguaje con recursividad B valor de retorno dirección de retorno B anterior parámetros variables locales temporales locales donde B es un registro del procesador que se utiliza para apuntar al registro de activación actual Cada vez que se hace una llamada hay que guardar el valor anterior de B, crear el nuevo registro y hacer que B apunte a ese nuevo registro Procesamiento de Lenguajes Tema 6: Generación de código (parte 2) 7 / 13
Ejemplo 1 (con recursividad) int incrementa(int a) int res; res = a + 1; return res; L1 mov @B+0 @B+2 ; tmp1 = a mov #1 @B+3 ; tmp2 = 1 mov @B+2 A addi @B+3 mov A @B+4 ; tmp3 = tmp1 + tmp2 mov @B+4 @B+1 ; res = tmp3 ; secuencia de retorno mov @B+1 @B+2 ; tmp1 = res mov @B+2 @B-3 ; valor de retorno = tmp1 mov @B-2 A ; dirección de retorno en A jmp @A B valor de retorno dirección de retorno B anterior a res tmp1 tmp2 tmp3 Procesamiento de Lenguajes Tema 6: Generación de código (parte 2) 8 / 13 Ejemplo 1 (con recursividad) Código de la llamada n = 7; b = incrementa(n); // suponemos dir(n) = @B+2, dir(b)=@b+3 mov #7 @B+5 ; tmp1 = 7 mov @B+5 @B+2 ; n = tmp1 ; secuencia de llamada: reservamos 5,6,7,8 para RA mov @B+2 @B+9 ; cálculo de los parámetros mov @B+9 @B+8 ; cargar el primer parámetro (n --> a) mov B @B+7 ; guardar B anterior mov B A addi #8 mov A B ; poner nueva B apuntando al primer argumento mvetq L7 @B-2 ; guardar dirección de retorno jmp L1 L7 mov @B-1 B ; restaurar valor de B mov @B+5 @B+3 ; b = valor de retorno Procesamiento de Lenguajes Tema 6: Generación de código (parte 2) 9 / 13
Compilación de funciones en lenguajes con recursividad En el código de la función: Direcciones de argumentos, variables locales y temporales relativas a B (@B+0, @B+1, ) Secuencia de retorno al compilar return Secuencia de retorno por defecto (por si no hay return) En la llamada: Reserva de espacio (temporales) para el RA Cálculo y carga de parámetros en RA Guardar B anterior Poner nuevo valor de B Guardar dirección de retorno y saltar Al volver, restaurar B (podría hacerse en la función) Usar el valor devuelto (es como una temporal más) Procesamiento de Lenguajes Tema 6: Generación de código (parte 2) 10 / 13 Generación de código para funciones Caso particular: lenguajes con subprogramas anidados En lenguajes como Pascal se permite declarar funciones locales a otras funciones: funcion abuelo:integer; var abu:real; function padre(a:integer;b:real):real; var pad:real; function hijo(c:real):real; begin hijo := c+pad+abu; (* return c+pad+abu *) end; function hermano(v:integer):real; var w:real; begin w := hijo(v/25); Procesamiento de Lenguajes Tema 6: Generación de código (parte 2) 11 / 13
Lenguajes con subprogramas anidados (ej Pascal) En los subprogramas (funciones o procedimientos) es posible utilizar las variables del padre, abuelo, etc Problema: dónde están esas variables? los RA del padre, abuelo, etc están situados debajo del actual, pero no se sabe exactamente dónde, y puede variar en función del código (puede ser que a un subprograma lo llame su padre o un hermano) Solución: guardar en todo momento un vector de punteros a RA de todos los niveles de anidamiento, conocido con el nombre de Display Puesto que un subprograma puede llamar a un tio (o tio abuelo), es necesario guardar el Display (todo o una parte) en el RA al hacer la llamada, y se debe restaurar al terminar la función Procesamiento de Lenguajes Tema 6: Generación de código (parte 2) 12 / 13 Registro de activación con subprogramas anidados B valor de retorno dirección de retorno Display B anterior parámetros variables locales temporales locales Procesamiento de Lenguajes Tema 6: Generación de código (parte 2) 13 / 13