Professional Documents
Culture Documents
Facultad deIngeniera
PROGRAMACION DE SISTEMAS II
Un compilador es un programa traductor que lee un programa escrito en un lenguaje (programa
fuente) y lo traduce a un programa equivalente en otro lenguaje (programa objeto). Una parte importante
durante el proceso de traduccin, es que el compilador indique los errores ocurridos.
PROGRAMA
FUENTE
PROGRAMA
OBJETO
COMPILADOR
MENSAJES DE
ERROR
El programa fuente puede estar escrito en varios lenguajes, as mismo, el programa objeto puede
ser diferente, quizs otro lenguaje, cdigo intermedio, o cdigo de mquina, el cual puede ser
ejecutado "directamente" por un microprocesador.
Existen compiladores de un paso, o de varios pasos, dependiendo de las lecturas que hagan del
archivo fuente o archivos con representaciones intermedias. Tambin existen de optimizacin de
cdigo, etc.
FASES DE UNA COMPILACION
Anlisis.- Descompone el programa fuente en piezas para obtener una representacin intermedia
del mismo.
Sntesis.- Toma la representacin intermedia para generar el cdigo mquina, o cuando menos, el
cdigo intermedio.
Durante la fase de anlisis se crean estructuras jerrquicas como los rboles de sintaxis.
X=2*Y+C
=
X
Existen impresoras que permiten la impresin con diferentes tipos de FONTS y los programas con
sangras. Estos pueden considerarse como parte de un compilador.
PREPROCESADORES
Existen algunos editores que van realizando algunas tareas adicionales, por ejemplo: Si se coloca
un "if automticamente se agrega un "then", o bien cuando se trabaja con parntesis se verifica el
balanceo de expresiones.
Los "Static Chequers" son otro tipo de preprocesadores que descubren posibles ciclos sin criterio
de paro, detectar las partes de cdigo que nunca sern ejecutadas; es similar a un proceso de
optimizacin de cdigo. Es decir, se enfoca ms hacia errores lgicos o semnticos.
-1-
Libreras para
los archivos
objeto
relocalizables.
-2-
ASIGNACION
IDENTIFICADOR
:=
EXPRESION
EXPRESION
IDENTIFICADOR
b
EXPRESION
EXPRESION
IDENTIFICADOR
EXPRESION
EXPRESION
IDENTIFICADOR
EXPRESION
IDENTIFICADOR
As en programacin:
:=
a
Semantico
:=
+
a
*
+
b
*
a
*
real
-3-
*
a
PROG. FUENTE
A. LEXICO
F. ANALISIS
TABLAS DE
SIMBOLOS
F. SINTESIS
A. SINTACTICO
A. SEMANTICO
GEN. COD. INT.
MANEJADOR
DE ERRORES
OPT. CODIGO
GEN. COD. OBJ.
PROG. OBJETO
-4-
+
id2
*
id3
num
A. SEMANTICO
asig
id1
+
id2
*
id3
real(num)
Pide un token
PROG. FUENTE
A. LEXICO
A. SINTACTICO
Devuelve token
TABLA DE
SIMBOLOS
Al analizador lxico se le dejan normalmente tareas como:
En ocasiones se separa un analizador lexicogrfico en dos fases consecutivas "scanner" para las
tareas ms sencillas y "analizador lxico para las ms complejas". Por ejemplo, un scanner se puede
encargar nicamente de la eliminacin de espacios, tabuladores, lneas en blanco y comentarios.
Distinguiendo tokens de lexemas:
TOKEN
const
if
op_rel
id
num
LEXEMA
const
if
>, <, =, >=, <=, <>
valor, i, Precio, D1
3, 3.5, -7, -12.3e-15
Cuando un token se asocia con ms de un lexema se debe almacenar informacin adicional para
que pueda ser distinguido en las siguientes fases, tal es el caso del token num y del token id:
-6-
VAR1
*
3
=
Algunas tareas sofisticadas, pero que pueden confundir al parser en un analizador lxico, son:
El analizador lxico es prcticamente la nica fase que leer el archivo de entrada carcter por
carcter, lo cual puede llevar mucho tiempo.
Una tcnica para agilizar esta tarea, es leer los caracteres en un buffer de tamao 2n partido por
la mitad, y colocar dos apuntadores, (Ap_inicio, Ap_avance); al principio ambos se encuentran en el
carcter de inicio del lexema a leer, y Ap_avance, avanza carcter por carct er hasta formar un lexema
que pueda ser asociado, en ese momento, se empatan Ap_inicio y Ap_avance en el inicio del siguiente
lexema, si Ap_avance llega al fin de la primera mitad del buffer, llama a la segunda mitad del buffer, si
Ap_avance llega al final de la segunda mitad, llena la primera mitad, y avanza al principio de la
primera. Esto no representa problemas si el analizador no tiene que hacer visitas adelantadas, pero si
requiriera visitas adelantadas, hay problemas en caso de que la cantidad adelan tada de caracteres sea
mayor que n.
2n
n
n
/0
Ap_ini
/0
Ap_ava
n-izq.
LENGUAJES.
-7-
a .
, y definimos
son
{ |
{ |
Cerradura de L
(L es 0 o ms concatenaciones de L)
Cerradura positiva de L
(L es 1 o ms concatenaciones de L)
-8-
De esta manera, una expresin regular sobre un alfabeto puede generar un lenguaje particular,
este lenguaje se denota como L(r) dada la expresin regular r. Algunas reglas que definen una
expresin regular sobre y los lenguajes generados son :
1.-
}.
|
Ej:
1).2).3).4).-
|
|
En el ejemplo (4) las dos expresiones son equivalentes denotadas con un signo igual r=s.
Las expresiones regulares tienen las siguientes propiedades
AXIOMA
|
|
| |
|
|
|
|
DESCRIPCION
| es conmutativo
| es asociativo
La concatenacin es asociativa
La concatenacin es distributiva sobre |
es el elemento idntico para la concatenacin
* es idempotente
DEFINICIONES REGULARES
, una
.
.
.
-9-
donde cada
{
Ej 1:
| | | | | |
| | |
|
Ej 1:
| |
|
|
|
Reduciendo la notacin
1.- Utilizando la cerradura positiva, dada
entonces
y
| .
2.- Utilizando el signo (-), dada
| .
genera
y | | |
| como
|
|
CONJUNTOS NO REGULARES
Existen algunos conjuntos que no pueden ser expresados con una "expresin regular", pero s con
una gramtica de contexto libre. No obstante, existen algunos conjuntos que no pueden ser
expresados ni an con una gramtica de contexto libre.
Se puede pensar que en un archivo de entrada, los identificadores van separados por espacios o
tabs o newlines. Entonces se puede hacer una definicin regular para este propsito:
|
Con lo anterior, si el analizador lexicogrfico encuentra un separador, no hay que hacer nada. El
objetivo de un analizador lexicogrfico es analizar la entrada y devolver al parser un par, el token
- 10 -
asociado y el atributo correspondiente al token, por ejemplo : Considerando LT, GE, GT, EQ como
constantes
EXPRESION
REGULAR
separador
if
then
else
id
num
<
>
>=
=
TOKEN
ATRIBUTO
if
then
else
id
num
op_rel
op_rel
op_rel
op_rel
DIAGRAMAS DE TRANSICION
Un diagrama de transicin es una grfica que describe las acciones seguidas por un analizador
lexicogrfico cuando un token es encontrado, los diagramas de transicin se forman con flechas
etiquetadas con los caracteres que se deben asociar a la entrada, conectados a crculos llamados
estados para indicar la transicin de un estado a otro por medio de la flecha etiquetada.
El diagrama cuenta con una flecha para el estado inicial y un crculo doble indica el estado final.
Ej: para operadores relacionales
<
return(op_rel, LE)
>
return(op_rel, NE)
otro
* return(op_rel, LT)
return(op_rel, EQ)
return(op_rel, GE)
otro
* return(op_rel, GT)
>
6
El asterisco significa que hay que regresar el apuntador en el buffer (Ap_avance) una posicin
para que dicho carcter sea reledo y pasado por otro diagrama de transicin. Si no se puede hacer la
transicin de un estado a otro, y hay ms posibilidades, se trata de hacer la transicin con la siguiente
posibilidad, y si con ninguna se logra, ha ocurrido un error lxico. Se asume adems, que los
diagramas de transicin son deterministicos, es decir, entre otras cosas, no se permiten dos o ms
flechas saliendo del mismo estado. Cuando se tienen varios diagramas de transicin si no se logra
- 11 -
trazar el camino en uno de ellos por medio de la entrada, se pasa al siguiente diagrama, si ya no
existen ms diagramas donde buscar ocurre un error lxico:
digito
9
digito
10
digito
11
digito
12
digito
13
+o-
14
digito
18
15
otro
16
digito
digito
17
digito
digito
19
digito
24
20
otro
21
digito
22
digito
23
otro
digito
25
letra
26
otro
27
letra
- 12 -
digito
9
digito
10
digito
11
digito
12
digito
13
E
otro
17
+o-
14
digito
15
otro
16
digito
otro
18
digito
19
letra
20
otro
21
letra
Un diagrama de transicin para eliminar los espacios (tabs, espacios y CR) es:
delim
22
delim
23
otro
27
return(COMIENZO)
FIN FUN
FUNCION TOKEN():cadena
Repite
Caso ESTADO=0
C=lee_car()
Caso C='<'
ESTADO=1
Caso C='='
ESTADO=5
Caso C='>'
ESTADO=6
Otro
ESTADO=diagrama()
Fin caso
Caso ESTADO=1
C=lee_car()
Caso C='='
ESTADO=2
Caso C='>'
ESTADO=3
Otro
ESTADO=4
Fin caso
Caso ESTADO=2
Ap_inicio=Ap_avance
TokenVal='EQ'
return(op_rel)
.
.
.
Caso ESTADO=4
Ap_avance=Ap_avance-1
Ap_inicio=Ap_avance
TokenVal='LT'
return(op_rel)
.
.
.
Caso ESTADO=21
Ap_avance=Ap_avance-1
TokenVal=Anexa_Lex() /* Anexa a taba, devuelve apuntador */
Ap_inicio=Ap_avance
return(id)
.
.
.
Caso ESTADO=27
Ap_avance=Ap_avance-1
ESTADO=0
Fin caso
Fin repite
FIN FUN
Comienza
Ap_inicio=1
- 14 -
Ap_avance=1
escribe("Digitar cadena y al final *")
lee(cad)
Repite
ESTADO=0
COMIENZ0=0
T=TOKEN()
escribe("Token encontrado: ",T)
Ap_inicio=Ap_avance
Hasta(car[Ap_avancej="*")
Termina
AUTOMATAS NO-DETERMINISTICOS
Un autmata finito es un diagrama que permitir saber si una cadena es o no aceptada por una
expresin regular. Un NFA es un modelo matemtico que consiste de:
1.- Un conjunto S de estados.
2.- Un conjunto de smbolos de entrada .
3.- La funcin de transicin " mueve" que mapea pares estado-smbolos hacia un conjunto de
estados.
4.- Un estado de inicio .
5.- Un conjunto de estados de aceptacin o finales F.
Diagramticamente se ve como un grato dirigido. Ej:
A={a,b}
Expresin:
F={3}
a
0
b
El autmata puede ser representado fcilmente en una computadora como una matriz.
ESTADOS
0
1
2
SIMBOLOS
a
b
{0,1}
{0}
{2}
{3}
|
- 15 -
a
1
b
AUTOMATAS FINITOS DETERMINISTICOS
Un DFA es un caso particular de un NFA en el cual:
1.- No hay estados con una
.
2.- Para cada estado S y cada smbolo "a" hay cuando ms una flecha saliendo de S etiquetada
por "a".
Si se elabora una matriz para un DFA, sta contiene exactamente como elementos un estado.
Ejemplo:
|
b
b
0
a
a
Si (S F) entonces
Aceptada
otro
Rechazada
Fin si
termina
a travs de un carcter a
Ejemplo:
a
c
3
b
c
mueve(0,a) = 1
mueve(1 ,b) = 2
B).-
mueve(1,a) =1
etc.
: Donde T es un conjunto de estados, indica las transiciones sobre cada elemento del
conjunto.
Considerando el diagrama anterior. Ejemplo:
T={0,1,2}
mueve(T,a) = { 1,2 }
mueve(T,b) = { 2,3 }
C).-
: Estados de un NFA que pueden ser visitados al recorrer el NFA a travs de transiciones con comenzando por el estado S inclusive.
- 17 -
Ejemplo:
= { 1,2,4,5,6,7 }
C).-
= { 1,2,3,4,6,7,8 }
ALGORITMO
D: Conjunto de conjuntos de estados
AUTO: Matriz para representar el DFA obtenido
So: Estado inicial del NFA
comienza
D contiene a -cerradura(So) sin marcar
Mientras haya un T sin marcar en D
Marcar T
Para cada smbolo a hacer
U=-cerradura(mueve(T,a))
Si U no esta en D entonces
aade U a D sin marcar
Fin si
AUTO[T,a]=U
Fin para
Fin mientras
termina
CONSTRUCCION DE UN NFA A PARTIR DE UNA EXPRESION REGULAR
A continuacin se presenta un algoritmo para construir un NFA a partir de una expresin regular
considerando la concatenacin, la alternacin y la cerradura.
ALGORITMO
Entrada.- Expresin regular "r" sobre un alfabeto .
Salida.- NFA aceptando L(r).
- 18 -
Mtodo.- Primero se construyen NFA's muy sencillos para cada smbolo en , y para como se
muestra en (1) y (2).
Posteriormente, usando la estructura sintctica de la expresin regular "r", se van combinando los
incisos de (3). Los NFA's obtenidos tienen exactamente un estado inicial (al que no entran flechas) y
un estado final (del que no salen flechas).
1.- Para construir el NFA:
inicio
a
inicio
3.- Suponga que N(s) y N(t) son NFA's para las expresiones "s" y "t" respectivamente.
a).- Para la expresin regular s|t se construye el NFA N(s|t) como:
N(s)
inicio
N(t)
N(s)
inicio
N(t)
se construye el NFA
- 19 -
como:
inicio
N(s)
ANALISIS LEXICOGRAFICO
En programacin se distinguen cuatro elementos fundamentales:
Cuando una secuencia de dgitos es encontrada en el analizador lxico, se pasa el token (#, num,
etc.) al parser; aunque en alguna parte se debe almacenar el valor del numero en cuestin. Por
ejemplo, en parejas:
19 + 20 + 21
<#,19> <+,> <#,20> <+,> <#,21>
De la misma manera, cuando se tienen identificadores, al parser se le pasa un token como "id"
simplemente, aunque el lexema y sus atributos son almacenados en alguna parte. As
CONT = CONT + SUMA
id= id + id
- 20 -
Se debe conocer si un lexema ya ha sido encontrado con anterioridad, esto es viable con una
tabla de smbolos, donde se almacena el lexema, un apuntador y algunos Atributos asociados Al
lexema. La forma de distinguir entre identificadores y palabras reservadas, es fcil, ya que las palabras
reservadas son conocidas con anterioridad, normalmente se almacenan en alguna otra parte. En
muchas ocasiones el analizador lexicogrfico debe adelantarse a leer algunos caracteres ms ( >= )
para decidir que es, y hay que regresarse en ocasiones porque se est tomando un carcter de ms,
pero del siguiente token.
El analizador lexicogrfico se puede integrar al parser como un simple procedimiento.
Una forma til de implementar una tabla de smbolos es como sigue:
TABLA DE SIMBOLOS
Ap
1
2
3
4
5
Token
id
mod
num
div
id
Atributos
c o n t /0
Arreglo de lexemas
/0
/0
Conjunto de terminales
Conjunto de no terminales
Producciones
Smbolo inicial de la gramtica.
- 21 -
1) LISTA
2) LISTA
3) LISTA
4) DIGITO
LISTA + DIGITO
LISTA - DIGITO
DIGITO
0|1|2|3|4|5|6|7|8|9
As, 9-5+2
a.- 9 es una lista, y es un dgito por 3)
b.- 9-5 es una lista por 2), 9 es lista y 5 dgito
c.- 9-5+2 es lista por 1) 9-5 es lista y2 dgito
LISTA
LISTA
LISTA
DIGITO
DIGITO
DIGITO
9
Existe la notacin de para indicar cadenas vacas.
ARBOL DE PARSER
Dada una produccin X A B C
X
A
- 22 -
EXP
EXP
EXP
EXP
EXP
EXP
EXP
EXP
EXP
EXP
2
LISTA
LISTA
LISTA
DIGITO
DIGITO + LISTA
DIGITO - LISTA
DIGITO
0|1|2|3|4|5|6|7|8|9
LISTA
DIGITO
LISTA
DIGITO
LISTA
DIGITO
2
Perser es el proceso mediante el cual se determina si un string de tokens puede ser generado por
una gramtica. Existen mtodos top-down y bottom up.
Para hacer la expansin de un rbol de sintaxis e ir asociado con el rbol una cadena de entrada,
se comienza con el smbolo inicial de la gramtica, y se toma el primer token de la entrada y se busca
la produccin que derive el no-terminal y que comience con el token de entrada. Con dicha produccin
se construyen las ramas para el nodo. En caso de que uno de los hijos se asocie con uno de los
smbolos de entrada, se recorre el rbol de izquierda a derecha hacia el siguiente hijo y tambin se
toma el siguiente token de la entrada.
- 23 -
FRONTERA PARSER-LEXICO
En la construccin de un compilador es recomendable utilizar una gramtica de contexto libre para
especificar sintaxis y una definicin regular para la estructura de tokens, es decir, el anlisis lxico, as
considere la gramtica:
AFIRMACION
AFIRMACION
AFIRMACION
EXP
TERMINO
Para los terminales if, then, else, op_rel, id, num construimos una definicin regular como:
|
| |
| |
| |
| | | |
|
|
|
|
- 24 -
Peticion
Programa
Fuente
ANALIZADOR
LEXICO
ANALIZADOR
SINTACTICO
Arbol de Parser
RESTO DEL
FRONT END
Token
TABLA DE
SIMBOLOS
Existen mtodos generales para procesos de parser, pero son demasiado ineficientes, por lo cual
se prefieren mtodos como el top-down y el bottom-up El primero construye rboles sintcticos de la
raz a las hojas y el segundo de las hojas a la raz. En ambos casos se revisa la entrada de izquierda a
derecha tomando un smbolo a la vez.
Los parsers top-down y bottom-up ms eficientes trabajan sobre subclases de gramticas como
las LL o las LR, y con estas gramticas se pueden implementar prcticamente todos los lenguajes
actuales de programacin.
PARSER RECURSIVO-DESCENDENTE
Es un mtodo de parser top-down. Este m,todo asocia un procedimiento, o una funcin por cada
elemento no terminal de la gramtica. El procedimiento seleccionado esta en funcin del smbolo de
entrada. La ejecucin de los procedimientos durante la ejecucin, implcitamente define el rbol de
parser para la entrada. Se aade un procedimiento para la asociacin de los tokens de entrada con los
tokens de la gramtica.
Ejemplo:
PROC asocia(token)
comienza
Si CABEZA = token entonces
CABEZA = SIG_CABEZA
otro
Error()
Fin si
termina
PROC tipo()
comienza
CASO DE
CABEZA ={integer o char o #}
simple()
CABEZA = ^
asocia(^)
asocia(id)
CABEZA = array
asocia(array)
asocia([)
simple()
asocia(])
asocia(of)
- 25 -
tipo()
OTRO
Error()
FIN CASO
Termina
PROC simple()
comienza
CASO DE
CABEZA = integer
asocia(integer)
CABEZA = char
asocia(char)
CABEZA = #
asocia(#)
asocia(.)
asocia(.)
asocia(#)
OTRO
Error()
FIN CASO
termina
Este parser utiliza informacin sobre los primeros smbolos de la parte derecha de las
producciones; esto es, sobre los conjuntos FIRST.
As
FIRST(simple) = {integer,char,#}
FIRST(^id) = {^}
FIRST(array [SIMPLE] of TIPO) = {array}
Cuando se tienen producciones A y A , el parser recursivo descendente requiere que
FIRST( )<>FIRST( ) para poder decidir por medio del smbolo de entrada que produccin tomar, si
CABEZA esta en FIRST( ) se toma A , si CABEZA esta en FIRST( ) se toma A . Si la gramtica
no est diseada como se indica, habr que factorizarla.
En caso de que se tengan -producciones, se deben tratar con cuidado. El parser recursivo
descendente usa una -produccin cuando no existe el smbolo de entrada en el FIRST de la parte
derecha de la produccin en cuestin.
FACTORIZACION DE UNA GRAMATICA
Si se tienen producciones de la forma
A a | a
el parser no podr decidir que produccin usar porque ambas comienzan en la parte derecha con
"a". Esto se soluciona reemplazando las producciones por
A aA'
A' |
Esta regla se puede generalizar como sigue:
Para cada no terminal A se encuentra el prefijo ms grande comn a dos o ms producciones y
- 26 -
por
A A
A
Si se usan producciones corno esta, el proceso en computadora entra a un loop sin fin. El proceso
de eliminacin es sencillo y se trata de eliminar la recursividad izquierda convirtindola a recursividad
derecha:
A A'
A' A' |
| | |
Existen casos en que la recursin no es inmediata y hay que aplicar otro proceso.
CALCULO DEL CONJUNTO FIRST
Aplquense las 3 reglas siguientes para todos los smbolos gramaticales (terminales y no-
- 27 -
Entrada
Pila
X
Y
ANALIZADOR
SINTACTICO
Emite un
diagnstico
TABLA
PREDICTIVA
(Selecciona la
produccin
adecuada)
La tabla predictiva es un arreglo matricial que permite seleccionar la produccin adecuada para ir
asociando los tokens de la cadena de entrada por medio de la pila.
Para la construccin de los parsers con tabla predictiva, es necesario la elaboracin de otros
conjuntos, los FOLLOW's.
CALCULO DE CONJUNTOS FOLLOW
Para construir el conjunto FOLLOW( A) para todos los no-terminales A, se aplican las reglas
siguientes hasta que no se pueda aadir nada ms a los conjuntos FOLLOW:
1.- Aadase al FOLLOW(S ) dnde S es el smbolo inicial de la gramtica.
- 28 -
GRAMATICAS LL(1)
Las gramticas LL(1) son un subconjunto de las gramticas de contexto libre que cumplen con
que dadas dos producciones distintas de G como A | :
1.- Para ningn terminal "a" y derivan a la vez cadenas que comienzan con "a".
2.- A lo sumo una de y puede derivar .
3.- Si *, no deriva ninguna cadena que comience con un terminal en el FOLLOW( A ).
La primera L quiere decir "left to right", recorrido de la cadena de izquierda a derecha, y la
segunda L por leftmost derivation", derivaciones por la izquierda. El 1, es porque se utiliza el anlisis
de un solo smbolo de entrada a la vez para las decisiones del parser.
Para este tipo de gramticas se puede construir una tabla predictiva LL(1) con la cual se puede
seleccionar la produccin adecuada durante la revisin de una cadena de entrada. La tabla es un
arreglo matricial de
donde los renglones se encabezan con los no-terminales y las columnas con
los terminales inclusive , o viceversa.
CONSTRUCCION DE UNA TABLA LL(1)
Para cada produccin A de la gramtica hacer:
1.- Por cada terminal "a" en el FIRST() adase A a M[A,a].
2.- Si est en FIRST(), adase A a M[A,b] para cada terminal "b" del FOLLOW( A ). Si
est en FIRST() y est en FOLLOW(A ), adase A a M[A,].
3.
El parser funciona con una pila, que en un principio contiene en el fondo el smbolo terminal de la
gramtica(), y en el tope el smbolo inicial de la gramtica. La cadena a ser revisada debe tener hasta
el final el smbolo terminal de la gramtica. El parser toma el elemento X del tope de la pila, y un
elemento "a" de la cadena a ser revisada, con estos dos elementos el parser decide que accin realizar,
a saber, hay cuatro posibilidades :
1.- Si X=a= el anlisis ha terminado y quiere decir que la cadena ha sido revisada con xito.
2.- Si X=a<> el parser saca a X de la pila y lee el siguiente token de la cadena de entrada.
3.- Si X<>a y X es un terminal hay error.
4.- Si X es un no terminal, se consulta el elemento M[X,a] de la tabla predictiva, este elemento de
la tabla ser una produccin o un error. Si la entrada de la tabla es una produccin, por ejemplo,
M[X,a]=X A + C, se sustituye X por la parte derecha de la produccin en orden inverso C + A, de tal
modo que quede A en el tope de la pila. Si M[X,a]=error, el parser llama a una rutina de error.
Pseudocdigo:
- 29 -
a=lee_token()
Repite
pop(X)
Si(a= y X=) entonces
Aceptada
Otro
Si(X es terminal) entonces
Si(X=a) entonces
a= lee_token()
otro
Error()
Fin si
otro
Si(M[X,a]=XY1 Y2 ... Yk) entonces
Para i= k hasta 1
Push (Yk)
Finpara
otro
Error()
Finsi
Finsi
Hasta (X=)
NOTA: Por facilidad de manejo, en la tabla predictiva se guarda con frecuencia solamente un
nmero que indica la produccin por la que hay que reducir en la pila.
RECUPERACION DE ERRORES EN PARSERS LL(1)
Una tcnica que pudiera ser til para la recuperacin de los errores en este mtodo, es hacer lo
siguiente:
Se agregan a la tabla las entradas M[A,a]=sinc (sincronizacin) donde "a" son los elementos de
FOLLOW(A). Si existe colisin con una produccin, se prefiere (obviamente) la produccin.
La forma de utilizar la tabla es, si M[A,a]=sinc se saca el no-terminal del tope de la pila y se
contina con el anlisis. Si M[A,a] est en blanco, el parser se salta el token de entrada y continua con
el anlisis. Utilizando este mtodo hay posibilidad de que si se detecta un error, se ignore (previa
indicacin de que ha ocurrido un error), y pueda seguir la revisin. La tcnica anterior es heurstica,
por lo cual puede variar dependiendo de la gramtica, adems debemos tener cuidado en que la
tcnica no entre a un ciclo sin fin.
Quizs la tcnica puede mejorarse si se hace un anlisis ms a conciencia de los posibles errores
que pueden ocurrir, y con esto, colocar en la tabla en lugar de la palabra "si nc" o dejarla en blanco, la
llamada a un procedimiento especfico para recuperar ese error particular y hacer la indicacin.
ANALIZADORES SINTACTICOS LR
Otra tcnica para la revisin sintctica, son los analizadores LR que viene del ingls "L -left to
right" que es el recorrido de la cadena de entrada de izquierda a derecha, y la "R-rightmost derivation"
que son derivaciones por la derecha, ya que en este mtodo se parte de las hojas del rbol para llegar
a la raz (al inverso del LL(1)), y el 1 porque se utiliza un slo smbolo de entrada a la vez para tomar
las decisiones del parser.
Estos analizadores sintcticos requieren de mayor trabajo y mayor espacio para su
funcionamiento, no obstante, aceptan una gama ms amplia de gramticas. Se vern tres tipos del
- 30 -
mtodo LR.
El esquema de funcionamiento de los parsers LR es el siguiente : Entrada a*C+(3*x):
Entrada
Pila
Em
Xm
Em-1
Xm-1
.
.
.
E1
X1
E0
ANALIZADOR
SINTACTICO
Emite un
diagnstico
TABLA LR
ACCIOGOTO's
NES
(el estado 0
, Reduce( j )=
, Goto( )=
y cuyas columnas
Donde el fondo es
y el tope es
1. Si M[
, a]=
4. Si la entrada M[
Pseudocdigo:
a=lee_token()
Repite
S=Tope de la pila
Si M[S,a]=Si entonces
push(a)
push(i)
a=lee_token()
otro
Si M[S,a]=Rj (A) entonces
Para k=1 hasta 2*||
pop(e)
Fin para
push(A)
push(M[e,A])
otro
Si M[S,a]=Ac entonces
aceptada()
otro
error()
Finsi
Finsi
Finsi
Fin repite
El algoritmo para la revisin de un texto de entrada es el mismo para los tres casos de parser LR,
lo nico que vara son las tablas.
PARSER SLR(1)
A continuacin se muestra el mtodo para construir una tabla SLR(1) (Simple LR). Pero antes de
continuar se deben conocer algunos otros conceptos.
ITEMS LR(0)
Un item LR(0) es una produccin con un punto en alguna posicin de la parte derecha. Por
ejemplo la produccin A A+A tiene cuatro items LR(0)
[A A + A]
[A A + A]
[A A + A]
[A A + A ]
- 32 -
Al caso particular A , genera un solo tem, [A ] . A una serie de tems LR(0) se le denomina
coleccin cannica LR(0).
OPERACION DE CERRADURA
Si I es un conjunto de tems en G se construye cerradura(I) como:
1. Todos los elementos de I estn en cerradura(I).
2. Si hay un tem como [A B] y B es una produccin, se aade el tem [B ]. Se
repite esta regla hasta que ya no se puedan aadir ms tems.
OPERACION GOTO
La operacin GOTO que se escribe como goto(I,X), donde I es un conjunto de tems y X un
smbolo gramatical, se define como la cerradura del conjunto de todos los tem s [A X] tales que
[A X] estn en I.
Con las operaciones anteriores se puede encontrar la coleccin cannica de tems LR( 0), y los
estados del DFA, para posteriormente construir una tabla predictiva. Primero se obtiene a partir de G
una gramtica aumentada G', que consiste en agregar una produccin al principio y cambiar
consecuentemente el smbolo inicial de la gramtica, S' S. Posteriormente se calcula la cerradura
para S' S, y se comienzan a realizar las operaciones gto sobre el conjunto encontrado. Ejemplo :
0)
1)
2)
3)
4)
5)
6)
7)
8)
F'
F
MENOS
MENOS
EXP
S
S
OP
OP
F
f ( x ) = MENOS EXP
# S
OP EXP
TERMINALES={f, (, x, ), =, -, #, +, }
NO TERMINALES = {F', F, MENOS, EXP, S, OP}
0) F'
F
F
f ( x ) = MENOS EXP
1) F'
2) F
f ( x ) = MENOS EXP
goto(2,()=3
3) F
f ( x ) = MENOS EXP
goto(3,x)=4
4) F
f ( x ) = MENOS EXP
goto(4,))=5
5) F
f ( x ) = MENOS EXP
goto(5,=)=6
6) F
MENOS
MENOS
f ( x ) = MENOS EXP
goto(6,MENOS)=7
goto(6,-)=8
goto(0,F)=1
goto(0,f)=2
- 33 -
7) F
EXP
f ( x ) = MENOS EXP
# S
8) MENOS
9) F
f ( x ) = MENOS EXP
10) EXP
S
S
OP
OP
11) EXP
# S
12) S
EXP
OP EXP
# S
13) OP
14) OP
15) S
OP EXP
goto(7,EXP)=9
goto(7,#)=10
# S
OP EXP
goto(10,S)=11
goto(10,OP)=12
goto(10,-)=13
goto(10,+)=14
goto(12,EXP)=15
goto(12,#)=10
TABLA SLR(1)
Una vez construido el conjunto cannico, se siguen las reglas:
1. Si goto (i,a)= j, donde a es terminal, M[i,a]= Shift(j).
2. Si goto (i,A)= j, donde A es no-terminal, M[i,A]=Goto(j).
3. Si A est en i, M[i,b]=Reduce(j) (reduce por la produccin nmero j), para todo b en el
FOLLOW(A), y AS'.
4. Si S' S est en i, M[i,]=Acceptar.
5. Todas las dems entradas no definidas son error.
Si existen colisiones se dice que la gramtica no es SLR.
PARSER LR(1)
ITEMS LR(1)
Para la construccin de la tabla LR(1) se requiere calcular el conjunto cannico de tems LR(1). Se
modifica la operacin de cerradura.
Los tems del conjunto LR(1) tienen la forma [A B, a], (tienen el nuevo elemento a llamado
smbolo de anticipacin) y la cerradura para un conjunto de tems I se calcula como:
1. Para cada tem de la forma [A B, a] en I, sea B una produccin, se aade el tem
[B , b] para cada b en FIRST(a). Se repite esta regla hasta que no se pueda aadir nada ms.
- 34 -
Para construir el conjunto cannico de tems LR(1) dada una gramtica, primero se calcula la
cerradura para el tem [S' S, ], con lo que se crea el primer estado, y posteriormente se comienzan
a hacer las operaciones goto hasta que ya no puedan ser aadidos ms tems.
CONSTRUCCION DE LA TABLA LR(1)
1. Si goto (i,a)= j, donde a es terminal, M[i,a]= Shift(j).
2. Si goto (i,A)= j, donde A es no-terminal, M[i,A]=Goto(j).
3. Si [A , a] est en i, M[i,a]=Reduce(j) (reduce por la produccin j), y AS'.
4. Si [S' S, ] est en i, M[i,]=Aceptar.
5. Todas las dems entradas no definidas son error.
Una de las desventajas de este mtodo es que produce tablas predictivas demasiado grandes, por
lo que en ocasiones se utiliza un parser LALR que tiene mayor cobertura que un SLR, y produce tablas
ms pequeas que las LR.
PARSER LALR(1)
Este mtodo se basa en los ncleos de los tems LR(1), agrupando los ncleos iguales en un solo
estado, para reducir el nmero de estados. Se buscan los elementos LR(1) con mismos ncleos y se
reemplazan por su unin. El nico conflicto posible es el de reduccin/reduccin, y entonces, se dice
que la gramtica no es LALR. Para construir la tabla se realiza el siguiente mtodo. Las siglas del
mtodo quieren decir "look ahead-LR", anlisis sintctico LR con smbolo de anticipacin.
1. Constryanse el conjunto
de tems LR(1).
2. Bsquense todos los conjuntos con ncleos iguales y sustityanse por su unin obteniendo el
{
nuevo conjunto que llamaremos
. Al realizar la operacin goto(J,X)= , J puede
ser la unin de varios conjuntos I, es decir
, y si m no existe como conjunto
independiente porque m forma parte de alguna unin
, goto(J,X)=L.
3. Aplquense todos los pasos utilizados en la construccin de la tabla LR(1). Si existe algn
conflicto, se dice que la gramtica no es LALR(1).
TRASLACION DIRIGIDA POR SINTAXIS
NOTACION POSTFIJA.
1. Si E es variable o constante el postfijo de E es E.
2. Si E es una expresin de forma
con op como operador binario, el postfijo de E es
donde
y
son los postfijos de
y .
3. Si E es de la forma (
), el postfijo E es el postfijo de
(9-5)+2 = 9 5 - 2 +
9-(5+2) = 9 5 2 + Durante el proceso de traslacin, un compilador puede ir almacenando ciertas cantidades que
servir n para la generacin de cdigo. En este punto es donde se consideran los atributos asociados
con algn elemento.
Un formalismo para implementar estas actividades se llamado "SYNTAX DIRECTED DEFINITION"
(definicin dirigida por sintaxis). Esta especifica los atributos con los componentes sintcticos de
- 35 -
alguna definicin.
Una DDS usa una gramtica de contexto libre para especificar la estructura de una cadena, con
cada smbolo de la gramtica se asocia un conjunto de atributos, y con cada produccin de la
gramtica, una regla semntica. La gramtica y las reglas semnticas forman la SDD. Una translacin
es el mapeo de una entrada en una salida por medio de la DDS. Para producir la salida, primero se
construye un rbol de perser para X. Se escribe X.a para denotar el valor del atributo a en el nodo n. El
valor de X.a en el nodo n es calculado por la regla semntica asociada con la X-produccin.
Por ejemplo:
PRODUCCIONES
EXP
EXP
EXP
TERM
TERM
REGLA SEMANTICA
EXP + TERM
EXP - TERM
TERM
num
id
EXP.a := EXP.a T RM a
EXP.a := EXP.a T RM a EXP.a := TERM.a
TERM.a := num.val
TERM.a := id.val
Estas reglas semnticas trasladan una expresin en notacin infija a notacin postfija, el smbolo
significa concatenacin.
Para 9-5+2 se expande el rbol
EXP
EXP
EXP
+
TERM
TERM
EXP.a=95-2+
TERM
EXP.a=95-
EXP.a=9
TERM.a=2
TERM.a=5
TERM.a=9
La notacin postfija tiene una importante ventaja ya que solo hay una forma de codificarla debido a la
posicin y nmero de argumentos. La manera de interpretarla siempre es la misma y es muy sencilla.
Se recorre la cadena de izquierda a derecha hasta encontrar un operador, luego se toman los dos
operandos previos al operador encontrado, se evala el operador con sus operandos y se sustituyen
por el resultado luego se contina. Este proceso se repite hasta terminar con todas las evaluaciones.
Ejemplo:
Sea a=5, m=7 y d=3
dia := (1461*a) div 4 + (153*m + 2) div 5 + d
entonces dia=2043
Ahora la notacin postfija es:
dia 1461 a * 4 div 153 m * 2 + 5 div d + + :=
- 36 -
div
div
div
div
div
d
d
d
d
d
d
217
+
+
+
+
+
+
+
+
+
+
+
+
+
:=
:=
:=
:=
:=
:=
:=
:=
entonces dia=2043
Por ejemplo: ROBOT ( Tarea ).
Procedimiento recursivo para evaluar un rbol con reglas semnticas y atributos.
PROCEDURE VISITA (n:nodo)
inicio
Por cada hijo m del nodo n de izquierda a derecha HACER
VISITA(m)
Evaluar las reglas semnticas para n
fin procedimiento
ESQUEMAS DE TRANSLACION.
Un esquema de translacin es una gramtica de contexto libre en la cual se introducen
fragmentos de cdigo en la parte derecha de las producciones, prcticamente, es lo mismo que una
DDS, slo que el orden de evaluacin de las reglas semnticas es explcito.
La accin a ejecutar, es simplemente un nodo ms en un rbol sintctico. Cuando una DDS es
"simple" el orden de los no terminales de la gramtica conserva su posicin, y solamente se aaden
algunos strings adicionales. Una forma sencilla de construir un esquema de translacin para una
gramtica, es aadir los caracteres agregados de la regla semntica en la DDS. El esquema de
traslacin queda:
EXP
EXP
EXP
TERM
TERM
EXP + TERM
EXP - TERM
TERM
num
id
{ print '+' }
{ print '-' }
{ print num.val }
{ print id.val }
- 37 -
1
2
3
4
5
6
7
PROGRAMA
mete(5)
rvalor(2)
opsum
rvalor(3)
opmul
PILA
16
7
tope
1
2
3
4
DATOS
0
11
7
pc
En este diseo, las operaciones aritmticas se realizan en forma postfija. La pila y la memoria de
datos se manejan con estas instrucciones:
mete(x)
mete x a la pila.
rvalor(x)
lvalor(d(x))
saca
opabs
copia
opsum
opdif
Hace la resta.
opmul
Hace la multiplicacin.
opcoc
Hace la divisin
opdiv
opmod
Hace el mdulo.
opand
opor
opnot
asig
ira(x)
irfalso(x)
irverdad(x)
fin
{
Es decir, si hacemos la diferencia (a-b) dado a=b, nos dar falso si son iguales y verdadero si son
diferentes. Por lo que simplemente basta negar el valor. As la expresin la podemos traducir con
operaciones aritmticas:
- 39 -