Flex, versión 2.5 - Acciones
14 de Febrero de 2006
Herramientas de gestión de contenidos
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:
[ \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' (see section Cómo se empareja la entrada∞); 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:
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' ó `-CF' (see section Opciones∞ y section Consideraciones de rendimiento∞.) 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.
[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.
/* 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' (see section 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.
register int c;
for ( ; ; )
{
while ( (c = input()) != '*' &&
c != EOF )
; /* se come el texto del comentario */
if ( c '*' )
{
'*' )
;
if ( c '/' )
break; /* encontró el final */
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.)
"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' (see section Cómo se empareja la entrada∞); 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 (see section Condiciones de arranque∞).
- 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 el section 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' ó `-CF' (see section Opciones∞ y section Consideraciones de rendimiento∞.) 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":
[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. {
/* 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' (see section 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 (see section El escáner generado∞). Esta acción es un caso especial de la función más general `yy_flush_buffer()', descrita más abajo en el section 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.
Valora este capítulo:
Autor y licencia de 'Flex, versión 2.5 - Acciones'
|
Opiniona sobre 'Flex, versión 2.5 - Acciones' (2)
Tu nombre debe tener tres caracteres como mínimo.
Es necesario que te des de alta con una cuenta de correo válida.
Es necesario que te des de alta con una cuenta de correo válida.
El contenido del título de tu opinión debe tener tres caracteres como mínimo.
Es obligatorio que selecciones una valoración del recurso.
El contenido del comentario de tu opinión debe tener tres caracteres como mínimo.
Opina sobre este tutorial |
Wikis relacionados con 'Flex, versión 2.5 - Acciones'
El obtener una forma de participación dentro de una empresa por medio de acciones preferentes,...
Más »
Un elemento que usualmente se extraña en el lenguaje JavaScript es la posibilidad de realizar...
Más »
El el plan integral de marketing es un plan que incluye la publicidad de los...
Más »
El control estadístico de procesos, conocido habitualmente como SPC (Statistical Process Control) es un conjunto...
Más »
Los pasivos a largo plazo está representado por los adeudos cuyo vencimiento sea posterior a...
Más »
