Examen final de CL Fecha de publicación de notas: 25-6-2009 Sin apuntes. Tiemp: 3h. Junio de 2009 Fecha de revisión: 26-6-2009 Nombre y Apellidos: [Problema 1. Análisis semántica (2.5 puntos)] Supongamos que tenemos una versión del lenguaje CL donde se permiten definiciones de tipo, entre types y endtypes. Además se 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. A continuación tenenos una serie de declaraciones de tipos, variables y una función f, y debajo el AST correspondiente a una instrucción. program types t1 array [29] of t2 t2 pointer to struct a int z bool endstruct t3 array [23] of real t4 array [100] of pointer to real endtypes vars S struct c bool b pointer to t1 endstruct A t3 i int endvars function f(ref f real) return t4 ... endfunction := (*) endprogram Apartado a) [1 punto] Escribid arriba ((*), en CL) la instrucción correspondiente al AST, y 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 podeis inferir un tipo, pero no propaguéis innecesariamente los errores. := (22) [ ] (21) . (11) ^ (9) a (10) A (12) − (20) 1 (19) ^ (18) [ ] (8) [ ] (17) . (7) ^ (4) ( ) (15) A (5) . (3) S (1) b (2) f (16) i (6) f (13) function(<ref real>, name(t4)) no−ref 7 (14) Apartado b) [0.5 puntos] Emitid los errores semánticos que encontréis localizándolos con el número de nodo donde se detectan. Apartado c) [0.5 puntos] Escribid las reglas de inferencia de tipo correpondientes a la expresión de acceso con puntero y a la expresión de cálculo de la dirección de una expresión: tipo( expr1 ^ ) = ... si tipo( expr1 ) = . . . tipo( & expr1 ) = ... si . . . Apartado d) [0.5 puntos] Enumerad para cada una de ellas los posibles errores semánticos que pueden producirse en el typecheck de estas dos formas de expresión. Sin apuntes. Tiemp: 3h. Nombre y Apellidos: [Problema 2. Generación de código (2.5 puntos)] Se desea ampliar el lenguaje CL para incorporar las instrucciones break y continue del lenguaje C. Estas instruciones estan asociadas a un bucle. Para aquellos que no las conozcan, describimos informalmente su semántica: • break fuerza la finalización del bucle más interno en el que se encuentra, • continue fuerza el salto de las instrucciones siguientes a la instrucción, de forma que se vuelve a evaluar la condición del bucle. Por ejemplo en el siguiente programa: program vars i Int endvars i := 0 while i < 10 do i := i+1 if i < 5 then continue endif writeln(i) if i > 7 then break endif endwhile endprogram se imprimirán los números 5, 6, 7 y 8. Se pide: • (1.5 punto) Especifica la generación de código (función GenCod) para las instrucciones break y continue. Se asume ya dada la generación de GenRight y GenLeft, y por tanto las podeis usar sin definirlas. • (0.5 puntos) Escribe el t-código correspondiente al programa de ejemplo. • (0.5 puntos) Describe informalmente las modificaciones que habrı́a que hacer en las otras fases del compilador (desde análisis léxico a optimización). Sin apuntes. Tiemp: 3h. Nombre y Apellidos: [Problema 3. Optimitzación (2.5 puntos)] Considera el siguiente código de 3-direcciones: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: m = 0 v = 0 t = x+4 if v >= n goto 19 r = v s = 0 k = 0 if r >= n goto 17 k = k+1 z = k*4 q = M[z] s = s+q if s <= m goto 15 m = s r = r+1 goto 8 v = v+1 goto 3 return m • Calcula los bloques básicos y dibuja el grafo de control de flujo asociado. • Calcula el árbol de dominadores. • Identifica las aristas de retroceso y los bucles en el grafo de control de flujo. • Realiza las optimizaciones en los bucles (asume que todas las variables están vivas al final del código) Sin apuntes. Tiemp: 3h. Nombre y Apellidos: 4 PREGUNTAS CORTAS 1. (0.75 puntos) ¿Por qué una gramática ambigua no puede ser una gramática LL(1)? Da un ejemplo de gramática explicando por qué no lo es. 2. (0.75 puntos) A continuación teneis un algoritmo de análisis léxico, que dada una secuencia de caracteres en el vector IN[1 .. m], y un conjunto de n expresiones regulares (n DFA’s con función de transición δi ), calcula la partición de IN donde cada elemento cumple que: (i) es una palabra del lenguaje de alguna de las expresiones regulares, (ii) es el prefijo más largo posible de lo que falta por particionar, y (iii) en caso de que el prefijo más largo forme parte del lenguaje de dos o más expresiones regulares se elije la que tiene menor ı́ndice. p := f := 1; l := 0; ∀i : 1 ≤ i ≤ n : qi := Inii ; while p ≤ m do ∀i : 1 ≤ i ≤ n : qi := δi ( qi , IN[p] ); p :=p + 1; if ∃ i : 1 ≤ i ≤ n : qi ∈ Fi then l := p − 1; a = smallest i such that qi ∈ Fi ; elseif ∀ i : 1 ≤ i ≤ n : qi ∈ Erri then if l ≥ f then Generate token of type a with word IN[f.. l] p := f := l + 1; l := f − 1; ∀i : 1 ≤ i ≤ n : qi := Inii ; else Lexical error endif endif endwhile if l < f then Lexical error endif // Estados iniciales // Transición de estados // Estado f inal // Estados pozo Explicar por qué este algoritmo de análisis léxico no es lineal en la longitud de la entrada, y poner un ejemplo de expresiones regulares y de una entrada IN donde se demuestre. ¿Cuál es el coste asintótico (caso peor) de este algoritmo? Pon otro ejemplo —si el anterior no lo es— donde esa situación se dé. 3. (0.5 puntos) Se desea obtener una gramática en PCCTS para reconocer grafos. En la siguiente figura se presenta un grafo de ejemplo (izquierda), la representación en un fichero (centro) y el AST que se desea obtener (derecha, sólo se muestra una parte del AST). 5 1 2 3 GRAF0 4 nodes 1 2 3 4 5 arc 1 to 5 3 4 arc 5 to 2 arc 2 to 3 1 arc 4 to 2 REPRESENTACION FICHERO graf arcs nodes 1 2 AST ... 1 5 5 3 4 ... 2 Se pide: 1) Escribe la gramática en PCCTS para que construya el AST a partir de un fichero de entrada como el del ejemplo, 2) Describe los errores léxicos/sintácticos que se podrı́an detectar. 4. (0.5 puntos) Enumera los aspectos comunes y diferencias entre un intérprete y un compilador.