El objetivo de esta práctica es finalizar la construcción del compilador para el lenguaje de programación ALFA descrito en las prácticas anteriores. Para ello, se debe tomar como punto de partida el analizador sintáctico desarrollado en la práctica 2, que ya incluye el analizador morfológico de la práctica 1. El compilador final requerido deberá traducir programas escritos en lenguaje ALFA a sus equivalentes en ensamblador, es decir la entrada al compilador será texto que contenga un programa ALFA y la salida del compilador será texto que contenga instrucciones en lenguaje ensamblador.
En esta descripción sólo se mencionarán los aspectos en los que el lenguaje de programación ALFA pueda diferir de otros lenguajes de programación de alto nivel. Se sobreentienden por tanto reglas semánticas como que las variables deben ser definidas antes de ser utilizadas, o que deben ser únicas dentro de su ámbito de aplicación.
Cualquier duda respecto a la resolución de algún aspecto de la semántica del lenguaje ALFA, será resuelta por el profesor de prácticas.
En el lenguaje de programación ALFA, el nivel de indirección de un dato es el número de accesos a memoria necesarios para obtener el valor del dato.
Una constante (entera o lógica) tiene un nivel de indirección igual a 0.
Una variable de clase
escalar tiene un nivel de indirección igual a 1. Por ejemplo,
las variables x y b definidas como:
ENTERO x;
LOGICO b;
Una variable de clase
puntero tiene un nivel de indirección igual a 1 más el
número de almohadillas que aparecen en su declaración.
Por ejemplo, de las siguientes declaraciones, se deduce que la
variable px tiene un nivel de indirección igual a 2, y la
variable ppb tiene un nivel de indirección igual a
3:
ENTERO # px;
LOGICO ## ppb;
Los elementos de las variables de clase vector de una o dos dimensiones tienen un nivel de indirección igual a 1 (como las variable de clase escalar)
El acceso (->) a
un dato tiene un nivel de indirección una unidad menos que el
nivel de indirección del dato accedido. Por ejemplo, si se
define la variable ppx como:
ENTERO ## ppx;
la expresión de acceso ->ppx tiene un nivel de indirección igual a 2
la expresión de acceso ->->ppx tiene un nivel de indirección igual a 1
La operación
de obtención de la dirección (<-) de un dato tiene
un nivel de indirección una unidad más que el nivel de
indirección del dato. Por ejemplo, si se define la variable
ppx como:
ENTERO ## ppx;
la expresión <-ppx tiene un nivel de indirección igual a 4
Las expresiones aritmético-lógicas sólo pueden operar con datos de un único tipo:
tipo ENTERO para las expresiones aritméticas
tipo LOGICO para las expresiones lógicas
Todas las variables empleadas en la expresión y el resultado tienen que ser del mismo tipo.
Los operadores disponibles para operaciones aritméticas y su correspondiente significado son los siguientes:
+
,
suma
-
,
resta
*
,
multiplicación
/
,
división
– (unario), cambio de signo
Los operadores disponibles para operaciones lógicas y su correspondiente significado son los siguientes:
O, operación lógica disyunción
Y, operación lógica conjunción
NO, operación lógica de negación.
No se permite aritmética de punteros.
Las comparaciones sólo pueden operar con datos de tipo ENTERO, siendo el resultado de la expresión de tipo LOGICO.
Las operadores tienen el significado habitual:
==, operación de igualdad
!=, operación de desigualdad
<=, el primer operando menor o igual que el segundo
>=, el primer operando mayor o igual que el segundo
<, el primer operando menor que el segundo
>, el primer operando mayor que el segundo
No está permitida la comparación de punteros.
Para que una asignación sea válida, las partes izquierda y derecha de la asignación deben cumplir las siguientes condiciones:
Los tipos de dato de la parte izquierda y derecha deben ser iguales.
Las partes izquierda y derecha de la asignación deben tener el mismo nivel de indirección, o bien, la parte derecha un nivel de indirección igual a 0 y la parte izquierda igual a 1.
Las variables de clase puntero tienen la semántica habitual de los lenguajes de programación, con las siguientes peculiaridades:
No se permite operaciones aritméticas entre punteros.
Una expresión en la que se accede a lo apuntado por un puntero (con el operador “->”) puede aparecer en el mismo lugar en el que aparecería el objeto resultante de la operación.
La operación de acceso a la dirección de un identificador (con el operador “<-”), sólo puede aparecer en sentencias de asignación.
La palabras reservadas del lenguaje RESERVAR y LIBERAR se utilizan respectivamente para asignar a un puntero memoria para almacenar un nuevo valor y para liberarla. La sintaxis es la especificada en la gramática.
Las variables de tipo VECTOR tienen la semántica habitual de los lenguajes de programación con las siguientes peculiaridades:
Sólo pueden contener datos de tipo básico (ENTERO o LOGICO).
Sólo son de una o dos dimensiones.
Para indexar los elementos de un vector de una dimensión se utiliza [ <exp> ] a continuación del nombre del vector. Los corchetes deberán contener en su interior una expresión de tipo ENTERO, con un valor entre 0 y el tamaño definido para el vector menos 1 (ambos incluidos). En ningún caso podrá aparecer en el lugar de la expresión que encierran los corchetes una variable de tipo puntero, aunque sí el acceso al contenido de dicha variable, siempre que dicho contenido sea de tipo ENTERO.
Para indexar los elementos de un vector de dos dimensiones se utiliza [ <exp>,<exp> ] a continuación del nombre del vector. Las restricciones aplicables a las expresiones encerradas por los corchetes son las mismas que se aplican en el caso de los vectores de una dimensión.
Tras la declaración de una variable de tipo VECTOR, ésta aparecerá siempre indexada, y se utilizará de la misma manera que cualquier otro objeto que pueda ocupar su misma posición.
Los resultados de las condiciones de las sentencias SI-ENTONCES, SI-ENTONCES-SINO y MIENTRAS-HACER deben ser de tipo LOGICO.
El identificador que aparece después de la palabra reservada DESDE tiene que ser declarado de tipo entero y con un nivel de indirección igual a 1.
Las dos expresiones que aparecen en la declaración del bucle deben de ser de tipo entero y con nivel de indirección no superior a 1.
El grupo de sentencias situado entre las palabras reservadas HACER y FIN sólo se ejecuta si el valor de la segunda expresión es mayor o igual al valor de la primera expresión.
Cuando termina la ejecución del bucle, el identificador contiene el valor de la segunda expresión.
La expresión que aparece encerrada entre paréntesis detrás de las palabra reservada SELECCIONAR debe de ser de tipo entero y con nivel de indirección 0 ó 1.
No está permitido el anidamiento de esta sentencia de control de flujo.
Cuando termina la ejecución de un caso (estándar o defecto), termina la ejecución de la sentencia de control de flujo (a diferencia de la sentencia "switch" de C en la que es posible la ejecución de varios casos)
Si va a necesitar acotar alguna de las características del lenguaje para la realización del compilador guíese por las siguientes indicaciones:
Los identificadores deben ser de, como mucho, 50 caracteres de largo.
Las variables de tipo puntero no podrán superar 15 niveles de indirección.
Las dimensiones de los vectores no podrán exceder nunca el valor de 64.
El compilador debe traducir los programas válidos escritos en ALFA a los correspondientes programas en ensamblador nasm directamente, es decir, no se utilizará en la práctica ninguna representación intermedia.
Esta generación de código se realizará mediante la asociación de acciones a la reducción de las reglas de la gramática, descrita previamente en el analizador sintáctico.
En el laboratorio, se explicarán conceptos básicos de nasm para la realización de la práctica.
La gestión de la entrada y salida (instrucciónes LEER y ESCRIBIR) así como de la asignación y liberación de memoria (instrucciones RESERVAR y LIBERAR) se realizará mediante las librerías auxiliares disponibles en la página web de prácticas. El profesor de prácticas indicará el procedimiento a seguir para utilizar dichas librerías.
El compilador deberá cumplir los siguientes requisitos:
Nombre del
programa fuente que contenga la rutina principal (main) del
compilador: alfa.c
El ejecutable que contenga el compilador se llamará alfa y se le invocará de la siguiente manera:
alfa [ <nombre fichero entrada> [<nombre fichero salida>] ]
Es decir, el programa se puede llamar:
Con 0 argumentos, entonces se utilizan la entrada y la salida estándares.
Con 1 argumento, entonces se utiliza la salida estándar y el argumento como nombre del fichero de entrada.
Con 2 argumentos, entonces el primero se interpreta como el nombre del fichero de entrada y el segundo como el nombre del fichero de salida.
Descripción del fichero de entrada y de salida:
El fichero de entrada contiene un programa escrito en lenguaje ALFA.
El fichero de salida contiene un programa escrito en lenguaje ensamblador interpretable por la herramienta nasm.
El fichero empaquetado (.zip) que se debe entregar deberá complir los siguientes requisitos:
El fichero zip deberá contener todos los fuentes (ficheros .h y .c) necesarios para resolver el problema.
El fichero zip deberá conenter las librerías de entrada y salida así como de gestión de memoria disponibles en la web de prácticas.
El fichero zip deberá contener un fichero Makefile compatible con la herramienta make que para el objetivo all genere el ejecutable de nombre alfa.
El nombre del fichero zip será p3_gg_pp.zip, donde gg corresponde al grupo de prácticas y pp al número de pareja. Por ejemplo, el fichero comprimido de la pareja 5 del grupo Ma se llamará p3_ma_05.zip
Las prácticas que, tras eliminar cualquier fichero con extensión .o así como el propio ejecutable alfa (en el caso de que dichos ficheros aparezcan en la entrega), no compilen mediante el comando “make all” , no generen el ejecutable alfa tras la ejecución de dicho comando o no cumplan los requisitos descritos en este enunciado se considerarán como no entregadas.
La evaluación de los conocimientos
adquiridos por el alumno durante el desarrollo de esta tercera práctica se hará
mediante una prueba individual realizada en una sesión de laboratorio en los
días que se detallan en la lista adjunta.
La normativa de evaluación que se
aplicará está publicada en la página web del laboratorio de Procesadores de
Lenguaje.
Grupos del lunes: antes del lunes 26 de mayo de 2008
Grupos del martes: antes del martes 27 de mayo de 2008
Grupos del miércoles: antes del miércoles 28 de mayo de 2008
Grupos del jueves: antes del jueves 29 de mayo de 2008
Grupos del viernes: antes del viernes 30 de mayo de 2008