Está en la página 1de 66

Leng. Y Aut.

Beyra Domnguez Ballona

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.

Beyra Domnguez Ballona

Intrprete: Es un traductor que realiza la operacin de compilacin


paso a paso. Para cada sentencia que compone el texto de entrada,
se realiza una traduccin, ejecuta dicha sentencia y vuelve a iniciar
el proceso con la sentencia siguiente. La principal ventaja del
proceso de compilacin frente al de interpretacin es que los
programas se ejecutan mucho ms rpidamente una vez compilados;
por el contrario, es ms cmodo desarrollar un programa mediante
un intrprete que mediante un compilador puesto que en el
intrprete las fases de edicin y ejecucin estn ms integradas.
La depuracin de los programas suele ser ms fcil en los
intrpretes que en los compiladores puesto que el cdigo fuente
est presente durante la ejecucin. Estas ventajas pueden
incorporarse al compilador mediante la utilizacin de entornos de
desarrollo y depuradores simblicos en tiempo de ejecucin.
Preprocesadores: Procesan un texto fuente modificndolo en
cierta forma previamente a la compilacin. Por ejemplo, muchos
compiladores admiten un conjunto de macroinstrucciones ajenas al
lenguaje en s que indican al compilador si tiene que incluir algn
fichero externo, si ha de hacer o no un listado completo de la
compilacin, etc...
Conversores Fuente-Fuente: (LCP) Traducen un lenguaje fuente de
alto nivel a otro (por ejemplo, PASCAL -> C). Una aplicacin
interesante de la traduccin fuente-fuente es el desarrollo e
implementacin de prototipos de nuevos lenguajes de programacin.
As, por ejemplo, si se desea definir un lenguaje especializado
puede implementarse rpidamente mediante su traduccin a un
lenguaje convencional de alto nivel.
Rutinas de anlisis de instrucciones: El conjunto de instrucciones
del entorno de un sistema operativo constituye un lenguaje que
debe ser analizado previamente para realizar las acciones
2

Leng. Y Aut.

Beyra Domnguez Ballona

oportunas. Igualmente, ciertos programas como editores de texto,


sistemas de diseo asistido, etc..., utilizan instrucciones complejas
que deben interpretarse adecuadamente.

Ensambladores: Son compiladores cuyo lenguaje de entrada,


llamado ensamblador, permite la traduccin de cada sentencia
fuente a una instruccin en cdigo mquina.
Compilador cruzado: Es el que genera un cdigo objeto ejecutable
en un ordenador distinto de aqul en el que se realiza la
compilacin.
Compilacin-Montaje-Ejecucin: En las aplicaciones grandes es
conveniente fragmentar el programa a realizar en mdulos que se
compilan por separado, y una vez que estos estn compilados unirlos
mediante un programa denominado montador para formar el mdulo
ejecutable. El montador se encarga, a su vez, de incluir las libreras
donde estn guardadas las funciones predefinidas de uso comn.
Compilacin en una o varias pasadas: Se llama pasada a cada
lectura que hace el compilador del texto fuente.
Compilacin incremental. Este compilador acta de la siguiente
manera. Compila un programa fuente. Caso de detectar errores al
volver a compilar el programa corregido slo compila las
modificaciones que se han hecho respecto al primero.
Autocompilador: Es aqul que est escrito en el mismo lenguaje que
se pretende compilar. Supongamos, por ejemplo, que queremos
desarrollar la versin 2.0 de un compilador Pascal. Dicho compilador
generar un cdigo mucho ms rpido y eficiente que el que
generaba la versin anterior 1.0. Sin embargo, son ya muchas las
3

Leng. Y Aut.

Beyra Domnguez Ballona

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.

Beyra Domnguez Ballona

Lenguaje fuente: Lenguaje origen que traduce el compilador.


Lenguaje objeto: Lenguaje meta, al cul traduce el
compilador.
Lenguaje del compilador: Lenguaje en el que est escrito
el compilador.

Supongamos que se quiere implementar un nuevo lenguaje A(N) en


una mquina determinada. Disponemos solamente de un ensamblador
para dicha mquina. En principio parece que la solucin es escribir
un compilador en lenguaje ensamblador que traduzca desde el
lenguaje A(N) al lenguaje mquina LM.

sto en la prctica resulta bastante complicado, dado que


programar en ensamblador es muy engorroso.
Lo que se hace en estos casos es desarrollar un lenguaje
restringido A(1), parecido al A(N) pero ms simple, y para este
lenguaje escribir el compilador en ensamblador, o en cualquier otro
lenguaje soportado por la mquina.
Una vez construido este compilador, y dado que nuestra mquina es
ya capaz de entender el lenguaje A(1), se puede desarrollar un
compilador para otro lenguaje A(2) escribindolo en el lenguaje

Leng. Y Aut.

Beyra Domnguez Ballona

A(1), y as sucesivamente hasta llegar a obtener un autocompilador


del lenguaje A(N). Esta tcnica se conoce como bootstrapping.

El primer compilador de Pascal desarrollado en Zurich por Wirth


fue posible gracias a esta tcnica. El conocido compilador C de GNU
emplea tambin este mecanismo en tres pasos.
Estructura de un compilador.
Un compilador es un programa, en el que pueden distinguirse dos
subprogramas o fases principales: una fase de anlisis, en la cul se
lee el programa fuente y se estudia la estructura y el significado
del mismo; y otra fase de sntesis, en la que se genera el programa
objeto.
En un compilador pueden distinguirse, adems, algunas estructuras
de datos comunes, la ms importante de las cuales es la tabla de
smbolos, junto con las funciones de gestin de sta y de los dems
elementos del compilador, y de una serie de rutinas auxiliares para
deteccin de errores.
El esquema general de un compilador podra ser el siguiente:

Leng. Y Aut.

Beyra Domnguez Ballona

Leng. Y Aut.

Beyra Domnguez Ballona

Esquema de un compilador.
Las funciones de estos mdulos son las siguientes:
Analizador lexicogrfico: Las principales funciones que realiza son:

Identificar los smbolos.


Eliminar los blancos, caracteres de fin de lnea, etc...
Eliminar los comentarios que acompaan al fuente.
Crear unos smbolos intermedios llamados tokens.
Avisar de los errores que detecte.

Ejemplo: A partir de la sentencia en PASCAL siguiente


nuevo := viejo + RAZON*2
genera un cdigo simplificado para el anlisis sintctico posterior,
por ejemplo:
<id1> <:=> <id2> <+> <id3> <*> <ent>
Nota: Cada elemento encerrado entre <> representa un nico token.
Las abreviaturas id y ent significan identificador y entero,
respectivamente.
Analizador sintctico: Comprueba que las sentencias que componen
el texto fuente son correctas en el lenguaje, creando una
representacin interna que corresponde a la sentencia analizada.
De esta manera se garantiza que slo sern procesadas las
sentencias que pertenezcan al lenguaje fuente. Durante el anlisis
sintctico, as como en las dems etapas, se van mostrando los
errores que se encuentran.
Ejemplo: El esquema de la sentencia anterior corresponde al de una
sentencia de asignacin del lenguaje Pascal. Estas sentencias son de
la forma:
<id> <:=> <EXPRESION>
y la parte que se denomina <EXPRESION> es de la forma:

Leng. Y Aut.

Beyra Domnguez Ballona

<id> <+> <EXPRESION> o bien


<id> <*> <EXPRESION> o bien
<real>

La estructura de la sentencia queda, por tanto, de manifiesto


mediante el siguiente esquema:
<id1> <:=> <EXPRESION>
/ | \
<id2> <+>
<EXPRESION>
/ | \
<id3> <*>
<EXPRESION>
|
<real>
Anlisis semntico: Se ocupa de analizar si la sentencia tiene algn
significado. Se pueden encontrar sentencias que son
sintcticamente correctas pero que no se pueden ejecutar porque
carecen de sentido. En general, el anlisis semntico se hace a la
par que el anlisis sintctico introduciendo en ste unas rutinas
semnticas.
Ejemplo: En la sentencia que se ha analizado existe una variable
entera. Sin embargo, las operaciones se realizan entre
identificadores reales, por lo que hay dos alternativas: o emitir un
mensaje de error "Discordancia de tipos", o realizar una conversin
automtica al tipo superior, mediante una funcin auxiliar inttoreal.
<id1> <:=> <EXPRESION>
/ | \
<EXPRESION>
/ | \
<EXPRESION>
|
|
<inttoreal>
<int>

<id2> <+>
<id3> <*>
|

<real>

Generador de cdigo intermedio: El cdigo intermedio es un


cdigo abstracto independiente de la mquina para la que se
generar el cdigo objeto. El cdigo intermedio ha de cumplir dos
requisitos importantes: ser fcil de producir a partir del anlisis
9

Leng. Y Aut.

Beyra Domnguez Ballona

sintctico, y ser fcil de traducir al lenguaje objeto. Esta fase


puede no existir si se genera directamente cdigo mquina, pero
suele ser conveniente emplearla.
Ejemplo: Consideremos, por ejemplo, un cdigo intermedio de
tercetos, llamado as porque en cada una de sus instrucciones
aparecen como mximo tres operandos. La sentencia traducida a
este cdigo intermedio quedara :
temp1 := inttoreal (2)temp2 := id3 * temp1temp3 := id2 +
temp2id1 := temp3
Optimizador de cdigo: A partir de todo lo anterior crea un nuevo
cdigo ms compacto y eficiente, eliminando por ejemplo sentencias
que no se ejecutan nunca, simplificando expresiones aritmticas,
etc... La profundidad con que se realiza esta optimizacin vara
mucho de unos compiladores a otros. En el peor de los casos esta
fase se suprime.
Ejemplo: Siguiendo con el ejemplo anterior, es posible evitar la
funcin inttoreal mediante el cambio de 2 por 2.0, obviando adems
una de las operaciones anteriores. El cdigo optimizado queda como
sigue :
temp1 := id3 * 2.0id1 := id2 + temp1
Generador de cdigo: A partir de los anlisis anteriores y de las
tablas que estos anlisis van creando durante su ejecucin produce
un cdigo o lenguaje objeto que es directamente ejecutable por la
mquina. Es la fase final del compilador. Las instrucciones del
cdigo intermedio se traducen una a una en cdigo mquina
reubcable.
Nota: Cada instruccin de cdigo intermedio puede dar lugar a ms
de un cdigode mquina.
10

Leng. Y Aut.

Beyra Domnguez Ballona

Ejemplo: El cdigo anterior traducido a ensamblador DLX quedara:


LW R1,id3MUL R1,R1,2LW R2,id2ADD R2,R2,R1SW id1,R2
en donde id1, id2 y id3 representan las posiciones de memoria en
las que se hallan almacenadas estas variables; R1 y R2 son los
registros de la mquina; y las instrucciones LW, SW, MUL y ADD
representan las operaciones de colocar un valor de memoria en un
registro, colocar un valor de un registro en memoria, multiplicar en
punto flotante y sumar, respectivamente.
La tabla de smbolos: Es el medio de almacenamiento de toda la
informacin referente a las variables y objetos en general del
programa que se est compilando.
Ejemplo: Hemos visto que en ciertos momentos del proceso de
compilacin debemos hacer uso de cierta informacin referente a
los identificadores o los nmeros que aparecen en nuestra
sentencia, como son su tipo, su posicin de almacenamiento en
memoria, etc... Esta informacin es la que se almacena en la tabla
de smbolos.
Rutinas de errores: Estn incluidas en cada uno de los procesos de
compilacin (anlisis lexicogrfico, sintctico y semntico), y se
encargan de informar de los errores que encuentran en texto
fuente.
Ejemplo: El analizador semntico podra emitir un error (o al menos
un aviso) cuando detectase una diferencia en los tipos de una
operacin.

11

Leng. Y Aut.

Beyra Domnguez Ballona

COMPILADOR LEX Y YACC


El lex es un generador de programas diseado para el proceso
lxico de
cadenas de caracteres de input. El programa acepta una
especificacin, orientada
a resolver un problema de alto nivel para comparar literales de
caracteres, y
produce un programa C que reconoce expresiones regulares. Estas
expresiones
las especifica el usuario en las especificaciones fuente que se le
dan al lex. El
cdigo lex reconoce estas expresiones en una cadena de input y
divide este input
en cadenas de caracteres que coinciden con las expresiones. En los
bordes entre
los literales, se ejecutan las secciones de programas
proporcionados por el
usuario. El fichero fuente lex asocia las expresiones regulares y los
fragmentos
de programas. Puesto que cada expresin aparece en el input del
programa
escrito por el lex, se ejecuta el fragmento correspondiente.
El usuario proporciona el cdigo adicional necesario para completar
estas
funciones, incluyendo cdigo escrito por otros generadores. El
programa que
reconoce las expresiones se genera en forma de fragmentos de
programa C del

12

Leng. Y Aut.

Beyra Domnguez Ballona

usuario, El lex no es un lenguaje completo sino un generador que


representa una
cualidad de un nuevo lenguaje que se aade al leguaje de
programacin C.
El lex convierte las expresiones y acciones del usuario (llamadas
fuente
en este captulo) en un programa C llamado yylex. El programa yylex
reconoce
expresiones en un flujo (llamado input en este captulo) y lleva a
cabo las
acciones especificadas para cada expresin a medida que se va
detectando.
Considere un programa para borrar del input todos los espacios en
blanco
y todos los tabuladores de los extremos de las lneas. Las lneas
siguientes:
%%
[b\ t]+ $ ;
es todo lo que se requiere. El programa contiene un delimitado %%
para marcar
el principio de las rdenes, y una orden. Esta orden contiene una
expresin que
coincide con una o ms apariciones de los caracteres espacio en
blanco o
tabulador (escrito \ t para que se vea con mayor claridad, de
acuerdo con la
convencin del lenguaje C) justo antes del final de una lnea. Los
corchetes
indican la clase del carcter compuesto de espacios en blanco y
tabuladores; el +

13

Leng. Y Aut.

Beyra Domnguez Ballona

indica uno o ms del item anterior; y el signo de dlar ($) indica el


final de la
lnea. No se especifica ninguna accin, por lo tanto el programa
generado por el
lex ignorar estos caracteres. Todo lo dems se copiar . Para
cambiar cualquier
cadena de caracteres en blanco o tabuladores que queden en un
solo espacio en
blanco, aada otra orden:
%%
[b\ t]+$ ;
[b\ t] + printf ( );
Gua del Programador del XENIX.
2
La automatizacin generada por este fuente explora ambas rdenes
a la
vez, observa la terminacin de la cadena de espacios o tabuladores
haya o no un
carcter newline, y despus ejecuta la accin de la orden deseada.
La primera
orden coincide con todas las cadenas de caracteres de espacios en
blanco o
tabuladores hasta el final de las lneas, y la segunda orden coincide
con todos los
literales restantes de espacios o tabuladores.
El lex se puede usar slo para transformaciones sencillas, o por
anlisis o
estadsticas buscando en un nivel lxico. El lex tambin se puede
usar con un
generador reconocedor para llevar a cabo la fase de anlisis lxico;
es
especialmente fcil hacer que el lex y el yacc funcionen juntos. Los
programas
14

Leng. Y Aut.

Beyra Domnguez Ballona

lex reconocen slo expresiones regulares; yacc escribe


reconocedores que
aceptan una amplia clase de gramticas de texto libre, pero que
requieren un
analizador de nivel bajo para reconocer tokens de input. Por lo
tanto, a menudo
es conveniente una combinacin del lex y del yacc. Cuando se usa
como un
preprocesador para un generador, el lex se usa para dividir el input,
y el
generador de reconocimiento asigna una estructura a las piezas
resultantes. Los
programas adicionales, escritos por otros generadores o a mano, se
pueden
aadir fcilmente a programas que han sido escritos por el lex. Los
usuarios del
yacc se darn cuenta de que el nombre yylex es el que el yacc da a
su analizador
lxico, de forma que el uso de este nombre por el lex simplifica el
interface.
El lex genera un autmata finito partiendo de expresiones
regulares del
fuente. El autmata es interpretado, en vez de compilado, para
ahorrar espacio.
El resultado es todava un analizador rpido. En particular, el
tiempo que utiliza
un programa lex para reconocer y dividir una cadena de input es
proporcional a
la longitud del input. El nmero de rdenes lex o la complejidad de
las rdenes
no es importante para determinar la velocidad, a no ser que las
rdenes que

15

Leng. Y Aut.

Beyra Domnguez Ballona

incluyan contexto posterior requieran una cantidad importante de


exploracin.
Lo que aumenta con el nmero y complejidad de las rdenes es el
tamao del
autmata finito, y por lo tanto el tamao del programa generado
por el lex.
En el programa escrito por el lex, los fragmentos del usuario
(representando acciones que se van a llevar a cabo a medida que se
encuentra
cada expresin) se colectan como casos de un intercambio. El
intrprete del
autmata dirige el flujo de control. Se proporciona la oportunidad
al usuario para
insertar declaraciones o sentencias adicionales en la rutina que
contiene las
acciones, o para aadir subrutinas fuera de esta rutina de accin.
El lex no est limitado a fuente que se puede interpretar sobre la
base de
un posible carcter. Por ejemplo, si hay dos rdenes una que busca
ab y la otra
que busca abcdefg, y la cadena de caracteres del input es abcdefh,
el lex
reconocer ab y dejar el puntero del input justo delante de cd. Tal
precaucin es
ms costosa que el proceso de lenguajes ms sencillos.
LEX: El Analizador Lxico
3
8.2. Formato fuente del lex
El formato general de la fuente lex es:
{definiciones}
%%
{rdenes}
%%
16

Leng. Y Aut.

Beyra Domnguez Ballona

{subrutinas del usuario}


donde las definiciones y las subrutinas del usuarios se omiten a
menudo. El
segundo %% es opcional, pero el primero se requiere para marcar el
principio de
las rdenes. El programa lex mnimo absoluto es por lo tanto
%%
(sin definiciones, ni rdenes) lo cual se traduce en un programa que
copia el
input en el output sin variar.
En el formato del programa lex que se mostr anteriormente, las
rdenes
representan las decisiones de control del usuario. Estas forman una
tabla en la
cual la columna izquierda contiene expresiones regulares y la
columna derecha
contiene decisiones, fragmentos de programas que se ejecutarn
cuando se
reconozcan las expresiones. Por lo tanto la siguiente orden
individual puede
aparecer:
integer printf( localizada palabra reservada INT ) ;
Esto busca el literal integer en el input e imprime el mensaje:
localizada palabra reservada INT
siempre que aparezca en el texto de input. En este ejemplo la
funcin de librera
printf() se usa para imprimir la cadena de caracteres o literal. El
final de la
expresin regular lex se indica por medio del primer carcter
espacio en blanco o
tabulador. Si la accin es simplemente una sola expresin C, se
puede

17

Leng. Y Aut.

Beyra Domnguez Ballona

especificar en el lado derecho de la lnea; si es compuesta u ocupa


ms de una
lnea, deber incluirse entre llaves. Como ejemplo un poco ms til,
suponga que
se desea cambiar un nmero de palabras de la ortografa Britnica
a la
Americana. Las rdenes lex tales como
colour printf(color);
mechanise printf(mechanize);
petrol printf(gas);
ser una forma de empezar. Estas rdenes no son suficientes
puesto que la
palabra petroleum se convertir en gaseum; una forma de proceder
con tales
problemas se describe en una seccin posterior.
Gua del Programador del XENIX.
4
8.3. Expresiones del lex
Una expresin especifica un conjunto de literales que se van a
comparar.
Esta contiene caracteres de texto (que coinciden con los
caracteres
correspondientes del literal que se est comparando) y caracteres
operador (estos
especifican repeticiones, selecciones, y otras caractersticas). Las
letras del
alfabeto y los dgitos son siempre caracteres de texto. Por lo
tanto, la expresin
integer
Coincide con el literal integer siempre que ste aparezca y la
expresin
a57d
busca el literal a57d.
18

Leng. Y Aut.

Beyra Domnguez Ballona

Los caracteres operador son:


\[]^-?.*+|()$/{}%<>
Si cualquiera de estos caracteres se va a usar literalmente, es
necesario
incluirlos individualmente entre caracteres barra invertida ( \ ) o
como un grupo
dentro de comillas ( ).
El operador comillas ( ) indica que siempre que est incluido
dentro de
un par de comillas se va a tomar como un carcter de texto. Por lo
tanto
xyz++
coincide con el literal xyz++ cuando aparezca. Ntese que una parte
del literal
puede estar entre comillas. No produce ningn efecto y es
innecesario poner
entre comillas caracteres de texto normal; la expresin
xyz++
es la misma que la anterior. Por lo tanto poniendo entre comillas
cada carcter
no alfanumrico que se est usando como carcter de texto, no es
necesario
memorizar la lista anterior de caracteres operador.
Un carcter operador tambin se puede convertir en un carcter
de texto
ponindole delante una barra invertida ( \ ) como en
xyz\+\+
el cual, aunque menos legible, es otro equivalente de las
expresiones anteriores.
Este mecanismo tambin se puede usar para incluir un espacio en
blanco dentro
de una expresin; normalmente, segn se explicaba anteriormente,
los espacios
19

Leng. Y Aut.

Beyra Domnguez Ballona

en blanco y los tabuladores terminan una orden. Cualquier carcter


en blanco
que no est contenido entre corchete tiene que ponerse entre
comillas.
LEX: El Analizador Lxico
5
Se reconocen barios 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.
8.4. Llamar al lex.
Hay dos pasos al compilar un programa fuente lex Primero, el
programa
lex fuente tiene que ser convertido en un programa regenerado en
el lenguaje de
propsito general. Entonces ste programa tiene que ser compilado
y cargado,
normalmente con una librera de subrutinas lex. El programa
generado est en un
fichero llamado lex.yy.c. La librera I/O est definida en trminos
de la librera
estndar C.
A la librera se accede por medio del flag de la carga -ll. Por lo
tanto un
conjunto de comandos apropiados es
20

Leng. Y Aut.

Beyra Domnguez Ballona

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.

Beyra Domnguez Ballona

cualquier orden. Usando el guin entre cualquier par de caracteres


que ambos no
sean letras maysculas, letras minsculas, o dgitos, depende de la
implementacin y produce un mensaje de aviso. Si se desea incluir
el guin en
una clase de caracteres, ste deber ser el primero o el ltimo; por
lo tanto
[ -+0-9 ]
coincide con todos los dgitos y los signos ms y menos.
En las clases de caracteres, el operador ( ^ ) debe aparecer como
el
primer carcter despus del corchete izquierdo; esto indica que el
literal
resultante va a ser complementado con respecto al conjunto de
caracteres del
ordenador. Por lo tanto
[ ^abc ]
coincide con todos los caracteres excepto a, b, o c, incluyendo
todos los
caracteres especiales o de control; o
[ ^a-zA-Z ]
es cualquier carcter que no sea una letra. El carcter barra
invertida ( \ )
proporciona un mecanismo de escape dentro de los corchete de
clases de
caracteres, de forma que stos se pueden introducir literalmente
precedindolos
con este carcter.
8.6. Especificacin de un carcter arbitrario
Para hacer coincidir casi con cualquier carcter, el punto ( . )
designa la
clase de todos los caracteres excepto un carcter newline. Hacer
escape en octal
22

Leng. Y Aut.

Beyra Domnguez Ballona

es posible, aunque esto no es portable. Por ejemplo


[ \ 40 - \ 176 ]
coincide con todos los caracteres imprimibles del conjunto de
caracteres ASCII,
desde el octal 40 (espacio en blanco) hasta el octal 176 ( la tilde).
8.7. Especificar expresiones opcionales.
El operador signo de interrogacin ( ? ) indica un elemento opcional
de
una expresin. Por lo tanto
ab?c
coincide o con ac o con abc. Ntese que aqu el significado del signo
de
interrogacin difiere de su significado en la shell.
LEX: El Analizador Lxico
7
8.8. Especificacin de expresiones repetidas.
Las repeticiones de clases se indican con los operadores asterisco (
*)y
el signo ms ( + ). Por ejemplo
a*
coincide con cualquier nmero de caracteres consecutivos,
incluyendo cero;
mientras que a+ coincide con una o ms apariciones de a. Por
ejemplo,
[ a-z ]+
coincide con todos los literales de letras minsculas, y
[ A-Za-z ] [A-Za-z0-9 ]*
coincide con todos los literales alfanumricos con un carcter
alfabtico al
principio; sta es una expresin tpica para reconocer
identificadores en
lenguajes informticos.
8.9. Especificacin de alternacin y de agrupamiento.
23

Leng. Y Aut.

Beyra Domnguez Ballona

El operador barra vertical ( | ) indica alternacin. Por ejemplo


( ab|cd )
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.
8.10. 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 primer
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

24

Leng. Y Aut.

Beyra Domnguez Ballona

caso especial del operador barra ( / ) , el cual indica contexto al


final.
Gua del Programador del XENIX.
8
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
El contexto de la izquierda se maneja en el lex especificando las
condiciones start segn se explica en la seccin Especificacin de
sensibilidad
de contexto izquierdo . Si una orden slo se va a ejecutar cuando
el interprete
del autmata del lex est en la condicin x start, la orden se
deber incluir entre
corchetes de ngulos:
<x>
Si consideramos que estamos al comienzo de una lnea que es el
comienzo de la condicin ONE, entonces el operador ( ^ ) ser
equivalente a
<ONE>
Las condiciones start se explican con detalles ms tarde.
8.11. 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.
8.12. Especificar definiciones.
25

Leng. Y Aut.

Beyra Domnguez Ballona

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.

Beyra Domnguez Ballona

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 |
\ n ;
con el mismo resultado, aunque en un estilo diferente. Las comillas
alrededor de
\ n y \ 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

27

Leng. Y Aut.

Beyra Domnguez Ballona

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
Gua del Programador del XENIX.
10
[ 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
28

Leng. Y Aut.

Beyra Domnguez Ballona

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]
Ocasionalmente, una accin lex puede decidir que una orden no ha
reconocido el alcance correcto de los caracteres. Para ayudar a
resolver esta
situacin hay dos rutinas. La primera, yymore( ) se puede llamar
para indicar
que la siguiente expresin de input reconocida se va a aadir al
final de este
input. Normalmente, el siguiente literal de input escribir encima
de la entrada
actual en yytext. Segundo, yyless( n ) se puede llamar para indicar
que no todos
los caracteres que coinciden con la expresin actual se quieren en
ese momento.
El argumento n indica el nmero de caracteres de yytext que se van
a retener.
Otros caracteres que han coincidido previamente se devuelven al
input. Esto
proporciona el mismo tipo de anticipacin ofrecido por el operador
barra ( / ),
pero en una forma diferente.
Por ejemplo, considere un lenguaje que define un literal como un
conjunto de caracteres entre comillas ( ), y proporciona se para
incluir una

29

Leng. Y Aut.

Beyra Domnguez Ballona

marca comilla en un literal, tiene que ir precedido de un signo barra


invertida (\).
La expresin que coincide con esto es bastante confusa, de forma
que puede ser
preferible escribir
LEX: El Analizador Lxico
11
\ [ ^ ]* {
if (yytext [yyleng - 1] == \\)
yymore();
else
.... proceso del usuario normal
}
lo cual, cuando se compara con un literal tal como
abc\def
coincidir primero con los cinco caracteres
abc\
y despus la llamada a yymore() har que se aada al final la
siguiente parte del
literal,
def
Tngase en cuenta que el signo de comillas final que se encuentra al
final
del literal, se coger en el cdigo marcado como proceso normal.
La funcin yyless( ) se deber usar para reprocesar texto en
diversas
circunstancias. Considere el problema en la sintaxis C antigua de
distinguir la
ambigedad de =-a. Suponga que es deseable tratar esto como =-a e
imprimir un
mensaje. Una orden podra ser
=-[ a-zA-Z ] {
printf (Operator (=-) ambiguous\n);
30

Leng. Y Aut.

Beyra Domnguez Ballona

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.

Beyra Domnguez Ballona

que usa. Estas incluyen:


1. input ( ) el cual devuelve el siguiente carcter de input;
2. output ( ) el cual escribe el carcter c en el output; y
3. unput (c) el cual mete el carcter c de nuevo dentro del input que
se va a leer
despus por input ( ).
Por defecto, estas rutinas se proporcionan como definiciones
macro, pero
el usuario puede contrarrestarlas y proporcionar versiones
privadas. Estas rutinas
definen la relacin entre los ficheros externos y los caracteres
internos, y todas
se deben retener o modificar consistentemente. Estas se pueden
redefinir, para
hacer que el input o el output sea transmitido a o de lugares
extraos, incluyendo
otros programas o memoria internas pero el conjunto de caracteres
que se usa
debe ser consistente en todas las rutinas; un valor de cero devuelto
por input
tiene que significar final de fichero, y la relacin entre unput o
input debe ser
retenido o no funcionar el loockahead. Lex no mira hacia delante
si no es
necesario, pero cada orden que contiene una barra ( / ) o que
termina en uno de
los siguientes caracteres implica esto:
+*?$
El loockahead es tambin necesario para que coincida una
expresin
que es un prefijo de otra expresin. Ver a continuacin una
explicacin del

32

Leng. Y Aut.

Beyra Domnguez Ballona

conjunto de caracteres que usa el lex. La librera estndar del lex


impone un
lmite de 100 caracteres.
LEX: El Analizador Lxico
13
Otra rutina de la librera del lex que a veces es necesaria redefinir
es
yywrap ( ) la cual se llama siempre que lex llega a final de fichero.
Si yywrap
devuelve un 1, lex contina con un wrapup normal al final del input.
A veces, es
conveniente hacer que llegue ms input de una nueva fuente. En
este caso, el
usuario deber proporcionar un yywrap que obtenga nuevo input que
devuelva 0.
Esto indica al lex que contine el proceso; yywrap por defecto
siempre
devuelve 1.
Esta rutina es tambin un lugar conveniente para imprimir tabla
resmenes, etc. al final del programa. Ntese que si no es posible
escribir una
orden normal que reconozca el final del fichero; el nico acceso a
esta condicin
es a travs de yywrap ( ). De hecho, a no ser que se proporcione una
versin
privada de input ( ) no se puede manejar un fichero que contenga
datos nulos,
puesto que el valor 0 que input ( ) devuelve se toma como el final de
fichero.
8.14. Manejo de rdenes fuentes ambiguas
El lex puede manejar especificaciones ambiguas. Cuando ms de una
expresin puede coincidir con el input en curso, el lex selecciona de
la forma
33

Leng. Y Aut.

Beyra Domnguez Ballona

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.

Beyra Domnguez Ballona

lo que probablemente no es lo que se quera. Una orden mejor es de


la forma
[^\ n] *
lo cual, en el input anterior, se para despus de first. Las
consecuencias de
errores como ste estn mitigadas por el hecho de que el operador
punto ( . ) no
coincide con un newline. Por lo tanto, tales expresiones nunca
coinciden con
ms de una lnea. No intente evitar esto usando expresiones como
[ .\ n ] +
o sus equivalentes: el programa generado por el lex intentar leer
el fichero de
input completo, haciendo que el buffer interno se desborde.
Tngase en cuenta que normalmente el lex divide el input, y no
busca
todas las posibles coincidencias de cada expresin. Esto quiere
decir que cada
carcter slo se cuenta una vez, y slo una. Por ejemplo, suponga
quw se desea
contar las apariciones de she y he en un texto de input. Algunas
rdenes lex
para hacer esto podran ser
she s++;
he h++;
\n|
.;
donde las ltimas dos rdenes ignoran todo lo que no sea he y she.
Recuerde que
el punto ( . ) no incluye el carcter newline. Puesto que she incluye a
he, el lex
normalmente no reconocer las apariciones de he incluidas en she,
puesto que
35

Leng. Y Aut.

Beyra Domnguez Ballona

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.

Beyra Domnguez Ballona

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 coger 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
37

Leng. Y Aut.

Beyra Domnguez Ballona

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.

Beyra Domnguez Ballona

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.

Beyra Domnguez Ballona

Todas las dems palabras y todas las otras lneas no varan.


LEX: El Analizador Lxico
17
Estas rdenes son tan sencillas que la forma ms fcil de hacer el
trabajo,
es con un flag:
int flag;
%%
^a {flag = a ; ECHO;}
^b {flag = b ; ECHO;}
^c {flag = c ; ECHO;}
magic
switch (flag)
{
case a: printf ( first ); break;
case b: printf ( second ); break;
case c: printf ( third ); break;
default : ECHO; break ;
}
}
deber ser adecuado.
Para tratar el mismo problema con las condiciones start, cada
condicin
start debe ser introducida en el lex en la seccin de definiciones
con una lnea
que diga
%Start nombre1, nombre2
donde las condiciones se pueden especificar en cualquier orden. La
palabra start
se puede abreviar a s o S. Las condiciones se pueden referenciar al
principio de
40

Leng. Y Aut.

Beyra Domnguez Ballona

una orden incluyndolas entre ngulos. Por ejemplo


nombre1 expresin
es una orden que slo se reconoce cuando el lex est en la condicin
start
nombre1. Para introducir una condicin start
BEGIN nombre1;
la cual cambia la condicin start por nobre1, Para volver al estado
inicial
BEGIN 0;
Restaura la condicin del intrprete del autmata del lex. Una
orden
puede estar activa en varias condiciones start; por ejemplo:
< nombre1, nombre2, nombre3 >
es un prefijo legal. Cualquier orden que no comience con el operador
prefijo <>
est siempre activa.
Gua del Programador del XENIX.
18
El mismo ejemplo anterior se puede escribir:
%START AA BB CC
%%
^a {ECHO; BEGIN AA;}
^b {ECHO; BEGIN BB;}
^c {ECHO; BEGIN CC;}
\n {ECHO; BEGIN 0;}
<AA> magic printf (primero);
<BB> magic printf (segundo);
<CC> magic printf ( tercero );
donde la lgica es exactamente la misma que en el mtodo anterior
de tratar el

41

Leng. Y Aut.

Beyra Domnguez Ballona

problema, pero el lex hace el trabajo en vea de hacerlo el cdigo


del usuario.
8.16. Especificacin de definiciones fuente
Recuerde el formato de la fuente lex
{ definiciones }
%%
{ rdenes }
%%
{ rutinas del usuario }
Hasta ahora slo se han descrito las rdenes. Se necesitarn
opciones
adicionales, para definir variables para usarlas en el programa y
para que las use
el lex. Estas pueden ir bien en la seccin de definiciones o en la
seccin de
rdenes.
1. Cualquier lnea que no aparezca como una orden o accin de lex, la
cual
comienza con un espacio en blanco o un tabulador se copia en el
programa
generado. Tal input de fuente antes del primer delimitador %%
ser externo
a cualquier funcin del cdigo; si aparece inmediatamente despus
del
primer %%, aparece en un lugar apropiado para las declaraciones en
la
funcin escrita por el lex el cual contiene las acciones. Este
material tiene
que buscar fragmentos de programas, y deber ir delante de la
primera orden
de lex.
Como efecto secundario de lo anterior, las lneas que comienzan con
un
42

Leng. Y Aut.

Beyra Domnguez Ballona

espacio en blanco o un tabulador, y las cuales contienen un


comentario, se
pasan al programa generado. Esto se puede usar para incluir
comentarios
bien en la fuente lex o bien en el cdigo generado. Los comentarios
debern
seguir las convenciones del lenguaje C.
2. Cualquier cosa que vaya incluida entre lneas que slo contienen %
{y%}
se copia como en el anterior. Los delimitadores se desechan. Este
formato
permite introducir texto como sentencias de preprocesador que
deben
comenzar en la columna 1, o copiar lneas que no parecen programas.
LEX: El Analizador Lxico
19
3. Cualquier cosa que haya despus del tercer delimitador %% sin
tener en
cuenta los formatos, se copia despus del output del lex.
Las definiciones pensadas para el lex se especifican antes del
primer
delimitador %%. Cualquier lnea de esta seccin que no est incluida
entre %{ y
% }, y que comience en la columna 1, se asume que define los
literales de
sustitucin del lex. El formato de tales lneas es
nombre interpretacin
y hace que el literal especificado como una interpretacin sea
asociado con el
nombre. El nombre y la interpretacin tienen que estar separados
por al menos
un espacio en blanco o un tabulador, y el nombre tiene que
comenzar con una
43

Leng. Y Aut.

Beyra Domnguez Ballona

letra. La interpretacin se puede llamar entonces por la sintaxis


nombre de una
orden. Usando D para los dgitos, y E para un campo exponencial,
por ejemplo,
se puede abreviar las rdenes para que reconozcan nmeros:
D [ 0-9 ]
E [ DEde][ - + ]? {D}+
%%
{D}+ pritnf (integer);
{D}+.{D}*({E})? |
{D}*.{D}+({E})? |
{D}+{E} printf (real);
Tngase en cuenta que las dos primeras rdenes para los nmeros
reales;
requieren un punto decimal y contienen un campo exponencial
opcional, pero la
primera requiere que al menos un dgito antes del punto decimal, y
el segundo
requiere al menos un dgito despus del punto decimal. Para tratar
correctamente
el problema creado por una expresin FORTRAN tal como 25.EQ.I,
la cual no
contiene un nmero real, una orden sensitiva de contexto tal como
[ 0-9 ]+/.EQ printf(integer);
se podra usar adems de la orden normal para nmeros enteros.
La seccin de definiciones puede tambin contener otros comandos,
incluyendo una tabla de caracteres, una lista de condiciones start, o
ajustes al
tamao por defecto de las matrices dentro del propio lex para
programas fuentes
ms largos. Estas posibilidades se explican en la seccin Formato
Fuente.
Gua del Programador del XENIX.
44

Leng. Y Aut.

Beyra Domnguez Ballona

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.

Beyra Domnguez Ballona

aade 3 a cada nmero positivo divisible por 7. Podemos desarrollar


un
programa fuente lex que hace precisamente eso:
%%
int k;
[ 0-9 ]+ {
k = atoi(yytext);
if (k%7 == 0)
printf(%d,k+3);
else
printf(%d, k);
}
La orden [ 0-9 ]+ reconoce cadenas de dgitos; atoi( ) convierte los
dgitos en binario y almacena el resultado en k. El operador (%) se
usa para
comprobar si k es divisible por 7; si lo es, se incrementa en 3 a
medida que se va
escribiendo. Se puede objetar que este programa alterar input tal
como 49.63 o
X7. Adems incrementa el valor absoluto de todos los nmeros
negativos
divisible por 7. Para evitar esto, aada simplemente unas pocas ms
de rdenes
despus de la orden activa, como:
LEX: El Analizador Lxico
21
%%
int k;
-? [ 0 9 ]+ {
k = atoi(yytest);
printf(%d,k%7 == 0? K+3 : k);
}
46

Leng. Y Aut.

Beyra Domnguez Ballona

-? [ 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.

Beyra Domnguez Ballona

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.

Beyra Domnguez Ballona

{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.

Beyra Domnguez Ballona

}
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.

Beyra Domnguez Ballona

los caracteres, es necesario decrselo al lex, dando una tabla de


traduccin. Esta
tabla tiene que estar en la seccin de definiciones, y tienen que
estar incluidas
por lneas que contenga slo %T. La tabla contiene lneas de la
forma
{entero}{cadena de caracteres}
%T
1 Aa
2 Bb
...
26 Zz
27 |n
28 +
29
30 0
31 1
...
39 9
%T
Esta tabla convierte las letras minsculas y maysculas en los
enteros del
1 al 26, el carcter newline en el nmero 27, los signos ms (+) y
menos(+) en
los nmeros 28 y 29, y los dgitos en los nmeros 30 a 39. Ntese
el escape para
el caracteres newline. Si se proporciona una tabla, cada carcter
que va a
aparecer o bien en las rdenes o en cualquier input vlido tiene que
estar
incluido en la tabla. Ningn carcter puede ser asignado al nmero
0, y ningn

51

Leng. Y Aut.

Beyra Domnguez Ballona

carcter puede ser asignado a un nmero ms grande que el tamao


del conjunto
de caracteres del hardware.
Gua del Programador del XENIX.
24
Formato Fuente
El formato general de un fichero fuente del lex es:
{definiciones}
%%
{rdenes}
%%
{subrutinas del usuario}
La seccin de definiciones contiene una combinacin de
1. Definiciones en el formato nombre espacio traduccin.
2. Cdigo incluido, en el formato espacio cdigo .
3. Cdigo incluido en el formato
%{
cdigo
%}
4. Condiciones start, especificadas en el formato
%S nombre1, nombre2, ...
5. Tablas del conjunto de caracteres, en el formato
%T
numero espacio cadena de caracteres
%T
6. Cambia los tamaos de las matrices internas, en el formato
%x nnn
donde nnn es un nmero entero decimal que representa un tamao
de
matriz y x selecciona el parmetro de la forma siguiente:
Letra Parmetro
p posiciones
52

Leng. Y Aut.

Beyra Domnguez Ballona

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.

Beyra Domnguez Ballona

COMPILADOR

LEX

En este apartado y en el siguiente se describe una herramienta


particular, llamada Lex, que ha sido ampliamente usada para
especificar analizadores lxicos para una variedad de lenguajes. Se
har referencia a la herramienta como el compilador Lex, y a su
especificacin de entrada como el lenguaje Lex. La discusin de
una herramienta existente nos permitir mostrar como la
especificacin de patrones usando expresiones regulares puede
estar combinada con acciones, como por ejemplo, crear entradas en
una tabla de smbolos, expandir marcos, o incluso generar
documentacin automticamente.
El programa Lex est diseado para ser utilizado junto con el
programa Yacc ,es un generador de analizadores sintcticos.
Lex suele ser usado segn la siguiente figura.

54

Leng. Y Aut.

Beyra Domnguez Ballona

Primero, se prepara una especificacin de un analizador lxico


creando un programa contenido, por ejemplo en el fichero prog.l, en
lenguaje Lex. Entonces, prog.l se pasa a travs del compilador Lex
para producir un programa en C, que por defecto se denomina
lex.yy.c en el sistema operativo UNIX. ste consiste en una
representacin tabular de un diagrama de transicin construido a
partir de las expresiones regulares de prog.l, junto con una rutina
estndar que usa la tabla de reconocimiento de lexemas. Las
acciones asociadas con expresiones regulares en prog.l son trozos
de cdigo C, y son transcritas directamente a lex.yy.c. Finalmente,
lex.yy.c se pasa a travs del compilador C para producir un
programa objeto, que por defecto se llama a.out, el cual es el
analizador lxico que transforma una entrada en una secuencia de
tokens.

Un programa Lex consta de tres secciones:


55

Leng. Y Aut.

Beyra Domnguez Ballona

<declaraciones>
%%
<reglas de traduccin>
%%
<procedimientos auxiliares>

La seccin de declaraciones incluye declaraciones de variables,


constantes y definiciones regulares. Las definiciones regulares son
sentencias usadas como componentes de las expresiones regulares
que aparecen en las reglas.

Las reglas de traduccin de un programa Lex son sentencias


de la forma:
p1 { accin1 }
p2 { accin2 }
... ...
pn { accinn }
donde cada pi es una expresin regular y cada accini es un
fragmento de programa, describiendo qu accin debe realizar el
analizador lxico cuando el patrn pi se corresponde con un lexema.
En Lex, las acciones estn escritas en C.
La tercera seccin contiene cualesquiera procedimientos auxiliares
que sean requeridos por las acciones. Alternativamente, estos
procedimientos pueden ser compilados separadamente y montados
junto con el analizador lxico.
Un analizador lxico creado por Lex funciona en concierto con un
analizador sintctico de la siguiente manera. Cuando es activado
56

Leng. Y Aut.

Beyra Domnguez Ballona

por el analizador sintctico, el analizador lxico comienza leyendo


de su entrada un carcter a la vez, hasta que encuentre el prefijo
ms largo de la entrada que ha correspondido con una de las
expresiones regulares pi. Entonces, ejecuta accin, que tpicamente
devolver el control al parser. Pero, si no lo hace, entonces el
analizador lxico procede a buscar ms lexemas, hasta que una
accin contenga una sentencia return o se lea el fichero completo.
La bsqueda repetida de lexemas hasta una devolucin explcita del
control permite que el analizador lxico procese los espacios en
blanco y comentarios convenientemente.
El analizador lxico devuelve un entero, que representa el token, al
analizador sintctico. Para pasar un valor de atributo con
informacin sobre el lexema, se puede usar una variable global
llamada yylval. Esto se hace cuando se use Yacc como generador del
analizador sintctico.
Los analizadores lxicos, para ciertas construcciones de lenguajes
de programacin, necesitan ver adelantadamente ms all del final
de un lexema antes de que puedan determinar un token con
certeza. En Lex, se puede escribir un patrn de la forma r1/r2,
donde r1 y r2 son expresiones regulares, que significa que una
cadena se corresponde con r1, pero slo si est seguida por una
cadena que se corresponde con r2. La expresin regular r2, despus
del operador lookahead "/", indica el contexto derecho para una
correspondencia; se usa nicamente para restringir una
correspondencia, no para ser parte de la correspondencia.

Recuperacin de errores lexicogrficos: Los programas pueden


contener diversos tipos de errores, que pueden ser:

57

Leng. Y Aut.

Beyra Domnguez Ballona

Errores lexicogrficos: Que veremos a continuacin.


Errores sintcticos: Por ejemplo, una expresin aritmtica
con mayor numero de parntesis de apertura que de cierre.
Errores semnticos: Por ejemplo, la aplicacin de un operador
a un tipo de datos incompatible con el mismo.
Errores lgicos: Por ejemplo, un bucle sin final.

Cuando se detecta un error, un compilador puede detenerse en ese


punto e informar al usuario, o bien desechar una serie de
caracteres del texto fuente y continuar con el anlisis, dando al
final una lista completa de todos los errores detectados. En ciertas
ocasiones es incluso posible que el compilador corrija el error,
haciendo una interpretacin coherente de los caracteres ledos. En
estos casos, el compilador emite una advertencia, indicando la
suposicin que ha tomado, y contina el proceso sin afectar a las
sucesivas fases de compilacin.
Los errores lexicogrficos se producen cuando el analizador no es
capaz de generar un token tras leer una determinada secuencia de
caracteres. En general, puede decirse que los errores
lexicogrficos son a los lenguajes de programacin lo que las faltas
de ortografa a los lenguajes naturales. Las siguientes situaciones
producen con frecuencia la aparicin de errores lexicogrficos:
1. Lectura de un carcter que no pertenece al vocabulario
terminal previsto para el autmata. Lo ms normal en este
caso es que el autmata ignore estos caracteres extraos y
continu el proceso normalmente. Por ejemplo, pueden dar
error en la fase de anlisis lexicogrfico la inclusin de
caracteres de control de la impresora en el programa fuente
para facilitar su listado.
2. Omisin de un carcter. Por ejemplo, si se ha escrito ELS en
lugar de ELSE.

58

Leng. Y Aut.

Beyra Domnguez Ballona

3. Se ha introducido un nuevo carcter. Por ejemplo, si


escribimos ELSSE en lugar de ELSE.
4. Han sido permutados dos caracteres en el token analizado.
Por ejemplo, si escribiramos ESLE en lugar de ELSE.
5. Un carcter ha sido cambiado. Por ejemplo, si se escribiera
ELZE en vez de ELSE.
Las tcnicas de recuperacin de errores lexicogrficos se basan,
en general, en la obtencin de los distintos sinnimos de una
determinada cadena que hemos detectado como errnea. Por otra
parte, el analizador sintctico es capaz en muchos casos de avisar
al analizador lexicogrfico de cul es el token que espera que ste
lea.
Para el ejemplo de borrado de un carcter, tenemos que los
sinnimos de ELSE son ELS, ELE, ESE, y LSE. Por tanto, si
incluimos en nuestro analizador una rutina de recuperacin de
errores debidos a omisin de caracteres, cualquiera de estos
sinnimos sera aceptado en lugar del lexema ELSE, se emitira la
correspondiente advertencia, y el proceso continuara asumiendo
que se ha ledo el token <pal_res_ELSE>.
Anlogamente, podemos incluir rutinas para los dems casos. Por
ejemplo, si el analizador lee el lexema ESLE, y no puede construir
un token correcto para l mismo, procedera a generar los
sinnimos por intercambio de caracteres (es decir, SELE, ELSE o
ESEL) y comprobara si alguno de ellos es reconocible. En caso
afirmativo, genera el token correspondiente y advierte al usuario
del posible error y de su interpretacin automtica, continuando
con el proceso.
Todos los procedimientos para la recuperacin de errores
lexicogrficos son en la prctica mtodos espepcficos, y muy
dependientes del lenguaje que se pretende compilar.

59

Leng. Y Aut.

Beyra Domnguez Ballona

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.

Un programa fuente en YACC tiene tres secciones:


60

Leng. Y Aut.

Beyra Domnguez Ballona

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.

Beyra Domnguez Ballona

En una produccin en YACC, un carcter simple


entrecomillado 'c' se considera como el smbolo terminal
c, y las cadenas sin comillas de letras y dgitos no
declarados como componentes lxicos se consideran
smbolos no terminales. Los lados derechos alternativos
de las reglas se pueden separar con una barra vertical, y
un smbolo de punto y coma sigue a cada lado izquierdo
con sus alternativas y sus acciones semnticas. El primer
lado izquierdo se considera, por defecto, como el
smbolo inicial.
Una accin semntica en YACC es una secuencia de
sentencias en C. En una accin semntica, el smbolo $$
se refiere al valor del atributo asociado con el no
terminal del lado izquierdo, mientras que $i se refiere al
valor asociado con el i-simo smbolo gramatical
(terminal o no terminal) del lado derecho. La accin
semntica se realiza siempre que se reduzca por la
produccin asociada, por lo que normalmente la accin
semntica calcula un valor para $$ en funcin de los $i.
Si la regla no especifica ninguna accin semntica, la
accin semntica por omisin es {$$ = $1;}.
La parte de las rutinas de apoyo en C. La tercera parte de
una especificacin en YACC consta de rutinas de apoyo
escritas en C. Para que el analizador sintctico funcione, se
debe proporcionar un anlisis lxico de nombre yylex(). En
caso necesario se pueden agregar otros procedimientos, como
rutinas de recuperacin de errores.
El analizador lxico yylex() produce pares formados por un
componente lxico y su valor de atributo asociado. Si se
devuelve un componente lxico como DIGITO, el componente
lxico se debe declarar en la primera seccin de la
especificacin en YACC. El valor del atributo asociado a un
62

Leng. Y Aut.

Beyra Domnguez Ballona

componente lxico se comunica al analizador sintctico


mediante una variable especial que se denomina yylval.
Uso de YACC con gramticas ambiguas. Si la gramtica de la
especificacin en YACC es ambigua se producen conflictos en las
acciones del analizador sintctico. YACC informar del nmero de
conflictos en las acciones del anlisis sintctico que se produzcan.
Se puede obtener una descripcin de los conjuntos de elementos y
de los conflictos en las acciones de anlisis sintctico invocando a
YACC con la opcin -v. Esta opcin generar un archivo adicional
llamado y.output que contiene los ncleos de los conjuntos de
elementos encontrados por el analizador sintctico, una descripcin
de los conflictos en las acciones del anlisis, y una representacin
legible de la tabla de anlisis sintctico LR que muestra cmo se
resolvieron los conflictos de las acciones del anlisis sintctico.
A menos que se ordene lo contrario, YACC resolver todos los
conflictos en las acciones del anlisis sintctico utilizando las dos
reglas siguientes:
1. Un conflicto de reduccin/reduccin se resuelve eligiendo la
regla en conflicto que se haya escrito primero en la
especificacin.
2. Un conflicto de desplazamiento/reduccin se resuelve en
favor del desplazamiento.
Como estas reglas que se siguen por omisin, no siempre reflejan lo
que quiere el escritor del compilador, YACC proporciona un
mecanismo
general
para
resolver
los
conflictos
de
desplazamiento/reduccin. En la parte de declaraciones, se pueden
asignar precedencias y asociatividades a los terminales. La
declaracin
%left '+' '-'

63

Leng. Y Aut.

Beyra Domnguez Ballona

hace que '+' y '-' tengan la misma precedencia y que sean


asociativos por la izquierda. Se puede declarar que un operador es
asociativo por la derecha diciendo
%right '^'
y se puede obligar a un operador a ser un operador binario no
asociativo (por ejemplo, dos casos del operador no se pueden
combinar en absoluto) diciendo:
%nonassoc '<'
A los componentes lxicos se les dan precedencias en el orden en
que aparecen en la parte de declaraciones, siendo los primeros los
de menor precedencia. Los componentes lxicos de una misma
declaracin tienen la misma precedencia. As, la declaracin
%right MENOSU
Dara al componente lxico MENOSU un nivel de precedencia mayor
que a los terminales declarados anteriormente.
YACC resuelve los conflictos de desplazamiento/reduccin
asociando una precedencia y asociatividad a cada produccin
implicada en un conflicto, as como a cada terminal implicado en un
conflicto. Si debe elegir entre desplazar el smbolo de entrada a y
reducir por la produccin A->a, YACC reduce si la precedencia de la
produccin es mayor que la de a o si las precedencias son las
mismas y la asociatividad de la regla es %left. De lo contrario se
elige la accin de desplazar.
Generalmente, la precedencia de una produccin se considera igual
a la del smbolo terminal situado ms a la derecha. En la mayora de
los casos, esta es la decisin sensata. En las situaciones en que el
smbolo terminal situado ms a la derecha no proporcione la
precedencia adecuada a una produccin, se puede forzar una
precedencia aadiendo al final a la regla la etiqueta
%prec < terminal >
64

Leng. Y Aut.

Beyra Domnguez Ballona

Entonces, la precedencia y asociatividad de la produccin sern las


mismas que las de terminal, que se define seguramente en la
seccin de declaraciones. YACC no informa de los conflictos de
desplazamiento/reduccin que se resuelven utilizando este
mecanismo de precedencia y asociatividad.
Este "terminal" puede ser simplemente un marcador. Es decir, el
terminal no es devuelto por el analizador lxico, sino que se declara
tan slo para definir una precedencia para una produccin. Por
ejemplo,
expr : '-' expr %prec MENOSU
hace que la regla anterior tenga la precedencia correspondiente al
token MENOSU, en lugar de la del token '

65

Leng. Y Aut.

Beyra Domnguez Ballona

Conclusin

66

También podría gustarte