Examen final de CL

Anuncio
Examen final de CL
Fecha de publicación de notas: 26-1-2010
Sin apuntes. Tiemp: 3h.
Enero de 2010
Fecha de revisión: 27-1-2010
Nombre y Apellidos:
[Problema 1. Análisis semántico (2.5 puntos)]
Supongamos que tenemos una versión del lenguaje CL a la que se la ha añadido el tipo básico Real, y
los punteros a cualquier tipo. El operador postfijo ^ sirve para acceder al objeto apuntado, y el operador
prefijo & permite obtener la dirección de una expresión. Para simplificar, asumiremos coerción de entero a
real (pero no en sentido inverso) cuando sea necesario. A continuación tenemos un programa en CL.
1: Program
2:
Vars
3:
x Real
4:
v Array [1..20] of Pointer to Array [2..9] of Real
5:
u Array[4..7] of Struct x Pointer to Real y Real Endstruct
6:
Endvars
7:
Procedure P(Val y Int)
8:
v[u[5].x^]^[6] := x + y
9:
Endprocedure
10:
Procedure Q(Val x Struct x Pointer to Real y Real Endstruct)
11:
Vars
12:
v Array [0..30] Of Pointer to Struct a Int b Real Endstruct
13:
Endvars
14:
P(31)
15:
Endprocedure
16:
Q(u[5])
17: Endprogram
Apartado a) [0.5 puntos] Mostrad el contenido de la tabla de sı́mbolos inmediatamente antes de analizar
semánticamente la porción del AST (Árbol de Sintaxis Abstracta) correspondiente a la lı́nea 8.
Apartado b) [0.75 puntos] Dibujad el AST de la instrucción de la lı́nea 8. Decorad (anotad) los nodos
del árbol con información del tipo de cada subexpresión y de si es o no referenciable. Usad el tipo error si
no podéis inferir un tipo, pero no propaguéis innecesariamente los errores.
Apartado c) [0.25 puntos] Numerad el AST en preordren y emitid los errores semánticos que encontréis
indicando el número del nodo del AST donde se detectan.
Sin apuntes. Tiemp: 3h.
Nombre y Apellidos:
Apartado d) [0.75 puntos] Dibujad de nuevo el AST de la instrucción de la lı́nea 8. Suponiendo visibilidad
dinámica y que se ha llegado a la lı́nea 8 después de haber ejecutado el programa principal, decorad (anotad)
los nodos del árbol con información del tipo de cada subexpresión y de si es o no referenciable. Recordad que
el lenguaje CL estandard se basa en visibilidad estática y el árbol se decora en tiempo de compilación. Ahora
se trata de decorar el AST con la información de visibilidad obtenida en tiempo de ejecución. Tal como se os
pedı́a en el apartado b), usad el tipo error si no podéis inferir un tipo, pero no propaguéis innecesariamente
los errores. Indicad claramente que ha cambiado respecto b).
Apartado e) [0.25 puntos] Manteniendo la numeración de los nodos del AST de las preguntas anteriores y
suponiendo visibilidad dinámica, emitid los errores semánticos que encontréis indicando el número del nodo
del AST donde se detectan.
Sin apuntes. Tiemp: 3h.
Nombre y Apellidos:
[Problema 2. Generación de código (2.5 puntos)]
Queremos extender el lenguaje CL para considerar el tipo PQueue que representa colas de prioridad de
tamaño máximo fijo. Por ejemplo, el siguiente programa en CL:
program
vars
Q PQueue[5] of Char
T Array[8] of Char
a Char
endvars
T[3] := ’e’
push(Q,8*2,’i’)
push(Q,100,’m’)
push(Q,24,’s’)
push(Q,97-2,T[2+1])
push(Q,25,’s’)
while (Not empty(Q)) Do
a := pop(Q)
Write(a)
EndWhile
endprogram
declarará una cola de prioridad de tamaño 5 e imprimirá los carácteres ’m’,’e’,’s’,’s’,’i’ (asumid que el tipo
Char existe en CL). Como se puede ver, la cola está ordenada por prioridad descendente. La semántica de
cada operación es:
• push(Q,expr1 ,expr2 ) inserta expr2 en Q con la prioridad especificada por expr1 . Si Q está llena esta
operación no hace nada.
• pop(Q) devuelve la cima (elemento con prioridad más alta) y lo desapila de Q. Si Q está vacı́a no hace
nada.
• empty(Q) devuelve un booleano que determina si Q está vacı́a.
PISTA: no es necesario que la implementación sea eficiente en tiempo de ejecución, por tanto evitad soluciones complejas como por ejemplo colas circulares. Se sugiere que mantengáis los elementos ordenados en
la estructura de datos de la cola de forma que las operaciones de pop y push tengan como máximo coste lineal.
Se pide1 :
1. (0.5 puntos) Proponed una forma de representar en t-código las colas de prioridad, la cual deberá
tener la información necesaria para realizar las tres operaciones utilizadas en el código anterior. Es
importante considerar que el tipo de los elementos puede ser no básico. Describid como serı́a la
generación de código para la declaración de una variable de tipo PQueue.
2. (1.25 puntos) Describid formalmente la generación para las operaciones empty y pop. En este apartado
se requiere el uso del formalismo explicado en clase (GenCode, GenLeft, GenRight) para describir cada
operación. Justificad si es necesario el uso de espacio auxiliar (aux space).
3. (0.75 puntos) Describid informalmente (en un párrafo) como serı́a la generación de código para la
operación push. Enumerad las llamadas a GenLeft y GenRight que habrı́a.
1 Recordad
que GenRight es lo mismo que GenValue y que GenLeft es lo mismo que GenAddress.
Sin apuntes. Tiemp: 3h.
Nombre y Apellidos:
[Problema 3. Optimitzación (2.5 puntos)]
El código inicial distribuido en bloques básicos se muestra a continuación:
1: s = 0
2:
3:
4:
5:
6:
f=a+c
s=s+2
p=5*s
x=c+d
if (s < 15) goto 12
7: if (g > p) goto 15
8:
9:
10:
11:
i=a+b
r=2*s
j=a*c
goto 2
12: g = c + d
13: e = a * c
14: goto 17
15: g = a + b
16: e = g + c
17: print g+e
Sin apuntes. Tiemp: 3h.
Nombre y Apellidos:
PREGUNTAS CORTAS
1. (0.5 puntos) La gramática del lenguaje de programación C incluye los tokens <, <<, > y >>. < y
> son los operadores de comparación ”menor que”y ”mayor que”, respectivamente. << y >> son,
respectivamente, los operadores de ”desplazamiento de bits a la izquierda”y ”desplazamiento de bits a
la derecha. En el lenguaje C++, que es una extensión de C, < y > se utilizan también para introducir
los parámetros de plantillas de clases (templates). Por ejemplo, el programa en C++ siguiente declara
una variable de tipo vector a partir de una plantilla predefinida denominada vector.
1:
2:
3:
4:
5:
6:
7:
#include <vector>
using namespace std;
int main() {
vector<int> v; // Declara v como un vector de enteros.
}
Partiendo del modelo de análisis léxico visto en clase, razonad porque el siguiente programa en C++
1:
2:
3:
4:
5:
6:
7:
8:
#include <vector>
using namespace std;
int main() {
vector<vector<int> > m; // Declara una matriz de nombre m
// como un vector de vectores de enteros
}
no da ningún error mientras que el siguiente programa en C++
1:
2:
3:
4:
5:
6:
7:
#include <vector>
using namespace std;
int main() {
vector<vector<int>> matriz;
}
da un error en la lı́nea 6.
2. (1 punto) Supongamos que tenemos una gramática donde IDENT y DOT son dos terminales (tokens)
y expr es un no terminal. Supongamos también que la gramática tiene una sola regla que, escrita en
PCCTS, es:
expr: IDENT (DOT expr)*
Razonad porqué la única regla de la gramática no es LL(1) mediante los conceptos de first (primero),
de follow (siguiente) y nullable (anulable) vistos en clase.
3. (1 punto) Proponed y justificad una versión mejorada del patrón de generación de código siguiente2 :
GenRight(expr1 and expr2 , ti ) ≡
GenRight(expr1 , ti ) ||
GenRight(expr2 , ti+1 ) ||
land ti ti+1 ti
2 Recordad
que GenRight es lo mismo que GenValue y que GenLeft es lo mismo que GenAddress.
Descargar