Documentos de Académico
Documentos de Profesional
Documentos de Cultura
introduccion
ESQUEMA DE UN COMPILADOR.
Generalidades.
Traductor: Es una mquina terica que tiene como entrada un
texto escrito en un lenguaje L1 y como salida un texto escrito en un
lenguaje L2. Habitualmente se denomina a L1 lenguaje fuente y a L2
lenguaje objeto.
Las tcnicas que se desarrollan en esta asignatura no slo son
vlidas para la implementacin de compiladores, sino que son
aplicables en general a todos los sistemas de procesamiento de
lenguajes y de traduccin. Estos sistemas pueden ser de distintos
tipos:
Traductores de lenguaje natural: Seran los que tradujeran un
lenguaje natural en otro (por ejemplo, espaol a ingls). Esto en la
actualidad no se ha conseguido debido fundamentalmente a la
ambigedad del lenguaje natural. Los mayores logros en la materia
siempre trabajan con un subconjunto del lenguaje natural, limitando
las construcciones sintcticas vlidas y/o el vocabulario. Este tema
se aborda generalmente mediante tcnicas de inteligencia
artificial.
Compilador: Es un traductor que convierte un texto escrito en un
lenguaje fuente de alto nivel en un programa objeto en cdigo
mquina.
Leng. Y Aut.
Leng. Y Aut.
Leng. Y Aut.
mquinas (IBM 370, Serie 1, PDP 11, ...) que disponen del antiguo
compilador, o que al menos tienen otro compilador Pascal. La mejor
opcin consiste en escribir el nuevo compilador en Pascal, ya que as
podr (el compilador) ser compilado en las distintas mquinas por
los compiladores Pascal ya existentes.
Metacompilador: Es un traductor que tiene como entrada la
definicin de un lenguaje y como salida el compilador para dicho
lenguaje.
Decompilador: Es el que traduce cdigo mquina a lenguaje de alto
nivel. Los decompiladores ms usuales son los desensambladores,
que traducen un programa en lenguaje mquina a otro en
ensamblador.
Bootstrapping.
Es una tcnica muy usada actualmente para el desarrollo de
compiladores de lenguajes de alto nivel, en especial si se quiere
obtener un autocompilador, o sea, un compilador que se compile a s
mismo.
Para describir el proceso de autocompilacin se emplea la notacin
en T que representa grficamente los tres lenguajes implicados en
el proceso de compilacin:
Leng. Y Aut.
Leng. Y Aut.
Leng. Y Aut.
Leng. Y Aut.
Esquema de un compilador.
Las funciones de estos mdulos son las siguientes:
Analizador lexicogrfico: Las principales funciones que realiza son:
Leng. Y Aut.
<id2> <+>
<id3> <*>
|
<real>
Leng. Y Aut.
Leng. Y Aut.
11
Leng. Y Aut.
12
Leng. Y Aut.
13
Leng. Y Aut.
Leng. Y Aut.
15
Leng. Y Aut.
Leng. Y Aut.
17
Leng. Y Aut.
Leng. Y Aut.
Leng. Y Aut.
Leng. Y Aut.
lex source
cc lex.yy.c ll
El programa resultante se pone en el fichero usual a.out para ser
ejecutado posteriormente. Para usar el lex con el yacc ver la
seccin lex y
Yacc de este captulo y en el capitulo 9, Yacc: el CompiladorCompilador,
Aunque las rutinas I/O por defecto del lex usan la librera
estndar C, el
autmata del lex no lo hace. Si se especifican las versiones privadas
de input,
output, y unput, la librera se puede evitar.
8.5. Especificacin de clases de caracteres.
Las clases de caracteres se pueden especificar usando corchetes:
[y]. La
construccin
[ abc ]
coincide con cualquier carcter, que pueda se una a, b, o c. Dentro
de los
corchetes, la mayora de los significados de los operadores se
ignoran. Slo tres
caracteres son especiales: stos son la barra invertida ( \ ), el
guin ( - ), y el
signo de intercalacin ( ^ ). El carcter guin indica rangos, por
ejemplo
[ a-z0-9<>_ ]
Gua del Programador del XENIX.
6
indica la clase de carcter que contiene todos los caracteres en
minsculas, los
dgitos, los ngulos y el subrayado. Los rangos se pueden
especificar en
21
Leng. Y Aut.
Leng. Y Aut.
Leng. Y Aut.
24
Leng. Y Aut.
Leng. Y Aut.
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.
LEX: El Analizador Lxico
9
8.13. 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.
26
Leng. Y Aut.
27
Leng. Y Aut.
Leng. Y Aut.
29
Leng. Y Aut.
Leng. Y Aut.
yyless (yyleng 1 );
... accin para =- ...
}
lo cual imprime un mensaje, devuelve las letras despus del
operador al input, y
trata el operador como =- .
Alternativamente podra ser deseable tratar esto como =-a. Para
hacer
esto, simplemente se devuelve el signo menos as como la letra al
input. Lo
siguiente lleva a cavo la interpretacin:
=- [ a-zA-Z ] {
printf (Operator (=-) ambiguious\n);
yyless (yyleng 2);
... accin para =...
}
Gua del Programador del XENIX.
12
Tngase en cuenta que la expresin para los dos casos se podra
escribir
ms fcilmente con
=- / [ A-Za-z]
en el primer caso, y
= / - [ A-Za-z ]
en el segundo: en la orden de accin no se requerir ningn backup.
No es
necesario reconocer el identificador completo para observar la
ambigedad. La
posibilidad de =-3, de todos modos hace de
=-[^\ t\ n]
una orden an mejor.
Adems de estas rutinas, el lex tambin permite acceso a las
rutinas de I/O
31
Leng. Y Aut.
32
Leng. Y Aut.
Leng. Y Aut.
siguiente:
Se prefiere la coincidencia ms larga.
De entre las rdenes que coinciden en el mismo nmero de
caracteres, se prefiere la primera orden especificada.
Por ejemplo: suponga que se especifican las rdenes siguientes:
integer keyword action ... ;
[ a-z ] + identifier action ... ;
Si el input es integers, se toma como un identificador, puesto que
[ a-z ] +
es integer, ambas rdenes coinciden en siete
caracteres, y se selecciona la orden keyword porque sta ha sido
especificada
primero. Cualquier cosa ms corta ( por ejemplo, int) no coincide
con la
expresin integer, por lo tanto se usa la interpretacin coincide con
ocho caracteres mientras que
integer
slo coincide con siete. Si el input identifier.
El principio de la preferencia de la coincidencia ms larga hace que
ciertas construcciones sean peligrosas, tales como la siguiente:
.*
Gua del Programador del XENIX.
14
Por ejemplo
.*
parece ser una buena forma de reconocer un literal que se
encuentra entre
comillas. Pero es una invitacin a que el programa lea ms all,
buscando un
solo signo de comilla distante. Presentado el input
first quoted string here, second here
la expresin anterior coincide con
first quoted string here, second
34
Leng. Y Aut.
Leng. Y Aut.
una vez que ha pasado un she estos caracteres se han ido para
siempre.
A veces el usuario quiere cancelar esta seleccin. 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:
LEX: El Analizador Lxico
15
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
a [ bc ] + { ... ; REJECT;}
a [ cd ] + { ... ; REJECT;}
Si el input es ab, slo coincide la primera orden, y en ad slo
coincide la
36
Leng. Y Aut.
Leng. Y Aut.
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.
8.15. Especificacin de sensibilidad de contexto izquierdo
A veces es deseable aplicar varios grupos de rdenes lxicas en
diferentes ocasiones en el input. Por ejemplo, un compilador
preprocesador
Gua del Programador del XENIX.
16
puede distinguir sentencias del preprocesador y analizarlas de
forma diferente a
como hace con las sentencias ordinarias. Esto requiere sensitividad
al contexto
previo, y hay varias formas de tratar tales problemas. El operador (
^ ), por
ejemplo, es un operador de contexto previo, que reconoce
inmediatamente
contexto que precede por la izquierda del mismo modo que el signo
de dlar ( $
) reconoce el contexto que va inmediatamente a la derecha. El
contexto
adyacente a la izquierda se podra extender, para producir un
dispositivo similar
al del contexto adyacente a la derecha, pero no es muy probable
que sea de
utilidad, puesto que a menudo el contexto de la derecha relevante
apareci algn
tiempo antes tal como al principio de una lnea.
Esta seccin describe tres formas de tratar con entornos
diferentes:
1. El uso de flags, cuando de un entorno a otro slo cambian unas
pocas
38
Leng. Y Aut.
rdenes.
2. El uso de condiciones start con rdenes.
3. El uso de diversos analizadores lxicos funcionando juntos.
En cada caso, hay rdenes que reconocen la necesidad de cambiar
el
entorno en el cual se analiza el texto de input siguiente, y ponen
varios
parmetros para reflejar el cambio. Esto puede ser un flag probado
explcitamente por el cdigo de accin del usuario; tal flag es una
forma ms
sencilla de tratar con el problema, puesto que el lex no est
relacionado. Puede
que sea ms conveniente, hacer que el lex recuerde los flags como
condiciones
iniciales de las rdenes. Cualquier orden puede estar relacionada
con una
condicin start. Slo ser reconocida cuando el lex est en esa
misma condicin.
La condicin de start en curso se puede cambiar en cualquier
momento.
Finalmente, si los conjuntos de rdenes de los diferentes entornos
son muy
diferentes, se puede lograr una mayor claridad escribiendo varios
analizadores
lxicos distintos, y cambiar de uno a otro segn se desee.
Considere el siguiente problema: copie el input en el output,
cambiando
la palabra magic a primero en cada lnea que comience con la
letra a,
cambiando magic por segundo en cada lnea que comience con la
letra b, y
cambiando magic por tercero en cada lnea que comience con la
letra c.
39
Leng. Y Aut.
Leng. Y Aut.
41
Leng. Y Aut.
Leng. Y Aut.
Leng. Y Aut.
Leng. Y Aut.
20
8.17. Lex y Yacc
Si se quiere usar el lex con el yacc, tngase en cuenta que el lex
escribe
un programa llamado yylex( ), el nombre requerido por el yacc para
su
analizador. Normalmente el programa main por defecto de la
librera lex llama a
esta rutina, pero si yacc est cargado, y se usa su programa main,
yacc llamar al
yylex( ). En este caso, cada orden lex deber terminar con
return (token);
donde se devuelve el valor de token apropiado. Una forma fcil de
obtener
acceso a los nombres del yacc para los tokens es compilar el
fichero de output
del lex como parte del fichero de output del yacc poniendo la lnea
#include lex.yy.c
en la ltima seccin del input del yacc. Suponiendo que la gramtica
se llame
good y las rdenes lxicas se llamen better , la secuencia de
comandos
XENIX puede ser:
yacc good
lex better
cc y.tab.c ly ll
La librera yacc (-ly) se deber cargar antes de la librera lex para
obtener
un programa main que llame al reconocedor yacc. La generacin de
programas
lex y yacc se puede hacer en cualquier orden.
Como problema trivial, considere copiar un fichero input mientras
se
45
Leng. Y Aut.
Leng. Y Aut.
-? [ 0-9 ]+ ECHO;
[A-Za-z] [A-Za-z0-9 ]+ ECHO;
Las cadenas de caracteres numricos que contienen un punto
decimal o
precedidas de una letra sern cogidas por una de las dos rdenes, y
no se
cambiarn. Si el if-else ha sido cambiado por una expresin
condicional C para
ahorrar espacio; la forma a?b:c quiere decir: si a entonces b, en
caso contrario c.
Como ejemplo de obtencin de estadsticas, aqu hay un programa
que
hace histogramas de longitudes de palabras, donde una palabra est
definida
como una cadena de letras.
int lengs[100];
%%
[ a-z ] + lengs[yyleng]++;
. |
\n ;
%%
yywrap( )
{
int i;
printf(Length No. words\n);
for(i=0; i<100; i++)
if (lengs[i] > 0)
printf(%5d%10d\n,i,lengs[i]);
return (1);
}
Este programa acumula el histograma, pero no produce output. Al
final
47
Leng. Y Aut.
del input imprime una tabla. La sentencia final return (1); indica que
el lex va a
llevar a cabo un wrapup. Si yywrap( ) devuelve un valor cero (false)
implica que
hay disponible ms input y el programa va a continuar leyendo y
procesando. Un
yywrap( ) que nunca devuelve un valor verdadero produce un bucle
infinito.
Como un ejemplo ms grande, aqu hay algunas partes de un
programa
escrito para convertir FORTRAN de doble precisin en FORTRAN
de precisin
simple. Puesto que FORTRAN no distingue entre letras maysculas
y letras
minsculas, esta rutina comienza definiendo un conjunto de clases
que incluyen
ambos tipos de letras de cada letra:
Gua del Programador del XENIX.
22
a [aA]
b [bB]
c [cC]
. .
. .
. .
z [zZ]
una clase adicional reconoce espacio en blanco:
W [ \ t ]*
La primera orden cambia precisin doble a real, o DOBLE
PRECISION
A REAL
48
Leng. Y Aut.
{d}{o}{u}{b}{l}{e}{W}{p}{r}{e}{c}{i}{s}{i}{o}{n}{
printf(yytext [0] == d ? real : REAL
}
A lo largo de este programa se tienen cuidado de conservar el tipo
de
letra del programa original. El operador condicional se usa para
seleccionar la
forma apropiada de la palabra reservada. La siguiente orden copia
indicaciones
de la tarjeta de continuacin para evitar confundirlos con las
constantes:
^ [ ^ 0] ECHO;
En la expresin regular, las comillas rodean los espacios en blanco.
Esto
se interpreta como el principio de lnea, despus cinco espacios en
blancos,
despus nada excepto un espacio en blanco o un cero. Ntese los
dos
significados diferentes del signo de intercalacin ( ^ ). A
continuacin van
algunas rdenes para cambiar constantes de doble precisin por
constantes de
precisin flotante.
[ 0-9 ]+ {W}{d}{W}[+-]?{W}[ 0-9 ]+ |
[ 0-9 ]+ {W}.{W}{d}{W}[+-]?{W}[ 0-9 ]+ |
.{W}[ 0-9 ]+ {W}{d}{W}[+-]?{W}[ 0-9 ]+ {
/* convert constants*/
for (p=yytext; *p = 0; p++)
{
if (*p == d 11 *p == D)
*p += e - d;
ECHO;
49
Leng. Y Aut.
}
Despus de que se ha reconocido la constante de punto flotante, el
bucle
for la explora para localizar la letra d o D. El programa aade
e d lo
cual lo convierte en la siguiente letra del alfabeto. La constante
modificada,
ahora de precisin simple, se escribe de nuevo. A continuacin va
una serie de
nombres que tienen que volverse a escribir para suprimir su d
inicial. Usando
la matriz yytext la misma accin es suficiente para todos los
nombres ( aqu slo
se especifica un ejemplo de una lista relativamente larga).
LEX: El Analizador Lxico
23
{d}{s}{i}{n} |
{d}{c}{o}{s} |
{d}{s}{q}{r}{t} |
{d}{a}{t}{a}{n} |
...
{d}{f}{l}{o}{a}{t} {printf(%s, yytext + 1);}
Otra lista de nombres debe cambiar la d inicial por una a inicial
{d}{l}{o}{g} |
{d}{l}{o}{g}10 |
{d}{m}{i}{n}1 |
{d}{m}{a}{x}1 {
yytext[0] += a d;
ECHO;
}
Si se cambia esta interpretacin proporcionando rutinas I/O que
traducen
50
Leng. Y Aut.
51
Leng. Y Aut.
Leng. Y Aut.
n estados
e nudos de rbol
a transiciones
k Clases de caracteres compactados
o tamao de la matriz de output
LEX: El Analizador Lxico
25
Las lneas en la seccin de rdenes tienen la forma:
expresin accin
donde la accin se puede continuar en las lneas siguientes usando
llaves para
delimitarlo.
Las expresiones regulares del lex usan los operadores siguientes:
x El carcter x
x Una x, incluso si x es un operador.
\x Una x, incluso si x es un operador.
[xy] El carcter x o y.
[x-z] Los caracteres x, y o z.
[^ x] Cualquier carcter salvo x.
. Cualquier carcter salvo newline.
^ x Una x al principio de la lnea.
<y>x Una x cuando el lex est en la condicin start y.
x$ Una x al final de una lnea.
x? Una x opcional.
x* 0,1,2 .... apariciones de x.
x+ 1,2,3 .... apariciones de x.
x|y Una x o una y.
x/y Una x, pero slo si va seguida de una y.
{xx} La traduccin de xx de la seccin de definiciones.
x{m,n} m a travs de n ocurrencias de x.
53
Leng. Y Aut.
COMPILADOR
LEX
54
Leng. Y Aut.
Leng. Y Aut.
<declaraciones>
%%
<reglas de traduccin>
%%
<procedimientos auxiliares>
Leng. Y Aut.
57
Leng. Y Aut.
58
Leng. Y Aut.
59
Leng. Y Aut.
COMPILADOR YACC
YACC significa "otro compilador de compiladores ms" (del ingls
Yet Another Compilers-Compiler), lo que refleja la popularidad de
los generadores de analizadores sintcticos al principio de los aos
setenta, cuando S. C. Johnson cre la primera versin de YACC.
Este generador se encuentra disponible como una orden del sistema
UNIX, y se ha utilizado para facilitar la implantacin de cientos de
compiladores.
Para construir un traductor utilizando YACC primero se prepara un
archivo.
Ejemplo traduce.y, que contiene una especificacin en YACC del
traductor. La orden del sistema UNIX
yacc traduce.y
transforma al archivo traduce.y en un programa escrito en C
llamado y.tab.c, que implementa un analizador sintctico escrito en
C, junto con otras rutinas en C que el usuario pudo haber preparado
en el fichero traduce.y. Posteriormente, se compila el fichero
y.tab.c y se obtiene el programa objeto deseado que realiza la
traduccin especificada por el programa original en YACC. Si se
necesitan otros procedimientos, se pueden compilar o cargar con
y.tab.c, igual que en cualquier programa en C.
Leng. Y Aut.
declaraciones
%%
reglas
de
traduccin
%%rutinas en C de apoyo
La parte de declaraciones. Hay dos secciones opcionales en
la parte de declaraciones de un programa en YACC:
o En la primera seccin, se ponen declaraciones ordinarias
en C, delimitadas por %{ y %}. Aqu se sitan las
declaraciones de todas las variables temporales usadas
por las reglas de traduccin o los procedimientos de la
segunda y tercera secciones. Por ejemplo:
%{
#include <string.h> %}
Tambin en la parte de declaraciones hay declaraciones
de los componentes lxicos de la gramtica. Por ejemplo:
%token DIGITO
declara que DIGITO es un componente lxico o token.
Los componentes lxicos que se declaran en esta seccin
se pueden utilizar despus en la segunda y tercera
partes de la especificacin en YACC.
La parte de las reglas de traduccin. En la parte de la
especificacin en YACC despus del primer par %% se
escriben las reglas de traduccin. Cada regla consta de una
produccin de la gramtica y la accin semntica asociada. Un
conjunto de producciones como:
< lado izquierdo > -> < alt1 > | < alt2 > ... | < altn >
En YACC se escribira:
< lado izquierdo > : < alt1 >
{ accin semntica 1 }
| < alt2 >
{ accin semntica 2 }
....
| < altn >
{ accin semntica n }
;
61
Leng. Y Aut.
Leng. Y Aut.
63
Leng. Y Aut.
Leng. Y Aut.
65
Leng. Y Aut.
Conclusin
66