Compiladores e Intérpretes: Ejercicios resueltos (curso 14/15) Ejercicio 1: Para cada una de las plataformas de ejecución seleccionadas, disponemos de un compilador de C a código objeto y de un enlazador de código objeto a lenguaje máquina, que podemos ver representados en la siguiente figura: C OBJ C OBJ P1 C OBJ P2 OBJ P4 OBJ P2 P1 OBJ P3 OBJ P1 C P3 P2 OBJ P4 P3 P4 Necesitamos disponer de al menos un compilador para cada uno de los lenguajes soportados. Los escribimos en lenguaje C y con salida en código objeto: Fortran OBJ Ada C OBJ Modula C OBJ C Cada uno de estos compiladores, los compilamos y enlazamos para cada una de las plataformas (en la siguiente figura se muestra el ejemplo de obtención de un compilador Fortran para la plataforma P1): Fortran C OBJ Fortran C OBJ OBJ OBJ Fortran OBJ P1 P1 OBJ P1 P1 Finalmente, el siguiente diagrama muestra un ejemplo de proceso de compilado y enlazado de un programa P escrito en Fortran para la plataforma objetivo P2: P P Fortran Fortran OBJ OBJ P OBJ P2 P2 P2 P2 P2 1 P2 Ejercicio 2: En el fragmento de código fuente se pueden identificar los siguientes componentes léxicos: ’function’ → Palabra reservada. ’maximo’ → Identificador. ’(’ → Paréntesis izquierdo. ’num1’ → Identificador. ’,’ → Coma. ’num2’ → Identificador. ’:’ → Dos puntos. ’integer’ → Identificador. ’;’ → Punto y coma. ’(* devuelve el maximo de dos numeros *)’ → Comentario. ’begin’ → Palabra reservada. ’if’ → Palabra reservada. ’num1’ → Identificador. ’<’ → Operador. ’num2’ → Identificador. ’then’ → Palabra reservada. ’maximo’ → Identificador. ’:=’ → Operador. ’num2’ → Identificador. ’else’ → Palabra reservada. ’maximo’ → Identificador. ’:=’ → Operador ’num1’ → Identificador. ’end’ → Palabra reservada. ’;’ → Punto y coma. ’(* maximo *)’ → Comentario. Ejercicio 3 Las siguientes expresiones regulares permiten reconocer el lenguaje propuesto: alfanum: [a-zA-Z0-9] barra: [\\] comilla: [\”] cadena: “({alfanum}|{barra}|{comilla})*” 2 Ejercicio 4 1) Diseño de un AFN que reconozca el lenguaje propuesto: q2 q0 a q3 q1 q12 q6 q4 b q7 a q8 b q9 b q10 q13 q11 q16 q14 q5 a b q17 q15 2) Conversión del AFN anterior a un AFD equivalente: 1. El estado inicial del AFD equivalente será cierre-ε(q0 ): qd0 = {q0 , q1 , q2 , q4 , q7 } 2. Calculamos las transiciones desde cualquier estado del autómata determinista para cada uno de los sı́mbolos de entrada {a,b} con las operaciones cierre-ε(mueve()): cierre-ε(mueve(qd0 , a)) = {q1 , q2 , q3 , q4 , q6 , q7 , q8 } =qd1 cierre-ε(mueve(qd0 , b)) = {q1 , q2 , q4 , q5 , q6 , q7 } =qd2 cierre-ε(mueve(qd1 , a)) = {q1 , q2 , q3 , q4 , q6 , q7 , q8 } =qd1 cierre-ε(mueve(qd1 , b)) = {q1 , q2 , q4 , q5 , q6 , q7 , q9 } =qd3 cierre-ε(mueve(qd2 , a)) = {q1 , q2 , q3 , q4 , q6 , q7 , q8 } =qd1 cierre-ε(mueve(qd2 , b)) = {q1 , q2 , q4 , q5 , q6 , q7 } =qd2 cierre-ε(mueve(qd3 , a)) = {q1 , q2 , q3 , q4 , q6 , q7 , q8 } =qd1 cierre-ε(mueve(qd3 , b)) = {q1 , q2 , q4 , q5 , q6 , q7 , q10 , q11 , q12 , q14 , q17 } =qd4 cierre-ε(mueve(qd4 , a)) = {q1 , q2 , q3 , q4 , q6 , q7 , q8 , q11 , q12 , q13 , q14 , q16 , q17 } =qd5 cierre-ε(mueve(qd4 , b)) = {q1 , q2 , q4 , q5 , q6 , q7 , q11 , q12 , q14 , q15 , q16 , q17 } =qd6 cierre-ε(mueve(qd5 , a)) = {q1 , q2 , q3 , q4 , q6 , q7 , q8 , q11 , q12 , q13 , q14 , q16 , q17 } =qd5 cierre-ε(mueve(qd5 , b)) = {q1 , q2 , q4 , q5 , q6 , q7 , q9 , q11 , q12 , q14 , q15 , q16 , q17 } =qd7 cierre-ε(mueve(qd6 , a)) = {q1 , q2 , q3 , q4 , q6 , q7 , q8 , q11 , q12 , q13 , q14 , q16 , q17 } =qd5 cierre-ε(mueve(qd6 , b)) = {q1 , q2 , q4 , q5 , q6 , q7 , q11 , q12 , q14 , q15 , q16 , q17 } =qd6 cierre-ε(mueve(qd7 , a)) = {q1 , q2 , q3 , q4 , q6 , q7 , q8 , q11 , q12 , q13 , q14 , q16 , q17 } =qd5 cierre-ε(mueve(qd7 , b)) = {q1 , q2 , q4 , q5 , q6 , q7 , q10 , q11 , q12 , q14 , q15 , q16 , q17 } =qd8 cierre-ε(mueve(qd8 , a)) = {q1 , q2 , q3 , q4 , q6 , q7 , q8 , q11 , q12 , q13 , q14 , q16 , q17 } =qd5 cierre-ε(mueve(qd8 , b)) = {q1 , q2 , q4 , q5 , q6 , q7 , q11 , q12 , q14 , q15 , q16 , q17 } =qd6 El autómata finito determinista equivalente queda por tanto de la siguiente forma: 3 b qd0 0,1,7,2,4 a a b b qd1 8,3,6,1,7,2,4 a qd3 2,6,5,4,1,9,7 b b qd4 5,6,1,7,2,4,10,17,11,12,14 qd6 2,12,6,5,14,16,4,17,15,1,11,10,7 a a qd8 b 5,6,1,7,2,4,15,16,11,17,12,14 b qd2 b 5,6,1,7,2,4 a a a b qd5 8,3,6,1,7,2,4,13,16,11,17,12,14 a qd7 2,12,6,5,14,16,4,17,15,1,11,9,7 3) Secuencia de cómputo en ambos autómatas: La secuencia de cómputo en cada uno de los autómatas para la entrada ’bbabbab’ es la siguiente: • AFN: {q0 } →ε {q1 , q7 } →ε {q2 , q4 } →b {q5 } →ε {q6 } →ε {q1 , q7 } →ε {q2 , q4 } →b {q5 } →ε {q6 } →ε {q1 , q7 } →a {q8 } →b {q9 } →b {q10 } →ε {q11 , q17 } →ε {q12 , q14 } →a {q13 } →ε {q16 } →ε {q11 , q17 } →ε {q12 , q14 } →b {q15 } →ε {q16 } →ε {q11 , q17 } • AFD: qd0 →b qd2 →b qd2 →a qd1 →b qd3 →b qd4 →a qd5 →b qd7 Ejercicio 5 Tabla de sı́mbolos no ordenada: (2) (1) Tabla de sı́mbolos uno dos tres cinco uno dos seis cuatro uno dos Índices Tabla de sı́mbolos uno dos tres cinco cuatro uno dos 1 2 4 4 Índices 1 5 Tabla de sı́mbolos con estructura de árbol (1) uno dos cinco uno 4 dos 4 dos 3 tres 2 cuatro 3 seis 2 3 (2) uno dos cinco 3 uno 3 dos cuatro 2 5 1 2 tres 2 uno 3 2 2 1 Tabla de sı́mbolos con estructura de bosque (1) 1 2 uno dos 3 uno tres cinco dos cuatro (2) 1 2 uno dos cinco 4 3 uno tres dos cuatro 6 uno dos seis Tabla de sı́mbolos con estructura de tabla hash (1) (2) tres 2 tres 2 seis 3 cinco 2 cinco 2 cuatro 3 uno 4 uno 3 uno 1 dos 4 dos 3 dos 2 cuatro 2 uno 3 uno 1 dos 3 dos 2 Ejercicio 6 Existe un pequeño error en la definición de la gramática que provoca una recursión infinita en la definición de estructuras “if-then”. La definición de la gramática deberı́a ser la siguiente: <proposicion> → if <expresion> then <proposicion> <else> | <expresion> <else> → else <proposicion> | ε <expresion> → expr Para demostrar la ambigüedad de esta gramática, construiremos dos árboles de derivación diferentes para la siguiente cadena: if expr then if expr then expr else expr a) <proposicion> if <expresion> then <proposicion> <else> ε if <expresion> then <proposicion> <else> <expresion> else <proposicion> <expresion> if expr then if expr then expr else expr 7 b) <proposicion> if <expresion> then <proposicion> <else> if <expresion> then <proposicion> <else> ε <expresion> else <proposicion> <expresion> if expr then if expr then expr else expr Como podemos ver, la ambigüedad radica en la asignación de la estructura <else> al if correspondiente. Ejercicio 7 Para simplificar la representación, asumiremos E = <expresion>, M = <expr mult>, X = <expr exp>, V = <valor>. a) 2+(2–2)/2*(2-2)/(2–2) E E + M M M X M / * V M / 2 X V V 2 X X X V V ( ( E − M M X M X X V M X V V 2 M X V 2 2 X V 2 V 2 E E − ) 2 8 − E ) M ( E ) E b) 2+2–2/2*2–2/2–2 E E − E E E + − − M M M M * / X X V 2 X X V X V V 2 2 2 M X M X V X V V 2 V 2 2 / M M 2 Ejercicio 8 Debemos eliminar la recursividad por la izquierda que afecta a los no terminales <expresion>, <termino> y <factor> del siguiente modo: <expresion> → <termino> <expresion’> <expresion’> → + <termino><expresion’> | ε <termino> → <factor><termino’> <termino’> → <factor><termino’> | ε <factor> → <valor><factor’> <factor’> → *<factor’> | ε Ejercicio 9 a): Cálculo de los conjuntos PRIMEROS y SIGUIENTES: • PRIMEROS(<expresion>) = {PRIMEROS(<izquierda>), ε} = {PRIMEROS(<factor>), ε} = {(, id, ε} • PRIMEROS(<izquierda>) = PRIMEROS(<factor>) = {(, id} • PRIMEROS(<derecha>) = {+, ε} • PRIMEROS(<factor>) = {(, id} 9 • SIGUIENTES(<expresion>) = {), $} • SIGUIENTES(<derecha>) = SIGUIENTES(<expresion>) = {), $} • SIGUIENTES(<izquierda>) = PRIMEROS(<derecha>) - ε ∪ SIGUIENTES(<derecha>) = {+,),$} • SIGUIENTES(<termino>) = SIGUIENTES(<izquierda>) = {+,),$} • SIGUIENTES(<factor>) = PRIMEROS(<termino>) - ε ∪ SIGUIENTES(<termino>) = {*,+,),$} b): Tabla de análisis sintáctico descendente <e> <i> <d> <t> <f> + * ( <e> → <i><d> <i> → <f><t> <d> → +<i><d> <t> → ε <t> → *<f><t> ) <e> → ε id <e> → <i><d> <i> → <f><t> <d> → ε <t> → ε <f> → (<e>) <d> → ε <t> → ε <f> → id A la vista de la tabla de análisis sintáctico, podemos comprobar que efectivamente se trata de una gramática LL(1), pues en cada celda de la tabla aparece como máximo una regla. c): Análisis de la cadena id*id+id Pila $<e> $<d><i> $<d><t><f> $<d><t>id $<d><t> $<d><t><f>* $<d><t><f> $<d><t>id $<d><t> $<d> $<d><i>+ $<d><i> $<d><t><f> $<d><t>id $<d><t> $<d> $ Entrada id*id+id$ id*id+id$ id*id+id$ id*id+id$ *id+id$ *id+id$ id+id$ id+id$ +id$ +id$ +id$ id$ id$ id$ $ $ $ Acción <e> → <i><d> <i> → <f><t> <f> → id Avanzar <t> → *<f><t> Avanzar <f> → id Avanzar <t> → ε <d> → +<i><d> Avanzar <i> → <f><t> <f> → id Avanzar <t> → ε <d> → ε Aceptación Ejercicio 10: a): Obtención de la colección canónica de conjuntos de elementos LR(0): En primer lugar, aumentamos la gramática añadiendo la siguiente regla: 10 $ <e> → ε <sentencia’> → <sentencia>$ A continuación, construimos la colección canónica LR(0) de la gramática, obteniendo los siguientes conjuntos: I0 = clausura(<sentencia’> → • <sentencia>$) = { <sentencia’> → • <sentencia> $ <sentencia> → • = <valorizq> [<corchete>] } I1 = Ir a(I0 , <sentencia>) = { <sentencia’> → <sentencia> •$ } I2 = Ir a(I0 , =) = { <sentencia> → = • <valorizq> [<corchete>] <valorizq> → • id1 <valorizq> → • id2 } I3 = Ir a(I2 , <valorizq>) = { <sentencia> → = <valorizq> • [<corchete>] } I4 = Ir a(I2 , id1) = { <valorizq> → id1 • } I5 = Ir a(I2 , id2) = { <valorizq> → id2 • } I6 = Ir a(I3 , [) = { <sentencia> → = <valorizq> [• <corchete>] <corchete> → • <corchete> + <valorizq> <corchete> → • <valorizq> <valorizq> → • id1 <valorizq> → • id2 } I7 = Ir a(I6 , <corchete>) = { <sentencia> → = <valorizq> [<corchete> •] 11 <corchete> → <corchete> • + <valorizq> } I8 = Ir a(I6 , <valorizq>) = { <corchete> → <valorizq> • } I9 = Ir a(I7 , ]) = { <sentencia> → = <valorizq> [<corchete>] • } I10 = Ir a(I7 , +) = { <corchete> → <corchete> + • <valorizq> <valorizq> → • id1 <valorizq> → • id2 } I11 = Ir a(I10 , <valorizq>) = { <corchete> → <corchete> + <valorizq> • } b) Generación de la tabla de transiciones Estado 0 1 2 3 4 5 6 7 8 9 10 11 id1 id2 4 5 = 2 + [ ] $ <sentencia> 1 <valorizq> <corchete> 3 6 4 5 8 10 4 9 5 11 Para simplificar la descripción de la tabla de acciones, numeramos las reglas de la gramática de la siguiente forma: 0 1 2 3 4 : : : : : <sentencia> → = <valorizq> [<corchete>] <valorizq> → id1 <valorizq> → id2 <corchete> → <corchete> + <valorizq> <corchete> → <valorizq> 12 7 A continuación se muestra la tabla de acciones para esta gramática. Las entradas correspondientes a sı́mbolos terminales se refieren a las acciones a tomar durante el análisis, mientras que las entradas correspondientes a sı́mbolos no terminales se refieren al estado a transitar mediante la función Ir a(). Estado 0 1 2 3 4 5 6 7 8 9 10 11 id1 id2 d4 d5 = d2 + [ ] $ <sentencia> 1 <valorizq> OK 3 r1 r2 d4 d6 r1 r2 r1 r2 d5 8 d10 r4 d9 r4 r0 d4 d5 11 r3 r3 A la vista de la tabla de acciones podemos afirmar que efectivamente esta es una gramática SLR(1), ya que en cada celda aparece como mucho una acción. c) Analizar la siguiente cadena: =id1[id1+id2] Estados 0 0,2 0,2,4 0,2,3 0,2,3,6 0,2,3,6,4 0,2,3,6,8 0,2,3,6,7 0,2,3,6,7,10 0,2,3,6,7,10,5 0,2,3,6,7,10,11 0,2,3,6,7 0,2,3,6,7,9 0,1 Sı́mbolos = =id1 =<vi> =<vi>[ =<vi>[id1 =<vi>[<vi> =<vi>[<c> =<vi>[<c>+ =<vi>[<c>+id2 =<vi>[<c>+<vi> =<vi>[<c> =<vi>[<c>] S Entrada =id1[id1+id2]$ id1[id1+id2]$ [id1+id2]$ [id1+id2]$ id1+id2]$ +id2]$ +id2]$ +id2]$ id2]$ ]$ ]$ ]$ $ $ Acción d2 d4 r1 d6 d4 r1 r4 d10 d5 r2 r3 d9 r0 OK Ejercicio 11 a) Ampliación de la gramática para el cálculo del valor mediante atributos sintetizados. F L L B B → → → → → <corchete> .L { F.valor = L.valor } LB { L.exp = L.exp − 1; L.valor = L.valor + B.valor · 2L.exp } B { L.exp = −1; L.valor = B.valor/2} 0 { B.valor = 0} 1 { B.valor = 1} 13 7 b) Mostrar el árbol de análisis aumentado para la cadena .101 F valor = 0.625 L valor = 0.625 exp = -3 L valor = 0.5 exp = -2 L valor = 0.5 exp = -1 B . B B valor = 1 valor = 0 valor = 1 1 0 1 14