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

NOMBRE

       flex - generador de analizadores léxicos rápidos

SINOPSIS

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

INTRODUCCIÓN

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

           Descripción
               una breve introducción a la herramienta

           Algunos Ejemplos Simples

           Formato del Fichero de Entrada

           Patrones
               las expresiones regulares extendidas que utiliza flex

           Cómo se Empareja la Entrada
               las reglas para determinar lo que ha concordado

           Acciones
               cómo especificar qué hacer cuando concuerde un patrón

           El Escáner Generado
               detalles respecto al escáner que produce flex;
               cómo controlar la fuente de entrada

           Condiciones de Arranque
               la introdución de contexto en sus escáneres, y
               conseguir "mini-escáneres"

           Múltiples Buffers de Entrada
               cómo manipular varias fuentes de entrada; cómo
               analizar cadenas en lugar de ficheros.

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

           Macros Misceláneas
               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 escáneres de flex junto con analizadores de yacc

           Opciones
               opciones de línea de comando de flex, y la directiva
               "%option"

           Consideraciones de Rendimiento
               cómo hacer que sus analizadores vayan tan rápido
               como sea posible

           Generando Escáneres en C++
               la facilidad (experimental) para generar analizadores
               léxicos como clases de C++

           Incompatibilidades con Lex y POSIX
               cómo flex difiere del lex de AT&T y del lex estándar
               de POSIX

           Diagnósticos
               esos mensajes de error producidos por flex (o por
               los escáneres que este genera) cuyo significado podría
               no ser evidente

           Ficheros
               los ficheros usados por flex

           Deficiencias / Errores
               problemas de flex conocidos

           Ver También
               otra documentación, herramientas relacionadas

           Autor
               incluye información de contacto

DESCRIPCIÓN

       flex es una herramienta para generar escáneres: programas que reconocen  patrones  léxicos
       en un texto.  flex lee los ficheros de entrada dados, o la entrada estándar si no se le ha
       indicado ningún nombre de fichero, con  la  descripción  de  un  escáner  a  generar.   La
       descripción  se  encuentra  en  forma  de  parejas  de  expresiones  regulares y código 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 librería -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
       código 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 escáner que siempre que encuentre la
       cadena "username" la reemplazará por el nombre de entrada al sistema del usuario:

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

       Por defecto, cualquier texto que no reconozca el analizador léxico de flex se copia  a  la
       salida, así que el efecto neto de este escáner es copiar su fichero de entrada a la salida
       con cada aparición de "username" expandida.  En esta entrada,  hay  solamente  una  regla.
       "username"  es  el  patrón  y  el "printf" es la acción.  El "%%" marca el comienzo de las
       reglas.

       Aquí hay otro ejemplo simple:

                   int num_lineas = 0, num_caracteres = 0;

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

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

       Este analizador cuenta el número de caracteres y el número de líneas  en  su  entrada  (no
       produce  otra  salida  que  el  informe final de la cuenta).  La primera línea declara dos
       variables globales, "num_lineas" y "num_caracteres", que  son  visibles  al  mismo  tiempo
       dentro  de  yylex()  y  en  la  rutina main() declarada después del segundo "%%".  Hay dos
       reglas, una que empareja una línea nueva ("\n") e incrementa la  cuenta  de  líneas  y  la
       cuenta  de  caracteres,  y  la  que empareja cualquier caracter que no sea una línea nueva
       (indicado por la expresión regular ".").

       Un ejemplo algo más complicado:

           /* escáner para un lenguaje de juguete al estilo de Pascal */

           %{
           /* se necesita esto para la llamada a atof() más 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 podría ser los comienzos de un escáner 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 explicarán en las secciones siguientes.

FORMATO DEL FICHERO DE ENTRADA

       El  fichero  de  entrada de flex está compuesto de tres secciones, separadas por una línea
       donde aparece únicamente un %% en esta:

           definiciones
           %%
           reglas
           %%
           código de usuario

       La sección de definiciones contiene declaraciones de  definiciones  de  nombres  sencillas
       para  simplificar  la  especificación  del  escáner,  y  declaraciones  de  condiciones de
       arranque, que se explicarán en una sección posterior.

       Las definiciones de nombre tienen la forma:

           nombre definición

       El "nombre" es una palabra que comienza con una letra o un  subrayado  ('_')  seguido  por
       cero  o  más letras, dígitos, '_', o '-' (guión).  La definición 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  línea.  Posteriormente se puede hacer referencia a la definición
       utilizando "{nombre}", que se expandirá a "(definición)".  Por ejemplo,

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

       define "DIGITO" como una expresión regular que empareja un dígito sencillo,  e  "ID"  como
       una expresión regular que empareja una letra seguida por cero o más letras o dígitos.  Una
       referencia posterior a

           {DIGITO}+"."{DIGITO}*

       es idéntica a

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

       y empareja uno o más dígitos seguido por un '.' seguido por cero o más dígitos.

       La sección de reglas en la entrada de flex contiene una serie de reglas de la forma:

           patrón   acción

       donde el patrón debe estar sin sangrar y la acción debe comenzar en la misma línea.

       Ver más abajo para una descripción más amplia sobre patrones y acciones.

       Finalmente, la sección de código de usuario simplemente se copia a lex.yy.c  literalmente.
       Esta  sección  se utiliza para rutinas de complemento que llaman al escáner o son llamadas
       por este.  La presencia de esta sección es opcional; Si se omite,  el  segundo  %%  en  el
       fichero de entrada se podría omitir también.

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

       En  la  sección de reglas, cualquier texto o %{} sangrado que aparezca antes de la primera
       regla podría utilizarse para declarar variables que son locales a la rutina de análisis  y
       (después  de  las  declaraciones)  al código que debe ejecutarse siempre que se entra a la
       rutina de análisis.  Cualquier otro texto sangrado o %{} en la  sección  de  reglas  sigue
       copiándose  a  la  salida,  pero su significado no está bien definido y bien podría causar
       errores en tiempo de compilación (esta propiedad se presenta para conformidad con POSIX  ;
       ver más abajo para otras características similares)

       En la sección de definiciones (pero no en la sección de reglas), un comentario sin sangría
       (es decir, una línea comenzando con "/*") también se copia literalmente a la salida  hasta
       el próximo "*/".

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 línea nueva
           [xyz]      una "clase de caracteres"; en este caso, el patrón
                        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
                        mayúscula.
           [^A-Z\n]   cualquier caracter EXCEPTO una letra mayúscula o
                        una línea nueva
           r*         cero o más r's, donde r es cualquier expresión regular
           r+         una o más 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 más r's
           r{4}       exactamente 4 r's
           {nombre}   la expansión de la definición de "nombre"
                      (ver más abajo)
           "[xyz]\"foo"
                      la cadena literal: [xyz]"foo
           \X         si X es una 'a', 'b', 'f', 'n', 'r', 't', o 'v',
                        entonces la interpretación ANSI-C de \x.
                        En otro caso, un literal 'X' (usado para
                        indicar operadores tales como '*')
           \0         un caracter NUL (código ASCII 0)
           \123       el caracter con valor octal 123
           \x2a       el caracter con valor hexadecimal 2a
           (r)        empareja una r; los paréntesis se utilizan para
                        anular la precedencia (ver más abajo)

           rs         la expresión regular r seguida por la expresión
                        regular s; se denomina "concatenación"

           r|s        bien una r o una s

           r/s        una r pero sólo si va seguida por una s.  El
                        texto emparejado por s se incluye cuando se
                        determina si esta regla es el "emparejamiento
                        más largo", pero se devuelve entonces a la
                        entrada antes que se ejecute la acción.  Así
                        que la acción sólo 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 sección Deficiencias / Errores más abajo
                        respecto al "contexto posterior peligroso".)
           ^r         una r, pero sólo al comienzo de una línea (es
                        decir, justo al comienzo del análisis, o a la
                        derecha después de que se haya analizado una
                        línea nueva).
           r$         una r, pero sólo al final de una línea (es decir,
                        justo antes de una línea nueva).  Equivalente
                        a "r/\n".

                      Fíjese que la noción de flex de una "línea nueva"
                      es exáctamente 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 explícitamente
                      usar r/\r\n para "r$".

           <s>r       una r, pero sólo en la condición de arranque s
                        (ver más abajo para una discusión 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 condición de arranque, incluso
                        una exclusiva.

           <<EOF>>    un fin-de-fichero
           <s1,s2><<EOF>>
                      un fin-de-fichero en una condición de arranque s1 o s2

       Fíjese 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  están  agrupadas  de  acuerdo  a  la
       precedencia,  desde la precedencia más alta en la cabeza a la más 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 concatenación,  y  la  concatenación
       más alta que el operador '|'.  Este patrón por lo tanto empareja bien la cadena "foo" o la
       cadena "ba" seguida de cero o más r's.  Para emparejar "foo" o, cero o más "bar"'s, use:

           foo|(bar)*

       y para emparejar cero o más "foo"'s o "bar"'s:

           (foo|bar)*

       Además de caracteres y rangos de caracteres,  las  clases  de  caracteres  pueden  también
       contener  expresiones  de  clases  de  caracteres.   Son  expresiones encerradas entre los
       delimitadores [: y :] (que también deben aparecer entre el '[' y el ']'  de  la  clase  de
       caracteres;  además  pueden  darse otros elementos dentro de la clase de caracteres).  Las
       expresiones válidas 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  función  estándar  isXXX  de  C.  Por ejemplo, [:alnum:] designa aquellos
       caracteres para los cuales isalnum() devuelve verdadero  -  esto  es,  cualquier  caracter
       alfabético  o  numérico.   Algunos  sistemas  no  ofrecen  isblank(),  así 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 escáner ignora la distinción  entre  mayúsculas  y  minúsculas  (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á una
              línea nueva a menos que "\n" (o una secuencia de escape equivalente) sea uno de los
              caracteres  presentes explícitamente en la clase de caracteres negada (p.ej., "[^A-
              Z\n]").  Esto es diferente a cómo muchas de las otras herramientas  de  expresiones
              regulares  tratan  las  clases  de  caracteres  negadas, pero desafortunadamente la
              inconsistencia está fervientemente  enrraizada  históricamente.   Emparejar  líneas
              nuevas  significa  que  un  patrón como [^"]* puede emparejar la entrada completa a
              menos que haya otra comilla en la entrada.

       -      Una regla puede tener lo más una instancia del contexto posterior (el operador  '/'
              o el operador '$').  La condición de arranque, los patrones '^', y "<<EOF>>" pueden
              aparecer solamente al principio de un patrón, y, al igual que con  '/'  y  '$',  no
              pueden  agruparse dentro de paréntesis.  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 está permitido:

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

              Fíjese 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 línea nueva, puede usarse
              lo siguiente (la acción especial '|' se explica más abajo):

                  foo      |
                  bar$     /* la acción va aquí */

              Un truco parecido funcionará para emparejar un "foo" o, un "bar"  al  principio  de
              una línea.

CÓMO SE EMPAREJA LA ENTRADA

       Cuando  el escáner generado está funcionando, este analiza su entrada buscando cadenas que
       concuerden con cualquiera de sus patrones.  Si encuentra más de un emparejamiento, toma el
       que  empareje  más  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  más
       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)  está  disponible  en  el  puntero  a caracter global yytext, y su
       longitud en la variable global entera  yyleng.   Entonces  la  acción  correspondiente  al
       patrón  emparejado  se  ejecuta  (una  descripción  más  detallada de las acciones viene a
       continuación), 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 estándar.
       Así, la entrada válida más simple de flex es:

           %%

       que genera un escáner que simplemente copia su entrada (un caracter a la vez) a la salida.

       Fíjese 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 definición que usa flex
       incluyendo una de las directivas especiales  %pointer  o  %array  en  la  primera  sección
       (definiciones)  de su entrada de flex.  Por defecto es %pointer, a menos que use la opción
       de compatibilidad -l, en cuyo caso yytext será un array.  La ventaja de usar  %pointer  es
       un  análisis substancialmente más rápido y la ausencia de desbordamiento del buffer cuando
       se emparejen tokens muy grandes (a menos que se agote la memoria dinámica).  La desventaja
       es  que  se  encuentra  restringido  en  cómo sus acciones pueden modificar yytext (vea la
       siguiente sección), y las llamadas a la función 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 más abajo).  Además, los programas de lex
       existentes a veces acceden a yytext externamente utilizando declaraciones de la forma:
           extern char yytext[];
       Esta definición es errónea 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  tamaño símplemente definiendo con #define a
       YYLMAX con un valor diferente en la primera sección  de  su  entrada  de  flex.   Como  se
       mencionó  antes,  con  %pointer  yytext  crece dinámicamente para acomodar tokens grandes.
       Aunque esto signifique que con %pointer su  escáner  puede  acomodar  tokens  muy  grandes
       (tales  como emparejar bloques enteros de comentarios), tenga presente que cada vez que el
       escáner deba cambiar el tamaño de yytext también debe  reiniciar  el  análisis  del  token
       entero  desde  el  principio,  así que emparejar tales tokens puede resultar lento.  Ahora
       yytext no crece dinámicamente si una llamada a unput() hace que se deba devolver demasiado
       texto; en su lugar, se produce un error en tiempo de ejecución.

       También tenga en cuenta que no puede usar %array en los analizadores generados como clases
       de C++ (la opción c++; vea más abajo).

ACCIONES

       Cada patrón en una regla tiene una acción asociada, que puede ser cualquier  sentencia  en
       C.  El patrón finaliza en el primer caracter de espacio en blanco que no sea una secuencia
       de escape; lo que queda de la línea es su acción.   Si  la  acción  está  vacía,  entonces
       cuando  el  patrón  se empareje el token de entrada simplemente se descarta.  Por ejemplo,
       aquí está la especificación de un programa que borra todas las apariciones de "zap me"  en
       su entrada:

           %%
           "zap me"

       (Este  copiará  el  resto de caracteres de la entrada a la salida ya que serán emparejados
       por la regla por defecto.)

       Aquí 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 línea:

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

       Si  la  acción  contiene  un  '{',  entonces  la  acción  abarca hasta que se encuentre el
       correspondiente '}', y la acción podría entonces cruzar varias líneas.  flex es  capaz  de
       reconocer  las  cadenas  y  comentarios  de  C  y  no se dejará engañar por las llaves que
       encuentre dentro de estos, pero aun así también permite que las acciones comiencen con  %{
       y  considerará  que  la acción es todo el texto hasta el siguiente %} (sin tener en cuenta
       las llaves ordinarias dentro de la acción).

       Una acción que consista sólamente de una barra vertical ('|') significa "lo mismo  que  la
       acción para la siguiente regla."  Vea más abajo para una ilustración.

       Las acciones pueden incluir código C arbitrario, incuyendo sentencias return para devolver
       un valor desde cualquier rutina llamada yylex().  Cada vez que se  llama  a  yylex()  esta
       continúa  procesando  tokens  desde donde lo dejó la última vez hasta que o bien llegue al
       final del fichero o ejecute un return.

       Las acciones tienen libertad para  modificar  yytext  excepto  para  alargarla  (añadiendo
       caracteres  al  final--esto  sobreescribirá  más tarde caracteres en el flujo de entrada).
       Sin embargo esto no se aplica cuando se utiliza %array (ver arriba); en ese  caso,  yytext
       podría modificarse libremente de cualquier manera.

       Las  acciones  tienen libertad para modificar yyleng excepto que estas no deberían hacerlo
       si la acción también incluye el uso de yymore() (ver más abajo).

       Hay un número de directivas especiales que pueden incluirse dentro de una acción:

       -      ECHO copia yytext a la salida del escáner.

       -      BEGIN seguido del nombre de  la  condición  de  arranque  pone  al  escáner  en  la
              condición de arranque correspondiente (ver más abajo).

       -      REJECT  ordena  al escáner 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  describió
              anteriormente  en  "Cómo  se  Empareja la Entrada", y yytext e yyleng se ajustan de
              forma apropiada.  Podría ser una que empareje tanto texto como  la  regla  escogida
              originalmente  pero que viene más tarde en el fichero de entrada de flex, o una que
              empareje menos texto.  Por  ejemplo,  lo  que  viene  a  continuación  contará  las
              palabras en la entrada y llamará a la rutina especial() siempre que vea "frob":

                          int contador_palabras = 0;
                  %%

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

              Sin  el  REJECT, cualquier número de "frob"'s en la entrada no serían contados como
              palabras, ya que el escáner normalmente ejecuta solo  una  acción  por  token.   Se
              permite el uso de múltiples REJECT's, cada uno buscando la siguiente mejor elección
              a la regla que actualmente esté activa.  Por ejemplo, cuando el  siguiente  escáner
              analice el token "abcd", este escribirá "abcdabcaba" a la salida:

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

              (Las  primeras  tres  reglas  comparten la acción de la cuarta ya que estas usan la
              acción especial '|'.)  REJECT es una propiedad particularmente cara en términos  de
              rendimiento  del  escáner; si se usa en cualquiera de las acciones del escáner esta
              ralentizará todo el proceso de emparejamiento del escáner.  Además, REJECT no puede
              usarse con las opciones -Cf o -CF (ver más abajo).

              Fíjese  también  que  a  diferencia de las otras acciones especiales, REJECT es una
              bifurcación; el código que la siga inmediatamente en la acción no será ejecutado.

       -      yymore() dice al escáner que la próxima  vez  que  empareje  una  regla,  el  token
              correspondiente  debe  ser  añadido  tras  el  valor  actual  de yytext en lugar de
              reemplazarlo.   Por  ejemplo,  dada  la  entrada  "mega-klugde"  lo  que  viene   a
              continuación escribirá "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 aún está esperando al inicio de yytext asi que  el
              ECHO para la regla del "kludge" realmente escribirá "mega-kludge".

       Dos  notas  respecto  al  uso  de  yymore().  Primero, yymore() depende de que el valor de
       yyleng refleje correctamente el tamaño del token actual, así que no debe modificar  yyleng
       si  está  utilizando yymore().  Segundo, la presencia de yymore() en la acción del escáner
       implica una pequeña penalización de rendimiento en  la  velocidad  de  emparejamiento  del
       escáner.

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

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

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

       Fíjese 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 será el próximo
              caracter analizado.  La siguiente acción tomará el  token  actual  y  hará  que  se
              vuelva a analizar pero encerrado entre paréntesis.

                  {
                  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 );
                  }

              Fíjese  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  atrás  hacia
              delante.

       Un  problema potencial importante cuando se utiliza unput() es que si está usando %pointer
       (por defecto), una llamada a unput() destruye el contenido de yytext,  comenzando  con  su
       caracter  más  a  la  derecha y devorando un caracter a la izquierda con cada llamada.  Si
       necesita que se preserve el valor de yytext después de una llamada a unput() (como  en  el
       ejemplo  anterior),  usted debe o bien copiarlo primero en cualquier lugar, o construir su
       escáner usando %array
        (ver Cómo 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 próximo caracter del flujo de entrada.  Por ejemplo, lo que viene a
              continuación 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;    /* encontró el final */
                                      }

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

              (Fíjese que si el escáner se compila usando C++, entonces  a  input()  se  le  hace
              referencia  con  yyinput(),  para evitar una colisión de nombre con el flujo de C++
              por el nombre input.)

       -      YY_FLUSH_BUFFER vacía el buffer interno del escáner de manera que  la  próxima  vez
              que  el escáner intente emparejar un token, este primero rellenará el buffer usando
              YY_INPUT (ver El Escáner Generado, más abajo).  Esta acción es un caso especial  de
              la  función  más  general  yy_flush_buffer(),  descrita  más  abajo  en  la sección
              Múltiples Buffers de Entrada.

       -      yyterminate() se puede utilizar en lugar de una sentencia de retorno en una acción.
              Esta  hace  que finalice el escáner y retorne un 0 a quien haya llamado al escáner,
              indicando que "todo está hecho".  Por defecto, también  se  llama  a  yyterminate()
              cuando se encuentra un fin-de-fichero.  Esta es una macro y podría ser redefinida.

El Escáner Generado

       La  salida  de flex es el fichero lex.yy.c, que contiene la rutina de análisis yylex(), un
       número de tablas usadas por esta para emparejar tokens, y un número de rutinas  auxiliares
       y macros.  Por defecto, yylex() se declara así

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

       (Si  su  entorno  acepta prototipos de funciones, entonces este será "int yylex( void )").
       Esta definición podría modificarse definiendo la macro  "YY_DECL".   Por  ejemplo,  podría
       utilizar:

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

       para  darle  a  la  rutina de análisis el nombre lexscan, que devuelve un real, y toma dos
       reales como argumentos.  Fíjese que si pone argumentos a la rutina de análisis usando  una
       declaración  de  función no-prototipada/tipo-K&R, debe hacer terminar la definición 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 función continúa 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  escáner  alcanza  un  fin-de-fichero,  entonces  el comportamiento en las llamadas
       posteriores está indefinido a menos que o bien yyin apunte a un nuevo fichero  de  entrada
       (en  cuyo  caso  el  análisis continúa 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  asignación  a  yyin  de  un  nuevo
       fichero  de  entrada o el uso de yyrestart() para hacerlo; esto último está disponible por
       compatibilidad con versiones anteriores de flex, y porque puede utilizarse  para  conmutar
       ficheros  de  entrada  en  medio del análisis.  También se puede utilizar para desechar el
       buffer de entrada actual, invocándola con un argumento igual a yyin; pero  mejor  es  usar
       YY_FLUSH_BUFFER  (ver más arriba).  Fíjese que yyrestart() no reinicializa la condición de
       arranque a INITIAL (ver Condiciones de Arranque, más abajo).

       Si yylex() para el análisis debido a la ejecución de una sentencia return en  una  de  las
       acciones, el analizador podría ser llamado de nuevo y este reanudaría el análisis donde lo
       dejó.

       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 acción es poner hasta max_size caracteres
       en el array de caracteres buf y devolver en la variable entera result bien o el número  de
       caracteres  leídos  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 definición de ejemplo para YY_INPUT (en la sección  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  definición  cambiará el procesamiento de la entrada para que suceda un caracter a la
       vez.

       Cuando el analizador reciba una indicación de fin-de-fichero desde YY_INPUT, entonces esta
       comprueba  la  función yywrap().  Si yywrap() devuelve falso (cero), entonces se asume que
       la función ha ido más allá y ha preparado yyin para que apunte a otro fichero de  entrada,
       y  el  análisis  continúa.   Si  este  retorna verdadero (no-cero), entonces el analizador
       termina, devolviendo un 0 a su invocador.  Fíjese que en cualquier caso, la  condición  de
       arranque permanece sin cambios; esta no vuelve a ser INITIAL.

       Si  no  proporciona  su  propia  versión  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 versión 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
       sección Múltiples Buffers de Entrada.

       El analizador escribe su salida con ECHO a la variable global yyout (por defecto, stdout),
       que el usuario podría redefinir asignándole cualquier otro puntero a FILE.

CONDICIONES DE ARRANQUE

       flex  dispone  de un mecanismo para activar reglas condicionalmente.  Cualquier regla cuyo
       patrón se prefije con "<sc>" únicamente estará activa cuando el analizador se encuentre en
       la condición de arranque llamada "sc".  Por ejemplo,

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

       estará activa solamente cuando el analizador esté en la condición de arranque "STRING", y

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

       estará  activa  solamente  cuando  la  condición  de arranque actual sea o bien "INITIAL",
       "STRING", o "QUOTE".

       Las condiciones de arranque se declaran en la (primera)  sección  de  definiciones  de  la
       entrada usando líneas sin sangrar comenzando con %s o %x seguida por una lista de nombres.
       Lo primero declara condiciones de arranque inclusivas, lo último condiciones  de  arranque
       exclusivas.  Una condición de arranque se activa utilizando la acción BEGIN.  Hasta que se
       ejecute la próxima acción BEGIN, las reglas con la  condición  de  arranque  dada  estarán
       activas y las reglas con otras condiciones de arranque estarán inactivas.  Si la condición
       de arranque es inclusiva, entonces las reglas sin condiciones de arranque también  estarán
       activas.  Si  es  exclusiva, entonces sólamente las reglas calificadas con la condición de
       arranque estarán activas. Un conjunto de reglas dependientes  de  la  misma  condición  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
       fácil  la  especificación de "mini-escáneres" que analizan porciones de la entrada que son
       sintácticamente diferentes al resto (p.ej., comentarios).

       Si la distinción entre condiciones de arranque inclusivas o  exclusivas  es  aún  un  poco
       vaga,  aquí  hay  un ejemplo simple que ilustra la conexión 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 patrón bar en el segundo ejemplo no estará activo
       (es  decir, no puede emparejarse) cuando se encuentre en la condición de arranque example.
       Si hemos usado <example> para calificar  bar,  aunque,  entonces  este  únicamente  estará
       activo en example y no en INITIAL, mientras que en el primer ejemplo está activo en ambas,
       porque en el primer ejemplo la condición de arranque example es una condición de  arranque
       inclusiva (%s).

       Fíjese  también  que  el  especificador  especial de la condición de arranque <*> empareja
       todas las condiciones de arranque.  Así, el ejemplo anterior también 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
       están activas.  Este estado también puede referirse a la condición de arranque  "INITIAL",
       así  que  BEGIN(INITIAL)  es  equivalente  a  BEGIN(0).   (No  se requieren los paréntesis
       alrededor del nombre de la condición de arranque pero se considera de buen estilo.)

       Las acciones BEGIN pueden darse también como código sangrado al comienzo de la sección  de
       reglas.   Por  ejemplo,  lo  que  viene  a continuación hará que el analizador entre en la
       condición 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
           ...más reglas a continuación...

       Para  ilustrar  los usos de las condiciones de arranque, aquí hay un analizador que ofrece
       dos interpretaciones diferentes para una cadena  como  "123.456".   Por  defecto  este  la
       tratará  como tres tokens, el entero "123", un punto ('.'), y el entero "456".  Pero si la
       cadena viene precedida en la línea por la cadena "espera-reales" este la tratará  como  un
       único token, el número en coma flotante 123.456:

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

           %%
           espera-reales        BEGIN(espera);

           <espera>[0-9]+"."[0-9]+      {
                       printf( "encontró un real, = %f\n",
                               atof( yytext ) );
                       }
           <espera>\n           {
                       /* este es el final de la línea,
                        * así que necesitamos otro
                        * "espera-numero" antes de
                        * que volvamos a reconocer más
                        * números
                        */
                       BEGIN(INITIAL);
                       }

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

           "."         printf( "encontró un punto\n" );

       Aquí  está  un analizador que reconoce (y descarta) comentarios de C mientras mantiene una
       cuenta de la línea 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 más que pueda, ya que esto es un buen logro.

       Fíjese que los nombres de las condiciones de arranque  son  realmente  valores  enteros  y
       pueden  ser  almacenados  como  tales.  Así, lo anterior podría 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);

       Además, puede acceder a la condición de arranque actual usando la macro  de  valor  entero
       YY_START.   Por  ejemplo,  las  asignaciones  anteriores  a  invocador_comentario  podrían
       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).

       Fíjese 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,  aquí  hay  un ejemplo de cómo emparejar cadenas entre comillas al estilo de C
       usando condiciones de arranque exclusivas,  incluyendo  secuencias  de  escape  expandidas
       (pero sin incluir la comprobación 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 está hecho */
                   BEGIN(INITIAL);
                   *string_buf_ptr = '\0';
                   /* devuelve un tipo de token de cadena constante y
                    * el valor para el analizador sintáctico
                    */
                   }

           <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 errónea;
                    * 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 número
       de reglas todas precedidas por la(s) misma(s) condición(es) de arranque.  Flex  hace  esto
       un  poco  más fácil y claro introduciendo la noción de ámbito de la condición de arranque.
       Un ámbito de condición de arranque comienza con:

           <SCs>{

       Donde SCs es una lista de una o más condiciones de arranque.   Dentro  del  ámbito  de  la
       condición  de arranque, cada regla automáticamente tiene el prefijo <SCs> aplicado a esta,
       hasta un '}' que corresponda con el '{' inicial.  Así, 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 ámbitos de las condiciones de arranque pueden anidarse.

       Están disponibles tres rutinas para manipular pilas de condiciones de arranque:

       void yy_push_state(int new_state)
              empuja la condición 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 también 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 dinámicamente y por ello  no  tiene  asociada
       ninguna  limitación  de  tamaño.   Si  la  memoria  se  agota,  se aborta la ejecución del
       programa.

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

MÚLTIPLES 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  dónde será leída la siguiente entrada escribiendo
       símplemente un YY_INPUT que sea sensible al contexto del análisis.  A YY_INPUT sólo se  le
       llama  cuando  el analizador alcanza el final de su buffer, que podría ser bastante tiempo
       después 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 tamaño "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 tamaño).  Este devuelve un handle YY_BUFFER_STATE, que podría  pasarse
       a  otras  rutinas  (ver  más  abajo).   El  tipo  de  YY_BUFFER_STATE  es un puntero a una
       estructura opaca struct yy_buffer_state, de manera que podría inicializar de forma  segura
       variables  YY_BUFFER_STATE a ((YY_BUFFER_STATE) 0) si lo desea, y también hacer referencia
       a la estructura opaca para declarar correctamente buffers de  entrada  en  otros  ficheros
       fuente  además  de  los  de  su  analizador.  Fíjese 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 más 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.  Fíjese que yy_switch_to_buffer() podría usarlo  yywrap()  para  arreglar
       las  cosas para un análisis continuo, en lugar de abrir un nuevo fichero y que yyin apunte
       a este.  Fíjese  también  que  cambiar  las  fuentes  de  entrada  ya  sea  por  medio  de
       yy_switch_to_buffer() o de yywrap() no cambia la condición 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 también limpiar el  contenido  actual  de  un
       buffer usando:

           void yy_flush_buffer( YY_BUFFER_STATE buffer )

       Esta  función  descarta  el  contenido  del  buffer,  de  manera que la próxima vez que el
       analizador intente emparejar un token desde el buffer, este primero  rellenará  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 dinámicos.

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

       Aquí hay un ejemplo del uso de estas propiedades para escribir un analizador  que  expande
       ficheros incluidos (la propiedad <<EOF>> se comenta más 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 análisis 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 debería borrar
       con yy_delete_buffer() cuando termine con él).  Estas también  conmutan  el  nuevo  buffer
       usando  yy_switch_to_buffer(),  de  manera  que  la  próxima  llamada  a yylex() comenzará
       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.

       Fíjese que ambas de estas funciones crean y analizan una  copia  de  la  cadena  o  bytes.
       (Esto  podría  ser  deseable,  ya  que  yylex()  modifica el contenido del buffer que está
       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  últimos  bytes  deben  ser  YY_END_OF_BUFFER_CHAR (ASCII NUL).  Estos dos
              últimos  bytes  no  se  analizan;  así,  el  análisis  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 conversión a una
              expresión entera para reflejar el tamaño 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 acción debe finalizar  haciendo  una  de  estas  cuatro
       cosas:

       -      asignando  a  yyin  un  nuevo  fichero de entrada (en versiones anteriores de flex,
              después de hacer la asignación debía llamar a la acción especial YY_NEW_FILE;  esto
              ya no es necesario);

       -      ejecutando una sentencia return;

       -      ejecutando la acción especial yyterminate();

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

       Las reglas <<EOF>> no deberían usarse con otros patrones; estas deberían  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 condición de arranque inicial, use

           <INITIAL><<EOF>>

       Estas reglas son útiles 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ÁNEAS

       La  macro  YY_USER_ACTION  puede  definirse para indicar una acción que siempre se ejecuta
       antes de la acción de la regla emparejada.  Por ejemplo,  podría  declararse  con  #define
       para  que  llame  a  una  rutina  que  convierta  yytext a minúsculas.  Cuando se invoca a
       YY_USER_ACTION, la variable yy_act da el número de la regla emparejada (las  reglas  están
       numeradas  comenzando en 1).  Suponga que quiere medir la frecuencia con la que sus reglas
       son emparejadas.  Lo que viene a continuación podría hacer este truco:

           #define YY_USER_ACTION ++ctr[yy_act]

       donde ctr en un vector que mantiene la cuenta para las diferentes reglas.  Fíjese  que  la
       macro  YY_NUM_RULES da el número total de reglas (incluyendo la regla por defecto, incluso
       si usted usa -s), así que una declaración correcta para ctr es:

           int ctr[YY_NUM_RULES];

       La macro YY_USER_INIT podría definirse para indicar una  acción  que  siempre  se  ejecuta
       antes  del  primer  análisis  (y  antes  de  que  se  haga  la  inicialización interna del
       analizador).  Por ejemplo, este podría 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  más  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 más abajo).  Un valor distinto de cero en la invocación de la macro marcará
       el buffer como interactivo, un valor de cero como no-interactivo.  Fíjese que  el  uso  de
       esta  macro no tiene en cuenta %option always-interactive o %option never-interactive (ver
       Opciones más abajo).  yy_set_interactive() debe invocarse antes del comienzo del  análisis
       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
       análisis actual para el próximo emparejamiento de token se hace como si se  encontrara  al
       principio  de  una  línea.   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 próximo token analizado a partir del buffer
       actual tendrá activas las reglas '^', de otra manera falso.

       En el analizador generado, las acciones están recogidas en una  gran  sentencia  switch  y
       separadas  usando YY_BREAK, que puede ser redefinida.  Por defecto, este es símplemente un
       "break", para separar la acción 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
       (¡mientras 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 acción de
       la regla finaliza con un "return", el YY_BREAK es inaccesible.

VALORES DISPONIBLES AL USUARIO

       Esta sección 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 añadir caracteres al final).

              Si aparece la directiva especial %array en la primera sección de la descripción 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  sección  si
              no  le  gusta  el  valor  por defecto (generalmente 8KB).  El uso de %array produce
              analizadores algo más 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 podría  redefinirse
              pero  hacerlo solo tiene sentido antes de que el análisis comience o después de que
              se haya encontrado un EOF.  Cambiándolo en medio  del  análisis  tendrá  resultados
              inesperados ya que flex utiliza buffers en su entrada; use yyrestart() en su lugar.
              Una vez que el análisis 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 ) podría 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).  Fíjese que llamando  a  yyrestart()
              con  yyin  como  argumento  de  esta  manera elimina el buffer de entradda actual y
              continúa 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 condición de arranque
              actual.  Posteriormente puede  usar  este  valor  con  BEGIN  para  retornar  a  la
              condición de arranque.

INTERFAZ CON YACC

       Uno  de  los  usos  principales  de  flex  es como compañero del generador de analizadores
       sintácticos yacc.  Los analizadores de yacc esperan invocar a una rutina  llamada  yylex()
       para  encontrar el próximo token de entrada.  La rutina se supone que devuelve el tipo del
       próximo token además de poner cualquier valor asociado en la variable global yylval.  Para
       usar  flex  con  yacc,  uno especifica la opción -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 podría parecerse a:

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

           %%

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

OPCIONES

       flex tiene las siguientes opciones:

       -b     Genera información 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.
              Añadiendo reglas uno puede eliminar estados de retroceso.  Si todos los estados  de
              retroceso  se  eliminan  y  se usa -Cf o -CF, el analizador generado funcionará más
              rápido (ver la bandera -p).  Únicamente los usuarios que desean exprimir  hasta  el
              último  ciclo  de  sus  analizadores necesitan preocuparse de esta opción.  (Ver la
              sección sobre Consideraciones de Rendimiento más abajo.)

       -c     es una opción que no hace nada, incluída para cumplir con POSIX.

       -d     hace que el analizador generado se ejecute en modo de depuración.  Siempre  que  se
              reconoce  un  patrón y la variable global yy_flex_debug no es cero (que por defecto
              no lo es), el analizador escribirá en stderr una línea de la forma:

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

              El número de línea 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 también
              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ápido.  No se realiza una compresión de tablas y se evita
              el uso de stdio.  El resultado es grande pero rápido.  Esta opción es equivalente a
              -Cfr (ver más abajo).

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

       -i     indica a flex que genere un analizador case-insensitive.  Se ignorará si las letras
              en los patrones de entrada de flex son en mayúsculas o en minúsculas, y los  tokens
              en la entrada serán emparejados sin tenerlo en cuenta.  El texto emparejado dado en
              yytext  tendrá  las  mayúsculas  y  minúsculas  preservadas  (es   decir,   no   se
              convertirán).

       -l     activa  el  modo  de máxima compatibilidad con la implementación original de lex de
              AT&T.  Fíjese que esto no significa una compatibilidad completa.  El  uso  de  esta
              opción  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 sección "Incompatibilidades con Lex y POSIX" más abajo.  Esta
              opción también hace que se defina el nombre  YY_FLEX_LEX_COMPAT  en  el  analizador
              generado.

       -n     es otra opción que no hace nada, incluída 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  provocarán  pérdidas
              serias  de  rendimiento  en  el  analizador resultante.  Si indica esta bandera dos
              veces, también obtendrá comentarios que tratan  de  las  propiedades  que  producen
              pérdidas menores de rendimiento.

              Fíjese  que  el  uso  de REJECT, %option yylineno, y el contexto posterior variable
              (vea  la  sección  Deficiencias  /  Errores  más  abajo)  supone  una  penalización
              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  opción  es
              útil para encontrar agujeros en el conjunto de reglas del analizador.

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

       -v     especifica que flex debería escribir en stderr un sumario de estadísticas  respecto
              al  analizador  que  genera.   La mayoría de las estadísticas no tienen significado
              para el usuario casual de flex, pero la primera línea identifica la versión de flex
              (la misma que se informa con -V), y la próxima línea 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 más abajo).   En  general,  use  -B  cuando  esté
              seguro  de que su analizador nunca se usará de forma interactiva, y quiere con esto
              exprimir un poco más el rendimiento.  Si por el contrario su objetivo es exprimirlo
              mucho más, debería estar utilizando la opción -Cf o -CF (comentadas más abajo), que
              activa -B automáticamente de todas maneras.

       -F     especifica que se debe utilizar la representación de la  tabla  rápida  (y  elimina
              referencias  a  stdio).   Esta representación es aproximadamente tan rápida como la
              representación completa de la tabla (-f), y para algunos conjuntos de patrones será
              considerablemente más pequeña (y para otros, mayor).  En general, si el conjunto de
              patrones contiene "palabras clave" y una regla "identificador" atrápalo-todo,  como
              la del conjunto:

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

              entonces  será  mejor  que utilice la representación de la tabla completa.  Si sólo
              está presente la regla "identificador" y utiliza una tabla  hash  o  algo  parecido
              para detectar palabras clave, mejor utilice -F.

              Esta opción es equivalente a -CFr (ver más abajo).  Esta opción 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 únicamente si
              debe hacerlo.  Resulta que mirando siempre un caracter extra hacia delante, incluso
              si el analizador ya ha visto suficiente texto para eliminar la ambigüedad del token
              actual, se es un poco más rápido que mirando solamente cuando es  necesario.   Pero
              los  analizadores  que  siempre  miran  hacia  delante  producen  un comportamiento
              interactivo malísimo; por ejemplo, cuando un usuario teclea una línea  nueva,  esta
              no  se reconoce como un token de línea nueva hasta que introduzca otro token, que a
              menudo significa introducir otra línea completa.

              Los analizadores de flex por defecto son interactivos a menos que use la opción -Cf
              o  -CF  de  compresión  de  tablas  (ver  más abajo).  Esto es debido a que si está
              buscando un rendimiento alto tendría que estar utilizando una  de  estas  opciones,
              así que si no lo ha hecho flex asume que prefiere cambiar un poco de rendimiento en
              tiempo de ejecución en beneficio de un comportamiento iteractivo intuitivo.  Fíjese
              también  que no puede utilizar -I conjuntamente con -Cf o -CF.  Así, esta opción no
              se necesita realmente; está activa por defecto para todos esos casos en los que  se
              permite.

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

       -L     ordena  a  flex que no genere directivas #line.  Sin esta opción, flex acribilla al
              analizador generado con directivas #line para que los  mensajes  de  error  en  las
              acciones  estén  localizadas correctamente respecto al fichero original de flex (si
              los errores son debidos al código en el fichero de entrada), o a lex.yy.c  (si  los
              errores  son  fallos  de  flex  --  debería  informar  de este tipo de errores a la
              dirección de correo dada más abajo).

       -T     hace que flex se ejecute en modo de traza.  Este generará un montón de mensajes  en
              stderr  relativos  a  la forma de la entrada y el autómata finito no-determinista o
              determinista  resultante.   Esta  opción  generalmente  es  para   usarla   en   el
              mantenimiento de flex.

       -V     imprime el número de la versión en stdout y sale.  --version es un sinónimo de -V.

       -7     ordena  a  flex  que  genere  un analizador de 7-bits, es decir, uno que sólo 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 tamaño de aquellas generadas
              usando la opción -8 (ver más abajo).  La desventaja es  que  tales  analizadores  a
              menudo se cuelgan o revientan si su entrada contiene caracteres de 8-bits.

              Fíjese,  sin  embargo, que a menos que genere su analizador utilizando las opciones
              de compresión de tablas -Cf o -CF, el uso de  -7  ahorrará  solamente  una  pequeña
              cantidad  de  espacio  en  la  tabla,  y hará 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 esté configurado para generar analizadores de
              8-bits  (a menudo este será el caso de los sistemas fuera de EEUU).  Puede decir si
              flex generó un analizador de 7 u 8 bits inspeccionando el sumario de banderas en la
              salida de -v como se describió anteriormente.

              Fíjese  que si usa -Cfe o -CFe (esas opciones de compresión de tablas, pero también
              el uso de clases de equivalencia como se comentará más abajo), flex genera aún  por
              defecto  un  analizador  de  8-bits,  ya  que  normalmente  con  estas  opciones de
              compresión las tablas de 8-bits completas no son mucho más 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 sólo 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 más arriba a cerca del  comportamiento  por  defecto  de
              flex y la discusión entre los analizadores de 7-bits y 8-bits.

       -+     especifica  que quiere que flex genere un analizador como una clase de C++.  Vea la
              sección Generando Escáners en C++ más abajo para los detalles.

       -C[aefFmr]
              controla el grado de compresión de la tabla  y,  más  generalmente,  el  compromiso
              entre analizadores pequeños y analizadores rápidos.

              -Ca  ("alinea")  ordena  a  flex  que  negocie  tablas más grandes en el analizador
              generado para un comportamiento más rápido porque los elementos de las tablas están
              mejor  alineados  para el acceso a memoria y computación.  En algunas arquitecturas
              RISC, la búsqueda y manipulación de  palabras  largas  es  más  eficiente  que  con
              unidades  más  pequeñas  tales  como  palabras cortas.  Esta opción puede doblar el
              tamaño 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  léxicas  (por ejemplo, si la única
              aparición de dígitos en la entrada de flex es en la  clase  de  caracteres  "[0-9]"
              entonces  los  dígitos  '0',  '1',  ...,  '9' se pondrán todos en la misma clase de
              equivalencia).  Las clases de equivalencia normalmente ofrecen notables reducciones
              en  los  tamaños  de los ficheros finales de tabla/objeto (típicamente un factor de
              2-5)  y  son  juiciosamente  bastante  baratos  en  cuanto  al   rendimiento   (una
              localización en un vector por caracter analizado).

              -Cf  especifica  que se deben generar las tablas del analizador completas - flex no
              debería comprimir las  tablas  tomando  ventaja  de  las  funciones  de  transición
              similares para diferentes estados.

              -CF   especifica  que  debería  usarse  la  representación  del  analizador  rápido
              alternativo (descrito anteriormente en la bandera -F ) Esta opción 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  están
              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 localización en un
              array por caracter analizado).

              -Cr hace que el analizador generado elimine el uso de la librería de  E/S  estándar
              para la entrada.  En lugar de llamar a fread() o getc(), el analizador utilizará la
              llamada al sistema read(), produciendo una ganancia en el rendimiento que varía  de
              sistema  en  sistema,  pero  en general probablemente es insignificante a menos que
              también esté usando -Cf o -CF.  El uso de  -Cr  puede  producir  un  comportamiento
              extraño  si,  por  ejemplo,  lee de yyin usando stdio antes de llamar al analizador
              (porque el analizador perderá 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 Escáner Generado más arriba).

              Con  solamente  -C se especifica que las tablas del analizador deberían comprimirse
              pero no debería 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 está siendo comprimida.  De otra  forma
              las opciones podrían mezclarse líbremente, y son acumulativas.

              La  configuración  por  defecto  es  -Cem,  que especifica que flex debería generar
              clases de equivalencia y clases de meta-equivalencias.  Esta  configuración  provee
              el mayor grado de compresión.  Puede llegarse a un compromiso entre analizadores de
              ejecución más rápida con el coste de tablas mayores siendo  generalmente  verdadero
              lo siguiente:

                  lo más lento y pequeño
                        -Cem
                        -Cm
                        -Ce
                        -C
                        -C{f,F}e
                        -C{f,F}
                        -C{f,F}a
                  lo más rápido y grande

              Fíjese  que  los  analizadores  con  tablas  más  pequeñas normalmente se generan y
              compilan de la forma más rápida  posible,  así  que  durante  el  desarrollo  usted
              normalmente querrá usar como viene por defecto, compresión máxima.

              -Cfe  a menudo es un buen compromiso entre velocidad y tamaño para la producción 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 opción -t, entonces el analizador se escribe en stdout pero
              sus directivas #line (vea la opción -L más  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 también cambia el nombre por defecto del
              fichero de salida de lex.yy.c a lex.foo.c.  Aquí están 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 está utilizando un  analizador  en  C++,  entonces  únicamente  yywrap  y
              yyFlexLexer se ven afectados.)  Dentro de su analizador, puede aún hacer referencia
              a las variables globales y funciones usando cualquier versión de  su  nombre;  pero
              externamente, estas tienen el nombre modificado.

              Esta opción le deja enlazar fácilmente múltiples programas flex conjuntamente en el
              mismo ejecutable.  Fíjese, sin embargo, que usando esta opción también se  renombra
              yywrap(),  de  manera  que ahora debe o bien proveer su propia versión de la rutina
              (con el nombre apropiado) para su analizador,  o  usar  %option  noyywrap,  ya  que
              enlazar con -lfl no podrá proveerle una por defecto.

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

       flex  también  ofrece  un  mecanismo  para  controlar  las  opciones  dentro  de la propia
       especificación del analizador, en vez de a partir de la línea de comando.   Esto  se  hace
       incluyendo  las  directivas  %option  en  la  primera  sección  de  la  especificación del
       analizador.  Usted puede especificar varias opciones con una  sola  directiva  %option,  y
       varias directivas en la primera sección de su fichero de entrada de flex.

       La mayoría 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 negación son equivalentes a un número:

           7bit            opción -7
           8bit            opción -8
           align           opción -Ca
           backup          opción -b
           batch           opción -B
           c++             opción -+

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

           case-insensitive o
           caseless        opción -i

           debug           opción -d
           default         opuesto de la opción -s
           ecs             opción -Ce
           fast            opción -F
           full            opción -f
           interactive     opción -I
           lex-compat      opción -l
           meta-ecs        opción -Cm
           perf-report     opción -p
           read            opción -Cr
           stdout          opción -t
           verbose         opción -v
           warn            opuesto de la opción -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 están 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 debería leer un caracter a la vez.  Cuando  esta  opción
              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 opción implica noyywrap (ver más 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  más
              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 compilación.

       yylineno
              ordena a flex a generar un analizador que mantenga el número  de  la  línea  actual
              leída desde su entrada en la variable global yylineno.  Esta opción viene implícita
              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 más 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 están  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 desactivándolas 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"

       sólo se aplica cuando se genera un analizador en C++ (opción -+).  Este informa a flex que
       ha derivado a foo como una subclase de yyFlexLexer, así que flex pondrá sus acciones en la
       función  miembro  foo::yylex()  en lugar de yyFlexLexer::yylex().  Este también genera una
       función miembro yyFlexLexer::yylex() que emite un error en tiempo de ejecución  (invocando
       a  yyFlexLexer::LexerError())  si  es  llamada.  Ver Generando Escáners en C++, más abajo,
       para información adicional.

       Están disponibles un número de opciones para los puristas de lint que desean  suprimir  la
       aparición  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 aparecerán de todas manera a menos que use %option
       stack).

CONSIDERACIONES DE RENDIMIENTO

       El principal objetivo de diseño 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 compresión de tablas  -C
       anteriormente   introducidas,   hay   un  número  de  opciones/acciones  que  degradan  el
       rendimiento.  Estas son, desde la más 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 línea
           yymore()

       siendo las tres primeras bastante costosas y las dos últimas bastante económicas.   Fíjese
       también  que  unput()  se  implementa  como  una llamada de rutina que potencialmente hace
       bastante trabajo, mientras que yyless() es una macro bastante económica; así que  si  está
       devolviendo algún texto excedente que ha analizado, use yyless().

       REJECT  debería  evitarse a cualquier precio cuando el rendimiento es importante.  Esta es
       una opción particularmente cara.

       Es lioso deshacerse del retroceso y a menudo podría 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 -
            números de línea 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 -
            números de línea 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 -
            números de línea 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 líneas nos dicen que hay un estado del analizador en el que  se  puede  hacer
       una  transición  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 líneas 2 y 3 en el fichero de entrada.  Si
       el analizador está en ese estado y entoces lee cualquier cosa que no sea una  'o',  tendrá
       que  retroceder  para encontrar una regla que empareje.  Con un poco de análisis uno puede
       ver que este debe ser el estado en el que se está cuando se ha visto  "fo".   Cuando  haya
       ocurrido,  si se ve cualquier cosa que no sea una 'o', el analizador tendrá 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
       tendrá 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 haciéndolo con analizadores comprimidos.

       La manera de quitar los retrocesos es añadiendo 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  eliminación  de  retroceso  en  una  lista  de  palabras  clave  también puede hacerse
       utilizando una regla "atrápalo-todo":

           %%
           foo         return TOK_KEYWORD;
           foobar      return TOK_KEYWORD;

           [a-z]+      return TOK_ID;

       Normalmente esta es la mejor solución cuando sea adecuada.

       Los mensajes sobre retrocesos tienden a aparecer en cascada.  Con un  conjunto  complicado
       de  reglas  no  es poco común obtener cientos de mensajes.  Si uno puede descifrarlos, sin
       embargo, a menudo sólo hay que tomar una docena de reglas o algo  así  para  eliminar  los
       retrocesos  (ya  que  es  fácil  cometer  una  equivocación y tener una regla de error que
       reconozca un token válido.  Una posible característica futura de flex será  añadir  reglas
       automáticamente para eliminar el retroceso).

       Es importante tener en cuenta que se obtienen los beneficios de eliminar el retroceso sólo
       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  pérdida  de  rendimiento  que  REJECT  (es  decir,
       substanciales).  Así que cuando sea posible una regla como esta:

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

       es mejor escribirla así:

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

       o así

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

       Fíjese  que aquí la acción especial '|' no ofrece ningún ahorro, y puede incluso hacer las
       cosas peor (ver Deficiencias / Errores más abajo).

       Otro área donde el usuario puede incrementar el rendimiento del analizador (y una  que  es
       más  fácil  de implementar) surge del hecho que cuanto más tarde se empareje un token, más
       rápido irá el analizador.  Esto es debido a que con tokens grandes el procesamiento de  la
       mayoría  de  los  caracteres  de  entrada  tiene lugar en el (corto) bucle de análisis más
       interno, y no tiene que ir tan a menudo a hacer el  trabajo  de  más  para  constituir  el
       entorno  del  analizador  (p.ej., yytext) para la acción.  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 podría acelerarse escribiéndolo 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 línea  nueva  requiera  el  procesamiento  de  otra  regla,  el
       reconocimiento  de  las líneas nuevas se "distribuye" sobre las otras reglas para mantener
       el texto reconocido tan largo como sea posible.  ¡Fíjese que el añadir reglas no ralentiza
       el analizador!  La velocidad del analizador es independiente del número de reglas o (dadas
       las consideraciones dadas al inicio de esta sección)  cuán  complicadas  sean  las  reglas
       respecto a operadores tales como '*' y '|'.

       Un  ejemplo  final  sobre  la aceleración de un analizador: suponga que quiere analizar un
       fichero que contiene identificadores y palabras clave, una por línea y sin ningún caracter
       extraño, y reconocer todas las palabras clave.  Una primera aproximación 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 atrápalo-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 exáctamente una palabra por línea, entonces podemos reducir
       el número total de emparejamientos por la mitad  mezclando  el  reconocimiento  de  líneas
       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 aquí, ya que hemos reintroducido retroceso en el analizador.
       En particular, aunque nosotros sepamos que ahí nunca habrán otros caracteres en  el  flujo
       de  entrada que no sean letras o líneas nuevas, flex no puede figurarse eso, y planeará la
       posible necesidad de retroceder cuando haya analizado un token como "auto"  y  el  próximo
       caracter  sea  algo  distinto  a  una  línea  nueva  o una letra.  Previamente este podría
       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,
       podríamos o bien duplicar todas las reglas pero sin línea nueva al final, o, ya que  nunca
       esperamos  encontrar tal entrada y por lo tanto ni cómo es clasificada, podemos introducir
       una regla atrápalo-todo más, esta que no incluye una línea 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 rápido 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 múltiples NUL's.  Es mejor escribir reglas que  emparejen  cortas  cantidades  de
       texto si se anticipa que el texto incluirá NUL's a menudo.

       Otra  nota final en relación con el rendimiento: tal y como se mencionó en la sección Cómo
       se Reconoce la Entrada, el reajuste dinámico 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,  debería  intentar  emparejar
       "grandes"  cantidades de texto pero no "inmensas" cantidades, donde el punto medio está en
       torno a los 8K caracteres/token.

GENERANDO ESCÁNERES 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 debería encontrarse ante ningún error  de  compilación
       (por  favor  informe de cualquier error que encuentre a la dirección de correo electrónico
       dada en la sección Autores más abajo).  Puede entonces usar código C++ en sus acciones  de
       las  reglas  en  lugar  de  código C.  Fíjese que la fuente de entrada por defecto para su
       analizador permanece como yyin, y la repetición por defecto se hace aún  a  yyout.   Ambos
       permanecen como variables FILE * y no como flujos de C++.

       También  puede  utilizar flex para generar un analizador como una clase de C++, utilizando
       la opción -+ (o, equivalentemente, %option c++), que se especifica automáticamente  si  el
       nombre  del  ejecutable  de flex finaliza con un '+', tal como flex++.  Cuando se usa esta
       opción, flex establece por defecto la generación 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 más recientemente, el equivalente a yytext.

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

       int lineno() const
              retorna el número de línea de entrada actual (ver %option yylineno), o 1 si  no  se
              usó %option yylineno.

       void set_debug( int flag )
              activa  la bandera de depuración para el analizador, equivalente a la asignación de
              yy_flex_debug (ver la sección Opciones más arriba).  Fíjese que debe  construir  el
              analizador utilizando %option debug para incluir información de depuración en este.

       int debug() const
              retorna el estado actual de la bandera de depuración.

       También    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 acción 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  estará utilizando esa
              subclase  en  lugar  de  yyFlexLexer.   Es   este   caso,   en   vez   de   generar
              yyFlexLexer::yylex(),  flex  genera  S::yylex()  (y  también  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().

       Además, 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 número de caracteres leídos.
              Para  indicar  el  fin-de-la-entrada,  devuelve  0  caracteres.   Fíjese  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 está 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  también 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 versión  por  defecto  de  esta  función
              escribe el mensaje al flujo cerr y finaliza.

       Fíjese  que  un  objeto  yyFlexLexer  contiene  su estado de análisis completo.  Así 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 opción -P comentada anteriormente.

       Finalmente, note que la característica %array no está disponible en clases de analizadores
       en C++; debe utilizar %pointer (por defecto).

       Aquí 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 << "número " << 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 opción
       prefix= ) para renombrar cada  yyFlexLexer  a  algún  otro  xxFlexLexer.   Entonces  puede
       incluir  <FlexLexer.h> en los otros ficheros fuente una vez por clase analizadora, primero
       renombrando yyFlexLexer como se presenta a continuación:

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

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

       si, por ejemplo, usted utilizó %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 podría 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    ningún   código),   con   algunas   extensiones   e
       incompatibilidades,  de  las  que  ambas  conciernen  a  aquellos  que   desean   escribir
       analizadores  aceptables  por  cualquier  implementación.   Flex  sigue  completamente  la
       especificación 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 especificación
       POSIX.

       En esta sección comentaremos todas las áreas conocidas de incompatibilidades  entre  flex,
       lex de AT&T, y la especificación POSIX.

       La opción -l de flex activa la máxima compatibilidad con la implementación original de lex
       de AT&T, con el coste de una mayor pérdida  de  rendimiento  en  el  analizador  generado.
       Indicamos más abajo qué incompatibilidades pueden superarse usando la opción -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 debería gestionarse  por  buffer,  en  lugar  de  por  analizador  (simple
              variable global).

              yylineno no es parte de la especificación POSIX.

       -      La  rutina  input()  no  es  redefinible,  aunque  podría  invocarse  para leer los
              caracteres que siguen a continuación 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 restricción de flex de que input() no puede  redefinirse  va  de  acuerdo  a  la
              especificación  POSIX, que simplemente no especifica ninguna manera de controlar la
              entrada del analizador que no sea haciendo una asignación inicial a yyin.

       -      La rutina unput() no es redefinible.  Esta restricción 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 interrupción con
              long-jumps fuera del analizador, y el analizador a continuación se invoca de nuevo,
              podría 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 eliminará cualquier entrada en el buffer; normalmente esto no
              es un problema con un analizador interactivo.

              Dese cuenta también de que las clases analizadoras en C++ son reentrantes, así  que
              si  usar C++ es una opción para usted, debería utilizarla.  Vea "Generando Escáners
              en C++" más 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 especificación POSIX.

       -      lex  no  acepta  condiciones  de  arranque  exclusivas  (%x),  aunque  están  en la
              especificación POSIX.

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

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

              no  reconocerá  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 expandirá a "foo([A-Z][A-Z0-9]*)?" y así la
              cadena "foo" se reconocerá.

              Fíjese que si la definición comienza con ^ o finaliza con $ entonces no se  expande
              con  paréntesis,  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 definición de flex.

              El  uso  de -l produce en el comportamiendo de lex el no poner paréntesis alrededor
              de la definición.

              La especificación de  POSIX  dice  que  la  definición  debe  ser  encerrada  entre
              paréntesis.

       -      Algunas implementaciones de lex permiten que la acción de una regla comience en una
              línea separada, si el patrón de la regla tiene espacios en blanco al final:

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

              flex no dispone de esta propiedad.

       -      La opción %r de lex (generar un analizador Ratfor) no se ofrece.  No es parte de la
              especificación de POSIX.

       -      Después  de una llamada a unput(), el contenido de yytext está indefinido hasta que
              se reconozca el próximo token, a menos que el analizador se haya construido  usando
              %array.   Este  no  es  el  caso de lex o la especificación de POSIX.  La opción -l
              elimina esta incompatibilidad.

       -      La precedencia del operador {}  (rango  numérico)  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 último va de acuerdo con la especificación de POSIX.

       -      La precedencia del  operador  ^  es  diferente.   lex  interpreta  "^foo|bar"  como
              "empareja  bien  'foo'  al  principio  de  una  línea, o 'bar' en cualquier lugar",
              mientras que flex lo interpreta como "empareja 'foo' o 'bar' si vienen al principio
              de una línea".  Lo último va de acuerdo con la especificación de POSIX.

       -      Las  declaraciones especiales del tamaño 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  podrían
              escribirse  para  ser  procesados  con  flex  o  con lex.  Los analizadores también
              incluyen YY_FLEX_MAJOR_VERSION y YY_FLEX_MINOR_VERSION  indicando  qué  versión  de
              flex  generó  el  analizador  (por ejemplo, para la versión 2.5, estas definiciones
              serán 2 y 5 respectivamente).

       Las siguientes propiedades de flex no se incluyen en lex o la especificación POSIX:

           analizadores en C++
           %option
           ámbitos 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 línea

       más casi todas las banderas de flex.  La última propiedad en la lista se refiere al  hecho
       de  que con flex puede poner varias acciones en la misma línea, 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 acción.  Las acciones que no  se  encierran  en  llaves  simplemente  se
       terminan al final de la línea.

DIAGNÓSTICOS

       aviso,  la  regla no se puede aplicar indica que la regla dada no puede emparejarse porque
       sigue a otras reglas que siempre emparejarán el mismo texto que el de esta.  Por  ejemplo,
       en  el  siguiente  ejemplo  "foo"  no  puede emparejarse porque viene después de una regla
       "atrápalo-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ón  -s  pero  se  puede  aplicar  la  regla  por  defecto
       significa  que  es posible (tal vez únicamente en una condición de arranque en particular)
       que la regla por defecto (emparejar cualquier caracter simple) sea la única que emparejará
       una  entrada  particular.   Ya  que  se  indicó  -s,  presumiblemente esto no es lo que se
       pretendía.

       definición  no  definida   {reject_used_but_not_detected}   o   definición   no   definida
       {yymore_used_but_not_detected}  -  Estos  errores pueden suceder en tiempo de compilación.
       Indican que el analizador usa REJECT o yymore() pero que flex falló en  darse  cuenta  del
       hecho, queriendo decir que flex analizó las dos primeras secciones buscando apariciones de
       estas acciones y falló en encontrar alguna, pero que de algún 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 también debido a
       problemas internos.

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

       el analizador requiere la opción -8 para poder usar el carácter 'x' - La especificación de
       su analizador incluye el reconocimiento del caracter de 8-bits 'x' y no ha especificado la
       bandera  -8,  y su analizador por defecto está a 7-bits porque ha usado las opciones -Cf o
       -CF de compresión de tablas.  Vea el comentario de la bandera -7 para los detalles.

       flex scanner push-back overflow - usted utilizó 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 debería ajustar  dinámicamente  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 necesitó 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 después de que un long-jump haya saltado fuera (o sobre)  el
       registro de activación del analizador.  Antes de reintroducir el analizador, use:

           yyrestart( yyin );

       o, como se comentó más arriba, cambie y use el analizador como clase de C++.

       too many start conditions in <> construct! - ha listado más condiciones de arranque en una
       construcción <> que las que existen (así que tuvo que haber listado al menos una de  ellas
       dos veces).

FICHEROS

       -lfl   librería 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 únicamente cuando  se  construye
              flex, no cuando flex se ejecuta.

       lex.backup
              información  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. (Fíjese que el borrador
       de POSIX establece que el texto reconocido por tales patrones no está definido.)

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

       La  combinación  de  contexto  posterior  con la acción especial '|' puede producir que el
       contexto posterior fijo se convierta en contexto posterior variable que es más caro.   Por
       ejemplo, en lo que viene a continuación:

           %%
           abc      |
           xyz/def

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

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

       El  ajuste  dinámico del buffer de entrada es lento, ya que conlleva el reanálisis de todo
       el texto reconocido hasta entonces por el (generalmente enorme) token actual.

       Debido al uso simultáneo 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  número  de
       entradas  en  la tabla necesarias para determinar qué regla ha sido emparejada.  El número
       de entradas es igual al número de estados del DFA si el analizador no usa REJECT,  y  algo
       mayor que el número de estados si se usa.

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

       El algoritmo interno de flex necesita documentación.

VER TAMBIÉN

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

       John Levine, Tony Mason, and Doug Brown, Lex & Yacc, O'Reilly and Associates.  Esté seguro
       de obtener la 2ª edición.

       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)  (Edición  en  castellano:  Compiladores:  Principios,  Técnicas  y
       Herramientas, Addison-Wesley  Iberoamericana,  S.A.  (1990))   Describe  las  técnicas  de
       concordancia de patrones usadas por flex (autómata finito determinista).

AUTOR

       Vern Paxson, con la ayuda de muchas ideas e inspiración de Van Jacobson.  Versión original
       por Jef Poskanzer.  La representación de tablas rápidas es una implementación  parcial  de
       un  diseño  hecho  por  Van  Jacobson.   La implementación 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 caído 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 distribución.

       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 múltiples 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 allí  por
       el apoyo que recibí.

       Enviar comentarios a vern@ee.lbl.gov.

       Sobre esta traducción enviar comentarios a Adrián Pérez Jorge (alu1415@csi.ull.es).