0
votes

I was able to sidestep this problem when manually setting up the order in which header files are read by the compiler. In this case, I'm able to spoof the default "pearl" with the correct definition, but when I have no control of the order in which headers are included, this... genius of engineering surfaces:

/* Default declaration of generated scanner - a define so the user can
 * easily add parameters.
 */
#ifndef YY_DECL
#define YY_DECL_IS_OURS 1
/* %if-c-only Standard (non-C++) definition */

extern int yylex \
               (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner);

#define YY_DECL int yylex \
               (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner)
/* %endif */
/* %if-c++-only C++ definition */
/* %endif */
#endif /* !YY_DECL */

This is defined in the header file, but my definition of YY_DECL is copied into *.c file.

The documentation says:

(If your environment supports function prototypes, then it will be "int yylex( void )".) This definition may be changed by defining the "YY_DECL" macro. For example, you could use:

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

to give the scanning routine the name lexscan, returning a float, and taking two floats as arguments. Note that if you give arguments to the scanning routine using a K&R-style/non-prototyped function declaration, you must terminate the definition with a semi-colon (`;').

Yes, right, just what I was missing! How would I live without being able to use non-standard C syntax that died in the seventies? Yet, the documentation blatantly lies about what happens if you declare YY_DECL: in reality it gets ignored, unless you manage to spoof a different header to the compiler before any of the code generated by Flex would have been compiled.

I'm at the point now where I'd just write a sed call to patch the output of Flex. Please tell me it is actually possible to fix it without this kind of "instrumentation".

1
There's probably no solution which will make you happy. I agree that YY_DECL is not the ideal way of configuring the yylex prototype, not least because once you have parameters to yylex (as you do with reentrant lexers and parsers) then you need to get their names right, and the correct names aren't documented. But it would be useful to know why you want to change the prototype. To add extra state, it's usually easier to use yyextra. If you just want to change the name, then #define yylex my_name is crude but effective.rici
I'll try yyextra - didn't know about this one. Will report back today. And yes, my goal is to add an extra parameter since the parser is reentrant, I need to pass the state.wvxvw
Are you using a push-parser, then? IMHO, that is the best solution for reentrant parsing (and for other reasons, too). I often use yyextra for that, although it is sometimes convenient to allocate the parse state at the top of yylex and delete it after sendimg the END token.rici
@rici yes, I'm using push parser.wvxvw
@rici yes, it worked with yyextra. If you want to, you can post this as an answer, I'll accept it.wvxvw

1 Answers

1
votes

If you want to change the prototype to add a parameter containing extra state, it's usually easier to use Flex's "extra data" feature, yyextra. That avoids the irritations of YY_DECL.

On the other hand, if you want to change the name of the generated lexer (because, for example, you want to export a wrapper called yylex), then a crude but effective technique is to put

#define yylex my_name

In the prologue and

#undef yylex

in the epilogue. (Obviously these shouldn't be placed in header files.)

I agree that the YY_DECL macro is far from an ideal way of configuring the yylex prototype. My complaint has always been that once you have parameters to yylex (as you do with reentrant lexers) then you need to get their names right, and the correct names aren't documented, and therefore are subject to change, making for a future incompatibility in waiting.