Generación de código -...

72
Prácticas de Procesadores de Lenguaje 2008-2009 1 Generación de código Notación Generación de código correspondiente a la declaración de variables globales Ubicación de la acción Resultado esperado de la acción Esquema de la acción Generación de la etiqueta “main:” Contenido del fichero ensamblador antes de la traducción de la primera sentencia Control de errores en tiempo de ejecución Aclaraciones previas a la generación de código de sentencias Generación de código para las expresiones de tipo identificador Generación de código para las constantes Introducción Constantes lógicas Constantes enteras Constantes reales Índice Marina de la Cruz Alfonso Ortega Prácticas de Procesadores de Lenguaje 2008-2009 2 Generación de código Generación de código para las operaciones aritméticas Introducción Aritmética entera Aritmética real Reglas de la gramática para las operaciones aritméticas Generación de código para la operación suma con operandos enteros Generación de código para la operación suma con operandos reales Generación de código para el resto de las operaciones aritméticas binarias Generación de código para la negación de un operando entero Generación de código para la negación de un operando real Generación de código para las operaciones lógicas Introducción Generación de código para la conjunción lógica Generación de código para la disyunción lógica Generación de código para la negación lógica Índice

Transcript of Generación de código -...

Page 1: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 1

Generación de código

� Notación

� Generación de código correspondiente a la declaración de variables globales� Ubicación de la acción

� Resultado esperado de la acción

� Esquema de la acción

� Generación de la etiqueta “main:”

� Contenido del fichero ensamblador antes de la traducción de la primera sentencia

� Control de errores en tiempo de ejecución

� Aclaraciones previas a la generación de código de sentencias

� Generación de código para las expresiones de tipo identificador

� Generación de código para las constantes� Introducción

� Constantes lógicas

� Constantes enteras

� Constantes reales

Índice Marina de la CruzAlfonso Ortega

Prácticas de Procesadores de Lenguaje 2008-2009 2

Generación de código

� Generación de código para las operaciones aritméticas� Introducción

� Aritmética entera

� Aritmética real

� Reglas de la gramática para las operaciones aritméticas

� Generación de código para la operación suma con operandos enteros

� Generación de código para la operación suma con operandos reales

� Generación de código para el resto de las operaciones aritméticas binarias

� Generación de código para la negación de un operando entero

� Generación de código para la negación de un operando real

� Generación de código para las operaciones lógicas� Introducción

� Generación de código para la conjunción lógica

� Generación de código para la disyunción lógica

� Generación de código para la negación lógica

Índice

Page 2: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 3

Generación de código

� Generación de código para las comparaciones� Introducción

� Generación de código para las comparaciones de operandos enteros

� Generación de código para la comparación “==“de operandos enteros

� Generación de código para la comparación “!=“ de operandos enteros

� Generación de código para la comparación “<=“de operandos enteros

� Generación de código para la comparación “>=“de operandos enteros

� Generación de código para la comparación “<“ de operandos enteros

� Generación de código para la comparación “>“ de operandos enteros

� Generación de código para las comparaciones de operandos reales

� Generación de código para operaciones de acceso� Introducción

� Diseño de las acciones semánticas

� Generación de código para la liberación de memoria

� Generación de código para indexación de vectores� Introducción

� Vectores de una dimensión

� Vectores de dos dimensiones

Índice

Prácticas de Procesadores de Lenguaje 2008-2009 4

Generación de código

� Generación de código para operaciones de conjuntos� Representación de conjuntos

� Inserción de un elemento en un conjunto

� Vaciado de un conjunto

� Unión e intersección de conjuntos

� Tamaño de un conjunto

� Pertenencia a un conjunto

� Generación de código para sentencias de asignación� Introducción

� Asignación de una expresión a un identificador: esquema

� Asignación de una expresión a un identificador: ejemplo

� Asignación de una expresión al elemento de un vector

� Asignación de una expresión a una operación de acceso

� Reserva de memoria

� Asignación de la dirección de un identificador a otro identificador

Índice

Page 3: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 5

Generación de código

� Generación de código para entrada de datos� Introducción

� Lectura de un identificador

� Lectura de un elemento de vector

� Generación de código para salida de datos� Introducción

� Escritura de una expresión

� Escritura de una colección

� Generación de código para sentencias condicionales� Introducción

� Condicionales simples

� Condicionales compuestas

� Generación de código para sentencias iterativas� Introducción

� Sentencia WHILE

� Sentencia FOR

� Generación de código para sentencias de selección

Índice

Prácticas de Procesadores de Lenguaje 2008-2009 6

Generación de código

� Generación de código para funciones� Convenio de las llamadas

� Ejemplo

� Generación de código para las llamadas a funciones

� Generación de código inicial y final en el cuerpo de una función

� Generación de código para la localización del contenido de los parámetros

� Generación de código para la localización del contenido de las variables locales

� Generación de código para la localización de la dirección de parámetros y variables locales

� Tratamiento de identificadores

Índice

Page 4: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 7

Notación

� En este documento, la representación de las producciones de la gramática del lenguaje de programación ALFA se ajusta a la notación propia de Bison con las siguientes particularidades:

� Los símbolos no terminales se representan en minúsculas

� Los símbolos terminales se representan con TOK_ …

� Los símbolos terminales de un carácter se representan encerrados entre comillas simples

Prácticas de Procesadores de Lenguaje 2008-2009 8

Generación de código correspondiente a la declaración de variables globales

� Cuando termina la compilación de la sección de declaración de variables globales de un programa ALFA, todas las variables globales declaradas están almacenadas en la tabla de símbolos. En ese punto es posible generar el código ensamblador correspondiente a la declaración de las variables (segmento de datos) Por lo tanto, el punto adecuado para escribir el segmento de datos del fichero ensamblador es el indicado por el símbolo � en la producción del axioma:

programa: TOK_MAIN ‘{‘ declaraciones � funciones sentencias ‘}’

Se crea un nuevo no terminal y se añade una producción lambda para dicho símbolo en cuya acción semántica sea generar el código ensamblador correspondiente a la declaración de las variables . Por ejemplo:

programa: TOK_MAIN ‘{‘ declaraciones escritura1 funciones sentencias ‘}’

escritura1: {

/* Tarea adecuada */

}

� Esta acción semántica se puede “aprovechar” para escribir la cabecera del segmento de código, que es un texto fijo.

Ubicación de la acción

Page 5: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 9

Generación de código correspondiente a la declaración de variables globales

Resultado esperado de la acción

main {int x;boolean a;float ** ppe;array int [8] v8;array boolean [3 , 4] u12;set of 20 c;…

Programa ALFA

segment .bss_x resd 1_a resd 1_ppe resd 1_v8 resd 8_u12 resd 12_c resd 21

...

ProgramaNASM

Procesado de la sección declarativa

20-----CONJUNTO-variablec

4

-

-

-

-

columnas

-

-

-

-

-

capacidad

-

8

-

-

-

tamaño

variable

variable

variable

variable

variable

categoría

32-VECTORBOOLEANu12

-1-VECTORINTv8

--3PUNTEROFLOATppe

--1ESCALARBOOLEANa

--1ESCALARINTx

etcfilasdimensiónnivel de indirección

clasetipoclave

Tabla de símbolos

Reducción de la nueva regla

Prácticas de Procesadores de Lenguaje 2008-2009 10

Generación de código correspondiente a la declaración de variables globales

� Según lo visto anteriormente, la acción semántica asociada a la sección declarativa contendría:

� La escritura del segmento de datos bss.

� La escritura de la cabecera del segmento de código.

� Por razones de estructuración, se sugiere escribir una librería que contenga funciones de apoyo a la generación de código. De momento esta librería contendría:

� Una función que a partir de la tabla de símbolos escriba el segmento de datos correspondiente.

� Una función que escriba la cabecera del segmento de código, que es como sigue:

segment .text

global main

extern scan_int, scan_float, scan_boolean

extern print_int, print_float, print_boolean, print_string, print_blank, print_endofline

extern ld_float, afa_malloc, alfa_free

Esquema de la acción

PENDIENTE 1: escritura de segmento .data

Page 6: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 11

Generación de la etiqueta “main:”

� La etiqueta “main:” tiene que ser escrita en el fichero antes de la primera sentenciacorrespondiente al programa principal. Por lo tanto, el punto adecuado es el indicado por el símbolo � en la producción del axioma:

programa: TOK_MAIN ‘{‘ declaraciones escritura1 funciones � sentencias ‘}’

Se crea un nuevo no terminal y se añade una producción lambda para dicho símbolo cuya acción semántica sea escribir en el fichero ensamblador la etiqueta “main:”. Por ejemplo:

programa: TOK_MAIN ‘{‘ declaraciones escritura1 funciones escritura2 sentencias ‘}’

escritura2: {

/* Tarea adecuada */}

Prácticas de Procesadores de Lenguaje 2008-2009 12

Generación de la etiqueta “main:”

� Se puede añadir a la librería que contiene las funciones de apoyo a la generación de código una función que simplemente escriba la etiqueta “main:” en el fichero ensamblador.

� Posteriormente se estudiará en profundidad las tareas que debe realizar el generador de código en relación al no terminal “funciones”.

PENDIENTE 2: salvar registros como primera acción del programa ensamblador. Inicialización variables conjunto.

Page 7: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 13

Contenido del fichero ensamblador antes de la traducción de la primera sentencia

� Según lo visto anteriormente, el contenido del fichero ensamblador antes de la traducción de primera sentencia sería el siguiente:

segment .bss

; declaración de variables según el contenido de la tabla de símbolos

;

segment .data

; declaración de variables inicializadas

;

segment .text

global main

extern scan_int, scan_float, scan_boolean

extern print_int, print_float, print_boolean, print_string, print_blank, print_endofline

extern ld_float, afa_malloc, alfa_free

;

; código correspondiente a la compilación del no terminal “funciones”

;

main:

Prácticas de Procesadores de Lenguaje 2008-2009 14

Control de errores en tiempo de ejecución

� La gestión de errores en tiempo de ejecución requiere que en el proceso de compilación se genere el código ensamblador que comprueba dichos errores.

� El código ensamblador asociado a un control de error puede funcionar de la siguiente manera:

� comprueba la condición de error

� si se cumple la condición de error, se transfiere el flujo de ejecución a una etiqueta en la que se realizan dos acciones:

� se informa al usuario del error ocurrido

� se salta de manera incondicional al final del programa

� Para poder informar de los errores, se tienen que declarar los mensajes en el segmento .data, por ejemplo:

segment .data

mensaje_1 db “índice fuera de rango” , “0”

mensaje_2 db “Intento de inserción de un elemento en un conjunto lleno” , “0”

mensaje_3 db “División por cero” , ”0”

……….

Page 8: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 15

Control de errores en tiempo de ejecución

� En la parte final del programa se puede dedicar una zona para las etiquetas en las que se informa al usuario de un error de ejecución. La estructura de esta zona sería la siguiente:

error_1: push dword mensaje_1

call print_string

add esp, 4

jmp near fin

error_2: push dword mensaje_2

call print_string

add esp, 4

jmp near fin

…..

…..

fin: ret

NOTA: la estructura del código ensamblador podría ser diferente.

Prácticas de Procesadores de Lenguaje 2008-2009 16

Control de errores en tiempo de ejecución

� Obviamente la producción en la que se puede escribir la zona final del programa ensamblador es la regla del axioma.

Page 9: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 17

Aclaraciones previas a la generación de código de sentencias

� El compilador de ALFA genera código ensamblador para una máquina a pila.

� Cuando sea necesario apilar una variable, se apilará siempre su dirección, no su contenido (en NASM, la dirección de una variable es el nombre de la misma)

� Cuando se apile una constante, se apilará su valor.

� La generación de código implica la creación automática de etiquetas (en sentencias condicionales, bucles de control, comparaciones, etc)

Por lo tanto, es necesario un mecanismo que asegure que las etiquetas que se utilicen en el programa ensamblador son únicas.

Un posible mecanismo es usar una variable entera global (etiqueta), inicializada a un valor concreto, por ejemplo 1, y que sea incrementada cada vez que se utilice en la generación de código.

Prácticas de Procesadores de Lenguaje 2008-2009 18

Generación de código para las expresiones de tipo identificador

� La producción de la gramática correspondiente a las expresiones de tipo identificador es la siguiente:

� exp : TOK_IDENTIFICADOR

� En general, la generación de código que se realiza en esta producción consiste en apilar la dirección del identificador. Por lo tanto la evolución de la pila gráficamente sería:

� Es importante recordar que si el identificador corresponde a una variable de clase puntero, la dirección que se apila corresponde a la primera de todas las direcciones que ocupa el identificador en memoria.

ANTES DE LA REDUCCIÓN

PILA

DESPUÉS DE LA REDUCCIÓN

dirección

PILA

Page 10: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 19

Generación de código para las expresiones de tipo identificador

� El acceso a la dirección del identificador es diferente dependiendo de que el identificador sea:

� Variable global

� Variable local

� Parámetro de función

� Por lo tanto es necesario un mecanismo que permita saber si una variable es local o global.

� Además, si el identificador corresponde a un parámetro de una llamada a función, es necesario realizar las acciones específicas que permitan dejar en la pila el valor del identificador en lugar de su dirección (los parámetros se pasan por valor)

� Si el identificador corresponde a una variable global, el código que se debe generar consiste en apilar la dirección del identificador, que se corresponde con su nombre.

� Los demás casos los estudiaremos posteriormente, después de conocer la generación de código para funciones.

PENDIENTE 3: expresiones de tipo identificador que no son variables globales.

Prácticas de Procesadores de Lenguaje 2008-2009 20

Generación de código para las constantes

� El objetivo de la generación de código para las constantes es apilar el valor de la constante. Hay distintas alternativas para conseguir este objetivo.

� Estudiaremos los tres casos:� Constantes enteras

� Constantes reales

� Constantes lógicas

Introducción

Page 11: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 21

Generación de código para las constantes

� Las producciones de la gramática en las que se realiza la inserción en la pila de la constante lógica son las siguientes:

� constante_logica: TOK_TRUE

� constante_logica: TOK_FALSE

� Por ejemplo, la acción semántica de la primera producción, incorporando análisis semántico y generación de código, podría ser:

constante_logica: TOK_TRUE

{

/* análisis semántico */

$$.tipo = BOOLEAN;

$$.direcciones = 0;

/* generación de código */

fprintf(fichero_ensamblador, "; numero_linea %d\n", numero_linea);

fprintf(fichero_ensamblador, "\tpush dword 1\n");

}

Constantes lógicas

Prácticas de Procesadores de Lenguaje 2008-2009 22

Generación de código para las constantes

� La gestión de las constantes enteras tiene la siguiente particularidad: la reducción del no terminal “constante_entera” requiere un tratamiento diferente dependiendo de si aparece en una sección declarativa o si lo hace en una sección de sentencias.

� Las producciones correspondientes a una sección declarativa son las siguientes:

� clase_vector: TOK_ARRAY tipo ‘[‘ constante_entera ‘]’

� clase_vector: TOK_ARRAY tipo ‘[‘ constante_entera ‘,’ constante_entera ‘]’

� clase_conjunto: TOK_SET TOK_OF constante_entera

� Y las producciones relativas a sentencias son:

� caso_estandar: TOK_CASE constante_entera ‘:’ sentencias

� constante: constante_entera

Constantes enteras

Page 12: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 23

Generación de código para las constantes

� En la sección de sentencias, la aparición del no terminal “constante_entera” implica la generación de código para apilar el valor de la constante.

� En la sección declarativa, la aparición del no terminal “constante_entera”no requiere generación de código. Lo que requiere es acceder al valor de la constante, que se supone que está guardado en uno de sus atributos.

� Para poder realizar un tratamiento correcto de las constantes enteras dependiendo de la sección en la que aparezcan, es necesario diseñar un mecanismo que lo permita. Hay múltiples alternativas, una de ellas es utilizar una variable global.

Constantes enteras

Prácticas de Procesadores de Lenguaje 2008-2009 24

Generación de código para las constantes

� La acción semántica asociada a la reducción del no terminal “constante_entera” podría ser la siguiente:

constante_entera: TOK_CONSTANTE_ENTERA

{

/* análisis semántico */

$$.tipo = INT;

$$.direcciones = 0;

$$.valor_entero = $1.valor_entero;

/* generación de código */

if (! en_declaraciones)

{

fprintf(fichero_ensamblador, "; numero_linea %d\n", numero_linea);

fprintf(fichero_ensamblador, "\tpush dword %d\n", $1.valor_entero);

}

}

Constantes enteras

Variable para controlar si la reducción de la regla ocurre en una sección de declaraciones o en una de sentencias.

Esta propagación permite acceder al valor de la constante entera en las producciones de las secciones declarativas en las que aparece el no terminal constante_entera.

Page 13: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 25

Generación de código para las constantes

� La gestión de las constantes reales requiere un tratamiento especial debido a que en NASM sólo pueden aparecer constantes reales en el segmento de datos, y por lo tanto, no es posible apilar directamente el valor de la constante real, es decir, no pueden aparecer instrucciones del tipo “push dword 1.35”

� Para conseguir dejar en la pila el valor de la constante real en la pila, es necesario articular un mecanismo. El que se propone en este curso es el siguiente:

� El analizador morfológico, cuando encuentra en la entrada una constante real, propaga su lexema.

� En el analizador sintáctico, cuando reduce la producción:

constante_real: TOK_CONSTANTE_REAL

se realizan las siguientes tareas:� Extraer del lexema de la constante real un numerador entero y un denominador entero tales que su

división genere el valor de la constante entera. Por ejemplo, si la constante es 12.45, el numerador sería 1245, y el denominador 100.

� Generar código para apilar el valor del numerador.� Generar código para apilar el valor del denominador.� Generar código para invocar a la función de librería “ld_float”.� Generar código para restaurar el puntero de pila.� Generar código para apilar el contenido del registro eax (la función “ld_float” deposita en eax el

resultado de dividir numerador entre denominador, es decir, el valor de la constante real)

Constantes reales

Prácticas de Procesadores de Lenguaje 2008-2009 26

Generación de código para las constantes

� Por lo tanto, la acción semántica asociada a la reducción del no terminal “constante_real” es:

constante_real: TOK_CONSTANTE_REAL

{

/* análisis semántico */

$$.tipo = FLOAT;

$$.direcciones = 0;

/* generación de código */

numerador_constante_real = obtener_numerador($1.lexema);

denominador_constante_real = obtener_denominador($1.lexema);

fprintf(fichero_ensamblador, "\tpush dword %d\n", numerador_constante_real);

fprintf(fichero_ensamblador, "\tpush dword %d\n", denominador_constante_real);

fprintf(fichero_ensamblador, "\tcall ld_float\n");

fprintf(fichero_ensamblador, "\tadd esp, 8\n");

fprintf(fichero_ensamblador, "\tpush eax\n");

}

Constantes reales

Obtener el numerador

Obtener el denominador

Apilar el denominador

Apilar el numerador

Invocar a la función “ld_float”

Restaurar la pila

Apilar eax que contiene el valor de la constante real

Page 14: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 27

Generación de código para las operaciones aritméticas

� Las operaciones aritméticas en NASM utilizan distintos registros y distintos códigos de operación dependiendo del tipo de los operandos.

� Para el estudio de la generación de código correspondiente a las operaciones aritméticas distinguiremos dos casos:

� Aritmética entera: los dos operandos son de tipo entero.

� Aritmética real: los dos operandos son de tipo real, o uno de ellos es de tipo real y el otro de tipo entero.

� Es muy importante no olvidar que, independientemente del tipo de los operandos, la secuencia para la ejecución de una operación aritmética es la siguiente:

� Antes de realizar cualquier operación aritmética, los operandos están en la pila.

� Se extraen los operandos de la pila a los registros adecuados al tipo de los operandos.

� Se realiza la operación aritmética con el código de operación adecuado al tipo de los operandos.

� Se deposita en la pila el resultado de la operación.

Introducción

Prácticas de Procesadores de Lenguaje 2008-2009 28

Generación de código para las operaciones aritméticas

� Los registros que se utilizan para aritmética entera, son los de propósito general: eax, edx, etc.

� Los códigos de operación son, entre otros: add, imul, sub, etc. Y se detallarán más adelante.

Aritmética entera

Page 15: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 29

Generación de código para las operaciones aritméticas

� Los registros que se utilizan para aritmética real, son los registros de coma flotante st0, st1, etc. Estos registros se comportan como una pila, siendo st0 la cima de la misma.

� Para realizar cualquier operación de números reales es necesario cargar los operandos en los registros de coma flotante. La carga de estos registros se realiza siempre desde memoria con las siguientes instrucciones NASM.

� fld dword <fuente>Carga en la cima de la pila de reales (st0) un número real de 32 bits almacenado en memoria.

� fild dword <fuente>Lee un número entero de 32 bits almacenado en memoria, lo convierte a real, y lo carga en la cima de la pila de reales (st0)

� Como la carga de los registros de coma flotante se realiza siempre desde memoria, y los operandos siempre están en la pila, entonces, el código correspondiente a operaciones aritméticas con números reales obligatoriamente tendrá que utilizar una memoria intermedia a la que se mueven los operandos desde la pila, y desde la que se cargan los registros de coma flotante.

Aritmética real

Prácticas de Procesadores de Lenguaje 2008-2009 30

Generación de código para las operaciones aritméticas

� Una vez que los operandos están cargados en los registros de coma flotante, los códigos de operación son, entre otros: fadd, fmul, fsub, etc. Y se detallarán más adelante.En general, el resultado de la operación se almacena también en un registro de coma flotante.

� Una vez que se tiene el resultado de la operación en un registro de coma flotante, es necesario apilarlo como refutado de la operación. Para ello, es obligatorio pasar por memoria, ya que no es posible apilar directamente el valor de un registro real.

� La siguiente instrucción carga en memoria el número real que está en la cima de la pila de reales (st0)

fst dword <destino>

� Una vez que el resultado de la suma está en memoria, ya se puede apilar directamente.

� Por último, para resetear la pila de reales después de su uso, se puede utilizar el código de operación finit.

Aritmética real

Page 16: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 31

Generación de código para las operaciones aritméticas

� Como resumen podríamos decir que en aritmética real es obligatorio pasar los operandos por memoria para así poder cargar los registros de coma flotante. De la misma manera, para apilar el resultado de la operación se necesita primero pasar por memoria ese resultado desde los registros de coma flotante.

Aritmética real

exp2

exp1

ANTES DE LA OPERACIÓN

PILA

exp2

exp1

MEMORIA

exp2

exp1

REGISTROS COMA FLOTANTE

DESPUÉS DE LA OPERACIÓN

exp1+exp2

PILA

exp1 + exp2

MEMORIA

exp1 + exp2

REGISTROS COMA FLOTANTE

Apilar el resultadoen la pila�

Mover los operandosa memoria �

Cargar los registrosde coma flotante �

Realizaroperación

Mover el resultadoa memoria�

mov fild

fld

fst

fadd

fmul

......

push

Prácticas de Procesadores de Lenguaje 2008-2009 32

Generación de código para las operaciones aritméticas

� La necesidad de pasar los operandos por memoria requiere la declaración de esas posiciones de memoria, es decir, la declaración de las variables que se consideren necesarias.

� Se declararán en el segmento .data las siguientes variables:

� __auxint: esta variable se utiliza como memoria intermedia para almacenar valores de tipo entero antes de cargar dichos valores en los registros de coma flotante. (Obsérvese que el nombre de la variable comienza por 2 guiones bajos)

� __auxfloat: esta variable se utiliza como memoria intermedia para almacenar valores de tipo real antes de cargar dichos valores en los registros de coma flotante. (Obsérvese que el nombre de la variable comienza por 2 guiones bajos)

� La escritura de este segmento se puede realizar inmediatamente después de la escritura del segmento bss y antes de la escritura de la cabecera del segmento de código (ver PENDIENTE en transparencia 7)

Aritmética real

Page 17: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 33

Generación de código para las operaciones aritméticas

� Las reglas de la gramática relativas a las operaciones aritméticas son:� exp : exp ‘+’ exp

� exp : exp ‘-’ exp

� exp : exp ‘/’ exp

� exp : exp ‘*’ exp

� exp : ‘-’ exp

� La generación de código de todas las reglas anteriores comparten la misma estructura básica consistente en distinguir dos casos y generar código adecuado a cada uno de ellos:

� Caso 1: los dos operandos son de tipo entero.

� Caso 2: al menos alguno de los operandos es de tipo real.

Reglas de la gramática para las operaciones aritméticas

Prácticas de Procesadores de Lenguaje 2008-2009 34

Generación de código para las operaciones aritméticas

Generación de código para la operación suma con operandos enteros

GENERACIÓN DE CÓDIGO

; cargar el segundo operando en edxpop dword edxSI $3.direcciones>0mov dword edx , [edx]

; cargar el primer operando en eaxpop dword eaxSI $1.direcciones>0mov dword eax , [eax]

; realizar la suma y dejar el resultado en eaxadd eax, edx

; apilar el resultadopush dword eax

exp : exp1 ‘+’ exp2

EVOLUCIÓN DE LA PILA

exp2

exp1

ANTES DE LA REDUCCIÓN

PILA

DESPUÉS DE LA REDUCCIÓN

exp1+exp2

PILA

Page 18: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 35

Generación de código para las operaciones aritméticas

� La generación de código se puede ubicar directamente en la acción semántica de la regla, o bien programando una función. Para la suma de expresiones de tipo entero, la función tendría el siguiente aspecto:

void gc_suma_enteros(FILE* f, ni_op1, ni_op2)

{

fprintf(f, “; cargar el segundo operando en edx\n”);

fprintf(f, “pop dword edx\n”);

if (ni_op2 > 0)

fprintf(f, “mov dword edx , [edx]\n”);

fprintf(f, “; cargar el primer operando en eax\n”);

fprintf(f,”pop dword eax\n”);

if (ni_op1 > 0)

fprintf(f, “mov dword eax , [eax]\n”);

fprintf(f, “; realizar la suma y dejar el resultado en eax \n”);

fprintf(f, “add eax,edx\n);

fprintf(f, “; apilar el resultado\n”);

fprintf(f, “push dword eax\n”);

return;

}

Generación de código para la operación suma con operandos enteros

Prácticas de Procesadores de Lenguaje 2008-2009 36

Generación de código para las operaciones aritméticas

Generación de código para la operación suma con operandos reales

; cargar el segundo operando en edxpop dword edxSI $3.direcciones>0mov edx , [edx]

; cargar el segundo operando en st0SI $3.tipo == INTmov dword [__auxint] , edxfild dword [__auxint]

SI NOmov dword [__auxfloat] , edxfld dword [__auxfloat]

; cargar el primer operando en eaxpop dword eaxSI $1.direcciones>0mov eax , [eax]

; cargar el primer operando en st0SI $1.tipo == INTmov dword [__auxint] , eaxfild dword [__auxint]

SI NOmov dword [__auxfloat] , eaxfld dword [__auxfloat]

; realizar la sumafadd st1 ; st0 = st0 + st1

; mover el resultado a memoria

fst dword [__auxfloat]

; apilar el resultadopush dword [__auxfloat]

; limpiar los registros de coma flotantefinit

; cargar el segundo operando en edxpop dword edxSI $3.direcciones>0mov dword edx , [edx]

; cargar el segundo operando en st0SI $3.tipo == INTmov dword [__auxint] , edxfild dword [__auxint]

SI NOmov dword [__auxfloat] , edxfld dword [__auxfloat]

; cargar el primer operando en eaxpop dword eaxSI $1.direcciones>0mov dword eax , [eax]

; cargar el primer operando en st0SI $1.tipo == INTmov dword [__auxint] , eaxfild dword [__auxint]

SI NOmov dword [__auxfloat] , eaxfld dword [__auxfloat]

; realizar la sumafadd st1 ; st0 = st0 + st1

; mover el resultado a memoria

fst dword [__auxfloat]

; apilar el resultadopush dword [__auxfloat]

; limpiar los registros de coma flotantefinit

Page 19: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 37

Generación de código para las operaciones aritméticas

� Las producciones correspondientes al resto de las operaciones aritméticas binarias son las siguientes:

� exp : exp ‘-’ exp

� exp : exp ‘/’ exp

� exp : exp ‘*’ exp

� El código ensamblador correspondiente a las producciones anteriores es similar al de la regla de la suma visto anteriormente. La única diferencia es la instrucción ensamblador que se utilice y las posibles peculiaridades de la misma.

� Para la resta de operandos de tipo entero se puede utilizar la instrucción ensamblador siguiente:

sub eax,edx

que resta al contenido del registro eax el contenido del registro edx y deja el resultado en eax.

Generación de código para el resto de las operaciones aritméticas binarias

Prácticas de Procesadores de Lenguaje 2008-2009 38

Generación de código para las operaciones aritméticas

� Para la resta de operandos de tipo real se puede utilizar la instrucción ensamblador siguiente:

fsub <registro real>

que resta al contenido del registro real st0 el contenido del registro <registro real> y deja el resultado en st0.

Generación de código para el resto de las operaciones aritméticas binarias

Page 20: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 39

Generación de código para las operaciones aritméticas

� Para la división de operandos de tipo entero se puede utilizar la instrucción ensamblador de división entera idiv. Esta instrucción trabaja de la siguiente manera:

� Asume que el dividendo está en la composición de registros edx:eax

� El divisor es el registro que aparece en la instrucción.� El resultado de la división entera se ubica en el registro eax

� Para que el dividendo esté en la composición de registros edx:eax y realizar correctamente la división se tiene que hacer:

� Cargar el divisor en ecx

� Cargar el dividendo en eax

� Extender el dividendo a la composición de registros edx:eax (cdq)

� Realizar la división (idiv ecx)

� Se debe controlar la división por cero según se explicó en el apartado “Control de errores en tiempo de ejecución”

Generación de código para el resto de las operaciones aritméticas binarias

Prácticas de Procesadores de Lenguaje 2008-2009 40

Generación de código para las operaciones aritméticas

� Para la división de operandos de tipo real se puede utilizar la instrucción ensamblador siguiente:

fdiv <registro real>

que divide el contenido del registro real st0 entre el contenido del registro <registro real> y deja el resultado en st0.

� Se debe controlar la división por cero según se explicó en el apartado “Control de errores en tiempo de ejecución”

Generación de código para el resto de las operaciones aritméticas binarias

Page 21: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 41

Generación de código para las operaciones aritméticas

� Para el producto de operandos de tipo entero se puede utilizar la instrucción ensamblador de multiplicación entera imul. Esta instrucción asume que uno de los operandos está en el registro eax, y el otro operando está en el registro que aparece en la instrucción. El resultado se carga en edx:eax, y consideraremos el valor de eaxcomo resultado de la operación.

� Para el producto de operandos de tipo real se puede utilizar la instrucción ensamblador siguiente:

fmul <registro real>

que multiplica el contenido del registro real st0 por el contenido del registro <registro real> y deja el resultado en st0.

Generación de código para el resto de las operaciones aritméticas binarias

Prácticas de Procesadores de Lenguaje 2008-2009 42

Generación de código para las operaciones aritméticas

Generación de código para la negación de un operando entero

GENERACIÓN DE CÓDIGO

; cargar el operando en eaxpop dword eaxSI $2.direcciones>0mov dword eax , [eax]

; realizar la negación. El resultado en eaxneg eax

; apilar el resultadopush dword eax

exp : ‘-’ exp1

EVOLUCIÓN DE LA PILA

ANTES DE LA REDUCCIÓN

exp1

PILA

DESPUÉS DE LA REDUCCIÓN

-exp1

PILA

Page 22: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 43

Generación de código para las operaciones aritméticas

� La negación de un operando de tipo real se puede implementar haciendo uso de la instrucción NASM siguiente:

fchs

que niega el contenido del registro real st0 y deja el resultado también en st0.

Generación de código para la negación de un operando real

Prácticas de Procesadores de Lenguaje 2008-2009 44

Generación de código para las operaciones lógicas

� Las producciones de la gramática correspondientes a las operaciones lógicas son las siguientes:

� exp : exp TOK_AND exp

� exp : exp TOK_OR exp

� exp : ‘!’ exp

� De la misma manera que en las operaciones aritméticas, cuando se reduce una de las anteriores producciones los operandos están en la pila porque han sido reducidos previamente por alguna de las producciones del no terminal “exp”.

� El código ensamblador correspondiente a operaciones lógicas usa la pila con la siguiente secuencia de acciones:

� Desapilar los operandos.

� Realizar la operación lógica correspondiente.

� Apilar el resultado de la operación.

Introducción

Page 23: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 45

Generación de código para las operaciones lógicas

Generación de código para la conjunción lógica

GENERACIÓN DE CÓDIGO

; cargar el segundo operando en edxpop dword edxSI $3.direcciones>0mov dword edx , [edx]

; cargar el primer operando en eaxpop dword eaxSI $1.direcciones>0mov dword eax , [eax]

; realizar la conjunción y dejar el resultado en eaxand eax , edx

; apilar el resultadopush dword eax

exp : exp1 TOK_AND exp2

EVOLUCIÓN DE LA PILA

exp2

exp1

ANTES DE LA REDUCCIÓN

PILA

DESPUÉS DE LA REDUCCIÓN

exp1 Y exp2

PILA

Prácticas de Procesadores de Lenguaje 2008-2009 46

Generación de código para las operaciones lógicas

Generación de código para la disyunción lógica

GENERACIÓN DE CÓDIGO

; cargar el segundo operando en edxpop dword edxSI $3.direcciones>0mov dword edx , [edx]

; cargar el primer operando en eaxpop dword eaxSI $1.direcciones>0mov dword eax , [eax]

; realizar la conjunción y dejar el resultado en eaxor eax , edx

; apilar el resultadopush dword eax

exp : exp1 TOK_OR exp2

EVOLUCIÓN DE LA PILA

exp2

exp1

ANTES DE LA REDUCCIÓN

PILA

DESPUÉS DE LA REDUCCIÓN

exp1 O exp2

PILA

Page 24: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 47

Generación de código para las operaciones lógicas

Generación de código para la negación lógica

GENERACIÓN DE CÓDIGO

; cargar el operando en eaxpop dword eaxSI $2.direcciones>0mov dword eax , [eax]

; ver si eax es 0 y en ese caso saltar a negar_falsoor eax , eaxjz near negar_falso#

; cargar 0 en eax (negación de verdadero) y saltar al finalmov dword eax,0jmp near fin_negacion#

; cargar 1 en eax (negación de falso)negar_falso#: mov dword eax,1

; apilar eaxfin_negacion#: push dword eax

exp : ‘!’ exp1

EVOLUCIÓN DE LA PILA

ANTES DE LA REDUCCIÓN

exp1

PILA

DESPUÉS DE LA REDUCCIÓN

NO exp1

PILA

UNICIDAD DE ETIQUETAS

etiqueta ++

Prácticas de Procesadores de Lenguaje 2008-2009 48

Generación de código para las comparaciones

� De la misma manera que en las expresiones aritméticas, en la generación de código ensamblador para las comparaciones se distinguirán dos casos generales:

� Comparaciones con los dos operandos de tipo entero.

� Comparaciones en las que los dos operandos son de tipo real, o uno de ellos es de tipo real y el otro de tipo entero.

� Independientemente del tipo de los operandos, la secuencia para la ejecución de la comparación es la siguiente:

� Los operandos de la comparación están en la pila.

� Se extraen los operandos de la pila a los registros adecuados al tipo de los operandos.

� Se realiza la comparación con el código de operación adecuado al tipo de los operandos.

� Se deposita en la pila el resultado de la comparación (1 si ha terminado con éxito y 0 en el caso contrario)

Introducción

Page 25: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 49

Generación de código para las comparaciones

� Las producciones de la gramática correspondientes a las comparaciones son las siguientes:

� comparacion: exp TOK_IGUAL exp

� comparacion: exp TOK_DISTINTO exp

� comparacion: exp TOK_MENORIGUAL exp

� comparacion: exp TOK_MAYORIGUAL exp

� comparacion: exp ‘<‘ exp

� comparacion: exp ‘>’ exp

Introducción

Prácticas de Procesadores de Lenguaje 2008-2009 50

Generación de código para las comparaciones

� En general, la implementación en ensamblador de una comparación de operandos de tipo entero se hará de la siguiente manera:

� Suponiendo que los operandos están en los registros eax y edx

� Se utiliza la instrucción:

cmp eax , edx

� Dependiendo del resultado de la comparación se redirige el flujo de ejecución mediante saltos condicionales. Las instrucciones de salto disponibles, para comparaciones de enteros con signo) son las siguientes:

je salta si eax == edx (también jz)

jne salta si eax != edx (también jnz)

jle salta si eax <= edx (también jng)

jge salta si eax >= edx (también jnl)

jl salta si eax < edx (también jnge)

jg salta si eax > edx (también jnle)

� En los destinos de los saltos se procederá a apilar un 0 o un 1 dependiendo del éxito de la comparación.

Generación de código para las comparaciones de operandos enteros

Page 26: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 51

Generación de código para las comparaciones

Generación de código para la comparación “==“ de operandos enteros

GENERACIÓN DE CÓDIGO

; cargar la segunda expresión en edxpop dword edxSI $3.direcciones>0mov dword edx , [edx]

; cargar la primera expresión en eaxpop dword eaxSI $1.direcciones>0mov dword eax , [eax]

; comparar y apilar el resultadocmp eax, edxje near igual#push dword 0jmp near fin_igual#

igual#: push dword 1fin_igual#:

comparacion : exp1 TOK_IGUALexp2

EVOLUCIÓN DE LA PILA

UNICIDAD DE ETIQUETAS

etiqueta ++

exp2

exp1

ANTES DE LA REDUCCIÓN

PILA

DESPUÉS DE LA REDUCCIÓN

0 ó 1

PILA

Prácticas de Procesadores de Lenguaje 2008-2009 52

Generación de código para las comparaciones

Generación de código para la comparación “!=“de operandos enteros

GENERACIÓN DE CÓDIGO

; cargar la segunda expresión en edxpop dword edxSI $3.direcciones>0mov dword edx , [edx]

; cargar la primera expresión en eaxpop dword eaxSI $1.direcciones>0mov dword eax , [eax]

; comparar y apilar el resultadocmp eax, edxjne near distinto#push dword 0jmp near fin_distinto#

distinto#: push dword 1fin_igual#:

comparacion : exp1 TOK_DISTINTOexp2

EVOLUCIÓN DE LA PILA

UNICIDAD DE ETIQUETAS

etiqueta ++

exp2

exp1

ANTES DE LA REDUCCIÓN

PILA

DESPUÉS DE LA REDUCCIÓN

0 ó 1

PILA

Page 27: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 53

Generación de código para las comparaciones

Generación de código para la comparación “<=“de operandos enteros

GENERACIÓN DE CÓDIGO

; cargar la segunda expresión en edxpop dword edxSI $3.direcciones>0mov dword edx , [edx]

; cargar la primera expresión en eaxpop dword eaxSI $1.direcciones>0mov dword eax , [eax]

; comparar y apilar el resultadocmp eax, edxjle near menorigual#push dword 0jmp near fin_menorigual#

menorigual#: push dword 1fin_menorigual#:

comparacion : exp1 TOK_MENORIGUALexp2

EVOLUCIÓN DE LA PILA

UNICIDAD DE ETIQUETAS

etiqueta ++

exp2

exp1

ANTES DE LA REDUCCIÓN

PILA

DESPUÉS DE LA REDUCCIÓN

0 ó 1

PILA

Prácticas de Procesadores de Lenguaje 2008-2009 54

Generación de código para las comparaciones

Generación de código para la comparación “>=“de operandos enteros

GENERACIÓN DE CÓDIGO

; cargar la segunda expresión en edxpop dword edxSI $3.direcciones>0mov dword edx , [edx]

; cargar la primera expresión en eaxpop dword eaxSI $1.direcciones>0mov dword eax , [eax]

; comparar y apilar el resultadocmp eax, edxjge near mayorigual#push dword 0jmp near fin_mayorigual#

mayorigual#: push dword 1fin_mayorigual#:

comparacion : exp1 TOK_MAYORIGUALexp2

EVOLUCIÓN DE LA PILA

UNICIDAD DE ETIQUETAS

etiqueta ++

exp2

exp1

ANTES DE LA REDUCCIÓN

PILA

DESPUÉS DE LA REDUCCIÓN

0 ó 1

PILA

Page 28: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 55

Generación de código para las comparaciones

Generación de código para la comparación “<“de operandos enteros

GENERACIÓN DE CÓDIGO

; cargar la segunda expresión en edxpop dword edxSI $3.direcciones>0mov dword edx , [edx]

; cargar la primera expresión en eaxpop dword eaxSI $1.direcciones>0mov dword eax , [eax]

; comparar y apilar el resultadocmp eax, edxjl near menor#push dword 0jmp near fin_menor#

menor#: push dword 1fin_menor#:

comparacion : exp1 ‘<‘exp2

EVOLUCIÓN DE LA PILA

UNICIDAD DE ETIQUETAS

etiqueta ++

exp2

exp1

ANTES DE LA REDUCCIÓN

PILA

DESPUÉS DE LA REDUCCIÓN

0 ó 1

PILA

Prácticas de Procesadores de Lenguaje 2008-2009 56

Generación de código para las comparaciones

Generación de código para la comparación “>“de operandos enteros

GENERACIÓN DE CÓDIGO

; cargar la segunda expresión en edxpop dword edxSI $3.direcciones>0mov dword edx , [edx]

; cargar la primera expresión en eaxpop dword eaxSI $1.direcciones>0mov dword eax , [eax]

; comparar y apilar el resultadocmp eax, edxjg near mayor#push dword 0jmp near fin_mayor#

mayor#: push dword 1fin_mayor#:

comparacion : exp1 ‘>‘exp2

EVOLUCIÓN DE LA PILA

UNICIDAD DE ETIQUETAS

etiqueta ++

exp2

exp1

ANTES DE LA REDUCCIÓN

PILA

DESPUÉS DE LA REDUCCIÓN

0 ó 1

PILA

Page 29: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 57

Generación de código para las comparaciones

� Las comparaciones de operandos reales requieren que los operandos estén cargados en los registros reales, de la misma manera que se estudió para las operaciones aritméticas con números reales.

� La carga de los operandos en los registros reales se hace utilizando posiciones de memoria auxiliares como se explicó en las operaciones aritméticas con operandos reales.

� La comparación se hará de la siguiente manera:� Suponiendo que los operandos están ya cargados en los registros st0 y st1

� Se utiliza la instrucción:

fcomp st1 (compara st0 con st1)

La instrucción fcomp no modifica directamente el registro de flags sino que modifica algunos bits del registro de estado del coprocesador. Como los saltos condicionales utilizan el registro de flags, es necesario realizar una transferencia entre ambos registros. Para ello se pueden utilizar las siguientes instrucciones:

fstsw ax carga el registro de estado del coprocesador en ax

sahf carga el registro ah en el registro de flags

Generación de código para las comparaciones de operandos reales

Prácticas de Procesadores de Lenguaje 2008-2009 58

Generación de código para las comparaciones

� Una vez realizada la comparación y actualizado el registro de flags, se pueden utilizar las siguientes instrucciones de salto condicional:

je salta si eax == edx (también jz)

jne salta si eax != edx (también jnz)

jbe salta si eax <= edx (también jna)

jae salta si eax >= edx (también jnb)

jb salta si eax < edx (también jnae)

ja salta si eax > edx (también jnbe)

� En los destinos de los saltos se procederá a apilar un 0 o un 1 dependiendo del éxito de la comparación.

� Por último, se procede a resetear la pila de reales con la instrucción finit.

Generación de código para las comparaciones de operandos reales

Page 30: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 59

Generación de código para operaciones de acceso

� Una operación de acceso significa acceder a una dirección de memoria “apuntada”.

� En términos de generación de código, “acceder” a una dirección de memoria significa apilar dicha dirección.

� El operador de acceso de ALFA es “*”.

� Sólo es correcto aplicar el operador “*” a variables que tengan un nivel de indirección superior a 1.

� El usuario de ALFA es el responsable de realizar la reserva de memoria para las variables declaradas con nivel de indirección mayor que 1, utilizando la palabra reservada malloc.

� El compilador de ALFA no tiene que controlar los casos en los que se declare una variable con nivel de indirección mayor que 1 y se le aplique el operador de acceso sin haber reservado previamente la memoria.

Introducción

4

pe dir

dir

MEMORIA

main{

int * pe;

pe = malloc;*pe = 4;

El código ensamblador para la operación de acceso *pe sería:push dword [_pe]

Prácticas de Procesadores de Lenguaje 2008-2009 60

Generación de código para operaciones de acceso

� Ya que el objetivo en términos de generación de código es apilar la dirección de memoria a la que se realiza el acceso, en esta producción, la dirección que se apila es la que está almacenada en la dirección de memoria que ocupa la variable representada por TOK_IDENTIFICADOR. Por lo tanto la instrucción NASM sería:

push dword [_$2.lexema]

Diseño de las acciones semánticas

acceso: ‘*’ TOK_IDENTIFICADOR

_$2.lexema dir

dir

MEMORIA

ANTES DE LA REDUCCIÓN

PILA

DESPUÉS DE LA REDUCCIÓN

dir

PILA

Page 31: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 61

Generación de código para operaciones de acceso

� En la producción relativa a la definición recursiva de la operación de acceso, hay que tener en cuenta que en la cima de la pila se encuentra la dirección correspondiente a la reducción del no terminal acceso2. Por lo tanto la generación de código sería:

pop dword eaxpush dword [eax]

Diseño de las acciones semánticas

acceso: ‘*’ accesod

Prácticas de Procesadores de Lenguaje 2008-2009 62

Generación de código para la liberación de memoria

� La generación de código correspondiente a la liberación de memoria requiere la invocación de la función alfa_free de la librería alfalib de la siguiente manera:

� Apilar la dirección de memoria que se quiere liberar, es decir, apilar el contenido de la variable representada por TOK_IDENTIFICADOR.

push dword [_$2.lexema]

� Invocar a la función.

call alfa_free

� Restaurar el puntero de pila.

add esp, 4

liberacion: TOK_FREE TOK_IDENTIFICADOR

Page 32: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 63

Generación de código para indexación de vectores

� Hay dos producciones de la gramática relativas a la operación de indexación de vectores, una para vectores de una dimensión y otra para vectores de dos dimensiones:

� elemento_vector: TOK_IDENTIFICADOR ‘[‘ exp ‘]’

� elemento_vector: TOK_IDENTIFICADOR ‘[‘ exp ‘,’ exp ‘]’

� Los objetivos básicos de la generación de código de las producciones anteriores son:� Generar código para comprobar, en tiempo de ejecución, que los índices están dentro de

los rangos permitidos según el tamaño del vector según se explicó en el apartado “Control de errores en tiempo de ejecución”

� Generar código para dejar en la cima de la pila la dirección del elemento indexado.

Introducción

Prácticas de Procesadores de Lenguaje 2008-2009 64

Generación de código para indexación de vectores

Vectores de una dimensión

GENERACIÓN DE CÓDIGO

; Carga del valor del índice en eaxpop dword eaxSI ($3.direcciones>0)mov dword eax , [eax]

; Si el índice es menor que 0, error en tiempo de ejecucióncmp eax,0jl near mensaje_1; Si el índice es mayor de lo permitido , error en tiempo de ejecucióncmp eax, <tamaño del vector –1>jl near mensaje_1

; EN ESTE PUNTO EL ÍNDICE ES CORRECTO...

elemento_vector: TOK_IDENTIFICADOR ‘[’ exp ‘]’

EVOLUCIÓN DE LA PILA

ANTES DE LA REDUCCIÓN

exp

PILA

PUNTO INTERMEDIOEN LA REDUCCIÓN

PILA

� El primer paso consiste en comprobar que el índice está dentro del límite permitido, es decir, entre 0 y el tamaño del vector menos 1 (ambos inclusive)

Page 33: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 65

Generación de código para indexación de vectores

� El código correspondiente a la etiqueta mensaje_1 sería:

mensaje_1:

push dword mensaje_1

call print_string

add esp, 4

jmp near fin

� La etiqueta fin está situada al final del programa, justo antes de la última instrucción ret.

Vectores de una dimensión

Prácticas de Procesadores de Lenguaje 2008-2009 66

Generación de código para indexación de vectores

� El segundo paso consiste en generar código para dejar en la cima de la pila la dirección del elemento indexado. Para ello hay que tener en cuenta las siguientes consideraciones:

� En el segmento de datos .bss se reserva un bloque de memoria para almacenar todos los elementos del vector, y por lo tanto es necesario definir la disposición de dichos elementos dentro del bloque. Lo más razonable es ubicar los elementos por orden creciente de índice, es decir, primero el elemento 0, después el 1, y así sucesivamente hasta el elemento (tamaño-1).

� Una vez que se ha elegido una disposición concreta, las operaciones de indexado deben de ser coherentes con la elección.

� Cada elemento ocupa 4 bytes (porque así se ha hecho la reserva de memoria)

� La dirección de inicio del vector es accesible mediante el nombre del vector.

� Si se ubican los elementos por orden creciente de índice, la dirección del elemento [i] sería la siguiente:

dirección elemento [i] = dirección_inicio_vector + i*4

Vectores de una dimensión

Page 34: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 67

Generación de código para indexación de vectores

� Por ejemplo, la siguiente declaración de un vector de 5 posiciones en un programa ALFA:

array int [5] v;

se traduce en la declaración ensamblador siguiente:

_v resd 5

que reserva en memoria un bloque contiguo de 20 bytes, que se puede interpretar como 5 posiciones de 4 bytes cada una de ellas. Y si se considera que los elementos del vector se disponen dentro del bloque por orden creciente de índice, la memoria tendría el siguiente contenido:

Vectores de una dimensión

v[0]_v

MEMORIA

v[1]_v +4

v[2]

v[3]

_v +8

_v +12

v[4]_v +16

Prácticas de Procesadores de Lenguaje 2008-2009 68

Generación de código para indexación de vectores

Vectores de una dimensión

GENERACIÓN DE CÓDIGO

OPCIÓN 1 OPCIÓN 2

; Cargar en edx la dirección de inicio del vector ; Cargar 4 en edx (nº de bytes de cada elemento del vector)mov dword edx _$1.lexema mov dword edx, 4; Cargar en eax la dirección del elemento indexado ; eax = eax*edx, es decir, eax = eax*4lea eax, [edx + eax*4] imul edx; Apilar la dirección del elemento indexado ; Cargar en edx la dirección de inicio del vectorpush dword eax mov dword edx _$1.lexema

; Cargar en eax la dirección del elemento indexadoadd eax, edx; Apilar la dirección del elemento indexadopush dword eax

EVOLUCIÓN DE LA PILA

PUNTO INTERMEDIOEN LA REDUCCIÓN

PILA

DESPUÉS DE LA REDUCCIÓN

dirección

PILAEl registro eax contiene el valor del índice como consecuencia de la comprobación de la

validez del valor del índice.

Page 35: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 69

Generación de código para indexación de vectores

Vectores de dos dimensiones

elemento_vector: TOK_IDENTIFICADOR ‘[’ exp1 ‘,’ exp2 ‘]’

� La generación de código para la indexación de vectores de dos dimensiones es similar a la correspondiente a vectores de una dimensión.

� En primer lugar se genera código para comprobar que los índices están dentro de los rangos permitidos. En el caso de vectores de una dimensión sólo es necesario comprobar la validez de un índice mientras que si el vector es de dos dimensiones, la comprobación se extiende a los dos índices.

� La idea básica del segundo paso, generación de código para dejar en la cima de la pila la dirección del elemento indexado, es la siguiente: en el segmento de datos .bssse reserva un bloque de memoria para almacenar todos los elementos del vector, y por lo tanto es necesario definir la disposición de dichos elementos dentro del bloque para que las operaciones de indexación sean correctas. Las dos disposiciones más generales son:

� Disposición por filas: en el bloque se sitúan primero los elementos de la primera fila, después los de la segunda, y así sucesivamente.

� Disposición por columnas: dentro del bloque, se almacenan en primer lugar los elementos de la primera columna, después los de la segunda, y así sucesivamente.

Una vez que se ha elegido una disposición concreta, las operaciones de indexado deben de ser coherentes con la elección.

Prácticas de Procesadores de Lenguaje 2008-2009 70

Generación de código para indexación de vectores

� Por ejemplo, si se utiliza una disposición por filas, el elemento [f,j] donde f es la fila, y cla columna, está en la siguiente dirección de memoria:

Dirección elemento [f,c] = dirección_inicio_vector

+

(f * numero_columnas + c) * 4

� Si se utiliza una disposición por columnas, el elemento [f,j] donde f es la fila, y c la columna, está en la siguiente dirección de memoria:

Dirección elemento [f,c] = dirección_inicio_vector

+

(c* numero_filas + f) * 4

Vectores de dos dimensiones

Page 36: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 71

Generación de código para indexación de vectores

� Por ejemplo, la siguiente declaración de un vector de dos dimensiones, de 3 filas y 4 columnas en un programa ALFA:

array int [3,4] z;

se traduce en la declaración ensamblador siguiente:

_z resd 12

que reserva en memoria un bloque contiguo de 48 bytes, que se puede interpretar como 12 posiciones de 4 bytes cada una de ellas. Si se considera una disposición por filas de los elementos del vector, la memoria tendría el contenido que se muestra en la figura adjunta.

Vectores de dos dimensiones

v[0,0]_v

MEMORIA

v[0,1]_v +4

v[0,2]

v[0,3]

_v +8

_v +12

v[1,0]_v +16

v[1,1]_v +20

v[1,2]_v +24

v[1,3]_v +28

v[2,0]_v +32

v[2,1]_v +36

v[2,2]_v +40

v[2,3]_v +44

1ª fila

2ª fila

3ª fila

Prácticas de Procesadores de Lenguaje 2008-2009 72

Generación de código para operaciones de conjuntos

� Una variable de tipo conjunto se puede representar en el segmento .bss como un bloque de memoria con tantas posiciones de 32 bits como capacidad máxima tenga el conjunto más una posición extra en la que se almacena el número de elementos del conjunto.

� Por ejemplo, la declaración ALFA set of 4 c se transforma en una declaración en el segmento .bbs del tipo _c resd 5 que representa un bloque de memoria de 5 posiciones de 32 bits.

Representación de conjuntos

# de elementos_c

MEMORIA

elemento 1_c + 4

elemento 2

elemento 3

_c + 8

_c + 12

elemento 4_c + 16

� En la primera posición del bloque se almacena el número de elementos del conjunto. El acceso a esta primera posición se hace a través del nombre de la variable.

� En la segunda posición del bloque se almacena el primer elemento del conjunto, en la tercera posición el segundo, y así sucesivamente.

Page 37: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 73

Generación de código para operaciones de conjuntos

� El número de elementos del conjunto varía en tiempo de ejecución. Inicialmente vale 0 y se incrementa en uno con cada operación de inserción de un elemento nuevo en el conjunto (operación add).

� Para cada variable de tipo conjunto que se declare en un programa ALFA, es necesario inicializar a 0 la posición de memoria en la que se almacena su número de elementos. Esta inicialización se debe hacer antes de la primera sentencia del programa. Se puede realizar inmediatamente después de la etiqueta “main”, en la acción semántica del nuevo no terminal escritura2 (ver PENDIENTE 2)

� Para implementar la inicialización descrita en el punto anterior, se puede escribir una función que recorra la tabla de símbolos y que para cada variable de tipo conjunto genere la instrucción ensamblador que mueve un 0 a la posición de memoria que almacena el número de elementos del conjunto.Por ejemplo:

set of 45 a; � mov dword [_a] , 0

set of 20 b; � mov dword [_b] , 0

Representación de conjuntos

Prácticas de Procesadores de Lenguaje 2008-2009 74

Generación de código para operaciones de conjuntos

� La producción de la gramática relativa a la operación de inserción de un elemento en un conjunto es la siguiente:

� operacion_conjunto: TOK_ADD ‘(’ exp ‘,’ TOK_IDENTIFICADOR ‘)’

� Los objetivos básicos de la generación de código de la producción anterior son:� Generar código para comprobar, en tiempo de ejecución, que el conjunto dispone de

espacio para insertar un nuevo elemento según se explicó en el apartado “Control de errores en tiempo de ejecución”

� Generar código para hacer la inserción efectiva, es decir, mover el valor de la expresión a la primera posición libre del conjuto.

Inserción de un elemento en un conjunto

Page 38: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 75

Generación de código para operaciones de conjuntos

� La producción de la gramática relativa a la operación de vaciado de un conjunto es la siguiente:

� operacion_conjunto: TOK_CLEAR ‘(’ TOK_IDENTIFICADOR ‘)’

� La generación de código asociada a la operación de vaciado de un conjunto consiste simplemente en establecer a 0 el número de elementos del conjunto. Recordar que el número de elementos del conjunto se almacena en la primera posición de memoria del bloque que ocupa el conjunto, y que el acceso a esta primera posición se realiza directamente con el nombre del conjunto.

Vaciado de un conjunto

Prácticas de Procesadores de Lenguaje 2008-2009 76

Generación de código para operaciones de conjuntos

� Las producciones de la gramática relativas a las operaciones de unión e intersección de conjuntos son las siguientes:

� operacion_conjunto: TOK_UNION ‘(’ TOK_IDENTIFICADOR ‘,‘ TOK_IDENTIFICADOR ‘,’

TOK_IDENTIFICADOR ‘)’

� operacion_conjunto: TOK_INTERSECTION ‘(’ TOK_IDENTIFICADOR ‘,‘ TOK_IDENTIFICADOR ‘,’

TOK_IDENTIFICADOR ‘)’

� La generación de código asociada a cada una de las dos operaciones tiene como objetivo realizar de manera efectiva la operación concreta.

� Por ejemplo, para la unión de conjuntos, el código ensamblador tiene que:� Almacenar en el bloque de memoria asignado al conjunto destino la unión de los otros dos

conjuntos que aparecen en la instrucción, entendiendo como unión la definición habitual de unión de conjuntos en matemáticas. Evidentemente el contenido previo del conjunto destino se pierde.

� Actualizar el tamaño del conjunto destino para que sea acorde con su número de elementos.

Unión e intersección de conjuntos

Page 39: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 77

Generación de código para operaciones de conjuntos

� La producción de la gramática relativa al tamaño de un conjunto es la siguiente:

� exp: TOK_SIZE ‘(’ TOK_IDENTIFICADOR ‘)’

� La generación de código asociada al tamaño de un conjunto consiste en depositar en la pila el tamaño del conjunto. Recordar que el número de elementos del conjunto se almacena en la primera posición de memoria del bloque que ocupa el conjunto, y que el acceso a esta primera posición se realiza directamente con el nombre del conjunto.

Tamaño de un conjunto

Prácticas de Procesadores de Lenguaje 2008-2009 78

Generación de código para operaciones de conjuntos

� La producción de la gramática relativa a la función de pertenencia a un conjunto es la siguiente:

� exp: TOK_CONTAINS ‘(’ exp ‘,’ TOK_IDENTIFICADOR ‘)’

� La generación de código asociada a la función de pertenencia a un conjunto consiste en recorrer el conjunto buscando el valor de la expresión, y depositar en la pila el valor 1 (true) si se ha encontrado el valor, o 0 (false) si no se ha encontrado.

� Es importante recordar que antes de reducirse esta producción, en la cima de la pila se encuentra lo que se haya depositado en la reducción del no terminal exp.

Pertenencia a un conjunto

Page 40: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 79

Generación de código para sentencias de asignación

� Las producciones de las sentencias de asignación son: � asignacion : TOK_IDENTIFICADOR ‘=’ exp

� asignacion : elemento_vector ‘=’ exp

� asignacion : acceso ‘=’ exp

� asignacion : TOK_IDENTIFICADOR ‘=’ TOK_MALLOC

� asignacion : TOK_IDENTIFICADOR ‘=’ ‘&’ TOK_IDENTIFICADOR

� Básicamente, la generación de código de las producciones anteriores tiene como objetivo escribir el código ensamblador que hace efectiva la asignación. Es decir, si por ejemplo la sentencia es una asignación de una constante a un identificador, la generación de código deberá producir las instrucciones en ensamblador que cargan el valor de la constante en la posición de memoria que ocupa el identificador.

� Las características de las partes izquierda y derecha de la asignación, determinan el conjunto de instrucciones en ensamblador que realizan de manera efectiva la asignación.

Introducción

Prácticas de Procesadores de Lenguaje 2008-2009 80

Generación de código para sentencias de asignación

Asignación de una expresión a un identificador: esquema

GENERACIÓN DE CÓDIGO

; Cargar en eax la parte derecha de la asignaciónpop dword eax

; Nivel de indirección igual a 1 en la parte izquierda y; 0 en la parte derecha

mov dword [_$1.lexema] , eax

; Nivel de indirección igual a ambos lados de la; asignación

mov dword eax, [eax]mov dword [_$1.lexema] , eax

asignacion: TOK_IDENTIFICADOR ‘=’ exp

EVOLUCIÓN DE LA PILA

ANTES DE LA REDUCCIÓN

exp

PILA

DESPUÉS DE LA REDUCCIÓN

PILA

Page 41: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 81

Generación de código para sentencias de asignación

Asignación de una expresión a un identificador: ejemplo

...int ** ppe1, ppe2;...ppe1 = ppe2;...

Valor entero

dir2 dir3

dir3

dir2ppe1

MEMORIA

Valor entero

dir4 dir5

dir5

dir4ppe2

ANTES DE LA REDUCCIÓN

ppe2

PILA

eax

eax

ppe2

eax

dir4

Valor entero

dir2 dir3

dir3

dir4ppe1

MEMORIA

Valor entero

dir4 dir5

dir5

dir4ppe2

1

2

3

PROCESO DE REDUCCIÓN EN 3 PASOS

1. pop eax2. mov dword eax, [eax]3. mov dword [_$1.lexema] , eax

Prácticas de Procesadores de Lenguaje 2008-2009 82

Generación de código para sentencias de asignación

Asignación de una expresión al elemento de un vector

GENERACIÓN DE CÓDIGO

; Cargar en eax la parte derecha de la asignaciónpop dword eax

; Cargar en edx la parte izquierda de la asignaciónpop dword edx

SI ($3.direcciones == 1)mov dword eax, [eax]

mov dword [edx] , eax

asignacion: elemento_vector ‘=’ exp

EVOLUCIÓN DE LA PILA

DESPUÉS DE LA REDUCCIÓN

PILA

ANTES DE LA REDUCCIÓN

elem_vect

PILA

exp

� En este tipo de asignación, la parte izquierda siempre tiene nivel de indirección igual a 1 (recordar que en ALFA no están permitidos vectores de punteros)

Page 42: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 83

Generación de código para sentencias de asignación

Asignación de una expresión a una operación de acceso

GENERACIÓN DE CÓDIGO

; Cargar en eax la parte derecha de la asignaciónpop dword eax

; Cargar en edx la parte izquierda de la asignaciónpop dword edx

SI ($3.direcciones >0)mov dword eax, [eax]

mov dword [edx] , eax

asignacion: acceso ‘=’ exp

EVOLUCIÓN DE LA PILA

DESPUÉS DE LA REDUCCIÓN

PILA

ANTES DE LA REDUCCIÓN

dir_acceso

PILA

exp

� Se distinguen dos casos en función de los niveles de indirección de las partes izquierda y derecha de la asignación.

Prácticas de Procesadores de Lenguaje 2008-2009 84

Generación de código para sentencias de asignación

Reserva de memoria

asignacion: TOK_IDENTIFICADOR ‘=’ TOK_MALLOC

� Una vez realizadas las comprobaciones semánticas oportunas, que consisten en verificar que el identificador está declarado y que es de clase puntero, la generación de código de esta sentencia de asignación consiste básicamente en:

� Realizar la reserva de memoria invocando a la función alfa_malloc de la librería alfalib. Esta función no tiene parámetros de entrada y devuelve en “eax” la dirección de memoria reservada.

call alfa_malloc

� Hacer efectiva la asignación moviendo a la posición de memoria del identificador la nueva dirección reservada (contenido de eax)

mov dword [_$1.lexema] , eax

� El contenido de la pila es irrelevante para el planteamiento de la generación de código de esta producción de asignación.

Page 43: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 85

Generación de código para sentencias de asignación

Asignación de la dirección de un identificador a otro identificador

asignacion: TOK_IDENTIFICADOR ‘=’ ‘&’ TOK_IDENTIFICADOR

� Una vez realizadas las comprobaciones semánticas oportunas, que básicamente consiste en comprobar que los identificadores que aparecen a ambos lados de la asignación corresponden a variables declaradas con las siguientes características:

� Son del mismo tipo.

� Ninguna de las dos partes de la asignación es de clase vector, conjunto o de categoría función.

� El nivel de indirección del identificador de la parte izquierda es mayor que 1 y además es igual a 1 más el nivel de indirección del identificador de la parte derecha

� La generación de código consiste en hacer efectiva la asignación moviendo a la posición de memoria del identificador de la parte izquierda la dirección del identificador de la parte derecha.

mov dword [_$1.lexema] , _$4.lexema

� El contenido de la pila es irrelevante para el planteamiento de la generación de código de esta producción de asignación.

Prácticas de Procesadores de Lenguaje 2008-2009 86

Generación de código para entrada de datos

� El lenguaje de programación ALFA tiene dos sentencias para la entrada de datos. Las producciones de la gramática para dichas sentencias son:

� lectura: TOK_SCANF TOK_IDENTIFICADOR

� lectura: TOK_SCANF elemento_vector

� En las acciones semánticas de las anteriores producciones, además de realizar las comprobaciones semánticas oportunas, se hace uso de la librería alfalib de la siguiente manera:

� Si la lectura corresponde a un dato de tipo entero, se invoca a la función scan_int.

� Si la lectura corresponde a un dato de tipo real, se invoca a la función scan_float.

� Si la lectura corresponde a un dato de tipo lógico, se invoca a la función scan_boolean.

� Las funciones scan_int, scan_float y scan_boolean tienen como parámetro de entrada la dirección de memoria que será destino del dato leído, por lo tanto, antes de invocar a una de ellas es necesario apilar la dirección adecuada.

� Después de la invocación se restaura la pila (manipulando el puntero de pila o desapilando el parámetro apilado previamente)

Introducción

Page 44: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 87

Generación de código para entrada de datos

Lectura de un identificador

lectura: TOK_SCANF TOK_IDENTIFICADOR

� En primer lugar, se prepara la pila para la llamada a la función correspondiente de la librería alfalib, apilando la dirección de memoria que será destino del dato leído:

push dword _$2.lexema

� El segundo paso consiste en invocar a la rutina de lectura adecuada al tipo del identificador:

call scan_int ; si el identificador es de tipo entero

call scan_float ; si el identificador es de tipo real

call scan_boolean ; si el identificador es de tipo lógico

� Por último se restaura el puntero de pila:

add esp, 4

PENDIENTE 4: el identificador puede ser variable local, global o parámetro.

Prácticas de Procesadores de Lenguaje 2008-2009 88

Generación de código para entrada de datos

Lectura de un elemento de vector

lectura: TOK_SCANF <elemento_vector>

� La única diferencia entre la generación de código de esta producción y la anterior es que cuando se reduce esta regla, en la cima de la pila se encuentra la dirección del elemento del vector, y por lo tanto, no es necesario apilarla.

� La invocación de la rutina de lectura adecuada al tipo del vector y la restauración de la pila después de la invocación, se realiza de manera similar a la producción anterior.

Page 45: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 89

Generación de código para salida de datos

� El lenguaje de programación ALFA tiene una sentencia para escritura de expresiones. La producción correspondiente es:

� escritura: TOK_PRINTF exp

� También hay una sentencia para escribir datos de tipo colección, y su regla es la siguiente:

� escritura: TOK_CPRINTF TOK_IDENTIFICADOR

Introducción

Prácticas de Procesadores de Lenguaje 2008-2009 90

Generación de código para salida de datos

� En la acción semántica de la producción correspondiente a la escritura de una expresión, además de comprobar que la expresión tiene nivel de indirección 0 ó 1, para la generación de código, se hace uso de la librería alfalib de la siguiente manera:

� Si la expresión es de tipo entero, se invoca a la función print_int.

� Si la expresión es de tipo real, se invoca a la función print_float.

� Si la expresión es de tipo lógico, se invoca a la función print_boolean.

� Las funciones print_int, print_float y print_boolean tienen un único parámetro que corresponde al VALOR de salida, por lo tanto, antes de invocar a una de ellas es necesario apilar dicho valor.

� Después de la invocación se restaura la pila (manipulando el puntero de pila o desapilando el parámetro apilado previamente)

� Una vez escrito el valor de salida, es conveniente realizar un salto de línea. La librería alfalibtambién proporciona la función print_endofline que escribe un salto de línea en la salida estándar. Esta función no tiene parámetros.

� Antes de reducir la producción, en la cima de la pila se encuentra el resultado de la reducción del no terminal exp.

Escritura de una expresión

Page 46: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 91

Generación de código para salida de datos

Escritura de una expresión

escritura: TOK_PRINTF exp

GENERACIÓN DE CÓDIGO

; Acceso al valor de exp si es distinto de constanteSI $2.direcciones == 1pop dword eaxmov dword eax , [eax]push dword eax

; Si la expresión es de tipo enterocall print_int; Si la expresión es de tipo realcall print_float; Si la expresión es de tipo lógicocall print_boolean

; Restauración del puntero de pilaadd esp, 4

; Salto de líneacall print_endofnile

EVOLUCIÓN DE LA PILA

ANTES DE LA REDUCCIÓN

exp

PILA

DESPUÉS DE LA REDUCCIÓN

PILA

Prácticas de Procesadores de Lenguaje 2008-2009 92

Generación de código para salida de datos

� En la descripción de la semántica del lenguaje ALFA, se especifica el formato para la escritura de colecciones.

� La generación de código de la producción correspondiente a la escritura de una colección hace uso de las siguientes funciones de la librería alfalib:

� Si el tipo básico de la colección es entero, para imprimir cada uno de los elementos se invoca a la función print_int. No olvidar que los conjuntos por defecto son de tipo básico entero, mientras que los elementos de los vectores pueden ser de cualquiera de los tres tipos básicos.

� Si el tipo básico de la colección es float, para imprimir cada uno de los elementos se invoca a la función print_float.

� Si el tipo básico de la colección es boolean, para imprimir cada uno de los elementos se invoca a la función print_boolean.

� Para separar los elementos de la colección se utiliza la función print_blank. Esta función no tiene parámetros.

� Para separar las filas de los vectores de dos dimensiones se utiliza la función print_endofline. Esta función tampoco tiene parámetros.

� Una vez finalizada la escritura de la colección, es conveniente realizar un salto de línea con la función print_endofline.

Escritura de una colección

Page 47: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 93

Generación de código para sentencias condicionales

� El lenguaje de programación ALFA tiene dos formatos de sentencia condicional descritos en las siguientes producciones:

� condicional : TOK_IF ‘(‘ exp ‘)’ ‘{‘ sentencias ‘}’� condicional : TOK_IF ‘(‘ exp ‘)’ ‘{‘ sentencias ‘}’ TOK_ELSE ‘{‘ sentencias ‘}’

� La generación de código de las sentencias condicionales tiene una característica particular que hasta ahora no se ha presentado en el desarrollo del compilador. La bifurcación del flujo de ejecución en función del valor de la condición requiere “recordar” las etiquetas de salto. En concreto, en la primera producción, una vez procesado el no terminal “exp”, si su valor es VERDADERO, el flujo de ejecución continúa por las instrucciones correspondientes a la traducción del no terminal “sentencias”, pero si su valor es FALSO, el flujo debe saltar a una etiqueta inmediatamente posterior a dicho bloque de instrucciones. El punto adecuado para escribir en ensamblador la instrucción de salto se encuentra antes “sentencias”, pero la escritura de la propia etiqueta a la que se salta sólo se puede hacer después de “sentencias”. Por lo tanto, es necesario un mecanismo para asegurar que se usa el mismo nombre de etiqueta en los dos puntos en los que se hace uso de ella.

� Un posible mecanismo para “recordar” etiquetas consiste en:� Modificar la gramática de manera adecuada.� Añadir un nuevo atributo semántico que permita propagar etiquetas.

Introducción

Prácticas de Procesadores de Lenguaje 2008-2009 94

Generación de código para sentencias condicionales

Condicionales simples

exp

PILA

pop eaxmov eax, [eax] ; si nivel de indirección exp>0cmp eax, 0je near fin_si#

;; exp;

;; sentencias;

fin_si#:

Estos dos bloques de código ensamblador se generan en momentos diferentes pero hacen referencia a una misma etiqueta (fin_si#)

condicional : TOK_IF ‘(’ exp ‘)’ ‘{’ sentencias ‘}’

Page 48: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 95

MODIFICACIÓN DE LA GRAMÁTICA

if_exp: TOK_IF ‘(’ exp ‘)’ ‘{’

condicional: if_exp sentencias ’}’

Generación de código para sentencias condicionales

Condicionales simples

Generación de código

fin_si#: ; # es $1.etiqueta

Comprobaciones semánticasComprobar que $3.tipo == BOOLEANComprobar que $3.direcciones == 0/1

Reserva de etiqueta (#)$$.etiqueta = etiqueta++

Generación de códigopop eaxmov eax , [eax] ; Si nivel de indirección de exp == 1cmp eax, 0je near fin_si# ; # es $$.etiqueta

condicional : TOK_IF ‘(’ exp ‘)’ ‘{’ sentencias ‘}’

Prácticas de Procesadores de Lenguaje 2008-2009 96

pop eaxmov eax, [eax] ; si nivel de indirección exp>0cmp eax, 0je near fin_si#

;; exp;

;; sentencias;

jmp near fin_sino#fin_si#:

fin_sino#:

;; sentencias;

condicional: TOK_IF ‘(’ exp ‘)’ ‘{’ sentencias ‘}’ TOK_ELSE ‘{’ sentencias ‘}’

Generación de código para sentencias condicionales

Condicionales compuestas

exp

PILA

Estos tres bloques de código ensamblador se generan en momentos diferentes pero hacen referencia a las mismas etiquetas (fin_si# y fin_sino#)

Page 49: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 97

Generación de código para sentencias condicionales

Condicionales compuestas

Propagación de atributos$$.etiqueta = $1.etiqueta

Generación de código

jmp near fin_sino# ; # es $1.etiquetafin_si#: ; # es $1.etiqueta

Comprobaciones semánticasComprobar que $3.tipo == BOOLEANComprobar que $3.direcciones == 0/1

Reserva de etiqueta (#)$$.etiqueta = etiqueta++

Generación de códigopop eaxmov eax , [eax] ; Si nivel de indirección de exp == 1cmp eax, 0je near fin_si# ; # es $$.etiqueta

MODIFICACIÓN DE LA GRAMÁTICA

if_exp: TOK_IF ‘(’ exp ‘)’ ‘{’

if_exp_sentencias : if_exp sentencias

condicional : if_exp_sentencias TOK_ELSE ‘{‘ sentencias ‘}’

Generación de código

fin_sino#: ; # es $1.etiqueta

condicional: TOK_IF ‘(’ exp ‘)’ ‘{’ sentencias ‘}’ TOK_ELSE ‘{’ sentencias ‘}’

Prácticas de Procesadores de Lenguaje 2008-2009 98

Generación de código para sentencias iterativas

� El lenguaje de programación ALFA tiene dos sentencias iterativas cuya sintaxis se describe en las siguientes producciones:

� bucle: TOK_WHILE ‘(‘ exp ‘)’ ‘{’ sentencias ‘}’

� bucle: TOK_FOR ‘(’ TOK_IDENTIFICADOR '=‘ exp ‘;’ exp ‘)’ ‘{’ sentencias ‘}‘

� La traducción a ensamblador de las sentencias iterativas tiene características similares a la traducción de sentencias condicionales.La idea básica es la necesidad de implementar un mecanismo que permita “recordar” etiquetas.

Introducción

Page 50: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 99

bucle: TOK_WHILE ‘(’ exp ‘)’ ‘{’ sentencias ‘}’

Generación de código para sentencias iterativas

Sentencia WHILE

exp

PILA

Estos tres bloques de código ensamblador se generan en momentos diferentes pero hacen referencia a las mismas etiquetas (inicio_while# y fin_while#)

pop eaxmov eax, [eax] ; si nivel de indirección exp>0cmp eax, 0je near fin_while#

;; exp;

;; sentencias;

jmp near inicio_while#fin_while#:

inicio_while#:

Prácticas de Procesadores de Lenguaje 2008-2009 100

bucle: TOK_WHILE ‘(’ exp ‘)’ ‘{’ sentencias ‘}’

Generación de código para sentencias iterativas

Sentencia WHILE

Reserva de etiqueta (#)$$.etiqueta = etiqueta++

Generación de código

inicio_while#: ; # es $$.etiqueta

Comprobaciones semánticasComprobar que $2.tipo == BOOLEANComprobar que $2.direcciones == 0/1

Propagación de atributos$$.etiqueta = $1.etiqueta

Generación de códigopop eaxmov eax , [eax] ; Si nivel de indirección de exp == 1cmp eax, 0je near fin_while# ; # es $$.etiqueta

MODIFICACIÓN DE LA GRAMÁTICA

while : TOK_WHILE ‘(’

while_exp : while exp ‘)’ ‘{’

bucle : while_exp sentencias ‘}’

Generación de código

jmp near inicio_while# ; # es $1.etiquetafin_while#: ; # es $1.etiqueta

Page 51: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 101

Generación de código para sentencias iterativas

� La generación de código de esta sentencia se propone como trabajo del alumno.

� La producción de la gramática que describe la sintaxis de la sentencia FOR es:

� bucle: TOK_FOR ‘(’ TOK_IDENTIFICADOR '=‘ exp ‘;’ exp ‘)’ ‘{’ sentencias ‘}‘

� En el enunciado de la última práctica se describe detalladamente el funcionamiento de la sentencia. Es imprescindible conocer dicho funcionamiento para implementar de manera correcta la generación de código correspondiente, y se podría resumir en los siguientes puntos:

� El grupo de sentencias situado entre las llaves sólo se ejecuta si el valor de la segunda expresión es mayor o igual al valor de la primera expresión.

� En cada iteración se incrementa en 1 el valor de la variable de control del bucle.

� Cuando termina la ejecución del bucle, el identificador contiene el valor de la segunda expresión.

� Habría que añadir al enunciado de la práctica que en el caso en el que no se ejecuten las sentencias porque el valor de la segunda expresión es mayor o igual al valor de la primera expresión, inmediatamente después de la sentencia FOR, el valor del identificador coincidecon el de la primera expresión. Es decir, la asignación inicial en la que se asigna al identificador el valor de la primera expresión, se realiza siempre independientemente de si se ejecutan o no las sentencias.

Sentencia FOR

Prácticas de Procesadores de Lenguaje 2008-2009 102

Generación de código para sentencias de selección

� El lenguaje de programación ALFA tiene una sentencia de selección cuya sintaxis se describe en las siguientes producciones:

� seleccion: TOK_SWITCH ‘(’ exp ‘)’ ‘{’casos_seleccion ‘}’

� casos_seleccion: casos_estandar caso_defecto

� casos_estandar: caso_estandar

� casos_estandar: casos_estandar caso_estandar

� caso_estandar: TOK_CASE constante_entera ‘:’ sentencias

� caso_defecto: TOK_DEFAULT sentencias

� La generación de código de esta sentencia se propone como trabajo del alumno.

� En el enunciado de la última práctica se describe detalladamente el funcionamiento de la sentencia. Es imprescindible conocer dicho funcionamiento para implementar de manera correcta la generación de código correspondiente.

Page 52: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 103

Generación de código

� Generación de código para funciones� Convenio de las llamadas

� Ejemplo

� Generación de código para las llamadas a funciones

� Generación de código inicial y final en el cuerpo de una función

� Generación de código para la localización del contenido de los parámetros

� Generación de código para la localización del contenido de las variables locales

� Generación de código para la localización de la dirección de parámetros y variables locales

� Tratamiento de identificadores

Índice

Prácticas de Procesadores de Lenguaje 2008-2009 104

Generación de código para funciones

� Para que las llamadas a funciones trabajen de manera correcta, es necesario establecer lo que conoce como convenio de llamadas que debe ser especificado explícitamente al diseñar el compilador.

� El convenio de llamadas tiene que dar respuesta a las siguientes preguntas:� ¿Cómo se comunican los argumentos desde el programa llamante a la función llamada?

� ¿Cómo se comunican los resultados desde la función llamada hasta el programa llamante?

� Se recomienda utilizar el siguiente convenio de llamadas:� Para comunicar los argumentos desde el programa llamante a la función llamada:

� Se utilizará la pila.

� El programa llamante dejará en la pila el valor de los argumentos de la llamada en el mismo ordenen el aparecen en la definición de la función.

� Tras la llamada, el programa llamante tiene la responsabilidad de eliminar los argumentos de la pila.

� Para comunicar los resultados desde la función llamada:� Se utilizará el registro eax.

Convenio de las llamadas

Page 53: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 105

Generación de código para funciones

� Explicando más detalladamente el proceso consideremos el siguiente programa ALFA.

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

Ejemplo

Prácticas de Procesadores de Lenguaje 2008-2009 106

Generación de código para funciones

� Imaginemos el código NASM equivalente. Comencemos por el programa principal.

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

Ejemplo

Page 54: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 107

Generación de código para funciones

� Las secciones .bss y .data junto con la cabecera del segmento de código tendrían el contenido que se muestra en la figura. Posteriormente estudiaremos la zona correspondiente al código de las funciones.

segment .bss

_z resd 1

segment .data

.....

segment .text

global main

extern ...

;

; código de las

; funciones

;

main:

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

Ejemplo

Prácticas de Procesadores de Lenguaje 2008-2009 108

Generación de código para funciones

� La primera instrucción del programa principal es una sentencia de lectura que se traduce en NASM en una llamada a la función “scan_int”. Antes de llamar a esta función, se apila su parámetro, que es la dirección donde debe depositar el dato.

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

···

main:

push dword _z

call lee_entero

add esp, 4

El programa llamante introduce en la pila los argumentos de la

función “scan_int”

Ejemplo

Page 55: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 109

Generación de código para funciones

� Después de introducir en la pila el parámetro de la llamada, se invoca a la función.

···

main:

push dword _z

call scan_int

add esp, 4

Realiza la llamada a la función

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

Ejemplo

Prácticas de Procesadores de Lenguaje 2008-2009 110

Generación de código para funciones

� La función “scan_int” realiza su trabajo, y desde el principal se restaura la pila.

···

main:

push dword _z

call scan_int

add esp, 4El programa llamante restaura la pila manipulando el puntero de

pila

Ejemplo

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

Page 56: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 111

Generación de código para funciones

� La segunda sentencia del programa principal ALFA es una instrucción de escritura, en la cual, antes de la propia escritura, se procesa la llamada a la función. Esta llamada implica realizar las mismas acciones que con la llamada a “scan_int”

···

main:

push dword _z

call scan_int

add esp, 4

push dword [_z]

call _doble

add esp, 4

De la misma manera hay que hacer con una llamada a una

función definida por el programador de ALFA

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

Ejemplo

Prácticas de Procesadores de Lenguaje 2008-2009 112

Generación de código para funciones

� Siguiendo el convenio de llamadas previamente definido, la función deja el retorno en el registro eax. Por lo tanto, después de restaurar la pila, será necesario apilar en ella el contenido del registro eax (ya que la llamada a una función es una “exp”)

···

main:

push dword _z

call scan_int

add esp, 4

push dword [_z]

call _doble

add esp, 4

push dword eaxEl retorno de la función se

encuentra en eax

Ejemplo

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

Page 57: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 113

Generación de código para funciones

� El código NASM correspondiente a la traducción de la sentencia de escritura “printf” y también el código del final del programa no son relevantes en la explicación actual y por ello se omiten en la figura.

···

main:

push dword _z

call scan_int

add esp, 4

push dword [_z]

call _doble

add esp, 4

push dword eax

;

; resto de código

;

Ejemplo

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

Prácticas de Procesadores de Lenguaje 2008-2009 114

Generación de código para funciones

� Para comprender el código que hay que generar para la función imaginemos cómo está la pila (donde se tiene que almacenar toda la información) en una llamada si z contiene el valor 3.

···

main:

push dword _z

call scan_int

add esp, 4

push dword [_z]

call _doble

add esp, 4

push dword eax

;

; resto de código

;

Ejemplo

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

Page 58: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 115

Generación de código para funciones

� Recuérdese que la pila de 32 bits tiene su puntero almacenado en el registro esp recuerde, también, que la pila “crece” hacia posiciones de memoria de valor menor, se representará gráficamente con crecimiento “hacia abajo”.

3 esp

Se introduce en la pila el valor de z

···

main:

push dword _z

call scan_int

add esp, 4

push dword [_z]

call _doble

add esp, 4

push dword eax

;

; resto de código

;

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

Ejemplo

Prácticas de Procesadores de Lenguaje 2008-2009 116

Generación de código para funciones

� La instrucción “call” introduce en la pila la dirección de retorno a la que hay que regresar cuando termine la función.

3

dir ret.

La instrucción call introduce en la pila la dirección de retorno

esp

Ejemplo

···

main:

push dword _z

call scan_int

add esp, 4

push dword [_z]

call _doble

add esp, 4

push dword eax

;

; resto de código

;

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

Page 59: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 117

Generación de código para funciones

� Esta es la pila que se encuentra la función cuando comienza su ejecución.� Está claro dónde se encuentra el argumento de la función (arg)

� Se tiene que utilizar también la pila para guardar las variables locales (auxArg)

� Debemos conocer qué expresión, en función de los registros de gestión de la pila, sirve para localizar en ella argumentos y variables locales.

� Obsérvese que el compilador tendrá que generar el código necesario para el cuerpo de la función.

� Por las decisiones de diseño tomadas, se utilizará la pila, por lo tanto, el valor del registro esp cambiará.

� NASM proporciona otro registro ebp específicamente para poder solucionar esta circunstancia.

� Para ello, hay que hacer lo siguiente:� Guardar el valor de ebp (también en la pila)

� Utilizar ebp para mantener una copia del valor de esp en el momento de la entrada

� Utilizar ebp para localizar los parámetros y las variables locales

� Recuperar los valores de los dos registros antes de salir de la función

Ejemplo

Prácticas de Procesadores de Lenguaje 2008-2009 118

Generación de código para funciones

3

dir ret.

_doble:

push ebp

ebp esp

Se guarda el valor deebp en la pila

Ejemplo

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

� La primera acción en la generación de código del cuerpo de una función es salvar en la pila el registro ebp, ya que se va a utilizar como puntero base para localizar en la pila los argumentos y las variables locales de la función.

Page 60: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 119

Generación de código para funciones

3

dir ret.

_doble:

push ebp

mov ebp, esp

ebp esp ebp

Se guarda en ebp el valor de esp

Ejemplo

� La segunda acción es guardar el registro ebp el valor del puntero de pila, para poder gestionar el acceso a los parámetros y las variables locales (se verá posteriormente)

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

Prácticas de Procesadores de Lenguaje 2008-2009 120

Generación de código para funciones

� Recuérdese que usamos un tamaño de dato de 32 bits, que son 4 bytes. Así es fácil saber que arg se encuentra separado de ebp por 2 dword, es decir + 8 bytes

3

dir ret.

_doble:

push ebp

mov ebp, esp

ebp esp ebp

ebp+8

Ejemplo

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

Page 61: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 121

Generación de código para funciones

� Ahora sólo queda localizar (reservar espacio en la pila y saber como acceder posteriormente) las variables locales (auxArg). Para ello se utiliza las posiciones libres bajo la cima de la pila (como con push, restamos a esp lo necesario)

3

dir ret.

_doble:

push ebp

mov ebp, esp

sub esp, 4 ebp ebp

ebp+8

esp

Ejemplo

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

Espacio reservado para la variable local

Prácticas de Procesadores de Lenguaje 2008-2009 122

Generación de código para funciones

� Por lo tanto, auxArg se encontrará siempre 4 bytes por debajo de ebp es decir, en ebp-4

3

dir ret.

_doble:

push ebp

mov ebp, esp

sub esp, 4 ebp ebp

ebp+8

esp ebp-4

Ejemplo

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

Page 62: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 123

Generación de código para funciones

� Ahora se puede generar el código para el cuerpo de la función (aquí se genera “a mano” y es diferente de lo generado automáticamente por el compilador)

3

dir ret.

_doble:

push ebp

mov ebp, esp

sub esp, 4

mov dword eax, [ebp+8]

mov dword [ebp-4], eax

mov dword edx, 2

imul edx

ebp ebp

ebp+8

3 esp ebp-4

Ejemplo

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

Prácticas de Procesadores de Lenguaje 2008-2009 124

Generación de código para funciones

� Antes de salir de la función se debe “recuperar” los valores iniciales de ebp y esp. Recuérdese que en ebp se guardó el valor de esp, y por lo tanto recuperar el valor de esp consiste en un simple movimiento.

3

dir ret.

_doble:

push ebp

mov ebp, esp

sub esp, 4

mov dword eax, [ebp+8]

mov dword [ebp-4], eax

mov dword edx, 2

imul edx

mov esp, ebp

ebp ebp esp

ebp+8

Se copia en esp su valor que está guardado en ebp. Obsérvese que es como si se hicieran los pop necesarios para eliminar las variables locales

3 ebp-4

Ejemplo

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

Page 63: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 125

Generación de código para funciones

� Para recuperar el valor que tenía el registro ebp al inicio de la función, simplemente se accede a la cima de la pila, ya que se apiló previamente.

3

dir ret.

_doble:

push ebp

mov ebp, esp

sub esp, 4

mov dword eax, [ebp+8]

mov dword [ebp-4], eax

mov dword edx, 2

imul edx

mov esp, ebp

pop ebp

ebp ebp

ebp+8

3 ebp-4

Se recupera (desde la pila) el antiguo valor de ebp. Obsérvese

que, tras modificar en la instrucción anterior esp la cima de la pila apunta ahora a la

posición que guarda la copia de ebp

esp

Ejemplo

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

Prácticas de Procesadores de Lenguaje 2008-2009 126

Generación de código para funciones

� Como última instrucción de la función, la instrucción “ret”, que coge de la pila la dirección de retorno que apiló la instrucción “call”

3

dir ret.

_doble:

push ebp

mov ebp, esp

sub esp, 4

mov dword eax, [ebp+8]

mov dword [ebp-4], eax

mov dword edx, 2

mul edx

mov esp, ebp

pop ebp

ret

esp

Y ya se puede devolver el control al programa llamante mediante la instrucción ret. Esta instrucción elimina de la pila la dirección de

retorno

Ejemplo

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

Page 64: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 127

Generación de código para funciones

� Retornamos, por lo tanto, al código del programa principal que se encuentra la pila como la tenía antes de la ejecución de la instrucción call. Obsérvese que la pila todavía contiene los argumentos de la función, el programa debe “limpiar” la pila.

3 esp

Ejemplo

···

main:

push dword _z

call scan_int

add esp, 4

push dword [_z]

call _doble

add esp, 4

push dword eax

;

; resto de código

;

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

Prácticas de Procesadores de Lenguaje 2008-2009 128

Generación de código para funciones

� Para restaurar la pila se manipula su puntero, y se posicionará en el lugar donde estaba antes de producirse la inserción de los parámetros de la llamada a la función.

3

esp

···

main:

push dword _z

call scan_int

add esp, 4

push dword [_z]

call _doble

add esp, 4

push dword eax

;

; resto de código

;

main {

int z;

function int doble(int arg)

{

int auxArg;

auxArg = arg;

return 2*arg ;

}

scanf z;

printf doble(z)

}

Ejemplo

Page 65: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 129

Generación de código para funciones

� Lo observado en el ejemplo anterior puede generalizarse para cualquier función con cualquier número de variables locales y cualquier número de argumentos.

� El programa llamante debe primero copiar los argumentos de la función en la pila en el mismo orden en el que aparecen en la declaración de la función

� Las producciones relacionadas con los argumentos de llamada a una función son las siguientes:

exp: TOK_IDENTIFICADOR ‘(‘ lista_expresiones ‘)’

lista_expresiones: exp resto_lista_expresiones

lista_expresiones:

resto_lista_expresiones: ‘,’ exp resto_lista_expresiones

resto_lista_expresiones:

push dword <1er argumento>···

push dword <último argumento>

Generación de código para las llamadas a funciones

Prácticas de Procesadores de Lenguaje 2008-2009 130

Generación de código para funciones

� Como puede observarse en las producciones anteriores, los parámetros de llamada a una función son una lista de no terminales “exp”.

� Por lo tanto, para cumplir el convenio de llamadas en el que se dice que los parámetros se pasan por valor, es necesario controlar que las reducciones del no terminal “exp” que ocurran dentro de una lista de parámetros de llamada dejen en la pila un valor y nunca una dirección.

� Por ejemplo, la producción siguiente:

exp: TOK_IDENTIFICADOR

si se reduce dentro de una lista de parámetros de llamada, debe dejar en la pila el valor del identificador y no su dirección.

� Para implementar esta característica del convenio de llamadas, basta con diseñar un mecanismo que permita saber en las reducciones del no terminal “exp” si está ocurriendo dicha reducción dentro de una lista de parámetros de llamada a función o no, y en caso afirmativo dejar en la pila el valor y no la dirección.

Generación de código para las llamadas a funciones

Page 66: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 131

Generación de código para funciones

� De todas las reglas del no terminal “exp”, solamente hay tres que dejen de manera habitual en la pila una dirección en lugar de un valor, y son las siguientes:

exp: TOK_IDENTIFICADOR

exp: acceso

exp: elemento_vector

� Por lo tanto, sólo en estas producciones hay que controlar si la reducción ocurre dentro de una lista de parámetros de llamada a función.

� Las demás producciones del no terminal “exp” siempre dejan un valor en la pila y por lo tanto su reducción siempre trabaja de la misma manera. Estas reglas son:

exp: exp ‘+’ exp (y todas las demás reglas de operaciones aritmético-lógicas)

exp: constante

exp: ‘(‘ comparacion ‘)’

exp: TOK_SIZE ‘(‘ TOK_IDENTIFICADOR ‘)’

exp: TOK_CONTAINS ‘(‘ exp ‘,’ TOK_IDENTIFICADOR ‘)’

exp: TOK_IDENTIFICADOR ‘(‘ lista_expresiones ‘)’

Generación de código para las llamadas a funciones

Prácticas de Procesadores de Lenguaje 2008-2009 132

Generación de código para funciones

� El programa llamante, después de depositar en la pila los parámetros de la llamada a la función debe llamar a la función:

� Posteriormente restaurar la pila.

� Como la función, atendiendo al convenio de llamadas, deja el resultado en eax, y siempre la llamada a una función aparece en el lugar de una expresión, es necesario, después de que la función termine, apilar el la pila el contenido de eax.

� La producción adecuada para realizar estas tres acciones se muestra en la siguiente figura, en la que también se incluyen acciones relacionadas con el análisis semántico.

call _<nombre función>

add esp, <4 * nº argumentos de la función>

Generación de código para las llamadas a funciones

push dword eax

Page 67: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 133

Generación de código para funciones

Generación de código para las llamadas a funciones

¿número de parámetros formales = actuales?

Comprobación semánticaBuscar en la tabla de símbolos el identificador $1.lexema

Mostrar mensaje de error semánticoy terminar con error

NOSI

exp: fn_name ‘(’ lista_expresiones ’)’

Cálculo de atributos

$$.tipo = tipo del elemento buscado en la tabla$$.direcciones = 0

Generación de código

call _$1.lexema

add esp, 4* global_num_parametros_llamada_actual push dword eax

Actualización de variables globales

en_explist = 0

La variable “en_explist” es la variable global que permite controlar si el

proceso de compilación se encuentra dentro de una lista de parámetros de

una llamada a función

Recuerde que para la gestión de los

identificadores de función, se modificó la gramática creando el símbolo nuevo

“fn_name”

Prácticas de Procesadores de Lenguaje 2008-2009 134

Generación de código para funciones

� Las primeras sentencias NASM del cuerpo de cualquier función deben ser las siguientes:

� El punto adecuado para generar las primeras líneas de código de la función sería el indicado con el símbolo � en la producción. Dicho punto también se identificó en el estudio del análisis semántico como lugar adecuado para la realización de acciones. Por lo tanto, la gramática ya está modificada.

(22) funcion : TOK_FUNCTION tipo TOK_IDENTIFICADOR

‘(‘ parametros_funcion ‘)’ ‘{‘ declaraciones_funcion �

sentencias ‘}’

_<nombre_funcion>:push ebp

mov ebp, esp

sub esp, <4*nº variables locales>

Código inicial y final en el cuerpo de una función

Page 68: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 135

Generación de código para funciones

� Las últimas instrucciones en el cuerpo de una función deben ser las siguientes:

� La producción adecuada para escribir estas últimas instrucciones del cuerpo de una función se muestra en la siguiente figura, en la que también se incluyen acciones relacionadas con el análisis semántico.

mov esp, ebp

pop ebp

ret

Código inicial y final en el cuerpo de una función

Prácticas de Procesadores de Lenguaje 2008-2009 136

Generación de código para funciones

Código inicial y final en el cuerpo de una función

Generación de código

pop dword eax

SI $2.direcciones>0

mov eax , [eax]

mov dword esp, ebp

pop dword ebp

ret

retorno_funcion : TOK_RETURN exp

¿OK ?

Comprobación de tipo y direcciones

NOSI

Mostrar mensaje de errory terminar con error

exp

PILA

Actualización de variables globales

fn_return ++

Se accede a la información de la función en la tabla de

símbolos para comprobar que “exp” tiene el mismo tipo que el

retorno de la función.

Las direcciones de exp siempre tienen

que ser 0 ó 1.

La variable fn_return permite controlar que siempre haya al menos

una instrucción de retorno en el cuerpo de una función

Page 69: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 137

Generación de código para funciones

� En el código del cuerpo de la función, cuando se quiera acceder al valor de los parámetros se utilizará la expresión

� Esta expresión de acceso es válida siempre que el primer parámetro tenga asignada la posición 0.

� Recuerde que, el primer 4 es para “saltar” la dirección de retorno.

� Por ejemplo:� El valor del último argumento será [ebp+8].

� El valor del penúltimo argumento será [ebp+12].

� ···� El valor del i-esimo argumento será [ebp+<4+4*(numero de parámetros – i)>].

[ebp + <4 + 4*(numero de parámetros -posición del parámetro en declaración)>]

Localización del contenido de los parámetros

Prácticas de Procesadores de Lenguaje 2008-2009 138

Generación de código para funciones

� En el código del cuerpo de la función, cuando se quiera acceder al valor de las variables locales se utilizará la expresión

� Esta expresión de acceso es válida siempre que la primera variable local tenga asignada la posición 1.

� Por ejemplo:� El valor de la primera variable local será [ebp-4].

� El valor de la segunda variable local será [ebp-8].

� ···� El valor de la i-esima variable local será [ebp-<4*i>].

[ebp - <4*posición de la variable en declaración>]

Localización del contenido de las variables locales

Page 70: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 139

Generación de código para funciones

� Sin embargo, como se ha indicado en la generación de código de otras construcciones de ALFA (por ejemplo en el de las expresiones que contienen identificadores), a veces es necesario utilizar “la dirección” y no “el contenido“

� Recuérdese, por ejemplo, que para la variable global ALFA z, � La expresión para referirse al contenido es

� Pero, la expresión para la dirección es

� Las funciones no utilizan nombres explícitos para los parámetros y las variables locales, por lo que la expresión equivalente para su dirección (ebp+<desplazamiento> y ebp-<desplazamiento>, respectivamente) son incorrectas en NASM.

� NASM proporciona la instrucción lea para gestionar esta cuestión.

[_z]

Localización de la dirección de parámetros y variables globales

_z

Prácticas de Procesadores de Lenguaje 2008-2009 140

Generación de código para funciones

� En este curso se va a utilizar la siguiente sintaxis para la instrucción lea de NASM

� Donde� <registro>, es el nombre de un registro (por ejemplo eax)

� <expresión>, puede ser, por ejemplo ebp+12.

lea <registro> [<expresión>]

Localización de la dirección de parámetros y variables globales

Page 71: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 141

Generación de código para funciones

� Como resumen de estos últimos puntos, considérese el identificador ALFA z. Se utilizará las siguientes expresiones NASM para

� Acceder a su contenido� Si es una variable global

� Si es el argumento i-ésimo de una función (el primer argumento es el número 0)

� Si es la variable local i-ésima de una función (la primera variable local es la número 1)

[_z]

[ebp+<4+4*(total argumentos – i)>]

[ebp-<4*i>]

Tratamiento de identificadores

Prácticas de Procesadores de Lenguaje 2008-2009 142

Generación de código para funciones

� Acceder a su dirección� Si es una variable global

� Si es el argumento i-ésimo de una función, lo siguiente deja en el registro eax la dirección

� Si es la variable local i-ésima de una función

_z

lea eax, [ebp+<4+4*(número parámetros –i)>]

lea eax, [ebp-<4*i>]

Tratamiento de identificadores

Page 72: Generación de código - arantxa.ii.uam.esarantxa.ii.uam.es/~mdlcruz/docencia/compiladores/2008_2009/generac... · Esquema de la acción Generación de la ... Constantes reales Índice

Prácticas de Procesadores de Lenguaje 2008-2009 143

Generación de código para funciones

� Es muy importante que el alumno propague este tratamiento a todos los lugares donde pueda aparecer un identificador, exceptuando:

� Identificadores de vectores y conjuntos porque nunca pueden ser variables locales o parámetros.

� Identificadores en operaciones de acceso, reserva o liberación de memoria porque no puede haber variables locales o globales que sean punteros, y por lo tanto nunca se va a presentar el caso.

� Evidentemente identificadores de funciones.

� Por lo tanto, la propagación del tratamiento se realizará en las siguientes producciones:

asignacion: TOK_IDENTIFICADOR ‘=’ exp

lectura: TOK_SCANF TOK_IDENTIFICADOR

exp: TOK_IDENTIFICADOR

bucle: for ‘(’ TOK_IDENTIFICADOR ‘=‘ exp ‘;’ exp ‘)’ ‘{‘ sentencias ‘}’

Tratamiento de identificadores

Prácticas de Procesadores de Lenguaje 2008-2009 144

Generación de código para funciones

� En resumen, en las producciones anteriormente indicadas, se tiene que determinar para el identificador que aparece:

� Si es � una variable global

� una variable local de una función

� un argumento de una función

� Si el código que se necesita generar accederá� A su contenido

� A su dirección

Ya que cada opción necesita un tratamiento diferente.

Tratamiento de identificadores