How does flex support bison-location exactly?

Kevin Yu picture Kevin Yu · Mar 18, 2009 · Viewed 18.2k times · Source

I'm trying to use flex and bison to create a filter, because I want get certain grammar elements from a complex language. My plan is to use flex + bison to recognise the grammar, and dump out the location of elements of interest. (Then use a script to grab text according the locations dumped.)

I found flex can support a bison feature called bison-locations, but how it works in exactly. I tried the example in flex document, it seems the yylloc is not set automatically by flex, I always get (1,0)-(1,0). Could flex calculate each token's location automatically? If not, what interface function is defined for me to implement? Is there any example?

Any better solution regarding to tools?

Best Regards, Kevin

Edit:

Now the interface for yylex turn to:

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

bison manual does not specify how lexer should implement to correctly set yylloc_param. For me it is hard to manually trace column number of each token.

Answer

Shlomi Loubaton picture Shlomi Loubaton · Apr 28, 2011

The yylex declaration probably changed because you used a reentrant or pure-parser. Seems like many documents around the web suggest it's required if you want bison locations to work but it's not required.

I needed line numbers too and found the Bison documentation confusing in that regard. The simple solution (using the global var yylloc): In your Bison file just add the %locations directive:

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

in your 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
...
%%
...

The YY_USER_ACTION macro is "called" before each of your token actions and updates yylloc. Now you can use the @N/@$ rules like this:

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

, or use the yylloc global var:

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