mexicano extinto europeo carne caracteristicas bufalo bonasus bisonte americano bison flex-lexer

extinto - ¿Cómo es que flex apoya exactamente la ubicación del bisonte?



bufalo y bisonte (8)

Creo que me las arreglé para hacerlo funcionar (el crédito es para el escritor del analizador léxico ltcalc manual de bison). Por defecto, bison crea yylloc que contiene.

{ first_line, first_column , last_line , last_column }

Solo necesitamos actualizar esos valores en nuestro analizador léxico. Ex:

[ /t] { ++yylloc.last_column; } [/n] { yyloc.last_column = 0; return EOL; } [a-zA-Z]+ { yylloc.last_column += strlen(yytext); return IDENTIFIER; }

Ahora en bison, para recuperar esos campos:

statement : IDENTIFIER ''='' expression { printf("%d - %d/n", @1.last_line, @1.last_column); }

Por defecto, estos campos se inicializan en uno, debemos inicializar los campos de columna a cero, de lo contrario, informarán la columna incorrecta.

Estoy tratando de usar flex y bison para crear un filtro, porque quiero obtener ciertos elementos gramaticales de un lenguaje complejo. Mi plan es utilizar flex + bison para reconocer la gramática y eliminar la ubicación de los elementos de interés. (Luego use un script para capturar el texto de acuerdo con las ubicaciones vaciadas).

Descubrí que flex puede admitir una función de bisonte llamada bison-locations, pero cómo funciona exactamente. Intenté el ejemplo en flex document, parece que el yylloc no está configurado automáticamente por flex, siempre obtengo (1,0)-(1,0) . ¿Podría la flexibilidad calcular la ubicación de cada token automáticamente? Si no, ¿qué función de interfaz está definida para que yo implemente? ¿Hay algún ejemplo?

¿Alguna mejor solución con respecto a las herramientas?

Saludos cordiales, Kevin

Editar:

Ahora la interfaz para yylex pasa a:

int yylex(YYSTYPE * yylval_param,YYLTYPE * yylloc_param );

El manual de bison no especifica cómo debe implementar Lexer para establecer correctamente yylloc_param. Para mí es difícil rastrear manualmente el número de columna de cada token.


Eche un vistazo a la sección 3.6 del manual de Bison , que parece abarcar las ubicaciones con cierto detalle. Combinado con lo que encontró en el manual de Flex, eso puede ser suficiente.


Entonces, tengo esto para "trabajar", pero con un par de pasos adicionales (es posible que los haya pasado por alto aquí ... disculpas en ese caso):

  1. En parser.y , tuve que decir:

    #define YYLEX_PARAM &yylval, &yylloc

    incluso con %locations y bison --locations , para que pasen los datos.

  2. En lexer.l tuve que usar -> lugar de . para yylloc

  3. También en lexer.l , reinicio la columna en la acción:

    [/n] { yycolumn = 1; }

Obviamente un poco más complejo, por /r , etc., pero al menos lo hice funcionar.


La declaración de yylex probablemente cambió porque usaste un reentrante o un analizador puro. Parece que muchos documentos en la web sugieren que es necesario si quieres que funcionen las ubicaciones de bisontes pero no es obligatorio.

También necesitaba números de línea y encontré la documentación de Bison confusa en ese sentido. La solución simple (usando la var yylloc global): En su archivo de Bison, simplemente agregue la directiva% ubicaciones:

%{ ... %} %locations ... %% ...

en tu lexer

%{ ... #include "yourprser.tab.h" /* This is where it gets the definition for yylloc from */ #define YY_USER_ACTION yylloc.first_line = yylloc.last_line = yylineno; %} %option yylineno ... %% ...

La macro YY_USER_ACTION se "llama" antes de cada una de sus acciones de token y actualiza yylloc. Ahora puedes usar las reglas @N / @ $ de esta manera:

statement : error '';'' { fprintf(stderr, "Line %d: Bad statement./n", @1.first_line); }

, o usa la var de yylloc global:

void yyerror(char *s) { fprintf(stderr, "ERROR line %d: %s/n", yylloc.first_line, s); }


La respuesta de Shomi es la solución más simple si solo te importa mantener el número de línea. Sin embargo, si también desea números de columna, entonces debe realizar un seguimiento de ellos.

Una forma de hacerlo es agregar reglas yycolumn = 1 todas partes donde aparece una nueva línea (como se sugiere en la respuesta de David Elson), pero si no desea realizar un seguimiento de todos los lugares donde podría aparecer una nueva línea (espacios en blanco, comentarios, etc.) .) una alternativa es inspeccionar el búfer de yytext al inicio de cada acción:

static void update_loc(){ static int curr_line = 1; static int curr_col = 1; yylloc.first_line = curr_line; yylloc.first_column = curr_col; {char * s; for(s = yytext; *s != ''/0''; s++){ if(*s == ''/n''){ curr_line++; curr_col = 1; }else{ curr_col++; } }} yylloc.last_line = curr_line; yylloc.last_column = curr_col-1; } #define YY_USER_ACTION update_loc();

Finalmente, una cosa a tener en cuenta es que una vez que comience a realizar un seguimiento de los números de las columnas a mano, también podría hacer un seguimiento de los números de las líneas en el mismo lugar y no molestarse en usar la opción yylineno de Flex.


Me gusta la respuesta de Shlomi.

Además, también estaba buscando la ubicación de la columna de actualización. Encontré http://oreilly.com/linux/excerpts/9780596155971/error-reporting-recovery.html que tenía más sentido después de leer la respuesta de Shlomi.

Desafortunadamente hay un error tipográfico en esa página para yylloc. Lo he simplificado un poco más abajo.

En su analizador agregue:

%locations

en tu lexer

%{ #include "parser.tab.h" int yycolumn = 1; #define YY_USER_ACTION yylloc.first_line = yylloc.last_line = yylineno; / yylloc.first_column = yycolumn; yylloc.last_column = yycolumn + yyleng - 1; / yycolumn += yyleng; / yylval.str = strdup(yytext); %} %option yylineno

Puede que haya algo en la ubicación de la columna que no haga un seguimiento estricto de las columnas, sino que siga aumentando. Eso es solo mi ignorancia y disculparme si confunde a alguien. Actualmente estoy usando la columna para mantener un recuento de caracteres de archivo, que en mi caso es más beneficioso que la ubicación de la columna.

Espero que ayude.


Ni bison ni flex actualiza yylloc automáticamente, pero en realidad no es difícil hacerlo usted mismo, si conoce el truco.

El truco para implementar el soporte de yylloc es que, aunque yyparse() declara yylloc , nunca lo cambia. Eso significa que si modifica yylloc en una llamada al lexer, encontrará los mismos valores en ella en la próxima llamada. Por lo tanto, yylloc contendrá la posición del último token. Como el final del último token es el mismo que el inicio del token actual, puede usar el valor antiguo de yylloc para ayudarlo a determinar el nuevo valor.

En otras palabras, yylex() no debe calcular yylloc ; debería actualizar yylloc .

Para actualizar yylloc , primero debemos copiar los valores de first_ a first_ , y luego actualizar los valores de last_ para reflejar la longitud del token que acaba de coincidir. (Este no es el strlen() del token; es la longitud de las líneas y columnas). Podemos hacer esto en la macro YY_USER_ACTION , que se llama justo antes de que se realice cualquier acción del lexer; eso asegura que si una regla coincide pero no devuelve un valor (por ejemplo, una regla que salta espacios en blanco o comentarios), la ubicación de ese no-token se omite, en lugar de incluirse al comienzo del token real, o perdido de una manera que hace que el seguimiento de la ubicación sea inexacto.

Aquí hay una versión para un analizador reentrante; podría modificarlo por un analizador no reentrante cambiando los operadores -> por . :

#define YY_USER_ACTION / yylloc->first_line = yylloc->last_line; / yylloc->first_column = yylloc->last_column; / for(int i = 0; yytext[i] != ''/0''; i++) { / if(yytext[i] == ''/n'') { / yylloc->last_line++; / yylloc->last_column = 0; / } / else { / yylloc->last_column++; / } / }

Si prefieres, puedes poner ese código en una función y hacer que la macro llame a la función, pero las dos técnicas son equivalentes.


Una adición a la respuesta de Shlomi:

Si está utilizando% define api.pure en bison para crear un analizador reentrante, también debe especificar% option bison-locations en flex. Esto se debe a que, en un analizador reentrante, yylloc no es una variable global y debe ser transferida al lexer.

Así, en el analizador:

%define api.pure %locations

en el lexer

#include "yourprser.tab.h" #define YY_USER_ACTION yylloc.first_line = yylloc.last_line = yylineno; %option bison-locations %option yylineno