Provided by: manpages-es-extra_0.8a-17_all bug

NOMBRE

       flex - generador de analizadores lexicos rapidos

SINOPSIS

       flex    [-bcdfhilnpstvwBFILTV78+?    -C[aefFmr]    -osalida   -Pprefijo
       -Sesqueleto] [--help --version] [nombrefichero ...]

INTRODUCCI'ON

       Este manual describe  flex,  una  herramienta  para  la  generacion  de
       programas  que  realizan  concordancia de patrones en texto.  El manual
       incluye a la vez secciones de tutorial y de referencia:

           Descripcion
               una breve introduccion a la herramienta

           Algunos Ejemplos Simples

           Formato del Fichero de Entrada

           Patrones
               las expresiones regulares extendidas que utiliza flex

           Como se Empareja la Entrada
               las reglas para determinar lo que ha concordado

           Acciones
               como especificar que hacer cuando concuerde un patron

           El Escaner Generado
               detalles respecto al escaner que produce flex;
               como controlar la fuente de entrada

           Condiciones de Arranque
               la introducion de contexto en sus escaneres, y
               conseguir "mini-escaneres"

           Multiples Buffers de Entrada
               como manipular varias fuentes de entrada; como
               analizar cadenas en lugar de ficheros.

           Reglas de Fin-de-Fichero
               reglas especiales para reconocer el final de la entrada

           Macros Miscelaneas
               un sumario de macros disponibles para las acciones

           Valores Disponibles para el Usuario
               un sumario de valores disponibles para las acciones

           Interfaz con Yacc
               conectando escaneres de flex junto con analizadores de yacc

           Opciones
               opciones de linea de comando de flex, y la directiva
               "%option"

           Consideraciones de Rendimiento
               como hacer que sus analizadores vayan tan rapido
               como sea posible

           Generando Escaneres en C++
               la facilidad (experimental) para generar analizadores
               lexicos como clases de C++

           Incompatibilidades con Lex y POSIX
               como flex difiere del lex de AT&T y del lex estandar
               de POSIX

           Diagnosticos
               esos mensajes de error producidos por flex (o por
               los escaneres que este genera) cuyo significado podria
               no ser evidente

           Ficheros
               los ficheros usados por flex

           Deficiencias / Errores
               problemas de flex conocidos

           Ver Tambien
               otra documentacion, herramientas relacionadas

           Autor
               incluye informacion de contacto

DESCRIPCI'ON

       flex es una herramienta para generar esc'aneres: programas que reconocen
       patrones  lexicos en un texto.  flex lee los ficheros de entrada dados,
       o la entrada estandar si no se le ha indicado ningun nombre de fichero,
       con  la  descripcion  de  un  escaner  a  generar.   La  descripcion se
       encuentra en forma de parejas de  expresiones  regulares  y  codigo  C,
       denominadas  reglas.  flex  genera  como salida un fichero fuente en C,
       lex.yy.c, que define una rutina yylex().  Este fichero se compila y  se
       enlaza  con  la  libreria  -lfl para producir un ejecutable.  Cuando se
       arranca el fichero ejecutable, este analiza  su  entrada  en  busca  de
       casos de las expresiones regulares.  Siempre que encuentra uno, ejecuta
       el codigo C correspondiente.

ALGUNOS EJEMPLOS SIMPLES

       En primer lugar veremos algunos  ejemplos  simples  para  una  toma  de
       contacto  con  el uso de flex.  La siguiente entrada de flex especifica
       un  escaner  que  siempre  que  encuentre  la  cadena   "username"   la
       reemplazara por el nombre de entrada al sistema del usuario:

           %%
           username    printf( "%s", getlogin() );

       Por  defecto,  cualquier texto que no reconozca el analizador lexico de
       flex se copia a la salida, asi que el efecto neto de  este  escaner  es
       copiar  su  fichero  de  entrada  a  la  salida  con  cada aparicion de
       "username" expandida.   En  esta  entrada,  hay  solamente  una  regla.
       "username"  es  el patr'on y el "printf" es la acci'on.  El "%%" marca el
       comienzo de las reglas.

       Aqui hay otro ejemplo simple:

                   int num_lineas = 0, num_caracteres = 0;

           %%
           \n      ++num_lineas; ++num_caracteres;
           .       ++num_caracteres;

           %%
           main()
                   {
                   yylex();
                   printf( "# de lineas = %d, # de caracteres. = %d\n",
                           num_lineas, num_caracteres );
                   }

       Este analizador cuenta el numero de caracteres y el numero de lineas en
       su  entrada (no produce otra salida que el informe final de la cuenta).
       La  primera  linea  declara  dos  variables  globales,  "num_lineas"  y
       "num_caracteres",  que son visibles al mismo tiempo dentro de yylex() y
       en la rutina main()  declarada  despues  del  segundo  "%%".   Hay  dos
       reglas,  una que empareja una linea nueva ("\n") e incrementa la cuenta
       de lineas y la cuenta  de  caracteres,  y  la  que  empareja  cualquier
       caracter  que no sea una linea nueva (indicado por la expresion regular
       ".").

       Un ejemplo algo mas complicado:

           /* escaner para un lenguaje de juguete al estilo de Pascal */

           %{
           /* se necesita esto para la llamada a atof() mas abajo */
           #include <math.h>
           %}

           DIGITO   [0-9]
           ID       [a-z][a-z0-9]*

           %%

           {DIGITO}+   {
                       printf( "Un entero: %s (%d)\n", yytext,
                               atoi( yytext ) );
                       }

           {DIGITO}+"."{DIGITO}*      {
                       printf( "Un real: %s (%g)\n", yytext,
                               atof( yytext ) );
                       }

           if|then|begin|end|procedure|function        {
                       printf( "Una palabra clave: %s\n", yytext );
                       }

           {ID}        printf( "Un identificador: %s\n", yytext );

           "+"|"-"|"*"|"/"   printf( "Un operador: %s\n", yytext );

           "{"[^}\n]*"}"     /* se come una linea de comentarios */

           [ \t\n]+          /* se come los espacios en blanco */

           .           printf( "Caracter no reconocido: %s\n", yytext );

           %%

           main( argc, argv )
           int argc;
           char **argv;
               {
               ++argv, --argc;  /* se salta el nombre del programa */
               if ( argc > 0 )
                       yyin = fopen( argv[0], "r" );
               else
                       yyin = stdin;

               yylex();
               }

       Esto podria ser los comienzos de un escaner  simple  para  un  lenguaje
       como  Pascal.   Este  identifica diferentes tipos de tokens e informa a
       cerca de lo que ha visto.

       Los detalles de este ejemplo se explicaran en las secciones siguientes.

FORMATO DEL FICHERO DE ENTRADA

       El fichero de  entrada  de  flex  esta  compuesto  de  tres  secciones,
       separadas por una linea donde aparece unicamente un %% en esta:

           definiciones
           %%
           reglas
           %%
           codigo de usuario

       La  seccion  de  definiciones contiene declaraciones de definiciones de
       nombres sencillas para simplificar la  especificacion  del  escaner,  y
       declaraciones  de  condiciones  de  arranque,  que se explicaran en una
       seccion posterior.

       Las definiciones de nombre tienen la forma:

           nombre definicion

       El "nombre" es una palabra que comienza con una letra  o  un  subrayado
       ('_')  seguido  por cero o mas letras, digitos, '_', o '-' (guion).  La
       definicion se considera que comienza en el primer caracter que  no  sea
       un  espacio  en blanco siguiendo al nombre y continuando hasta el final
       de la linea.  Posteriormente se puede hacer referencia a la  definicion
       utilizando "{nombre}", que se expandira a "(definicion)".  Por ejemplo,

           DIGITO   [0-9]
           ID       [a-z][a-z0-9]*

       define  "DIGITO"  como  una  expresion  regular  que empareja un digito
       sencillo, e "ID" como una expresion  regular  que  empareja  una  letra
       seguida por cero o mas letras o digitos.  Una referencia posterior a

           {DIGITO}+"."{DIGITO}*

       es identica a

           ([0-9])+"."([0-9])*

       y  empareja uno o mas digitos seguido por un '.' seguido por cero o mas
       digitos.

       La seccion de reglas en la entrada de flex contiene una serie de reglas
       de la forma:

           patron   accion

       donde  el patron debe estar sin sangrar y la accion debe comenzar en la
       misma linea.

       Ver mas  abajo  para  una  descripcion  mas  amplia  sobre  patrones  y
       acciones.

       Finalmente,  la  seccion  de  codigo  de usuario simplemente se copia a
       lex.yy.c  literalmente.   Esta  seccion  se  utiliza  para  rutinas  de
       complemento  que  llaman  al  escaner  o  son  llamadas  por  este.  La
       presencia de esta seccion es opcional; Si se omite, el segundo %% en el
       fichero de entrada se podria omitir tambien.

       En  las  secciones de definiciones y reglas, cualquier texto sangrado o
       encerrado entre %{ y %} se copia integramente  a  la  salida  (sin  los
       %{}'s).   Los  %{}'s  deben  aparecer  sin  sangrar  en lineas ocupadas
       unicamente por estos.

       En la seccion de reglas, cualquier texto o %{}  sangrado  que  aparezca
       antes de la primera regla podria utilizarse para declarar variables que
       son locales a la rutina de analisis y (despues de las declaraciones) al
       codigo  que  debe  ejecutarse  siempre  que  se  entra  a  la rutina de
       analisis.  Cualquier otro texto sangrado o %{} en la seccion de  reglas
       sigue copiandose a la salida, pero su significado no esta bien definido
       y bien podria causar errores en tiempo de compilacion  (esta  propiedad
       se  presenta  para  conformidad  con  POSIX  ; ver mas abajo para otras
       caracteristicas similares)

       En la seccion de definiciones (pero no en la  seccion  de  reglas),  un
       comentario  sin  sangria  (es  decir,  una  linea  comenzando con "/*")
       tambien se copia literalmente a la salida hasta el proximo "*/".

PATRONES

       Los patrones en la entrada se escriben utilizando un conjunto extendido
       de expresiones regulares.  Estas son:

           x          empareja el caracter 'x'
           .          cualquier caracter (byte) excepto una linea nueva
           [xyz]      una "clase de caracteres"; en este caso, el patron
                        empareja una 'x', una 'y', o una 'z'
           [abj-oZ]   una "clase de caracteres" con un rango; empareja
                        una 'a', una 'b', cualquier letra desde la 'j'
                        hasta la 'o', o una 'Z'
           [^A-Z]     una "clase de caracteres negada", es decir, cualquier
                        caracter menos los que aparecen en la clase.  En
                        este caso, cualquier caracter EXCEPTO una letra
                        mayuscula.
           [^A-Z\n]   cualquier caracter EXCEPTO una letra mayuscula o
                        una linea nueva
           r*         cero o mas r's, donde r es cualquier expresion regular
           r+         una o mas r's
           r?         cero o una r (es decir, "una r opcional")
           r{2,5}     donde sea de dos a cinco r's
           r{2,}      dos o mas r's
           r{4}       exactamente 4 r's
           {nombre}   la expansion de la definicion de "nombre"
                      (ver mas abajo)
           "[xyz]\"foo"
                      la cadena literal: [xyz]"foo
           \X         si X es una 'a', 'b', 'f', 'n', 'r', 't', o 'v',
                        entonces la interpretacion ANSI-C de \x.
                        En otro caso, un literal 'X' (usado para
                        indicar operadores tales como '*')
           \0         un caracter NUL (codigo ASCII 0)
           \123       el caracter con valor octal 123
           \x2a       el caracter con valor hexadecimal 2a
           (r)        empareja una r; los parentesis se utilizan para
                        anular la precedencia (ver mas abajo)

           rs         la expresion regular r seguida por la expresion
                        regular s; se denomina "concatenacion"

           r|s        bien una r o una s

           r/s        una r pero solo si va seguida por una s.  El
                        texto emparejado por s se incluye cuando se
                        determina si esta regla es el "emparejamiento
                        mas largo", pero se devuelve entonces a la
                        entrada antes que se ejecute la accion.  Asi
                        que la accion solo ve el texto emparejado
                        por r.  Este tipo de patrones se llama
                        "de contexto posterior".
                        (Hay algunas combinaciones de r/s que flex
                        no puede emparejar correctamente; vea las notas
                        en la seccion Deficiencias / Errores mas abajo
                        respecto al "contexto posterior peligroso".)
           ^r         una r, pero solo al comienzo de una linea (es
                        decir, justo al comienzo del analisis, o a la
                        derecha despues de que se haya analizado una
                        linea nueva).
           r$         una r, pero solo al final de una linea (es decir,
                        justo antes de una linea nueva).  Equivalente
                        a "r/\n".

                      Fijese que la nocion de flex de una "linea nueva"
                      es exactamente lo que el compilador de C utilizado
                      para compilar flex interprete como '\n'; en
                      particular, en algunos sistemas DOS debe filtrar
                      los \r's de la entrada used mismo, o explicitamente
                      usar r/\r\n para "r$".

           <s>r       una r, pero solo en la condicion de arranque s
                        (ver mas abajo para una discusion sobre las
                        condiciones de arranque)
           <s1,s2,s3>r
                      lo mismo, pero en cualquiera de las condiciones
                        de arranque s1, s2, o s3
           <*>r       una r en cualquier condicion de arranque, incluso
                        una exclusiva.

           <<EOF>>    un fin-de-fichero
           <s1,s2><<EOF>>
                      un fin-de-fichero en una condicion de arranque s1 o s2

       Fijese  que  dentro de una clase de caracteres, todos los operadores de
       expresiones  regulares  pierden  su  significado  especial  excepto  el
       caracter de escape ('\') y los operadores de clase de caracteres, '-',

       Las  expresiones  regulares  en  el listado anterior estan agrupadas de
       acuerdo a la precedencia, desde la precedencia mas alta en la cabeza  a
       la mas baja al final.  Aquellas agrupadas conjuntamente tienen la misma
       precedencia.  Por ejemplo,

           foo|bar*

       es lo mismo que

           (foo)|(ba(r*))

       ya que el operador '*' tiene mayor precedencia que la concatenacion,  y
       la  concatenacion  mas  alta  que  el operador '|'.  Este patron por lo
       tanto empareja bien la cadena "foo" o la cadena "ba" seguida de cero  o
       mas r's.  Para emparejar "foo" o, cero o mas "bar"'s, use:

           foo|(bar)*

       y para emparejar cero o mas "foo"'s o "bar"'s:

           (foo|bar)*

       Ademas  de  caracteres y rangos de caracteres, las clases de caracteres
       pueden tambien contener  expresiones  de  clases  de  caracteres.   Son
       expresiones  encerradas  entre  los  delimitadores [: y :] (que tambien
       deben aparecer entre el '[' y el ']' de la clase de caracteres;  ademas
       pueden  darse  otros  elementos dentro de la clase de caracteres).  Las
       expresiones validas son:

           [:alnum:] [:alpha:] [:blank:]
           [:cntrl:] [:digit:] [:graph:]
           [:lower:] [:print:] [:punct:]
           [:space:] [:upper:] [:xdigit:]

       Todas estas expresiones designan un conjunto de caracteres equivalentes
       a  la  correspondiente  funcion  estandar  isXXX  de  C.   Por ejemplo,
       [:alnum:]  designa  aquellos  caracteres  para  los  cuales   isalnum()
       devuelve verdadero - esto es, cualquier caracter alfabetico o numerico.
       Algunos sistemas no ofrecen isblank(), asi que  flex  define  [:blank:]
       como un espacio en blanco o un tabulador.

       Por   ejemplo,   las   siguientes   clases   de  caracteres  son  todas
       equivalentes:

           [[:alnum:]]
           [[:alpha:][:digit:]]
           [[:alpha:]0-9]
           [a-zA-Z0-9]

       Si su escaner ignora la distincion entre mayusculas  y  minusculas  (la
       bandera  -i  ),  entonces  [:upper:]  y  [:lower:]  son  equivalentes a
       [:alpha:].

       Algunas notas sobre los patrones:

       -      Una clase de caracteres negada  tal  como  el  ejemplo  "[^A-Z]"
              anterior  emparejar'a  una  l'inea  nueva  a menos que "\n" (o una
              secuencia de escape  equivalente)  sea  uno  de  los  caracteres
              presentes  explicitamente  en  la  clase  de  caracteres  negada
              (p.ej., "[^A-Z\n]").  Esto es diferente a  como  muchas  de  las
              otras herramientas de expresiones regulares tratan las clases de
              caracteres negadas, pero  desafortunadamente  la  inconsistencia
              esta fervientemente enrraizada historicamente.  Emparejar lineas
              nuevas significa que un patron como  [^"]*  puede  emparejar  la
              entrada completa a menos que haya otra comilla en la entrada.

       -      Una  regla  puede  tener  lo  mas  una  instancia  del  contexto
              posterior (el operador '/' o el operador '$').  La condicion  de
              arranque,   los   patrones  '^',  y  "<<EOF>>"  pueden  aparecer
              solamente al principio de un patron, y, al igual que con  '/'  y
              '$',  no  pueden  agruparse dentro de parentesis.  Un '^' que no
              aparezca al principio de una regla o un '$' que no  aparezca  al
              final  de  una  regla  pierde  sus  propiedades  especiales y es
              tratado como un caracter normal.

              Lo siguiente no esta permitido:

                  foo/bar$
                  <sc1>foo<sc2>bar

              Fijese que la primera regla se puede escribir como "foo/bar\n".

              En el siguiente ejemplo un '$' o  un  '^'  es  tratado  como  un
              caracter normal:

                  foo|(bar$)
                  foo|^bar

              Si  lo  que se desea es un "foo" o un "bar" seguido de una linea
              nueva, puede usarse lo siguiente  (la  accion  especial  '|'  se
              explica mas abajo):

                  foo      |
                  bar$     /* la accion va aqui */

              Un truco parecido funcionara para emparejar un "foo" o, un "bar"
              al principio de una linea.

C'OMO SE EMPAREJA LA ENTRADA

       Cuando el escaner generado esta funcionando, este  analiza  su  entrada
       buscando  cadenas  que  concuerden  con cualquiera de sus patrones.  Si
       encuentra mas de un emparejamiento, toma  el  que  empareje  mas  texto
       (para  reglas de contexto posterior, se incluye la longitud de la parte
       posterior, incluso si se devuelve a la entrada).  Si  encuentra  dos  o
       mas emparejamientos de la misma longitud, se escoge la regla listada en
       primer lugar en el fichero de entrada de flex.

       Una vez que se determina el emparejamiento, el texto correspondiente al
       emparejamiento  (denominado  el  token) esta disponible en el puntero a
       caracter global yytext, y su longitud  en  la  variable  global  entera
       yyleng.   Entonces  la  acci'on  correspondiente al patron emparejado se
       ejecuta  (una  descripcion  mas  detallada  de  las  acciones  viene  a
       continuacion),  y  entonces  la  entrada  restante se analiza para otro
       emparejamiento.

       Si no se encuentra un emparejamiento, entonces se ejecuta la regla  por
       defecto:  el siguiente caracter en la entrada se considera reconocido y
       se copia a la salida estandar.  Asi, la entrada valida  mas  simple  de
       flex es:

           %%

       que  genera  un escaner que simplemente copia su entrada (un caracter a
       la vez) a la salida.

       Fijese que yytext se puede definir de dos maneras diferentes: bien como
       un  puntero  a  caracter  o  como  un array de caracteres.  Usted puede
       controlar la definicion que usa flex incluyendo una de  las  directivas
       especiales %pointer o %array en la primera seccion (definiciones) de su
       entrada de flex.  Por defecto es %pointer, a menos que use la opcion de
       compatibilidad  -l,  en  cuyo caso yytext sera un array.  La ventaja de
       usar %pointer es un analisis substancialmente mas rapido y la  ausencia
       de  desbordamiento del buffer cuando se emparejen tokens muy grandes (a
       menos que se agote la memoria  dinamica).   La  desventaja  es  que  se
       encuentra restringido en como sus acciones pueden modificar yytext (vea
       la siguiente seccion), y las llamadas a la funcion unput() destruyen el
       contenido  actual  de  yytext, que puede convertirse en un considerable
       quebradero de  cabeza  de  portabilidad  al  cambiar  entre  diferentes
       versiones de lex.

       La  ventaja de %array es que entoces puede modificar yytext todo lo que
       usted quiera, las llamadas a  unput()  no  destruyen  yytext  (ver  mas
       abajo).   Ademas,  los  programas  de  lex existentes a veces acceden a
       yytext externamente utilizando declaraciones de la forma:
           extern char yytext[];
       Esta definicion es erronea cuando se utiliza  %pointer,  pero  correcta
       para %array.

       %array  define  a  yytext  como  un array de YYLMAX caracteres, que por
       defecto es un valor bastante grande.  Usted  puede  cambiar  el  tamano
       simplemente  definiendo  con #define a YYLMAX con un valor diferente en
       la primera seccion de su entrada de flex.  Como se menciono antes,  con
       %pointer  yytext  crece  dinamicamente  para  acomodar  tokens grandes.
       Aunque esto signifique que  con  %pointer  su  escaner  puede  acomodar
       tokens   muy   grandes   (tales   como  emparejar  bloques  enteros  de
       comentarios), tenga presente que cada vez que el escaner  deba  cambiar
       el tamano de yytext tambien debe reiniciar el analisis del token entero
       desde el principio, asi  que  emparejar  tales  tokens  puede  resultar
       lento.   Ahora  yytext  no crece dinamicamente si una llamada a unput()
       hace que se deba devolver demasiado texto; en su lugar, se  produce  un
       error en tiempo de ejecucion.

       Tambien  tenga  en  cuenta que no puede usar %array en los analizadores
       generados como clases de C++ (la opcion c++; vea mas abajo).

ACCIONES

       Cada patron en una regla tiene  una  accion  asociada,  que  puede  ser
       cualquier  sentencia en C.  El patron finaliza en el primer caracter de
       espacio en blanco que no sea una secuencia de escape; lo que  queda  de
       la  linea  es  su  accion.  Si la accion esta vacia, entonces cuando el
       patron se empareje el token de entrada simplemente  se  descarta.   Por
       ejemplo, aqui esta la especificacion de un programa que borra todas las
       apariciones de "zap me" en su entrada:

           %%
           "zap me"

       (Este copiara el resto de caracteres de la entrada a la salida  ya  que
       seran emparejados por la regla por defecto.)

       Aqui  hay  un  programa  que  comprime  varios  espacios  en  blanco  y
       tabuladores a un solo espacio en blanco, y desecha los espacios que  se
       encuentren al final de una linea:

           %%
           [ \t]+        putchar( ' ' );
           [ \t]+$       /* ignora este token */

       Si  la  accion  contiene un '{', entonces la accion abarca hasta que se
       encuentre el correspondiente '}', y la accion  podria  entonces  cruzar
       varias lineas.  flex es capaz de reconocer las cadenas y comentarios de
       C y no se dejara enganar por las llaves que encuentre dentro de  estos,
       pero  aun  asi  tambien  permite  que  las  acciones comiencen con %{ y
       considerara que la accion es todo el texto hasta el siguiente  %}  (sin
       tener en cuenta las llaves ordinarias dentro de la accion).

       Una accion que consista solamente de una barra vertical ('|') significa
       "lo mismo que la accion para la siguiente regla."  Vea mas  abajo  para
       una ilustracion.

       Las  acciones  pueden incluir codigo C arbitrario, incuyendo sentencias
       return para devolver un valor desde cualquier rutina  llamada  yylex().
       Cada  vez  que se llama a yylex() esta continua procesando tokens desde
       donde lo dejo la ultima vez hasta  que  o  bien  llegue  al  final  del
       fichero o ejecute un return.

       Las  acciones  tienen  libertad  para  modificar  yytext  excepto  para
       alargarla (anadiendo caracteres al final--esto sobreescribira mas tarde
       caracteres  en  el  flujo  de  entrada).  Sin embargo esto no se aplica
       cuando se utiliza %array (ver  arriba);  en  ese  caso,  yytext  podria
       modificarse libremente de cualquier manera.

       Las acciones tienen libertad para modificar yyleng excepto que estas no
       deberian hacerlo si la accion tambien incluye el uso de  yymore()  (ver
       mas abajo).

       Hay  un  numero de directivas especiales que pueden incluirse dentro de
       una accion:

       -      ECHO copia yytext a la salida del escaner.

       -      BEGIN seguido del nombre de la condicion  de  arranque  pone  al
              escaner  en  la  condicion  de arranque correspondiente (ver mas
              abajo).

       -      REJECT ordena al escaner a que proceda con  la  "segunda  mejor"
              regla que concuerde con la entrada (o un prefijo de la entrada).
              La regla se escoge como se describio anteriormente en  "Como  se
              Empareja  la  Entrada",  y  yytext  e yyleng se ajustan de forma
              apropiada.  Podria ser una que  empareje  tanto  texto  como  la
              regla  escogida  originalmente  pero  que  viene mas tarde en el
              fichero de entrada de flex, o una que empareje menos texto.  Por
              ejemplo,  lo que viene a continuacion contara las palabras en la
              entrada y llamara a la rutina especial() siempre que vea "frob":

                          int contador_palabras = 0;
                  %%

                  frob        especial(); REJECT;
                  [^ \t\n]+   ++contador_palabras;

              Sin el REJECT, cualquier numero de "frob"'s  en  la  entrada  no
              serian  contados  como  palabras,  ya que el escaner normalmente
              ejecuta solo una  accion  por  token.   Se  permite  el  uso  de
              multiples   REJECT's,  cada  uno  buscando  la  siguiente  mejor
              eleccion a la regla que actualmente este activa.   Por  ejemplo,
              cuando  el  siguiente  escaner  analice  el  token  "abcd", este
              escribira "abcdabcaba" a la salida:

                  %%
                  a        |
                  ab       |
                  abc      |
                  abcd     ECHO; REJECT;
                  .|\n     /* se come caracteres sin emparejar */

              (Las primeras tres reglas comparten la accion de  la  cuarta  ya
              que estas usan la accion especial '|'.)  REJECT es una propiedad
              particularmente cara en terminos de rendimiento del escaner;  si
              se   usa   en  cualquiera  de  las  acciones  del  escaner  esta
              ralentizara todo  el  proceso  de  emparejamiento  del  escaner.
              Ademas,  REJECT  no puede usarse con las opciones -Cf o -CF (ver
              mas abajo).

              Fijese  tambien  que  a  diferencia  de   las   otras   acciones
              especiales,  REJECT  es  una  bifurcaci'on; el codigo que la siga
              inmediatamente en la accion no sera ejecutado.

       -      yymore() dice al escaner que la proxima  vez  que  empareje  una
              regla,  el  token correspondiente debe ser a~nadido tras el valor
              actual de yytext en lugar de reemplazarlo.  Por ejemplo, dada la
              entrada  "mega-klugde"  lo  que  viene  a continuacion escribira
              "mega-mega-kludge" a la salida:

                  %%
                  mega-    ECHO; yymore();
                  kludge   ECHO;

              El primer "mega-" se empareja y se repite a la salida.  Entonces
              se  empareja "kludge", pero el "mega-" previo aun esta esperando
              al inicio de yytext asi que el ECHO para la regla  del  "kludge"
              realmente escribira "mega-kludge".

       Dos  notas  respecto  al uso de yymore().  Primero, yymore() depende de
       que el valor de  yyleng  refleje  correctamente  el  tamano  del  token
       actual,  asi  que no debe modificar yyleng si esta utilizando yymore().
       Segundo, la presencia de yymore() en la accion del escaner implica  una
       pequena  penalizacion  de rendimiento en la velocidad de emparejamiento
       del escaner.

       -      yyless(n) devuelve todos excepto los primeros n  caracteres  del
              token   actual  de  nuevo  al  flujo  de  entrada,  donde  seran
              reanalizados   cuando   el   escaner   busque    el    siguiente
              emparejamiento.   yytext  e  yyleng se ajustan de forma adecuada
              (p.ej., yyleng no sera igual a n ).  Por ejemplo, con la entrada
              "foobar" lo que viene a continuacion escribira "foobarbar":

                  %%
                  foobar    ECHO; yyless(3);
                  [a-z]+    ECHO;

              Un  argumento  de  0  para  yyless hara que la cadena de entrada
              actual sea analizada por completo de nuevo.  A  menos  que  haya
              cambiado  la  manera  en  la  que el escaner procese de ahora en
              adelante  su  entrada  (utilizando  BEGIN,  por  ejemplo),  esto
              producira un bucle sin fin.

       Fijese  que  yyless  es una macro y puede ser utilizada solamente en el
       fichero de entrada de flex, no desde otros ficheros fuente.

       -      unput(c) pone el caracter c de nuevo en  el  flujo  de  entrada.
              Este  sera  el  proximo caracter analizado.  La siguiente accion
              tomara el token actual y hara que  se  vuelva  a  analizar  pero
              encerrado entre parentesis.

                  {
                  int i;
                  /* Copia yytext porque unput() desecha yytext */
                  char *yycopia = strdup( yytext );
                  unput( ')' );
                  for ( i = yyleng - 1; i >= 0; --i )
                      unput( yycopia[i] );
                  unput( '(' );
                  free( yycopia );
                  }

              Fijese que ya que cada unput() pone el caracter dado de nuevo al
              principio  del  flujo  de  entrada,  al  devolver   cadenas   de
              caracteres se debe hacer de atras hacia delante.

       Un  problema  potencial  importante cuando se utiliza unput() es que si
       esta usando %pointer (por defecto), una llamada a unput()  destruye  el
       contenido  de  yytext,  comenzando  con  su caracter mas a la derecha y
       devorando un caracter a la izquierda con cada llamada.  Si necesita que
       se  preserve  el valor de yytext despues de una llamada a unput() (como
       en el  ejemplo  anterior),  usted  debe  o  bien  copiarlo  primero  en
       cualquier lugar, o construir su escaner usando %array
        (ver Como se Empareja la Entrada).

       Finalmente,  note  que  no  puede  devolver EOF para intentar marcar el
       flujo de entrada con un fin-de-fichero.

       -      input() lee el proximo  caracter  del  flujo  de  entrada.   Por
              ejemplo,  lo  que  viene a continuacion es una manera de comerse
              los comentarios en C:

                  %%
                  "/*"        {
                              register int c;

                              for ( ; ; )
                                  {
                                  while ( (c = input()) != '*' &&
                                          c != EOF )
                                      ;    /* se come el texto del comentario */

                                  if ( c == '*' )
                                      {
                                      while ( (c = input()) == '*' )
                                          ;
                                      if ( c == '/' )
                                          break;    /* encontro el final */
                                      }

                                  if ( c == EOF )
                                      {
                                      error( "EOF en comentario" );
                                      break;
                                      }
                                  }
                              }

              (Fijese que si el escaner se  compila  usando  C++,  entonces  a
              input()  se  le  hace  referencia con yyinput(), para evitar una
              colision de nombre con el flujo de C++ por el nombre input.)

       -      YY_FLUSH_BUFFER vacia el buffer interno del  escaner  de  manera
              que  la  proxima  vez que el escaner intente emparejar un token,
              este primero rellenara el buffer usando YY_INPUT (ver El Escaner
              Generado,  mas  abajo).   Esta  accion es un caso especial de la
              funcion mas general yy_flush_buffer(), descrita mas abajo en  la
              seccion Multiples Buffers de Entrada.

       -      yyterminate()  se  puede  utilizar  en lugar de una sentencia de
              retorno en una accion.  Esta hace  que  finalice  el  escaner  y
              retorne  un  0  a  quien  haya llamado al escaner, indicando que
              "todo  esta  hecho".   Por   defecto,   tambien   se   llama   a
              yyterminate()  cuando  se  encuentra un fin-de-fichero.  Esta es
              una macro y podria ser redefinida.

El Esc'aner Generado

       La salida de flex es el fichero lex.yy.c, que  contiene  la  rutina  de
       analisis  yylex(),  un  numero de tablas usadas por esta para emparejar
       tokens, y un numero de  rutinas  auxiliares  y  macros.   Por  defecto,
       yylex() se declara asi

           int yylex()
               {
               ... aqui van varias definiciones y las acciones ...
               }

       (Si  su entorno acepta prototipos de funciones, entonces este sera "int
       yylex( void )").  Esta  definicion  podria  modificarse  definiendo  la
       macro "YY_DECL".  Por ejemplo, podria utilizar:

           #define YY_DECL float lexscan( a, b ) float a, b;

       para  darle  a la rutina de analisis el nombre lexscan, que devuelve un
       real, y toma dos reales como argumentos.  Fijese que si pone argumentos
       a  la  rutina  de  analisis  usando  una  declaracion  de  funcion  no-
       prototipada/tipo-K&R, debe hacer terminar la definicion con un punto  y
       coma (;).

       Siempre que se llame a yylex(), este analiza tokens desde el fichero de
       entrada global yyin (que por defecto es igual  a  stdin).   La  funcion
       continua  hasta  que  alcance  el  final  del  fichero (punto en el que
       devuelve el valor 0) o  una  de  sus  acciones  ejecute  una  sentencia
       return.

       Si  el escaner alcanza un fin-de-fichero, entonces el comportamiento en
       las llamadas posteriores esta indefinido a menos que o bien yyin apunte
       a  un  nuevo  fichero  de  entrada (en cuyo caso el analisis continua a
       partir de ese fichero), o se llame a yyrestart().  yyrestart() toma  un
       argumento,  un  puntero  FILE  * (que puede ser nulo, si ha preparado a
       YY_INPUT para que analice una fuente distinta  a  yyin),  e  inicializa
       yyin  para  que  escanee  ese fichero.  Esencialmente no hay diferencia
       entre la asignacion a yyin de un nuevo fichero de entrada o el  uso  de
       yyrestart()   para   hacerlo;   esto   ultimo   esta   disponible   por
       compatibilidad  con  versiones  anteriores  de  flex,  y  porque  puede
       utilizarse  para  conmutar  ficheros  de entrada en medio del analisis.
       Tambien se puede utilizar para desechar el buffer  de  entrada  actual,
       invocandola  con  un  argumento  igual  a  yyin;  pero  mejor  es  usar
       YY_FLUSH_BUFFER  (ver  mas  arriba).    Fijese   que   yyrestart()   no
       reinicializa  la  condicion  de  arranque a INITIAL (ver Condiciones de
       Arranque, mas abajo).

       Si yylex() para el analisis debido a  la  ejecucion  de  una  sentencia
       return  en  una  de  las  acciones, el analizador podria ser llamado de
       nuevo y este reanudaria el analisis donde lo dejo.

       Por defecto (y por razones de eficiencia), el analizador  usa  lecturas
       por  bloques en lugar de simples llamadas a getc() para leer caracteres
       desde yyin.  La manera en la que toma su  entrada  se  puede  controlar
       definienfo la macro YY_INPUT.  La secuencia de llamada para YY_INPUT es
       "YY_INPUT(buf,result,max_size)".  Su accion  es  poner  hasta  max_size
       caracteres  en  el  array  de  caracteres buf y devolver en la variable
       entera result bien o el numero de  caracteres  leidos  o  la  constante
       YY_NULL  (0  en  sistemas Unix) para indicar EOF.  Por defecto YY_INPUT
       lee desde la variable global puntero a fichero "yyin".

       Una definicion de ejemplo para YY_INPUT (en la seccion de  definiciones
       del fichero de entrada) es:

           %{
           #define YY_INPUT(buf,result,max_size) \
               { \
               int c = getchar(); \
               result = (c == EOF) ? YY_NULL : (buf[0] = c, 1); \
               }
           %}

       Esta definicion cambiara el procesamiento de la entrada para que suceda
       un caracter a la vez.

       Cuando el analizador reciba  una  indicacion  de  fin-de-fichero  desde
       YY_INPUT,  entonces  esta  comprueba  la funcion yywrap().  Si yywrap()
       devuelve falso (cero), entonces se asume que la funcion ha ido mas alla
       y  ha  preparado  yyin  para que apunte a otro fichero de entrada, y el
       analisis continua.  Si este retorna verdadero  (no-cero),  entonces  el
       analizador  termina,  devolviendo  un  0 a su invocador.  Fijese que en
       cualquier caso, la condicion de arranque permanece sin cambios; esta no
       vuelve a ser INITIAL.

       Si  no  proporciona su propia version de yywrap(), entonces debe bien o
       usar %option noyywrap (en cuyo caso el analizador se comporta  como  si
       yywrap()  devolviera  un  1),  o  debe enlazar con -lfl para obtener la
       version por defecto de la rutina, que siempre devuelve un 1.

       Hay disponibles tres rutinas para analizar desde buffers de memoria  en
       lugar   de   desde   ficheros:   yy_scan_string(),  yy_scan_bytes(),  e
       yy_scan_buffer().  Las trataremos en la seccion  Multiples  Buffers  de
       Entrada.

       El  analizador  escribe  su  salida con ECHO a la variable global yyout
       (por defecto, stdout), que  el  usuario  podria  redefinir  asignandole
       cualquier otro puntero a FILE.

CONDICIONES DE ARRANQUE

       flex  dispone  de  un  mecanismo  para activar reglas condicionalmente.
       Cualquier regla cuyo patron se prefije  con  "<sc>"  unicamente  estara
       activa  cuando  el  analizador se encuentre en la condicion de arranque
       llamada "sc".  Por ejemplo,

           <STRING>[^"]*        { /* se come el cuerpo de la cadena ... */
                       ...
                       }

       estara activa solamente cuando el analizador este en  la  condicion  de
       arranque "STRING", y

           <INITIAL,STRING,QUOTE>\. { /* trata una secuencia de escape ... */
                       ...
                       }

       estara  activa  solamente  cuando la condicion de arranque actual sea o
       bien "INITIAL", "STRING", o "QUOTE".

       Las condiciones de arranque se declaran  en  la  (primera)  seccion  de
       definiciones  de la entrada usando lineas sin sangrar comenzando con %s
       o %x seguida por una lista de nombres.  Lo primero declara  condiciones
       de  arranque  inclusivas, lo ultimo condiciones de arranque exclusivas.
       Una condicion de arranque se activa utilizando la accion BEGIN.   Hasta
       que  se ejecute la proxima accion BEGIN, las reglas con la condicion de
       arranque dada estaran activas y las reglas  con  otras  condiciones  de
       arranque  estaran inactivas.  Si la condicion de arranque es inclusiva,
       entonces  las  reglas  sin  condiciones  de  arranque  tambien  estaran
       activas. Si es exclusiva, entonces s'olamente las reglas calificadas con
       la condicion  de  arranque  estaran  activas.  Un  conjunto  de  reglas
       dependientes  de  la  misma condicion de arranque exclusiva describe un
       analizador que es independiente de cualquiera de las otras reglas en la
       entrada de flex.  Debido a esto, las condiciones de arranque exclusivas
       hacen  facil  la  especificacion  de  "mini-escaneres"   que   analizan
       porciones  de  la  entrada  que son sintacticamente diferentes al resto
       (p.ej., comentarios).

       Si la distincion entre condiciones de arranque inclusivas o  exclusivas
       es aun un poco vaga, aqui hay un ejemplo simple que ilustra la conexion
       entre las dos.  El conjunto de reglas:

           %s ejemplo
           %%

           <ejemplo>foo   hacer_algo();

           bar            algo_mas();

       es equivalente a

           %x ejemplo
           %%

           <ejemplo>foo   hacer_algo();

           <INITIAL,ejemplo>bar    algo_mas();

       Sin el calificador <INITIAL,example>,  el  patron  bar  en  el  segundo
       ejemplo  no  estara  activo  (es decir, no puede emparejarse) cuando se
       encuentre  en  la  condicion  de  arranque  example.   Si  hemos  usado
       <example>  para  calificar bar, aunque, entonces este unicamente estara
       activo en example y no en INITIAL, mientras que en  el  primer  ejemplo
       esta  activo  en  ambas,  porque  en  el primer ejemplo la condicion de
       arranque example es una condicion de arranque inclusiva (%s).

       Fijese tambien  que  el  especificador  especial  de  la  condicion  de
       arranque  <*>  empareja  todas  las  condiciones  de arranque.  Asi, el
       ejemplo anterior tambien pudo haberse escrito;

           %x ejemplo
           %%

           <ejemplo>foo   hacer_algo();

           <*>bar    algo_mas();

       La regla  por  defecto  (hacer  un  ECHO  con  cualquier  caracter  sin
       emparejar)  permanece  activa  en las condiciones de arranque.  Esta es
       equivalente a:

           <*>.|\n     ECHO;

       BEGIN(0)  retorna  al  estado  original  donde  solo  las  reglas   sin
       condiciones  de  arranque  estan  activas.   Este  estado tambien puede
       referirse a la condicion de arranque "INITIAL", asi que  BEGIN(INITIAL)
       es  equivalente  a BEGIN(0).  (No se requieren los parentesis alrededor
       del nombre de la condicion  de  arranque  pero  se  considera  de  buen
       estilo.)

       Las  acciones  BEGIN  pueden  darse  tambien  como  codigo  sangrado al
       comienzo de la  seccion  de  reglas.   Por  ejemplo,  lo  que  viene  a
       continuacion  hara  que el analizador entre en la condicion de arranque
       "ESPECIAL" siempre  que  se  llame  a  yylex()  y  la  variable  global
       entra_en_especial sea verdadera:

                   int entra_en_especial;

           %x ESPECIAL
           %%
                   if ( entra_en_especial )
                       BEGIN(ESPECIAL);

           <ESPECIAL>blablabla
           ...mas reglas a continuacion...

       Para  ilustrar  los  usos  de  las condiciones de arranque, aqui hay un
       analizador que ofrece dos interpretaciones diferentes para  una  cadena
       como  "123.456".   Por  defecto  este  la  tratara como tres tokens, el
       entero "123", un punto ('.'), y el entero "456".   Pero  si  la  cadena
       viene  precedida  en  la  linea  por  la cadena "espera-reales" este la
       tratara como un unico token, el numero en coma flotante 123.456:

           %{
           #include <math.h>
           %}
           %s espera

           %%
           espera-reales        BEGIN(espera);

           <espera>[0-9]+"."[0-9]+      {
                       printf( "encontro un real, = %f\n",
                               atof( yytext ) );
                       }
           <espera>\n           {
                       /* este es el final de la linea,
                        * asi que necesitamos otro
                        * "espera-numero" antes de
                        * que volvamos a reconocer mas
                        * numeros
                        */
                       BEGIN(INITIAL);
                       }

           [0-9]+      {
                       printf( "encontro un entero, = %d\n",
                               atoi( yytext ) );
                       }

           "."         printf( "encontro un punto\n" );

       Aqui esta un analizador que reconoce  (y  descarta)  comentarios  de  C
       mientras mantiene una cuenta de la linea actual de entrada.

           %x comentario
           %%
                   int num_linea = 1;

           "/*"         BEGIN(comentario);

           <comentario>[^*\n]*       /* come todo lo que no sea '*' */
           <comentario>"*"+[^*/\n]*  /* come '*'s no seguidos por '/' */
           <comentario>\n            ++num_linea;
           <comentario>"*"+"/"       BEGIN(INITIAL);

       Este  analizador se complica un poco para emparejar tanto texto como le
       sea posible en cada regla.  En general, cuando se intenta  escribir  un
       analizador  de  alta  velocidad haga que cada regla empareje lo mas que
       pueda, ya que esto es un buen logro.

       Fijese que los nombres de las condiciones  de  arranque  son  realmente
       valores  enteros y pueden ser almacenados como tales.  Asi, lo anterior
       podria extenderse de la siguiente manera:

           %x comentario foo
           %%
                   int num_linea = 1;
                   int invocador_comentario;

           "/*"         {
                        invocador_comentario = INITIAL;
                        BEGIN(comentario);
                        }

           ...

           <foo>"/*"    {
                        invocador_comentario = foo;
                        BEGIN(comentario);
                        }

           <comentario>[^*\n]*        /* se come cualquier cosa que no sea un '*' */
           <comentario>"*"+[^*/\n]*   /* se come '*'s que no continuen con '/'s */
           <comentario>\n             ++num_linea;
           <comentario>"*"+"/"        BEGIN(invocador_comentario);

       Ademas, puede acceder a la condicion de arranque actual usando la macro
       de  valor  entero YY_START.  Por ejemplo, las asignaciones anteriores a
       invocador_comentario podrian escribirse en su lugar como

           invocador_comentario = YY_START;

       Flex ofrece YYSTATE como un alias para YY_START (ya que es lo  que  usa
       lex de AT&T).

       Fijese  que  las condiciones de arranque no tienen su propio espacio de
       nombres; los %s's y %x's declaran nombres de la misma  manera  que  con
       #define's.

       Finalmente,  aqui  hay  un  ejemplo  de  como  emparejar  cadenas entre
       comillas al estilo de C  usando  condiciones  de  arranque  exclusivas,
       incluyendo  secuencias  de  escape  expandidas  (pero  sin  incluir  la
       comprobacion de cadenas que son demasiado largas):

           %x str

           %%
                   char string_buf[MAX_STR_CONST];
                   char *string_buf_ptr;

           \"      string_buf_ptr = string_buf; BEGIN(str);

           <str>\"        { /* se vio la comilla que cierra - todo esta hecho */
                   BEGIN(INITIAL);
                   *string_buf_ptr = '\0';
                   /* devuelve un tipo de token de cadena constante y
                    * el valor para el analizador sintactico
                    */
                   }

           <str>\n        {
                   /* error - cadena constante sin finalizar */
                   /* genera un mensaje de error */
                   }

           <str>\\[0-7]{1,3} {
                   /* secuencia de escape en octal */
                   int resultado;

                   (void) sscanf( yytext + 1, "%o", &resultado );

                   if ( resultado > 0xff )
                           /* error, constante fuera de rango */

                   *string_buf_ptr++ = resultado;
                   }

           <str>\\[0-9]+ {
                   /* genera un error - secuencia de escape erronea;
                    * algo como '\48' o '\0777777'
                    */
                   }

           <str>\\n  *string_buf_ptr++ = '\n';
           <str>\\t  *string_buf_ptr++ = '\t';
           <str>\\r  *string_buf_ptr++ = '\r';
           <str>\\b  *string_buf_ptr++ = '\b';
           <str>\\f  *string_buf_ptr++ = '\f';

           <str>\\(.|\n)  *string_buf_ptr++ = yytext[1];

           <str>[^\\\n\"]+        {
                   char *yptr = yytext;

                   while ( *yptr )
                           *string_buf_ptr++ = *yptr++;
                   }

       A menudo,  como  en  alguno  de  los  ejemplos  anteriores,  uno  acaba
       escribiendo  un  buen  numero  de  reglas  todas  precedidas  por la(s)
       misma(s) condicion(es) de arranque.  Flex hace esto un poco mas facil y
       claro  introduciendo  la  nocion de 'ambito de la condicion de arranque.
       Un ambito de condicion de arranque comienza con:

           <SCs>{

       Donde SCs es una lista de una o mas condiciones  de  arranque.   Dentro
       del  ambito  de  la  condicion  de arranque, cada regla automaticamente
       tiene el prefijo <SCs> aplicado a esta, hasta un  '}'  que  corresponda
       con el '{' inicial.  Asi, por ejemplo,

           <ESC>{
               "\\n"   return '\n';
               "\\r"   return '\r';
               "\\f"   return '\f';
               "\\0"   return '\0';
           }

       es equivalente a:

           <ESC>"\\n"  return '\n';
           <ESC>"\\r"  return '\r';
           <ESC>"\\f"  return '\f';
           <ESC>"\\0"  return '\0';

       Los ambitos de las condiciones de arranque pueden anidarse.

       Estan  disponibles  tres rutinas para manipular pilas de condiciones de
       arranque:

       void yy_push_state(int new_state)
              empuja la condicion de arranque actual al tope de la pila de las
              condiciones  de  arranque  y  cambia a new_state como si hubiera
              utilizado BEGIN new_state  (recuerde  que  los  nombres  de  las
              condiciones de arranque tambien son enteros).

       void yy_pop_state()
              extrae el tope de la pila y cambia a este mediante un BEGIN.

       int yy_top_state()
              devuelve el tope de la pila sin alterar el contenido de la pila.

       La  pila  de las condiciones de arranque crece dinamicamente y por ello
       no tiene asociada ninguna limitacion  de  tamano.   Si  la  memoria  se
       agota, se aborta la ejecucion del programa.

       Para  usar pilas de condiciones de arranque, su analizador debe incluir
       una directiva %option stack (ver Opciones mas abajo).

M'ULTIPLES BUFFERS DE ENTRADA

       Algunos  analizadores  (tales  como  aquellos  que   aceptan   ficheros
       "incluidos")  requieren la lectura de varios flujos de entrada.  Ya que
       los analizadores de flex hacen mucho  uso  de  buffers,  uno  no  puede
       controlar   de  donde  sera  leida  la  siguiente  entrada  escribiendo
       simplemente un YY_INPUT que sea sensible al contexto del  analisis.   A
       YY_INPUT  solo  se le llama cuando el analizador alcanza el final de su
       buffer, que podria ser bastante tiempo despues de haber  analizado  una
       sentencia  como  un  "include"  que  requiere el cambio de la fuente de
       entrada.

       Para solventar este tipo de problemas, flex provee  un  mecanismo  para
       crear y conmutar entre varios buffers de entrada.  Un buffer de entrada
       se crea usando:

           YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )

       que toma un puntero a FILE y un tamano "size" y crea un buffer asociado
       con  el  fichero  dado  y  lo suficientemente grande para mantener size
       caracteres  (cuando  dude,  use  YY_BUF_SIZE  para  el  tamano).   Este
       devuelve  un handle YY_BUFFER_STATE, que podria pasarse a otras rutinas
       (ver mas abajo).  El tipo  de  YY_BUFFER_STATE  es  un  puntero  a  una
       estructura   opaca   struct   yy_buffer_state,  de  manera  que  podria
       inicializar   de   forma    segura    variables    YY_BUFFER_STATE    a
       ((YY_BUFFER_STATE)  0)  si  lo  desea,  y tambien hacer referencia a la
       estructura opaca para declarar  correctamente  buffers  de  entrada  en
       otros  ficheros  fuente  ademas de los de su analizador.  Fijese que el
       puntero a FILE en la llamada a yy_create_buffer se usa  solamente  como
       el  valor  de  yyin  visto  por YY_INPUT; si usted redefine YY_INPUT de
       manera que no use mas a yyin, entonces puede pasar de forma  segura  un
       puntero  FILE  nulo  a  yy_create_buffer.   Se  selecciona un buffer en
       particular a analizar utilizando:

           void yy_switch_to_buffer( YY_BUFFER_STATE nuevo_buffer )

       conmuta el buffer de entrada del analizador de manera  que  los  tokens
       posteriores      provienen     de     nuevo_buffer.      Fijese     que
       yy_switch_to_buffer() podria usarlo yywrap() para  arreglar  las  cosas
       para  un  analisis  continuo,  en lugar de abrir un nuevo fichero y que
       yyin apunte a este.  Fijese tambien que cambiar las fuentes de  entrada
       ya  sea  por  medio de yy_switch_to_buffer() o de yywrap() no cambia la
       condicion de arranque.

           void yy_delete_buffer( YY_BUFFER_STATE buffer )

       se usa para recuperar el almacenamiento  asociado  a  un  buffer.   (El
       buffer  puede  ser  nulo,  en cuyo caso la rutina no hace nada.)  Puede
       tambien limpiar el contenido actual de un buffer usando:

           void yy_flush_buffer( YY_BUFFER_STATE buffer )

       Esta funcion descarta el contenido del buffer, de manera que la proxima
       vez  que el analizador intente emparejar un token desde el buffer, este
       primero rellenara el buffer utilizando YY_INPUT.

       yy_new_buffer() es un alias de yy_create_buffer(), que  se  ofrece  por
       compatibilidad  con el uso en C++ de new y delete para crear y destruir
       objetos dinamicos.

       Finalmente,   la   macro   YY_CURRENT_BUFFER    retorna    un    handle
       YY_BUFFER_STATE al buffer actual.

       Aqui  hay  un  ejemplo  del  uso  de estas propiedades para escribir un
       analizador que expande ficheros  incluidos  (la  propiedad  <<EOF>>  se
       comenta mas abajo):

           /* el estado "incl" se utiliza para obtener el nombre
            * del fichero a incluir.
            */
           %x incl

           %{
           #define MAX_INCLUDE_DEPTH 10
           YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
           int include_stack_ptr = 0;
           %}

           %%
           include             BEGIN(incl);

           [a-z]+              ECHO;
           [^a-z\n]*\n?        ECHO;

           <incl>[ \t]*      /* se come los espacios en blanco */
           <incl>[^ \t\n]+   { /* obtiene el nombre de fichero a incluir */
                   if ( include_stack_ptr >= MAX_INCLUDE_DEPTH )
                       {
                       fprintf( stderr, "Demasiados include anidados" );
                       exit( 1 );
                       }

                   include_stack[include_stack_ptr++] =
                       YY_CURRENT_BUFFER;

                   yyin = fopen( yytext, "r" );

                   if ( ! yyin )
                       error( ... );

                   yy_switch_to_buffer(
                       yy_create_buffer( yyin, YY_BUF_SIZE ) );

                   BEGIN(INITIAL);
                   }

           <<EOF>> {
                   if ( --include_stack_ptr < 0 )
                       {
                       yyterminate();
                       }

                   else
                       {
                       yy_delete_buffer( YY_CURRENT_BUFFER );
                       yy_switch_to_buffer(
                            include_stack[include_stack_ptr] );
                       }
                   }

       Se  dispone  de  tres  rutinas para preparar buffers de entrada para el
       analisis de cadenas en memoria en lugar de archivos.  Todas estas crean
       un  nuevo  buffer  de  entrada  para analizar la cadena, y devuelven el
       correspondiente handle YY_BUFFER_STATE (que usted  deberia  borrar  con
       yy_delete_buffer()  cuando  termine con el).  Estas tambien conmutan el
       nuevo buffer usando yy_switch_to_buffer(), de  manera  que  la  proxima
       llamada a yylex() comenzara analizando la cadena.

       yy_scan_string(const char *str)
              analiza una cadena terminada en nulo.

       yy_scan_bytes(const char *bytes, int len)
              analiza  len  bytes (incluyendo posibles NUL's) comenzando desde
              el punto bytes.

       Fijese que ambas de estas funciones crean y analizan una  copia  de  la
       cadena  o bytes.  (Esto podria ser deseable, ya que yylex() modifica el
       contenido del buffer que esta analizado.)  Usted puede evitar la  copia
       utilizando:

       yy_scan_buffer(char *base, yy_size_t size)
              que  analiza  in situ el buffer comenzando en base, que consiste
              de  size  bytes,  donde  los  dos  ultimos   bytes   deben   ser
              YY_END_OF_BUFFER_CHAR  (ASCII  NUL).  Estos dos ultimos bytes no
              se  analizan;  asi,  el  analisis  consta   de   base[0]   hasta
              base[size-2], inclusive.

              Si  se  equivoca  al  disponer  base  de  esta manera (es decir,
              olvidar los dos YY_END_OF_BUFFER_CHAR bytes  finales),  entonces
              yy_scan_buffer()  devuelve  un puntero nulo en lugar de crear un
              nuevo buffer de entrada.

              El tipo yy_size_t es un tipo entero con el que puede  hacer  una
              conversion  a  una  expresion entera para reflejar el tamano del
              buffer.

REGLAS DE FIN-DE-FICHERO

       La regla especial "<<EOF>>"  indica  las  acciones  que  deben  tomarse
       cuando  se  encuentre  un  fin-de-fichero  e  yywrap() retorne un valor
       distinto  de  cero  (es  decir,  indica  que  no  quedan  ficheros  por
       procesar).   La  accion  debe  finalizar  haciendo  una de estas cuatro
       cosas:

       -      asignando a yyin un  nuevo  fichero  de  entrada  (en  versiones
              anteriores  de flex, despues de hacer la asignacion debia llamar
              a la accion especial YY_NEW_FILE; esto ya no es necesario);

       -      ejecutando una sentencia return;

       -      ejecutando la accion especial yyterminate();

       -      o, conmutando a un  nuevo  buffer  usando  yy_switch_to_buffer()
              como se mostro en el ejemplo anterior.

       Las  reglas  <<EOF>>  no  deberian  usarse  con  otros  patrones; estas
       deberian calificarse con una lista de condiciones de arranque.   Si  se
       da  una  regla  <<EOF>>  sin  calificar,  esta  se  aplica  a todas las
       condiciones de arranque  que  no  tengan  ya  acciones  <<EOF>>.   Para
       especificar  una  regla <<EOF>> solamente para la condicion de arranque
       inicial, use

           <INITIAL><<EOF>>

       Estas reglas son utiles para atrapar cosas tales como  comentarios  sin
       final.  Un ejemplo:

           %x comilla
           %%

           ...otras reglas que tengan que ver con comillas...

           <comilla><<EOF>>   {
                    error( "comilla sin cerrar" );
                    yyterminate();
                    }
           <<EOF>>  {
                    if ( *++filelist )
                        yyin = fopen( *filelist, "r" );
                    else
                       yyterminate();
                    }

MACROS MISCEL'ANEAS

       La  macro  YY_USER_ACTION  puede  definirse para indicar una accion que
       siempre se ejecuta antes de la accion  de  la  regla  emparejada.   Por
       ejemplo,  podria declararse con #define para que llame a una rutina que
       convierta yytext a minusculas.  Cuando se invoca a  YY_USER_ACTION,  la
       variable  yy_act  da el numero de la regla emparejada (las reglas estan
       numeradas comenzando en 1).  Suponga que quiere medir la frecuencia con
       la  que sus reglas son emparejadas.  Lo que viene a continuacion podria
       hacer este truco:

           #define YY_USER_ACTION ++ctr[yy_act]

       donde ctr en un vector que  mantiene  la  cuenta  para  las  diferentes
       reglas.   Fijese que la macro YY_NUM_RULES da el numero total de reglas
       (incluyendo la regla por defecto, incluso si usted usa -s), asi que una
       declaracion correcta para ctr es:

           int ctr[YY_NUM_RULES];

       La  macro  YY_USER_INIT  podria  definirse  para indicar una accion que
       siempre se ejecuta antes del primer analisis (y antes de que se haga la
       inicializacion  interna  del  analizador).   Por  ejemplo,  este podria
       usarse para llamar a una rutina que lea una tabla de datos o  abrir  un
       fichero de registro.

       La   macro   yy_set_interactive(is_interactive)   se  puede  usar  para
       controlar si el buffer actual  se  considera  interactivo.   Un  buffer
       interactivo  se  procesa  mas  lentamente,  pero  debe usarse cuando la
       fuente de entrada del analizador es realmente interactiva  para  evitar
       problemas  debidos  a  la espera para el llenado de los buffers (ver el
       comentario de la bandera -I mas abajo).  Un valor distinto de  cero  en
       la  invocacion de la macro marcara el buffer como interactivo, un valor
       de cero como no-interactivo.  Fijese que el uso de esta macro no  tiene
       en  cuenta  %option always-interactive o %option never-interactive (ver
       Opciones mas abajo).  yy_set_interactive()  debe  invocarse  antes  del
       comienzo del analisis del buffer que es considerado (o no) interactivo.

       La  macro yy_set_bol(at_bol) puede usarse para controlar si el contexto
       del buffer de analisis actual para el proximo emparejamiento  de  token
       se  hace como si se encontrara al principio de una linea.  Un argumento
       de la macro distinto de cero hace activas a las reglas sujetas  a  '^',
       mientras que un argumento igual a cero hacer inactivas a las reglas con
       '^'.

       La macro YY_AT_BOL() devuelve verdadero si el proximo token analizado a
       partir  del buffer actual tendra activas las reglas '^', de otra manera
       falso.

       En el analizador generado, las acciones estan  recogidas  en  una  gran
       sentencia switch y separadas usando YY_BREAK, que puede ser redefinida.
       Por defecto, este es simplemente un "break", para separar la accion  de
       cada regla de las reglas que le siguen.  Redefiniendo YY_BREAK permite,
       por ejemplo, a los usuarios de C++ que #define YY_BREAK  no  haga  nada
       (imientras tengan cuidado para que cada regla finalice con un "break" o
       un  "return"!)  para  evitar  que  sufran  los  avisos  de   sentencias
       inalcanzables cuando debido a que la accion de la regla finaliza con un
       "return", el YY_BREAK es inaccesible.

VALORES DISPONIBLES AL USUARIO

       Esta seccion resume los diferentes valores disponibles  al  usuario  en
       las acciones de la regla.

       -      char  *yytext  apunta  al  texto  del  token actual.  Este puede
              modificarse pero no alargarse (no  puede  anadir  caracteres  al
              final).

              Si aparece la directiva especial %array en la primera seccion de
              la descripcion del analizador, entonces yytext se declara en  su
              lugar como char yytext[YYLMAX], donde YYLMAX es la definicion de
              una macro que puede redefinir en la primera  seccion  si  no  le
              gusta el valor por defecto (generalmente 8KB).  El uso de %array
              produce analizadores algo mas lentos, pero el valor de yytext se
              vuelve   inmune   a  las  llamadas  a  input()  y  unput(),  que
              potencialmente destruyen su valor cuando yytext es un puntero  a
              caracter.   El  opuesto  de %array es %pointer, que se encuentra
              por defecto.

              Usted no puede utilizar %array cuando genera  analizadores  como
              clases de C++ (la bandera -+ ).

       -      int yyleng contiene la longitud del token actual.

       -      FILE  *yyin es el fichero por el que flex lee por defecto.  Este
              podria redefinirse pero hacerlo solo tiene sentido antes de  que
              el analisis comience o despues de que se haya encontrado un EOF.
              Cambiandolo en medio del analisis tendra resultados  inesperados
              ya que flex utiliza buffers en su entrada; use yyrestart() en su
              lugar.  Una vez que el analisis termina debido a que se ha visto
              un  fin-de-fichero,  puede  asignarle a yyin el nuevo fichero de
              entrada y entonces llamar al analizador de nuevo para  continuar
              analizando.

       -      void  yyrestart(  FILE  *new_file  ) podria ser llamada para que
              yyin apunte al nuevo fichero de entrada.   El  cambio  al  nuevo
              fichero  es  inmediato (cualquier entrada contenida en el buffer
              previamente se pierde).  Fijese que llamando a  yyrestart()  con
              yyin como argumento de esta manera elimina el buffer de entradda
              actual y continua analizando el mismo fichero de entrada.

       -      FILE *yyout es el fichero sobre el que  se  hacen  las  acciones
              ECHO.  Este puede ser reasignado por el usuario.

       -      YY_CURRENT_BUFFER  devuelve  un handle YY_BUFFER_STATE al buffer
              actual.

       -      YY_START devuelve un valor entero correspondiente a la condicion
              de  arranque  actual.   Posteriormente puede usar este valor con
              BEGIN para retornar a la condicion de arranque.

INTERFAZ CON YACC

       Uno de los usos principales de flex es como companero del generador  de
       analizadores  sintacticos  yacc.   Los  analizadores  de  yacc  esperan
       invocar a una rutina llamada yylex() para encontrar el proximo token de
       entrada.   La  rutina  se supone que devuelve el tipo del proximo token
       ademas de poner cualquier valor asociado en la variable global  yylval.
       Para  usar  flex  con  yacc,  uno  especifica la opcion -d de yacc para
       intruirle a que genere el fichero y.tab.h que contiene las definiciones
       de todos los %tokens que aparecen en la entrada de yacc.  Entonces este
       archivo se incluye en el analizador de flex Por ejemplo, si uno de  los
       tokens es "TOK_NUMERO", parte del analizador podria parecerse a:

           %{
           #include "y.tab.h"
           %}

           %%

           [0-9]+        yylval = atoi( yytext ); return TOK_NUMERO;

OPCIONES

       flex tiene las siguientes opciones:

       -b     Genera  informacion  de  retroceso  en  lex.backup.  Esta es una
              lista de estados del analizador que requieren  retroceso  y  los
              caracteres de entrada con los que la hace.  Anadiendo reglas uno
              puede eliminar estados de retroceso.  Si todos  los  estados  de
              retroceso se eliminan y se usa -Cf o -CF, el analizador generado
              funcionara mas rapido  (ver  la  bandera  -p).   Unicamente  los
              usuarios  que  desean  exprimir  hasta  el  ultimo  ciclo de sus
              analizadores necesitan preocuparse  de  esta  opcion.   (Ver  la
              seccion sobre Consideraciones de Rendimiento mas abajo.)

       -c     es una opcion que no hace nada, incluida para cumplir con POSIX.

       -d     hace   que   el  analizador  generado  se  ejecute  en  modo  de
              depuraci'on.  Siempre que se reconoce un  patron  y  la  variable
              global  yy_flex_debug  no es cero (que por defecto no lo es), el
              analizador escribira en stderr una linea de la forma:

                  --accepting rule at line 53 ("el texto emparejado")

              El numero de linea hace referencia al lugar de la  regla  en  el
              fichero que define al analizador (es decir, el fichero que se le
              introdujo a flex).  Los mensajes tambien se  generan  cuando  el
              analizador  retrocede,  acepta  la regla por defecto, alcanza el
              final de su buffer de entrada  (o  encuentra  un  NUL;  en  este
              punto,  los  dos  parecen  lo  mismo  en  lo que le concierne al
              analizador), o alcance el fin-de-fichero.

       -f     especifica un analizador r'apido.  No se realiza  una  compresion
              de  tablas  y  se evita el uso de stdio.  El resultado es grande
              pero rapido.  Esta opcion es equivalente a -Cfr (ver mas abajo).

       -h     genera un sumario de "ayuda" de las opciones de flex por  stdout
              y entonces finaliza.  -?  y --help son sinonimos de -h.

       -i     indica  a  flex  que  genere un analizador case-insensitive.  Se
              ignorara si las letras en los patrones de entrada de flex son en
              mayusculas  o  en  minusculas,  y los tokens en la entrada seran
              emparejados sin tenerlo en cuenta.  El texto emparejado dado  en
              yytext tendra las mayusculas y minusculas preservadas (es decir,
              no se convertiran).

       -l     activa el modo de maxima compatibilidad  con  la  implementacion
              original  de  lex  de  AT&T.   Fijese  que esto no significa una
              compatibilidad completa.  El  uso  de  esta  opcion  cuesta  una
              cantidad  considerable de rendimiento, y no puede usarse con las
              opciones -+, -f, -F, -Cf, o -CF.  Para los detalles a  cerca  de
              la    compatibilidad    que    se   ofrece,   vea   la   seccion
              "Incompatibilidades con Lex y POSIX"  mas  abajo.   Esta  opcion
              tambien  hace  que  se defina el nombre YY_FLEX_LEX_COMPAT en el
              analizador generado.

       -n     es otra opcion que no  hace  nada,  incluida  para  cumplir  con
              POSIX.

       -p     genera  un  informe de rendimiento en stderr.  El informe consta
              de comentarios que tratan de  las  propiedades  del  fichero  de
              entrada de flex que provocaran perdidas serias de rendimiento en
              el analizador resultante.  Si indica  esta  bandera  dos  veces,
              tambien  obtendra  comentarios que tratan de las propiedades que
              producen perdidas menores de rendimiento.

              Fijese que el uso de REJECT, %option  yylineno,  y  el  contexto
              posterior  variable  (vea  la seccion Deficiencias / Errores mas
              abajo) supone una penalizacion substancial del rendimiento;   el
              uso  de  yymore(),  el  operador  ^,  y  la  bandera  -I  supone
              penalizaciones del rendimiento menores.

       -s     hace que la regla por defecto (que la entrada sin emparejar  del
              analizador  se  repita por stdout) se suprima.  Si el analizador
              encuentra entrada que  no  es  reconocida  por  ninguna  de  sus
              reglas,  este  aborta  con  un  error.  Esta opcion es util para
              encontrar agujeros en el conjunto de reglas del analizador.

       -t     indica a flex que escriba el analizador que genera a  la  salida
              estandar en lugar de en lex.yy.c.

       -v     especifica  que  flex  deberia  escribir en stderr un sumario de
              estadisticas respecto al analizador que genera.  La  mayoria  de
              las estadisticas no tienen significado para el usuario casual de
              flex, pero la primera linea identifica la version  de  flex  (la
              misma  que  se  informa con -V), y la proxima linea las banderas
              utilizadas cuando se genera el analizador,  incluyendo  aquellas
              que se encuentran activadas por defecto.

       -w     suprime los mensajes de aviso.

       -B     dice a flex que genere un analizador batch, que es lo opuesto al
              analizador interactivo generador por -I  (ver  mas  abajo).   En
              general, use -B cuando este seguro de que su analizador nunca se
              usara de forma interactiva, y quiere con esto exprimir  un  poco
              mas  el  rendimiento.   Si  por  el  contrario  su  objetivo  es
              exprimirlo mucho mas, deberia estar utilizando la opcion  -Cf  o
              -CF  (comentadas  mas  abajo),  que activa -B automaticamente de
              todas maneras.

       -F     especifica que se debe utilizar la representacion  de  la  tabla
              r'apida  (y elimina referencias a stdio).  Esta representacion es
              aproximadamente tan rapida como la representacion completa de la
              tabla   (-f),   y   para  algunos  conjuntos  de  patrones  sera
              considerablemente  mas  pequena  (y  para  otros,  mayor).    En
              general,  si el conjunto de patrones contiene "palabras clave" y
              una regla "identificador" atrapalo-todo, como la del conjunto:

                  "case"    return TOK_CASE;
                  "switch"  return TOK_SWITCH;
                  ...
                  "default" return TOK_DEFAULT;
                  [a-z]+    return TOK_ID;

              entonces sera mejor que utilice la representacion  de  la  tabla
              completa.   Si  solo  esta  presente  la regla "identificador" y
              utiliza una tabla hash o algo parecido  para  detectar  palabras
              clave, mejor utilice -F.

              Esta  opcion es equivalente a -CFr (ver mas abajo).  Esta opcion
              no puede utilizarse con -+.

       -I     ordena a flex que genere un analizador interactivo Un analizador
              interactivo  es uno que solo mira hacia delante para decidir que
              token ha sido reconocido unicamente si  debe  hacerlo.   Resulta
              que  mirando siempre un caracter extra hacia delante, incluso si
              el analizador ya ha visto  suficiente  texto  para  eliminar  la
              ambiguedad  del  token  actual,  se  es  un  poco mas rapido que
              mirando solamente cuando es necesario.   Pero  los  analizadores
              que  siempre  miran  hacia  delante  producen  un comportamiento
              interactivo malisimo; por ejemplo, cuando un usuario teclea  una
              linea  nueva,  esta  no se reconoce como un token de linea nueva
              hasta  que  introduzca  otro  token,  que  a  menudo   significa
              introducir otra linea completa.

              Los  analizadores  de  flex por defecto son interactivos a menos
              que use la opcion -Cf o -CF de compresion  de  tablas  (ver  mas
              abajo).   Esto  es  debido a que si esta buscando un rendimiento
              alto tendria que estar utilizando una de estas opciones, asi que
              si  no  lo  ha  hecho flex asume que prefiere cambiar un poco de
              rendimiento  en  tiempo  de  ejecucion  en   beneficio   de   un
              comportamiento  iteractivo  intuitivo.   Fijese  tambien  que no
              puede utilizar -I conjuntamente con -Cf o -CF.  Asi, esta opcion
              no  se  necesita  realmente;  esta activa por defecto para todos
              esos casos en los que se permite.

              Usted puede forzar al analizador que no sea  interactivo  usando
              -B (ver mas arriba).

       -L     ordena  a flex que no genere directivas #line.  Sin esta opcion,
              flex acribilla al analizador generado con directivas #line  para
              que  los  mensajes  de  error  en las acciones esten localizadas
              correctamente respecto al  fichero  original  de  flex  (si  los
              errores  son  debidos  al  codigo en el fichero de entrada), o a
              lex.yy.c (si los errores son fallos de flex -- deberia  informar
              de  este  tipo  de  errores  a  la  direccion de correo dada mas
              abajo).

       -T     hace que flex se ejecute en modo de  traza.   Este  generara  un
              monton  de mensajes en stderr relativos a la forma de la entrada
              y el automata finito no-determinista o determinista  resultante.
              Esta  opcion  generalmente es para usarla en el mantenimiento de
              flex.

       -V     imprime el numero de la version en stdout y sale.  --version  es
              un sinonimo de -V.

       -7     ordena  a flex que genere un analizador de 7-bits, es decir, uno
              que solo puede reconocer caracteres de 7-bits en su entrada.  La
              ventaja  de  usar -7 es que las tablas del analizador pueden ser
              hasta la mitad del tamano de aquellas generadas usando la opcion
              -8  (ver  mas abajo).  La desventaja es que tales analizadores a
              menudo se cuelgan o revientan si su entrada contiene  caracteres
              de 8-bits.

              Fijese,  sin  embargo,  que  a  menos  que  genere su analizador
              utilizando las opciones de compresion de tablas -Cf  o  -CF,  el
              uso  de -7 ahorrara solamente una pequena cantidad de espacio en
              la tabla, y hara su analizador considerablemente menos portable.
              El  comportamiento  por defecto de flex es generar un analizador
              de 8-bits a menos que use -Cf o  -CF,  en  cuyo  caso  flex  por
              defecto  genera  analizadores  de  7-bits a menos que su sistema
              siempre este configurado para generar analizadores de 8-bits  (a
              menudo  este sera el caso de los sistemas fuera de EEUU).  Puede
              decir si flex genero un analizador de 7 u 8 bits  inspeccionando
              el  sumario  de  banderas  en  la salida de -v como se describio
              anteriormente.

              Fijese que si usa -Cfe o -CFe (esas opciones  de  compresion  de
              tablas,  pero  tambien  el uso de clases de equivalencia como se
              comentara mas abajo), flex genera aun por defecto un  analizador
              de  8-bits,  ya que normalmente con estas opciones de compresion
              las tablas de 8-bits completas no son mucho mas  caras  que  las
              tablas de 7-bits.

       -8     ordena  a flex que genere un analizador de 8-bits, es decir, uno
              que puede reconocer caracteres de 8-bits.  Esta bandera solo  es
              necesaria  para  analizadores generados usando -Cf o -CF, ya que
              de otra manera flex por defecto genera un analizador  de  8-bits
              de todas formas.

              Vea el comentario sobre -7 mas arriba a cerca del comportamiento
              por defecto de flex y la discusion  entre  los  analizadores  de
              7-bits y 8-bits.

       -+     especifica  que  quiere  que  flex genere un analizador como una
              clase de C++.  Vea la seccion  Generando  Escaners  en  C++  mas
              abajo para los detalles.

       -C[aefFmr]
              controla el grado de compresion de la tabla y, mas generalmente,
              el  compromiso  entre  analizadores  pequenos   y   analizadores
              rapidos.

              -Ca  ("alinea")  ordena a flex que negocie tablas mas grandes en
              el analizador generado para un comportamiento mas rapido  porque
              los elementos de las tablas estan mejor alineados para el acceso
              a memoria y computacion.   En  algunas  arquitecturas  RISC,  la
              busqueda  y manipulacion de palabras largas es mas eficiente que
              con unidades mas pequenas  tales  como  palabras  cortas.   Esta
              opcion  puede  doblar  el  tamano  de  las  tablas  usadas en su
              analizador.

              -Ce ordena a flex  que  construya  clases  de  equivalencia,  es
              decir,  conjunto  de caracteres que tienen identicas propiedades
              lexicas (por ejemplo, si la unica aparicion  de  digitos  en  la
              entrada  de  flex  es en la clase de caracteres "[0-9]" entonces
              los digitos '0', '1', ..., '9' se  pondran  todos  en  la  misma
              clase  de equivalencia).  Las clases de equivalencia normalmente
              ofrecen notables reducciones en  los  tamanos  de  los  ficheros
              finales  de  tabla/objeto  (tipicamente  un factor de 2-5) y son
              juiciosamente bastante baratos en  cuanto  al  rendimiento  (una
              localizacion en un vector por caracter analizado).

              -Cf  especifica  que  se deben generar las tablas del analizador
              completas - flex no deberia comprimir las tablas tomando ventaja
              de   las  funciones  de  transicion  similares  para  diferentes
              estados.

              -CF  especifica  que  deberia  usarse  la   representacion   del
              analizador  rapido  alternativo  (descrito  anteriormente  en la
              bandera -F ) Esta opcion no puede usarse con -+.

              -Cm ordena a flex a que construya clases de  meta-equivalencias,
              que  son  conjuntos  de clases de equivalencia (o caracteres, si
              las clases de equivalencia no se estan usando) que comunmente se
              usan  de forma conjunta.  Las clases de meta-equivalencias son a
              menudo un gran ahorro cuando se usan  tablas  comprimidas,  pero
              tienen  un  impacto  moderado en el rendimiento (uno o dos tests
              "if" y una localizacion en un array por caracter analizado).

              -Cr hace que  el  analizador  generado  elimine  el  uso  de  la
              libreria  de E/S estandar para la entrada.  En lugar de llamar a
              fread() o getc(), el analizador utilizara la llamada al  sistema
              read(),  produciendo una ganancia en el rendimiento que varia de
              sistema  en  sistema,   pero   en   general   probablemente   es
              insignificante  a  menos  que tambien este usando -Cf o -CF.  El
              uso de -Cr puede producir  un  comportamiento  extrano  si,  por
              ejemplo,  lee de yyin usando stdio antes de llamar al analizador
              (porque el analizador perdera cualquier texto que  sus  lecturas
              anteriores dejaron en el buffer de entrada de stdio).

              -Cr  no  tiene  efecto  si usted define YY_INPUT (ver El Escaner
              Generado mas arriba).

              Con solamente -C se especifica que  las  tablas  del  analizador
              deberian comprimirse pero no deberia utilizarse ni las clases de
              equivalencia ni las clases de meta-equivalencias.

              Las opciones -Cf o -CF y -Cm no tienen sentido juntas -  no  hay
              oportunidad para las clases de meta-equivalencias si la tabla no
              esta siendo comprimida.  De  otra  forma  las  opciones  podrian
              mezclarse libremente, y son acumulativas.

              La  configuracion  por  defecto es -Cem, que especifica que flex
              deberia  generar  clases  de  equivalencia  y  clases  de  meta-
              equivalencias.   Esta  configuracion  provee  el  mayor grado de
              compresion.  Puede llegarse a un compromiso  entre  analizadores
              de  ejecucion  mas  rapida con el coste de tablas mayores siendo
              generalmente verdadero lo siguiente:

                  lo mas lento y pequeno
                        -Cem
                        -Cm
                        -Ce
                        -C
                        -C{f,F}e
                        -C{f,F}
                        -C{f,F}a
                  lo mas rapido y grande

              Fijese que los analizadores con tablas mas pequenas  normalmente
              se  generan  y  compilan de la forma mas rapida posible, asi que
              durante el desarrollo usted normalmente querra usar  como  viene
              por defecto, compresion maxima.

              -Cfe  a  menudo  es  un buen compromiso entre velocidad y tamano
              para la produccion de analizadores.

       -osalida
              ordena a flex que escriba el analizador  al  fichero  salida  en
              lugar  de  a lex.yy.c.  Si combina -o con la opcion -t, entonces
              el analizador se escribe en stdout  pero  sus  directivas  #line
              (vea  la  opcion  -L  mas  arriba)  hacen  referencia al fichero
              salida.

       -Pprefijo
              cambia el prefijo yy usado por defecto por flex para  todas  las
              variables  visibles  globalmente y nombres de funciones para que
              sea prefijo.  Por ejemplo, -Pfoo cambia el nombre  de  yytext  a
              footext.   Este tambien cambia el nombre por defecto del fichero
              de salida de lex.yy.c a lex.foo.c.  Aqui estan todos los nombres
              afectados:

                  yy_create_buffer
                  yy_delete_buffer
                  yy_flex_debug
                  yy_init_buffer
                  yy_flush_buffer
                  yy_load_buffer_state
                  yy_switch_to_buffer
                  yyin
                  yyleng
                  yylex
                  yylineno
                  yyout
                  yyrestart
                  yytext
                  yywrap

              (Si  usted  esta  utilizando  un  analizador  en  C++,  entonces
              unicamente yywrap y yyFlexLexer se ven afectados.)  Dentro de su
              analizador,  puede aun hacer referencia a las variables globales
              y  funciones  usando  cualquier  version  de  su  nombre;   pero
              externamente, estas tienen el nombre modificado.

              Esta  opcion le deja enlazar facilmente multiples programas flex
              conjuntamente en el mismo ejecutable.  Fijese, sin embargo,  que
              usando  esta  opcion tambien se renombra yywrap(), de manera que
              ahora debe o bien proveer su propia version de la rutina (con el
              nombre  apropiado)  para su analizador, o usar %option noyywrap,
              ya que enlazar con -lfl no podra proveerle una por defecto.

       -Sfichero_esqueleto
              ignora el fichero de esqueleteo por  defecto  con  el  que  flex
              construye   sus   analizadores.    Usted   probablemente   nunca
              necesitara utilizar  esta  opcion  a  menos  que  este  haciendo
              mantenimiento o un desarrollo de flex.

       flex  tambien ofrece un mecanismo para controlar las opciones dentro de
       la propia especificacion del analizador, en vez de a partir de la linea
       de  comando.   Esto  se  hace  incluyendo  las directivas %option en la
       primera seccion de  la  especificacion  del  analizador.   Usted  puede
       especificar  varias  opciones  con una sola directiva %option, y varias
       directivas en la primera seccion de su fichero de entrada de flex.

       La mayoria de las  opciones  vienen  dadas  simplemente  como  nombres,
       opcionalmente  precedidos  por  la  palabra  "no"  (sin  intervenir  un
       espacio) para negar su significado.  Las banderas de flex o su negacion
       son equivalentes a un numero:

           7bit            opcion -7
           8bit            opcion -8
           align           opcion -Ca
           backup          opcion -b
           batch           opcion -B
           c++             opcion -+

           caseful o
           case-sensitive  opuesto de -i (por defecto)

           case-insensitive o
           caseless        opcion -i

           debug           opcion -d
           default         opuesto de la opcion -s
           ecs             opcion -Ce
           fast            opcion -F
           full            opcion -f
           interactive     opcion -I
           lex-compat      opcion -l
           meta-ecs        opcion -Cm
           perf-report     opcion -p
           read            opcion -Cr
           stdout          opcion -t
           verbose         opcion -v
           warn            opuesto de la opcion -w
                           (use "%option nowarn" para -w)

           array           equivalente a "%array"
           pointer         equivalente a "%pointer" (por defecto)

       Algunas  directivas  %option  ofrecen propiedades que de otra manera no
       estan disponibles:

       always-interactive
              ordena a flex que genere un analizador que siempre considere  su
              entrada  como "interactiva".  Normalmente, sobre cada fichero de
              entrada nuevo el analizador llama a isatty() como  intento  para
              determinar  si la entrada del analizador es interactiva y por lo
              tanto deberia leer un caracter a la vez.  Cuando esta opcion  se
              utilice, sin embargo, entonces no se hace tal llamada.

       main   ordena  a  flex que facilite un programa main() por defecto para
              el analizador, que simplemente llame  a  yylex().   Esta  opcion
              implica noyywrap (ver mas abajo).

       never-interactive
              ordena  a  flex  que genere un analizador que nunca considere su
              entrada como "interactiva" (de nuevo, no se hace ninguna llamada
              a isatty()).  Esta es la opuesta a always-interactive.

       stack  activa   el  uso  de  pilas  de  condiciones  de  arranque  (ver
              Condiciones de Arranque mas arriba).

       stdinit
              si se establece (es decir, %option stdinit)  inicializa  yyin  e
              yyout  a  stdin y stdout, en lugar del que viene por defecto que
              es nil.  Algunos pogramas de lex  existentes  dependen  de  este
              comportamiento,  incluso  si no sigue el ANSI C, que no requiere
              que stdin y stdout sean constantes en tiempo de compilacion.

       yylineno
              ordena a flex a generar un analizador que mantenga el numero  de
              la  linea  actual  leida  desde su entrada en la variable global
              yylineno.  Esta opcion viene implicita con %option lex-compat.

       yywrap si no se establece (es decir, %option  noyywrap),  hace  que  el
              analizador  no  llame  a  yywrap() hasta el fin-de-fichero, pero
              simplemente asume que no hay mas ficheros  que  analizar  (hasta
              que  el  usuario  haga apuntar yyin a un nuevo fichero y llame a
              yylex() otra vez).

       flex analiza las acciones de sus reglas para determinar si utiliza  las
       propiedades  REJECT  o  yymore()  Las  opciones  reject  e yymore estan
       disponibles para ignorar sus decisiones siempre que use las opciones, o
       bien  estableciendolas  (p.ej.,  %option  reject)  para  indicar que la
       propiedad se utiliza realmente, o desactivandolas para indicar  que  no
       es utilizada (p.ej., %option noyymore).

       Tres opciones toman valores delimitados por cadenas, separadas por '=':

           %option outfile="ABC"

       es equivalente a -oABC, y

           %option prefix="XYZ"

       es equivalente a -PXYZ.  Finalmente,

           %option yyclass="foo"

       solo se aplica cuando se genera un analizador en C++ (opcion -+).  Este
       informa a flex que ha derivado a foo como una subclase de  yyFlexLexer,
       asi  que flex pondra sus acciones en la funcion miembro foo::yylex() en
       lugar de yyFlexLexer::yylex().  Este tambien genera una funcion miembro
       yyFlexLexer::yylex()   que  emite  un  error  en  tiempo  de  ejecucion
       (invocando a yyFlexLexer::LexerError()) si es llamada.   Ver  Generando
       Escaners en C++, mas abajo, para informacion adicional.

       Estan  disponibles  un numero de opciones para los puristas de lint que
       desean suprimir la aparicion de rutinas no necesarias en el  analizador
       generado.   Cada una de la siguientes, si se desactivan (p.ej., %option
       nounput ), hace  que  la  rutina  correspondiente  no  aparezca  en  el
       analizador generado:

           input, unput
           yy_push_state, yy_pop_state, yy_top_state
           yy_scan_buffer, yy_scan_bytes, yy_scan_string

       (aunque  yy_push_state()  y  sus amigas no apareceran de todas manera a
       menos que use %option stack).

CONSIDERACIONES DE RENDIMIENTO

       El principal objetivo de diseno de flex es que genere  analizadores  de
       alto  rendimiento.   Este  ha sido optimizado para comportarse bien con
       conjuntos grandes de reglas.  Aparte de los efectos sobre la  velocidad
       del   analizador   con   las   opciones  de  compresion  de  tablas  -C
       anteriormente introducidas, hay  un  numero  de  opciones/acciones  que
       degradan el rendimiento.  Estas son, desde la mas costosa a la menos:

           REJECT
           %option yylineno
           contexto posterior arbitrario

           conjunto de patrones que requieren retroceso
           %array
           %option interactive
           %option always-interactive

           '^' operador de comienzo de linea
           yymore()

       siendo  las  tres primeras bastante costosas y las dos ultimas bastante
       economicas.  Fijese tambien que unput() se implementa como una  llamada
       de  rutina  que  potencialmente  hace  bastante  trabajo,  mientras que
       yyless() es una macro bastante economica; asi que si  esta  devolviendo
       algun texto excedente que ha analizado, use yyless().

       REJECT  deberia  evitarse  a  cualquier precio cuando el rendimiento es
       importante.  Esta es una opcion particularmente cara.

       Es lioso deshacerse del retroceso y a menudo podria ser una cantidad de
       trabajo  enorme  para  un  analizador  complicado.   En  principio, uno
       comienza utilizando la bandera -b para generar un  archivo  lex.backup.
       Por ejemplo, sobre la entrada

           %%
           foo        return TOK_KEYWORD;
           foobar     return TOK_KEYWORD;

       el fichero tiene el siguiente aspecto:

           El estado #6 es no-aceptar -
            numeros de linea asociados a la regla:
                  2       3
            fin de transiciones: [ o ]
            transiciones de bloqueo: fin de archivo (EOF) [ \001-n  p-\177 ]

           El estado #8 es no-aceptar -
            numeros de linea asociados a la regla:
                  3
            fin de transiciones: [ a ]
            transiciones de bloqueo: fin de archivo (EOF) [ \001-`  b-\177 ]

           El estado #9 es no-aceptar -
            numeros de linea asociados a la regla:
                  3
            fin de transiciones: [ r ]
            transiciones de bloqueo: fin de archivo (EOF) [ \001-q  s-\177 ]

           Las tablas comprimidas siempre implican un retroceso.

       Las  primeras  lineas  nos dicen que hay un estado del analizador en el
       que se puede hacer una transicion con una 'o' pero no  sobre  cualquier
       otro  caracter, y que en ese estado el texto recientemente analizado no
       empareja con  ninguna  regla.   El  estado  ocurre  cuando  se  intenta
       emparejar  las  reglas encontradas en las lineas 2 y 3 en el fichero de
       entrada.  Si el analizador esta en ese estado y entoces  lee  cualquier
       cosa que no sea una 'o', tendra que retroceder para encontrar una regla
       que empareje.  Con un poco de analisis uno puede ver que este debe  ser
       el  estado  en  el  que  se  esta cuando se ha visto "fo".  Cuando haya
       ocurrido, si se ve cualquier cosa que no sea  una  'o',  el  analizador
       tendra  que  retroceder para simplemente emparejar la 'f' (por la regla
       por defecto).

       El comentario que tiene que ver con el Estado  #8  indica  que  hay  un
       problema  cuando  se analiza "foob".  En efecto, con cualquier caracter
       que no sea una 'a', el analizador tendra que  retroceder  para  aceptar
       "foo".  De forma similar, el comentario para el Estado #9 tiene que ver
       cuando se ha analizado "fooba" y no le sigue una 'r'.

       El comentario final nos recuerda que no mecere la pena todo el  trabajo
       para eliminar el retroceso de las reglas a menos que estemos usando -Cf
       o -CF, y que no hay  ninguna  mejora  del  rendimiento  haciendolo  con
       analizadores comprimidos.

       La manera de quitar los retrocesos es anadiendo reglas de "error":

           %%
           foo         return TOK_KEYWORD;
           foobar      return TOK_KEYWORD;

           fooba       |
           foob        |
           fo          {
                       /* falsa alarma, realmente no es una palabra clave */
                       return TOK_ID;
                       }

       La  eliminacion  de  retroceso  en  una lista de palabras clave tambien
       puede hacerse utilizando una regla "atrapalo-todo":

           %%
           foo         return TOK_KEYWORD;
           foobar      return TOK_KEYWORD;

           [a-z]+      return TOK_ID;

       Normalmente esta es la mejor solucion cuando sea adecuada.

       Los mensajes sobre retrocesos tienden a aparecer en  cascada.   Con  un
       conjunto  complicado  de  reglas  no  es  poco comun obtener cientos de
       mensajes.  Si uno puede descifrarlos, sin embargo, a  menudo  solo  hay
       que  tomar una docena de reglas o algo asi para eliminar los retrocesos
       (ya que es facil cometer una equivocacion y tener una  regla  de  error
       que  reconozca  un  token valido.  Una posible caracteristica futura de
       flex sera anadir reglas automaticamente para eliminar el retroceso).

       Es importante tener  en  cuenta  que  se  obtienen  los  beneficios  de
       eliminar  el  retroceso  solo  si elimina cada instancia del retroceso.
       Dejar solamente una significa que no ha ganado absolutamente nada.

       El contexto posterior variable (donde la parte delantera y posterior no
       tienen  una  longitud fija) supone casi la misma perdida de rendimiento
       que REJECT (es decir, substanciales).  Asi que cuando sea  posible  una
       regla como esta:

           %%
           raton|rata/(gato|perro)   correr();

       es mejor escribirla asi:

           %%
           raton/gato|perro          correr();
           rata/gato|perro           correr();

       o asi

           %%
           raton|rata/gato           correr();
           raton|rata/perro          correr();

       Fijese que aqui la accion especial '|' no ofrece ningun ahorro, y puede
       incluso hacer las cosas peor (ver Deficiencias / Errores mas abajo).

       Otro area  donde  el  usuario  puede  incrementar  el  rendimiento  del
       analizador  (y una que es mas facil de implementar) surge del hecho que
       cuanto mas tarde se empareje un token, mas rapido  ira  el  analizador.
       Esto  es debido a que con tokens grandes el procesamiento de la mayoria
       de los caracteres de  entrada  tiene  lugar  en  el  (corto)  bucle  de
       analisis mas interno, y no tiene que ir tan a menudo a hacer el trabajo
       de mas para constituir el entorno del analizador (p.ej.,  yytext)  para
       la accion.  Recuerde el analizador para los comentarios en C:

           %x comentario
           %%
                   int num_linea = 1;

           "/*"         BEGIN(comentario);

           <comentario>[^*\n]*
           <comentario>"*"+[^*/\n]*
           <comentario>\n             ++num_linea;
           <comentario>"*"+"/"        BEGIN(INITIAL);

       Esto podria acelerarse escribiendolo como:

           %x comentario
           %%
                   int num_linea = 1;

           "/*"         BEGIN(comentario);

           <comentario>[^*\n]*
           <comentario>[^*\n]*\n      ++num_linea;
           <comentario>"*"+[^*/\n]*
           <comentario>"*"+[^*/\n]*\n ++num_linea;
           <comentario>"*"+"/"        BEGIN(INITIAL);

       Ahora  en  lugar  de  que cada linea nueva requiera el procesamiento de
       otra regla, el reconocimiento de  las  lineas  nuevas  se  "distribuye"
       sobre las otras reglas para mantener el texto reconocido tan largo como
       sea posible.  iFijese que el a~nadir reglas no ralentiza el  analizador!
       La  velocidad  del  analizador  es independiente del numero de reglas o
       (dadas las consideraciones  dadas  al  inicio  de  esta  seccion)  cuan
       complicadas sean las reglas respecto a operadores tales como '*' y '|'.

       Un  ejemplo  final  sobre  la aceleracion de un analizador: suponga que
       quiere analizar un fichero  que  contiene  identificadores  y  palabras
       clave,  una  por linea y sin ningun caracter extrano, y reconocer todas
       las palabras clave.  Una primera aproximacion natural es:

           %%
           asm      |
           auto     |
           break    |
           ... etc ...
           volatile |
           while    /* es una palabra clave */

           .|\n     /* no es una palabra clave */

       Para eliminar el retroceso, introduzca una regla atrapalo-todo:

           %%
           asm      |
           auto     |
           break    |
           ... etc ...
           volatile |
           while    /* es una palabra clave */

           [a-z]+   |
           .|\n     /* no es una palabra clave */

       Ahora, si se garantiza que  hay  exactamente  una  palabra  por  linea,
       entonces  podemos  reducir  el  numero  total de emparejamientos por la
       mitad mezclando el reconocimiento de lineas nuevas con las de los otros
       tokens:

           %%
           asm\n    |
           auto\n   |
           break\n  |
           ... etc ...
           volatile\n |
           while\n  /* es una palabra clave */

           [a-z]+\n |
           .|\n     /* no es una palabra clave */

       Uno  tiene que ser cuidadoso aqui, ya que hemos reintroducido retroceso
       en el analizador.  En particular, aunque nosotros sepamos que ahi nunca
       habran  otros  caracteres  en  el flujo de entrada que no sean letras o
       lineas nuevas, flex no puede  figurarse  eso,  y  planeara  la  posible
       necesidad de retroceder cuando haya analizado un token como "auto" y el
       proximo caracter sea algo distinto a  una  linea  nueva  o  una  letra.
       Previamente este podria entonces emparejar la regla "auto" y estar todo
       hecho, pero ahora este no tiene una regla "auto", solamente  una  regla
       "auto\n".   Para eliminar la posibilidad de retroceso, podriamos o bien
       duplicar todas las reglas pero sin linea nueva  al  final,  o,  ya  que
       nunca  esperamos  encontrar  tal  entrada  y  por  lo  tanto ni como es
       clasificada, podemos introducir una regla atrapalo-todo mas,  esta  que
       no incluye una linea nueva:

           %%
           asm\n    |
           auto\n   |
           break\n  |
           ... etc ...
           volatile\n |
           while\n  /* es una palabra clave */

           [a-z]+\n |
           [a-z]+   |
           .|\n     /* no es una palabra clave */

       Compilado  con  -Cf,  esto  es  casi  tan  rapido como lo que uno puede
       obtener de un analizador de flex para este problema en particular.

       Una nota final: flex es lento cuando  empareja  NUL's,  particularmente
       cuando un token contiene multiples NUL's.  Es mejor escribir reglas que
       emparejen cortas cantidades de  texto  si  se  anticipa  que  el  texto
       incluira NUL's a menudo.

       Otra  nota final en relacion con el rendimiento: tal y como se menciono
       en la seccion Como se Reconoce la  Entrada,  el  reajuste  dinamico  de
       yytext  para  acomodar  tokens enormes es un proceso lento porque ahora
       requiere que el token (inmenso) sea reanalizado desde el principio.  De
       esta  manera  si  el  rendimiento  es vital, deberia intentar emparejar
       "grandes" cantidades de texto pero no "inmensas" cantidades,  donde  el
       punto medio esta en torno a los 8K caracteres/token.

GENERANDO ESC'ANERES EN C++

       flex ofrece dos maneras distintas de generar analizadores para usar con
       C++.  La primera manera es simplemente compilar un analizador  generado
       por  flex  usando  un compilador de C++ en lugar de un compilador de C.
       No deberia encontrarse ante ningun  error  de  compilacion  (por  favor
       informe  de  cualquier  error  que  encuentre  a la direccion de correo
       electronico dada en la seccion Autores mas abajo).  Puede entonces usar
       codigo  C++ en sus acciones de las reglas en lugar de codigo C.  Fijese
       que la fuente de entrada por defecto para su analizador permanece  como
       yyin,  y  la  repeticion  por  defecto  se  hace  aun  a  yyout.  Ambos
       permanecen como variables FILE * y no como flujos de C++.

       Tambien puede utilizar flex para generar un analizador como  una  clase
       de C++, utilizando la opcion -+ (o, equivalentemente, %option c++), que
       se especifica automaticamente si  el  nombre  del  ejecutable  de  flex
       finaliza  con un '+', tal como flex++.  Cuando se usa esta opcion, flex
       establece por defecto la generacion del analizador al fichero lex.yy.cc
       en  vez  de  lex.yy.c.   El  analizador  generado incluye el fichero de
       cabecera FlexLexer.h, que define el interfaz con las dos clases de C++.

       La primera clase, FlexLexer, ofrece una clase base abstracta definiendo
       la  interfaz  a  la  clase  del  analizador  general.   Este provee las
       siguientes funciones miembro:

       const char* YYText()
              retorna el texto del  token  reconocido  mas  recientemente,  el
              equivalente a yytext.

       int YYLeng()
              retorna  la  longitud del token reconocido mas recientemente, el
              equivalente a yyleng.

       int lineno() const
              retorna el numero  de  linea  de  entrada  actual  (ver  %option
              yylineno), o 1 si no se uso %option yylineno.

       void set_debug( int flag )
              activa  la bandera de depuracion para el analizador, equivalente
              a la asignacion de yy_flex_debug (ver la  seccion  Opciones  mas
              arriba).   Fijese  que  debe  construir el analizador utilizando
              %option debug para incluir informacion de depuracion en este.

       int debug() const
              retorna el estado actual de la bandera de depuracion.

       Tambien    se    proveen    funciones    miembro     equivalentes     a
       yy_switch_to_buffer(),  yy_create_buffer()  (aunque el primer argumento
       es un puntero a objeto istream*  y  no  un  FILE*),  yy_flush_buffer(),
       yy_delete_buffer(),  y yyrestart() (de nuevo, el primer argumento es un
       puntero a objeto istream* ).

       La segunda clase definida en FlexLexer.h es yyFlexLexer, que se  deriva
       de   FlexLexer.    Esta   define   las   siguientes  funciones  miembro
       adicionales:

       yyFlexLexer( istream* arg_yyin = 0, ostream* arg_yyout = 0 )
              construye un objeto yyFlexLexer usando los flujos dados para  la
              entrada y salida.  Si no se especifica, los flujos se establecen
              por defecto a cin y cout, respectivamente.

       virtual int yylex()
              hace el mismo papel que yylex()  en  los  analizadores  de  flex
              ordinarios:  analiza  el  flujo  de entrada, consumiendo tokens,
              hasta que la accion de una regla retorne  un  valor.   Si  usted
              deriva una subclase S a partir de yyFlexLexer y quiere acceder a
              las funciones y  variables  miembro  de  S  dentro  de  yylex(),
              entonces  necesita  utilizar %option yyclass="S" para informar a
              flex que estara utilizando esa subclase en lugar de yyFlexLexer.
              Es  este  caso,  en  vez  de  generar yyFlexLexer::yylex(), flex
              genera   S::yylex()   (y   tambien    genera    un    substituto
              yyFlexLexer::yylex() que llama a yyFlexLexer::LexerError() si se
              invoca).

       virtual void switch_streams(istream* new_in = 0,
              ostream* new_out = 0) reasigna yyin a new_in (si no es  nulo)  e
              yyout  a  new_out (idem), borrando el buffer de entrada anterior
              si se reasigna yyin.

       int yylex( istream* new_in, ostream* new_out = 0 )
              primero conmuta el flujo de entrada via switch_streams(  new_in,
              new_out ) y entonces retorna el valor de yylex().

       Ademas,   yyFlexLexer   define   las   siguientes  funciones  virtuales
       protegidas que puede redefinir en  clases  derivadas  para  adaptar  el
       analizador:

       virtual int LexerInput( char* buf, int max_size )
              lee  hasta  max_size  caracteres  en buf y devuelve el numero de
              caracteres leidos.  Para indicar el fin-de-la-entrada,  devuelve
              0  caracteres.   Fijese que los analizadores "interactivos" (ver
              las banderas -B y -I )  definen  la  macro  YY_INTERACTIVE.   Si
              usted  redefine LexerInput() y necesita tomar acciones distintas
              dependiendo de si el analizador esta analizando  una  fuente  de
              entrada  interactivo  o no, puede comprobar la presencia de este
              nombre mediante #ifdef.

       virtual void LexerOutput( const char* buf, int size )
              escribe a la salida size caracteres desde el  buffer  buf,  que,
              mientras termine en NUL, puede contener tambien NUL's "internos"
              si las reglas del analizador pueden emparejar  texto  con  NUL's
              dentro de este.

       virtual void LexerError( const char* msg )
              informa  con  un mensaje de error fatal.  La version por defecto
              de esta funcion escribe el mensaje al flujo cerr y finaliza.

       Fijese que  un  objeto  yyFlexLexer  contiene  su  estado  de  analisis
       completo.   Asi  puede  utilizar  tales  objetos para crear analizadore
       reentrantes.   Puede  hacer  varias  instancias  de  la   misma   clase
       yyFlexLexer,  y  puede  combinar  varias  clases de analizadores en C++
       conjuntamente en el  mismo  programa  usando  la  opcion  -P  comentada
       anteriormente.

       Finalmente,  note  que  la  caracteristica %array no esta disponible en
       clases de analizadores en C++; debe utilizar %pointer (por defecto).

       Aqui hay un ejemplo de un analizador en C++ simple:

           // Un ejemplo del uso de la clase analizador en C++ de flex.

           %{
           int mylineno = 0;
           %}

           string  \"[^\n"]+\"

           ws      [ \t]+

           alpha   [A-Za-z]
           dig     [0-9]
           name    ({alpha}|{dig}|\$)({alpha}|{dig}|[_.\-/$])*
           num1    [-+]?{dig}+\.?([eE][-+]?{dig}+)?
           num2    [-+]?{dig}*\.{dig}+([eE][-+]?{dig}+)?
           number  {num1}|{num2}

           %%

           {ws}    /* evita los espacios en blanco y tabuladores */

           "/*"    {
                   int c;

                   while((c = yyinput()) != 0)
                       {
                       if(c == '\n')
                           ++mylineno;

                       else if(c == '*')
                           {
                           if((c = yyinput()) == '/')
                               break;
                           else
                               unput(c);
                           }
                       }
                   }

           {number}  cout << "numero " << YYText() << '\n';

           \n        mylineno++;

           {name}    cout << "nombre " << YYText() << '\n';

           {string}  cout << "cadena " << YYText() << '\n';

           %%

           int main( int /* argc */, char** /* argv */ )
               {
               FlexLexer* lexer = new yyFlexLexer;
               while(lexer->yylex() != 0)
                   ;
               return 0;
               }
       Si desea crear varias (diferentes) clases analizadoras, use la  bandera
       -P  (o la opcion prefix= ) para renombrar cada yyFlexLexer a algun otro
       xxFlexLexer.   Entonces  puede  incluir  <FlexLexer.h>  en  los   otros
       ficheros  fuente  una  vez  por  clase analizadora, primero renombrando
       yyFlexLexer como se presenta a continuacion:

           #undef yyFlexLexer
           #define yyFlexLexer xxFlexLexer
           #include <FlexLexer.h>

           #undef yyFlexLexer
           #define yyFlexLexer zzFlexLexer
           #include <FlexLexer.h>

       si, por ejemplo, usted utilizo %option  prefix="xx"  para  uno  de  sus
       analizadores y %option prefix="zz" para el otro.

       IMPORTANTE:  la  forma actual de la clase analizadora es experimental y
       podria cambiar considerablemente entre versiones principales.

INCOMPATIBILIDADES CON LEX Y POSIX

       flex es una reescritura de la herramienta lex del Unix de AT&T  (aunque
       las  dos  implementaciones  no  comparten  ningun  codigo), con algunas
       extensiones  e  incompatibilidades,  de  las  que  ambas  conciernen  a
       aquellos  que  desean  escribir  analizadores  aceptables por cualquier
       implementacion.  Flex sigue completamente la  especificacion  POSIX  de
       lex,  excepto que cuando se utiliza %pointer (por defecto), una llamada
       a unput() destruye el contenido de yytext,  que  va  en  contra  de  la
       especificacion POSIX.

       En   esta   seccion   comentaremos   todas   las   areas  conocidas  de
       incompatibilidades entre flex, lex de AT&T, y la especificacion POSIX.

       La  opcion  -l  de  flex  activa  la  maxima  compatibilidad   con   la
       implementacion  original  de  lex  de  AT&T,  con el coste de una mayor
       perdida de rendimiento en el analizador generado.  Indicamos mas  abajo
       que incompatibilidades pueden superarse usando la opcion -l.

       flex es totalmente compatible con lex con las siguientes excepciones:

       -      La  variable  interna  del  analizador  de  lex  sin  documentar
              yylineno no se ofrece a menos que se use -l o %option yylineno.

              yylineno  deberia  gestionarse  por  buffer,  en  lugar  de  por
              analizador (simple variable global).

              yylineno no es parte de la especificacion POSIX.

       -      La  rutina  input()  no  es redefinible, aunque podria invocarse
              para leer los caracteres que siguen a  continuacion  de  lo  que
              haya sido reconocido por una regla.  Si input() se encuentra con
              un  fin-de-fichero  se  realiza  el  procesamiento  de  yywrap()
              normal.  input() retorna un fin-de-fichero ``real'' como EOF.

              La entrada en su lugar se controla definiendo la macro YY_INPUT.

              La restriccion de flex de que input() no puede redefinirse va de
              acuerdo a la especificacion POSIX, que simplemente no especifica
              ninguna manera de controlar la entrada del analizador que no sea
              haciendo una asignacion inicial a yyin.

       -      La rutina unput() no es redefinible.   Esta  restriccion  va  de
              acuerdo a POSIX.

       -      Los  analizadores  de  flex  no  son  tan  reentrantes  como los
              analizadores de lex.  En  particular,  si  tiene  un  analizador
              interactivo y un gestor de interrupcion con long-jumps fuera del
              analizador, y el analizador a continuacion se invoca  de  nuevo,
              podria obtener el siguiente mensaje:

                  fatal flex scanner internal error--end of buffer missed

              Para volver al analizador, primero utilice

                  yyrestart( yyin );

              Vea  que  esta llamada eliminara cualquier entrada en el buffer;
              normalmente  esto  no  es  un   problema   con   un   analizador
              interactivo.

              Dese  cuenta  tambien  de que las clases analizadoras en C++ son
              reentrantes, asi que si usar  C++  es  una  opcion  para  usted,
              deberia  utilizarla.  Vea "Generando Escaners en C++" mas arriba
              para los detalles.

       -      output() no se provee.  La salida desde la macro ECHO se hace al
              puntero de fichero yyout (por defecto a stdout).

              output() no es parte de la especificacion POSIX.

       -      lex  no  acepta  condiciones de arranque exclusivas (%x), aunque
              estan en la especificacion POSIX.

       -      Cuando se expanden las definiciones,  flex  las  encierra  entre
              parentesis.  Con lex, lo siguiente:

                  NOMBRE    [A-Z][A-Z0-9]*
                  %%
                  foo{NOMBRE}?      printf( "Lo encontro\n" );
                  %%

              no  reconocera la cadena "foo" porque cuando la macro se expanda
              la regla es equivalente a "foo[A-Z][A-Z0-9]*?" y la  precedencia
              es tal que el '?' se asocia con "[A-Z0-9]*".  Con flex, la regla
              se expandira a "foo([A-Z][A-Z0-9]*)?" y asi la cadena  "foo"  se
              reconocera.

              Fijese  que  si  la  definicion  comienza con ^ o finaliza con $
              entonces no se expande con parentesis, para permitir  que  estos
              operadores   aparezcan   en   las  definiciones  sin  perder  su
              significado especial.  Pero los operadores <s>, /, y <<EOF>>  no
              pueden utilizarse en una definicion de flex.

              El  uso  de  -l  produce en el comportamiendo de lex el no poner
              parentesis alrededor de la definicion.

              La especificacion de POSIX  dice  que  la  definicion  debe  ser
              encerrada entre parentesis.

       -      Algunas  implementaciones  de  lex permiten que la accion de una
              regla comience en una linea separada, si el patron de  la  regla
              tiene espacios en blanco al final:

                  %%
                  foo|bar<espacio aqui>
                    { foobar_action(); }

              flex no dispone de esta propiedad.

       -      La opcion %r de lex (generar un analizador Ratfor) no se ofrece.
              No es parte de la especificacion de POSIX.

       -      Despues de una llamada a unput(), el contenido  de  yytext  esta
              indefinido  hasta que se reconozca el proximo token, a menos que
              el analizador se haya construido usando %array.  Este no  es  el
              caso  de lex o la especificacion de POSIX.  La opcion -l elimina
              esta incompatibilidad.

       -      La precedencia del operador {} (rango  numerico)  es  diferente.
              lex  interpreta  "abc{1,3}"  como  "empareja  uno,  dos,  o tres
              apariciones de
               'abc'", mientras que flex lo  interpreta  como  "empareja  'ab'
              seguida de una, dos o tres apariciones de 'c'".  Lo ultimo va de
              acuerdo con la especificacion de POSIX.

       -      La precedencia del operador  ^  es  diferente.   lex  interpreta
              "^foo|bar"  como "empareja bien 'foo' al principio de una linea,
              o 'bar' en cualquier lugar", mientras  que  flex  lo  interpreta
              como  "empareja  'foo'  o  'bar'  si  vienen al principio de una
              linea".  Lo ultimo va de acuerdo con la especificacion de POSIX.

       -      Las declaraciones especiales del tamano de las tablas  tal  como
              %a que reconoce lex no se requieren en los analizadores de flex;
              flex los ignora.

       -      El identificador FLEX_SCANNER  se  #define  de  manera  que  los
              analizadores  podrian  escribirse para ser procesados con flex o
              con     lex.      Los     analizadores     tambien      incluyen
              YY_FLEX_MAJOR_VERSION   y  YY_FLEX_MINOR_VERSION  indicando  que
              version de flex genero  el  analizador  (por  ejemplo,  para  la
              version 2.5, estas definiciones seran 2 y 5 respectivamente).

       Las  siguientes  propiedades  de  flex  no  se  incluyen  en  lex  o la
       especificacion POSIX:

           analizadores en C++
           %option
           ambitos de condiciones de arranque
           pilas de condiciones de arranque
           analizadores interactivos/no-interactivos
           yy_scan_string() y sus amigas
           yyterminate()
           yy_set_interactive()
           yy_set_bol()
           YY_AT_BOL()
           <<EOF>>
           <*>
           YY_DECL
           YY_START
           YY_USER_ACTION
           YY_USER_INIT
           directivas #line
           %{}'s alrededor de acciones
           varias acciones en una linea

       mas casi todas las banderas de flex.  La ultima propiedad en  la  lista
       se  refiere  al hecho de que con flex puede poner varias acciones en la
       misma linea, sepradas con punto  y  coma,  mientras  que  con  lex,  lo
       siguiente

           foo    handle_foo(); ++num_foos_seen;

       se trunca (sorprendentemente) a

           foo    handle_foo();

       flex  no  trunca la accion.  Las acciones que no se encierran en llaves
       simplemente se terminan al final de la linea.

DIAGN'OSTICOS

       aviso, la regla no se puede aplicar indica que la regla dada  no  puede
       emparejarse  porque  sigue  a  otras  reglas que siempre emparejaran el
       mismo texto que el de esta.  Por ejemplo, en el siguiente ejemplo "foo"
       no  puede emparejarse porque viene despues de una regla "atrapalo-todo"
       para identificadores:

           [a-z]+    obtuvo_identificador();
           foo       obtuvo_foo();

       El uso de REJECT en un analizador suprime este aviso.

       aviso, se ha especificado la opci'on -s pero se puede aplicar  la  regla
       por  defecto  significa  que  es  posible  (tal  vez  unicamente en una
       condicion  de  arranque  en  particular)  que  la  regla  por   defecto
       (emparejar  cualquier  caracter simple) sea la unica que emparejara una
       entrada particular.  Ya que se indico -s, presumiblemente esto no es lo
       que se pretendia.

       definici'on  no  definida {reject_used_but_not_detected} o definici'on no
       definida {yymore_used_but_not_detected} - Estos errores pueden  suceder
       en  tiempo  de  compilacion.   Indican  que  el analizador usa REJECT o
       yymore() pero que flex fallo en darse cuenta del hecho, queriendo decir
       que  flex  analizo  las  dos primeras secciones buscando apariciones de
       estas acciones y fallo en encontrar alguna, pero que de algun  modo  se
       le  han  colado  (por  medio de un archivo #include, por ejemplo).  Use
       %option reject o %option yymore para indicar a flex que  realmente  usa
       esta funcionalidad.

       flex  scanner jammed - un analizador compilado con -s ha encontrado una
       cadena de entrada que no fue reconocida por niguna de sus reglas.  Este
       error puede suceder tambien debido a problemas internos.

       token too large, exceeds YYLMAX - su analizador usa %array y una de sus
       reglas reconocio una cadena mas grande  que  la  constante  YYLMAX  (8K
       bytes  por  defecto).   Usted  puede  incrementar  el valor haciendo un
       #define YYLMAX en la seccion de definiciones de su entrada de flex.

       el analizador requiere la opci'on -8 para poder usar el car'acter  'x'  -
       La  especificacion  de  su  analizador  incluye  el  reconocimiento del
       caracter de 8-bits 'x' y  no  ha  especificado  la  bandera  -8,  y  su
       analizador por defecto esta a 7-bits porque ha usado las opciones -Cf o
       -CF de compresion de tablas.  Vea el comentario de la bandera  -7  para
       los detalles.

       flex  scanner  push-back overflow - usted utilizo unput() para devolver
       tanto texto que el buffer del analizador  no  pudo  mantener  el  texto
       devuelto y el token actual en yytext.  Idealmente el analizador deberia
       ajustar dinamicamente el buffer en este caso, pero  actualmente  no  lo
       hace.

       input buffer overflow, can't enlarge buffer because scanner uses REJECT
       - el analizador estaba intentando  reconocer  un  token  extremadamente
       largo  y  necesito expandir el buffer de entrada.  Esto no funciona con
       analizadores que usan REJECT.

       fatal flex scanner internal error--end of buffer missed  -  Esto  puede
       suceder en un analizador que se reintroduce despues de que un long-jump
       haya saltado fuera (o sobre) el registro de activacion del  analizador.
       Antes de reintroducir el analizador, use:

           yyrestart( yyin );

       o, como se comento mas arriba, cambie y use el analizador como clase de
       C++.

       too many start conditions in <> construct! - ha listado mas condiciones
       de  arranque  en  una construccion <> que las que existen (asi que tuvo
       que haber listado al menos una de ellas dos veces).

FICHEROS

       -lfl   libreria con la que los analizadores deben enlazarse.

       lex.yy.c
              analizador generado (llamado lexyy.c en algunos sistemas).

       lex.yy.cc
              clase generada en C++ con el analizador, cuando se utiliza -+.

       <FlexLexer.h>
              fichero de cabecera definiendo la clase base del  analizador  en
              C++, FlexLexer, y su clase derivada, yyFlexLexer.

       flex.skl
              esqueleto  del  analizador.   Este fichero se utiliza unicamente
              cuando se construye flex, no cuando flex se ejecuta.

       lex.backup
              informacion de  los  retrocesos  para  la  bandera  -b  (llamada
              lex.bck en algunos sistemas).

DEFICIENCIAS / ERRORES

       Algunos   patrones   de   contexto   posterior  no  pueden  reconocerse
       correctamente  y  generan  mensajes  de  aviso   ("contexto   posterior
       peligroso").   Estos son patrones donde el final de la primera parte de
       la regla reconoce el comienzo de la segunda parte, tal como  "zx*/xy*",
       donde  el  'x*'  reconoce  la  'x'  al comienzo del contexto posterior.
       (Fijese que el borrador de POSIX establece que el texto reconocido  por
       tales patrones no esta definido.)

       Para  algunas  reglas de contexto posterior, partes que son de hecho de
       longitud fija no se reconocen como tales, resultando en la  perdida  de
       rendimiento  mencionada  anteriormente.   En particular, las partes que
       usan '|' o {n} (tales como "foo{3}") siempre se consideran de  longitud
       variable.

       La  combinacion  de contexto posterior con la accion especial '|' puede
       producir que el  contexto  posterior  fijo  se  convierta  en  contexto
       posterior  variable  que  es  mas caro.  Por ejemplo, en lo que viene a
       continuacion:

           %%
           abc      |
           xyz/def

       El uso de unput() invalida yytext e yyleng,  a  menos  que  se  use  la
       directiva %array o la opcion -l.

       La  concordancia de patrones de NUL's es substancialmente mas lento que
       el reconocimiento de otros caracteres.

       El ajuste dinamico del buffer de entrada es lento, ya que  conlleva  el
       reanalisis   de   todo  el  texto  reconocido  hasta  entonces  por  el
       (generalmente enorme) token actual.

       Debido  al  uso  simultaneo  de  buffers  de  entrada  y  lecturas  por
       adelantado,  no  puede  entremezclar  llamadas  a rutinas de <stdio.h>,
       tales como, por ejemplo, getchar(), con reglas de flex  y  esperar  que
       funcione.  Llame a input() en su lugar.

       La  totalidad  de  las  entradas  de la tabla listada por la bandera -v
       excluye el numero de entradas en la tabla  necesarias  para  determinar
       que regla ha sido emparejada.  El numero de entradas es igual al numero
       de estados del DFA si el analizador no usa REJECT, y algo mayor que  el
       numero de estados si se usa.

       REJECT no puede usarse con las opciones -f o -F.

       El algoritmo interno de flex necesita documentacion.

VER TAMBI'EN

       lex(1), yacc(1), sed(1), awk(1).

       John  Levine,  Tony  Mason,  and  Doug  Brown, Lex & Yacc, O'Reilly and
       Associates.  Este seguro de obtener la 2a edicion.

       M. E. Lesk and E. Schmidt, LEX - Lexical Analyzer Generator

       Alfred Aho, Ravi  Sethi  and  Jeffrey  Ullman,  Compilers:  Principles,
       Techniques  and  Tools,  Addison-Wesley  (1986) (Edicion en castellano:
       Compiladores:  Principios,  T'ecnicas  y  Herramientas,   Addison-Wesley
       Iberoamericana,  S.A. (1990))  Describe las tecnicas de concordancia de
       patrones usadas por flex (automata finito determinista).

AUTOR

       Vern Paxson, con  la  ayuda  de  muchas  ideas  e  inspiracion  de  Van
       Jacobson.   Version  original  por Jef Poskanzer.  La representacion de
       tablas rapidas es una implementacion parcial de un diseno hecho por Van
       Jacobson.  La implementacion fue hecha por Kevin Gong y Vern Paxson.

       Agradecimientos   a   los  muchos  flex  beta-testers,  feedbackers,  y
       contribuidores, especialmente a Francois Pinard, Casey  Leedom,  Robert
       Abramovitz,  Stan  Adermann,  Terry  Allen,  David Barker-Plummer, John
       Basrai, Neal Becker, Nelson H.F.  Beebe,  benson@odi.com,  Karl  Berry,
       Peter  A.  Bigot,  Simon  Blanchard,  Keith Bostic, Frederic Brehm, Ian
       Brockbank, Kin Cho, Nick  Christopher,  Brian  Clapper,  J.T.  Conklin,
       Jason  Coughlin,  Bill  Cox,  Nick  Cropper,  Dave  Curtis, Scott David
       Daniels,  Chris  G.  Demetriou,  Theo  Deraadt,  Mike  Donahue,   Chuck
       Doucette,  Tom  Epperly,  Leo  Eskin, Chris Faylor, Chris Flatters, Jon
       Forrest, Jeffrey Friedl, Joe Gayda, Kaveh  R.  Ghazi,  Wolfgang  Glunz,
       Eric  Goldman,  Christopher  M. Gould, Ulrich Grepel, Peer Griebel, Jan
       Hajic, Charles Hemphill, NORO Hideo, Jarkko Hietaniemi, Scott  Hofmann,
       Jeff  Honig,  Dana  Hudes, Eric Hughes, John Interrante, Ceriel Jacobs,
       Michal Jaegermann, Sakari Jalovaara, Jeffrey R. Jones,  Henry  Juengst,
       Klaus   Kaempf,  Jonathan  I.  Kamens,  Terrence  O  Kane,  Amir  Katz,
       ken@ken.hilco.com, Kevin B. Kenny, Steve Kirsch, Winfried Koenig,  Marq
       Kole,  Ronald  Lamprecht,  Greg  Lee,  Rohan  Lenard, Craig Leres, John
       Levine, Steve Liddle, David Loffredo, Mike Long, Mohamed el Lozy, Brian
       Madsen,  Malte,  Joe  Marshall,  Bengt  Martensson, Chris Metcalf, Luke
       Mewburn, Jim Meyering, R. Alexander Milowski, Erik Naggum, G.T.  Nicol,
       Landon  Noll,  James  Nordby,  Marc  Nozell,  Richard  Ohnemus, Karsten
       Pahnke, Sven Panne, Roland Pesch,  Walter  Pelissero,  Gaumond  Pierre,
       Esmond   Pitt,   Jef  Poskanzer,  Joe  Rahmeh,  Jarmo  Raiha,  Frederic
       Raimbault, Pat Rankin, Rick Richardson, Kevin Rodgers, Kai Uwe  Rommel,
       Jim  Roskind,  Alberto  Santini, Andreas Scherer, Darrell Schiebel, Raf
       Schietekat, Doug Schmidt, Philippe Schnoebelen, Andreas  Schwab,  Larry
       Schwimmer,  Alex  Siegel,  Eckehard  Stolz,  Jan-Erik  Strvmquist, Mike
       Stump, Paul Stuart, Dave Tallman,  Ian  Lance  Taylor,  Chris  Thewalt,
       Richard  M. Timoney, Jodi Tsai, Paul Tuinenga, Gary Weik, Frank Whaley,
       Gerhard Wilhelms, Kent Williams, Ken Yap,  Ron  Zellar,  Nathan  Zelle,
       David  Zuhn,  y aquellos cuyos nombres han caido bajo mis escasas dotes
       de archivador de correo pero cuyas contribuciones son apreciadas  todas
       por igual.

       Agradecimientos  a  Keith  Bostic,  Jon  Forrest,  Noah  Friedman, John
       Gilmore, Craig Leres, John Levine, Bob Mulcahy, G.T.   Nicol,  Francois
       Pinard,  Rich  Salz,  y  a  Richard  Stallman por la ayuda con diversos
       quebraderos de cabeza con la distribucion.

       Agradecimientos a  Esmond  Pitt  y  Earle  Horton  por  el  soporte  de
       caracteres  de 8-bits; a Benson Margulies y a Fred Burke por el soporte
       de C++; a Kent Williams y a Tom Epperly por el soporte de la  clase  de
       C++;  a  Ove  Ewerlid  por  el soporte de NUL's; y a Eric Hughes por el
       soporte de multiples buffers.

       Este trabajo fue hecho principalmente cuando yo estaba con el Grupo  de
       Sistemas de Tiempo Real en el Lawrence Berkeley Laboratory en Berkeley,
       CA.  Muchas gracias a todos alli por el apoyo que recibi.

       Enviar comentarios a vern@ee.lbl.gov.

       Sobre  esta  traduccion  enviar  comentarios  a  Adrian   Perez   Jorge
       (alu1415@csi.ull.es).

Version 2.5                       Abril 1995                           FLEX(1)