Teorı́a de Lenguajes Práctica 8 (Parsers Descendentes) 1. Para cada Gi , decidir si es LL(1). En caso contrario dar una gramática que sea LL(1) y genere L(Gi ). En ambos casos indicar los sı́mbolos directrices de cada producción de la gramática resultante. (a) G1 = h{S, A}; {a, b}; P1 ; Si, con P1 : S −→ aAS | b A −→ a | bSA (b) G2 = h{S}; {a, b}; P2 ; Si, con P2 : S −→ aaSbb | a | λ (c) G3 = h{S, A, B}; {a, b}; P3 ; Si, con P3 : S −→ A | B A −→ aA | λ B −→ bB | λ (d) G4 = h{S, A}; {a, b}; P4 ; Si, con P4 : S −→ aAaa | bAba A −→ b | λ (e) G5 = h{S}; {a}; P5 ; Si, con P5 : S −→ aS | a (f) G6 = h{S, A}; {a, d}; P6 ; Si, con P6 : S −→ Aa | a A −→ Sd | d (g) G7 = h{S, A}; {a, c}; P7 ; Si, con P7 : S −→ A −→ 1 Sc | cA | λ aA | a (h) G8 = h{S, A, L}; {(, ), , , f, x}; P8 ; Si, con P8 : S −→ A −→ L −→ fA (L) x | x, L | S (i) G9 = h{S, A}, {a, b}, P9 , Si, con P9 : −→ −→ S A SAa | Aa Aa | b (j) G10 = h{S, T }, {a, b}, P10 , Si, con P10 : S T −→ −→ b | Sb | T b aT b | ab 2. A veces es posible utilizar un parser predictivo para reconocer el lenguaje de una gramática que tiene conflictos LL(1). Esto puede realizarse resolviendo los conflictos en favor de alguna de las producciones involucradas. Por ejemplo, la siguiente gramática representa el problema del if − then − else: G1 = h{S, E, C}; {if, then, sent, else, cond}; P ; Si S E C −→ −→ −→ if C then S E | sent else S | λ cond (a) Mostrar que G1 no es LL(1). (b) Indicar los sı́mbolos directrices de cada producción. (c) Para los terminales que sean sı́mbolo directriz de mas de una producción del mismo no terminal, asignárselos a una sola de las producciones de manera que en el árbol de derivación resultante cada else quede asociado con el if más cercano. (d) Mostrar un parseo top-down y el árbol de derivación resultante para: if cond then if cond then sent else sent 3. Escribir gramáticas ELL(1) para: (a) lista de sentencias terminadas en ; (b) lista de valores separados por , (c) expresiones con +, -, *, (, ), id (d) if ... then ... elseif ... then ... else ... endif, con las partes de elseif y else opcionales. 4. Dar gramáticas LL(1) y ELL(1) para cada uno de los lenguajes de la práctica 7. Escribir los parsers recursivos-iterativos correspondientes a las gramáticas ELL(1). 2 5. La siguiente gramática extendida representa una versión (simplificada!) de declaraciones de variables y funciones en el lenguaje C: Declaracion Declarador −→ −→ LP arDecl P arDecl LId T ipo −→ −→ −→ −→ T ipo Declarador ( , Declarador )∗ ( * )∗ ( ID | ( Declarador ) ) ( ( ( LP arDecl | LId )? ) | [ NUM ? ] )∗ P arDecl ( , P arDecl )∗ T ipo ( Declarador )? ID ( , ID )∗ int | char Escribir un parser recursivo-iterativo para este lenguaje, verificando que la gramática sea ELL(1). 3