I was trying to build a mini-compiler for a course on compilers and I was going through code on GitHub at https://github.com/rabishah/Mini-C-Compiler-using-Flex-And-Yacc and https://github.com/vikash002/C---mini-Compiler and many other such mini-compilers.
When I clone them and run them using the code
$ lex c.l
$ yacc c.y
$ gcc y.tab.c -ll -ly
I get this error telling
In file included from c.y:140:
c.l: In function ‘yylex’:
c.l:6:3: error: ‘yylineno’ undeclared (first use in this function); did you mean ‘yyleng’?
6 | [ \n] { yylineno = yylineno + 1;}
| ^~~~~~~~
| yyleng
c.l:6:3: note: each undeclared identifier is reported only once for each function it appears in
c.y: At top level:
c.y:157:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
157 | yyerror(char *s) {
| ^~~~~~~
c.y:157:1: warning: conflicting types for ‘yyerror’
c.y:8:6: note: previous declaration of ‘yyerror’ was here
8 | void yyerror(const char *s);
| ^~~~~~~
c.y: In function ‘yyerror’:
c.y:158:25: error: ‘yylineno’ undeclared (first use in this function); did you mean ‘yyleng’?
158 | printf("%d : %s %s\n", yylineno, s, yytext );
| ^~~~~~~~
| yyleng
I'm still learning Fex and Yacc and when I looked online I saw that yylineno is a default variable in them. I even tried initializing it to one but I get the same error.
Any idea where I'm going wrong? Or is this some error related to the newer versions of Flex and Yacc?
Any help would be greatly appreciated.
Yes, it's related to the version of flex you are running.
Unlike lex and very old versions of flex, any flex you're likely to come across doesn't define (or initialise) yylineno
unless you run it in lex-compatibility mode (not really recommended) or request that flex tracks line numbers (highly recommended but not done by the source code you're using).
So you have the following options, roughly in order by my prejudices: Only do one of these! They are not compatible with each other.
Add %option yylineno
to the beginning of the c.l
file. Then change line 5 to:
[ \t\n] ;
and delete line 6 (the rule with the pattern [ \n]
). This removes the action which increments yylineno
, which is necessary because %option yylineno
asks Flex to build a scanner which tracks line numbers by itself.
Add the following line to c.y after the #include
statements at the beginning of the file (that is, about line 4):
extern int yylineno = 1;
That will declare the global yylineno
variable and initialize it. In this option you are not asking Flex to generate a scanner which tracks line numbers. so you are going to have to do it yourself.
A slightly better option (but a bit more work) would be to change the name of yylineno
throughout your code to something else. Then you won't have to worry about accidentally enabling line number tracking. (But personally, I'd go with enabling line number tracking from the beginning, as in option 1.)
Run flex in lex-compatibility mode by adding the -l
command-line option when invoking lex
(which is really flex):
lex -l c.l
Opinion follows. You have been warned.
Having said all that, I'd really suggest that if you want to copy code, find some code written by someone who actually knows how to write parsers, instead of copying bad, unfinished and probably buggy code from random GitHub repositories. In general, copying other people's mistakes is a lousy way to learn how to program. Writing the code yourself is obviously more time-consuming in the short-term, but it's a lot more educational and you end up only have to deal with your own mistakes.