Transparencias generación de código

Anuncio
Generación de código
Índice (i)
Marina de la Cruz
Alfonso Ortega
• Definición del tipo semántico
• Ejemplo de uso del tipo semántico para la comprobación de tipos
• Declaración de variables
• Modificación de la gramática
• Deducción del tipo y del número de referencias
• Generación de código
•
•
•
•
•
•
•
•
•
Aclaraciones previas a la generación de código de sentencias
Generación e código para desreferenciación
Generación de código para expresiones
Generación de código para sentencias de asignación
Generación de código para entrada de datos
Generación de código para salida de datos
Generación de código para el principio del programa
Generación de código para el final del programa
Estructura de un programa en NASM
1
Prácticas de compiladores 2004-2005
Definición del tipo semántico (I)
• El tipo semántico (tipo de los atributos de los símbolos en el árbol de análisis
sintáctico) tiene que contemplar todos los casos posibles de valores semánticos de
cualquier símbolo del lenguaje (terminal o no terminal).
• El valor semántico de los terminales lo proporciona el analizador léxico:
• los identificadores tiene como valor semántico su lexema
• las constantes numéricas tienen como valor semántico su valor numérico
• las constantes booleanas tienen como valor semántico 0 (false) o 1 (true). No olvidar
modificar el fichero asple.l para las reglas de las constantes booleanas.
• Para la comprobación de tipos se pueden utilizar los siguientes atributos
semánticos:
• tipo: que puede ser “int”, “bool” o “error”.
• número de referencias: que puede ser 0, 1, 2, 3, …
• Posteriormente se incorporarán nuevos atributos semánticos, por ejemplo etiquetas
para generar código para las sentencias de control.
Prácticas de compiladores 2004-2005
2
Definición del tipo semántico (II)
• El tipo semántico se define con la declaración %union en el fichero de
especificación de Yacc/Bison.
• El tipo union sólo permite la utilización de uno de sus campos, pero hay símbolos
con un valor semántico múltiple, por ejemplo, un identificador de una variable tiene
un atributo para el lexema, otro para el tipo y otro para el número de referencias.
Para permitir la multiplicidad de atributos, se puede definir en la declaración
%union un sólo campo, atributos, cuyo tipo sea tipo_atributos, que es un
tipo definido como struct con tantos campos como sea necesario para
contemplar todos los casos posibles de valores semánticos de cualquier símbolo
del
lenguaje
(terminal
o
no
terminal).
El tipo_atributos lo definimos en un .h aparte.
3
Prácticas de compiladores 2004-2005
Definición del tipo semántico (III)
asple.y
• En la declaración %union del fichero
asple.y, se define un sólo campo,
atributos,
cuyo
tipo
sea
tipo_atributos (definido en el
fichero asple.h).
• Se
añaden las correspondientes
declaraciones
%token.
¿qué
símbolos terminales tienen valor
semántico?
• Se
añaden las correspondientes
declaraciones %type. Todos los no
terminales tienen valor semántico
para permitir la propagación de
atributos en el árbol de análisis.
Prácticas de compiladores 2004-2005
%{
#include “asple.h”
%}
%union
{
tipo_atributos atributos;
}
%token
%token
%token
%token
<atributos>
<atributos>
<atributos>
<atributos>
TOK_ID
TOK_NUM
TOK_FALSE
TOK_TRUE
/* resto de los tokens sin valor */
/* semántico
*/
%type <atributos> program
%type <atributos> dcl_train
%type <atributos> sm_train
/* resto de los no terminales */
...
%%
...
%%
...
4
Definición del tipo semántico (IV)
• En el fichero asple.h, se define el tipo
asple.h
tipo_atributos como un struct con los
siguientes campos :
#ifndef ASPLE_H
#define ASPLE_H
• valor semántico de los terminales:
• lexemaID: para identificadores
• valorNUM: para constantes enteras
• valorBOOL: para constantes booleanas
#define MAXID 255
#define TIPO_ERROR 0
#define TIPO_BOOL 1
#define TIPO_INT 2
• valor semántico para comprobación de tipos:
• tipo: para comprobación de tipos básicos
• nrefs: para comprobación de número de
referencias.
/* otros defines */
typedef struct
{
char lexemaID[MAXID+1];
int valorNUM;
int valorBOOL;
int tipo;
int nrefs;
}tipo_atributos;
• En el fichero asple.h, se definen:
• una constante que define la longitud máxima
de los identificadores.
• las constantes que definen los distintos tipos.
#endif
5
Prácticas de compiladores 2004-2005
Ejemplo de uso del tipo semántico para la comprobación de tipos
•
•
•
1
2
Supongamos la declaración int X;
Supongamos la declaración bool B;
Supongamos la expresión X+B
COMPROBACIÓN DE TIPOS
exp
El analizador léxico identifica un TOK_ID
y se lo comunica al analizador sintáctico
tipo
TIPO_INT
devolviendo TOK_ID y cargando su valor
nrefs
1
semántico en el campo correspondiente
yylval.atributos.lexemaID
El analizador sintáctico apila en su pila
de análisis el TOK_ID y su valor
semántico.
tipo: TIPO_INT
nrefs: 1
El analizador sintáctico reduce la
producción exp::=TOK_ID. Busca en la
tabla de símbolos y obtiene el tipo y el
número de referencias del identificador Y
calcula el tipo y el número de referencias
X
del símbolo de la parte izquierda como
Tabla de
copia de los mismos atributos del
símbolos
símbolo de la parte derecha.
3
exp
+
Prácticas de compiladores 2004-2005
tipo
TIPO_BOOL
nrefs
1
tipo: TIPO_BOOL
nrefs: 1
2
2
TOK_ID
3 Se dispone de los atributos necesarios
($1 y $3) para realizar la
comprobación de tipos.
exp
B
Tabla de
símbolos
TOK_ID
1
1
X
+
B
6
Declaración de variables (I)
Modificación de la gramática (i)
• Una lista de identificadores de variables en ASPLE tiene la forma:
idlist:
TOK_ID
| TOK_ID ‘,’ idlist
• Cada vez que se declara una variable hay que guardarla en la tabla de símbolos,
por lo tanto dicha acción hay que realizarla en las posiciones marcadas con el
símbolo :
idlist:
TOK_ID
| TOK_ID
‘,’ idlist
• Como las acciones semánticas se ejecutan cuando se reduce la regla, para
poder guardar una variable en la tabla de símbolos cuando se declara, es
necesario modificar la gramática de la siguiente manera:
idlist:
idv
| idv ‘,’ idlist
idv: TOK_ID
7
Prácticas de compiladores 2004-2005
Declaración de variables (II)
Modificación de la gramática (ii)
idv: TOK_ID
Se modificará
cuando se
implementen las
funciones
Comprobación semántica
Buscar en la tabla de símbolos el identificador
$1.lexemaID
NO
Insertar el identificador en la tabla de símbolos
clave = $1.lexemaID
clase = CLASE_VARIABLE
tipo = el que tenga
número de referencias = las que tenga
número de parámetros = 0
posición del parámetro = 0
número de variables locales = 0
posición de variable local = 0
Prácticas de compiladores 2004-2005
¿ Existe ?
SI
Mostrar mensaje de error semántico
“Identificador $1.lexemaID
duplicado”
Incrementar el número de errores
semánticos
8
Declaración de variables (III)
Deducción del tipo y del número de referencias (i)
• Una declaración de variables en ASPLE puede ser, por ejemplo:
int X, Y, Z;
La producción de la gramática:
declaration: mode idlist ‘;’
indica que lo primero que se identifica es el modo, en este caso int, y después la
lista de variables, en este caso X, Y, Z. Hay que encontrar un mecanismo
para recordar que el tipo int afecta a las tres variables X, Y, Z.
• Sugerencia:
• declarar una variable global global_tipo que se actualice con el valor correspondiente
cada vez que se reduzca una de las dos primeras producciones de mode.
• declarar una variable global global_nrefs que se inicialice a 1 cada vez que se reduzca
una de las dos primeras producciones de mode y se incremente en 1 cada vez que se
reduzca la última producción de mode.
9
Prácticas de compiladores 2004-2005
Declaración de variables (IV)
Deducción del tipo y del número de referencias (ii)
• La declaración: int X, Y, Z; es analizada de la siguiente forma:
dcl_train
declaration
mode
idlist
idv
:
|
:
:
|
|
:
|
:
declaration
declaration dcl_train
mode idlist ‘;’
TOK_BOOL
TOK_INT
TOK_REF mode
idv
idv ‘,’ idlist
TOK_ID
1 mode
int
dcl_train
9
declaration
8
idlist
2 idv
X
7
;
,
idlist
3 idv
Y
global_tipo = TIPO_INT;
global_nrefs = 1;
Prácticas de compiladores 2004-2005
,
6
idlist 5
4 idv
Z
10
Declaración de variables (V)
Deducción del tipo y del número de referencias (iii)
• La declaración: ref ref ref bool A,B; es analizada así:
dcl_train
declaration
mode
idlist
idv
:
|
:
:
|
|
:
|
:
declaration
declaration dcl_train
mode idlist ‘;’
TOK_BOOL
TOK_INT
TOK_REF mode
idv
idv ‘,’ idlist
TOK_ID
global_nrefs ++; /*4*/
dcl_train 11
declaration 10
idlist 9
4 mode
ref
global_nrefs ++; /*3*/
ref
global_nrefs ++; /*2*/
ref
3 mode
5 idv
2 mode
A
,
;
idlist
8
idlist 7
idv 6
1 mode
B
global_tipo = TIPO_BOOL;
global_nrefs = 1;
bool
11
Prácticas de compiladores 2004-2005
Declaración de variables (VI)
Generación de código (i)
• Cuando termina la sección de declaraciones de un programa APSLE, las
variables 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.
program: TOK_BEGIN dcl_train
subroutines stm_train TOK_END
• Como las acciones semánticas se ejecutan cuando se reduce la regla, para poder
generar código cuando se termina la sección de declaraciones, es necesario
modificar la gramática de la siguiente manera:
program: declaraciones subroutines stm_train TOK_END
declaraciones: TOK_BEGIN dcl_train
NOTA: MÁS ADELANTE VEREMOS QUE LA REDUCCIÓN DE LA PRODUCCIÓN
DE declaraciones LA VAMOS A APROVECHAR PARA ESCRIBIR LA
CABECERA DEL PROGRAMA Y LA CABECERA DEL SEGMENTO DE DATOS.
Prácticas de compiladores 2004-2005
12
Declaración de variables (VII)
Generación de código (ii)
begin
X int;
A bool;
ref ref int Y;
...
PROGRAMAR UNA FUNCIÓN
...
_X
0
_A
0
_Y
_ _Y
__Y
_ _ _Y
Programa ASPLE
clave
tipo
nrefs
...
X
TIPO_INT
1
...
A
TIPO_BOOL
1
...
Y
TIPO_INT
3
...
...
...
...
...
Tabla de símbolos
segment .data
_X dd 0
_A dd 0
_ _ _Y dd 0
_ _ Y dd _ _ _Y
_ Y dd _ _ Y
...
___Y
Programa NASM
0
MEMORIA
Prácticas de compiladores 2004-2005
13
Aclaraciones previas a la generación de código de sentencias
• El código que vamos a generar es para una máquina a pila.
• Cuando se apile un variable, se apilará siempre su dirección, no su contenido (en
NASM es el nombre de la variable)
• Cuando se apile una constante, se apilará su valor.
• Es necesario un mecanismo que asegure que las etiquetas que se utilicen el en
programa ensamblador sean únicas.
• Un posible mecanismo es utilizar una variable entera global, etiqueta, que se
incremente cada vez que se utiliza.
Prácticas de compiladores 2004-2005
14
Generación de código para desreferenciación (I)
dereference :
TOK_DEREF
TOK_ID
Comprobación semántica
Buscar en la tabla de símbolos el elemento
con clave $2.lexemaID
Se modificará
cuando se
implementen las
funciones
SI
NO
SI
¿Nº refs <2 ?
Cálculo de atributos
$$.tipo = elemento.tipo;
$$.nrefs = elemento.nrefs-1;
NO
¿existe ?
Mostrar mensaje de error
“Error de indirección”
Mostrar mensaje de error
“Identificador no declarado”
Incrementar el número de errores
semánticos
Incrementar el número de errores
semánticos
Generación de código
push dword [_elemento.clave]
15
Prácticas de compiladores 2004-2005
Generación de código para desreferenciación (II)
dereference :
NO
Cálculo de atributos
$$.tipo = $2.tipo;
$$.nrefs = $2.nrefs-1;
TOK_DEREF dereference
¿ $2.Nº refs <2 ?
SI
Mostrar mensaje de error
“Error de indirección”
Incrementar el número de errores
semánticos
Generación de código
pop dword eax
push dword [eax]
Prácticas de compiladores 2004-2005
16
Generación de código para expresiones (I)
• Las ideas básicas son:
• Hacer comprobación de tipos (en los puntos adecuados), por ejemplo, no se pueden
sumar variables de distinto tipo.
• Hacer otras comprobaciones semánticas si es necesario, por ejemplo, comprobar si una
variable ha sido declarada.
• Generar código haciendo uso de la pila, desapilando los operadores y apilando los
resultados de las operaciones.
17
Prácticas de compiladores 2004-2005
Generación de código para expresiones (II)
exp
:
|
|
|
|
|
|
|
|
compare
:
|
|
constant
:
|
bool_constant :
|
int_constant :
Prácticas de compiladores 2004-2005
exp + exp
exp - exp
exp * exp
- exp
TOK_ID
constant
( exp )
( compare )
dereference
exp = exp
exp <= exp
exp > exp
bool_constant
int_constant
TOK_TRUE
TOK_FALSE
TOK_NUM
18
Generación de código para expresiones (III)
int_constant : TOK_NUM
CÁCULO DE ATRIBUTOS
$$
atributos
GENERACIÓN DE CÓDIGO
$1
atributos
lexemaID
lexemaID
valorNUM
valorNUM
valorBOOL
valorBOOL
tipo
nrefs
88
88
tipo
TIPO_INT
nrefs
0
PILA
Fichero ensamblador
push dword $1.valorNUM
$$.tipo = TIPO_INT;
$$.nrefs = 0;
19
Prácticas de compiladores 2004-2005
Generación de código para expresiones (IV)
bool_constant : TOK_FALSE
CÁCULO DE ATRIBUTOS
$$
atributos
GENERACIÓN DE CÓDIGO
$1
atributos
lexemaID
lexemaID
valorNUM
valorNUM
valorBOOL
valorBOOL
tipo
nrefs
TIPO_BOOL
0
0
tipo
0
nrefs
PILA
$$.tipo = TIPO_BOOL;
$$.nrefs = 0;
Prácticas de compiladores 2004-2005
Fichero ensamblador
push dword $1.valorBOOL
20
Generación de código para expresiones (V)
bool_constant : TOK_TRUE
CÁCULO DE ATRIBUTOS
$$
GENERACIÓN DE CÓDIGO
atributos
$1
atributos
lexemaID
lexemaID
valorNUM
valorNUM
valorBOOL
valorBOOL
tipo
1
tipo
TIPO_BOOL
nrefs
1
nrefs
0
PILA
Fichero ensamblador
push dword $1.valorBOOL
$$.tipo = TIPO_BOOL;
$$.nrefs = 0;
21
Prácticas de compiladores 2004-2005
Generación de código para expresiones (VI)
constant : int_constant
CÁCULO DE ATRIBUTOS
atributos
$$
$1
atributos
lexemaID
lexemaID
valorNUM
valorNUM
valorBOOL
valorBOOL
tipo
nrefs
TIPO_INT
tipo
nrefs
0
TIPO_INT
0
$$.tipo = $1.tipo;
$$.nrefs = $1.nrefs;
Prácticas de compiladores 2004-2005
22
Generación de código para expresiones (VII)
constant : bool_constant
CÁCULO DE ATRIBUTOS
atributos
$$
atributos
$1
lexemaID
lexemaID
valorNUM
valorNUM
valorBOOL
valorBOOL
tipo
nrefs
tipo
TIPO_BOOL
nrefs
0
TIPO_BOOL
0
$$.tipo = $1.tipo;
$$.nrefs = $1.nrefs;
23
Prácticas de compiladores 2004-2005
Generación de código para expresiones (VIII)
exp : constant
CÁCULO DE ATRIBUTOS
atributos
$$
$1
atributos
lexemaID
lexemaID
valorNUM
valorNUM
valorBOOL
valorBOOL
tipo
El tipo
tipo
El tipo
nrefs
Nº refs
nrefs
Nº refs
$$.tipo = $1.tipo;
$$.nrefs = $1.nrefs;
Prácticas de compiladores 2004-2005
24
Generación de código para expresiones (IX)
exp : ‘(’ exp ‘)’
CÁCULO DE ATRIBUTOS
atributos
$$
atributos
$1
lexemaID
lexemaID
valorNUM
valorNUM
valorBOOL
valorBOOL
tipo
El tipo
tipo
El tipo
nrefs
Nº refs
nrefs
Nº refs
$$.tipo = $2.tipo;
$$.nrefs = $2.nrefs;
25
Prácticas de compiladores 2004-2005
Generación de código para expresiones (X)
exp : ‘(’ compare ‘)’
CÁCULO DE ATRIBUTOS
atributos
$$
$1
atributos
lexemaID
lexemaID
valorNUM
valorNUM
valorBOOL
valorBOOL
tipo
El tipo
tipo
El tipo
nrefs
Nº refs
nrefs
Nº refs
$$.tipo = $2.tipo;
$$.nrefs = $2.nrefs;
Prácticas de compiladores 2004-2005
26
Generación de código para expresiones (XI)
exp : dereference
CÁCULO DE ATRIBUTOS
atributos
$$
atributos
$1
lexemaID
lexemaID
valorNUM
valorNUM
valorBOOL
valorBOOL
tipo
El tipo
tipo
El tipo
nrefs
Nº refs
nrefs
Nº refs
$$.tipo = $1.tipo;
$$.nrefs = $1.nrefs;
27
Prácticas de compiladores 2004-2005
Generación de código para expresiones (XII)
exp : TOK_ID
Se modificará
cuando se
implementen las
funciones
Comprobación semántica
Buscar en la tabla de símbolos el elemento con clave
$1.lexemaID
SI
NO ¿es función?
Cálculo de atributos
¿existe?
NO
SI
Mostrar mensaje de error
“Identificador no declarado”
Mostrar mensaje de error
“llamada a función sin
parámetros”
$$.tipo = elemento.tipo;
$$.nrefs = elemento.nrefs;
Incrementar el número de errores
semánticos
Incrementar el número de errores
semánticos
Cálculo de atributos
Generación de código
push dword _elemento.clave
Prácticas de compiladores 2004-2005
Cálculo de atributos
$$.tipo = TIPO_ERROR;
$$.nrefs = 0;
$$.tipo = TIPO_ERROR;
$$.nrefs = 0;
28
Generación de código para expresiones (XIII)
exp : exp1 + exp2
Comprobación de tipos
SI
exp2
exp1
¿Tipos OK ?
NO
Comprobación de Nº de referencias
PILA
SI
¿Nº refs OK ?
Generación de código
pop dword edx
SI $3.nrefs>0
mov edx , [edx]
pop dword eax
SI $1.nrefs>0
mov eax , [eax]
add eax,edx | or eax,edx
push dword eax
NO
Mostrar mensaje de error
“La aritmética de punteros no está
permitida ”
Mostrar mensaje de error
“La suma/OR requiere tipos
básicos iguales”
Incrementar el número de errores
semánticos
Incrementar el número de errores
semánticos
29
Prácticas de compiladores 2004-2005
Generación de código para expresiones (XIV)
exp : exp1 - exp2
exp : exp1 * exp2
• La generación de código para las producciones de resta y multiplicación de
expresiones es similar a la generación de código para la suma de expresiones
descrita en la transparencia anterior.
Prácticas de compiladores 2004-2005
30
Generación de código para expresiones (XV)
exp : ‘-’ exp %prec MENOSU
Comprobación de Nº de referencias
SI
exp
Cálculo de atributos
$$.tipo = $2.tipo;
$$.nrefs = 0;
PILA
Mostrar mensaje de error
“La aritmética de punteros no está
permitida ”
Generación de código
pop dword eax
SI $2.nrefs>0
mov eax , [eax]
TIPO_BOOL
¿Tipo?
Incrementar el número de errores
semánticos
TIPO_INT
Generación de código
not_false#:
fin_not#
NO
¿OK ?
Generación de código
neg eax
or eax,eax
jz near not_false#
mov dword eax,0
jmp near fin_not#
mov dword eax,1
No olvidar incrementar
el número de etiqueta
Generación de código
push dword eax
31
Prácticas de compiladores 2004-2005
Generación de código para expresiones (XVI)
compare : exp1 ‘=’ exp2
Comprobación de tipos
SI
¿Tipos OK ?
NO
Comprobación de Nº de referencias
exp2
exp1
SI
PILA
¿Nº refs
OK ?
NO
Mostrar mensaje de error
“La comparación de igualdad
requiere tipos básicos int”
Incrementar el número de errores
semánticos
Generación de código
pop dword edx
SI $3.nrefs>0
mov edx , [edx]
pop dword eax
SI $1.nrefs>0
mov eax , [eax]
cmp eax, edx
jne near no_igual#
push dword 1
jmp near fin_igual#
no_igual#:
push dword 0
fin_igual#:
Prácticas de compiladores 2004-2005
Mostrar mensaje de error
“La comparación de punteros no
está permitida ”
Incrementar el número de errores
semánticos
No olvidar incrementar
el número de etiqueta
32
Generación de código para expresiones (XVII)
compare : exp1 ‘<=’ exp2
compare : exp1 ‘>’ exp2
• La generación de código para las producciones de comparación “<=“ y “>” de
expresiones es similar a la generación de código para la comparación de igualdad
de expresiones descrita en la transparencia anterior.
33
Prácticas de compiladores 2004-2005
Generación de código para sentencias de asignación (I)
asgt_stm :
TOK_ID ‘:=’ exp
Comprobación semántica
Buscar en la tabla de símbolos el elemento
con clave $1.lexemaID
SI
¿existe ?
NO
Comprobación de tipos
SI
¿Tipos OK ?
Comprobación de Nº de referencias
SI
¿Nº refs
OK ?
Generación de código
DISTIGUIR
CASOS
(ver página siguiente)
NO
Mostrar mensaje de error
“Identificador no declarado”
Incrementar el número de errores
semánticos
NO
Mostrar mensaje de error
“Asignación incompatible por el
número de referencias”
Mostrar mensaje de error
“Asignación incompatible por los
tipos”
Incrementar el número de errores
semánticos
Incrementar el número de errores
semánticos
Prácticas de compiladores 2004-2005
34
Generación de código para sentencias de asignación (II)
asgt_stm :
TOK_ID ‘:=’ exp
exp
PILA
CASO 2
Parte izquierda y parte derecha con el mismo
número de referencias
CASO 1
Parte izquierda 1 referencia y parte derecha 0
referencias
Generación de código
Generación de código
pop dword eax
mov dword eax, [eax]
mov dword [_elemento.clave],eax
pop dword eax
mov dword [_elemento.clave],eax
Se modificará
cuando se
implementen las
funciones
35
Prácticas de compiladores 2004-2005
Generación de código para sentencias de asignación (III)
asgt_stm: dereference ‘:=’ exp
Comprobación de tipos
SI
¿Tipos OK ?
NO
Comprobación de Nº de referencias
SI
¿Nº refs
OK ?
Generación de código
DISTIGUIR
CASOS
(ver página siguiente)
Prácticas de compiladores 2004-2005
NO
Mostrar mensaje de error
“Asignación incompatible por el
número de referencias”
Mostrar mensaje de error
“Asignación incompatible por los
tipos”
Incrementar el número de errores
semánticos
Incrementar el número de errores
semánticos
36
Generación de código para sentencias de asignación (IV)
asgt_stm: dereference ‘:=’ exp
CASO 2
Parte izquierda y parte derecha con el mismo
número de referencias
CASO 1
Parte izquierda 1 referencia y parte derecha 0
referencias
Generación de código
Generación de código
pop
pop
mov
mov
pop dword eax
pop dword edx
mov dword [edx],eax
dword
dword
dword
dword
eax
edx
eax, [eax]
[edx],eax
exp
dereference
PILA
37
Prácticas de compiladores 2004-2005
Generación de código para entrada de datos (I)
transput_stm : TOK_INPUT TOK_ID
Comprobación semántica
Buscar en la tabla de símbolos el elemento
con clave $2.lexemaID
SI
NO
NO
¿nrefs>1 ?
Generación de código
DISTIGUIR DOS
CASOS POR TIPOS
(ver página siguiente)
Prácticas de compiladores 2004-2005
¿Clase función?
¿existe ?
Se modificará
cuando se
implementen las
funciones
NO
SI
SI
Mostrar mensaje de error
“No se admiten referencias
en sentencia input ”
Mostrar mensaje de error
“Identificador erróneo
en sentencia input ”
Incrementar el número de
errores semánticos
Incrementar el número de
errores semánticos
Mostrar mensaje de error
“Identificador no
declarado”
Incrementar el número de
errores semánticos
38
Generación de código para entrada de datos (II)
transput_stm : TOK_INPUT TOK_ID
Se modificará
cuando se
implementen las
funciones
Apilar la dirección
donde guardar la
lectura
(requerimiento io)
Generación de código
push dword _elemento.clave
TIPO_BOOL
TIPO_INT
¿Tipo?
Generación de código
Generación de código
call lee_booleano
add esp, 4
call lee_entero
add esp, 4
39
Prácticas de compiladores 2004-2005
Generación de código para salida de datos
transput_stm : TOK_OUTPUT exp
NO
SI
SI
¿nrefs>1 ?
¿nrefs=1?
Mostrar mensaje de error
“No se admiten referencias
en sentencia output ”
Generación de código
pop eax
mov eax, [eax]
push dword eax
Incrementar el número de
errores semánticos
TIPO_BOOL
$2.tipo
TIPO_INT
Generación de código
Generación de código
call imprime_booleano
call imprime_entero
Generación de código
add esp, 4
call imprime_fin_linea
Prácticas de compiladores 2004-2005
40
Generación de código para el principio del programa (I)
• Un programa nasm comienza con una cabecera para portabilidad. Esta cabecera
se puede escribir “aprovechando” la producción declaraciones en la que se
escribe la tabla de símbolos ya que, a continuación de la cabecera se sitúa el
segmento de datos.
• A continuación del segmento de datos viene el de código, que contiene:
• una sección constante que también se puede escribir “aprovechando” la producción
declaraciones.
• Las funciones
• El programa principal
• La producción declaraciones quedaría:
declaraciones: TOK_BEGIN dcl_train
{
escribirCabecera(ficheroEnsamblador);
escribirTablaSimbolos(ficheroEnsamblador,&tablaSimbolos);
escribirSegmentoCodigo(ficheroEnsamblador);
}
41
Prácticas de compiladores 2004-2005
Generación de código para el principio del programa (II)
• La sección de funciones del programa ASPLE genera para cada función el código
ensamblador correspondiente. Pero una vez que terminan las funciones en el
programa ensamblador, comienza la rutina main, y para escribir su etiqueta de
comienzo se puede utilizar la producción lambda del no terminal subroutines, ya
que esta es la última producción que se reduce antes del comienzo de la sección
de sentencias del programa ASPLE. La producción subroutines quedaría:
subroutines: subroutine subroutines {}
|
{
escribirInicioMain(ficheroEnsamblador);
}
;
void escribirInicioMain(FILE* fpasm)
{
fprintf(fpasm, "; -----------------------\n");
fprintf(fpasm, "; PROCEDIMIENTO PRINCIPAL\n");
fprintf(fpasm, "; -----------------------\n");
fprintf(fpasm, "main:\n");
}
Prácticas de compiladores 2004-2005
42
Generación de código para el final del programa
• Un programa nasm termina con la sentencia ret. Esta sentencia se puede escribir
cuando se reduzca la producción del axioma, invocando a la función
escribirFin del módulo de soporte generacion.c. (La producción del axioma
se modificó previamente para escribir la tabla de símbolos al terminar la sección
declarativa).
program: declaraciones subroutines stm_train TOK_END
{
escribirFin(ficheroEnsamblador);
}
;
void escribirFin(FILE* fpasm)
{
fprintf(fpasm, "\n");
fprintf(fpasm, "\tret");
}
43
Prácticas de compiladores 2004-2005
Estructura de un programa en NASM
%ifdef TIPO_MSVC
%define main _main
%endif
segment .data
...
...
segment .text
global main
extern lee_entero, imprime_entero ...
_fun1:
...
...
ret
_fun2:
...
...
ret
main:
...
...
ret
Prácticas de compiladores 2004-2005
Cabecera para portabilidad
Segmento de datos
Segmento de código
44
Descargar