Sunteți pe pagina 1din 21

UNIDAD 6

ANLISIS SINTCTICO
El anlisis sintctico es la fase del compilador que
se encarga de chequear el cdigo fuente en base a
una gramtica dada. Y en caso de que el programa
de entrada sea vlido, suministra el rbol sintctico
que lo reconoce. El rbol sintctico contiene la
secuencia de tokens reconocidos, suministrada por
el analizador lxico.
El anlisis sintctico para lenguajes se basa en
gramticas formales, ya que de otra forma se hace
muy difcil la comprensin del compilador, y se
pueden corregir, quizs ms fcilmente, errores de
muy difcil localizacin, como es la ambigedad en
el reconocimiento de ciertas sentencias.
Se puede describir la sintaxis de las construcciones
de los lenguajes de programacin por medio de
gramticas de contexto libre o notacin BNF
(Backus-Naur Form).
En el modelo de compilador, el analizador
sintctico obtiene una cadena de tokens del
analizador lxico, como se muestra en la Figura
6.1, y verifica que la cadena de nombres de los
tokens pueda generarse mediante la gramtica
para el lenguaje fuente.
Program Analizad
a fuente or lxico

toke
n

Analizad
or
Obtener sintctic
siguient
o
e token
Tabla de
smbolos

rbol de Rest
anlisis
o
sintctic etap
o
a
inicia
l

Representaci
n
intermedia

Figura 6.1 Posicin del analizador sintctico en el modelo de


compilador

6.1 Gramticas libres de contexto.


Una gramtica o sistema de estructuracin de
frases G consiste en:
1) Un conjunto finito N de smbolos no
terminales.
2) Un conjunto finito T de smbolos terminales,
en donde NT=
3) Un subconjunto finito P de [(NT)*T*]x(NT)*,
llamado
conjunto
de
composiciones o reglas de produccin.
4) Un smbolo inicial SN.
Se escribe G=(N,T,P,S).
Una composicin (A,B)P se expresa usualmente
AB
y por la definicin de composicin A(NT)*-T* y
B(NT)*. En consecuencia, A debe incluir al
menos un smbolo no terminal, mientras que B
puede consistir en cualquier combinacin de
smbolos terminales o no terminales.
Sea G una gramtica y sea el arreglo nulo. Si toda
composicin es de la forma
A en donde AN
(NT)*-{}
se dice que G es una gramtica libre del
contexto.
Ejemplo 6.1. La gramtica G definida por

6. Anlisis Sintctico

T={a,b}, N={S}
con composiciones
SaSb, Sab
y smbolo inicial S, es libre del contexto.

4. Si A 1, A 2, , A k, puede escribirse
A 1| 2 | | k.
5. A menos que se diga otra cosa, el lado izquierdo
de la primera produccin es el smbolo inicial.

Ejemplo 6.2. La gramtica para definir expresiones


aritmticas:
expr expr op expr
expr (expr)
expr - expr
expr id
op + | - | * | / | ^
donde, los smbolos terminales son: id + - * / ^ ( )
y los smbolos no terminales son: expr y op, con
expr como smbolo inicial, no es libre de contexto.

Ejemplo 6.3. Una gramtica ms reducida de


expresiones aritmticas:
1. expr expr + expr
2. expr expr * expr
3. expr (expr)
4. expr id

Alternativamente, la gramtica del Ejemplo 6.2


puede especificarse concisamente como:
E E A E | (E) | -E | id
A+|-|*|/|^
Donde se han aplicado las siguientes convenciones
de notacin gramatical:
1. Son terminales las minsculas como a, b, c; los
operadores como +, *; los signos de puntuacin;
los dgitos decimales; y, las cadenas en negritas.
2. Son no terminales
las primeras letras
maysculas como A, B, C; la letra S, que cuando
aparece suele ser el smbolo inicial; y, las
cadenas en cursivas.
3. Son smbolos gramaticales, es decir, pueden ser
terminales o no terminales, las ltimas letras
maysculas como X, Y, Z o las letras griegas
minsculas como , , .
Lenguajes y Autmatas I

6.2 rboles de derivacin.


La construccin de un rbol de anlisis sintctico
puede hacerse precisa si se toma una vista
derivacional, en la cual las producciones se tratan
como reglas de rescritura. Empezando con el
smbolo inicial, cada paso de rescritura sustituye a
un no terminal por el cuerpo de una de sus
producciones. Esta vista derivacional corresponde a
la construccin descendente
de un rbol de
anlisis sintctico.
Sea G=(N,T,P,S) una gramtica. Si es una
composicin y xy(NT)*, se dice que xy se
deriva directamente de xy y se escribe
xy xy
Si i(NT)* para i=1,...,n; y i+1 se deriva
directamente de i para i=1,...,n-1, se dice que n
es derivable de 1 y se escribe
1n
Se llama
2

6. Anlisis Sintctico

12...n
derivacin de n. Por convencin, cualquier
elemento de (NT)* es derivable de s mismo.
El lenguaje generado por G consiste en todos los
arreglos definidos sobre T que se derivan de S, y se
denota L(G).
Para la gramtica del Ejemplo 6.1, las nicas
derivaciones de S son
SaSb

an-1Sbn-1
an-1abbn-1= anbn
As que, L(G) es un lenguaje libre del contexto que
consiste en los arreglos definidos sobre {a,b} de la
forma
anbn, n=1,2,...
Mediante la aplicacin repetida de las producciones
de la gramtica del Ejemplo 6.3 pueden obtenerse
expresiones ms y ms complicadas. Por ejemplo
exp expr * expr
(expr) * expr
(expr) * id
(expr + expr) * id expr
(expr + id) * id
(id + id) *expr
id
expr
*
Los rboles de derivacin o de anlisis
expr
) una estructura
id
gramatical( superponen
sobre las
palabras de un lenguaje, que es de utilidad en las
aplicaciones tales como la compilacin de los
+
expr
expr
Lenguajes y Autmatas I

id

id

Figura 6.2. rbol de

lenguajes de programacin. Los vrtices de un


rbol de derivacin estn etiquetados
con
smbolos terminales o variables de la gramtica, o
posiblemente con . Si un vrtice interior n tiene
etiqueta A y los hijos de n estn etiquetados con
X1, X2, , Xk partiendo de la izquierda, entonces A
X1 X2 Xk debe ser una produccin. La Figura
6.2 muestra el rbol de anlisis gramatical para la
derivacin de la gramtica del Ejemplo 6.3. Ntese
que si se leen las hojas de izquierda a derecha se
obtiene la ltima lnea de la derivacin, (id + id) *
id.

De manera ms formal, sea G=(V, T, P, S) una GLC.


Un rbol es un rbol de derivacin (o de anlisis
gramatical) para G si:
1. Cada vrtice tiene una etiqueta, que es un
smbolo de VT.
2. La etiqueta de la raz es S.
3. Si un vrtice es interior y tiene etiqueta A,
entonces A debe estar en V.
4. Si n tiene etiqueta A y vrtices n1, n2, , nk son
los hijos del vrtice n, de izquierda a derecha,
con etiquetas X1, X2, , Xk, respectivamente,
3

6. Anlisis Sintctico

entonces AX1 X2 Xk debe ser una produccin


de P.
5. Si el vrtice n tiene etiqueta, entonces n es
una hoja y es el nico hijo de su padre.

6.3 Formas normales de Chomsky.


La forma normal de Chomsky se establece por
medio de teoremas que garantizan que toda
gramtica libre del contexto es equivalente a una
gramtica con restricciones sobre la forma de las
producciones.
Forma normal de Chomsky o CNF (Teorema).
Cualquier lenguaje libre de contexto sin , es
generado por una gramtica en la que todas las
producciones son de la forma A BC o A a.
Aqu, A, B y C son variables y a es un terminal.
Ejemplo 6.4. Sea la gramtica ({S, A, B}, {a, b}, P,
S) con producciones:
S bA|aB
A bAA|aS|a
B aBB|bS|b
Encuntrese una gramtica equivalente en CNF.
Solucin. Primero, las nicas producciones que ya
se encuentran en forma apropiada son A a y B
b. No existen producciones unitarias, as que puede
empezarse sustituyendo los terminales de la
derecha por variables, excepto en el caso de la
producciones ya apropiadas. S bA se sustituye
por S CbA y Cb b. De manera similar, A aS se
sustituye por A CaS y Ca a; A bAA es
Lenguajes y Autmatas I

sustituida por A CbAA; S aB se reemplaza por


S CaB; B bS es reemplazado por B CbS; y, B
aBB es sustituida por B CaBB. En una siguiente
etapa, la produccin A CbAA se sustituye A
CbD1 y D1 AA; y la produccin B CaBB se
reemplaza por B CaD2 y D2 BB. Las
producciones para la gramtica CNF son:
S CbA| CaB
A CaS| CbD1|a
B CbS| CaD2|b
D1 AA
D2 BB
Ca a
Cb b
Forma normal de Greibach o GNF (teorema).
Cada lenguaje libre de contexto L que no contenga
, puede ser generado por una gramtica para la
cual cada produccin es de la forma A a, en
donde A es una variable, a un terminal y una
cadena (posiblemente vaca) de variables.
El teorema de Greibach se basa en los dos lemas
siguientes.
Lema 1. Defnase una produccin A como una
produccin con variable A en la izquierda. Sea G =
(V, T, P, S) una CFG. Sea A 1B2 una produccin
de P y sea B 1|2||r el conjunto de todas las
producciones B. Hgase G1 = (V, T, P, S) la
gramtica obtenida de G mediante la eliminacin
de la produccin A 1B2 de P y la adicin de las
4

6. Anlisis Sintctico

producciones A 112|122||1r2. Entonces


L(G) = L(G1)
Lema 2. Sea G = (V, T, P, S) una CFG. Sea A A1|
A2|| Ar el conjunto de las producciones A para
las cuales A es el smbolo que est ms a la
izquierda del lado derecho. Sean A 1|2||s las
restantes producciones de A. Hgase G1 = (V{B},
T, P, S) la CFG formada por la adicin de la variable
B a V y la sustitucin de todas las producciones A
por las producciones:
1

A i
1 i s,
A i B

B i
1 i r.
B i B

Entonces L(G1) = L(G).


Ejemplo 6.5. Convertir a GNF la gramtica
G = ({A1, A2, A3}, {a, b}, P, A1)
en donde P consiste en lo siguiente
A1 A2A3
A2 A3A1|b
A3 A1A2|a
Solucin. Primer paso: Como el lado derecho de las
producciones para A1 y A2 comienzan con
terminales o variables con nmero mayor, se
empieza con la produccin A3 A1A2 y se sustituye
la cadena por A2A3A2. Ntese que A1 A2A3 es la
nica produccin con A1 en la izquierda.
El conjunto resultante de producciones es:
A1 A2A3
Lenguajes y Autmatas I

A2 A3A1|b
A3 A2A3A2|a
Como el lado derecho de la produccin A 3 A2A3A2
comienza con una variable de nmero menor, se
sustituye la primera ocurrencia de A 2 con A3A1 y b.
Por tanto A3 A2A3A2 se sustituye con A3
A3A1A3A2 y A3A2. El nuevo conjunto es
A1 A2A3
A2 A3A1|b
A3 A3A1A3A2|bA3A2|a
Se transforman ahora las producciones
A3 A3A1A3A2|bA3A2|a.
Se introduce el smbolo B3 y la produccin A3
A3A1A3A2 se sustituye por A3 bA3A2B3, A3 aB3, B3
A1A3A2 y B3 A1A3A2B3. El conjunto resultante es
A1 A2A3
A2 A3A1|b
A3 bA3A2B3|aB3|bA3A2|a
B3 A1A3A2|A1A3A2B3
Segundo paso: Ahora todas las producciones con
A3 en la izquierda tienen lado derecho que
comienzan con terminales. Estas se utilizan para
sustituir a A3 en la produccin A2 A3A1 y entonces
las producciones con A2 en el lado izquierdo se
utilizan para sustituir a A2 en la produccin A1
A2A3. El resultado es el siguiente.
A3 bA3A2B3
A3 bA3A2
A3 aB3
A3 a
A2 bA3A2B3A1
A2 bA3A2A1
A2 aB3A1
A2 aA1
A2 b
5

6. Anlisis Sintctico

A1
A1
A1
B3

bA3A2B3A1A3
aB3A1A3
bA3
A1A3A2

A1 bA3A2A1A3
A1 aA1A3
B3 A1A3A2B3

Paso 3. Las dos producciones B3 se convierten a


una forma apropiada, lo que trae como resultado
otras 10 producciones ms. Es decir, las
producciones
B3 A1A3A2 y B3 A1A3A2B3
quedan alteradas mediante la colocacin dl lado
derecho de las cinco producciones con A1 en la
izquierda en lugar de la primera A 1. En
consecuencia B3 A1A3A2 se convierte en
B3 bA3A2B3A1A3A3A2
B3 aB3A1A3A3A2
B3 bA3A3A2
B3 bA3A2A1A3A3A2
B3 aA1A3A3A2
Las otras producciones para B3 se sustituyen de
manera similar. El conjunto final de producciones
es
A3 bA3A2B3
A3 bA3A2
A3 aB3
A3 a
A2 bA3A2B3A1
A2 bA3A2A1
A2 aB3A1
A2 aA1
A2 b
A1 bA3A2B3A1A3
A1 bA3A2A1A3
A1 aB3A1A3
A1 aA1A3
A1 bA3
B3 bA3A2B3A1A3A3A2B3
B3 bA3A2B3A1A3A3A2
B3 aB3A1A3A3A2B3
B3 aB3A1A3A3A2
Lenguajes y Autmatas I

B3 bA3A3A2B3
B3 bA3A2A1A3A3A2B3
B3 aA1A3A3A2B3

B3 bA3A3A2
B3 bA3A2A1A3A3A2
B3 aA1A3A3A2

6.4 Diagramas de sintaxis.


Un diagrama de sintaxis es una forma grfica de
expresar reglas de gramticas. Cada regla est
representada por un camino que va de la entrada a
la izquierda a la salida a la derecha. Cualquier
trayecto vlido de entrada a salida representa una
cadena generada por esa regla.
Existen varias diferencias entre los diagramas de
transiciones para un analizador lxico y para un
analizador sintctico predictivo. En el caso de un
analizador sintctico, hay un diagrama por cada no
terminal. Las etiquetas de las aristas son
componentes lxicos y no terminales. Una
transicin con un componente lxico (terminal)
supone que se debe tomar dicha transicin si ese
componente lxico es el siguiente smbolo de
entrada. Una transicin con un no terminal A es
una llamada al procedimiento para A.
Para construir el diagrama de transiciones de un
analizador sintctico predictivo a partir de una
gramtica, primero se debe eliminar la recursin
por la izquierda de la gramtica, y despus
factorizar dicha gramtica por la izquierda. Luego,
para cada no terminal A se hace lo siguiente:
1. Crear un estado inicial y un estado final (de
retorno).

6. Anlisis Sintctico

2. Para cada produccin A X1X2Xn, crear un


camino desde el estado inicial al estado final,
con aristas etiquetadas con X1, X2, , Xn.
E
:

E
:

E
:

T
:

T
:

1
0

F
:
3

T
+

2
5

1
+4

F
*

(
4

1
1

1
2

1
T5

9
1
3

1
6

1 T
7+

5
3
4
i

d
:
Figura 6.36Diagramas de sintaxis.

6
Ejemplo 6.6. Sea la gramtica:
E TE
T
+
E +TE|
T
T
+

T FT
0
3
4
E

6
0
3
T *FT|
:
F (E) | id

6
* gramtica se
Los diagramas de sintaxis para esta

muestran en la Figura 6.3. FLos diagramas


T
7
8
simplificados se muestran en la figura 6.4.
1
:
3
F
1
:
4 I
Lenguajes y Autmatas

1
5

1
6

1
7

i
d
Figura 6.4 Diagramas de sintaxis

6.5 Ambigedad.
Si en cada paso de una derivacin se aplica una
produccin a la variable que se encuentra ms a la
izquierda, entonces la derivacin es de extrema
izquierda. De manera similar, se dice que una
derivacin, en la que la variable que est ms a la
derecha se sustituye en cada paso, es de extrema
derecha. Si w est en L(G) para la CFG G, entonces
w tiene al menos un rbol de anlisis gramatical, y
correspondiendo a un rbol de anlisis gramatical
7

6. Anlisis Sintctico

particular, w tiene una derivacin izquierda y una


derivacin derecha nicas.
Por supuesto, w puede tener varias derivaciones
derechas o izquierdas, ya que puede haber ms de
un rbol de derivacin para w. Sin embargo, de
cada rbol de derivacin slo se puede obtener una
derivacin extrema izquierda y una derivacin
extrema derecha.
Ejemplo 6.6. Para el rbol de derivacin de la
Figura 6.5 correspondiente a la gramtica con
producciones S aAS|a, A SbA|SS|ba, la
derivacin extrema izquierda es
S aAS aSbAS aabAS aabbaS aabbaa
Y la derivacin extrema derecha es
S aAS aAa aSbAa aSbbaa aabbaa
S
a

A veces, una gramtica ambigua se puede rescribir


para eliminar la ambigedad. Como ejemplo, se
eliminar la ambigedad de la siguiente gramtica
con else ambiguo:
prop if expr then prop |
if expr then prop else prop |
otra
Aqu, otra representa cualquier otra proposicin.
De acuerdo con esta gramtica, la proposicin
condicional compuesta
if E1 then S1 else if E2 then S2 else S3
tiene el rbol de anlisis sintctico que se muestra
en la Figura 6.6. La gramtica es ambigua puesto
que lapro
cadena
if E1 then
p
if E1 then S1 else S2
tiene
los
dos
rbolespro
de anlisis sintctico que se
if
exp
the
muestranr en la n
Figura p
6.7.

S
a

A
b

Figura
6.5.
rbol
de
derivacin.
Una gramtica libre de contexto G de la que alguna
palabra tenga dos rboles de anlisis gramatical se
dice que es gramtica ambigua. Es decir, una
gramtica es ambigua si alguna palabra tiene ms
de una derivacin extrema izquierda o ms de una
derivacin extrema derecha.
Lenguajes y Autmatas I

pro E1
p
if

exp
r

if
the
n

E1
pro
p
if

exp
r

exp the pro els pro


pror els
n pro
p
e
p
p
e
p
E
S1
S2
S1 2
if

the
n

pro
p

exp the
r
n
els pro
eE2
p

pro els pro


p
e
p
S2

S3

S2
Figura
para la
E16.6 rbol de anlisis sintctico
proposicin condicional
if
exp
the
pro
r
n
p
E2

S1

Figura 6.7 Dos rboles de anlisis sintctico para


una frase ambigua

6. Anlisis Sintctico

estara obligado a concordar con este then no


emparejado. Una proposicin emparejada es o una
proposicin
if-then-else
que
no
contenga
proposiciones sin emparejar o cualquier otra clase
de proposicin no condicional. As, se puede utilizar
la gramtica
prop propEmp |
propNoEmp
propEmp if expr then propEmp else propEmp |
otra
propNoEmp if expr then prop |
if expr then propEmp else propNoEmp
Esta gramtica genera el mismo conjunto de
cadenas, pero permite slo un anlisis sintctico
para la cadena del ejemplo, es decir, el que asocia
cada else con el then sin emparejar anterior ms
cercano.

En todos los lenguajes de programacin con


proposiciones condicionales de esta forma, se
prefiere el primer rbol de anlisis sintctico. La
regla general es, emparejar cada else con el then
sin emparejar anterior ms cercano. Esta regla
para eliminar ambigedades se puede incorporar
directamente a la gramtica. Por ejemplo, se puede
rescribir la gramtica ambigua como la siguiente
gramtica no ambigua. La idea es que una
proposicin que aparezca entre un then y un else
debe estar emparejada; es decir, no debe
terminar con un then sin emparejar seguido de
cualquier proposicin, porque entonces el else
Lenguajes y Autmatas I

Ejemplo 6.7 Sea la gramtica: E E + E | E * E |


(E) | id. Para el enunciado id + id * id se tienen
dos derivaciones por la izquierda distintas:
EE+E
EE*E
id + E
E+E*E
id + E * E
id + E * E
id + id * E
id + id * E
id + id * id
id + id * id
Los rboles de anlisis sintctico correspondientes
aparecen en la Figura 6.8.
E
E
i
d

E
E

E
E

*
E

E +
i
d
i
i
i
9
i
d
d
d
d
Figura 6.8 Dos rboles de anlisis sintctico para
id+id*id

6. Anlisis Sintctico

La gramtica no ambigua
EE+T|T
TT*F|F
F ( E ) | id
Genera el mismo lenguaje, pero da a + una menor
precedencia que a *, y convierte a ambos
operadores en asociativos por la izquierda.

6.6 Generacin de la matriz predictiva.


Los analizadores sintcticos predictivos, es decir,
los analizadores sintcticos de descenso recursivo
que no necesitan rastreo hacia atrs, pueden
construirse para una clase de gramticas llamadas
LL(1). La primera L significa explorar la entrada de
izquierda a derecha, la segunda L significa una
derivacin por la izquierda, y el 1 significa usar un
smbolo de entrada de anticipacin en cada paso,
para tomar las decisiones de accin del anlisis
sintctico.
Para definir formalmente las gramticas LL(1) es
necesario definir las funciones PRIMERO y
SIGUIENTE.
Si es una cadena de smbolos gramaticales, se
considera PRIMERO() como el conjunto de
terminales que inician las cadenas derivadas de .
Si * , entonces tambin est en PRIMERO().

Lenguajes y Autmatas I

Se define SIGUIENTE(A), para el no terminal A,


como el conjunto de terminales a que pueden
aparecer inmediatamente a la derecha de A en
alguna forma de frase, es decir, el conjunto de
terminales a tal que haya una derivacin de a
forma S * Aa para algn y . Obsrvese que
en algn momento de la derivacin pudieron haber
existido smbolos entre A y a, pero si as fue,
derivaron a y desaparecieron. Si A puede ser el
smbolo situado ms a la derecha en una forma de
frase, entonces $ (fin de cadena) est en
SIGUIENTE(A).
Para calcular PRIMERO(X) para todos los smbolos
gramaticales X, se aplican las reglas siguientes
hasta que no puedan aadirse ms terminales o a
ningn conjunto PRIMERO.
1. Si X es terminal, entonces PRIMERO(X) es {X}.
2. Si X es una produccin, entonces adase
a PRIMERO(X).
3. Si X es no terminal y X Y1Y2Yk es una
produccin, entonces se pone a en PRIMERO(X)
si, para alguna i, a est en PRIMERO(Y i) y est
en todos los PRIMERO(Y1),, PRIMERO(Yi-1); es
decir, Y1Yi-1 * . Si est en PRIMERO(Yj) para
toda j=1, 2, , k, entonces se aade a
PRIMERO(X). Por ejemplo, todo lo que est en
PRIMERO(Y1) sin duda est en PRIMERO(X). Si Y 1
no deriva a , entonces no se aade nada ms a
PRIMERO(X), pero si Y1 * , entonces se le
aade PRIMERO(Y2), y as sucesivamente.
Ahora puede calcularse PRIMERO para cualquier
cadena X1X2Xn de la siguiente forma: se aade a
PRIMERO(X1X2Xn) todos los smbolos distintos de
10

6. Anlisis Sintctico

de PRIMERO(X1). Si est en PRIMERO(X1), se


aaden tambin los smbolos distintos de de
PRIMERO(X2); si est tanto en PRIMERO(X1) como
en PRIMERO(X2), se aaden tambin los smbolos
distintos de de PRIMERO(X3), y as sucesivamente.
Por ltimo, se aade a PRIMERO(X1X2Xn) si, para
toda i, PRIMERO(Xi) contiene .
Para calcular SIGUIENTE(A) para todos los no
terminales A, se aplican las reglas siguientes hasta
que no se pueda aadir nada ms a ningn
conjunto SIGUIENTE.
1. Se pone $ en SIGUIENTE(S), donde S es el
smbolo inicial y $ es el delimitador derecho de
la entrada.
2. Si hay una produccin A B, entonces todo lo
que est en PRIMERO() excepto se pone en
SIGUIENTE(B).
3. Si hay una produccin A B o una produccin
A B, donde PRIMERO() contenga (es
decir, * ), entonces todo lo que est en
SIGUIENTE(A) se pone en SIGUIENTE(B).
Ejemplo 6.8. Para la gramtica del ejemplo anterior
se tiene
PRIMERO(E) = PRIMERO(T) = PRIMERO(F) = {(, id}
PRIMERO(E) = {+, }
PRIMERO(T) = {*, }
SIGUIENTE(E) = SIGUIENTE(E) = {), $}
SIGUIENTE(T) = SIGUIENTE(T) = {+, ), $}
SIGUIENTE(F) = {+, *, ), $}

Lenguajes y Autmatas I

La clase de gramticas LL(1) es lo bastante robusta


como para cubrir la mayora de las construcciones
de programacin, aunque hay que tener cuidado al
escribir una gramtica adecuada para el lenguaje
fuente. Por ejemplo, ninguna gramtica recursiva
por la izquierda o ambigua puede ser LL(1).
Una gramtica G es LL(1) si y solo si cada vez que
A| son dos producciones distintas de G, se
aplican las siguientes condiciones:
1. Para el no terminal a, tanto como derivan
cadenas que empiecen con a.
2. A lo ms, slo o puede derivar la cadena
vaca.
3. Si *, entonces no deriva a ninguna cadena
que empiece con un terminal en SIGUIENTE(A).
De igual forma, si *, entonces no deriva a
ninguna cadena que empiece con un terminal
en SIGUIENTE(A).
Las primeras dos condiciones son equivalentes
para la instruccin que establece que PRIMERO() y
PRIMERO() son conjuntos separados. La tercera
condicin equivale a decir que si est en
PRIMERO(), entonces PRIMERO() y SIGUIENTE(A)
son conjuntos separados, y de igual forma si est
en PRIMERO().
Puede construirse la tabla de un analizador
sintctico predictivo mediante el algoritmo 6.1.
Algoritmo 6.1. Construccin de una tabla de
anlisis sintctico predictivo.
Entrada. Una gramtica G.
Salida. La tabla de anlisis sintctico M.
11

6. Anlisis Sintctico

Mtodo. Para cada produccin A de la


gramtica hacer:
1. Para cada terminal a en PRIMERO(A), agregar
A a M[A, a].
2. Si est en PRIMERO(), entonces para cada
terminal b en SIGUIENTE(A), se agrega A
a M[A, b]. Si est en PRIMERO() y $ se
encuentra en SIGUIENTE(A), se agrega A
a M[A, $] tambin.
Si despus de los pasos anteriores
no hay
produccin en M[A, a], entonces se establece M[A,
a] a error (que por lo general se representa
mediante una entrada vaca en la tabla.
Este algoritmo se basa en la siguiente idea: se
elige la produccin A si el siguiente smbolo de
entrada a se encuentra en PRIMERO(). La nica
complicacin ocurre cuando =, o en forma ms
general, *. En este caso, debe elegirse de
nuevo A si el smbolo de entrada actual se
encuentra en SIGUIENTE(A), o si se ha llegado a $
(fin de cadena) y $ se encuentra en SIGUIENTE(A).
Ejemplo 6.9. Considrese la gramtica:
EE+T|T
TT*F|F
F (E) | id
Eliminando la recursin directa por la izquierda
(producciones de la forma A A) a las
producciones de E y despus a las de T, se obtiene
E TE
E +TE|
T FT
Lenguajes y Autmatas I

T *FT|
F (E) | id
En la Figura 6.10 se muestra una tabla de anlisis
sintctico predictivo para esta gramtica. Los
espacios en blanco son entradas de error; los otros
espacios indican una produccin con la cual
expandir el no terminal de la cima en la pila.
NO
TERMI
N
E

id
ET
E

E
T

ET
E
ET
E

TFT

T
F

SMBOLO DE ENTRADA
+
*
(
)

TFT

T*F
T

Fid

F(E
)
Figura 6.10 Tabla de anlisis sintctico M.

El problema clave durante el anlisis sintctico


predictivo es determinar la produccin que debe
aplicarse a un no terminal. El analizador sintctico
no recursivo busca la produccin que debe
aplicarse en una tabla de anlisis sintctico.
Un analizador sintctico predictivo guiado por
tablas tiene un buffer de entrada, una pila, una
tabla de anlisis sintctico y una cadena de salida
(Figura 6.11). El buffer de entrada contiene la
12

6. Anlisis Sintctico

cadena que se va a analizar, seguida de $, un


smbolo utilizado como delimitador derecho para
indicar el fin de la cadena de entrada. La pila
contiene una secuencia de smbolos gramaticales
con $ en la parte de abajo, que indica la base de la
pila. Al principio, la pila contiene el smbolo inicial
de la gramtica encima de $. La tabla de anlisis
sintctico es una matriz bidimensional M[A, a]
donde A es un no terminal o el smbolo $. Se
controla el analizador sintctico mediante un
programa que se comporta como se describe a
continuacin.
El programa tiene en cuenta X, el smbolo de la
cima de la pila, y a, el smbolo en curso de la
entrada. Estos dos smbolos determinan la accin
del analizador. Existen tres posibilidades:
1. Si X=a=$, el analizador sintctico se detiene y
anuncia el xito de la realizacin del anlisis.
2. Si X=a$, el analizador sintctico saca a X de la
pila y mueve el apuntador de entrada al
siguiente smbolo de entrada.
3. Si X es un no terminal, el programa consulta la
entrada M[X,a] de la tabla de anlisis sintctico.
Esta entrada ser o una produccin de X de la
gramtica o una entrada de error. Si, por
ejemplo, M[X,a] = {X UVW}, el analizador
sintctico sustituye la X de la cima de la pila por
WVU (con U en la cima). Como salida, se sabe
que el analizador sintctico slo imprime la
a + b
ENTRA
produccin
utilizada; ah se podra ejecutar
$
DA
cualquier
otro cdigo. Si M[X,a]=error, el
Programa
paraa una rutina
analizadorX sintctico
llama
SALIDAde
anlisis
sintctico
recuperacin
de
error.
PIL
Y
predictivo
A
Z
Tabla de anlisis
$
sintctico M
Lenguajes y Autmatas I

Figura 6.11Modelo de analizador sintctico predictivo no

Se puede describir el comportamiento del


analizador
sintctico
en
funcin
de
sus
configuraciones, que dan el contenido de la pila y
la entrada restante (Algoritmo 6.2).
Algoritmo 6.2. Anlisis sintctico predictivo no
recursivo.
Entrada. Una cadena w y una tabla de anlisis
sintctico M para la gramtica G.
Salida. Si w est en L(G), una derivacin por la
izquierda de w, de lo contrario, una indicacin de
error.
Mtodo. Al principio, el analizador sintctico est
en una configuracin en la que tiene a $S en la pila
con S, el smbolo inicial de G en el tope, y w$ en el
buffer de entrada.
establecer ip para que apunte al primer smbolo de
w;
establecer X con el smbolo de la parte superior de
la pila;
while (X$) { /* la pila no est vaca */
if (X es a) sacar de la pila y avanzar ip;
else if (X es un terminal) error();
else if (M[X, a] es una entrada de error) error();
else if (M[X, a] = X Y1Y2Yk) {
enviar de salida la produccin X Y1Y2Yk;
13

6. Anlisis Sintctico

sacar de pila;
meter Yk Yk-1, , Y1 en la pila, con Y 1 en la
cima;
}
establecer X con el smbolo de la cima de la pila;
}
Con la entrada id + id * id el analizador sintctico
predictivo realiza la secuencia de movimientos de
la Figura 6.12. Estos movimientos corresponden a
una derivacin por la izquierda. El apuntador de
entrada apunta al smbolo de la extrema izquierda
de la cadena en la columna ENTRADA. Si se
observa con atencin las acciones de este
analizador sintctico, se nota que est buscando
una derivacin por la izquierda para la entrada, es
decir, las producciones emitidas son las de una
derivacin por la izquierda. Los smbolos de
entrada que ya se han examinado, seguidos de los
smbolos gramaticales de la pila (de la cima al
fondo), son las formas de frase izquierdas de la
derivacin.
PILA
$E
$ET
$ETF
$ETid
$ET
$E
$ET+
$ET
$ETF
$ETid
Lenguajes y Autmatas I

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$

SALIDA

$ET
* id$
$ETF*
* id$ T *FT
$ETF
id$
$ETid
id$ F id
$ET
$
$E
$ T
$
$ E
Figura 6.12 Movimientos del analizador sintctico
predictivo para id + id * id

6.7 Tipos de analizadores sintcticos.


Los tipos de analizadores sintcticos se definen de
acuerdo a la forma de construir el rbol sintctico.
Pueden
ser
generales,
descendentes
o
ascendentes.
Universales. Los mtodos universales de anlisis
sintctico como el algoritmo de Cocke-YoungerKasami y el algoritmo de Earley pueden analizar
cualquier gramtica. Sin embargo, estos mtodos
generales son demasiado ineficientes como para
usarse en la produccin de compiladores.

E TE
T FT
F id

Descendentes. Parten del smbolo inicial y van


efectuando derivaciones a la izquierda hasta
obtener la secuencia de derivaciones que
reconocen la sentencia.

T
E + TE

Ascendentes. Parten de los terminales y van


aplicando reglas de produccin hacia atrs, desde
el consecuente hasta el antecedente, hasta llegar
al smbolo inicial.

T FT
F id

14

6. Anlisis Sintctico

Analizadores con retroceso. Se hace una


bsqueda en profundidad con retroceso para
garantizar que se encuentra la frase. Costo O(kn).
Analizadores predictivos. Se determina qu
regla aplicar a partir de un anlisis de los primeros
tokens de la entrada.
Analizadores predictivos LL(1). Determinan qu
regla de produccin aplicar en cada paso en
funcin del token que se encuentra en cada
momento en la cabeza de lectura.
Analizadores predictivos LL(k). Determinan qu
regla de produccin aplicar en cada paso en
funcin de los k primeros tokens que se encuentra
en cada momento en la cabeza de lectura.
Analizadores sintcticos LR(k). Hacen un
anlisis sintctico ascendente de acuerdo a una
gramtica libre del contexto. La L es por el examen
de la entrada de izquierda a derecha (ingls: leftto-right), la R por construir una derivacin por la
derecha (ingls: rightmost derivation) en orden
inverso, y la k por el nmero de smbolos de
entrada de examen por anticipado utilizados para
tomar las decisiones del anlisis sintctico. Cuando
se omite, se supone que k es 1.
Existen tres tcnicas para construir una tabla de
anlisis sintctico LR para una gramtica. El primer
mtodo, llamado SLR (S de simple) es el ms fcil
de implantar pero pudiera fallar para algunas
gramticas. El segundo mtodo, llamado LR
cannico, es el ms poderoso y costoso. El tercer
Lenguajes y Autmatas I

mtodo, llamado LALR (LA de examen anticipado),


est entre los otros dos en cuanto a poder y costo.
Funciona con las gramticas de la mayora de los
lenguajes de programacin y, con un poco de
esfuerzo, se puede implantar en forma eficiente.

6.8 Manejo de errores.


Si un compilador tuviera que procesar slo
programas correctos, su diseo e implementacin
se simplificara en forma considerable. No obstante,
se espera que un compilador ayude al programador
a localizar y rastrear los errores que, de manera
inevitable, se infiltran en los programas, a pesar de
los mejores esfuerzos del programador.
Una vez que se detecta un error, cmo debe
recuperarse el analizador sintctico? El mtodo
ms simple es que el analizador sintctico termine
con un mensaje de error informativo cuando
detecte el primer error. A menudo se descubren
errores adicionales si el analizador sintctico puede
restaurarse a s mismo, a un estado en el que
pueda continuar el procesamiento de la entrada,
con esperanzas razonables de que un mayor
procesamiento proporcione informacin til para el
diagnstico. A continuacin, las estrategias de
recuperacin de errores: modo de pnico, nivel de
frase, producciones de errores y correccin global.
Recuperacin en modo de pnico.
Con este mtodo, al descubrir un error el
analizador sintctico descarta los smbolos de
entrada, uno a la vez, hasta encontrar un conjunto
15

6. Anlisis Sintctico

designado de tokens de sincronizacin. Por lo


general, los tokens de sincronizacin son
delimitadores como el punto y coma o }, cuya
funcin en el programa fuente es clara y sin
ambigedades. El diseador del compilador debe
seleccionar los tokens de sincronizacin apropiados
para el lenguaje fuente. Aunque la correccin de
modo de pnico a menudo omite una cantidad
considerable de entrada sin verificar errores
adicionales, tiene la ventaja de ser simple y, de
garantizar que no entrar en un ciclo infinito.
Recuperacin a nivel de frase.
Al descubrir un error, un analizador sintctico
puede realizar una correccin local sobre la entrada
restante; es decir, puede sustituir un prefijo de la
entrada restante por alguna cadena que le permita
continuar. Una correccin local comn es sustituir
una coma por un punto y coma, eliminar un punto
y coma extrao o insertar un punto y coma
faltante. La eleccin de la correccin local se deja
al diseador del compilador. Desde luego que debe
tenerse cuidado de elegir sustituciones que no
lleven hacia ciclos infinitos, como sera, por
ejemplo, si siempre se inserta algo en la entrada
adelante del smbolo de entrada actual.
La sustitucin a nivel de frase se ha utilizado en
varios compiladores, que reparan los errores, ya
que puede corregir cualquier cadena de entrada.
Su desventaja principal es la dificultad que tiene
para arreglrselas con situaciones en las que el
error actual ocurre antes del punto de deteccin.

Lenguajes y Autmatas I

Producciones de errores.
Al anticipar los errores comunes que pueden
encontrarse, puede que aumente la gramtica para
el lenguaje, con producciones que generen las
construcciones errneas. Un analizador sintctico
construido a partir de una gramtica aumentada
por estas producciones de errores detecta los
errores anticipados cuando se utiliza una
produccin de error durante el anlisis sintctico.
As, el analizador sintctico puede generar
diagnsticos de error apropiados sobre la
construccin errnea que se haya reconocido en la
entrada.
Correccin global.
Lo ideal sera que un compilador hiciera la menor
cantidad de cambios en el procesamiento de una
cadena de entrada incorrecta. Hay algoritmos para
elegir una secuencia mnima de cambios, para
obtener una correccin con el menor costo a nivel
global. Dada una cadena de entrada incorrecta x y
una gramtica G, estos algoritmos buscarn un
rbol de anlisis sintctico para una cadena y
relacionada, de tal forma que el nmero de
inserciones, eliminaciones y modificaciones de los
tokens requeridos para transformar a x en y sea lo
ms pequeo posible. Por desgracia, estos mtodos
son en general demasiado costosos para
implementarlos en trminos de tiempo y espacio,
por lo cual estas tcnicas slo son de inters
terico actualmente.
Hay que observar que un programa casi correcto
tal vez no sea lo que el programador tena en
mente. Sin embargo, la nocin de la correccin con
16

6. Anlisis Sintctico

el menor costo proporciona una norma para


evaluar las tcnicas de recuperacin de errores, la
cual se ha utilizado para buscar cadenas de
sustitucin ptimas para la recuperacin a nivel de
frase.

6.9 Generadores de analizadores sintcticos.


El generador de analizadores sintcticos LALR de
nombre Yacc implementa muchos conceptos del
anlisis sintctico y se emplea mucho. Yacc
significa yet another compiler-compiler (otro
compilador de compiladores ms) y su primera
versin es de S.C. Johnson, 1970.
Puede construirse un traductor mediante el uso de
Yacc de la forma que se ilustra en la Figura 6.13. En
primer lugar se prepara un archivo, por decir
traducir.y, el cual contiene una especificacin de
Yacc del traductor. El siguiente comando del
sistema
yacc traducir.y
transforma el archivo traducir.y en un programa en
C llamado y.tab.c usando el mtodo LALR. El
programa en y.tab.c es una representacin de un
analizador sintctico LALR escrito en C, junto con
otras rutinas en C que el usuario puede haber
preparado. Al compilar y.tab.c junto con la
biblioteca ly que contiene el programa de anlisis
sintctico LR mediante el uso del comando:
cc y.tab.c ly
se obtiene el programa objeto a.out deseado, el
cual realiza la traduccin especificada por el
programa original en Yacc. Si se necesitan otros
procedimientos, pueden compilarse o cargarse con
Lenguajes y Autmatas I

y.tab.c, de igual forma que con cualquier programa


en C.
traducir.
y

Compilador de
Yacc

y.tab.c

y.tab.c

Compilador de C

a.out

entrada

a.out

salida

Figura 6.13 Creacin de un traductor de E/S con


Yacc.
Un programa en Yacc tiene tres partes:
Declaraciones
%%
Reglas de traduccin
%%
Soporte de las rutinas en C
Ejemplo 6.10 Construccin de una calculadora de
escritorio simple que lee una expresin aritmtica,
la evala e imprime su valor numrico. Se define la
gramtica:
EE+T|T
TT*F|F
R ( E ) | digito
El token digito es un solo dgito entre 0 y 9. En la
figura 6.14 se muestra un programa en Yacc,
derivado a partir de esta gramtica.
%{
#include <ctye.h>
%}
17

6. Anlisis Sintctico

%token DIGITO
%%
linea
: expr \n
{ printf(%d\n, $1);
}
;
expr : expr + term
{ $$ = $1 + $3; }
| term
;
term
: term * factor { $$ = $1 * $3; }
| factor
;
factor : ( expr )
{ $$ = $2; }
| DIGITO
;
%%
yylex() {
int c;
c = getchar();
if (isdigit(c)) {
yyval = c 0;
return DIGITO;
}
return c;
}
Figura 6.14 Especificacin Yacc de una calculadora
de escritorio simple.

Resumen
Analizadores sintcticos. Un analizador sintctico
recibe como entrada tokens del analizador lxico, y
trata los nombres de los tokens como smbolos
terminales de una gramtica libre de contexto.
Despus, el analizador construye un rbol de
anlisis sintctico para su secuencia de tokens de
Lenguajes y Autmatas I

entrada; el rbol de anlisis sintctico puede


construirse en sentido figurado (pasando por los
pasos de derivacin correspondientes) o en forma
literal.
Gramticas libres de contexto. Una gramtica
especifica un conjunto de smbolos terminales
(entrada), otro conjunto de no terminales (smbolos
que representan construcciones sintcticas) y un
conjunto de producciones, cada una de las cuales
proporciona una forma en la que se pueden
construir las cadenas representadas por un no
terminal, a partir de smbolos terminales y cadenas
representados por otros no terminales. Una
produccin consiste en un encabezado (el no
terminal a sustituir) y un cuerpo (la cadena de
smbolos gramaticales de sustitucin).
Derivaciones. Al proceso de empezar con el no
terminal inicial de una gramtica y sustituirlo en
forma repetida por el cuerpo de una de sus
producciones se le conoce como derivacin. Si
siempre se sustituye el no terminal por la izquierda
(o por la derecha), entonces a la derivacin se le
llama por la izquierda (o respectivamente, por la
derecha).
rboles de anlisis sintctico. Un rbol de anlisis
sintctico es una representacin grfica de una
derivacin, en la cual hay un nodo para cada no
terminal que aparece en la derivacin. Los hijos de
un nodo son los smbolos mediante los cuales se
sustituye este no terminal en la derivacin. Hay
una correspondencia de uno a uno entre los rboles
de anlisis sintctico, las derivaciones por la
18

6. Anlisis Sintctico

izquierda y las derivaciones por la derecha de la


misma cadena de terminales.
Ambigedad. Una gramtica para la cual cierta
cadena de terminales tiene dos o ms rboles de
anlisis sintctico distintos, o en forma equivalente,
dos o ms derivaciones por la izquierda, o dos o
ms derivaciones por la derecha, se considera
ambigua. En la mayora de los casos de inters
prctico, es posible redisear una gramtica
ambigua de tal forma que se convierta en una
gramtica sin ambigedad para el mismo lenguaje.
No obstante, las gramticas ambiguas con ciertos
trucos aplicados nos llevan algunas veces a la
produccin de analizadores sintcticos ms
eficientes.
Anlisis sintctico descendente y ascendente. Por
lo general, los analizadores sintcticos se
diferencian en base a si trabajan de arriba hacia
abajo (si empiezan con el smbolo inicial de la
gramtica y construyen el rbol de anlisis
sintctico partiendo de la parte superior) o de
abajo hacia arriba (si empiezan con los smbolos
terminales que forman las hojas del rbol de
anlisis sintctico y construyen el rbol partiendo
de la parte inferior). Los analizadores sintcticos
descendentes incluyen los analizadores sintcticos
con descenso recursivo y LL, mientras que las
formas ms comunes de analizadores sintcticos
ascendentes son analizadores sintcticos LR.
Analizadores sintcticos LL(1). Una gramtica en la
que es posible elegir la produccin correcta con la
cual se pueda expandir un no terminal dado, con
Lenguajes y Autmatas I

solo analizar el siguiente smbolo de entrada, se


conoce como LL(1). Estas gramticas permiten
construir una tabla de anlisis sintctico predictivo
que proporcione, para cada no terminal y cada
smbolo de pre-anlisis, la eleccin de la
produccin correcta. La correccin de errores
puede facilitarse al colocar las rutinas de error en
algunas, o en todas las entradas en la tabla que no
tengan una produccin legtima.
Yacc. El generador de analizadores sintcticos Yacc
recibe una gramtica (posiblemente) ambigua
junto con la informacin de resolucin de
conflictos, y construye los estados del LALR.
Despus produce una funcin que utiliza estos
estados para realizar un anlisis sintctico
ascendente y llama a una funcin asociada cada
vez que se realiza una reduccin.

Ejercicios

Apndice. Construcciones de
independientes del contexto.

lenguajes

no

No debe sorprender que algunos lenguajes no


puedan ser generados por ninguna gramtica. De
hecho, unas cuantas construcciones sintcticas de
muchos lenguajes de programacin no se pueden
especificar utilizando tan solo gramticas.
Ejemplo 1. Considrese el lenguaje abstracto L 1 =
{wcw|w est en (a|b)*}. L1 consta de todas las
palabras compuestas por una cadena repetida de
caracteres a y b separados por una c, como
aabcaab. Puede demostrarse que este lenguaje no
es independiente del contexto. Este lenguaje
19

6. Anlisis Sintctico

resume el problema de asegurar que los


identificadores se declaren antes de su uso en un
programa. Es decir, la primera w de wcw
representa la declaracin de un identificador w. La
segunda w representa su uso. En un compilador
donde se requiera comprobar la declaracin de
identificadores antes de su uso, tal comprobacin
se lleva a cabo en la fase de anlisis semntico.
Ejemplo 2. El lenguaje L2 = {anbmcndm|n1 y m1}
no es independiente del contexto. Es decir, L2
consta de cadenas en el lenguaje generado por la
expresin regular a*b*c*d* tales que los nmeros
de a y c son iguales, lo mismo que los nmeros de
b y d. L2 resume el problema de comprobar si el
nmero de parmetros formales en la declaracin
de un procedimiento coincide con el nmero de
argumentos en uso de este procedimiento. Es
decir, an y bm podran representar las listas de
parmetros formales en dos procedimientos con n
y m argumentos, respectivamente. Entonces c n y
dm representan las listas de parmetros reales en
llamadas a dichos procedimientos.
Ejemplo 3. El lenguaje L3 = {anbncn|n>0}, es decir,
cadenas en L(a*b*c*) con el mismo nmero de
caracteres a, b, y c, no es independiente del
contexto. Un ejemplo de un programa que incluye
L3 es el siguiente. Los textos de tipografa utilizan
cursivas donde los textos corrientes utilizan el
subrayado. Al convertir un archivo de texto
destinado a imprimirse en una impresora de lneas
en texto adecuado para un dispositivo de
fotocomposicin, hay que sustituir las palabras
subrayadas por cursivas. Una palabra subrayada es
una cadena de letras seguida de un mismo nmero
Lenguajes y Autmatas I

de retrocesos (caracteres back space de ASCII) y de


un nmero igual de caracteres de subrayado. Si se
considera a como una letra, b como el carcter de
retroceso y c como el carcter de subrayado, el
lenguaje L3 representa palabras subrayadas. La
conclusin es que no se puede utilizar una
gramtica para describir palabras subrayadas de
esta forma. Por otra parte, si se representa una
palabra subrayada mediante una secuencia de
triples letra-retroceso-subrayado, entonces se
pueden representar las palabras subrayadas con la
expresin regular (abc)*.
Es interesante observar que lenguajes muy
similares a L1, L2 y L3 son independientes del
contexto. Por ejemplo, L1 = {wcwR|w est en (a|
b)*}, donde wR representa una w invertida, es
independiente dl contexto. Se genera por la
gramtica
SaSa|bSb|c
El lenguaje L2 = {anbmcmdn|n1 y m1} es
independiente del contexto, con la gramtica
SaSd|aAd
AbAc|bc
Asimismo, L2 = {anbncmdm| n1 y m1} es
independiente del contexto, con la gramtica
SAB
AaAb|ab
BcBd|cd
Por ltimo, L3 = {anbn| n1} es independiente del
contexto, con la gramtica
SaSb|ab
20

6. Anlisis Sintctico

Es conveniente saber que L3 es el tpico lenguaje


no definible por ninguna expresin regular.

Lenguajes y Autmatas I

21

S-ar putea să vă placă și