Uploaded by Erik

Nociones básicas de Sintaxis - Análisis de lenguajes de programación

advertisement
Nociones Básicas de Sintaxis
Análisis de Lenguajes de Programación
Mauro Jaskelioff
15/08/2017
Sintaxis
I
La sintaxis es la forma de un lenguaje.
I
Sintaxis concreta:
Las secuencias exactas de caracteres que son programas
sintácticamente válidos.
1+2+3
I
6=
(1 + 2) + 3
6=
(1 + 2)
+3
Sintaxis abstracta: La estructura esencial de los
programas sintácticamente válidos.
1+2+3
=
(1 + 2) + 3
=
(1 + 2)
+3
Lenguajes Formales
I
I
I
I
I
Un lenguaje es un conjunto de palabras.
Una palabra (cadena) es una secuencia finita de
sı́mbolos.
Con denotamos la palabra vacı́a, o sea la secuencia de
cero sı́mbolos.
Un sı́mbolo es un elemento de un conjunto finito
denominado alfabeto Σ.
Ejemplo:
alfabeto
palabras
lenguajes
Σ = {a, b }
ε, a, b, aa, ab, ba, bb,
aaa, aab, aba, abb, baa, bab, . . .
∅, {ε}, {a }, {b }, {a, aa },
{ε, a, aa, aaa },
{an | n > 0},
{an bn | n > 0, n par }
Palabras de un Alfabeto
I
Dado un alfabeto Σ, se define el conjunto Σ∗ como el
conjunto de secuencias sobre Σ. Inductivamente:
I
I
I
∈ Σ∗
Para sı́mbolo x ∈ Σ y palabra w ∈ Σ∗ ,
tenemos que xw ∈ Σ∗ .
Por ejemplo, para Σ = {0, 1}
Σ∗ = {,
0, 1,
00, 10, 01, 11,
000, 100, 010, 110, 001, 101, 011, 111,
...}
I
Nota: Hay infinitas palabras en Σ∗ , pero cada palabra es
de longitud finita.
Lenguajes
I
Dado un alfabeto Σ, un lenguaje L es
L ⊆ Σ∗
o equivalentemente
L ∈ P(Σ∗ )
I
Ejemplos
I
I
El conjunto de programas válidos en C es un lenguaje
sobre el conjunto de caracteres ASCII.
El conjunto de programas válidos en Haskell es un
lenguaje sobre el conjunto de caracteres Unicode.
Gramáticas Libres de Contexto
Gramáticas Libres de Contexto
I
I
Las Gramáticas libres de contexto (CFG) son una
manera de describir lenguajes libres de contexto.
Capturan nociones frecuentes en lenguajes de
programación:
I
I
I
I
estructura anidada,
paréntesis balanceados,
palabras clave emparejadas como begin y end.
La mayorı́a de los lenguajes razonables pueden ser
reconocidos en forma bastante simple: basta un autómata
de pila determinı́stico.
Gramáticas Libres de Contexto
Una gramática libre de contexto es una tupla (N, T, P, S)
I N es un conjunto finito de no terminales
I T es un conjunto finito de terminales (el alfabeto del
lenguaje que se describe)
I N ∩ T = ∅ (N y T son disjuntos)
I S es el sı́mbolo inicial, un elemento de N .
I P es un conjunto de producciones de la forma A → α,
donde A ∈ N y α ∈ (N ∪ T )∗ .
Ejemplo de CFG
I
G = ({S, A}, {a, b}, P, S) con P compuesto por las
siguientes producciones:
S →ε
S → aA
A → bS
I
Las producciones con el mismo lado izq, se pueden
agrupar (Backus-Naur Form o BNF):
S → ε | aA
I
A veces las producciones se escriben A ::= α.
La relación de derivación directa
I
Para obtener el lenguaje generado por una gramática
G = (N, T, P, S) definimos la relación binaria ⇒ para
cadenas de N ∪ T como la menor relación tal que
αAγ ⇒ αβγ
I
I
cuando A → β es una producción de G.
Una producción puede ser aplicada sin importar el
contexto (de ahı́, libre de contexto).
Ejemplo: para la gramática
S → ε | aA
A → bS
tenemos que
S ⇒ε
S ⇒ aA
aA
⇒ abS
SaAaa ⇒ SabSaa
La relación de derivación
I
I
La relación de derivación ⇒∗ es la clausura reflexiva
transitiva de ⇒.
O sea, es la menor relación sobre cadenas en N ∪ T tal
que:
I
I
I
I
α ⇒∗ β si α ⇒ β
α ⇒∗ α
α ⇒∗ β si α ⇒∗ γ ∧ γ ⇒∗ β
Ejemplo: para la gramática
S → ε | aA
A → bS
tenemos que
S ⇒∗ ε
S ⇒∗ aA
aA ⇒∗ abS
S ⇒∗ abS
S ⇒∗ ababS
S ⇒∗ abab
Lenguaje generado por una gramática
I
El lenguaje generado por una gramática
G = (N, T, P, S), se denota L(G), y se define como:
L(G) = {w | w ∈ T ∗ ∧ S ⇒∗ w }
I
I
I
Un lenguaje L es libre de contexto (CFL) sii L = L(G)
para algún CFG G.
Una cadena α ∈ (N ∪ T )∗ es una forma sentencial sii
S ⇒∗ α.
Ejemplo: para la gramática G
S → ε | aA
A → bS
L(G) = {(ab)i | i > 0} = {, ab, abab, ababab, . . . }
Árbol de Parseo
Un árbol es una derivación o árbol de parseo de un CFG
G = (N, T, P, S) si:
I cada nodo tiene una etiqueta en N ∪ T ∪ {},
I la etiqueta de la raı́z es S,
I la etiquetas de los nodos interiores están en N ,
I si el nodo n tiene etiqueta A e hijos n1 , n2 , . . . , nk (de
izq. a der.) con etiquetas X1 , X2 , . . . , Xk , entonces
A → X1 X2 . . . Xk es una producción en P ,
I si un nodo n tiene etiqueta , entonces n es una hoja y es
hijo único.
Árbol de parseo: Ejemplo
I
Dada la gramática G
S
a
S → ε | aA
A → bS
La cadena abab ∈ L(G) tiene
el árbol de parseo
I
I
I
A
b
S
a
A
b
S
La cadena de etiquetas en las hojas de izq. a der. es el
resultado del árbol.
El resultado es una forma sentencial de G.
Propiedad: α es el resultado de un árbol sii S ⇒∗ α.
Ejercicio
G = ({E , Ep , V , I , D },
{+, −, ∗, /, (, ), x , y, z , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
P, E)
donde P consiste de las producciones
E
Ep
V
I
D
→ E + E | E − E | E ∗ E | E / E | Ep
→ V | I | (E )
→x |y |z
→ DI | D
→0|1|2|3|4|5|6|7|8|9
Dibujar el árbol de parseo de las siguientes expresiones
I
I
1+x
42 ∗ x − z
I
I
(13 + 7 ∗ x ∗ (y − 123))
(1
Gramáticas Ambiguas
I
I
I
I
Una CFG G es ambigua si alguna palabra en L(G) tiene
más de un árbol de parseo.
Un CFL para el que toda CFG es ambigua es
inherentemente ambiguo.
La mayorı́a de los CFLs no son inherentemente ambiguos,
por lo que una CFG G ambigua, usualmente puede ser
transformada a una equivalente G0 que no es ambigua.
En general, la ambigüedad de una CFG no es decidible.
Eliminando Ambigüedad: el else colgado
I
La siguiente gramática posee el problema del “else
colgado” (dangling else).
Stmt → if Expr then Stmt
| if Expr then Stmt else Stmt
| other
I
el programa
if expr 1 then if expr 2 then stmt 1 else stmt 2
I
tiene 2 árboles de parseo posibles.
Por lo tanto la gramática es ambigua.
Eliminando Ambigüedad: el else colgado
Árbol 1:
Árbol 2:
Desambiguando gramáticas
I
I
I
Resolver la ambigüedad es importante.
¡Los dos árboles tienen diferente semántica!
Por ejemplo, suponer que expr 1 evalúa a True y expr 2 a
False. ¿Qué sentencias se ejecutan en cada caso?
Elegimos una interpretación
“Asociamos cada else al then más cercano que
no esté asociado a otro else.”
I
I
I
O sea, preferimos el árbol 1.
¿Cómo lo formalizamos?
Transformando la gramática en una equivalente pero sin
ambigüedades.
Desambiguando gramáticas
I
Idea: Una sentencia entre un then y un else debe ser
una sentencia “matcheada”.
Stmt
→ MatchedStmt
| UnmatchedStmt
MatchedStmt
→ if Expr then MatchedStmt
else MatchedStmt
| other
UnmatchedStmt → if Expr then Stmt
| if Expr then MatchedStmt
else UnmatchedStmt
Ejercicio
Considere la gramática para expresiones aritméticas vista
anteriormente.
¿Es ambigua? Justificar.
I
I
Las expresiones aritméticas se desambiguan mediante
convenciones como precedencia de operadores y
asociatividad.
Las mismas ideas se pueden usar para desambiguar
gramáticas.
Sintaxis Concreta y Abstracta
I
Los árboles de parseo que vimos se refieren a la sintaxis
concreta.
I
I
I
I
Se refieren a cadenas sin estructura.
Contienen detalles poco interesantes.
Su estructura no es única si la gramática es ambigua.
Por esto, es conveniente trabajar con árboles de sintaxis
abstracta.
I
I
La sintaxis abstracta es un árbol.
No puede haber problemas de ambigüedad.
Las gramáticas son mas simples ya que no es necesario
tener en cuenta formato ni paréntesis.
Ejemplo de sintaxis concreta
I
La sintaxis concreta de un lenguaje de expresiones
aritméticas (simplificado) es, en BNF:
hdigiti ::= ’0’ | ’1’ | ... | ’9’
hnati ::= hdigiti | hdigiti hnati
hintexpi ::= hnati
| hintexpi ’+’ hintexpi
| hintexpi ’*’ hintexpi
| ’(’ hintexpi ’)’
I
I
La sintaxis es ambigua
10 ∗ 2 + 3 = ?
La desambiguamos especificando asociatividad y
precedencia de operadores.
Sintaxis Abstracta
I
I
Lo que nos interesa son los naturales y expresiones como
entidades abstractas.
El árbol de sintaxis abstracta (AST) en BNF es:
hintexpi ::= hnati
| hintexpi + hintexpi
| hintexpi ∗ hintexpi
I
I
Los AST no contienen ambigüedades.
¿Pero qué es lo que estamos definiendo?
Definiendo Términos
I
I
Los AST me definen un conjunto de términos
El conjunto de términos del lenguaje es el menor conjunto
T tal que
1. n ∈ N entonces n ∈ T
2. t, u ∈ T entonces t + u ∈ T
3. t, u ∈ T entonces t ∗ u ∈ T
I
También podemos definir el conjunto mediante reglas de
inferencia
n∈N
n∈T
I
t∈T u∈T
t+u ∈T
t∈T u∈T
t∗u ∈T
Los sı́mbolos + y ∗ son arbitrarios y pueden ser diferentes
a la sintaxis concreta.
Implementación en Haskell
I
En Haskell podemos usar un tipo de datos algebraico para
representar el AST de un lenguaje.
data IntExp = Num Int
| Sum IntExp IntExp
| Prod IntExp IntExp
I
I
Los elementos de IntExp son árboles con etiquetas Num,
Sum y Prod en sus nodos.
En la implementación se ve bien claro que tratamos con
árboles y que los nombres de los constructores son
arbitrarios.
Lenguaje de Expresiones Aritméticas
Consideremos el árbol de sintaxis abstracta (AST) de un
lenguaje:
t ::= true
| false
| if t then t else t
| 0
| succ t
| pred t
| iszero t
Un programa es simplemente un término del lenguaje:
I El programa if false then 0 else 1 evalúa a 1.
I El programa iszero (pred (succ 0)) evalúa true.
Detalles de notación
I
I
I
I
I
Las metavariables están en el metalenguaje. Se usan para
representar entidades del lenguaje objeto.
La metavariable t, letras cercanas como u, s y r , y
variaciones como t1 o t 0 representan términos del lenguaje.
Un término es una frase que computa.
Una expresión es más general (por ejemplo podrı́amos
tener una expresión de tipos.)
Salvo que se aclare siempre nos referimos a la sintaxis
abstracta. Los paréntesis se usan exclusivamente para
expresar un árbol como una cadena de texto.
Los Términos dados Inductivamente
I
Podemos definir el conjunto de términos inductivamente:
Los términos son el menor conjunto T tal que
1. {true, false, 0} ⊆ T ;
2. si t1 ∈ T , entonces {succ t1 , pred t1 , iszero t1 } ⊆ T ;
3. si t1 ∈ T , t2 ∈ T , y t3 ∈ T , entonces
if t1 then t2 else t3 ∈ T
I
I
El requerimiento que T sea el conjunto más chico dice
que en T sólo están los elementos requeridos por las tres
cláusulas.
Recordar que T es un conjunto de árboles.
Los Términos dados por Reglas de Inferencia
true ∈ T
t1 ∈ T
succ t1 ∈ T
false ∈ T
0∈T
t1 ∈ T
t1 ∈ T
pred t1 ∈ T
iszero t1 ∈ T
t1 ∈ T t2 ∈ T t3 ∈ T
if t1 then t2 else t3 ∈ T
I
I
En este estilo, usualmente se deja implı́cito que uno está
interesado en el menor conjunto que satisface las reglas.
A menudo decimos “reglas de inferencia”, pero cuando
contienen metavariables, son en realidad esquemas de
reglas.
Los Términos en forma concreta
I
Para cada i ∈ N, definimos un conjunto Si .
S0 = ∅
Si+1 = {true, false, 0}
∪ {succ t1 , pred t1 , iszero t1 | t1 ∈ Si }
∪ {if t1 then t2 else t3 | t1 , t2 , t3 ∈ Si }
I
Luego, definimos
S=
[
Si
i∈N
I
Ejercicio: ¿Cuántos elementos tiene S3 ?
Solución: |Si+1 | = |Si |3 + |Si | × 3 + 3, |S0 | = 0.
|S3 | = 59439
Equivalencia de las definiciones
I
I
La definición inductiva y la dada por reglas caracterizan
los términos como un conjunto que satisface cierta
propiedad de clausura.
La definición concreta muestra como construir el conjunto
como el lı́mite de una secuencia.
Proposición (T = S )
El conjunto T fue definido como el menor conjunto que
satisface ciertas condiciones. Para probar el teorema basta:
1. probar que S satisface las condiciones;
2. probar que todo conjunto que satisface las condiciones
contiene a S .
Resumen
I
I
I
I
I
I
Los lenguajes de programación son lenguajes formales.
En general, basta gramáticas libres de contexto para
describir su sintaxis concreta.
La sintaxis concreta se refiere a cadenas, por lo que puede
ser ambigua.
La sintaxis abstracta trata con árboles, por lo que no es
ambigua.
Para procesar un programa, el primer paso es obtener su
árbol de sintaxis abstracta (AST).
Un AST es un conjunto de términos definidos
inductivamente.
I
Caracterizaciones. Pruebas por inducción estructural.
Bibliografı́a
I
Types and Programming Languages. B.C. Pierce.
I
Foundations of Programming Languages. J.C. Mitchell.
Download