0

I am new in Flex/Bison. I want to use only strings for values (is a language translator). I have this for test:

example.l:

%option noyywrap nodefault

%{
#include <string.h>
#include "example.tab.h"
%}

%%

[ \t\n] {;}
"<="    {return LEFT;}
"=>"    {return RIGHT;}
[0-9]+ { yylval=strdup(yytext); return NUMBER; }
. { return yytext[0]; }

%%

example.y:

%{
#include <stdio.h>
#define YYSTYPE char const *
%}

%token NUMBER
%token LEFT "<=" RIGHT "=>"

%%

start: %empty | start tokens

tokens:
       NUMBER "<=" NUMBER { printf("%s <= %s\n",$1,$3); }
     | NUMBER "=>" NUMBER { printf("%s => %s\n",$1,$3); }
     | NUMBER '>' NUMBER  { printf("%s > %s\n",$1,$3); }
     | NUMBER '<' NUMBER  { printf("%s < %s\n",$1,$3); }

%%

main(int argc, char **argv) { yyparse(); }
yyerror(char *s) { fprintf(stderr, "error: %s\n", s); }

When I compiled:

bison -d example.y
flex example.l
cc -o example example.tab.c lex.yy.c -lfl
example.l: In function ‘yylex’:
example.l:13:9: warning: assignment makes integer from pointer without a cast
 [0-9]+ { yylval=strdup(yytext); return NUMBER; }
         ^

But work as awaited.

If I don't use #define YYSTYPE char const * and use instead the %union:

%union {
   char * txt;
}

%token <txt> NUMBER

And change the assignation to [0-9]+ { yylval.txt=strdup(yytext); return NUMBER; }, it has no warning and works.

I tried thing like define the same YYSTYPE in flex file and cast the assignation without success. What is wrong? How to fix without using %union?

Thanks.

RAM
  • 65
  • 4
  • 11
  • 1
    To avoid memory leaks you need use YYSTYPE as `char *` and doing free(): `NUMBER "<=" NUMBER { printf("%s <= %s\n",$1,$3); free($1); free($3);} | | NUMBER "=>" NUMBER { printf("%s => %s\n",$1,$3); free($1); free($3);}` and so on. You can check your program with and without free for memory leaks with valgrind http://valgrind.org/ – komar Mar 30 '17 at 20:23
  • Great! The final example includes your recommendation. – RAM Mar 30 '17 at 20:37

2 Answers2

1

You need move #define YYSTYPE char const * to example.l before #include "example.tab.h".

If you take a look inside example.tab.h you will find something like this:

#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef int YYSTYPE;
// ...
#endif

This i mean you need define YYSTYPE before this code, i.e. before #include "example.tab.h. Otherwise, if YYSTYPE not defined on this moment, YYSTYPE will be defined as int.

Another possibility is use bison feature %define api.value.type {char const *}, what you need to put in example.y. In that case example.tab.h will be generated with YYSTYPE of char const * type.

komar
  • 861
  • 5
  • 8
  • It works! I understood that inserting in `.y` was enough. Moreover, I tried but after the inclusion of example.tab.h. I see that Flex/Bison have some tricks no so clear in the manuals. Thanks! – RAM Mar 30 '17 at 20:13
  • BTW, your program have memory leaks. strdup() use malloc() to allocate memory for string, but you did't have in your program any free(). – komar Mar 30 '17 at 20:17
  • Yes I know. This is not my program, is only an example to explain the main problem. BTW: in the example, y must do free($1) and free($3) in each case to ensure avoid the memory leak? There are other useful options? – RAM Mar 30 '17 at 20:22
  • In you simple example I did't think you can find other useful options. For more advanced example you need %union, define type of `tokens` as some stucture what can hold all pointers to string(array of `char *` or list), and free it in the end of expession, in this example you did't have something to mark end of expession (for example `\n` or `;`). For you simple example better to use `char string[20]` as YYSTYPE and `strncpy()` instead of `strdup()`. There is more http://stackoverflow.com/questions/31104302/freeing-the-string-allocated-in-strdup-from-flex-bison – komar Mar 30 '17 at 21:02
  • Ok, I understand. I know about %union, but my compiler is only a translator between languages. I will think about to use a `char string[NUM]` instead. Thanks Komar. – RAM Mar 31 '17 at 13:17
0

The final working example is:

example.l:

%option noyywrap nodefault

%{
#include <string.h>
#define YYSTYPE char *
#include "example.tab.h"
%}

%%

[ \t\n] {;}
"<="    {return LEFT;}
"=>"    {return RIGHT;}
[0-9]+ { yylval=strdup(yytext); return NUMBER; }
. { return yytext[0]; }

%%

example.y:

%{
#include <stdio.h>
#define YYSTYPE char *
%}

%token NUMBER
%token LEFT "<=" RIGHT "=>"

%%

start: %empty | start tokens

tokens:
       NUMBER "<=" NUMBER { 
          printf("%s <= %s\n",$1,$3);
          free($1);
          free($3);
       }
     | NUMBER "=>" NUMBER {
          printf("%s => %s\n",$1,$3);
          free($1);
          free($3);
       }
     | NUMBER '>' NUMBER  {
          printf("%s > %s\n",$1,$3);
          free($1);
          free($3);
       }
     | NUMBER '<' NUMBER  {
          printf("%s < %s\n",$1,$3);
          free($1);
          free($3);
       }

%%

main(int argc, char **argv) { yyparse(); }
yyerror(char *s) { fprintf(stderr, "error: %s\n", s); }
RAM
  • 65
  • 4
  • 11
  • I probe the `%define api.value.type {char const *}` option and I think that is better, because is only in one place. So, I only use it in my `.y`, before `%token` declarations. – RAM Mar 31 '17 at 19:34