Вы находитесь на странице: 1из 95

Compiladores

Ingeniera Informtica, 4 curso


Master en Informtica, 1
er
curso









Primer cuatrimestre:

- Introduccin
- Lenguajes y gramticas
- Anlisis Lxico
- Anlisis Sintctico












Profesores: Bernardino Arcay
Carlos Dafonte
Departamento de Tecnoloxas da Informacin e as Comunicacins.
Universidade da Corua
Curso 2009/2010 Rev.061009
ii


NDICE

1 INTRODUCCIN. ................................................................................................... 1
1.1 Estructura de un compilador.......................................................................... 2
1.2 Ejemplo de las fases de un compilador. ......................................................... 3
2 LENGUAJES Y GRAMTICAS. ............................................................................ 5
2.1 Notacin de Chomsky (1959). ......................................................................... 6
2.2 Clasificacin de Chomsky. .............................................................................. 7
2.3 Gramticas de contexto libre (GCL).............................................................. 8
2.4 Diagramas de Conway. .................................................................................... 9
2.5 Reglas BNF. .................................................................................................... 10
2.6 Problemas en las GCL. .................................................................................. 11
2.6.1 Recursividad.........................................................................................................................11
2.6.2 Reglas con factor repetido por la izquierda. .........................................................................13
2.6.3 Ambigedad. ........................................................................................................................13
2.7 Simplificacin de gramticas. ....................................................................... 14
2.7.1 Deteccin de un lenguaje vaco............................................................................................14
2.7.2 Eliminacin de reglas lambda ().........................................................................................14
2.7.3 Eliminacin de reglas unitarias o reglas cadena. ..................................................................16
2.7.4 Eliminacin de smbolos intiles..........................................................................................17
2.8 Gramtica limpia. .......................................................................................... 19
2.9 Forma normal de Chomsky (FNC). ............................................................. 19
2.10 Resumen. ..................................................................................................... 20
2.11 Ejercicios. .................................................................................................... 21
3 ANLISIS LXICO............................................................................................... 22
3.1 Tipos de mquinas reconocedoras o autmatas.......................................... 23
3.2 Autmatas Finitos. ......................................................................................... 23
3.3 Conversin de una Gramtica Regular en un Autmata finito................. 25
3.4 Expresin regular. ......................................................................................... 26
3.5 Algoritmo de Thompson................................................................................ 27
3.6 Transformacin de un AFND- en un AFD. ............................................... 28
3.7 Traductores finitos (TF). ............................................................................... 30
3.8 Implementacin de autmatas. ..................................................................... 31
3.8.1 Tabla compacta.....................................................................................................................31
3.8.2 Autmata programado..........................................................................................................33
3.9 Ejemplo. Scanner para nmeros reales sin signo en Pascal....................... 33
3.10 Acciones semnticas. .................................................................................. 36
3.11 Generador LEX. ......................................................................................... 37
iii
3.11.1 Partes de un programa LEX .............................................................................................37
3.11.2 Expresiones regulares.......................................................................................................38
3.11.3 Paso de valores en Lex.....................................................................................................39
3.11.4 Ejemplos...........................................................................................................................39
4 Anlisis sintctico (Parsing). ................................................................................. 43
4.1 Mquinas tericas, mecanismos con retroceso............................................ 46
4.1.1 Autmatas con pila (AP). .....................................................................................................46
4.1.2 Esquemas de traduccin (EDT)............................................................................................50
4.1.3 Traductores con pila (TP).....................................................................................................52
4.2 Algoritmos sin retroceso................................................................................ 53
4.2.1 Anlisis sintctico ascendente por precedencia simple.........................................................54
4.2.2 Anlisis sintctico ascendente por precedencia de operadores.............................................64
4.2.3 Analizadores descendentes LL(K)........................................................................................67
4.2.4 Analizadores ascendentes LR(k). .........................................................................................73
4.2.5 Generador de analizadores sintcticos YACC......................................................................89

iv
BIBLIOGRAFA.

Aho, A.V.; Lam M.; Sethi, R. ; Ullman, J.D.
"Compiladores: Principios, tcnicas y herramientas"
Addison-Wesley, Reading, Massachussetts (2008).

Louden D. K. [2004], Construccin de compiladores. Principios y Prctica,
Paraninfo Thomson Learning.

Garrido, A. ; Iesta J.M. ; Moreno F. ; Prez J.A. [2004] Diseo de
compiladores, Publicaciones Universidad de Alicante.

Sanchis, F.J.; Galn, J.A.
"Compiladores, teora y construccin"
Ed. Paraninfo (1987).

Aho, A.V.; Ullman, J.D.
"The theory of parsing, translation and compiling", I y II
Prentice-Hall (1972).

Aho, A.V.; Ullman J.D.
"Principles of compiler design"
Addison-Wesley, Reading, Massachussetts.

Hopcroff, J.E. ; Motwani R. ; Ullman, J. D. [2002] Introduccin a la teora de
autmatas, lenguajes y computacin, Addison-Wesley, Madrid.

Allen I.; Holub
"Compiler design in C"
Prentice-Hall (1991).

Snchez, G.; Valverde J.A.
"Compiladores e Intrpretes"
Ed. Daz de Santos (1984).

Sudkamp T.A.
Languages and machines
Addison-Wesley.
1

1 INTRODUCCIN.
Un lenguaje es un conjunto de oraciones finito o infinito, cada una de ellas de
longitud finita (es decir, constitudas cada una de ellas por un nmero finito
de elementos).

Compilacin: Proceso de traduccin en el que se convierte un programa
fuente (en un lenguaje de alto nivel) en un lenguaje objeto, generalmente
cdigo mquina (en general un lenguaje de bajo nivel).

La Teora de compiladores se usa para:
- Realizar compiladores.
- Disear procesadores de texto.
- Manejo de datos estructurados (XML).
- Inteligencia Artificial (en el diseo de interfaces hombre-mquina).
- Traductores de lenguajes naturales.
- Etc.

Se denominan tokens a los lexemas, las unidades mnimas de informacin
(por ejemplo, una instruccin FOR). La identificacin de estos elementos es la
finalidad del anlisis lxico.

Sintaxis de un lenguaje: Conjunto de reglas formales que nos permiten
construir las oraciones del lenguaje a partir de los elementos mnimos.

Semntica: Es el conjunto de reglas que nos permiten analizar el significado
de las frases del lenguaje para su interpretacin.

Intrprete: Conjunto de programas que realizan la traduccin de lenguaje
fuente a objeto, paso a paso, no de todo el programa (aparecieron por
problemas de memoria).

Ensamblador: Compilador sencillo donde el lenguaje es simple, con una
relacin uno-a-uno entre la sentencia y la instruccin mquina.

Compilacin cruzada: La compilacin se realiza en una mquina A y la
ejecucin se realiza en otra mquina B.

Link (encadenar, enlazar): Es el proceso por el cual un programa dividido en
varios mdulos, compilados por separado, se unen en un solo.

Pasadas en compilacin: Recorridos de todo el programa fuente que realiza
el compilador. Cuantas ms pasadas, el proceso de compilacin es ms
completo, aunque ms lento.

Traductor o compilador incremental, interactivo o conversacional: Es un
tipo de compilador que, al detectar un error, intenta compilar el cdigo del
entorno en donde est el error, no todo el programa de nuevo.
2


El programa fuente es el conjunto de oraciones escritas en el lenguaje
fuente, y que normalmente estar en un fichero.

Bootstraping: Mediante esta tcnica se construye un lenguaje L utilizando el
mismo lenguaje L, realizando mejoras en el propio compilador como puede
ser, por ejemplo, la inclusin de nuevas sentencias y estructuras.

Existe una notacin grfica, denominada Notacin de Bratman, que muestra
como se realiza un compilador:

LF -> Lenguaje fuente
LO -> Lenguaje objeto
LC -> Lenguaje del compilador

Decompilador: Conjunto de programas que a partir de un cdigo de bajo nivel
obtiene cdigo de alto nivel.

1.1 Estructura de un compilador.

Es importante comentar que aunque aqu se especifica un mdulo de anlisis
semntico, ste tambin est implicado en la generacin de cdigo.

Es cada una de esas etapas pueden aparecer errores que han de ser
detectados. Las etapas 1, 2 y 3 se denominan etapas de anlisis y las 4, 5 y 6
etapas de sntesis.

Etapa 1. Analizador lxico o scanner.

En esta etapa, es preciso mantener separados cada uno de los tokens y
almacenarlos en una tabla de smbolos. Aqu ya se podra detectar algn
error, por ejemplo, poner FAR no correspondera a una palabra del lenguaje.
No slo en esta etapa se utiliza la tabla de smbolos ya que la informacin ah
Programa
Fuente
ANALI ZADOR
LXI CO
scanner
ANALI ZADOR
SI NTCTI CO
par ser
ANALI ZADOR
SEMNTI CO
GENERACI N
DE CDI GO
I NTERMEDI O
GENERACI N
DE CDI GO
OPTI MI ZADOR
Programa
Objeto
1
2 3
4 5 6
LF LO
LC
3
contenida se va completando durante las siguientes fases; por ejemplo,
tambin almacenaremos el tipo establecido en su definicin.

Etapa 2. Analizador sintctico o parser.

Se pretende ver la estructura de la frase, ver si los elementos tienen
estructura de frase del lenguaje.

Etapa 3. Analizador semntico.

Se analiza si la frase encontrada tiene significado. Utilizar la tabla de
smbolos para conocer los tipos de las variables y poder estudiar el significado
semntico de la oracin. Por ejemplo, si tenemos:

a = b + c

y sabemos que b es de tipo carcter y c es de tipo entero entonces,
dependiendo del lenguaje, puede significar un error.

Etapa 4. Generacin de cdigo intermedio.
Se traduce el programa fuente a otro lenguaje ms sencillo. Esto servir para:
- Facilitar el proceso de optimizacin.
- Facilitar la traduccin al lenguaje de la mquina.
- Compatibilizacin (el anlisis ser independiente de la computadora
fsica, con el consecuente ahorro econmico).

Etapa 5. Optimizador.

Intenta optimizar el programa en cuanto a variables utilizadas, bucles, saltos
en memoria, etc.

Etapa 6. Generacin de cdigo.
Construye del programa objeto, esto es, se genera el cdigo en ensamblador,
propio de la plataforma en la que se ejecutar el programa. La tabla de
smbolos contendr normalmente informacin detallada sobre la memoria
utilizada por las variables.

1.2 Ejemplo de las fases de un compilador.

Supongamos una instruccin de la siguiente forma:

posicion := inicial + velocidad * 60

En la tabla de smbolos tendremos estas tres variables registradas de tipo
real. Veamos las fases por las que pasara dentro del compilador:
ANALIZADOR LXICO

Id1 = id2 + id3 * 60
4

ANALIZADOR SINTCTICO
ANALIZADOR SEMNTICO
GENERADOR DE CDIGO INTERMEDIO

temp1 := enteroAreal (60)
temp2 := id3 * temp1
temp3 := id2 + temp2
id1 := temp3

OPTIMIZADOR DE CDIGO

temp1 := id3 * 60.0
id1 := id2 + temp1

GENERADOR DE CDIGO

MOVF id3, R2 ADDF R2, R1
MULT #60.0, R2 MOVF R1, id1
MOVF id2, R1
id1
:=
+
id2 *
60
id3
id1
:=
+
id2 *
60
id3
enteroAreal
5

2 LENGUAJES Y GRAMTICAS.
Definiciones:

Alfabeto: Conjunto de smbolos que nos permiten construir las sentencias del
lenguaje.

Tira de caracteres: Yustaposicin o concatenacin de los smbolos del
alfabeto.

Tira nula ( c): Tira de longitud 0, es la tira mnima del lenguaje

Longitud de una tira: El nmero de caracteres que tiene la tira. Si tenemos
una tira x, su logitud se representa como |x|.

Ejemplo.- x = abc |x| = 3
|| = 0

Potencia de una tira: Concatenacin de una tira consigo misma tantas veces
como indique el exponente.

Ejemplo.- x = abc
x
2
= abcabc
x
0
=
x
1
= abc

Cabeza de una tira: El conjunto de subtiras que podemos formar tomando
caracteres desde la izquierda de la tira.

Ejemplo.- x = abc
Head (x) o Cabeza (x) = , a, ab, abc

Cola de una tira: Conjunto de subtiras que podemos formar tomando
caracteres desde la derecha de la tira.

Ejemplo.- x = abc
Tail (x) o Cola (x) = , c, bc, abc

Producto Cartesiano: Sean A y B dos conjuntos de caracteres, el producto
cartesiano entre ellos (AB) se define como:

AB = { xy / xeA, yeB }

Definimos Potencia A
n
= A.A
n-1
; A
0
={} ; A
1
= A
Definimos Cierre Transitivo A
+
= U
i>0
A
i

Definimos Cierre Transitivo y Reflexivo A
*
= U
i>0
A
i

A partir de estas dos ltimas tenemos que: A
*
= A
+
U A
0
= A
+
U {}
6
Definicin: Un lenguaje estar formado por dos elementos: un diccionario y
un conjunto de reglas.

Diccionario: significado de las palabras del lenguaje.
Conjunto de reglas (gramtica): son las que indican si las sentencias
construidas a partir de las palabras pertenecen o no al lenguaje.

Tenemos distitas formas de definir un lenguaje:

a) Enumerando sus elementos.
Ejemplo.- L
1
= { a, abc, d , ef, g }
b) Notacin matemtica.
Ejemplo 1.- L
2
= { a
n
/ neN} = { , a, aa, ... }
Ejemplo 2.- L
3
= { x / |x| = 3 y xeV }
V = { a, b, c, d }
Cuntos elementos tiene el lenguaje?
VR
4
3
= 4
3
= 64 elementos

2.1 Notacin de Chomsky (1959).

Esta notacin define una gramtica como una tupla (N, T, P, S)
N es el conjunto de los no terminales (conjunto de smbolos que introducimos
en la gramtica como elementos auxiliares que no forman parte de las
sentencias del lenguaje).
T es el conjunto de los terminales (son los smbolos o caracteres que forman
las sentencias del lenguaje).
P es el conjunto de reglas de produccin (reglas de derivacin de las tiras).
S es el axioma de la gramtica, S est incluido en N (es el smbolo inicial o
metanocin).

Ejemplo.-

G1 = { {S}, {a,b}, P, S}
P: S ab
S aSb

Si aplicamos las reglas a la cadena aabb, su rbol de derivacin sera:
Lenguaje L(G): Es el conjunto de las tiras con smbolos terminales que
podemos formar a partir del axioma de la gramtica aplicando las reglas de
produccin P que pertenecen a la gramtica.

S
b S a
a b
7
2.2 Clasificacin de Chomsky.

Esta clasificacin define cuatro tipos dependiento de las reglas de produccin
de la gramtica.

a) Gramticas tipo 0, gramticas con estructura de frase o reconocibles por
una Mquina de Turing.

G = (N, T, P, S) o |
o e (N U T)
+
(NOTA: o nunca puede ser )
| e (N U T)
*
(NOTA: | puede ser )

Con esta definicin podemos observar que podra admitir cualquier estructura
de frase.

b) Gramticas tipo 1, gramticas sensibles al contexto o dependientes del
contexto.

G = (N, T, P, S) oA| ov|
o, | e (N U T)
*

v e (N U T)
+

A e N

Se puede ver que, si llamamos oA| = x1 y ov| = x2, entonces |x2| > |x1|

Basndonos en esta propiedad podemos definir este tipo de gramticas
tambin de la siguiente forma (tiene una peculiaridad que veremos al final):

G = (N, T, P, S) e v
e, v (N U T)
+

|e| s |v|

c) Gramticas tipo 2, gramticas de contexto libre (GCL) o independientes
del contexto (GIC).

G = (N, T, P, S) A o
A e N
o e (N U T)
*


Este tipo de gramtica es la de los lenguajes de alto nivel, ser la que
usaremos durante el curso.

d) Gramticas tipo 3, gramticas regulares.

G = (N, T, P, S) A aB ; A a ; A
a e T
A, B e N

8
Las gramticas tipo 3 son las ms restrictivas y las tipo 0 las menos pero existe
una peculiaridad porque, de forma terica extricta, un lenguaje
independiente del contexto es tambin un lenguaje dependiente del
contexto, pero una gramtica independiente del contexto puede no ser una
gramtica dependiente del contexto. Esto ocurrir si la gramtica contiene
reglas .

Tambin existe una pequea diferencia entre las dos definiciones mostradas
de gramticas tipo 1. Ejemplo.-

G = (N, T, P, S)
S ASBc
bB bb Es tipo 1 segn la 2 definicin de tipo 1, pero es
S aBc tipo 0 si usamos la 1 definicin de tipo 1 pues la
BC bc regla CB BC no la cumple.
CB BC
CC cc
AB ab

2.3 Gramticas de contexto libre (GCL).
Recordemos la definicin:

G = (N, T, P, S) A o
A e N
o e (N U T)
*


Derivacin: o | (se lee o deriva |), o y | son dos tiras, si se puede
escribir:
o = oA , | = ov , o y son dos tiras y aplicamos A v
o y pueden ser tiras nulas, con lo cual sera una derivacin directa.

Una derivacin de longitud n, de la forma:

o
0
o
1
o
2
.... o
n


se representar como:

o
0

+
o
n
o
0
* o
n
(incluyendo la derivacin nula, sin cambio)

Ejemplo.- Gramtica S aSb |
S aSb aaSbb aaaSbbb aaaaSbbbb aaaaaSbbbbb
Es una derivacin de longitud 5.

Sentencias, con G = (N, T, P, S), son el conjunto de tiras de la siguiente
forma, L(G) = { e / S * e, e e T*}.

9
S
H c B d
c d
H c
c d
Formas sentenciales, con G = (N, T, P, S), son el conjunto de combinaciones
de terminales y no terminales que se pueden generar aplicando las reglas de
derivacin de la siguiente forma, D(G) = { o / S * o, o e (N U T)* }

Un rbol sintctico es una representacin grfica de una regla que se realiza
mediante un rbol. Cada nodo es la parte izquierda de una regla aplicada
(siendo la raz del rbol la metanocin); a continuacin se colocan tantas
ramas como nodos terminales o no terminales tengamos en la regla en su
parte derecha, incluyendo todas las derivaciones que se hayan hecho.

Ejemplo.-

S BcdH
B Hc
H cd






Derivacin a la izquierda: es la derivacin que se realiza sustituyendo las
metanociones que se encuentran ms a la izquierda de la forma sentencial.

Derivacin a la derecha: es la derivacion que se realiza sustituyendo las
metanociones que se encuentran ms a la derecha de la forma sentencial.

Ejemplo.-

S BcdH
B b
H h



2.4 Diagramas de Conway.
Este tipo de diagrama se utiliz por primera vez para representar el lenguaje
PASCAL. Es un grafo dirigido formado por rectngulos y crculos, el rectngulo
corresponde a los no terminales y el
crculo indica un smbolo terminal.
Servir para representar grficamente
las reglas de produccin de la
gramtica de un lenguaje.


S
H c B
b
d
Es una der i vaci n
a l a i zqui er da
S
H c B
h
d
Es una der i vaci n
a l a der echa
i dent i f i cador ( )
;
10
2.5 Reglas BNF.
La notacin Backus-Naur (ms comunmente conocida como BNF o Backus-Naur
Form) es una forma matemtica de describir un lenguaje. Esta notacin fue
originalmente desarrollada por John Backus basndose en los trabajos del
matemtico Emil Post y mejorada por Peter Naur para describir la sintaxis del
lenguaje Algol 60. Por ello Naur la denominaba BNF por Backus Normal Form,
mientras en la bibliografa aparece como Backus-Naur Form.

Esta notacin nos permite definir formalmente la gramtica de un lenguaje
evitando la ambigedad, definiendo claramente qu est permitido y qu no
lo est. La gramtica ha de ser, al menos, una gramtica de contexto libre,
de tipo 2. De hecho, existe una gran cantidad de teora matemtica
alredededor de este tipo de gramticas, pudindose construir mecnicamente
un reconocedor sintctico de un lenguaje dado en forma de gramtica BNF (en
realidad en algunos tipos de gramticas esto es imposible, aunque pueden ser
modificadas manualmente para que s lo sea, de ello hablaremos a
continuacin).

La forma de una regla BNF es la que sigue:

smbolo alternativa1 | alternativa2 ...

NOTA: Tambin se puede utilizar, en lugar de , el smbolo :=

Ejemplo.-

S - D | D
D L | L . L
L N | N L
N 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

S es la metanocin
D es un nmero decimal
L es una lista de dgitos
N es un nmero, un dgito



Por ejemplo, el rbol para el nmero "33.5"
sera el que se muestra a la derecha.




S
D
L . L
N L
3 N
N
5
3
11
2.6 Problemas en las GCL.
En este apartado describiremos los distintos problemas que nos vamos a
encontrar en las GCL as como los mecanismos de los que disponemos para
resolverlos.
2.6.1 Recursividad.
Tenemos diferentes tipos de recursividad. Supongamos que tenemos una regla
de la forma A oA|

a) Si o = , A A|, A e N, | e (N U T)* diremos que la regla es recursiva por
la izquierda.

b) Si | = , A oA, o e (N U T)*, diremos que la regla es recursiva por la
derecha.

c) Si o = y | = diremos que se trata de una recursividad autoimbricada.


PROBLEMA: Recursividad por la izquierda.

La recursividad por la izquierda nos crear problemas pues en el desarrollo
del rbol, que habitualmente analizaremos de izquierda a derecha. Solucionar
este problema ser especialmente interesante en el caso del anlisis
sintctico (parsing).

Supongamos que tenemos:

A Ao
1
| Ao
2
| ... | Ao
q
| |
1
| |
2
| ... | |
p


Esto podemos ponerlo de la siguiente forma:

A Ao
i
1 s i s q
A |
j
1 s j s p

Estas reglas podemos transformarlas de la siguiente forma sin variar el
lenguaje generado:

A |
j
A 1 s j s p
A o
i
A , A 1 s i s q

Por ejemplo, si tenemos las reglas:

A Aa | Ab | c | d

La transformacin podra ser la siguiente:

A cA | dA
12
A aA | bA |

Si no queremos introducir reglas en la gramtica la transformacin podra
ser de la siguiente forma:

A |
j
, A |
j
A 1 s j s p
A o
i
, A o
i
A 1 s i s q

Siguiendo el ejemplo anterior, la transformacin sera:

A c | d | cA | dA
A a | b | aA | bA

Ejemplo 1.-

E E + T | T
T T * F | F
F (E) | x

Vamos a resolver la recursividad por la izquierda paso a paso:

En el caso de E E + T | T . Esto es de la forma A A o | | con o = "+ T" y |
= "T". Cambindolo como A | A', A' o A' | , tenemos:

E T E'
E' + T E' |

En el caso de T T * F | F hacemos lo mismo:

T F T'
T' * F T' |

La gramtica resultante es:

E T E'
E' + T E' |
T F T'
T' * F T' |
F (E) | x

Ejemplo 2.-

S uBDz S uBDz
B Bv | w ===> transformamos as ===> B wB
=> B vB |
D EF D EF
E y | E y |
F x | F x |
13
2.6.2 Reglas con factor repetido por la izquierda.
Si tenemos una regla de la forma:

A oB | oC

Cuando vamos a realizar el reconocimiento de izquierda a derecha, al
encontrar un o, algunos analizadores no podrn decidir cual de las dos reglas
aplicar. Para solucionar este problema realizamos una factorizacin de la
siguiente forma, sin variar el lenguaje:

A oA
A B | C

2.6.3 Ambigedad.
Diremos que una gramtica G es ambigua si el lenguaje definido por ella tiene
alguna sentencia para la cual existe ms de un rbol sintctico. Hay que tener
claro que la que es ambigua es la gramtica, no el lenguaje y que con una
gramtica ambigua no ser posible implementar un analizador. Asimismo,
siempre es posible modificar las reglas de la gramtica para solucionar la
ambigedad y manteniendo el mismo lenguaje.

Ejemplo.-

G = { {s}, {a,+,*}, P, S }

P: S a
S S+S
S S*S

Si dibujamos el rbol de derivacin para "a*a+a", nos puede salir de dos
formas distintas:
Aqu se ve claramente que la gramtica es ambigua, pues podemos aplicar
indistintamente la segunda o la tercera regla.

S
a
S
+
S S
*
a a
S
a
S
*
S S
+
a a
14
Existen algunas soluciones para este tipo de ambigedad sin reescribir la
gramtica y como un mecanismo externo:

a) Dar mayor prioridad al producto que a la suma.
b) En caso de igualdad en la prioridad obligar al uso de parntesis.

2.7 Simplificacin de gramticas.
Nos permiten eliminar smbolos no terminales o reglas que no aportan nada al
lenguaje.

Sabemos que un lenguaje podemos describirlo como:

L(G) = { e / S * e, e e T}

2.7.1 Deteccin de un lenguaje vaco.
Vamos a ver un algoritmo para saber si una determinada gramtica genera el
lenguaje vaco.

Algoritmo L(G) = C?

BEGIN
viejo = {C}
nuevo = {A / (A t) e P, t e T*}
WHILE nuevo = viejo do BEGIN
viejo := nuevo
nuevo := viejo U { B / (B o) e P, o e (T U viejo)*}
END
IF S e nuevo THEN vacio := "NO" ELSE vacio := "SI"
END.

Ejemplo.-

S Ac
A a | b

Aplicando el algoritmo, primero tendramos el conjunto {A}, pues es el nico
que contiene en su parte derecha nicamente terminales. En la segunda
pasada ya se incluira S pues S Ac, una combinacin de un terminal y un
elemento del conjunto de la pasada anterior, es decir {A}.

2.7.2 Eliminacin de reglas lambda ().
Una regla- es de la forma A. Se dice una gramtica sin lambda si verifica
que no existen reglas de la forma A en P excepto en el caso de la
metanocin, para la cual puede existir la regla de la forma S siempre y
15
cuando S no est en la parte derecha de una regla de P. Es decir, no puede
ser un elemento del lenguaje, si no no se puede eliminar completamente
(debemos de mantener S).

Un no terminal A es anulable si existe una regla de la forma A * .

TEOREMA

Sea el lenguaje L=L(G), con una gramtica de contexto libre G=(N, T, P, S)
entonces L - {} es L(G) con Gsin smbolos intiles ni reglas-.

Algoritmo de deteccin de smbolos anulables

BEGIN
viejo := {C}
nuevo := {A / A e P}
WHILE viejo = nuevo DO
BEGIN
viejo := nuevo
nuevo := viejo U {B / B o, o e viejo*}
END
ANULABLES := nuevo
END

Una vez que tenemos ANULABLES, Pse construye de la siguiente forma:

i) Eliminamos todas las reglas- excepto la S , si existe.
ii) Con reglas de la forma A o
0
B
0
o
1
B
1
o
2
B
2
...o
k
B
k
siendo k > 0, estando las
B
i
en el conjunto ANULABLES pero las o
i
no, entonces aadimos en P las
reglas de la siguiente forma A o
0
X
0
o
1
X
1
o
2
X
2
...o
k
X
k
, en donde las X
i

sern B
i
o bien , realizando todas las combinaciones posibles.
iii) Si S est en ANULABLES aadimos a P la regla S S | .

Ejercicio.-

S aS | AB | AC
A aA |
B bB | bS
C cC |
ANULABLES = { A, C, S}

S S |
S aS | a | AB |B | AC | A | C
A aA | a
B bB | bS | b
C cC | c
16
2.7.3 Eliminacin de reglas unitarias o reglas cadena.
Denominamos reglas unitarias o reglas cadena a las reglas del tipo A B, con
A, B e N. En cualquier caso, nos interesar eliminarlas pues no aaden nada a
la gramtica.
A continuacin veremos un algoritmo para la eliminacin de este tipo de
reglas, partimos de una gramtica G = (N, T, P, S) y la convertimos en una
gramtica G = (N, T, P, S). Como condicin necesaria tenemos que las
gramticas no tengan reglas .

En el algoritmo primero construiremos una serie de conjuntos (NA, NB, ..),
tantos como nodos no terminales tenga la gramtica, utilizando este
algoritmo para cada no terminal.

Algoritmo

BEGIN
viejo := {C}
nuevo := {A}
WHILE viejo = nuevo DO
BEGIN
viejo := nuevo
nuevo := viejo U {C / B C, B e viejo}
END
NA := nuevo
END

Una vez construidos los conjuntos NX, generamos el conjunto P de la
siguiente forma:

Si B o e P, y no es una regla unitaria, entonces hacemos que A o e P
A en los cuales B e NA.

NOTA: con este algoritmo tambin eliminaremos las derivaciones de la forma:
A * X , es decir A B C X, y no solamente las cadenas directas.

Ejemplo.-

E E+T | T
T T*F | F
F (E) | a

Aplicando el algoritmo, algo muy sencillo, vemos que los conjuntos NX son:

NE = {E, T, F}
NT = {T, F}
NF = {F}

Y la gramtica sin reglas cadena resultante sera:
17

E E+T
E T*F T T*F
E (E) T (E) F (E)
E a T a F a
2.7.4 Eliminacin de smbolos intiles.
Dada una gramtica G= (N, T, P, S), decimos que un smbolo X es un smbolo
til si tenemos una cadena de derivaciones:

S * oX| * t , t e T*, o y | e (N U T)*

La primera parte (S * oX|) indica que X es un "smbolo accesible", es decir,
puedo conseguir una cadena que la contenga, por derivacin desde el axioma
de la gramtica.

La segunda parte (oX| * t) indica que X es un "smbolo terminable", es decir,
podemos dar lugar, partiendo de l, a una cadena en la que todos los
elementos estn en T*.

Entonces, por negacin de cualquiera de estas dos caractersticas tendramos
un smbolo intil.

Algoritmo para la eliminacin de smbolos no terminables

Veremos a continuacin un algoritmo para, partiendo de una gramtica G =
(N, T, P, S), llegar a otra gramtica G= (N, T, P, S) en la que no existen
smbolos no terminables, expresado en forma matemtica:

A e N - t e T* / A * t

Lo que haremos ser incluir A en N si existe una regla de la forma A t o si
tenemos A x
1
x
2
...x
n
con x
i
e (N U T).

Algoritmo

BEGIN
viejo = {C}
nuevo = { A / A t e P, t e T*}
WHILE viejo = nuevo DO
BEGIN
viejo := nuevo
nuevo := viejo U {B / B o e P, o e (T U viejo)*}
END
N := nuevo
P := reglas cuyos smbolos estn en (N U T)
END

18
Ejemplo.-

A a A es terminable pues genera un terminal
B c B es tambin terminable por la misma razn
H Bd Como B c, H tambin es terminable

Algoritmo para la eliminacin de smbolos no accesibles.

Este algoritmo transformar una gramtica G = (N, T, P, S) en otra gramtica
G= (N, T, P, S) en la que no existen smbolos no accesibles, expresado en
forma matemtica:

x
i
e (N U T), - o,| e (NU T)* / S * ox
i
|

Algoritmo

BEGIN
viejo := {S}
nuevo := {x / S ox| e P}
WHILE viejo = nuevo DO
BEGIN
viejo := nuevo
nuevo := viejo U {y / A oy|, A e viejo}
END
N:= nuevo N
T:= nuevo T
P:= Las reglas que hacen referencia a N U T
END

Es importante hacer notar que para la eliminacin de smbolos intiles es
preciso aplicar los dos algoritmos anteriores y en este mismo orden.

Ejercicio.- Eliminar los smbolos intiles en la siguiente gramtica.
G = (N, T, P, S)
N = {S, A, B, C, D}
T = {a, b, c}
S aAA
A aAb | aC
B BD | Ac
C b

Aplicamos primero el algoritmo de eliminacin de smbolos no terminables:

viejo nuevo
Pasada 1
C
C Regla que genera un terminal
Pasada 2 C C, A C es generado por A
Pasada 3 C, A C, A, S, B A es generado por S y por B
Pasada 4 C, A, S, B C, A, S, B Aqu paramos
La nueva gramtica es la siguiente:
19

N= {C, A, S, B}
S aAA
A aAb | aC
B Ac
C b

Ahora es cuando podemos aplicar el segundo algoritmo, el de eliminacin de
smbolos no accesibles:

viejo nuevo
Pasada 1 S S, a, A
Pasada 2 S, a, A S, a, A, b, C
Pasada 3 S, a, A, b, C S, a, A, b, C

T= { a, b }
N= { S, A, C }
S aAA
A aAb | aC
C b

2.8 Gramtica limpia.
Decimos que una gramtica G = (N, T, P, S) es limpia (en mucha de la
bibliografa aparece como propia por una mala traduccin del francs
propre, que significa limpia) si no posee ciclos, no tiene reglas y no tiene
smbolos intiles.

Una gramtica sin ciclos es aquella que no tiene reglas de la forma A
+
A,
con AeN. Es importante hacer notar que eliminando reglas-, reglas unitarias
o cadena y smbolos intiles ya resolvemos el problema.

2.9 Forma normal de Chomsky (FNC).
Una gramtica G=(N, T, P, S) est en forma normal de Chomsky si las reglas
son de la forma: A BC A a, con A,B,C e N y a e T. Como se puede
observar, la FNC no admite recursividad en S.

A continuacin veremos un algoritmo para convertir una gramtica a la forma
normal de Chomsky. Para ello, exigimos a la gramtica original, G, que sea
una gramtica propia y sin reglas unitarias

Algoritmo

BEGIN
P= {C}
Aadimos a P las reglas del tipo A a
20
Aadimos a P las reglas del tipo A BC
IF A x
1
x
2
...x
k
e P, k>2 THEN
BEGIN
Aadimos a P A x
1
< x
2
...x
k
>
< x
2
...x
k
> x
2
< x
3
...x
k
>
< x
3
...x
k
> x
3
< x
4
...x
k
>
< x
k-2
> x
k-1
x
k

END
IF A x
1
x
2
e P, si x
1
e T x
2
e T THEN
BEGIN
Llamamos x
a
al x
i
e T
Sustitumos x
a
por x
a
en esa regla de P
Aadimos a P x
a
' x
a

END
END

Ejercicio.- Convertir la siguiente gramtica a la FNC.

S BA
A 01ABO
A 0
B 1

El nico caso problemtico es el de A 01AB0, lo resolvemos as.
A 01AB0 A A
1
A
2
A
1
0 A
2
1AB0 A
2
A
3
A
4

A
3
1 A
4
ABO A
4
AA
6
A
5
B0 A
5
BA
6

A
6
0

En negrita estn las reglas que definitivamente quedan en la gramtica.

2.10 Resumen.
Resumiendo, los problemas que podemos encontrarnos en las gramticas son:

i) Recursividad por la izquierda.
ii) Factor repetido por la izquierda.
iii) Ambigedad.

Como resumen de la simplificacin de gramticas, los pasos a seguir son los
siguientes:

i) Eliminar reglas-.
ii) Eliminar reglas unitarias o cadena.
iii) Eliminar smbolos intiles (1 no terminables y 2 no accesibles).

21
2.11 Ejercicios.
Ejercicio1.-

Simplificar la siguiente gramtica:

S aS | AB | AC
A aA |
B bB | bS
C cC |

Solucin 1.-

S aS | a | AB | bB | bS | b | AC | aA | a | cC | c |
S aS | a | AB | bB | bS | b | AC | aA | a | cC | c
A aA | a
B bB | bS | b
C cC | c

Ejercicio 2 .-

S ACA | CA | AA | C | A |
A aAa | aa | B | C
B bB | b
C cC | c

Solucin 2.-

S ACA | CA | AA | cC | c | aAa | aa | bB | b |
A aAa | aa | bB | b | cC | c
B bB | b
C cC | c

Ejercicio 3.-

S AC | BS | B
A aA | aF
B cC | D
D aD | BD | C
E aA | BSA
F bB | b

Solucin 3.-

Vaco


22

3 ANLISIS LXICO.
En el anlisis lxico analizamos token a token el archivo fuente. El analizador
lxico se comunica con la tabla de smbolos (TDS) en donde se encuentra la
informacin sobre los tokens, asimismo, tambin se comunica con el mdulo
de errores.

El scanner abre el fichero fuente y convierte los datos a un formato ms
regular, deshaciendo marcos, comprobando los formatos si el lenguaje es de
formato fijo, etc. Posteriormente pasa a analizar los tokens (variables,
instrucciones, etc).

Una mquina reconocedora o autmata es un dispositivo formal que nos
permite identificar un lenguaje en funcin de la aceptacin o no de las
cadenas que lo forman. Esto es, crearemos un autmata que nos reconozca si
una cadena determinada pertenece o no al lenguaje.

Esta mquina reconocedora tendr una cinta de entrada dividida en celdas
con unos smbolos que denotaremos como Te. Tambin tendremos un smbolo
especial que ser el $ que nos indicar el fin de la tira de entrada. A veces
tambin dispondremos de otro alfabeto, denominado Tp, en el caso de
utilizar autmatas con pila.

Vamos a tener movimientos que dan lugar a almacenamientos en memoria o
cambios de estado. Para realizar este trabajo dispondremos de una memoria
con posibilidad de bsqueda y un sistema de control de estados para manejar
la transicin entre los estados.

Denominamos configuracin del autmata al conjunto de elementos que
definen la situacin del autmata en un momento t. Existen dos
configuraciones especiales: inicial y final, un autmata ha reconocido una
cadena cuando pasa del estado inicial a alguno de los estados finales. Aqu
podemos decir que el lenguaje es el conjunto de tiras que reconoce el
autmata.

Hablaremos de dos tipos de autmatas:

i) Determinista: Dada una entrada existe una nica posibilidad de transicin
desde un estado determinado con una entrada determinada (si es con
pila, usando tambin el mismo valor de la pila). S
i
S
j
.
ii) No determinista: Ante una entrada (si es con pila, teniendo en cuenta el
mismo valor en la pila tambin) existirn varios estados a los que puede
transitar el autmata. S
i
S
j
o bien S
i
S
k
.

23
3.1 Tipos de mquinas reconocedoras o autmatas.
a) Autmatas finitos, reconocen lenguajes regulares (Gramticas tipo 3).
Podemos representarlo como una expresin regular, a partir de ella
obtener un Autmata Finito No Determinista (AFND), para luego
convertirlo en un Autmata Finito Determinista (AFD).
b) Autmatas con pila, reconocen lenguajes tipo 2 (Gramticas de contexto
libre, tipo 2)
c) Autmatas bidireccionales o autmatas lineales acotados (LBA). Para
Gramticas tipo 1. La cinta de entrada de la mquina est limitada a la
longitud de la entrada a reconocer.
d) Mquinas de Turing para el reconocimiento de lenguajes tipo 0.

3.2 Autmatas Finitos.
Un autmata finito podemos definirlo como una tupla de la forma:

AF = (Q, Te, o, q
0
, F)

Q es el conjunto de estados.
Te es el alfabeto de entrada.
q
0
es el estado inicial.
F es el conjunto de estados finales (F c Q).
o es la funcin:
Q x {Te U {}} P(Q)

La configuracin del autmata la representaremos con:
(q, t) q es el estado y t es la tira por ejecutar.

Dos configuraciones especiales sern:
(q
0
, e) estado inicial, tenemos la tira completa.
(q
f
, ) estado final y tira vaca.

Llamamos movimiento a la transicin de un estado a otro y lo representamos
de la siguiente forma:

(q, ao) |---- (q, o)

Entonces decimos que q = o(q,a), en el caso de un AFD q sera el nico
estado al que podra transitar, en el caso de un AFND existiran varios estados,
es decir, o(q,a) sera un conjunto.

Para representar k pasos pondremos:

|--
k
--

El lenguaje definido por un AF podemos expersarlo como:

24
L(AF) = { t / t eTe*, (q
0
,t) |--*-- (q
i
,), qi e F}

Ejemplo.-

AF = (Q,Te, o, q
0
, F)

o
a b c
0 0, 1 0, 2 0, 3
1 1, 4 1 1
2 2 2, 4 2
3 3 3 3, 4
4 - - -

Como se puede observar, se trata de un AFND pues existen varias transiciones
para el mismo estado y entrada.

Este sera el diagrama de transiciones:












Para realizar un compilador no es una buena opcin utilizar un AFND pues el
recorrido del rbol es ms lento (habr muchas ramas intiles). Normalmente
nos interesar convertir el AFND en un AFD, algo, que como nos muestra el
teorema que viene a continuacin, es siempre posible.

Teorema

Sea L un conjunto aceptado por un AFND, entonces existe un AFD que acepta
L.

Teorema

Sea r una expresin regular, entonces existe un AFND con transiciones que
acepta L(r).

Teorema

Si L es aceptado por un AFD, entonces L se donota por una expresin regular.

Estos tres teoremas nos permiten decir lo siguiente:
0 1
2
3 4
a
a
c
c
a,b,c
a,b,c
a,b,c
b
b
a,b,c
25

i) L es un conjunto regular.
ii) L se denota por una expresin regular.
iii) L puede ser definido por un AFND.
iv) Cualquier AFND puede ser transformado en un AFD.

3.3 Conversin de una Gramtica Regular en un Autmata finito.
Aqu veremos como podemos convertir una gramtica regular en un autmata
finito, para ello utilizaremos un ejemplo:

Una gramtica regular es de la forma:

G = (N, T, P, S) A aB ; A a ; A , a e T, A, B e N

Vamos a convertirla en un autmata AFND (Q, Te, o, q
0
, F) en el cual:

i) Q = N U {Z}, Z e N si P contiene alguna regla de la forma A a
Q = N en otro caso (cuando slo tenemos reglas de la forma A )
ii) o(A, a) = B si A aB e P
o(A, a) = Z si A a e P
iii) F = {A / A e P} U Z si Z e Q
F = {A / A e P} en otro caso

Ejemplo 1.- Sea la gramtica:

S aS | bB | a
B bB |

El autmata sera:
Ejemplo 2.- Sea la gramtica:

S aS | bB |
B aB | bS | bC
C aC | a

S
b
b
B
a
a
Z
26
El autmata sera:

3.4 Expresin regular.
Es una forma de definir un lenguaje asociado a las gramticas de tipo 3. Una
expresin regular se define a partir de una serie de axiomas:

i) c |c| = 0 {c} es una expresin regular (ER).
ii) Si a e T (alfabeto), a es una ER.
iii) Si r,s son ER representaremos:
(r) | (s) L(r) U L(s)
(r) (s) L(r) L(s)
(r)* (L(r))*
(r) NOTA: pueden ponerse parntesis

Propiedades:

r | s s | r Conmutativa |
r | (s | t) (r | s) | t Asociativa |
(r s)t r (s t) Asociativa de la concatenacin
r (s | t) r s | r t Concatenacin distributiva sobre |
(s | t) r s r | t r Concatenacin distributiva sobre |
r c c r r c elemento identidad para concatenacin
r* (r | c)*
r** r* Idempotencia

L U M = { s / s e L s e M}
LM = { st /s e L y t e M}

Adems tenemos que:

L* = U

i=0
L
i

L
+
= U

i=1
L
i


Lgicamente: L
i
= L
i-1
L

* tiene mayor precedencia, luego concatenacin y por ltimo la |. Todas
ellas son asociativas por la izquierda.

S
a
b
B
a
a
Z
C
b
a
b
27
Llamamos conjunto regular al lenguaje asociado a una expresin regular.

Ejemplo.- Identificadores en Pascal
Su expresin regular sera: letra (letra | nmero)*

Ejemplo.-
E = T = alfabeto = {a, b}
a | b = {a, b}
a* = {c, a, aa, ...}
(a | b) (a | b) = {aa, bb, ab, ba}
(a | b)* = (a*b*)*

NOTA: Algunas abreviaturas utilizadas en la bibliografa son las siguientes:

r? = r | c
r
+
= rr*
r* = r
+
| c
(r)? = L(r) U {c}
[a, b, c] = a | b | c
[a-z] = a | b | c | ... | z

3.5 Algoritmo de Thompson.
Este algoritmo nos va a permitir convertir una expresin regular en un
autmata finito no determinista con transiciones (AFND-).

Un AFND- es un AFND al que incorporamos a Te un elemento ms, el , con
lo cual: Q x Te U {} Q. Es decir, se puede mover de estado si usar entrada.

Los pasos a seguir son los siguientes:

i) Para construiramos:

ii) a e Te construiramos:

iii) Tenemos M(s), M(t), dos AFND para 2 expresiones regulares s y t, de la
forma:

M(s)
0
f
M(t)
0
f
0 f
a
0 f

28

Entonces s|t podemos reconocerlo con un AFND- de la forma:

Entonces st podemos reconocerlo con un AFND- de la forma:


Entonces s* podemos reconocerlo con un AFND- de la forma:

Ejemplo.- Sea la expresin regular r = (a | b)* abb, crear el AFND-.
3.6 Transformacin de un AFND- en un AFD.
Primeramente definimos:

Si S es un estado:
Cerradura-E (S) = { S
k
e AFND / S

S
k
}

Siendo W un conjunto de estados:
Cerradura-E (W) = { S
k
e AFND / - S
j
e W, S
j

S
k
}

Y la funcin de movimiento (llammosle Mueve):
Mueve (W,a) = { S
k
e AFND / - S
j
e W, S
j

a
S
k
}

El mecanismo para realizar la transformacin consiste en:

M(s)
0a
fa
M(t)
0b
fb
0
0




M(s)
0
fa
M(t)
0b
f

M(s)
0a
fa
0
f




2 3
4 5
1
6




0
7 8 9 10

a b b
a
b


29
1) Calcular primero el nuevo estado A = Cerradura-E(0), es decir, la
Cerradura-E del estado 0 del AFND-.
2) Calculamos Mueve (A, a
i
), a
i
e T. Luego calculamos Cerradura-E (Mueve
(A, a
i
)), a
i
e T, es decir, para todos los terminales, y as vamos generando
los estados B, C, D...
3) Calculamos Mueve (B, a
i
), a
i
e T, y hacemos lo mismo. Esto se repite
sucesivamente hasta que no podamos inclur nuevos elementos en los
conjuntos Cerradura-E.

Algoritmo

BEGIN
Calcular Cerradura-E (0) = Estado A;
Inclur A en NuevosEstados;
WHILE no estn todos los W de NuevosEstados marcados DO BEGIN
Marcar W;
FOR cada a
i
e Te DO BEGIN
X = Cerradura-E (Mueve (W, a
i
));
IF X no est en el conjunto NuevosEstados aadirlo;
Transicin [W, a] = X;
END
END
END

Sern estados finales todos aquellos que contengan alguno de los estados
finales del autmata original.

Ejemplo.- Si tenemos el siguiente AFND- que reconoce la expresin regular r
= (a | b)* abb, convertirlo en un AFD.

Cerradura-E (0) = {0, 1, 7, 4, 2} = A
Mueve (A, a) = {3, 8}
Mueve (A, b) = {5}

Cerradura-E (Mueve(A,a)) = {3, 6, 7, 1, 2, 4, 8} = B (A con a mueve a B)
Cerradura-E (Mueve(A,b)) = {5, 6, 7, 1, 2, 4} = C (A con b mueve a C)
Mueve (B, a) = {3, 8} = Mueve (A, a) (B con a mueve a B)
Mueve (B, b) = {5, 9}
Mueve (C, a) = {3, 8} = Mueve (A, a) (C con a mueve a B)
Mueve (C, b) = {5} = Mueve (A, b) (C con b mueve a C)
2 3
4 5
1
6




0
7 8 9 10

a b b
a
b


30

Cerradura-E (Mueve(B, b)) = {5, 6, 7, 1, 2, 4, 9} = D (B con b mueve a D)
Mueve (D, a) = {3, 8} = Mueve (A, a) (D con a mueve a B)
Mueve (D, b) = {5, 10}

Cerradura-E (Mueve(D, b)) = {5, 6, 7, 1, 2, 4, 10} = E (D con b mueve a E)
Mueve (E, a) = {3, 8} = Mueve (B, a) (E con a mueve a B)
Mueve (E, b) = {5} = Mueve (C, b) (E con b mueve a C)

Tabla de transiciones:

Estado a b
A B C
B B D
C B C
D B E
E B C

Vamos a ver el autmata:

3.7 Traductores finitos (TF).
Ser un autmata finito de la forma:

TF = (Q, Te, Ts, o, q
0
, F)

Q es el conjunto de estados.
Te es el alfabeto de entrada.
Ts es el alfabeto de salida.
q
0
es el estado inicial.
F son los estados finales (un subconjunto de Q).

o: Q x {Te U {}} P(Q) x Ts*

A
C
a
b
b
a
b
B D
b
a
a
a
b
E
31
La configuracin del TF viene definida por una tupla (q, t, s), donde q es el
estado actual, t es la tira de caracteres por analizar (t e Te*) y s es la tira que
ha salido (s e Ts*).

Un movimiento es una transicin de la forma:

(q, ae, s) |---- (q, e, sz) cuando o(q, a) = (q, z)
q, q e Q
e e Te*
s e Ts*

Podemos definir el conjunto de traduccin como:

Tr(TF) = {(t, s), t e Te*, s e Ts* / (q
0
, t, ) |--*-- (q
f
, , s), q
f
e F}

Al igual que en el caso de los AF, pueden ser deterministas y no deterministas,
dependiendo de si exste una nica transicin posible o varias ante la misma
entrada y el mismo estado actual.


3.8 Implementacin de autmatas.

3.8.1 Tabla compacta.
Sea el siguiente lenguaje L = {dda$, ab
n
ca$ / n > 0} y su autmata:

La tabla de transiciones (M) correspondiente es la siguiente:

a b c d $
1 2 5
2 2 3
3 4
4 6
5 3
6

Se precisa mucha cantidad de memoria para almacenar esta matriz al
completo, entonces se utiliza la tcnica de la tabla compacta, que consiste en
definir los siguientes vectores:

1
5
$ c
a
d
2 3 4
d
a
6
b
32
iv) Valor.- En l se almacenan los elementos no nulos de la tabla.
v) Columna.- La columna en que se encuentra el elemento del vector
valor.
vi) PreFil.- Este vector tiene tantos elementos como filas tenga la tabla y
almacenaremos los nmeros de orden en el vector valor que comienzan
cada fila no nulos.
vii) NumFil.- Almacenamos el nmero de elementos no nulos que hay en
cada fila.

En nuestro ejemplo sera:

Valor Columna PreFil NumFil
2 1 1 2
5 4 3 2
2 2 5 1
3 3 6 1
4 1 7 1
6 5 0 0
3 4


El espacio ocupado viene dado por: (n de filas x 2) + (n no nulos x 2). En
nuestro caso sera (6 x 2) + (7 x 2) = 26.

En el caso de este ejemplo no parece un ahorro de espacio muy sustancial,
pero supongamos una tabla de tamao 100 x 100. Si suponemos 110 valores no
nulos tenemos que el espacio ocupado sera 10.000 sin comprimir y 420
implementando una tabla compacta.

Vamos a ver a continuacin como se realiza el direccionamiento mediante un
algoritmo.

Algoritmo

Function M (i, j: integer) : integer
VAR
num, com, k: integer;
hallado : boolean;
BEGIN
num := NUMFIL[i];
IF num = 0 THEN M := 9999;
ELSE BEGIN
com := PREFIL[i];
hallado := FALSE;
k := 0;
WHILE (k < num) AND NOT hallado DO
IF col[com+k] = j THEN hallado := TRUE
ELSE k := k + 1;
IF hallado THEN M := VALOR[com + k]
33
ELSE M := 9999;
END;
END;

En nuestro ejemplo, si queremos localizar M[2, 3] haremos:

PreFil [2] = 3, NumFil[2] = 2 Entonces puede ser Valor[3] o Valor[4]
Como columna es 3 entonces M[2, 3] = 3.

3.8.2 Autmata programado.
Otra opcin es hacer un programa para realizar las transiciones, de la
siguiente forma:

estado = 1
WHILE estado = 6 DO BEGIN
LeerCarcter
CASE estado OF
1 : IF Car="a" THEN estado = 2
ELSE IF Car="d" THEN estado = 5
...
2 : IF Car="e" THEN estado = 7
...
...

3.9 Ejemplo. Scanner para nmeros reales sin signo en Pascal.
Vamos a reconocer nmeros del tipo: 23E+12, 100E-15, ...

Reglas BNF:

<nmero> <entero> | <real>

<entero> <dgito> {<dgito>} con la { } indicamos 0 ms veces

<real> <entero> . <dgito> {<dgito>}
| <entero> . <dgito> {<dgito>} E <escala>
| <entero>
| <entero> E <escala>

<escala> <entero>
| <signo> <entero>

<signo> + | -

<dgito 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
Esta gramtica podemos ponerla en forma de gramtica regular, que sera la
siguiente:
34

<nmero> 0 <resto_nmero>
<nmero> 1 <resto_nmero>
...
<nmero> 9 <resto_nmero>

Este tipo de reglas las resumiremos como:

<nmero> dgito <resto_nmero> (10 reglas)

<resto_nmero> dgito <resto_nmero> (10 reglas)
| . <fraccin>
| E <exponente>
|

<fraccin> dgito <resto_fraccin> (10 reglas)

<resto_fraccin> dgito <resto_fraccin> (10 reglas)
| E <exponente>
|

<exponente> signo <entero_exponente> (2 reglas, + y -)

<entero_exponente> dgito <resto_entero_exponente> (10 reglas)

<resto_entero_exponente> dgito <resto_entero_exponente> (10 reglas)
|

Ahora implementaremos el autmata. Empezamos por definir los estados:

1 nmero 2 resto_nmero 3 fraccin 4 resto_fraccin
5 exponente 6 entero_exponente 7 resto_entero_exponente

El autmata sera:

1
5
$ .
d
d
2 3 4
d
d
8
d
7
6 d
E E
d
$
s
$
35
La transicin que marcamos punteada (de 5 a 7 con dgito), nos permite
aceptar nmeros sin signo en el exponente (por ejemplo.- 2E32), tal y como
estaba originalmente tenamos que poner siempre un + o un -.
La tabla asociada es la siguiente:

ESTADO Dgito . E Signo $
1 2
2 2 3 5 8
3 4
4 4 5 8
5 7 6
6 7
7 7 8

Ejemplo.- Gramtica de las expresiones regulares

<expresin> <literal> | <alternativa> |
<secuencia> | <repeticin> | '(' <expresin> ')'
<alternativa> <expresin> '|' <expresin>
<secuencia> <expresin> <expresin>
<repetition> <expresin> ' * '
<literal> 'a' | 'b' | 'c' | ... ( 'a' | 'b' | 'c' | ... )*

Ejemplo.- Especificaciones de tiempo en UNIX

timespec = time | time date | time increment
| time date increment | time decrement
| time date decrement | nowspec

nowspec = NOW | NOW increment | NOW decrement

time = hr24clock | NOON | MIDNIGHT | TEATIME

date = month_name day_number
| month_name day_number ',' year_number
| day_of_week | TODAY | TOMORROW
| year_number '-' month_number '-' day_number

increment = '+' inc_number inc_period

decrement = '-' inc_number inc_period

hr24clock = INT 'h' INT

inc_period = MINUTE | HOUR | DAY | WEEK | MONTH | YEAR

day_of_week = SUN | MON | TUE | WED | THU | FRI | SAT

month_name = JAN | FEB | MAR | APR | MAY | JUN | JUL
| AUG | SEP | OCT | NOV | DEC

36
3.10 Acciones semnticas.
Estas acciones se pueden inclur en la tabla de transiciones. Por ejemplo, en
el caso de las casillas en blanco, que son errores, se puede informar acerca
del error en concreto.

En el ejemplo del apartado anterior, en la casilla [3, "."] podramos mostrar el
error de "Doble punto decimal" y realizar incluso una correccin automtica.

Otra accin semntica interesante en el caso anterior sera ir almacenando en
la Tabla de Smbolos el valor del nmero que se est introduciendo. Por
ejemplo, una tabla para acciones semnticas de este tipo podra ser:

ESTADO Dgito $
1 T
2 T Z
3 U
4 U Z
5 V
6 V
7 V Z

T: num = 10 * num + dgito (calculamos nmero)
U: n = n + 1 (calculamos fraccin)
num = 10 * num + dgito
V exp = 10 * exp + dgito (calculamos exponente)

El clculo final ser realizara en Z, que sera:

Z: Valor = num * 10
signo exp - n

37

3.11 Generador LEX.
Lex es una de las herramientas que pueden ser utilizadas para generar un
analizador lxico a partir de una descripcin basada en expresiones regulares.

Si tenemos un programa lex en un fuente con nombre ejemplo.l, los pasos
para convertirlo en un ejecutable son los siguiente:

l ex ej empl o. l
cc o mi ej empl o l ex. yy. c l l
/ *A veces puede ser necesar i o t ambi n l m*/
mi ej empl o < f i cher o_pr ueba. t xt

Si se utiliza Flex y Gcc (GNU) :

f l ex ej empl o. l
gcc o mi ej empl o l ex. yy. c l f l

La secuencia es la siguiente:

1. Lex crea un fichero fuente en C, lex.yy.c, desde una descripcin del
analizador escrita en lenguaje Lex.
2. Lex.yy.c se compila (es un programa C) generndose el ejecutable.
3. Este ejecutable analizar una entrada lexicamente para producir una
secuencia de tokens.

3.11.1 Partes de un programa LEX
La estructura de un programa en LEX es la siguiente:

Declaraciones

%%

Reglas de traduccin

%%

Procedimientos Auxiliares
main() /* Si se desea ejecutar algo ms despus del analizador*/
{
yylex();
}

- En la parte de Declaraciones se incluyen identificadores, expresiones
regulares, constantes, los includes, etc
38
- Las reglas de traduccin son de la forma (siendo Pi una expresin
regular):
P1 {Accin 1}
P2 {Accin 2}
... ...
Pn {Accin n}
Es importante hacer notar que el orden de las relgas es fundamental. Las
expresiones regulares ms especficas se deben de poner antes que las ms
generales (ejemplo: ., que es cualquier cosa, si se utiliza, debera de
ponerse al final ya que en otro caso siempre tomara esta expresin regular
como vlida).

Los procedimientos auxiliares son todos aquellos procedimientos en C que se
van a utilizar en las reglas.

3.11.2 Expresiones regulares.
Algunos ejemplos de definicin de expresiones regulares son los siguientes:

Si queremos reconocer nmeros del tipo: 100, 111.02, 1, 111.2, etc, la
expresin regular sera la siguiente:

([0-9]*\.)?[0-9]+

Vamos a revisarla por partes:

[0-9]+
Dgitos de 0 a 9 (los [] indican eleccin de uno de entre el rango), al aadir el
+ indicamos la repeticin 1 o ms veces de lo que lo precede.

([0-9]*\.)
El * significa repeticin al igual que el +, aunque en este caso es de 0 o ms
veces, es decir lo que precede al * puede no aparecer. El . simplemente
indicara cualquier carcter excepto salto de lnea, en este caso queremos
identificar al punto decimal, por ello aadimos el carcter de escape \.

En la siguiente tabla se muestra un resumen de la sintaxis para la definicin
de expresiones regulares:

Symbol | Meani ng
- - - - - - - - - - - - - +- - - - - - - - - - - - - - - - - - -
x | The " x" char act er
. | Any char act er except \ n
[ xyz] | Ei t her x, ei t her y, ei t her z
[ ^bz] | Any char act er , EXCEPT b and z
[ a- z] | Any char act er bet ween a and z
[ ^a- z] | Any char act er EXCEPT t hose bet ween a and z
R* | Zer o R or mor e; R can be any r egul ar expr essi on
R+ | One R or mor e
R? | One or zer o R ( t hat i s an opt i onnal R)
R{2, 5} | Two t o 5 R
39
R{2, } | Two R or mor e
R{2} | Exact l y t wo R
" [ xyz\ " f oo" | The st r i ng " [ xyz" f oo"
{NOTI ON} | Expansi on of NOTI ON, t hat as been def i ned above i n t he f i l e
\ X | I f X i s a " a" , " b" , " f " , " n" , " r " , " t " , or
| " v" , t hi s r epr esent t he ANSI - C i nt er pr et at i on of \ X
\ 0 | ASCI I 0 char act er
\ 123 | ASCI I char act er whi ch ASCI I code i s 123 I N OCTAL
\ x2A | ASCI I char act er whi ch ASCI I code i s 2A i n hexadeci mal
RS | R f ol l owed by S
R| S | R or S
R/ S | R, onl y i f f ol l owed by S
^R | R, onl y at t he begi nni ng of a l i ne
R$ | R, onl y at t he end of a l i ne
<<EOF>> | End of f i l e

3.11.3 Paso de valores en Lex.
Si queremos devolver el valor de un token podemos utilizar return. Por
ejemplo, si hemos definido el valor de NUMBER a 257 (#define NUMBER 257),
podemos incorporar en nuestro scanner lo siguiente:

[ 0- 9] + {r et ur n NUMBER; }
Existen dos variables para el paso de valores a funciones C o bien a un parser
diseado mediante la herramienta YACC. La variable externa yytext contiene
el string de caracteres que son aceptados por la expresin regular. Tambin
tenemos la variable externa yylval, definida como un INTEGER (aunque puede
ser redefinida), pensada inicialmente para el paso del token desde el
analizador lxico al parser. Para asignar el valor de yytext a yylval es
necesario realizar una conversin.

Se puede utilizar la funcin C atoi para convertir el nmero almacenado en
yytext en forma de cadena de caracteres en su valor numrico en yylval:

[ 0- 9] + { yyl val = at oi ( yyt ext ) ;
r et ur n NUMBER;
}
3.11.4 Ejemplos.

Ejemplo1. Identificador de nmeros y palabras

di gi t [ 0- 9]
l et t er [ A- Za- z]
del i m [ \ t \ n]
ws {del i m}+

%%
{ws} { / * i gnor e whi t e space */ }
{di gi t }+ { pr i nt f ( " %s" , yyt ext ) ; pr i nt f ( " = number \ n" ) ; }
{l et t er }+ { pr i nt f ( " %s" , yyt ext ) ; pr i nt f ( " = wor d\ n" ; ) }
%%
mai n( )
{
40
yyl ex( ) ;
}


Ejemplo 2. Un contador de palabras similar al wc de UNIX

%{
unsi gned char Count = 0, wor dCount = 0, l i neCount = 0;
%}

wor d [ ^ \ t \ n] +
eol \ n

%%
{wor d} {wor dCount ++; char Count += yyl eng; }
{eol } {char Count ++; l i neCount ++; }
. {char Count ++; }
%%
mai n( )
{
yyl ex( ) ;
pr i nt f ( " %d %d %d\ n" , l i neCount , wor dCount , char Count ) ;
}

Ejemplo 3. Reconocedor de comentarios en lenguaje C.

%%
( . | \ n) ? {pr i nt f ( " " ) ; }
" / *" " / " *( [ ^*/ ] | [ ^*] " / " | " *" [ ^/ ] ) *" *" *" */ " {pr i nt f ( " [ comment ] %s" , yyt ext ) ; }
%%

NOTA: Pr obar con el si gui ent e ej empl o:

/ * coment ar i os en una l i nea */
/ * coment ar i os sobr e mul t i pl es
l i neas */
coment ar i os / *i ncl ui dos dent r o de una */ l i nea
coment ar i os / **/ r ar os
/ */ Acept a coment ar i os que no l o son?
/ **_/ */ Es cor r ect o, l o acept a?


Ejemplo 4. Calculadora

%{
/ *
** l ex pr ogr amf or si mpl e dc
** i nput of t he f or m: opd opr opd
** out put of t he f or m: opd opr opd = ans
*/
#def i ne NUM 1
#def i ne PLUS 2
#def i ne MI NUS 3
#def i ne MUL 4
#def i ne DI V 5
#def i ne MOD 6
#def i ne DELI M 7
%}

ws [ \ t ] +

%%
{ws} ;
- ?[ 0- 9] + {
41
pr i nt f ( " %s" , yyt ext ) ;
r et ur n ( NUM) ;
}

" +" {
ECHO;
r et ur n ( PLUS) ;
}
" - " {
ECHO;
r et ur n ( MI NUS) ;
}
" *" {
ECHO;
r et ur n ( MUL) ;
}
" / " {
ECHO;
r et ur n ( DI V) ;
}
" %" {
ECHO;
r et ur n ( MOD) ;
}
. |
" \ n" {
ECHO;
r et ur n ( DELI M) ;
}



%%
/ * mai n. c */
# i ncl ude <st di o. h>

mai n( )
{
i nt opd1, opd2, opr ;

/ * Look f or f i r st oper and. */
i f ( yyl ex( ) ! = NUM)
{
pr i nt f ( " mi ssi ng oper and\ n" ) ;
exi t ( 1) ;
}
opd1 = at oi ( yyt ext ) ;

/ * Check f or oper at or . */
opr = yyl ex( ) ;
/ * Bad cases - no oper and - ei t her a del i mi t er f or a number . */
i f ( opr == DELI M)
{
pr i nt f ( " mi ssi ng oper at or \ n" ) ;
exi t ( 1) ;
}
el se i f ( opr == NUM)
{
i f ( ( opd2=at oi ( yyt ext ) ) >= 0)
{
pr i nt f ( " mi ssi ng oper at or \ n" ) ;
exi t ( 1) ;
}
/ * Pr obl emcase - di st i ngui sh oper at or f r omoper and. */
el se
{
opr = MI NUS;
opd2 = - opd2;
42
}
}
/ * Check f or second oper and, i f not yet f ound. */
el se i f ( yyl ex( ) ! = NUM)
{
pr i nt f ( " mi ssi ng oper and\ n" ) ;
exi t ( 1) ;
}
el se / * Must have f ound oper and 2 */
opd2 = at oi ( yyt ext ) ;

swi t ch ( opr )
{
case PLUS: {
pr i nt f ( " = %d\ n" , opd1 + opd2) ;
br eak;
}
case MI NUS: {
pr i nt f ( " = %d\ n" , opd1 - opd2) ;
br eak;
}
case MUL: {
pr i nt f ( " = %d\ n" , opd1 * opd2) ;
br eak;
}
case DI V: {
i f ( opd2 == 0)
{
pr i nt f ( " \ nERROR: at t empt t o di vi de by zer o! \ n" ) ;
exi t ( 1) ;
}
el se
{
pr i nt f ( " = %d\ n" , opd1 / opd2) ;
br eak;
}
}
case MOD: {
i f ( opd2 == 0)
{
pr i nt f ( " \ nERROR: at t empt t o di vi de by zer o! \ n" ) ;
exi t ( 1) ;
}
el se
{
pr i nt f ( " = %d\ n" , opd1 %opd2) ;
br eak;
}
}
}
}
43

4 Anlisis sintctico (Parsing).
Analizar sintcticamente una tira de tokens es encontrar para ella el rbol de
derivacin (rbol sintctico) que tenga como raz el axioma de la gramtica.

Si lo encontramos diremos que la cadena pertenece al lenguaje, pasando a la
siguiente fase, si no lo encontramos quiere decir que no est bien construda y
entrarn en funcionamiento los mensajes de error.

Tenemos dos posibilidades a la hora de realizar el parsing:

a) Parsing a la izquierda, si para obtener el rbol de derivacin empleamos
derivaciones por la izquierda.
b) Parsing a la derecha, si las derivaciones las realizamos por la derecha.

Ejemplo.-

Sea la gramtica:

1. S S + T
2. S T
3. T T * F
4. T F
5. F (S)
6. F a
7. F b

Vamos a realizar el parsing descendente de la cadena "a*(a+b)" por la
izquierda y por la derecha:

Parsing descendente por la izquierda

Parse: 2
Parse: 2 3
Parse: 2 3 4
T
F T
*
S
T
T
*
F
S
a
F
T
S
44




Parsing descendente por la derecha

T
F T
*
F
S
a
T
F T
*
F
S
a
) (
S
Parse: 2 3 4 6
Parse: 2 3 4 6 5
...
T
F T
*
F
S
a
) (
S
T S
+
Parse: 2 3 4 6 5 1
T
F T
*
F
S
a
) (
S
T S
+
F
a
T
F
b
Parse: 2 3 4 6 5 1 2 4 6 4 7
45

As sucesivamente hasta llegar al rbol final (con un parse distinto):


Adems, tambin tenemos dos posibilidades en cuando a si comenzamos
desde la metanocin o desde la cadena que queremos reconocer. Esto sera:

a) Parsing descendente, si comenzamos por la metanocin.

a) Parsing ascendente, si comenzamos por la palabra a reconocer.

Parse: 2
Parse: 2 3
Parse: 2 3 5
T
F T
*
S
T
S
T
T
*
S
F
) (
S
T
F T
*
F
S
a
) (
S
T S
+
F
a
T
F
b
Parse: 2 3 5 1 4 7 2 4 6 4 6
46
En general podemos realizar la siguiente clasificacin:

















4.1 Mquinas tericas, mecanismos con retroceso.
En este tipo de algoritmos siempre tendremos el problema de buscar la
trayectoria correcta en el rbol, si seguimos una trayectoria equivocada, es
preciso volver hacia atrs, eso es precisamente el retroceso. Veremos una
serie de mquinas tericas que funcionan mediante este mecanismo.
4.1.1 Autmatas con pila (AP).
Este tipo de autmatas pueden reconocer lenguajes de contexto libre.

Esta mquina terica podemos definirla como:

G = (N, T, P, S)

P: A o ; A e N ; o e (N U T)*

AP = (Q, Te, Tp, o, q
0
, z
0
, F)

Q es el conjunto de estados
Te es el alfabeto de entrada
Tp es el alfabeto de la pila
q
0
es el estado inicial
z
0
es el carcter inicial de la pila
F es el conjunto de estados finales
o funcin Q x {Te U {}} x {Tp U {}} Q x Tp*

Para un estado, una configuracin de la pila y una entrada las imgenes son
varias en el caso de un APND y una sla imagen en un APD.

PARSING
ascendente descendente
EDT, AP
(tericas)
precedencia
operador
TP
(terica)
Herramienta
YACC
LR(K)
LR cannico SLR LALR
simple
LL(K)
47
Llamamos configuracin al estado actual del autmata y podemos definirlo
como:

(q, e, o) e Q x Te* x Tp*

q es el estado en que est el autmata (q e Q)
e es la cadena de caracteres que queda por analizar (e e Te*)
o es la cadena de caracteres que hay en la pila (o e Tp*)

Un movimiento podemos representarlo de la siguiente forma:

(q, ae, zo) |---- (q, e, |o) siendo (q, |) e o(q, a, z)

Si o(q, a, z) = {(p
1
, v
1
), (p
2
, v
2
), ... (p
n
, v
n
)} ser no determinista.
Si o(q, , z) = {(p
1
, v
1
), (p
2
, v
2
), ... (p
n
, v
n
)} ser no determinista de
transiciones .

Configuracin inicial: (q
0
, t, z
0
), t es la tira que queremos reconocer.

Existen tres posibilidades para el reconocimiento de un AP:

1. Una forma de definir un autmata con pila de forma que aceptar una
tira de entrada t si partiendo de una configuracin inicial consigue transitar a
un estado final final empleando movimientos vlidos.

(q
0
, t, z
0
) |--*-- (q
f
, , o) con q
f
e F, o e Tp*

Con esta definicin, la configuracin final ser: (q
f
, , o), q
f
e F

Lenguaje de un autmata con pila definido de esta forma:

L(AP) = { t, t e Te*/ (q
0
, t, z
0
) |--*-- (q
f
, , o)}

Aqu realizamos el reconocimiento por estado final (q
f
e F) pero o no tiene
por qu ser .

2. Hay otra forma de definirlo, de forma que aceptar una tira de entrada
t si partiendo de una configuracin inicial consigue dejar la pila vaca
empleando movimientos vlidos:

L(AP) = { t, t e Te* / (q
0
, t, z
0
)|--*-- (q, , )}

Con esta definicin, la configuracin final ser: (q' , , ), q' e Q

En este segundo caso reconocemos por pila vaca, q no tiene por qu ser un
estado final (en ese caso no definimos estados finales ya que no existen).

3. Tambin se puede definir el reconocimiento del autmata por ambas
condiciones, estado final y pila vaca. Se puede demostrar que todo lenguaje
48
aceptado por una de las dos cosas puede serlo por ambas. Los ejemplos los
veremos con este tipo de reconocimiento.

Con esta definicin, la configuracin final ser: (q
f
, , ), q
f
e F

Ejemplo.- un palndromo.

L = { t c t
r
/ t=(a | b)
+
}
T = {a, b, c}

Por ejemplo, si t = ab, entonces t
r
= ba.

Elementos vlidos del lenguaje seran: abcba, abbcbba, ababcbaba, etc

1 o(q
0
, a, z
0
) = (q
1
, az
0
)
2 o(q
0
, b, z
0
) = (q
1
, bz
0
)
3 o(q
1
, a, ) = (q
1
, a) NOTA : el significa sin mirar la pila
4 o(q
1
, b, ) = (q
1
, b)
5 o(q
1
, c, ) = (q
2
, )
6 o(q
2
, a, a) = (q
2
, ) NOTA : aqu tomamos la a de la pila
7 o(q
2
, b, b) = (q
2
, )
8 o(q
1
, $, z
0
) = (q
f
, )

Con ocho transiciones podemos reconocer el lenguaje. Lo que hacemos es
utilizar la pila para comprobar sin coinciden los caracteres de uno y otro lado.
Se trata de un autmata con pila determinista. El diagrama de estados es el
siguiente:

Ejemplo.-

L = {t t
r
/ t = (a | b)+}
T={a,b}

1 o(q
0
, a, z
0
) = (q
1
, az
0
) Tambin podramos decir:
2 o(q
0
, b, z
0
) = (q
1
, bz
0
)
3 o(q
1
, a, a) = {(q
1
, aa), (q
2
, )} o(q
1
, a, a) = (q
2
, )
4 o(q
1
, a, b) = (q
1
, ab) o(q
1
, a, ) = (q
1
, a)
5 o(q
1
, b, b) = {(q
1
, bb), (q
2
, )} o(q
1
, b, b) = (q
2
, )
6 o(q
1
, b, a) = (q
1
, ba) o(q
1
, b, ) = (q
1
, b)
7 o(q
2
, a, a) = (q
2
, )
0 1 2 f
(a,a,) (a,,a)
(b,,b)
(b,b,)
(a,z
0
,az
0
)
(b,z
0
,bz
0
)
(c,,)
($,z
0
,)
49
8 o(q
2
, b, b) = (q
2
, )
9 o(q
2
, $, z
0
) = (q
f
, )

Se trata de un autmata con pila no determinista.

Vamos a intentar reconocer la cadena abba$:

(0, abba$, z
0
) (1, bba$, az
0
) (1, ba$, baz
0
) (a) y (b)
(a) (1, a$, bbaz
0
) (1, $, abbaz
0
) No aceptamos.
(b) (2, a$, az
0
) (2, $, z
0
) (f, , ) Aceptamos.

4.1.1.1 Conversin de una GCL en un Autmata con pila.
El lenguaje expresado en forma de Gramtica de Contexto Libre puede
tambin expresarse en forma de un Autmata con pila. Veremos mediante un
ejemplo, como, dada una gramtica de contexto libre podemos construr un
autmata con pila que reconoce el mismo lenguaje. El tipo de anlisis que se
realiza es un anlisis sintctico descendente.

Es importante hacer notar que aqu daremos por reconocida la cadena
siempre que la cadena de entrada se ha terminado y la pila est vaca.

Sea la gramtica:

S S+T | T
T T*F | F
F (S) | a | b

Crearemos un autmata con pila de la siguiente forma:

AP = ({q}, {a, *, +, (, )}, Te U {S, T, F}, o, q, S, q}

Como se puede observar, solamente tenemos un estado que es inicial y final.

o(q, , S) = {(q, S+T), (q, T)} o(q, (, () = (q, )
o(q, , T) = {(q, T*F), (q, F)} o(q, ), )) = (q, )
o(q, , F) = {(q, (S)), (q, a), (q, b)} o(q, +, +) = (q, )
o(q, a, a) = (q, ) o(q, *, *) = (q, )
o(q, b, b) = (q, )

A continuacin vamos a ver el camino feliz para reconocer a+a*b:
0 1 2 f
(a,a,)
(a,b,ab)
(b,b,bb) (b,b,)
(a,z
0
,az
0
)
(b,z
0
,bz
0
)
(a,a,)
($,z
0
,)
(b,b,)
(b,a,ba)
(a,a,aa)
50

(q, a+a*b, S) (q, a+a*b, S+T) (q, a+a*b, T+T) (q, a+a*b, F+T)
(q, a+a*b, a+T) (q, +a*b, +T) (q, a*b, T) (q, a*b, T*F)
(q, a*b, F*F) (q, a*b, a*F) (q, *b, *F), (q, b, F) (q, b, b) (q, , )

Esta es una mquina terica, con este tipo de mquinas nunca podremos
resolver problemas como la ambigedad; en el tema siguiente hablaremos de
implementaciones de AP pero con restricciones para solucionar estos
problemas.

4.1.2 Esquemas de traduccin (EDT).
Con este tipo de mquinas podemos definir un anlisis sintctico descendente.
Un esquema de traduccin es una mquina terica que podemos definir de la
siguiente forma:

EDT = (N, Te, Ts, R, S)

N son los no terminales.
Te es el alfabeto de entrada.
Ts es el alfabeto de salida.
S es el axioma.
R son las reglas de la produccin de la forma:

A o, | con: o e (N U Te)*, |e (N U Ts)* y adems N (Ts U Te) = C

Lo que hace esta mquina es traducir una tira de caracteres a otro lenguaje,
el esquema podra ser el siguiente:


La gramtica de salida Gs = (N, Ts, P, S), donde P = { A | / A o,| e R},
es decir, nos quedamos con la parte derecha de las reglas R.

NOTA: Es importante hacer notar que aqu la salida es "modificable", es decir,
es una memoria. Es una tipo de autmata con pila en el cual tomamos la
salida de los valores que quedan en esa memoria.

Una forma de traduccin es un par (t, s), donde t es una combinacin de
caracteres entrada y s la salida proporcionada por el EDT, dichos caracteres
son una combinacin de terminales y no terminales. A la forma (S, S) la
llamamos forma inicial de traduccin.

Sea un par (t, s), una derivacin sera:

(vA, Ao) (voa, |o) si existe una regla A o,|

EDT
Ge Le Ls Gs
51
Representamos con * 0 o ms derivaciones y con
+
1 o ms derivaciones.

Podemos definir un conjunto de traduccin como:

Tr (EDT) = {(t, s) / (S, S)
+
(t, s), t e Te*, s e Ts*}

Llamamos traduccin regular a aquella cuyas reglas del esquema de
traduccin son regulares (es una gramtica regular).

Ejemplo1.- Notacin polaca inversa.

Ge = ({S}, {a, b, *, /, (, )}, P, S}

Reglas de P:
S (S)
S a | b
S S*S | S/S

Vamos a crear las reglas del EDT:

Reglas de P: Reglas de R:
S (S) S (S), S
S a S a, a
S b S b, b
S S*S S S*S, SS*
S S/S S S/S, SS/

Ya tenemos un EDT = (N, Te, Ts, R, S) en el que:
N = {S}
Te = {a, b, *, /, (, )}
Ts = {a, b, *, /}

Vamos a introducir en el EDT la tira "a/(a*b)" y ver su recorrido:

(S, S) (S/S, SS/) (a/S, aS/) (a/(S), aS/) (a/(S*S), aSS*/)
(a/(a*S), aaS*/) (a/(a*b), aab*/)

Ejemplo2.-

T = { a, b, c, (, ), *, + }
EDT = ( N, T, <1, 2, ..., n>, R, S>

S S + T,1ST
S T, 2T
T T * F, 3TF
T F, 4F
F (S), 5S
F a, 6
F b, 7
52

Vamos a intentar reconocer la palabra "a*(a+b)":

(S, S) (T, 2T) (T*F, 23TF) (F*F, 234FF) (a*F, 2346F)
(a*(S), 23465S) ... (a*(a+b), 23465124647)

La cadena que obtenemos nos informa del camino tomado por el parsing, es lo
que denominamos parse.

4.1.3 Traductores con pila (TP).
Un traductor con pila realiza un anlisis sintctico ascendente y tiene la
posibilidad de generar una salida, que ser el parse. Tambin se trata de una
mquina terica y podemos definirlo como:

TP = (Q, Te, Tp, Ts, o, q
0
, z
0
, F)

Q es el conjunto de estados.
Te es el alfabeto de entrada.
Tp es el alfabeto de la pila.
Ts es el alfabeto de salida.
q
0
es el estado inicial.
z
0
es el elemento inicial de la pila.
F son los estados finales (un subconjunto de Q).

o: Q x {Te U {}} x {Tp U {}} P(Q) x Tp* x Ts*

Llamamos configuracin a la siguiente tupla: (q, t, o, s), en donde q es el
estado actual, t es la tira de entrada que queda por analizar, o es el
contenido de la pila y s la cadena que est saliendo.

Un movimiento es una transicin de la forma:

(q, ax, zv, y) |---- (q, x, ov, yz) con q, q e Q, x e Te*, v e Tp*, y e Ts*

El conjunto de traduccin podemos definirlo como:

Tr(TP) = {(t,s) / (q
0
, t, z
0
, ) |--*-- (q
f
, , o, s), q
f
e F}

si realizamos la traduccin hasta que se agote la cadena de entrada y nos
encontremos en un estado final, o bien:

Tr(TP) = {(t,s) / (q
0
, t, z
0
, ) |--*-- (q, , , s)}

si realizamos la traduccin hasta que se agote la cadena de entrada y la
memoria de la pila.

Ejemplo.-
T = { a, b, (, ), *, + }
53
TP = ( {q}, T, N U T, <1, 2, ..., 7>, o, q, z
0
, q>

S S + T o(q, , S+T) = (q, S, 1)
S T o(q, , T) = (q, S, 2)
T T * F o(q, , T*F) = (q, T, 3)
T F o(q, , F) = (q, T, 4)
F (S) o(q, , (S)) = (q, F, 5)
F a o(q, , a) = (q, F, 6)
F b o(q, , b) = (q, F, 7)

Si queremos vaciar la pila aadimos la siguiente regla:

o(q, , S) = (q, , )

Siendo t un terminal, para introducirlo en la pila:

o(q, t, ) = (q, t, )

Vamos a reconocer la cadena "a*(a+b)" (veremos el camino feliz):

ENTRADA PILA SALIDA
a*(a+b) z
0


*(a+b) z
0
a

*(a+b) z
0
F 6
*(a+b) z
0
T 64
(a+b) z
0
T* 64
a+b) z
0
T*( 64
+b) z
0
T*(a 64
+b) z
0
T*(F 646
... ... ...

z
0
S 64642741532

z
0
64642741532


4.2 Algoritmos sin retroceso.
En los algoritmos vistos anteriormente tenemos el problema de buscar la
trayectoria correcta en el rbol, si es la equivocada, es preciso volver hacia
atrs y eso es precisamente el retroceso. Nos interesarn algoritmos
predictivos que, viendo los elementos que van a venir a continuacin sabrn a
que estado transitar. Esto implica que las gramticas sern ms restrictivas,
as hablaremos de gramticas LL1, LR, precedencia simple, etc, estas
gramticas siempre sern subconjuntos de las Gramticas de Contexto Libre.

54
4.2.1 Anlisis sintctico ascendente por precedencia simple.
Es un mtodo de parsing ascendente que se basa en la relaciones <, >, ,
relaciones que no son de equivalencia.

Decimos que una relacin R es una relacin de equivalencia cuando:
i) Reflexiva. x R x x e R
ii) Simtrica. x R y y R x
iii) Transitiva. x R y, y R z x R z

Ejemplo.-

R = { (x,y) / x > y } x, y e N S = { (x,y) / x = y } x, y e N
No es de equivalencia Es de equivalencia

x\y 0 1 2 3 ... x\y 0 1 2 3 ...
0 0 0 0 0 0 1 0 0 0
1 1 0 0 0 1 0 1 0 0
2 1 1 0 0 2 0 0 1 0
3 1 1 1 0 3 0 0 0 1
... ...

NOTA: No confundir la relacin = numrica, que s es de equivalencia, con
la relacin que usaremos aqu, que no es de equivalencia.

Definicin: Relacin universal

U = A x A = { (x, y) / x e A, y e A }

Definicin: Relacin traspuesta (R o R
T
)

Dada una relacin R, R
T
= { (y, x) / x R y }

Definicin: Complementario de una relacin (R
~
)

R
~
= { (x, y) / ~(x R y) } = U - R

Dadas dos relaciones R y S sobre A:

R + S = { (x, y) / (x R y) v (x S y) } (OR)
R x S = { (x, y) / (x R y) . (x S y) } (AND)

R + S = M
ij
OR M
kp

R x S = M
ij
AND M
kp


R . S = { (x, y) / - z (x R z) . (z S y) } denominado producto relativo.

A la hora de realizar la tabla de relaciones de la gramtica se puede hacer a
mano, haciendo todas las posibles derivaciones a partir del axioma de la
55
gramtica y determinar las relaciones en funcin del lugar en que nos
encontremos en el rbol.

Por ejemplo, supongamos la gramtica:

S aAa Algunos rboles seran los siguientes:
A bB
A c
B Acd




Las relaciones que podemos obtener son las siguientes:

b B
a < b
B > a
b < c
A c
Etc...

Si estn en la misma regla la relacin es , si estn en el nivel superior por la
izquierda < y si estn en el nivel superior por la derecha o cualquiera que
cuelgue de ste >.

Finalmente, la tabla sera:

S
a a
A
c
S
a a
A
B b
d A
c
c
S
a a
A
B b
d A
c
B b
d A
c
c
56
S a A B c b d
S
a


< <

A




B
>

>

c
>

>


b
< < <

d
>

>


Para que la gramtica sea de precedencia simple solamente ha de existir un
smbolo por casilla. Existen ms razones para que una gramtica no sea de
precedencia simple pero siempre que exista la misma parte derecha en dos
reglas distintas esta gramtica no lo ser.

Llamamos pivote a un conjunto de smbolos que se pueden sustituir por las
metanociones de la regla correspondiente (son smbolos situados entre < y >
con los intermedios relacionados con ). La tira completa la rodeamos por
izquierda y derecha pcon < y >. Utilizando el concepto de pivote, vamos a
realizar a continuacin el parsing de una tira, necesitamos encontrar un
pivote, si ste no existe querr decir que no pertenece al lenguaje:

TIRA PIVOTE REDUCCIN
<a<b<c>cd>a> c A c
<a<b<Acd>a> Acd B Acd
<a<bB>a> bB A bB
<aAa> aAa S aAa
<S> XITO, ACEPTADA

4.2.1.1 Clculo de la tabla por el mtodo matricial.
Dada una gramtica de contexto libre G = (N, T, P, S):

i) x < y si y slo si A oxB| e P y B
+
yv
ii) x y si y slo si A oxy| e P
iii) x > y si y slo si A oCD| con C
+
vx y D * y

El ejemplo anterior creemos que har comprender la diferencia entre < y >.
S
B A
D C
b
a
d c
Solamente A < D y A < d
pero:

C > B, C > D, C > d

y

c > B, c > D, c > d

57
Sea una GCL G = (N, T, P, S), y sea A ox| e P, definimos cabecera como:
Cab(A) = { x / A
+
x...}

Relacin PRIMERO: Diremos que A es PRIMERO de X si y slo si - A Xo|
As podemos decir que Cab(A) = { X / (A, X) e PRIMERO
+
}

A PRIMERO
+
X si y slo si - A
+
Xo|
A ULTIMO X si y slo si - A o|X
A ULTIMO
+
X si y slo si - A
+
o|X
A DENTRO x si y slo si - A oX|
A DENTRO
+
x si y slo si - A
+
oX|

Ejemplo.-

A Aa | B
B DbC | Dc
C c
D Ba

PRIMERO+ = { (A, A), (A, B), (A, D), (B, D), (B, B), (C, c), (D, B), (D, D) }

La matriz PRIMERO+ sera la siguiente:

A B C D a b c
A 1 1 0 1 0 0 0
B 0 1 0 1 0 0 0
C 0 0 0 0 0 0 1
D 0 1 0 1 0 0 0
a 0 0 0 0 0 0 0
b 0 0 0 0 0 0 0
c 0 0 0 0 0 0 0

Si una vez calculada la matriz PRIMERO la multiplicamos por sigo misma (con
AND, es decir 1+1=1, el denominado producto relativo) tantas veces como
haga falta hasta que no aparezcan ms unos (los que vayan apareciendo los
aadiremos), llegaremos a obtener PRIMERO
+
.

Algoritmo de Warshall

Nos permite hallar A
+
a partir de A; A
+
= U
i>0
A
i
a partir de la relacin R en
forma de una matriz.

B = A
I = 1
3 REPEAT
IF B(I, J) = 1 THEN
FOR K = 1 TO N DO
IF A(J, K) = 1 THEN A(I, K) = 1
UNTIL para todos los valores de J
58
I = I + 1
IF I s N THEN GOTO 3 ELSE STOP

Clculo de las matrices (), (<) y (>)

() se calcula por la propia definicin.

(<) = () (PRIMERO
+
)

(>) = (ULTIMO
+
)
T
() (I + PRIMERO
+
) , donde I es la matriz identidad.

Ejemplo 1.- Calcular las relaciones de precedencia simple para la gramtica:

S aSB |
B b

Tenemos que eliminar la regla , de forma que la gramtica nos quedara:

S S |
S aSB | aB
B b

La regla S S | podemos no tenerla en cuenta (y por lo tanto tampoco el
smbolo S), si bien al implementarlo contemplaramos la "sentencia vaca"
como parte del lenguaje. Se indican en negrita y con un asterisco los 1s que
seran 0s si no eliminramos la regla existente en la gramtica.

Vamos a calcular las matrices () y PRIMERO:


S B a b PRIMERO S B a b ULTIMO S B a b
S 0 1 0 0 S 0 0 1 0 S 0 1 0 0
B 0 0 0 0 B 0 0 0 1 B 0 0 0 1
a 1 1* 0 0 a 0 0 0 0 a 0 0 0 0
b 0 0 0 0 b 0 0 0 0 b 0 0 0 0

Por lo tanto:

0 1 0 0 0 0 1 0
() = 0 0 0 0 PRIMERO = 0 0 0 1
1 1* 0 0 0 0 0 0
0 0 0 0 0 0 0 0

Vamos a hacer el producto relativo con PRIMERO:

0 0 1 0 0 0 1 0 0 0 0 0
0 0 0 1 0 0 0 1 = 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0

59
Entonces PRIMERO
+
= PRIMERO

Vamos a hacer el producto relativo con ULTIMO:

0 1 0 0 0 1 0 0 0 0 0 1
0 0 0 1 0 0 0 1 = 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0

Como aparece un nuevo 1, volvemos a multiplicarlo por ULTIMO:

0 1 0 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 = 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0

Ahora ya tenemos las matrices PRIMERO
+
y ULTIMO
+
:

0 0 1 0 0 1 0 1
PRIMERO
+
= 0 0 0 1 ULTIMO
+
= 0 0 0 1
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

Ya podemos calcular (<) y (>):

() (PRIMERO
+
)
0 1 0 0 0 0 1 0 0 0 0 1
(<) = 0 0 0 0 0 0 0 1 = 0 0 0 0
1 1* 0 0 0 0 0 0 0 0 1 1*
0 0 0 0 0 0 0 0 0 0 0 0


0 0 0 0 0 1 0 0 0 0 0 0
(ULTIMO
+
)
T
() = 1 0 0 0 0 0 0 0 = 0 1 0 0
(+) 0 0 0 0 1 1* 0 0 0 0 0 0
1 1 0 0 0 0 0 0 0 1 0 0


(+) (I+PRIMERO
+
)
0 0 0 0 1 0 1 0 0 0 0 0
(>) = 0 1 0 0 0 1 0 1 = 0 1 0 1
0 0 0 0 0 0 1 0 0 0 0 0
0 1 0 0 0 0 0 1 0 1 0 1

La tabla final de parsing ser:

60
S B a b
S

<
B > >
a
* < <*
b > >

Si en esta tabla eliminamos los smbolos * y <* (que sera la tabla resultante
si no eliminramos la regla ) no podramos resolver elementos del lenguaje
como podra ser "aabb"; al mirar las precedencias no seramos capaces de
encontrar un pivote y no aceptaramos una palabra que s es del lenguaje. En
cambio con la tabla tal cual aparece podemos reconocer todo el lenguaje
excepto el elemento "cadena vaca", que habra que tratarlo y reconocerlo
especficamente (algo, por otro lado, muy sencillo).

Ejercicio 2.-
S AB
B A
A a


S A B a PRIMERO S A B a ULTIMO S A B a
S 0 0 0 0 S 0 1 0 0 S 0 0 1 0
A 0 0 1 0 A 0 0 0 1 A 0 0 0 1
B 0 0 0 0 B 0 1 0 0 B 0 1 0 0
a 0 0 0 0 a 0 0 0 0 a 0 0 0 0

Por lo tanto:

0 0 0 0 0 1 0 0
() = 0 0 1 0 PRIMERO = 0 0 0 1
0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0

Vamos a hacer el producto relativo con PRIMERO:

0 1 0 0 0 1 0 0 0 0 0 1
0 0 0 1 0 0 0 1 = 0 0 0 0
0 1 0 0 0 1 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0 0 0

Como aparecen dos nuevos 1, volvemos a multiplicarlo por PRIMERO:

0 1 0 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 = 0 0 0 0
0 1 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0

Vamos a hacer el producto relativo con ULTIMO:

61
0 0 1 0 0 0 1 0 0 1 0 0
0 0 0 1 0 0 0 1 = 0 0 0 0
0 1 0 0 0 1 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0 0 0

Como aparecen nuevos 1, volvemos a multiplicarlo por ULTIMO:

0 0 1 0 0 1 0 0 0 0 0 1
0 0 0 1 0 0 0 0 = 0 0 0 0
0 1 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0

Nuevamente aparece un "1", y seguimos:

0 0 1 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 = 0 0 0 0
0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0

Ahora ya tenemos las matrices PRIMERO
+
y ULTIMO
+
:

0 1 0 1 0 1 1 1
PRIMERO
+
= 0 0 0 1 ULTIMO
+
= 0 0 0 1
0 1 0 1 0 1 0 1
0 0 0 0 0 0 0 0

Ya podemos calcular (<) y (>):

() (PRIMERO
+
)
0 0 0 0 0 1 0 1 0 0 0 0
(<) = 0 0 1 0 0 0 0 1 = 0 1 0 1
0 0 0 0 0 1 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0


0 0 0 0 0 0 0 0 0 0 0 0
(ULTIMO
+
)
T
() = 1 0 1 0 0 0 1 0 = 0 0 0 0
(*) 1 0 0 0 0 0 0 0 0 0 0 0
1 1 1 0 0 0 0 0 0 0 1 0


(*) (I+PRIMERO
+
)
0 0 0 0 1 1 0 1 0 0 0 0
(>) = 0 0 0 0 0 1 0 1 = 0 0 0 0
0 0 0 0 0 1 1 1 0 0 0 0
0 0 1 0 0 0 0 1 0 1 1 1

La tabla final de parsing ser:

62
S A B a
S
A <

<
B
a > > >

Ejercicio 3.-

S CC
C cC
C d


S C c d PRIMERO S C c d ULTIMO S C c d
S 0 0 0 0 S 0 1 0 0 S 0 1 0 0
C 0 1 0 0 C 0 0 1 1 C 0 1 0 1
c 0 1 0 0 c 0 0 0 0 c 0 0 0 0
d 0 0 0 0 d 0 0 0 0 d 0 0 0 0

Por lo tanto:

0 0 0 0 0 1 0 0
() = 0 1 0 0 PRIMERO = 0 0 1 1
0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0

Vamos a hacer el producto relativo con PRIMERO:

0 1 0 0 0 1 0 0 0 0 1 1
0 0 1 1 0 0 1 1 = 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0

Como aparecen dos nuevos 1, volvemos a multiplicarlo por PRIMERO:

0 1 0 0 0 0 1 1 0 0 0 0
0 0 1 1 0 0 0 0 = 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0

Vamos a hacer el producto relativo con ULTIMO:

0 1 0 0 0 1 0 0 0 1 0 1
0 1 0 1 0 1 0 1 = 0 1 0 1
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0

Como aparece un nuevo 1, volvemos a multiplicarlo por ULTIMO:

63
0 1 0 0 0 1 0 1 0 1 0 1
0 1 0 1 0 1 0 1 = 0 1 0 1
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0

Ahora ya tenemos las matrices PRIMERO
+
y ULTIMO
+
:

0 1 1 1 0 1 0 1
PRIMERO
+
= 0 0 1 1 ULTIMO
+
= 0 1 0 1
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

Ya podemos calcular (<) y (>):

() (PRIMERO
+
)
0 0 0 0 0 1 1 1 0 0 0 0
(<) = 0 1 0 0 0 0 1 1 = 0 0 1 1
0 1 0 0 0 0 0 0 0 0 1 1
0 0 0 0 0 0 0 0 0 0 0 0


0 0 0 0 0 0 0 0 0 0 0 0
(ULTIMO
+
)
T
() = 1 1 0 0 0 1 0 0 = 0 1 0 0
(*) 0 0 0 0 0 1 0 0 0 0 0 0
1 1 0 0 0 0 0 0 0 1 0 0


(*) (I+PRIMERO
+
)
0 0 0 0 1 1 1 1 0 0 0 0
(>) = 0 1 0 0 0 1 1 1 = 0 1 1 1
0 0 0 0 0 0 1 0 0 0 0 0
0 1 0 0 0 0 0 1 0 1 1 1

La tabla final de parsing ser:

S C c d
S
C >

>
<
>
<
c

< <
d > > >

En la fila de B aparecen varias relaciones en la misma casilla, se trata de una
gramtica no implementable por precedencia simple.

64
4.2.2 Anlisis sintctico ascendente por precedencia de operadores.
Una gramtica de contexto libre G=(N, T, P, S) diremos que es una gramtica
de operador si no posee reglas y si en la parte derecha de sus reglas no
aparecen dos no terminales adyacentes. Esto es:

1) no - A
2) no - A oBC| con A, B, C e N

Sean a y b dos smbolos, trabajaremos con las siguientes precedencias: a > b,
b < a y a b.

Algoritmo

1. Obtener la tira de entrada, se ponen las reglas de precedencia entre cada
dos elementos y se delimita mediante otro smbolo, por ejemplo $. Por
ejemplo: $<id>+<id>$. NOTA: Slo existen relaciones entre terminales.
2. Analizamos la cadena de entrada de izquierda a derecha y vamos
avanzando hasta encontrar el smbolo de precedencia mayor (>), luego
iremos hacia atrs hasta encontrar el smbolo de precedencia menor (<),
con lo que todo lo encerrado entre ambos ser el pivote y el que nos
permitir realizar la reduccin.

De esta forma, los errores que pueden producirse son:

a) Ninguna relacin de precedencia entre un smbolo y el siguiente.
b) Una vez encontrada la relacin de precedencia, es decir, tenemos pivote,
no existe ninguna regla que permita reducirlo.

Algoritmo para la obtencin de las relaciones de precedencia operador

i) Si el operador u
1
tiene mayor precedencia que el u
2
u
1
> u
2
u
2
< u
1

ii) Si el operador u
1
tiene igual precedencia que el u
2

- Si son asociativos por la izquierda u
1
> u
2
u
2
> u
1

- Si son asociativos por la derecha u
1
< u
2
u
2
< u
1

iii) Hgase:
u < ( < u > ) > u ( < ( ) > )
$ < ( ) > $
u < id > u u > $ < u
( < id > ) $ < id > $

Ejemplo1.- Sea la siguiente gramtica:

S S + S asumimos que el operador + es asociativo por la izquierda
S S * S asumimos que el operador * es asociativo por la izquierda
S id

La tabla de precedencia operador ser la siguiente:

65
id + * $
id > > >
+ < > < >
* < > > >
$ < < <

Vamos a reconocer la tira $id+id*id$

TIRA PIVOTE REDUCCIN
$<id>+<id>*<id>$ id S id
$<S+<id>*<id>$ id S id
$<S+<S*<id>$ id S id
$<S+<S*S>$ S*S S S*S
$<S+S>$ S+S S S+S
$S$ XITO, ACEPTADA

Ejemplo 2.- Sea la siguiente gramtica:

S SAS | (S) | id
A + | - | * | / | |

Esta gramtica no es de precedencia operador porque en S SAS tenemos
tres no terminales consecutivos, pero si sustitumos las alternativas de A en
esa regla la podemos convertir en una gramtica de precedencia operador de
la siguiente forma:

S S + S
S S S
S S * S
S S / S
S S | S
S (S)
S id

Asumimos que:
- El operador | tiene la mayor precedencia y es asociativo por la derecha.
- Los operadores * y / tienen la siguiente mayor precedencia y son
asociativos por la izquierda.
- Los operadores + y son los de menor precedencia y son asociativos por la
izquierda.

La tabla de precedencia operador sera la siguiente:

+ - * /
|
id ( ) $
+ > > < < < < < > >
- > > < < < < < > >
* > > > > < < < > >
/ > > > > < < < > >
66
|
> > > > < < < > >
id > > > > > > >
( < < < < < < <


) > > > > > > >
$ < < < < < < <

Funciones de precedencia

Normalmente no se almacena la tabla de precedencias de operador sino que
se definen unas funciones de precedencia. Utilizando estas funciones
ahorramos memoria pues no es preciso almacenar la tabla. El mtodo se basa
en implementar dos funciones f y g que transformarn smbolos terminales en
enteros que compararemos para mirar su prioridad. Esto es:

a, b e T
f(a) < g(b) sii a < b
f(a) > g(b) sii a b
f(a) > g(b) sii a > b

Para la tabla del ejercicio 2, las funciones f y g seran las siguientes:

+ - * /
|
id ( ) $
f 2 2 4 4 4 6 0 6 0
g 1 1 3 3 5 5 5 0 0

De esta forma, ante una cadena de entrada como la siguiente:

$id+id*id$

Las precedencias las calcularamos de la siguiente forma:

f($) = 0 y g(id) = 5 entonces $ < id
f(id) = 6 y g(+) = 1 entonces id < +
f(+) = 2 y g(id) = 5 entonces + < id
f(id) = 6 y g(*) = 3 entonces id > *
f(*) = 4 y g(id) = 5 entonces * < id
f(id) = 6 y g($) = 0 entonces id > $

Con lo cual:

$<id>+<id>*<id>$

Reduciramos <id> con la regla S id y continuaramos el proceso.

Algoritmo para la construccin de las funciones de precedencia

1. Partimos de la matriz de precedencia.
2. Creamos para un grafo los nodos f
a
y g
a
a e T incluyendo $.
3. Si tienen igual precedencia los agrupamos.
67
4. Creamos un grafo dirigido cuyos nodos sean los smbolos creados en el
paso anterior.
5. Si a < b la arista va de g
b
a f
a
.
6. Si a > b la arista va de f
a
a g
b
.
7. Si el grafo as construido tiene ciclos significa que no se pueden calcular
las funciones de precedencia. En otro caso,las funciones las construiremos
asignando a f
a
la longitud del camino ms largo que podemos recorrer por
el grafo desde el nodo donde est f
a
, al igual que con g
a
.

Para la tabla del ejemplo 1 las funciones seran las siguientes (construdas a
partir del grafo):

id + * $
f 4 2 4 0
g 5 1 3 0

4.2.3 Analizadores descendentes LL(K).
Este tipo de analizadores consta de los siguientes elementos:
g
id

f
*

g
+

f
$

f
id

g
*

f
+

g
$

68

Los analizadores sintcticos LL(k) funcionan de forma descendente, sin
retroceso y son predictivos en k smbolos. Nosotros nos quedaremos con los
LL(1). La primera L significa Left, izquierda en ingls, indicando que el
anlisis de la entrada se realiza de izquierda a derecha; la segunda L indica
tambin Left y representa una derivacin por la izquierda; K, en nuestro
caso K=1, indica que utilizamos un smbolo de entrada de examen por
anticipado a cada paso para tomar decisiones de accin en el anlisis
sintctico.

Suponiendo que tenemos la tabla, el funcionamiento ser:

Si X = a = $ xito en el anlisis (X elemento de la pila, a es entrada).
Si X = a $ El analizador quita X de la pila y va a la siguiente entrada.
Si X e N Consulta la tabla en M[X,a], en donde tendremos una
produccin, por ejemplo X WZT, sustituyendo X en la pila por WZT.

Ejemplo.- Sea la gramtica:

E TE
E +TE | c
T FT
T *FT | c
F (E) | id

Y la tabla correspondiente:

id + * ( ) $
E
E TE E TE
E
E +TE E c E c
T
T FT T FT
T
T c T *FT T c T c
F
F id F (E)

Vamos a realizar un reconocimiento de id+id*id$:

Programa de
anlisis
Mij, tabla del
analizador
Pila
Tira de entrada
Resultado
69

PILA ENTRADA Reduccin
$E id+id*id$
$ET id+id*id$ E TE
$ETF id+id*id$ T FT
$ETid id+id*id$ F id
$ET +id*id$
$E +id*id$ T c
$ET+ +id*id$ E +TE
$ET id*id$
$ETF id*id$ T FT
$ETid id*id$ F id
$ET *id$
$ETF* *id$ T *FT
$ETF id$
$ETid id$ F id
$ET $
$E $ T c
$ $ E c
$ $ XITO

Si realizramos el recorrido con la cadena id**id en algn paso nos
encontraramos con una casilla en blanco, es decir, un error.


4.2.3.1 Construccin de la tabla Mij.
Clculo del conjunto PRIMERO (X):

i) X e T entonces PRIMERO(X) = {X}
ii) X c entonces c e PRIMERO(X)
iii) X e N, X X
1
X
2
... X
n
entonces a e T, a e PRIMERO(X
j
), a e
PRIMERO(X) siempre y cuando: X
1
* c, X
2
* c, ..., X
j-1
* c. Si
ocurriera que X
1
* c, X
2
* c, ..., X
n
* c entonces c e PRIMERO(X).

Clculo del conjunto SIGUIENTE(X):

i) Si X = S (smbolo inicial o axioma) entonces $ e SIGUIENTE(X).
ii) Si tenemos una produccin de la forma A oB|, con | = c, entonces
PRIMERO(|) \ {c} e SIGUIENTE(B) (nota: \ significa menos).
iii) Si tenemos producciones de la forma: A oB bien A oB| donde
PRIMERO(|) contenga c (o lo que es lo mismo, | * c) entonces
hacemos SIGUIENTE(A) c SIGUIENTE(B).

Ejemplo.- Sea la gramtica del ejemplo anterior:

E TE
E +TE | c
70
T FT
T *FT | c
F (E) | id

Si calculamos PRIMERO y SIGUIENTE quedara:

PRIMERO SIGUIENTE
E (, id ), $
E +, c ), $
T (, id +, ), $
T *, c +, ), $
F (, id *, +, ), $

En el caso de E tenemos que $ e SIGUIENTE(E) por (i), adems tenemos la
regla F (E), caso (ii), por lo que PRIMERO()) = { ) } e SIGUIENTE(E) (no est
c, en ese caso no la aadiramos), entonces tenemos ya que SIGUIENTE(E) =
{$, )}.

En el caso de E tenemos la regla E TE, que es el caso (iii), con lo cual
SIGUIENTE(E) c SIGUIENTE(E), con lo cual SIGUIENTE(E) = {), $}.

En el caso de T tenemos la regla E TE, por la regla (ii) tenemos que
PRIMERO (E)\c = {+} e SIGUIENTE(T). Adems, en la regla E +TE tenemos
la situacin (iii), con lo cual SIGUIENTE(E) c SIGUIENTE(T), por lo que
aadimos {), $}. Finalmente tenemos que SIGUIENTE(T) = {+, ), $}.

Algoritmo de confeccin de la tabla Mij

1) A o e P aplicamos (2) y (3).
2) a e T, a e PRIMERO(o), aadir A o en M[A, a].
3) Si c e PRIMERO(o), aadir A o en M[A, b] b e SIGUIENTE(A). Como
caso ms especial, incluido en el anterior, tenemos que si c est en
PRIMERO(o) y $ est en SIGUIENTE(A), adase A o a M[A, $].
4) Cualquier entrada no definida en Mij ser un error.

Es importante sealar que una gramtica ser LL(1) si en cada casilla
tenemos, como mximo, una produccin. Si la gramtica es recursiva por la
izquierda o ambigua, entonces M tendr al menos una entrada con definicin
mltiple, y por lo tanto no se podr implementar mediante LL(1).

Ejemplo.- Para la gramtica anterior vamos a calcular Mij:

71
Id + * ( ) $
E
E TE E TE
E
E +TE E c E c
T
T FT T FT
T
T c T *FT T c T c
F
F id F (E)

Con la regla E TE
En este caso PRIMERO (TE) = PRIMERO(T) porque c no est incluido en este
ltimo. Utilizando la regla (2), {(, id} e PRIMERO(T), entonces hemos aadido
E TE en M[E, (] y M[E, id}

Con la regla E +TE
Tambin tenemos que PRIMERO(+TE) = PRIMERO(+) = {+}, entonces, tambin
con la regla (2), en M[E, +] introducimos E +TE.

Con la regla E c
Como PRIMERO(c) = c y SIGUIENTE(E) = {), $}, entonces introducimos E c
en M[E, )] y M[E, $], aplicando la regla (3).

Y as continuaramos con el resto de las reglas.

Condiciones a cumplir para que una gramtica sea LL(1):

1) Ninguna gramtica ambigua o recursiva por la izquierda puede ser LL(1).
2) Puede demostrarse que una gramtica G es de tipo LL(1) si, y slo si,
cuando A o | | sean dos producciones distintas de G se cumplan las
siguientes condiciones:
3) Para ningn terminal a tanto o como | derivan a la vez cadenas que
comiencen con a.
4) A lo sumo una de o y | pude derivar la cadena vaca.
5) Si | * c, o no deriva ninguna cadena que comience con un terminal en
SIGUIENTE(A).

Ejemplo.- Implemntese un analizador LL(1) de la gramtica:

E E + T | E T | T
T T * F | T / F | F
F id | id [ E ] | ( E )

Ejemplo.- Sea la gramtica:

S { A }
A id = E
E id

Implementar un analizador LL(1).

Ejemplo.-
72

S S ; L
S L
L if expr then S else S fi
L if expr then S fi
L instr

No es LL(1), hay que transformarlo eliminando recursividad por la izquierda y
factorizacin en:

S L S
S ; L S | c
L if expr then S X fi
L instr
X else S | c

Primero calculamos los conjuntos PRIMERO y SIGUIENTE:

PRIMERO SIGUIENTE
S if expr then, instr $, else, fi
L if expr then, instr ;, $, else, fi
S ;, c $, else, fi
X c, else fi,

La tabla resultante es la que viene a continuacin:
; if expr then fi instr else $
S S L S S L S
L L if expr then S X
fi
L instr
S S ; LS S c S c S c
X X c X else S

Reconozcamos if expr then if expr then instr fi else if expr then instr fi fi$:
PILA ENTRADA SALIDA
$S
if expr then if expr then instr fi else if
expr then instr fi fi$

$SL
if expr then if expr then instr fi else if
expr then instr fi fi$
S L S
$Sfi X S then expr if
if expr then if expr then instr fi else if
expr then instr fi fi$
L if expr
then S X fi
$S fi X S
if expr then instr fi else if expr then
instr fi fi$

$S fi XSL
if expr then instr fi else if expr then
instr fi fi$
S L S
$S fi XSfi X S then expr if
if expr then instr fi else if expr then
instr fi fi$
L if expr
then S X fi
$S fi XSfi X S
instr fi else if expr then instr fi fi$

$ S fi X Sfi X S L
instr fi else if expr then instr fi fi$
S L S
$ S fi X Sfi X S instr
instr fi else if expr then instr fi fi$ L instr
$ S fi X Sfi X S
fi else if expr then instr fi fi$

73
$ S fi X Sfi X
fi else if expr then instr fi fi$ S c
$ S fi X Sfi
fi else if expr then instr fi fi$ X c
$ S fi X S
else if expr then instr fi fi$

$ S fi X
else if expr then instr fi fi$ S c
$ S fi S else
else if expr then instr fi fi$ X else S
$ S fi S
if expr then instr fi fi$

$ S fi S L
if expr then instr fi fi$ S L S
$ S fi S fi X S then expr if
if expr then instr fi fi$ L if expr
then S X fi
$ S fi S fi X S
instr fi fi$

$ S fi S fi X SL
instr fi fi$ S L S
$ S fi S fi X S instr
instr fi fi$ L instr
$ S fi S fi X S
fi fi$

$ S fi S fi X
fi fi$ S c
$ S fi S fi
fi fi$ X c
$ S fi S
fi$

$ S fi
fi$ S c
$ S
$

$
$ S c
$
$
XITO

4.2.4 Analizadores ascendentes LR(k).
Los analizadores sintcticos LR(k) funcionan de forma ascendente, sin
retroceso y son predictivos en k smbolos. Es un mecanismo que se puede
utilizar para analizar una clase ms amplia de GCL. La primera L significa
Left, izquierda en ingls, indicando que el anlisis de la entrada se realiza
de izquierda a derecha; la segunda R significa Right e indica que se
realizan las derivaciones por la derecha; k, en nuestro caso k=1, indica que
utilizamos un smbolo de entrada de examen por anticipado a cada paso para
tomar decisiones de accin en el anlisis sintctico.

A la hora de construir la tabla LR tenemos tres tcnicas:

1) SLR.- El ms sencillo y menos potente y ms restrictivo.
2) LALR.- De potencia intermedia (YACC utiliza este analizador).
3) LR-cannico.- El mtodo ms general y por lo tanto el ms potente aunque
es ms difcil de implementar.

Este tipo de analizador consta de los siguientes elementos:
74


La tabla de "accin" nos dir lo que hacer con cada entrada y la tabla "ir_a"
nos indicar las transiciones entre estados. El funcionamiento es:

1) Tomamos S
m
de la pila y a
i
de la tira de entrada.
2) Miramos en accion[S
m
, a
i
] que nos indicar una de las siguientes acciones:
a) Desplazar S
p
(S
p
es un estado).
b) Reducir A |. Miramos ir_a[S
m-r
, A] y obtendremos un nuevo estado
al que transitar S
q
(r es la longitud de |).
c) Aceptar.
d) Error.

Llamamos configuracin a un par formado por el estado de la pila y la tira de
entrada que estamos analizando.
Supongamos una configuracin inicial: (S
0
X
1
S
1
X
2
S
2
... X
m
S
m
, a
i
a
i+1
... a
n
$).
Respecto a la notacin, los S
i
son estados y los X
i
son smbolos gramaticales
(terminales y no terminales).

Vamos a ver las diferentes posibilidades:

a) Si tenemos que la accion[S
k
, a
i
] = desplazar S
p
, entonces la configuracin
variara de la siguiente forma:

(S
0
X
1
S
1
X
2
S
2
... X
m
S
m
a
i
S
p
, a
i+1
... a
n
$)

b) Sin embargo, si ocurriera que accion[S
k
, a
i
] = reducir A |, la
configuracin quedara como:

(S
0
X
1
S
1
X
2
S
2
... X
m-r
S
m-r
AS
q
, a
i
a
i+1
... a
n
$)

En donde S
q
= ir_a[S
m-r
,A] y r es la longitud de |.

c) Si accion[S
k
, a
i
] = aceptar entonces significa el fin del anlisis sintctico.

Programa de
anlisis


accin
Pila
Tira de entrada
Resultado
S
m

X
m

S
m-1
X
m-1
...


ir_a
75

d) Si accion[S
k
, a
i
] = error significar que no es una frase correcta,
posteriormente se podra lanzar una rutina que manejara los mensajes de
error o de recuperacin de errores.

En el siguiente ejemplo veremos como funciona el reconocimiento LR cuando
ya disponemos de la tabla.

Ejemplo.-

(1) E E+T (2) E T (3) T T*F (4) T F
(5) F (E) (6) F id

Suponemos que ya hemos calculado la tabla LR(1), es decir, con un smbolo de
anticipacin, que sera:

ESTADO id + * ( ) $ E T F
0 d5 d4 1 2 3
1 d6 ACEP.
2 r2 d7 r2 r2
3 r4 r4 r4 r4
4 d5 d4 8 2 3
5 r6 r6 r6 r6
6 d5 d4 9 3
7 d5 d4 10
8 d6 d11
9 r1 d7 r1 r1
10 r3 r3 r3 r3
11 r3 r3 r5 r5
ACCIN IR_A

Vamos a reconocer "id*id+id":

PILA ENTRADA Accin
0 id*id+id$ d5
0id5 *id+id$ r6 (F id)
0F3 *id+id$ r4 (T F)
0T2 *id+id$ d7
0T2*7 id+id$ d5
0T2*7id5 +id$ r6 (F id)
0T2*7F10 +id$ r3 (T T*F)
0T2 +id$ r2 (E T)
0E1 +id$ d6
0E1+6 id$ d5
0E1+6id5 $ r6 (F id)
0E1+6F3 $ r4 (T F)
0E1+6T9 $ r1 (E E+T)
0E1 $ ACEPTAR
76

Llamamos gramtica LR a aquella gramtica de contexto libre para la cual es
posible construir la tabla.

4.2.4.1 Mtodo SLR.
Es el mtodo ms sencillo pero el menos general, siendo por lo tanto el que
tiene ms restricciones para la gramtica que LALR LR-cannico.

Llamamos elemento de anlisis LR(0) a una produccin de la gramtica G con
un punto en alguna posicin del lado derecho de la regla.

Por ejemplo.-

A XYZ los elementos LR(0) son: A .XYZ
A X.YZ
A XY.Z
A XYZ.

Un caso especial sern las producciones A c, en donde A .

La base para construir la tabla de anlisis LR(0) son una serie de elementos
LR(0) asociados a una gramtica G se denomina coleccin cannica LR(0).
Para conseguir la coleccin cannica LR(0) tenemos que definir previamente
los conceptos de : gramtica aumentada, cerradura y funcin ir_a.

Dada una gramtica G se define G como una gramtica aumentada,
equivalente a G, a la que se le aade la produccin S S, siendo S la
metanocin de la gramtica.

Dado un conjunto I de elementos LR(0) de G, cerradura(I) ser el conjunto de
elementos obtenidos de la siguiente manera:

i) Todo elemento de I e cerradura(I).
ii) A o.B| e cerradura(I), B v e P, entonces B .v e cerradura(I).
iii) Se repite (2) hasta que no se puedan aadir ms elementos.

Algoritmo para calcular cerradura(I)

Funcin cerradura(I)
BEGIN
J = I
REPEAT
FOR cada elemento A o.B| e J Y cada B v e G Y B .v e J
DO aadir B .v a J
UNTIL no se puedan aadir ms a J
END.

Ejemplo.- En la gramtica aumentada:
77

(0) E E (1) E E+T (2) E T (3) T T*F
(4) T F (5) F (E) (6) F id

Vamos a calcular cerradura(E .E):

1) E .E por la regla (i)
2) E .E+T por la regla (ii) desde (1)
3) E .T por la regla (ii) desde (1)
4) T .T*F por la regla (ii) desde (3)
5) T .F por la regla (ii) desde (3)
6) F .(E) por la regla (ii) desde (5)
7) F .id por la regla (ii) desde (5)

Se llaman elementos nucleares a aquellos elementos que no tienen el punto
en el extremo izquierdo. Un caso especial es S .S, que se pone en este
grupo.

Se llaman elementos no nucleares a aquellos que tienen el punto en el
extremo izquierdo.

Definimos la funcin Ir_a(I, X) con I un conjunto LR(0) y X e (N U T):

Ir_a (I, X) = { cerradura(A oX.|) / A o.X| e I}

NOTA: Es la transicin que nos produce X en el autmata.

Ejemplo.- En la gramtica del ejemplo anterior, si tomamos:

I = { E E., E E.+T }

Ir_a(I, +) se calcula como cerradura(E E+.T), que sera:

E E+.T
T .T*F
T .F
F .(E)
F .id

Intuitivamente puede interpretarse que, si A a.Bb est en la cerradura(I),
en este punto el parsing la secuencia Bb debera ser nuestra entrada. Adems,
si tenemos que B g es otra regla, un substring prefijo de g debera ser
tambin nuestra entrada. Ir_a nos indica que si I es un conjunto de elementos
LR(0) vlidos para un posible prefijo de g, entonces Ir_a(I, X) es un conjunto
de sucesores vlidos si X viene despus de g y gX es un prefijo posible.

Obtencin de la coleccin cannica LR(0)

78
Para construir la coleccin cannica LR(0) para una gramtica aumentada
G, utilizamos el siguiente algoritmo:

Algoritmo coleccin cannica LR(0)

Procedimiento elementos_LR(0)(G)
BEGIN
C = {cerradura({[S .S]})}
REPEAT
FOR cada I, I c C Y cada X e G donde Ir_a(I, X) = C Y
Ir_a(I, X) . C, entonces aadir Ir_a(I, X) a C
UNTIL no se puedan aadir ms conjuntos a C
END.

Ejemplo.- Para la gramtica aumentada anterior:

(0) E E (1) E E+T (2) E T (3) T T*F
(4) T F (5) F (E) (6) F id

calculamos la coleccin cannica LR(0) como:

I
0
= cerradura(E .E) = E .E T .T*F F .id
E .E+T T .F
E .T F .(E)
I
1
= Ir_a(I
0
, E) = E E. I
2
= Ir_a(I
0
, T) = E T.
E E.+T T T.*F

I
3
= Ir_a(I
0
, F) = T F.

I
4
= Ir_a(I
0
, () = cerradura(F (.E)) = E (.E)
E .E+T
E .T
T .T*F
T .F
F .(E)
F .id

I
5
= Ir_a(I
0
, id) = F id. I
6
= Ir_a(I
1
, +) = cerradura(E E+.T) = E E+.T
T .T*F
T .F
F .(E)
F .id

I
7
= Ir_a(I
2
, *) = T T*.F I
8
= Ir_a(I
4
, E) = F (E.)
F .(E) E E.+T
F .id

Ir_a(I
4
, T) = I
2
79
Ir_a(I
4
, F) = I
3

Ir_a(I
4
, () = I
4

Ir_a(I
4
, id) = I
5

I
9
= Ir_a(I
6
, T) = E E+T. I
10
= Ir_a(I
7
, F) = T T*F.
T T.*F
Ir_a(I
7
, () = I
4
Ir_a(I
7
, id) = I
5


I
11
= Ir_a(I
8
, )) = F (E).

Ir_a(I
8
, +) = I
6




Cuando tenemos el autmata LR(0), tendremos diversas posibilidades en
cuanto a las reducciones posibles, es un mtodo con retroceso (si nos
equivocamos de rama tenemos que volver hacia atrs). En realidad se trata de
un Autmata finito no determinista pues existen transiciones de la forma A
I
0

E
I
1

I
3

I
7
I
9
I
6
I
4

I
3
I
8
I
4
I
5
I
2
I
10
I
7
I
4
I
5
I
11
I
5

I
6
T
F
(
id
+ T
F
(
id
* F
)
(
id
*
E
I
3
I
2
T
F
)
+
80
o.X| a A oX.| etiquetadas con "X" y transiciones c (dentro de los propios I
i
)
entre elementos de la forma A o.B| a B . .

Decimos que el elemento A |
1
.|
2
es un elemento vlido para un prefijo
variable o|
1
si existe una derivacin S * oAw * o|
1
|
2
w. En general, un
elemento ser vlido para muchos prefijos variables. El hecho de que
tengamos un elemento A |
1
.|
2
vlido para o|
1
informa sobre si desplazar
(|
2
= c) o reducir (|
2
= c) cuando se encuentre o|
1
en la pila del analizador.

Obtencin de la tabla de anlisis SLR

Para la construccin de la tabla seguimos los siguientes pasos:

i) Construir el conjunto C = { I
0
, I
1
, ..., I
n
}
ii) Los estados se construyen a partir de los conjuntos I
i
. El estado k es I
k
,
para rellenar las casillas hacemos (siendo a un terminal):
a) Si A o.a| e I
i
, Ir_a(I
i
,a) = I
j
accion[i, a] = desplazar j
b) Si A o. e I
i
accion[i, a] = reducir "A o" a e SIGUIENTE(A).
c) Si S S. e I
i
accion[i, $] = ACEPTAR
iii) Si Ir_a[I
i
, A] = I
j
, siendo A un no terminal IR_A[i, A] = j
iv) Todas las entradas no definidas constituyen los errores.

Ejemplo.- Para la gramtica aumentada ya vista:

(0) E E (1) E E+T (2) E T (3) T T*F
(4) T F (5) F (E) (6) F id

Veremos como con los terminales hallamos la tabla de accin y con los no
terminales la IR_A:

I
0
= E .E
E .E+T
E .T
T .T*F
T .F
F .(E) F .(E) e I
0
, Ir_a(I
0
,() = I
4
accion[0, (] = d4
F .id F .id e I
0
, Ir_a(I
0
,id) = I
5
accion[0, id] = d5

Adems, como:

Ir_a(I
0
,E) = I
1
IR_A[0, E] = 1
Ir_a(I
0
,T) = I
2
IR_A[0, T] = 2
Ir_a(I
0
,F) = I
3
IR_A[0, F] = 3

E E. e I
1
accion[1, $] = ACEPTAR

E E.+T e I
1
, Ir_a(I
1
, +) = I
6
accion[1, +] = d6

81
E T. e I
2
accion[2, a] = r2 (regla E T) a e SIGUIENTE(E) = { ), +, $},
con lo cual:
accion[2, )] = r2
accion[2, +] = r2
accion[2, $] = r2

T T.*F e I
2
, Ir_a(I
2
, *) = I
7
accion[2, *] = d7

T T*F. e I
10
accion[10, a] = r3 (regla T T*F) a e SIGUIENTE(T) = { *, ),
+, $}, con lo cual:
accion[10, *] = r3
accion[10, )] = r3
accion[10, +] = r3
accion[10, $] = r3

E (E.) e I
8
, Ir_a(I
8
, )) = I
11
accion[8, )] = d11
E E.+T e I
1
, Ir_a(I
8
, +) = I
6
accion[8, +] = d6

As continuaramos para todos los I
i
. Al final nos quedara la tabla ya vista
anteriormente:

ESTADO id + * ( ) $ E T F
0 d5 d4 1 2 3
1 d6 ACEP.
2 r2 d7 r2 r2
3 r4 r4 r4 r4
4 d5 d4 8 2 3
5 r6 r6 r6 r6
6 d5 d4 9 3
7 d5 d4 10
8 d6 d11
9 r1 d7 r1 r1
10 r3 r3 r3 r3
11 r5 r5 r5 r5
ACCIN IR_A

Veamos ahora el caso de una gramtica que no es SLR, si consideramos la
siguiente gramtica:

(0) S S (1) S L=E (2) S E (3) E L
(4) L *E (5) L id



Si realizamos el ejercicio completo nos quedara:

PRIMERO SIGUIENTE
S *, id $
L *, id =, $
82
E *, id =, $

Calculemos los elementos LR(0):

I
0
= {cerradura({[S .S]})} = S .S
S .L=E
S .E
L .*E
E .L
L .id
I
1
= Ir_a(I
0
, S) = S S.

Al generar la tabla el problema estara en I
2
porque obtendramos:

I
2
= Ir_a(I
0
, L) = S L.=E desplazar con =
E L. reducir EL con =
porque = e SIG(E)

Entre I
0
e I
2
la transicin se realizara por "L".

Con lo cual, mediante SLR no podramos generar la tabla, este mtodo no
sera lo suficientemente potente para esta gramtica.

I
3
= Ir_a(I
0
, E) = S E.

I
4
= Ir_a(I
0
, *) = L *.E
E .L
L .*E
L .id

I
5
= Ir_a(I
0
, id) = L id.

I
6
= Ir_a(I
2
, =) = S L=.E
E .L
L .*E
L .id

I
7
= Ir_a(I
4
, E) = L *E.

I
8
= Ir_a(I
4
, L) = E L.

Ir_a(I
4
, *) = I
4

Ir_a(I
4
, id) = I
5


I
9
= Ir_a(I
6
, E) = S L=E.

Ir_a(I
6
, L) = I
8

Ir_a(I
6
, *) = I
4

83
Ir_a(I
6
, id) = I
5


La tabla nos quedara:

ESTADO id = * $ S L E
0 d5 d4 1 2 3
1 ACEP.
2 d6/r3 r3
3 r2
4 d5 d4 8 7
5 r5 r5
6 d5 d4 8 9
7 r4 r4
8 r3 r3
9 r1
ACCIN IR_A

Como se puede ver, tenemos el conflicto en [2,=] tal y como habamos
anunciado.

Ejemplo.- Calcular la tabla de anlisis LR de la siguiente gramtica mediante
el mtodo SLR:

E E+T
E T
T TF
T F
F F*
F a
F b

Ejemplo.- Calcular la tabla de anlisis LR de la siguiente gramtica mediante
el mtodo SLR:

S E $
E T + E
E T
T ( E )
T x

Ejemplo.- Calcular la tabla de anlisis LR de la siguiente gramtica mediante
el mtodo SLR:

S S $
S ( L )
S x
L S
L L , S
84

4.2.4.2 Mtodo LR-cannico.
Es el mtodo LR ms potente, funciona para casi todas las gramticas.

Llamamos elemento de anlisis LR(1) a una produccin con un punto y un
terminal, esto es: [A o.|, a]

Si tenemos un elemento de la forma [A o.|, a], no tiene efecto, en cambio
si es [A o., a] lo que nos indica es que ese es el elemento que hay que
mirar cuando tenemos varios.

Al igual que en SLR, partimos de la gramtica aumentada G generada a partir
de G.

Algoritmo para calcular cerradura(I)

Funcin cerradura(I)
BEGIN
REPEAT
FOR cada elemento [A o.B|, a] e I
Y cada B v e G
Y b e PRIMERO(|a)
Y [B .v, b] e I
DO aadir [B .v, b] en I
UNTIL no se puedan aadir ms a I
END.

Algoritmo para calcular Ir_a(I, X)

Funcin Ir_a(I, X)
BEGIN
Sea J el conjunto [A oX.|, a] tal que [A o.X|, a] e I
Return cerradura(J)
END.

Algoritmos de coleccin de elementos LR(1)

Procedimiento elementos_LR(1)(G)
BEGIN
C = {cerradura({[S .S, $]})}
REPEAT
FOR cada I, I c C Y cada X e G donde Ir_a(I, X) = C Y
Ir_a(I, X) . C, entonces aadir Ir_a(I, X) a C
UNTIL no se puedan aadir ms conjuntos a C
END.

Ejemplo.- Sea la gramtica:

85
S CC
C cC | d

Calcular los elementos de anlisis por el mtodo LR-cannico.

Primero creamos la gramtica extendida:

S S
S CC
C cC | d

I
0
= {cerradura({[S .S, $]})} = S .S, $
S .CC, $ porque PRIMERO($) = {$}
C .cC, c porque PRIMERO(C$} = {c, d}
C .cC, d porque PRIMERO(C$} = {c, d}
C .d, c porque PRIMERO(C$} = {c, d}
C .d, d porque PRIMERO(C$} = {c, d}

Ir_a(I
0
,S) = cerradura([S S., $]) = I
1
= S S. , $

Ir_a(I
0
,C) = cerradura([S C.C, $]) = I
2
= S C.C, $
C .cC, $
C .d, $

Ir_a(I
0
,c) = cerradura([C c.C, c], [C c.C, d]) = I
3
= C c.C, c
C c.C, d
C .cC, c
C .cC, d
C .d, c
C .d, d

As continuaramos hasta llegar a conseguir el autmata siguiente:
86

Obtencin de la tabla de anlisis LR-cannico

Para la construccin de la tabla seguimos los siguientes pasos:
i) Construir el conjunto C = { I
0
, I
1
, ..., I
n
}
ii) Los estados se construyen a partir de los conjuntos I
i
. El estado k es I
k
,
para rellenar las casillas hacemos:
a) Si [A o.a|, b] e I
i
, Ir_a(I
i
,a) = I
j
accion[i, a] = desplazar j
b) Si [A o., a] e I
i
, A = S accion[i, a] = reducir "A o"
c) Si [S S., $] e I
i
accion[i, $] = ACEPTAR
iii) Si Ir_a[I
i
, A] = I
j
, siendo A un no terminal IR_A[i, A] = j
iv) Todas las entradas no definidas constituyen los errores.

Ejemplo.- Para la gramtica anterior la tabla resultante sera:
ESTADO c d $ S C
0 d3 d4 1 2
1 ACEP.
2 d6 d7 5
3 d3 d4 8
4 r3 r3
5 r1
6 d6 d7 9
7 r3
8 r2 r2
9 r2
ACCIN IR_A
S . S, $
S . CC, $
C . cC, c| d
C . d, c| d
I
0

S C. C, $
C . cC, $
C . d, $
I
2

S S. , $
I
1

C c. C, c| d
C . cC, c| d
C . d, c| d
I
3

C d. , c| d
I
4

S CC. , $
I
5

C c. C, $
C . cC, $
C . d, $
I
6

C cC. , c| d
I
8

C d. , $
I
7

C cC. , $
I
9

d
C
c
S
c
d
C
c
d
d
C
c
C
87


4.2.4.3 Mtodo LALR.
El nmero de estados que genera es equiparable al SLR, pero es ms potente,
ms general. Adems la herramienta YACC utiliza este tipo de anlisis.

Existen bastantes algoritmos para realizarlo pero vamos a ver como calcularlo
a partir del LR-cannico.

En LR-cannico tenemos, por ejemplo, un estado en el que nos encontramos:

[A o.a|, e]
[A o.a|, f]

En LALR, llamamos a "o.a|" corazn y definimos un nico estado para ambos.
Tendremos menos estados, menos errores y tambin es menos potente.

En el ejercicio realizado en LR-cannico tenamos:

I
4
= [C d., c|d]
I
7
= [C d., $]

Entonces definimos un estado nico I
47
= [C d., c|d|$].

Ocurre lo mismo con los estados 3 y 6 y con los estados 8 y 9.
Para realizar la tabla LALR hacemos los siguientes pasos:

1. Construimos el conjunto LR(1) como en el caso de LR-cannico.
2. Remplazamos los conjuntos con el mismo corazn por su unin.
3. Encontramos las acciones de la misma forma que en LR-cannico, si
aparecen conflictos es que no puede implementarse como LALR.
4. Construimos la tabla IR_A usando que: el valor del corazn de Ir_a (I
i
, X) es
el mismo para todos los I
i
con el mismo corazn.

La tabla resultante para la gramtica anterior es la siguiente:

ESTADO c D $ S C
0 d36 d47 1 2
1 ACEP.
2 d36 d47 5
36 d36 d47 89
47 r3 r3 r3
5 r1
89 r2 r2 r2
ACCIN IR_A

Ejemplo.- Sea la siguiente gramtica, ya extendida:

88
S S
S aAd | bBd | aBe | bAe
A c
B c

I
0
= {cerradura({[S .S, $]})} = S .S, $
S .aAd, $
S .bBd, $
S .aBe, $
S .bAe, $

Ir_a(I
0
,S) = cerradura([S S., $]) = S S. , $ = I
1


Ir_a(I
0
,a) = cerradura([S a.Ad, $], [S a.Be, $]) = S a.Ad, $ = I
2

S a.Be, $
A .c, d
B .c, e

Ir_a(I
0
,b) = cerradura([S b.Bd, $], [S b.Ae, $]) = S b.Bd, $ = I
3

S b.Ae, $
A .c, e
B .c, d

Ir_a(I
2
,A) = S aA.d, $ = I
4
Ir_a(I
2
,B) = S aB.e, $ = I
5

Ir_a(I
2
,c) = A c., d = I
6

B c., e


Ir_a(I
3
,A) = S bA.e, $ = I
7

Ir_a(I
3
,B) = S bB.d, $ = I
8


Ir_a(I
3
,c) = A c., e = I
9

B c., d


Ir_a(I
4
,d) = S aAd., $ = I
10

Ir_a(I
5
,e) = S aBe., $ = I
11
Ir_a(I
7
,e) = S bAe., $ = I
12

Ir_a(I
8
,d) = S bBd., $ = I
13


Si construimos los conjuntos LR(1), dos de ellos sern:

I
6
= { [A c., d], [B c., e] }
I
9
= { [A c., e], [B c., d] }

que tienen el mismo corazn y daran lugar a la unin de ambos:

I
69
= { [A c., d|e], [B c., d|e] }
89

en donde, al generar la tabla de anlisis LR, producir un conflicto, en dos
casillas aparecern dos reducciones simultneamente A c y B c. Este
sera un ejemplo de gramtica que s es LR-cannico pero no LALR.

4.2.5 Generador de analizadores sintcticos YACC.
YACC significa Yet Another Compiler-Compiler, es decir otro compilador de
compiladores ms; su primera versin fue creada por S. C. Johnson. Este
generador se encuentra disponible como una orden del sistema UNIX y se ha
utilizado para facilitar la implementacin de gran cantidad de analizadores
sintcticos, tanto para compiladores de lenguajes de programacin como con
otros fines.

Si tenemos un programa yacc en un fuente con nombre ejemplo.y, los pasos
para convertirlo en un ejecutable son los siguiente:

yacc ej empl o. y
cc o mi ej empl o y. t ab. c l y
/ *A veces puede ser necesar i o t ambi n l m*/
mi ej empl o < f i cher o_pr ueba. t xt

La secuencia es la siguiente:

4. Yacc crea un fichero fuente en C, y.tab.c, desde una descripcin del
analizador sintctico en YACC.
5. y.tab.c se compila (es un programa C) generndose el ejecutable.
6. Este ejecutable realizar la traduccin especificada.

4.2.5.1 Partes de un programa YACC
La estructura de un programa en YACC es la siguiente:

Declaraciones
%%
Reglas de traduccin
%%
Rutinas de apoyo en C

- En la parte de Declaraciones se incluyen declaraciones ordinarias de C,
delimitadas por %{ y %}, declaraciones de variables temporales usadas por
las reglas de traduccin o procedimientos auxiliares de la segunda y
tercera secciones y componentes lxicos.

- Las reglas de traduccin constan de una produccin de la gramtica y una
accin semntica asociada, de la siguiente forma:

<lado izquierdo> : <alt 1> { accin semntica 1}
| <alt 2> { accin semntica 2}
90
...
| <alt n> { accin semntica n
;

En las reglas de produccin, un carcter simple entrecomillado c se
considera como el smbolo terminal c, y las cadenas sin comillas de letras y
dgitos no declarados como componentes lxicos se consideran no terminales.
Las acciones semnticas son instrucciones C, dentro de ellas, el smbolo $$ se
refiere al valor del atributo asociado con el no terminal del lado izquierdo,
mientras que $i se refiere al valor asociado con el i-simo smbolo gramatical,
terminal o no terminal, del lado derecho.

- Las rutinas de apoyo en C es la tercera parte de un programa en YACC. Es
necesario proporcionar un anlisis lxico con nombre yylex(). Tambin
pueden aadirse rutinas e recuperacin de apoyo.

El analizador lxico yylex() produce pares formados por un componente lxico
y su valor de atributo asociado. Si se devuelve un componente lxico como
CIFRA, ste debe de declararse en la primera seccin del programa. El valor
del atributo asociado a un componente lxico se comunica al analizador
sintctico mediante la variable yylval.

Vamos a ver un ejemplo de implementacin sobre YACC de una calculadora
sencilla. La gramtica para las expresiones aritmticas ser la siguiente:

E E + T | T
T T * F | F
R (E) | dgito

El componente lxico dgito es un solo dgito entre 0 y 9. El cdigo YACC es el
siguiente:

%{
#i ncl ude <ct ype. h>
%}

%t oken CI FRA

%%

l i nea : expr \ n { pr i nt f ( %d\ n, $1) ; }

expr : expr + t er mi no { $$ = $1 + $3; }
| t er mi no
;

t er mi no : t er mi no * f act or {$$ = $1 * $3; }
| f act or
;

f act or : ( expr ) { $$ = $2; }
| CI FRA
;
%%

yyl ex( ) {
91
i nt c;
c = get char ( ) ;
i f ( i sdi gi t ( c) ) {
yyl val = c- 0;
r et ur n CI FRA;
}
r et ur n c;
}

En la parte de declaraciones se ha introducido el include <ctype.h>, que nos
permitir utilizar el yylex() la funcin isdigit. La produccin inicial (linea)
se introduce para obligar al programa a aceptar una entrada seguida de un
carcter de nueva lnea.

Вам также может понравиться