Recorrido del árbol en un ADPR

¿En que forma es recorrido el árbol de análisis sintáctico concreto en un analizador descendente predictivo recursivo? ¿En que orden son visitados los nodos?

Factores Comunes

Si se tiene una variable con producciones:

AαβαγA \rightarrow \alpha \beta \mid \alpha \gamma

Las dos producciones tienen un máximo factor común en la izquierda de su parte derecha α\alpha. Asumimos que FIRST(β)FIRST(γ)=FIRST(\beta) \cap FIRST(\gamma) = \emptyset.

  1. ¿Cómo puede modificarse la gramática para obtener una nueva gramática que cumpla la condición de que las partes derechas tienen conjuntos FIRST(γi)FIRST(\gamma_i) disjuntos?

  2. ¿Puede modificarse la técnica APDR para que funcione sobre gramáticas con este tipo de producciones?.

Derivaciones a vacío

Surge un problema cuando Aγ1γnA \rightarrow \gamma_1 \mid \ldots \mid \gamma_n y la palabra vacía está en alguno de los conjuntos FIRST(γi)FIRST(\gamma_i). ¿Que hacer entonces?

Nótese que si AγA \rightarrow \gamma y ϵFIRST(γ)\epsilon \in FIRST(\gamma) es porque existe una derivación γϵ\gamma \stackrel{*}{\Longrightarrow} \epsilon.

¿Que terminales podemos legalmente encontrarnos cuando estamos en la subrutina A?

Consideremos una derivación desde el símbolo de arranque en la que se use la producción AγA \rightarrow \gamma.

Dicha derivación forzosamente tendrá la forma:

SβA aμβγ aμβ aμS \stackrel{*}{\Longrightarrow} \beta A\ a \mu \Longrightarrow \beta \gamma\ a \mu \stackrel{*}{\Longrightarrow} \beta\ a \mu.

Cualquier terminal aΣa \in \Sigma que pueda aparecer en una derivación desde el símbolo de arranque inmediatamente a continuación de la variable AA es susceptible de ser visto cuando se esta analizando AA y se aplicó AγA \rightarrow \gamma con

γϵ\gamma \stackrel{*}{\Longrightarrow} \epsilon.

Esto nos lleva a la definición del conjunto FOLLOW(A)FOLLOW(A) como conjunto de terminales que pueden aparecer a continuación de AA en una derivación desde el símbolo de arranque:

Dada una gramática G=(Σ,V,P,S)G=(\Sigma,V,P,S) y una variable AVA \in V se define el conjunto FOLLOW(A)FOLLOW(A) como:

FOLLOW(A)={bΣ: SαAbβ}E(A)FOLLOW(A) = \left \{ b \in \Sigma : \exists\ S \stackrel{*}{\Longrightarrow} \alpha A b \beta \right \} \cup E(A)

donde E(A)={$}E(A) = \{ \$ \} si SαAS \stackrel{*}{\Longrightarrow} \alpha A y es el conjunto vacío E(A)=E(A) = \emptyset en otro caso. Donde $ denota el final de la entrada

Si Aγ1γnA \rightarrow \gamma_1 \mid \ldots \mid \gamma_n dado que los conjuntos FIRST(γi)FIRST(\gamma_i) han de ser disjuntos para que un analizador predictivo APDR funcione, sólo una parte derecha puede contener la palabra vacía en su FIRSTFIRST. Supongamos que es γn\gamma_n. Podemos reformular la construcción del procedimiento para la variable AA siguiendo este seudocódigo:

    function A() {
      if (lookahead in FIRST(gamma_1)) { imitar gamma_1 }
      elsif (lookahead in FIRST(gamma_2)) { imitar gamma_2 }
      ...
      else (lookahead in FIRST(gamma_n) or lookahead in FOLLOW(A)) { imitar gamma_n }
    }

Un caso particular de γnϵ\gamma_n \stackrel{*}{\Longrightarrow} \epsilon es que γn=ϵ\gamma_n = \epsilon.

En tal caso, y como es obvio, el significado de imitar gamma_n es equivalente a ejecutar una sentencia vacía.

Construcción de los conjuntos de Primeros y Siguientes

Construcción de los conjuntos FIRST(X)FIRST(X)

Repita el siguiente conjunto de reglas hasta que no se puedan añadir mas símbolos terminales o a ningún conjunto FIRST(X)FIRST(X):

  1. Si XΣ entonces FIRST(X)=XSi\ X \in \Sigma\ entonces\ FIRST(X) = {X}

  2. Si Xϵ entonces FIRST(X)=FIRST(X){ϵ}Si\ X \rightarrow \epsilon\ entonces\ FIRST(X) = FIRST(X) \cup \{ \epsilon \}

  3. SiXV y XY1Y2YkP entoncesSi X \in V \ y\ X \rightarrow Y_1 Y_2 \cdots Y_k \in P\ entonces

    i = 1;
    do FIRST(X) = FIRST(X) U FIRST*(Y_i);
     i++; 
    while (i <= k and € in FIRST(Y_i))
  4. Añadir ϵ\epsilon a FIRST(X)FIRST(X) si iki \geq k y ϵFIRST(Yk)\epsilon \in FIRST(Y_k)

Aqui FIRST(Y)FIRST^*(Y) denota al conjunto FIRST(Y){ϵ}FIRST(Y) - \{ \epsilon \}.

Este algoritmo puede ser extendido para calcular FIRST(α)FIRST(\alpha) para α=X1X2Xn(VΣ)\alpha = X_1 X_2 \cdots X_n \in (V \cup \Sigma)^*. El esquema es anólogo al de un símbolo individual.

Construcción de los conjuntos FOLLOW(A) AVFOLLOW(A)\ \forall A \in V:

Repetir los siguientes pasos hasta que ninguno de los conjuntos FOLLOWFOLLOW cambie:

  1. FOLLOW(S)={$}FOLLOW(S) = \{\$\} ($ representa el final de la entrada)

  2. Si AαBβ entoncesSi\ A \rightarrow \alpha B \beta\ entonces FOLLOW(B)=FOLLOW(B)(FIRST(β){ϵ})FOLLOW(B) = FOLLOW(B) \cup (FIRST(\beta) - \{\epsilon\})

  3. Si AαBSi\ A \rightarrow \alpha B o AαBβA \rightarrow \alpha B \beta y ϵFIRST(β)\epsilon \in FIRST(\beta) entonces FOLLOW(B)=FOLLOW(B)FOLLOW(A)FOLLOW(B) = FOLLOW(B) \cup FOLLOW(A)

Gramáticas LL(1)

Una gramática G=(Σ,V,P,S)G = (\Sigma, V, P, S) cuyo lenguaje generado L(G)L(G) puede ser analizado por un analizador sintáctico descendente recursivo predictivo se denomina LL(1). Una gramática es LL(1) si y sólo si para cualesquiera dos producciones AαA \rightarrow \alpha y AβA \rightarrow \beta de GG se cumple:

  1. FIRST(α)FIRST(β)=FIRST(\alpha) \cap FIRST(\beta) = \emptyset

  2. Si ϵFIRST(α)\epsilon \in FIRST(\alpha), entonces FIRST(β)FOLLOW(A)=FIRST(\beta) \cap FOLLOW(A) = \emptyset

¿De donde viene el nombre LL(1)?

La primera L hace alusión al hecho de que el flujo de terminales se lee de izquierda a derecha, accediendo a la entrada por su izquierda (Left).

La segunda L se refiere a que el método de análisis predictivo construye una derivación a izquierdas.

El número entre paréntesis indica el número de terminales que debemos consultar para decidir que regla de producción se aplica. Asi, en una gramática LL(2) la decisión final de que producción elegir se hace consultando los dos terminales a la entrada.

Ejercicio

Cuando se dice que una gramática es LL(1) si, y sólo si:

  1. FIRST(α)FIRST(β)=FIRST(\alpha) \cap FIRST(\beta) = \emptyset

  2. Si ϵFIRST(α)\epsilon \in FIRST(\alpha), entonces FIRST(β)FOLLOW(A)=FIRST(\beta) \cap FOLLOW(A) = \emptyset

se asume que los conjuntos FIRST(α)FIRST(\alpha) no son vacíos.

  • ¿Que se puede decir de la regla AαA \rightarrow \alpha si FIRST(α)=FIRST(\alpha) = \emptyset?

  • ¿Que se puede decir de la variable AA si FOLLOW(A)=FOLLOW(A) = \emptyset?

Ambiguedad y LL(1)

¿Puede una gramática LL(1) ser ambigua?. Razone su respuesta.

Recursión por la Izquierda

Una gramática es recursiva por la izquierda cuando existe una derivación AAαA \stackrel{*}{\Longrightarrow} A \alpha.

En particular, es recursiva por la izquierda si contiene una regla de producción de la forma AAαA \rightarrow A \alpha. En este caso se dice que la recursión por la izquierda es directa.

Cuando la gramática es recursiva por la izquierda, el método de análisis recursivo descendente predictivo no funciona. En ese caso, el procedimiento A asociado con AA ciclaría para siempre sin llegar a consumir ningún terminal.

Eliminación de la Recursión por la Izquierda en la Gramática

Es posible modificar la gramática para eliminar la recursión por la izquierda. En este apartado nos limitaremos al caso de recursión por la izquierda directa. La generalización al caso de recursión por la izquierda no-directa se reduce a la iteración de la solución propuesta para el caso directo.

Consideremos una variable AA con dos producciones:

AAαβA \rightarrow A \alpha \mid \beta

donde α,β(VΣ)\alpha, \beta \in (V \cup \Sigma)^* no comienzan por AA. Estas dos producciones pueden ser sustituidas por:

AβRA \rightarrow \beta R

RαRϵR \rightarrow \alpha R \mid \epsilon

eliminando así la recursión por la izquierda.

La producción RαRR \rightarrow \alpha R se dice recursiva por la derecha. También podemos usar el operador de repetición y reducir la solución a una única regla AβαA \rightarrow \beta \alpha *

Las producciones recursivas por la derecha dan lugar a árboles que se hunden hacia la derecha. Es mas difícil traducir desde esta clase de árboles operadores como el menos, que son asociativos a izquierdas.

Ejercicio

Elimine la recursión por la izquierda de la gramática

exprexprNUMexpr \rightarrow expr - NUM

exprNUMexpr \rightarrow NUM