Flex, versión 2.5 - Generando escaneres en C
Tutorial creado por Vern Paxson. Extraido de: http://es.tldp.org/Manuales-LuCAS/FLEX/flex-es-2.5.html#SEC25
14 de Febrero de 2006
Herramientas de gestión de contenidos
17 - Generando escaneres 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 el section Autor∞). 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óx, 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'), ó 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 (see section Opciones∞). 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}
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.
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óx, 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'), ó 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 (see section Opciones∞). 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.
Valora este capítulo:
Autor y licencia de 'Flex, versión 2.5 - Generando escaneres en C'
|
Opiniona sobre 'Flex, versión 2.5 - Generando escaneres en C' (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 - Generando escaneres en C'
Este es el diario de Peter Class sobre sus dias aprendizaje de una disciplina de...
Más »
La productividad esta asociada con el grado de producción que una empresa pueda alcanzar para...
Más »
El desarrollo de los medios informáticos y de las nuevas tecnologías en la red ha...
Más »
Villaurrutia es uno de nuestros clásicos. La razón: su obra está fija en nuestra memoria...
Más »
A partir de tres tesis que se enmarcarían de la siguiente forma: a) la omnipresencia...
Más »
