Anda di halaman 1dari 37

ANALISIS LEXICO

Concepto del analizador lxico.


Funciones del analizador lxico.
Necesidad del analizador lxico.
Nociones de Lenguaje.
Alfabeto.
Cadena.
Lenguaje.
Operaciones entre lenguajes
Unin
Concatenacin
Potencia
Cierre Transitivo
Cierre Reflexivo-Transitivo
Expresiones Regulares.
Concepto y aplicacin para la construccin de analizadores lxico.
Operaciones.
Ejemplos y desarrollo de planteamientos.
Token, patrn y lexema.
Generador de Analizadores Lxicos LEX.
Creacin de un analizador lxico.
Lenguaje de programacin LEX.
Estructura bsica de un programa.
Funciones y variables.
Ejemplos y desarrollo de planteamientos.

Para implementar un analizador lxico a mano, es til empezar con un diagrama o


cualquier otra descripcin de los lexemas de cada token. De esta manera, podemos

escribir cdigo para identificar cada ocurrencia de cada lexema en la entrada, y


devolver informacin acerca del token identificado. Podemos producir tambin un
analizador lxico en forma automtica, especificando los patrones de los lexemas a un
generador de analizadores lxicos, y compilando esos patrones en cdigo que funcione
como un analizador lxico. Este mtodo facilita la modificacin de un analizador
lxico, ya que slo tenemos que reescribir los patrones afectados, y no todo el
programa. Agiliza tambin el proceso de implementar el analizador, ya que el
programador especifica el software en el nivel ms alto de los patrones y se basa en el
generador para producir el cdigo detallado.

Se encarga de buscar los componentes lxicos o palabras que componen el programa


fuente, segn unas reglas o patrones. La entrada del analizador lxico podemos

definirla como una secuencia de caracteres, que pueda hallarse codificada segn
cualquier estndar: ASCII (American Standard Code for Information Interchange),
EBCDIC (Extended Binary Coded Decimal Interchange Code), Unicode, etc. El
analizador lxico divide esta secuencia en palabras con significado propio y despus
las convierte a una secuencia de terminales desde el punto de vista del analizador
sintctico. Dicha secuencia es el punto de partida para que el analizador sintctico
construya el rbol sintctico que reconoce la/s sentencia/s de entrada.

La principal tarea del analizador lxico es leer los caracteres de la entrada del programa
fuente, agruparlos en lexemas y producir como salida una secuencia de tokens para

cada lexema en el programa fuente. El flujo de tokens se enva al analizador sintctico


para su anlisis. Con frecuencia el analizador lxico interacta tambin con la tabla de
smbolos.

Cuando el analizador lxico descubre un lexema que constituye a un identificador, debe


introducir ese lexema en la tabla de smbolos. En algunos casos, el analizador lxico
puede leer la informacin relacionada con el tipo de informacin de la tabla de
smbolos, como ayuda para determinar el token apropiado que debe pasar al analizador
sintctico.

Como el analizador lxico es la parte del compilador que lee el texto de origen, debe
realizar otras tareas aparte de identificar lexemas. Una de esas tareas es eliminar los

comentarios y el espacio en blanco (caracteres de espacio, nueva lnea, tabulador y tal


vez otros caracteres que se utilicen para separar tokens en la entrada). Otra de las tareas
es correlacionar los mensajes de error generados por el compilador con el programa
fuente.

La principal tarea del analizador lxico es leer los caracteres de la entrada del programa
fuente, agruparlos en lexemas y producir como salida una secuencia de tokens para

cada lexema en el programa fuente. El flujo de tokens se enva al analizador sintctico


para su anlisis. Con frecuencia el analizador lxico interacta tambin con la tabla de
smbolos.

Cuando el analizador lxico descubre un lexema que constituye a un identificador, debe


introducir ese lexema en la tabla de smbolos. En algunos casos, el analizador lxico
puede leer la informacin relacionada con el tipo de informacin de la tabla de
smbolos, como ayuda para determinar el token apropiado que debe pasar al analizador
sintctico.

En otras palabras, por qu no se delega todo el procesamiento del programa fuente slo
en el anlisis sintctico, cosa perfectamente posible, ya que el sintctico trabaja con

gramticas de contexto libre y stas engloban a la regulares.

Simplificacin del diseo Un diseo sencillo es quizs la ventaja ms importante.

Separar el anlisis lxico del anlisis sintctico a menudo permite simplificar una, otra
o ambas fases.

Las expresiones regulares son una notacin importante para especificar patrones de
lexemas. Aunque no pueden expresar todos los patrones posibles, son muy efectivas

para especificar los tipos de patrones que en realidad necesitamos para los tokens.

Alfabeto, Cadenas y lenguajes

Un alfabeto es un conjunto finito de smbolos. Algunos ejemplos tpicos de smbolos


son las letras, los dgitos y los signos de puntuacin. El conjunto {0, 1} es el alfabeto
binario. ASCII es un ejemplo importante de un alfabeto; se utiliza en muchos sistemas

de software. Unicode, que incluye aproximadamente 10 000 caracteres de los alfabetos


alrededor del mundo, es otro ejemplo importante de un alfabeto.

Una cadena sobre un alfabeto es una secuencia finita de smbolos que se extraen de ese
alfabeto. En la teora del lenguaje, los trminos oracin y palabra a menudo se

utilizan como sinnimos de cadena. La longitud de una cadena s, que por lo general
se escribe como |s|, es el nmero de ocurrencias de smbolos en s.

Un lenguaje es cualquier conjunto contable de cadenas sobre algn alfabeto fijo. Esta
definicin es demasiado amplia. Los lenguajes abstractos como , el conjunto vaco, o
{}, el conjunto que contiene slo la cadena vaca, son lenguajes bajo esta definicin.
Tambin lo son el conjunto de todos los programas en C que estn bien formados en
sentido sintctico, y el conjunto de todas las oraciones en ingls gramaticalmente
correctas, aunque estos ltimos dos lenguajes son difciles de especificar con exactitud.

En el anlisis lxico, las operaciones ms importantes en los lenguajes son la unin, la


concatenacin y la cerradura.

- La unin es la operacin familiar que se hace con los conjuntos.


- La concatenacin de lenguajes es cuando se concatenan todas las cadenas que se
forman al tomar una cadena del primer lenguaje y una cadena del segundo lenguaje, en
todas las formas posibles.
- La cerradura (Kleene) de un lenguaje L, que se denota como L*, es el conjunto de
cadenas que se obtienen al concatenar L cero o ms veces. Observe que L0, la
concatenacin de L cero veces, se define como {}, y por induccin, Li es Li1L. Por

ltimo, la cerradura positiva, denotada como L+, es igual que la cerradura de Kleene,
pero sin el trmino L0. Es decir, no estar en L+ a menos que est en el mismo L.
.

Ejemplo: Sea L el conjunto de letras {A, B, ..., Z, a, b, ..., z} y sea D el conjunto de


dgitos {0, 1,...9}. Podemos pensar en L y D de dos formas, en esencia equivalentes.

Una forma es que L y D son, respectivamente, los alfabetos de las letras maysculas y
minsculas, y de los dgitos. La segunda forma es que L y D son lenguajes cuyas
cadenas tienen longitud de uno.

1. L D es el conjunto de letras y dgitos; hablando en sentido estricto, el lenguaje con


62 cadenas de longitud uno, y cada una de las cadenas es una letra o un dgito.

2. LD es el conjunto de 520 cadenas de longitud dos, cada una de las cuales consiste en
una letra, seguida de un dgito.
3. L4 es el conjunto de todas las cadenas de 4 letras.

4. L* es el conjunto de todas las cadenas de letras, incluyendo , la cadena vaca.


5. L(L D)* es el conjunto de todas las cadenas de letras y dgitos que empiezan con
una letra.

6. D+ es el conjunto de todas las cadenas de uno o ms dgitos.

1. L D es el conjunto de letras y dgitos; hablando en sentido estricto, el lenguaje con


62 cadenas de longitud uno, y cada una de las cadenas es una letra o un dgito.

2. LD es el conjunto de 520 cadenas de longitud dos, cada una de las cuales consiste en
una letra, seguida de un dgito.
3. L4 es el conjunto de todas las cadenas de 4 letras.

4. L* es el conjunto de todas las cadenas de letras, incluyendo , la cadena vaca.


5. L(L D)* es el conjunto de todas las cadenas de letras y dgitos que empiezan con
una letra.

6. D+ es el conjunto de todas las cadenas de uno o ms dgitos.

Patrn: es una expresin regular.


Token: es la categora lxica asociada a un patrn. Cada token se convierte en un

nmero o cdigo identificador nico. En algunos casos, cada nmero tiene asociada
informacin adicional necesaria para las fases posteriores de la etapa de anlisis. El
concepto de token coincide directamente con el concepto de terminal desde el punto

de vista de la gramtica utilizada por el analizador sintctico.

Lexema: Es cada secuencia de caracteres concreta que encaja con un patrn. P.ej: 8",
23" y 50" son algunos lexemas que encajan con el patrn (0'|1'|2'| ... |9') . El

nmero de lexemas que puede encajar con un patrn + puede ser finito o infinito, p.ej.
en el patrn WHILE slo encaja el lexema WHILE.
Una vez detectado que un grupo de caracteres coincide con un patrn, se considera que

se ha detectado un lexema. A continuacin se le asocia el nmero de su categora


lxica, y dicho nmero o token se le pasa al sintctico junto con informacin adicional,
si fuera necesario. Por ejemplo, si se necesita construir un analizador lxico que
reconozca los nmeros enteros, los nmeros reales y los identificadores de usuario en
minsculas, se puede proponer una estructura como.

Se presentara una herramienta conocida como Lex, o Flex en una implementacin ms


reciente, que nos permite especificar un analizador lxico mediante la especificacin de

expresiones regulares para describir patrones de los tokens. La notacin de entrada para la
herramienta Lex se conoce como el lenguaje Lex, y la herramienta en s es el compilador
Lex. El compilador Lex transforma los patrones de entrada en un diagrama de transicin y
genera cdigo, en un archivo llamado lex.yy.c, que simula este diagrama de transicin.

El lenguaje Lex describe el analizador lxico que se va a generar. El compilador Lex


transforma a lex.l en un programa en C, en un archivo que siempre se llama lex.yy.c. El

compilador de C compila este archivo en un archivo llamado a.out, como de costumbre. La


salida del compilador de C es un analizador lxico funcional, que puede recibir un flujo de
caracteres de entrada y producir una cadena de tokens.

El uso normal del programa compilado en C, denominado a.out,

es como una

subrutina del analizador sintctico. Es una funcin en C que devuelve un entero, el cual

representa un cdigo para uno de los posibles nombres de cada token. El valor del
atributo, ya sea otro cdigo numrico, un apuntador a la tabla de smbolos, o nada, se
coloca en una variable global llamada yylval,2 la cual se comparte entre el analizador
lxico y el analizador sintctico, con lo cual se simplifica el proceso de devolver tanto
el nombre como un valor de atributo de un token.

Un programa en Lex tiene la siguiente forma:


declaraciones
%%
reglas de traduccin
%%
funciones auxiliares
La seccin de declaraciones incluye las declaraciones de variables, constantes de
manifiesto (identificadores que se declaran para representar a una constante; por
ejemplo, el nombre de un token) y definiciones regulares. Cada una de las reglas de
traduccin tiene la siguiente forma:
Patrn { Accin }
Cada patrn es una expresin regular, la cual puede usar las definiciones regulares de la
seccin de declaraciones. Las acciones son fragmentos de cdigo, por lo general,
escritos en C, aunque se han creado muchas variantes de Lex que utilizan otros
lenguajes.

La tercera seccin contiene las funciones adicionales que se utilizan en las acciones.
De manera alternativa, estas funciones pueden compilarse por separado y cargarse con
el analizador lxico.
El analizador lxico que crea Lex trabaja en conjunto con el analizador sintctico de la
siguiente manera. Cuando el analizador sintctico llama al analizador lxico, ste
empieza a leer el resto de su entrada, un carcter a la vez, hasta que encuentra el prefijo
ms largo de la entrada que coincide con uno de los patrones Pi. Despus ejecuta la
accin asociada Ai. Por lo general, Ai regresar al analizador sintctico, pero si no lo
hace (tal vez debido a que Pi describe espacio en blanco o comentarios), entonces el
analizador lxico procede a buscar lexemas adicionales, hasta que una de las acciones
correspondientes provoque un retorno al analizador sintctico. El analizador lxico
devuelve un solo valor, el nombre del token, al analizador sintctico, pero utiliza la
variable entera compartida yylval para pasarle informacin adicional sobre el lexema
encontrado, si es necesario.

El yylex() generado por PCLex sigue dos directrices fundamentales para reconocer lexemas en caso de
ambigedad. Estas directrices son, por orden de prioridad:
1. Entrar siempre por el patrn que reconoce el lexema ms largo posible.
2. En caso de conflicto usa el patrn que aparece en primera posicin.
Como consecuencia de la segunda premisa: los patrones que reconocen palabras reservadas se colocan
siempre antes que el patrn de identificador de usuario. P.ej. un analizador lxico para Pascal (en el que
TYPE y VAR son palabras reservadas), podra tener una apariencia como:
%%
TYPE
VAR
[A-Z][A-Z0-9]*
...
Cuando yylex() se encuentra con la cadena VAR se produce un conflicto. Cambiar el orden de ambos
patrones tiene consecuencias funestas:
%%
TYPE
[A-Z][A-Z0-9]*
VAR
...
ya que esta vez el lexema VAR entrara por el patrn de identificador de usuario, y jams se
reconocera como una palabra reservada: el patrn VAR es superfluo.

Caracteres especiales de Lex


Lex se basa en el juego de caracteres ASCII para representar las expresiones regulares,
por lo que los caracteres que veremos a continuacin tienen un significado especial con
tal propsito:
: sirve para encerrar cualquier cadena de literales. Por regla general no es necesario
encerrar los literales entre comillas a no ser que incluyan smbolos especiales, esto es,
el patrn WHILE y el patrn WHILE son equivalentes; pero para representar p.ej. el
inicio de comentario en Modula-2 s es necesario entrecomillar los caracteres que
componen al patrn: (*, ya que ste contiene, a su vez, smbolos especiales.
\: hace literal al siguiente carcter. Ej.: \ reconoce unas comillas. Tambin se
utiliza para expresar aquellos caracteres que no tienen representacin directa
por pantalla: \n para el retorno de carro, \t para el tabulador, etc.

\noctal: representa el carcter cuyo valor ASCII es n octal. P.ej: \012 reconoce el
carcter decimal 10 que se corresponde con LF (Line Feed).

[ ]: permiten especificar listas de caracteres, o sea uno de los caracteres que encierra,
ej.: [abc] reconoce o la a, o la b, o la c, ( [abc] / (a|b|c) ).
Dentro de los corchetes los siguientes caracteres tambin tienen un sentido especial:
-: indica rango. Ej.: [A-Z0-9] reconoce cualquier carcter de la A a la Z o
del 0' a 9'.
^: indica complecin cuando aparece al comienzo, justo detrs de [.
Ej.: [^abc] reconoce cualquier carcter excepto la a, la b o la c.
Ej.: [^A-Z] reconoce cualquier carcter excepto los de la A a la Z.
?: aquello que le precede es opcional. Ej.: a? / ( a |
letra de la A a la Z o bien g. Ej.: a?b / ab | gb.

). Ej.: [A-Z]? Reconoce cualquier

.: representa a cualquier carcter (pero slo a uno) excepto el retorno de carro (\n). Es
muy interesante porque nos permite recoger cualquier otro carcter que no sea
reconocido por los patrones anteriores.

|: indica opcionalidad (OR). Ej.: a|b reconoce a la a o a la b. Ej.: .|\n reconoce


cualquier carcter. Resulta curioso el patrn (.|\n)* ya que por aqu entra el programa
entero, y como yylex() tiene la premisa de reconocer el lexema ms largo, pues
probablemente ignorar cualquier otro patrn. Tambin resulta probable que durante el
reconocimiento se produzca un error por desbordamiento del espacio de
almacenamiento de la variable yytext que, recordemos, almacena el lexema actual.
*: indica repeticin 0 o ms veces de lo que le precede.
+: indica repeticin 1 o ms veces de lo que le precede.
( ): permiten la agrupacin (igual que en las expresiones aritmticas).
{ }: indican rango de repeticin. Ej.: a{1,5} / aa?a?a?a? Las llaves vienen a ser algo
parecido a un * restringido. Tambin nos permite asignarle un nombre a una expresin
regular para reutilizarla en mltiples patrones.

Lex suministra ciertas capacidades para reconocer patrones que no se ajustan a una
expresin regular, sino ms bien a una gramtica de contexto libre. Esto es especialmente
til en determinadas circunstancias, como p.ej. para reconocer los comentarios de final de
lnea, admitidos por algunos lenguajes de programacin (los que suelen comenzar por // y se
extienden hasta el final de la lnea actual.
$: el patrn que le precede slo se reconoce si est al final de la lnea. Ej.: (a|b|cd)$. Que el
lexema se encuentre al final de la lnea quiere decir que viene seguido por un retorno de
carro, o bien por EOF. El carcter que identifica el final de la lnea no forma parte del
lexema.
^: fuera de los corchetes indica que el patrn que le sucede slo se reconoce si est al
comienzo de la lnea. Que el lexema se encuentre al principio de la lnea quiere decir que
viene precedido de un retorno de carro, o que se encuentra al principio del fichero. El
retorno de carro no pasa a formar parte del lexema. Ntese como las dos premisas de Lex
hacen que los patrones de sensibilidad al contexto deban ponerse en primer lugar en caso de
que existan ambigedades:
Programa 1
Programa 2
^casa
casa
casa
^casa

En ambos programas el lexema casa cuando se encuentra al comienzo de lnea puede


entrar por ambos patrones luego, al existir ambigedad, Lex selecciona el primero. Por
ello, ntese cmo en el primer programa se entra por el patrn adecuado mientras que
en el segundo se entra por el patrn general con lo que nunca se har uso del patrn
^casa.
/: Reconoce el patrn que le precede si y slo si es prefijo de una secuencia simple
como la que le sucede. Ej.: ab/c; en este caso si a la entrada se tiene abcd, se
reconocera el lexema ab porque est sucedido de c. Si la
entrada fuera abdc el patrn no se aplicara. Por otro lado, un patrn como ab/c+ es
errneo puesto que el patrn c+ no se considera simple.

Los estados lxicos vienen a ser como variables lgicas excluyentes (una y slo una
puede estar activa cada vez) que sirven para indicar que un patrn slo puede aplicarse
si el estado lxico que lleva asociado se encuentra activado. En los ejemplos que hemos
visto hasta ahora hemos trabajado con el estado lxico por defecto que, tambin por
defecto, se encuentra activo al comenzar el trabajo de yylex(). Por ser un estado lxico
por defecto no hemos tenido que hacer ninguna referencia explcita a l.
Los distintos estados lxicos (tambin llamados condiciones start) se declaran en el
rea de definiciones Lex de la forma:
%START id1, id2, ...
Una accin asociada a un patrn puede activar un estado lxico ejecutando la macro
BEGIN, que es suministrada por el programa generado por PCLex. As:
BEGIN idi;
activara la condicin start idi, que ha debido ser previamente declarada. La activacin
de un estado lxico produce automticamente la desactivacin de todos los dems. Por
otro lado, el estado lxico por defecto puede activarse con:
BEGIN 0;

Para indicar que un patrn slo es candidato a aplicarse en caso de que se encuentre
activa la condicin start idi, se le antepone la cadena <idi>. Si un patrn no tiene
asociada condicin start explcita, se asume que tiene asociado el estado lxico por
defecto.
El siguiente ejemplo muestra cmo visualizar todos los nombres de los procedimientos
y funciones de un programa Modula-2:
%START PROC
%%
PROCEDURE {BEGIN PROC;}
<PROC> [a-zA-Z][a-zA-Z0-9]* { printf (%s\n, yytext);
BEGIN 0 ; }

El rea de definiciones de un programa Lex tiene tres utilidades fundamentales:


a) Definir los estados lxicos.
b) Asignar un nombre a los patrones ms frecuentes.
c) Poner cdigo C que ser global a todo el programa.
Ya hemos visto cmo definir estados lxicos, por lo que pasaremos a estudiar las otras dos
posibilidades.
En el rea de definiciones podemos crear expresiones regulares auxiliares de uso frecuente y
asignarles un nombre. Posteriormente, estos patrones pueden ser referenciados en el rea de
reglas sin ms que especificar su nombre entre llaves: {}.
Por ejemplo, los siguientes dos programas son equivalentes, pero el primero es ms claro y
sus reglas ms concisas:
Programa 1
Programa 2
D [0-9]
%%
L [a-zA-Z]
[0-9]+
%%
[a-zA-Z][a-zA-Z0-9]*
{D}+
{L}({L}|{D})*

En Lex todo debe comenzar en la primera columna. Si algo no comienza en dicha columna,
PCLex lo pasa directamente al programa C generado, sin procesarlo. De esta forma es
posible crear definiciones de variables, etc. Sin embargo, esto no se recomienda ya que Lex
posee un bloque especfico para esto en el que se pueden poner incluso directivas del
procesador, que deben comenzar obligatoriamente en la primera columna.
As, el rea de definiciones tambin permite colocar cdigo C puro que se trasladar tal cual
al comienzo del programa en C generado por PCLex. Para ello se usan los delimitadores
%{ y %}. Ej.:
%{
#include <stdlib.h>
typedef struct _Nodo{
int valor;
Nodo * siguiente;
} Nodo;
Nodo * tablaDeSimbolos;
%}
Es normal poner en esta zona las declaraciones de variables globales utilizadas en las
acciones del rea de reglas y un #include del fichero que implementa la tabla de
smbolos.

Es normal poner en esta zona las declaraciones de variables globales utilizadas en las acciones del rea de reglas
y un #include del fichero que implementa la tabla de smbolos.
PCLex no genera main() alguno, sino que ste debe ser especificado por el programador. Por regla general,
cuando se pretende ejecutar aisladamente un analizador lxico (sin un sintctico asociado), lo normal es que las
acciones asociadas a cada regla no contengan ningn return y que se incluya un main() que nicamente invoque
a yylex():
void main(){
yylex();
};
Para especificar el main() y cuantas funciones adicionales se estimen oportunas, se dispone del rea de
funciones. Dicha rea es ntegramente copiada por PCLex en el fichero C generado. Es por ello que, a efectos
prcticos, escribir cdigo entre %{ y %} en el rea de definiciones es equivalente a escribirlo en el rea de
funciones.
El siguiente ejemplo informa de cuntas veces aparece el literal resultado en la cadena de entrada.
%{
int cont=0;
%}
%%
resultado {cont ++;}
. | \n {;}
%%
void main(){
yylex();
printf(resultado aparece %d veces, cont);
}

El ncleo bsico del programa en C generado por PCLex es la funcin yylex(), que se encarga de buscar un
lexema y ejecutar su accin asociada. Este proceso lo realiza iterativamente hasta que en una de las acciones se
encuentre un return o se acabe la entrada. Adems, PCLex suministra otras funciones macros y variables de
apoyo; entre los que tenemos:
yylex(): implementa el analizador lexicogrfico.
yytext: contiene el lexema actual
yyleng: nmero de caracteres del lexema actual.
yylval: es una variable global que permite la comunicacin con el sintctico.
Realmente no la define PCLex sino la herramienta PCYacc
yyin: es de tipo *FILE, y apunta al fichero de entrada que se lee. Inicialmente apunta a stdin, por lo que el
fichero de entrada coincide con la entrada estndar.
yyout: de tipo *FILE, apunta al fichero de salida (inicialmente stdout).
yyerror() : es una funcin que se encarga de emitir y controlar errores (saca mensajes de error por pantalla).
Realmente es definida por PCYacc
yylineno: variable de tipo entero que, curiosamente, debe ser creada, inicializada y actualizada por el
programador. Sirve para mantener la cuenta del nmero de lnea que se est procesando. Normalmente se
inicializa a 1 y se incrementa cada vez que se encuentra un retorno de carro.
yywrap(): el algoritmo de yylex() llama automticamente a esta macro cada vez que se encuentra con un EOF.
La utilidad de esta macro reside en que puede ser redefinida (para ello hay que borrarla previamente con la
directiva #undef). Esta macro debe devolver false (que en C se representa por el entero 0) en caso de que la
cadena de entrada no haya finalizado realmente, lo que puede suceder en dos tipos de situaciones: a) se est
procesando un fichero binario que puede contener por en medio el carcter EOF como uno ms, en cuyo caso el
verdadero final del fichero hay que descubrirlo contrastando la longitud del fichero con la longitud de la cadena
consumida; y b) la cadena a reconocer se encuentra particionada en varios ficheros, en cuyo caso cuando se
llega al final de uno de ellos, hay que cargar en yyin el siguiente y continuar el procesamiento. yywrap() debe
devolver true (valor entero 1) en caso de que el EOF encontrado identifique realmente el final de la cadena a
Procesar.

yyless(int n): deja en yytext los n primeros caracteres del lexema actual. El resto los devuelve a la entrada, por lo que podemos decir que son desconsumidos. yyleng tambin se modifica convenientemente. Por ejemplo, el patrn abc*/\n es equivalente a:
abc*\n { yyless(yyleng-1); }
input(): consume el siguiente carcter de la entrada y lo aade al lexema actual. P,ej., el programa:
%%
abc { printf (%s, yytext);
input( );
printf(%s, yytext);}
ante la entrada abcde entrara por este patrn: el lexema antes del input() (en el primer printf) es abc, y despus del input (en el segundo printf) es
abcd.
output(char c): emite el carcter c por la salida estndar. PCLex para DOS no soporta esta funcin, pero s el Lex para Unix.
unput(char c): des-consume el carcter c y lo coloca al comienzo de la entrada. P.ej., supongamos que el programa:
%%
abc { printf (%s,yytext); unput(t); }
tal { printf (%s,yytext); }
recibe la entrada abcal. Los tres primeros caracteres del lexema coinciden con el primer patrn. Despus queda en la entrada la cadena al, pero como se
ha hecho un unput(t), lo que hay realmente a la entrada es tal, que coincide con el segundo patrn.
ECHO: macro que copia la entrada en la salida (es la accin que se aplica por defecto a los lexemas que no encajan por ningn patrn explcito).
yymore(): permite pasar a reconocer el siguiente lexema, pero sin borrar el contenido actual de yytext, por lo que el nuevo lexema ledo se concatena al ya
existente. PCLex para DOS no soporta esta funcin, pero s el Lex para Unix.
La utilidad principal de yymore() reside en que facilita el reconocer los literales entrecomillados. Supongamos que se desea construir un patrn para
reconocer literales entrecomillados. Una primera idea podra ser el patrn:
\[^\]*\ /* Lexemas que empiecen por comillas,
cualquier cosa, y termine en comillas. */
que reconocera cadenas como Hola, adis, e incluso Ho;*. Sin embargo una cadena como Hola, \camarada\ que, a su vez contiene comillas
dentro, dar problemas porque la primera comilla de camarada, es considerada como unas comillas de cierre. La solucin a este problema pasa por el
siguiente bloque de cdigo Lex:
\[^\]*/\ { if (yytext[yyleng-1]==\\)

\[^\]*/\ { if (yytext[yyleng-1]==\\)
yymore();
else
input();}
Este patrn reconoce cadenas entrecomilladas (excepto las ltimas comillas), de forma
que las cadenas que tienen dentro comillas se reconocen por partes. Siguiendo con el
ejemplo de antes, Hola, \camarada\ se reconocera como:

Este patrn fallara si los caracteres anteriores a las comillas de cierre fuesen precisamente \\. Para
solucionarlo habra que hacer uso de unput y de una variable global que actuase como flag. Cualquier sentencia
que haya detrs de yymore() nunca se ejecutar, ya que acta como una especie de goto.
REJECT: rechaza el lexema actual, lo devuelve a la entrada y busca otro patrn.
REJECT le dice a yylex() que el lexema encontrado no corresponde realmente a la expresin regular en curso, y
que busque la siguiente expresin regular a que corresponda. La macro REJECT debe ser lo ltimo que una
accin ejecute puesto que si hay algo detrs, no se ejecutar. P.ej. Para buscar cuntas veces aparecen las
palabras teclado y lado, se puede construir el siguiente programa Lex:
%{
int t=0, l=0;
%}
%%
teclado {t ++; REJECT;}
lado {l ++;}
Ante la entrada teclado este programa se comporta de la siguiente forma:
1.- Entra por el patrn que lee el lexema ms largo que sera teclado y ejecuta la accin asociada: se
incrementa la variable t y se rechaza el lexema actual, por lo que el texto entero se devuelve a la entrada.
2.- Saca por pantalla tec que es la accin por defecto cuando se encuentran caracteres que no encajan con
ningn patrn.
3.- El lexema lado coincide con el segundo patrn y ejecuta la accin asociada: se incrementa la variable l.
Para finalizar, resulta evidente que el programador no debe declarar ninguna funcin o variable cuyo nombre
coincida con las que acabamos de estudiar. De hecho PCLex tambin genera una serie de variables auxiliares
cuyo nombre consta de un solo carcter, por lo que tampoco es bueno declarar variables o funciones con
nombres de una sola letra ni que empiecen por yy.

Anda mungkin juga menyukai