Professional Documents
Culture Documents
Compiladores I
Introduccin
Desde el punto de vista de un informtico, prcticamente todas las acciones que se va a ver
obligado a desarrollar en el transcurso de su carrera profesional, tendr que ver con traductores: la
programacin, la creacin de ficheros batch, la utilizacin de un intrprete de comando, etc.
Por ejemplo Que ocurre si nos dan un documento de Word que procede de una fusin con una base de
datos y se quiere, a partir de l, obtener la B.D. original?. Pues se puede:
a) Convertirla a texto.
b) Procesarla con un traductor para quitar el texto superfluo y dar como resultado un texto en el
que cada campo est entre comillas.
c) El texto anterior se importa con cualquier SGBD.
Otro ejemplo
Creacin de preprocesadores para lenguajes que no lo tienen . Por ejemplo para trabajar fcilmente con
SQL en C, se puede hacer un preprocesador para meter SQL inmerso.
Qu es un traductor?
Un traductor es un programa que traduce o convierte desde un texto o programa escrito en un lenguaje
fuente hasta un texto o programa escrito en un lenguaje destino produciendo, si cabe, mensajes de error.
* Los traductores engloban tanto al compilador como al intrprete.
* Esquema inicial para un traductor
Programa Fuente
escrito en Lenguaje
Fuente
TRADUCTORES
Programa Destino
escrito en Lenguaje
Destino
Mensajes de Error
Tipos de Traductores
Traductores del idioma : Traducen de un idioma dado a otro, por ejemplo, un traductor de Ingls a
Espaol..
* Problemas:
Inteligencia Artificial y problemas de las frases hechas: El problema de la inteligencia artificial es que tiene
mucho de artificial y poco de inteligencia. Por ejemplo una vez se tradujo del Ingles al Ruso (por lo de la
guerra fra) : El espritu es fuerte pero la carne es dbil que, de nuevo, se pas al Ingls, y dio: El vino
est bueno pero la carne est podrida ( En ingls spirit significa tanto espritu como alcohol ).
Falta de formalizacin en la especificacin del significado de las palabras.
Cambio del sentido de las palabras segn el contexto. Ej: Por decir aquello, se llev una galleta.
Slo un subconjunto del lenguaje.
Apuntes de Compiladores I
Compiladores : Es aquel traductor que tiene como entrada una sentencia en lenguaje formal y como salida
tiene un fichero ejecutable, es decir, hace una traduccin de alto nivel a cdigo mquina.
Intrpretes : Es como un compilador, solo que la salida es una ejecucin. El programa de entrada se
interpreta y ejecuta a la vez.
* Hay lenguajes que solo pueden ser interpretados.
Ej: SNOBOL (StriNg Oriented SimBOlyc Language),
LISP (LISt Processing)
BASIC (Beginners All ...)
La principal ventaja es que permiten una fcil depuracin. Los inconvenientes son, en primer lugar la lentitud
de ejecucin , ya que si uno ejecuta a la vez que traduce no puede aplicarse mucha optimizacin, adems si
el programa entra en un bucle tiene que interpretar y ejecutar todas las veces que se realice el bucle. Otro
inconveniente es que durante la ejecucin, es necesario el intrprete en memoria por lo que consumen ms
recursos.
Preprocesadores : Permiten modificar el programa fuente antes de la verdadera compilacin. Hacen uso
de macroinstrucciones y directivas.
Ej:
//Uno.c
#include Dos.c
Void main( ) {
xxxx
xxxxxxx
}
PREPROCESADOR
//Dos.c
yyy
yyyy
//Uno.c
yyy
yyyy
void main( ) {
xxxx
xxxxxxx
}
COMPILADOR
El preprocesador sustituye la instruccin #include Uno.c por el cdigo que tiene Uno.c, cuando el
compilador empieza se encuentra con el cdigo ya incluido en el programa fuente.
Ejemplos de algunas directivas de procesador (Clipper, C): #fi, #ifdef, #define, #ifndef, #define, #include ...
que permiten compilar trozos de cdigos opcionales.
Intrpretes de comandos : Lo que hace es traducir sentencias simples a llamadas a programas de una
biblioteca. Son especialmente utilizados por Sistemas Operativos.
Ej: El shell del DOS o del UNIX. Desencadenan la ejecucin de programas que pueden estar residentes en
memoria o encontrarse en disco.
Por ejemplo, si ponemos en MS-DOS el comando copy se ejecuta la funcin copy del
sistema operativo.
Ensambladores y Macroensambladores : Son los pioneros de los compiladores, ya que en los albores de
la informtica, los programas se escriban directamente en cdigo mquina, y los ensambladores establecen
una relacin biunvoca entre cada instruccin y una palabra nemotcnica, de manera que el usuario escribe
los programas haciendo uso de los mnemotcnicos, y el ensamblador se encarga de traducirlo al cdigo
mquina puro.
Preparado por Prof. Julio Surez
Apuntes de Compiladores I
El lenguaje que utiliza se llama lenguaje ensamblador y tiene una correspondencia uno a uno entre sus
instrucciones y el cdigo mquina.
Ej: Cdigo mquina 65h.00h.01h
Ensamblador LD HL, #0100
- Macroensamblador : Hay ensambladores que tienen macroinstrucciones que se suelen traducir a varias
instrucciones mquinas, pues bien, un macroensamblador es un ensamblador con un preprocesador
delante.
Conversores fuente - fuente : Pasan un lenguaje de alto nivel a otro lenguaje de alto nivel, para conseguir
mayor portabilidad.
Por ejemplo en un ordenador slo hay un compilador de PASCAL, y queremos ejecutar un programa escrito
en COBOL; Un conversor COBOL > PASCAL nos solucionara el problema.
Compilador cruzado : Es un compilador que obtiene cdigo para ejecutar en otra mquina. Se utilizan en la
fase de desarrollo de nuevos ordenadores.
Archivo.fue
Archivo.obj
COMPILAR
* El enlazador resuelve las referencias cruzadas, o externas, que pueden estar o en otros OBJ, o en
libreras LIB, y se encarga de generar el ejecutable final.
* Se obtiene un cdigo reubicable, es decir, un cdigo que en su momento se podr ejecutar en diferentes
posiciones de memoria, segn la situacin de la misma en el momento de la ejecucin.
Pasadas de compilacin : Es el nmero de veces que se lee el programa fuente. Hay algunas situaciones
en las que, para realizar la compilacin, no es suficiente con leer el fichero fuente una sola vez. Por ejemplo:
Que ocurre si tenemos una recursin indirecta?
A llama a B
B llama a A
Preparado por Prof. Julio Surez
Apuntes de Compiladores I
Apuntes de Compiladores I
Estructura de un Compilador
Un compilador se divide en dos fases : Una parte que analiza la entrada y genera estructuras intermedias y
otra parte que sintetiza la salida. En base a tales estructuras intermedias
Fuente
ANLISIS
SNTESIS
Destino
Mensajes de Error
Apuntes de Compiladores I
* Fase de optimizacin: La optimizacin puede realizarse durante las fases de generacin de cdigo
intermedio y/o generacin de cdigo mquina y puede ser una fase aislada de stas, o estar integrada con
ellas.
La optimizacin del cdigo intermedio debe ser independiente de la mquina.
El siguiente cuadro muestra un ejemplo de compilacin de una sentencia de asignacin, que incluye una
expresin aritmtica:
Analizador sintctico
id1
=
*
id3
Analizador
Semntico
+
id2
Generador de
Cdigo intermedio
Analizador lxico
60
Generador de Cdigo
Optimizador de Cdigo
MOVF id3, R2
MULF #60.0, R2
MOVF id2, R1
ADDF R2, R1
MOVF R1, id1
En este esquema, se supone que el compilador realiza todas las tareas listadas:
La entrada fuente es la sentencia posicion = inicial + velocidad * 60
El anlisis lxico separa la sentencia en sus componentes lxicos: id: es un terminal, en una gramtica libre
de contexto, que representa a cualquier nombre o identificador de variable de memoria, presente en el
programa fuente. num: es un terminal, de la misma gramtica, que representa a un nmero entero.
La salida del anlisis lxico ser la entrada para el anlisis sintctico.
Con frecuencia, las fases se agrupan en una etapa inicial (Front-End) y una etapa final (Back- End). La
etapa inicial comprende aquellas fases, o partes de fases que dependen principalmente del lenguaje fuente
y que son en gran parte independientes de la mquina objeto. Ah normalmente se introducen los anlisis
lxicos y sintcticos, la creacin de la tabla de smbolos, el anlisis semntico y la generacin de cdigo
intermedio. La etapa inicial tambin puede hacer cierta optimizacin de cdigo e incluye adems, el manejo
de errores correspondiente a cada una de esas fases.
La etapa final incluye aquellas partes del compilador que dependen de la mquina objeto y, en
general, esas partes no dependen del lenguaje fuente, sino slo del lenguaje intermedio. En la etapa final,
se encuentran aspectos de la fase de optimizacin de cdigo adems de la generacin de cdigo, junto con
el manejo de errores necesario y las operaciones con la tabla de smbolos.
Se ha convertido en rutina el toma r la etapa inicial de un compilador y rehacer su etapa final
asociada para producir un compilador para el mismo lenguaje fuente en una mquina distinta. Tambin
resulta tentador compilar varios lenguajes distintos en el mismo lenguaje intermedio y usar una etapa final
Preparado por Prof. Julio Surez
Apuntes de Compiladores I
comn para las distintas etapas iniciales, obtenindose as varios compiladores para una mquina. Veamos
ejemplos:
Apuntes de Compiladores I
Fuente
ANLISIS
SNTESIS
Mensajes de Error
Tabla de
Smbolos
Destino
Ejercicios
Captulo de Introduccin
Compiladores:
Interpretes:
2) Menciona otros tipos de traductores y haz una breve explicacin de cada uno.
Apuntes de Compiladores I
5) Grafica estructuralmente las fases de un proceso de compilacin, incluyendo una breve explicacin
al costado de cada fase.
Front-End 2
Front-End 3
Back-End 1
Back-End 2
Back-End 3
Apuntes de Compiladores I
9) En todos los casos los cdigos objetos se encuentran en lenguaje de mquina. Justifica.
2. Anlisis Lxico
Este captulo estudia la primera fase de un compilador, es decir su anlisis lexicogrfico, o ms
concisamente anlisis lxico. Las tcnicas utilizadas para construir analizadores lxicos tambin se pueden
aplicar a otras reas, como, por ejemplo, a lenguajes de consulta y sistemas de recuperacin de
informacin. En cada aplicacin, el problema de fondo es la especificacin y diseo de programas que
ejecuten las acciones activadas por palabras que siguen ciertos patrones dentro de las cadenas a
reconocer. Como la programacin dirigida por patrones es de mucha utilidad, se introduce un lenguaje de
patrn-accin, llamado LEX, para especificar los analizadores lxicos. En este lenguaje, los patrones se
especifican por medio de expresiones regulares, y un compilador de LEX puede generar un reconocedor de
las expresiones regulares mediante un autmata finito eficiente.
10
Apuntes de Compiladores I
El analizador lxico tiene que dividir la secuencia de caracteres en palabras con significado propio y
despus convertirlo a una secuencia de terminales desde el punto de vista del analizador sintctico, que es
la entrada del analizador sintctico.
El analizador lxico reconoce las palabras en funcin de una gramtica regular de manera que sus
SENTENCIAS se convierten en los elementos de entrada de fases posteriores.
11
Apuntes de Compiladores I
Componente Lxico
Lexemas de ejemplo
const
const
12
Apuntes de Compiladores I
if
if
if palabra reservada
relacin
<,<=,=,<>,>, >=
id
pi, cuenta, D2
num
3.1416, 0 , 6.02E23
literal
vaciado de pila
Los componentes lxicos se tratan como smbolos terminales de la gramtica del lenguaje fuente.
Los lexemas para el componente lxico que concuerdan con el patrn representan cadenas de caracteres
en el programa fuente que se pueden tratar juntos como una unidad lxica.
En la mayora de los lenguajes de programacin, se consideran componentes lxicos las siguientes
construcciones: palabras clave, operadores, identificadores, constantes, cadenas literales y signos de
puntuacin, como parntesis, coma y punto y coma.
Un patrn es una regla que describe el conjunto de lexemas que pueden representar a un
determinado componente lxico en los programas fuente. El patrn para el componente lxico const, de la
tabla anterior, es simplemente la cadena sencilla const. El patrn para el componente lxico relacin es el
conjunto de los seis operadores relacionales de Pascal. Para describir con precisin los patrones para
componentes lxicos ms complejos, como id (para identificador) y num(para nmero), se utilizar la
notacin de expresiones regulares.
13
Apuntes de Compiladores I
Son pocos los errores que se pueden detectar simplemente en el nivel lxico porque un analizador
lxico tiene una visin muy restringida de un programa fuente. Si aparece la cadena fi por primera vez en un
programa C en el contexto
fi ( a == f(x))
un analizador lxico no puede distinguir si fi es un error de escritura de la palabra clave if o si es un
identificador de funcin no declarado. Como fi es un identificador vlido, el analizador lxico debe devolver
el componente lxico de un identificador y dejar que alguna otra fase del compilador se ocupe de los
errores.
Pero, supngase que surge una situacin en la que el analizador lxico no puede continuar porque
ninguno de los patrones concuerda con un prefijo de la entrada restante.
Compilador
prog1. c
de LEX
prog1.c
Archivo de entrada
Compilador de C
prog1.exe
prog1.exe
Especificaciones en LEX
14
Apuntes de Compiladores I
{accin 1}
p2
{accin 2}
pn
{accin n}
donde pi es una expresin regular y cada accin es un fragmento de programa que describe cul ha de ser
la accin del analizador lxico cuando el patrn pi concuerda con un lexema. En LEX, las acciones se
esriben en C, en general, sin embargo, pueden estar en cualquier lenguaje de implantacin.
La tercera seccin contiene todos los procedimientos auxiliares que puedan necesitar las acciones. A veces,
estos procedimientos se pueden compilar por separado y cargar con el analizador lxico.
Un analizador lxico creado por LEX se comporta en sincrona con un analizador sintctico como sigue.
Cuando es activado por el analizador sintctico, el analizador lxico comienza a leer su entrada restante, un
carcter a la vez, hasta que encuentre el mayor prefijo de la entrada que concuerde con una de las
expresiones regulares pi. Entonces, ejecuta accin i. Generalmente, accin i devolver el control al
analizador sintctico. Sin embargo, si no lo hace, el analizador lxico se dispone a encontrar ms lexemas,
hasta que una accin hace que el control regrese al analizador sintctico. La bsqueda repetida de lexemas
hasta encontrar una instruccin return explcita permite al analizador lxico procesar espacios en blanco y
comentarios de manera apropiada.
El analizador lxico devuelve una nica cantidad, el componente lxico, al analizador sintctico. Para pasar
un valor de atributo con la informacin del lexema, se puede asignar una variable global llamada yylval.
15
Apuntes de Compiladores I
Este mecanismo tambin se puede usar para incluir un espacio en blanco dentro de una expresin;
normalmente, segn se explicaba anteriormente, los espacios en blanco y los tabuladores terminan una
orden. Cualquier carcter en blanco que no est contenido entre corchete tiene que ponerse entre comillas.
Se reconocen varios escapes C normales con la barra invertida ( \ ):
\ n newline
\ t tabulador
\ b backspace
\ \ barra invertida
Puesto que el carcter newline es ilegal en una expresin, es necesario usar n; no se requiere dar escape al
carcter tabulador y el backspace. Cada carcter excepto el espacio en blanco, el tabulador y el newline y la
lista anterior es siempre un carcter de texto.
16
Apuntes de Compiladores I
coincide con ab o con cd. Ntese que los parntesis se usan para agrupar, aunque stos no son
necesarios en el nivel exterior. Por ejemplo
ab | cd
hubiese sido suficiente en el ejemplo anterior. Los parntesis se debern usar para expresiones
ms complejas, tales como
( ab | cd+ )?( ef )*
la cual coincide con tales literales como abefef, efefef, cdef, cddd, pero no abc, abcd, o abcdef.
Especificacin de sensitividad de contexto
El lex reconoce una pequea cantidad del contexto que le rodea. Los dos operadores ms simples
para stos son el signo de intercalacin ( ^ ) y el signo de dlar ( $ ). Si el primer carcter de una expresin
es un signo ^, entonces la expresin slo coincide al principio de la lnea (despus de un carcter newline, o
al principio del input). Esto nunca se puede confundir con el otro significado
del signo ^, complementacin de las clases de caracteres, puesto que la complementacin slo se
aplica dentro de corchetes. Si el ltimo carcter es el signo de dlar, la expresin slo coincide al final de
una lnea (cuando va seguido inmediatamente de un carcter newline). Este ltimo operador es un caso
especial del operador barra ( / ) , el cual indica contexto al final.
La expresin
ab/cd
coincide con el literal ab, pero slo si va seguido de cd. Por lo tanto
ab$
es lo mismo que
ab/\n
Especificacin de repeticin de expresiones.
Las llaves ( { y } ) especifican o bien repeticiones ( si stas incluyen nmeros) o definicin de expansin (si
incluyen un nombre). Por ejemplo
{dgito}
busca un literal predefinido llamado dgito y lo inserta en la expresin, en ese punto.
Especificar definiciones.
Las definiciones se dan en la primera parte del input del lex, antes de las rdenes. En contraste,
a{1,5}
busca de una a cinco apariciones del carcter a.
Finalmente, un signo de tanto por ciento inicial ( % ) es especial puesto que es el separador para los
segmentos fuente del lex.
Especificacin de acciones.
Cuando una expresin coincide con un modelo de texto en el input el lex ejecuta la accin
correspondiente. Esta seccin describe algunas caractersticas del lex, las cuales ayudan a escribir
acciones. Ntese que hay una accin por defecto, la cual consiste en copiar el input en el output. Esto se
lleva a cabo en todos los literales que de otro modo no coincidiran. Por lo tanto el usuario del lex que desee
absorber el input completo, sin producir ningn output, debe proporcionar rdenes para hacer que coincida
todo. Cuando se est usando el lex con el yacc, sta es la situacin normal. Se puede tener en cuenta qu
acciones son las que se hacen en vez de copiar el input en el output; por lo tanto, en general, una orden que
simplemente copia se puede omitir.
Una de las cosas ms simples que se pueden hacer es ignorar el input.
Especificar una sentencia nula de C; como una accin produce este resultado.
La orden frecuente es
[ \ t \ n] ;
la cual hace que se ignoren tres caracteres de espaciado (espacio en blanco, tabulador, y newline).
Otra forma fcil de evitar el escribir acciones es usar el carcter de repeticin de accin, | , el cual
indica que la accin de esta orden es la accin para la orden siguiente. El ejemplo previo tambin se poda
haber escrito:
|
\ t |
Preparado por Prof. Julio Surez
17
Apuntes de Compiladores I
\ n ;
con el mismo resultado, aunque en un estilo diferente. Las comillas alrededor de
\ny\t
no son necesarias.
En acciones ms complejas, a menudo se quiere conocer el texto actual que coincida con algunas
expresiones como:
[ a-z ] +
El lex deja este texto en una matriz de caracteres externos llamada yytext. Por lo tanto, para
imprimir el nombre localizado, una orden como [ a-z ] + printf (%s , yytext); imprime el literal de yytext. La
funcin C printf acepta un argumento de formato y datos para imprimir; en este caso , el formato es print
literal donde el signo de tanto por ciento ( % ) indica conversin de datos, y la s indica el tipo de literal, y
los datos son los caracteres de yytext. Por lo tanto esto simplemente coloca el literal que ha
coincidido en el output. Esta accin es tan comn que se puede escribir como ECHO. Por ejemplo
[ a-z ]+ ECHO;
es lo mismo que el ejemplo anterior. Puesto que la accin por defecto es simplemente imprimir los
caracteres que se han encontrado, uno se puede preguntar Porqu especificar una orden, como sta, la
cual simplemente especifica la accin por defecto? Tales rdenes se requieren a menudo para
evitar la coincidencia con algunas otras rdenes que no se desean. Por ejemplo, si hay una orden que
coincide con read, sta normalmente coincidir con las apariciones de read contenidas en bread o en
readjust; para evitar esto, una orden de la forma
[ a-z ] +
es necesaria. Esto se explica ms ampliamente a continuacin.
A veces es ms conveniente conocer el final de lo que se ha encontrado; aqu el lex tambin
proporciona un total del nmero de caracteres que coinciden en la variable yyleng. Para contar el nmero
de palabras y el nmero de caracteres en las palabras del input, ser necesario escribir
[ a-zA-Z ] + {words++ ; chars += yyleng;}
lo cual acumula en las variables chars el nmero de caracteres que hay en las
palabras reconocidas. Al ltimo carcter del literal que ha coincidido se puede
acceder por medio de
yytext[ yyleng - 1]
La accin REJECT quiere decir, ve y ejecuta la siguiente alternativa. Esto hace que se ejecute
cualquiera que fuese la segunda orden despus de la orden en curso. La posicin del puntero de input se
ajusta adecuadamente. Suponga que el usuario quiere realmente contar las apariciones incluidas en she:
she { s++; REJECT;}
he { h++; REJECT;}
\n|
.;
Estas rdenes son una forma de cambiar el ejemplo anterior para hacer justamente eso. Despus
de contar cada expresin, sta se desecha; siempre que sea apropiado, la otra expresin se contar. En
este ejemplo, naturalmente, el usuario podra tener en cuenta que she incluye a he, pero no viceversa, y
omitir la accin REJECT en he; en otros casos, no sera posible decir qu caracteres de
input estaban en ambas clases.
Considere las dos rdenes
18
Apuntes de Compiladores I
a [ bc ] + { ... ; REJECT;}
a [ cd ] + { ... ; REJECT;}
Si el input es ab, slo coincide la primera orden, y en ad slo coincide la segunda. La cadena de
caracteres del input accb, cuatro caracteres coinciden con la primera orden, y despus la segunda orden
con tres caracteres. En contrate con esto, el input accd coincide con la segunda orden en cuatro caracteres
y despus la primera orden con tres.
En general, REJECT es muy til cuando el propsito de lex no es dividir el input, sino detectar todos
los ejemplares de algunos items del input, y las apariciones de estos items pueden solaparse o incluirse uno
dentro de otro.
Suponga que se desea una tabla diagrama del input; normalmente los diagramas se solapan, es
decir, la palabra the se considera que contiene a th y a he.
Asumiendo una matriz bidimensional llamada digram que se va a incrementar, el fuente apropiado
es
%%
[ a-z ] [ a-z ] {digram[yytext[0]] [yytext[1]] ++;
REJECT; }
.;
\n;
donde el REJECT es necesario para tomar un par de letras que comienzan en cada carcter, en vez de en
un carcter si y otro no.
Recuerde que REJECT no vuelve a explorar el input. En vez de esto recuerda los resultados de la
exploracin anterior. Esto quiere decir que si se encuentra una orden con un contexto, y se ejecuta
REJECT, no debera haber usado unput para cambiar los caracteres que vienen del input. Esta es la nica
restriccin de la habilidad de manipular el input que an no ha sido manipulado.
%{
/*PROG1.L: Cuenta cantidad de letras y nmeros encontrados*/
#include <stdio.h>
int contal,contad;
%}
%%
[a-zA-Z] {contal++;}
[0-9] {contad++;}
.
;
%%
main()
{
yylex();
printf ("Cantidad de letras :%d", contal);
printf ("Cantidad de digitos :%d", contad);
}
%{
/*Prog2.l: imprime OK cada vez que encuentre la palabra automata*/
#include <stdio.h>
int conta;
%}
%%
"automata " {printf ("OK\n"); conta++;}
.
;
%%
Preparado por Prof. Julio Surez
19
Apuntes de Compiladores I
main()
{
yylex();
printf ("\nCantidad de apariciones de la palaba automata :%d", conta);
}
%{
/* PROG 3.l*/
/*imprime Cantidad de lineas que terminan con a o con o*/
#include <stdio.h>
int conta;
%}
%%
(a|o)$ {conta++;}
.
;
%%
main()
{
yylex();
printf ("\nCantidad de lineas que terminan con a or o :%d", conta);
}
%{
/* PROG 4.l */
/*imprime Cantidad de cadenas que tienen de 2 a 3 "a" */
/* seguidas,como mximo*/
#include <stdio.h>
int conta=0;
%}
%%
^(a{2,3})" "|" "(a{2,3})" " {printf("Encontrado \n");conta++;}
.
;
%%
main()
{
yylex();
printf ("\nCantidad de subcadenas con 2 o 3 a :%d", conta);
}
%{
/* PROG5.L: imprime Cantidad de palabras con letras minsculas y nmeros enteros*/
#include <stdio.h>
int conta, contan;
%}
%%
[a-z]+ {conta++;}
[0-9]+
{contan++;}
.
;
%%
main()
Preparado por Prof. Julio Surez
20
Apuntes de Compiladores I
{
yylex();
printf ("\nCantidad de cadenas :%d", conta);
printf ("\nCantidad de nmeros :%d", contan);
}
%{
/* PROG6.L: Reconoce tres palabras reservadas, identificadores y numeros enteros y reales*/
/* En cada caso imprime la cadena encontrada*/
/* Indentificadores : empieza con a, continua con _ y luego cualquier letra y/o digito*/
/* pudiendo esta ltima seccin, ser vacia*/
#include <stdio.h>
%}
%%
if" "
{printf("Reservada: %s\n", yytext);}
else" "
{printf("Reservada: %s\n", yytext);}
endif" "
{printf("Reservada: %s\n", yytext);}
(w|W)(h|H)(i|I)(l|L)(e|E) {printf("Reservada: %s\n", yytext);}
(e|E)(n|N)(d|D)(w|W)(h|H)(i|I)(l|L)(e|E) {printf("Reservada: %s\n", yytext);}
([0-9]+)
{printf("Entero : %s\n", yytext);}
([0-9]+\.[0-9]+)
{printf("Real : %s\n",yytext);}
a_[a-zA-Z0-9]*
{printf("Identificador:%s\n", yytext);}
\n |
.
{;}
%%
main()
{
yylex();
}
%{
/* PROG7.L*/
/* Preparado por : Prof. Julio Surez ao 2003 */
/* Reconoce tres palabras reservadas, identificadores y numeros enteros y reales*/
/* En cada caso imprime la cadena encontrada*/
/* A ms de la cadena, imprimir la lnea en la que se encuentra*/
/*Caracteristicas Similares al PROG6*/
#include <stdio.h>
int conta=1;
%}
%%
if" "
{printf("Reservada: %s en linea %d\n", yytext,conta);}
else" " {printf("Reservada: %s en linea %d\n", yytext,conta);}
endif" " {printf("Reservada: %s en linea %d\n", yytext,conta);}
([0-9]+) {printf("Entero : %s en linea %d\n", yytext,conta);}
([0-9]+\.[0-9]+) {printf("Real : %s en linea %d\n",yytext,conta);}
a_[a-zA-Z0-9]* {printf("Identificador:%s en linea %d\n",yytext,conta);}
\n
{conta++;}
.
{;}
%%
main()
{
yylex(); }
Ejercitario
Trabaja individualmente y luego en grupo, para completar lo siguiente :
Preparado por Prof. Julio Surez
21
Apuntes de Compiladores I
3) Por qu se afirma que el analizador lxico, es una subrutina del analizador sintctico?
4) Con respecto al item anterior, grafica un esquema que represente este trabajo coordinado entre las
dos fases mencionadas.
5) Explica tres razones por los cuales es conveniente construir un analizador lxico, para el
compilador.
6) Explica que diferencia existe entre los conceptos de lexemas y componentes lxicos o tokens
22
Apuntes de Compiladores I
8) Escribe un ejemplo de lexemas, patrones y componentes lxicos, para los siguientes casos:
identificadores, nmeros enteros, una palabra reservada, un operador matemtico.
9) Escribe y explica dos ejemplos de errores lxicos que puede tener un programa fuente.
c.
Un scanner que lea archivos de textos con numeros binarios de longitud 8. y convierta, al
sistema numrico decimal y hexadecimal. Los nmeros binarios deben estar separados por
un espacio delante y detrs, con excepcin de los inician una lnea o los que terminan la
lnea.
d. Un scanner que lea archivos de textos y corrija errores ortograficos como : n antes de b, v
despues de m, uso de h intermedia en 5 palabras, 5 palabras que empiecen con h y que en
23
Apuntes de Compiladores I
el texto no se haya escrito correctamente, puntuacin de coma o punto y coma que debe
escribirse a continuacin de la letra de la palabra anterior, sin espacio intermedio.
12) Escribe un programa lex que busque las palabras reservadas mientras, para, y numeros reales
que pueden no tener ningn digito como parte entero, pero si al menos un cero en la parte decimal,
utilizando la coma como separador entre ambos. Si se detecta una cadena que no corresponda a
ninguno de estos tokens, imprimir un mensaje de error, y continuar el anlisis.
13) Con el uso de LEX escribe programas que generen los autmatas finitos para las siguientes
expresiones regulares :
13.1
13.2
( a+ ( b* | 2) + | b)
(a|b) (5* 4+ | abc) (d |e )
14) Con el uso de LEX escribe programas que generen los autmatas finitos para los lenguajes de las
siguientes gramticas regulares :
G( Z )
ZZ0 | Z1| P0
PP0| T1| 0
T Z1|P1| T1| 0 | 1
VT= { 0, 1}
G( P )
Pb | a | Pa| Fb
FFb | Eb | Ea | b
EEb | a | Fa| Fb
VT={a, b}
3. Anlisis
sintctico
3.1 Introduccin
El anlisis sintctico (parser en ingls) recibe la cadena de tokens, que le enva el analizador lxico
y comprueba si con ellos se puede formar alguna sentencia vlida generada por la gramtica del lenguaje
fuente.
La sintaxis de los lenguajes de programacin habitualmente se describe mediante gramticas libres
de contexto.
3.2 Funciones del analizador sintctico
Comprobar si la cadena de tokens proporcionada por el analizador lxico puede se generada por la
gramtica que define el lenguaje fuente ( GLC)
Construir el rbol de anlisis sintctico que define la estructura jerrquica de un programa y obtener
la serie de derivaciones para generar la cadena de tokens. El rbol sintctico, puede ser utilizado
como representacin intermedia en la generacin de cdigo.
Informar de los errores sintcticos de forma precisa y significativa. Deber contener un mecanismo
de recuperacin de errores para continuar con el anlisis.
24
Apuntes de Compiladores I
token
programa
fuente
Analizador
Lxico
Obtener
siguiente
componente
lxico
Analizador
Sintctico
rbol de
anlisis
sintctico
Resto del
Front-End
Representacin
intermedia
Gestor de
errores
Tabla de
Smbolos
Se debe recuperar de cada error con la suficiente rapidez como para detectar errores posteriores.
25
Apuntes de Compiladores I
Recuperacin a nivel de frase: Intenta recuperar el error una vez descubierto. En el caso anterior, por
ejemplo, podra haber sido lo suficientemente inteligente como para insertar el token ; . Hay que tener
cuidado con este mtodo, pues puede dar lugar a recuperaciones infinitas.
Reglas de produccin adicionales para el control de errores: La gramtica se puede aumentar con las
reglas que reconocen los errores ms comunes. En el caso anterior, se podra haber puesto algo como:
26
Apuntes de Compiladores I
Ascendentes: Parten de la sentencia de entrada, y van aplicando reglas de produccin hacia atrs (desde
el consecuente hasta el antecedente), hasta llegar al axioma inicial.
Pueden ser:
_ Con retroceso.
_ LR(1)
27
Apuntes de Compiladores I
El primer problema que se presenta con el anlisis sintctico descendente, es que a partir del nodo
raz el analizador sintctico no elija las producciones adecuadas para alcanzar la sentencia a reconocer.
Cuando el analizador se da cuenta de que se ha equivocado de produccin, se tienen que deshacer las
producciones aplicadas hasta encontrar otras producciones alternativas, volviendo a tener que reconstruir
parte del rbol sintctico. A este fenmeno se le denomina retroceso, vuelta a atrs o en ingls
backtracking.
El proceso de retroceso puede afectar a otros mdulos del compilador tales como la tabla de
smbolos , cdigo generado, interpretacin, etc. teniendo que deshacerse tambin los procesos
desarrollados en estos mdulos.
Ejemplo de retroceso : Sea la gramtica G(<PROGRAMA>)
28
Apuntes de Compiladores I
Se observa que el siguiente terminal generado, tampoco coincide con el token de la cadena de
entrada. Entonces el analizador sintctico debe volver atrs, hasta encontrar la ltima derivacin de un no
terminal, y comprobar si tiene alguna alternativa ms. En caso afirmativo se debe de elegir la siguiente y
probar. En caso negativo, volver ms atrs para probar con el no terminal anterior. Este fenmeno de vuelta
atrs es el que se ha definido anteriormente como retroceso.
Llegamos a este punto, tambin se debe de retroceder en la cadena de entrada hasta la primera d,
ya que en el proceso de vuelta atrs lo nico valido que nos ha quedado del rbol ha sido el primer token
module. Si se deriva <DECLARACIONES> nuevamente con la primera alternativa, se tiene
29
Apuntes de Compiladores I
El siguiente token de la cadena es ; mientras que en el rbol se tiene end, por lo tanto habr de
volver atrs hasta el anterior no terminal, y mirar si tiene alguna otra alternativa.
El ltimo no terminal derivado es <PROCEDIMIENTOS>, si se deriva con su otra alternativa se tiene
el rbol mostrado a continuacin. Con esta derivacin se ha reconocido la parte de la cadena de entrada
module d ; d; p;
El rbol sintctico ya acepta el siguiente token de la cadena (end) y por tanto la cadena completa.
Puede concluirse, que los tiempos de reconocimiento de sentencias de un lenguaje pueden
dispararse a causa del retroceso, por lo tanto los analizadores sintcticos deben eliminar las causa que
producen el retroceso.
30
Apuntes de Compiladores I
4.3.1
Gramticas LL(1)
Las gramticas LL(1) son un subconjunto de las gramticas libres de contexto. Permiten un anlisis
descendente determinista ( sin retroceso ).
Las gramticas LL(1), como ya se mencion, permiten construir un analizador determinista
descendente con tan solo examinar en cada momento el smbolo actual de la cadena de entrada ( smbolo
de preanlisis) para saber que produccin aplicar.
Una gramtica LL(1) debe cumplir con las siguientes condiciones :
Debe ser una gramtica limpia ( como toda gramtica formal )
No debe ser ambigua
No debe tener recursividades por izquierda, en sus reglas
Por lo tanto, previo a la construccin de un analizador sintctico LL(1), deber tratarse la gramtica
libre de contexto de manera que cumpla con las condiciones sealadas.
4.3.2
Gramticas limpias
Las gramticas de los lenguajes de programacin estn formadas por un conjunto de reglas, cuyo
nmero suele ser bastante amplio, lo cual incide en la ocultacin de distintos problemas que pueden
producirse, tales como tener reglas que produzcan smbolos que se usen despus, o que nunca se llegue a
cadenas de terminales. Todo esto se puede solucionar transformando la gramtica inicial sucia a una
gramtica limpia.
Definiciones
Smbolo muerto : es un Smbolo no terminal que no genera sentencia.
Gramtica sucia: es toda gramtica que contiene smbolos muertos y/o inaccesibles.
Gramtica limpia: es toda gramtica que no contiene smbolos muertos y/o inaccesibles.
Smbolo vivo: es un smbolo no terminal del cual se puede derivar una sentencia. Todos los
terminales son smbolos vivos. Es decir son smbolos vivos los que no son muertos
Smbolo accesible: es un smbolo que aparece en una cadena derivada el smbolo inicial. Es decir,
aquel smbolo que no es inaccesible.
31
Apuntes de Compiladores I
Limpieza de Gramticas
Como prctica constante, deber procederse a la limpieza de las gramticas, luego que las
mismas hayan sido diseadas. Para el efecto, existen algoritmos para la depuracin.
El mtodo consiste en detectar y eliminar, en primer lugar, a los smbolos muertos de la gramtica.
Posteriormente, se proceder a detectar y eliminar los smbolos inaccesibles.
Es importe respetar el orden en que se citaron los tipos de smbolos a eliminar, debido a que la
eliminacin de smbolos muertos, puede generar smbolos inaccesibles en la gramtica.
32
Apuntes de Compiladores I
<INICIAL> : := a <NOTER1><NOTER2><NOTER3>
<NOTER1> : := b <NOTER2> <NOTER3>
<NOTER2> : := e | d e
<NOTER3> : := g <NOTER2> | h
Ejemplo
Sea la gramtica en la BNF , G(<INICIAL>)
33
Apuntes de Compiladores I
4.3.3
Recursividad
Las reglas de produccin de una gramtica estn definidas de forma que al realizar derivaciones
dan lugar a recursividades. Entonces se dice que una regla de derivacin es recursiva si es de la forma:
A A a
Los analizadores LL(1), deben evitar las gramticas con recursividad por izquierda, debido a que
ests pueden producir ciclos infinitos en las derivaciones por izquierda.
Cabe aqu repasar el algoritmo para eliminar dichas recursividades.
Algoritmos para eliminacin de recursividades:
A lo largo del curso de Lenguajes y autmatas, hemos aprendido dos mtodos distintos con
idnticos efectos.
En el primero que repasaremos, se presenta la generacin de cadenas vacas como consecuentes
de no terminales de la gramtica.
En el segundo mtodo, los consecuentes equivalentes generan nuevos casos de factores comunes,
que debern ser nuevamente factorizados (sobre la factorizacin veremos ms adelante).
Mtodo 1:
Por cada caso de recursividad de la forma :
A A a1 | A a2 | .| Aan | 1 | 2 | | m
Donde A pertenece a VN, ai y j pertenecen a (VT U VN)* con la aclaracin que j no empieza con A.
Se reemplazan estas reglas por las siguientes, con C es un nuevo no terminal en la gramtica :
A 1 C | 2 C | | m C
C a1 C | a2 C | .| an C | e
34
Apuntes de Compiladores I
Mtodo 2 :
Por cada caso de recursividad de la forma :
A A a1 | A a2 | .| Aan | 1 | 2 | | m
Donde A pertenece a VN, ai y j pertenecen a (VT U VN)* con la aclaracin que j no empieza con A.
Se reemplazan estas reglas por las siguientes, con C es un nuevo no terminal en la gramtica :
A 1 | 2 | | m | 1 C | 2 C | | m C
C a1 | a2 | .| an | a1 C | a2 C | .| an C
Ejemplo
Dada la gramtica G( S ) donde VT = {(,), a, ,} y
P:{
S ( L ) | a
L L , S | S
}
La recursividad se presenta en L, entonces habr que eliminarlo, antes de construir el analizador LL(1)
Por el mtodo 1:
L L , S | S
LSA
A,SA| e
Entonces las reglas de la gramtica equivalente, sin recursividad por izquierda quedn:
S ( L ) | a
LSA
A,SA| e
Por el mtodo 2:
L L , S | S
L S | S B
B , S | , S B
Entonces las reglas de la gramtica equivalente, sin recursividad por izquierda quedn:
S ( L ) | a
L S | S B
B , S | , S B
35
Apuntes de Compiladores I
4.3.4
Gramticas Ambiguas
Una sentencia generada por una gramtica es ambigua si existe ms de un rbol sintctico para
ella. Una gramtica es ambigua si genera al menos una sentencia ambigua, en caso contrario es no
ambigua. Hay muchas gramticas equivalentes que pueden generar el mismo lenguaje, algunas son
ambiguas y otras no. Sin embargo existen ciertos lenguajes para los cuales no pueden encontrarse
gramticas no ambiguas. A tales lenguajes se les denomina ambiguos intrnsecos.
La ambigedad de una gramtica es una propiedad indecidible, lo que significa que no existe ningn
algoritmo que acepte una gramtica y determine con certeza y en un tiempo finito si la gramtica es
ambigua o no.
Ejemplo de gramtica ambigua :
G (<EXP>)
36
Apuntes de Compiladores I
La asociatividad se define de forma diferente para el operador de potenciacin que para el resto de los
operadores. El operador ^ es asociativo de derecha a izquierda
Mientras que el resto de los operadores binarios, son asociativos de izquierda a derecha, si hay casos de
igual precedencia.
Estas dos propiedades, precedencia y asociatividad, son suficientes para convertir la gramtica
ambigua basada en operadores en no ambigua, es decir, que cada sentencia tenga slo un rbol sintctico.
Para introducir las propiedades anteriores de las operaciones en la gramtica se tiene que escribir
otra gramtica equivalente en la cual se introduce un smbolo no terminal por cada nivel de precedencia.
Ejemplo
Sea la gramtica G(<EXP>
Con las reglas :
Nivel 1 de precedencia:
Introducimos el no terminal <A>, para describir una expresin indivisible, con la mxima precedencia,
entonces las reglas quedan:
<A> ::= ( <EXP>) | identificador | constante
Nivel 2 de precedencia:
Se introduce un nuevo no terminal, <B>, que describe el operador unario de negacin y el no terminal del
nivel anterior
<B> : : = - <B> | <A>
Nivel 3 de precedencia:
Agregamos el no terminal <C>, para representar al operador de potenciacin, considerando su
asociatividad; y el no terminal del nivel anterior.
<C> : : = <B> ^ <C> | <B>
Preparado por Prof. Julio Surez
37
Apuntes de Compiladores I
Como el operador ^ es binario, la regla de potenciacin debe incluir dos operadores. Esta consideracin se
tendr igualmente con los operadores binarios siguientes.
Nivel 4 de precedencia:
Para este nivel, introducimos el no terminal <D>, y representamos las operaciones de producto y divisin; y
como en los casos anteriores, el no terminal del nivel inmediato superior.
<D> : : = <D> * <C> | <D> / <C> | <C>
Como puede verse, el nuevo no terminal aparece a la izquierda de los operadores, por la asociatividad de
izquierda a derecha de los mismos.
Nivel 5 de precedencia:
Para el ltimo nivel de precedencia, se procede a utilizar el mismo no terminal de la gramtica original,
utilizada para representar las operaciones de este nivel.
<EXP> ::= <EXP> + <D> | <EXP> - <D> | <D>
4.3.5 Factorizacin
Hay veces en las que una gramtica no es recursiva por izquierda y sin embargo no es LL(1)
Veamos un caso:
<SENT> ::= if <COND> then <SENT> else <SENT> | if <COND> then <SENT>
Segn estas producciones de <SENT>, no podemos optar por una alternativa con slo el primer token ledo if. Esta
situacin se puede resolver usando la segunda tcnica de transformacin de gramticas: la factorizacin.
En una forma general, las reglas con factor comn tienen la forma:
<A>::= a | a d
donde a , , d ? ( VT U VN )+
La transformacin de las reglas, implicar la insercin en la gramtica, de un nuevo no terminal por cada
caso de factor comn existente en la misma:
<A> ::= a <C>
<C>::= | d
38
Apuntes de Compiladores I
Ejemplo del if
<SENT> ::= if <COND> then <SENT> else <SENT> | if <COND> then <SENT>
Transformado a:
<SENT> ::= if <COND> then <SENT> <NUEVO>
<NUEVO> ::= else <SENT> | e
Entrada
X
Y
Pila
SALIDA
Z
$
Tabla de anlisis sintctico
El analizador descendente LL(1) utiliza una pila auxiliar para almacenar los smbolos de la
gramtica libre de contexto, en base al cual se construy el analizador sintctico.
La tabla de anlisis sintctico, contiene las configuraciones de las reglas que predictivamente
debern ser utilizadas en cada paso de derivacin por izquierda.
La salida del anlisis sintctico, es la secuencia de reglas utilizadas en la derivacin descendente (
o por izquierda).
39
Apuntes de Compiladores I
La cadena a reconocer
Sea X el elemento en la cima de la pila y a el terminal apuntado en la entrada. El algoritmo consiste en:
40
Apuntes de Compiladores I
Ejemplo:
PRIMERO(A) = {d, a, c}
PRIMERO(S)=PRIMERO(A) = {d, a, c}
PRIMERO(B)=PRIMERO(A) U {b} = {d, a, c, b}
41
Apuntes de Compiladores I
Ejemplo: G( S )
42
Apuntes de Compiladores I
Ejercicios
1) Dada la gramtica G(S)
S ( L ) | a
L L , S | S
Grfica rboles sintcticos, ascendentes y descendentes, para las siguientes sentencias :
i)
(a,a)
ii)
(a,(a,a))
iii)
(a,((a,a),(a,a)))
2) Eliminar recursividad por izquierda de la gramtica G(S) del ejercicio anterior
43
Apuntes de Compiladores I
M a b B
Ce
B P
P b C
Ce
Be
C dP
Ce
d) Qu condiciones deben cumplirse, para que una gramtica pueda ser utilizada en la construccin de
un analizador sintctico LL(1)?
44
Apuntes de Compiladores I
f)
En que consiste la recursividad por izquierda, en una gramtica? Cmo afecta a un anlisis
predictivo?
45
Apuntes de Compiladores I
5.1 Introduccin
Se denominan analizadores sintcticos ascendentes (botton-up en ingls) porque procuran construir
el rbol de anlisis sintctico de una sentencia, a partir de esta, es decir desde las hojas del rbol hasta la
raz; o smbolo inicial de la gramtica.
Este proceso requiere la ejecucin de la operacin de reduccin secuencial. Recordemos que una
reduccin implica sustituir en la pila de anlisis, un pivote o parte derecha de una regla de produccin, por
su antecedente o parte izquierda
Reducir : es la inversa de la derivacin. Sustituir el consecuente de una produccin por su
antecedente.
Desplazar : se refiere a la accin de cargar elementos de la entrada que se analiza, a la Pila auxiliar
del analizador.
Pivote o Mango : de una cadena, es una subcadena que concuerda con el lado derecho de una
produccin, y cuya reduccin al no-terminal del lado izquierdo de la produccin, representa un paso a lo
largo de la inversa de una derivacin por la derecha.
Implantacin por medio de una Pila del Anlisis Ascendente por Desplazamiento - Reduccin
Funcionamiento: se desplazan cero o ms smbolos de la entrada a la pila hasta que un pivote est en
su cima. Entonces el analizador reduce por el lado izquierdo de la produccin adecuada. El analizador
repite este ciclo hasta que detecta un error o hasta que la Pila contiene el smbolo inicial de la gramtica y la
entrada est vaca.
Ejemplo:
G(E), donde P: E--> E + E | E*E | ( E ) | id
Anlisis para la sentencia id + id * id
PILA
$
ENTRADA
id + id * id $
ACCION
Desplazar
$id
+ id * id $
Reducir E-->id
$E
+ id * id $
Desplazar
id * id $
Desplazar
$E+
$E+id
* id $
Reducir E-->id
$E+E
* id $
Desplazar
id $
Desplazar
$E+E*
$E+E*id
Reducir E-->id
$E+E*E
Reducir E-->E * E
$E+E
Reducir E-->E + E
$E
Aceptar
46
Si se reduce aqu, la
traduccin que
podra acompaar al
anlisis, dara
resultado errneo
Apuntes de Compiladores I
Se pueden construir analizadores LR para reconocer prcticamente todas las construcciones de los
lenguajes de programacin para los que se pueden escribir GLC.
Los analizadores que utilizan la tcnica LR pueden analizar un nmero mayor de gramticas que los
analizadores descendentes.
Un analizador sintctico LR puede detectar un error sintctico tan pronto como sea posible hacerlo
en un examen de izquierda a derecha de la entrada
5.5 Desventajas
La principal desventaja del mtodo es el volumen de trabajo que supone construir un analizador
sintctico LR, a mano.
47
Apuntes de Compiladores I
Entrada
a1
...
ai
...
an
Sm
SALIDA
Xm
Pila
Sm-1
Xm-1
...
S0
Accin
Ir_a (Transicin)
Tabla de Anlisis
LR
El programa lee caracteres de un buffer de entrada de uno en uno. Utiliza una pila para almacenar una
cadena de la forma S0X1S1X2S2...XmSm, donde Sm est en la cima. Cada Xi es un smbolo gramatical y
cada Si es un estado del autmata.
48
Apuntes de Compiladores I
49
Apuntes de Compiladores I
Anlisis de la sentencia id * id + id $
PILA
0
ENTRADA
id * id + id $
ACCION
Desplazar
0id5
* id + id $
0F3
* id + id $
0T2
* id + id $
Desplazar
id + id $
Desplazar
0T2*7
0T2*7id5
+ id $
reducir F-->id
0T2*7F10
+ id $
reducir T-->T*F
0T2
+ id $
reducir E-->T
0E1
+ id $
Desplazar
id $
Desplazar
0E+6
0E+6id5
reducir F-->id
50
Apuntes de Compiladores I
0E+6F3
0E+6T9
$
$
reducir T-->F
reducir E-->E+T
0E1
Aceptar
S aA
ITEM : S a . A
GRAMATICA AUMENTADA
Si G es una GLC con axioma S , la gramtica aumentada G para G, se construye aadiendo S ->
S , siendo el nuevo axioma S
Sea la gramtica G(S):
S->E$
E-> E+T | E T | T
T-> (E ) | a
Funcin CLAUSURA o CIERRE
Sobre un conjunto I de items, se define la funcin cierre(I) como el conjunto de items resultante de
aplicar las siguientes reglas :
Regla 1: todos los items pertenecientes a I pertenecen a cierre (I)
Regla 2: Si [A-> . B] es un item que pertenece a cierre(I) y existe una regla de la forma B->, entonces
el item [B->.] pertenece a cierre(I)
Regla 3: Repetir la regla anterior hasta que no se aada ningn nuevo item al conjunto cierre(I)
Ejemplo si I={ S->.E$}
Cierre( I )={ S->.E$, E->.E+T, E->.E-T, E->.T , T-> .( E ), T-> .a}
Funcin GOTO o de Transicin
Se define la funcin de transicin , que se aplica a un conjunto de tems y a un smbolo
(terminal o no terminal) de la gramtica, y da como resultado un nuevo conjunto de tems.
, pertenece(VN U VT)*
(I,X) es igual al cierre del conjunto de todos los items de la forma [A-> X.], tales que
Preparado por Prof. Julio Surez
51
Apuntes de Compiladores I
[A-> .X] a I
Ejemplo:
Sea I={ S->.E$, E->.E+T, E->.E-T, E->.T , T-> .( E ), T-> .a}
Si X = E
(I,E) = cierre(S->E.$, E->E.+T, E->E.-T)={ S->E.$, E->E.+T, E->E.-T }
Si X= a
(I,a)= cierre(T->a.)={T->a.}
I0 = {[S -> E$],[E -> E+T],[E -> E-T],[E -> T], [T -> (E)],[T -> a]}
I1 = {[S -> E$],[E -> E+T],[E -> E-T]}
I2 = {[E -> T]}
I3 = {[T -> a]}
I4 = {[T -> (E)],[E -> E+T],[E -> E-T],[E -> T],[T -> (E)],[T -> a]}
I5 = {[S -> E$]}
I6 = {[E -> E+T],[T -> (E)],[T -> a]}
52
Apuntes de Compiladores I
53
Apuntes de Compiladores I
Como prctica construimos en clase, la tabla de anlisis SLR, segn la coleccin anterior
54
Apuntes de Compiladores I
55
Apuntes de Compiladores I
56
Apuntes de Compiladores I
57
Apuntes de Compiladores I
58
Apuntes de Compiladores I
c
D36
D36
D36
R3
R2
ACCION
d
$
D47
aceptar
D47
D47
R3
R3
R1
R2
R2
S
1
IR-A
C
2
5
89
59
Apuntes de Compiladores I
Ejercicios
1) CONTESTA EL SIGUIENTE CUESTIONARIO
a) Qu representa un item LR(1), en la construccin de tablas para el anlisis SLR? Escribe un ejemplo.
d) Por los mtodos estudiados, cuntos estados finales puede tener una analizador sintctico LR?
e) Cmo se determina el estado final para el autmata del analizador sintctico LR?
f)
60
Apuntes de Compiladores I
SA
AB%A|BC
B D|D*B
Dx|(C)
C +x | -x
VT= { %, *, x, (, ), +, - }
Obtener la tabla de anlisis LALR
3) Construye la Coleccin de conjuntos de items LR(1) y la tabla de anlisis LR-Cannica, para la siguiente
gramtica:
(1) Z RdT
VN= {Z, R TB}
(2) R dRd
VT= {d,H,b}
(3) R h
(4) T b
4) Escribe programas en Yacc/Lex para reconocer conjuntos de sentencias del lenguaje, separadas por un
retorno de carro. Correspondiente a la gramtica del item anterior.
Imprimir al final del reconocimiento de un texto con sentencias, la cantidad de sentencias vlidas analizadas.
Incluir el programa en LEX, que genere el analizador lxico correspondiente.
5) Considere la gramtica :
i)
ii)
iii)
S (L) |a
L L,S | S
6) Considere la siguiente gramtica escrita en formato estilo YACC (ignore las acciones por el momento):
decl
: lista_id ':' tipo_id
{ printf("DECL\n"); }
tipo_id : ID
{ printf("TIPO: %s\n", yytext); }
lista_id : id
{ printf("UNO\n"); }
| id ' , ' lista_id
{ printf { ("LISTA\n"; }
id
: ID
{ printf("VAR: %s\n", yytext); }
i)
ii)
ii)
61