按照该教程https://aquamentus.com/flex_bison.html学习flex和bison时,遇到了如下问题
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/libfl.so: undefined reference to `yylex'
collect2: error: ld returned 1 exit status
flex文件:
%{
#include <cstdio>
#include "snazzle.tab.h" // to get the token types from Bison
//extern int yylex();
%}
%%
[ \t\n] ;
[0-9]+\.[0-9]+ { yylval.fval = atof(yytext); return FLOAT; }
[0-9]+ { yylval.ival = atoi(yytext); return INT; }
[a-zA-Z0-9]+ {
// We have to strdup yytext because Flex will change it for the next token.
// Note that this memory must be freed somewhere, so that's why we call
// free() above in the Bison section. (Aside: we use free() instead of
// delete because strdup is a C function that uses malloc, not a C++
// function that uses new.)
yylval.sval = strdup(yytext);
return STRING;
}
%%
bison文件:
%{
#include <cstdio>
#include <iostream>
using namespace std;
// Declare stuff from Flex that Bison needs to know about:
extern int yylex();
extern int yyparse();
extern FILE *yyin;
void yyerror(const char *s);
%}
// Bison fundamentally works by asking flex to get the next token, which it
// returns as an object of type "yystype". Initially (by default), yystype
// is merely a typedef of "int", but for non-trivial projects, tokens could
// be of any arbitrary data type. So, to deal with that, the idea is to
// override yystype's default typedef to be a C union instead. Unions can
// hold all of the types of tokens that Flex could return, and this this means
// we can return ints or floats or strings cleanly. Bison implements this
// mechanism with the %union directive:
%union {
int ival;
float fval;
char *sval;
}
// Define the "terminal symbol" token types I'm going to use (in CAPS
// by convention), and associate each with a field of the %union:
%token <ival> INT
%token <fval> FLOAT
%token <sval> STRING
%%
// This is the actual grammar that bison will parse, but for right now it's just
// something silly to echo to the screen what bison gets from flex. We'll
// make a real one shortly:
snazzle:
INT snazzle {
cout << "bison found an int: " << $1 << endl;
}
| FLOAT snazzle {
cout << "bison found a float: " << $1 << endl;
}
| STRING snazzle {
cout << "bison found a string: " << $1 << endl; free($1);
}
| INT {
cout << "bison found an int: " << $1 << endl;
}
| FLOAT {
cout << "bison found a float: " << $1 << endl;
}
| STRING {
cout << "bison found a string: " << $1 << endl; free($1);
}
;
%%
int main(int, char**) {
// Open a file handle to a particular file:
FILE *myfile = fopen("a.snazzle.file", "r");
// Make sure it is valid:
if (!myfile) {
cout << "I can't open a.snazzle.file!" << endl;
return -1;
}
// Set Flex to read from it instead of defaulting to STDIN:
yyin = myfile;
// Parse through the input:
yyparse();
}
void yyerror(const char *s) {
cout << "EEK, parse error! Message: " << s << endl;
// might as well halt now:
exit(-1);
}
运行指令:
解决方法
在flex文件中添加%option noyywrap,加入该语句之后,g++指令就不需要添加-lfl参数
(-lfl 是为了将flex库文件链接!)
修改后的flex文件如下:
%{
#include <cstdio>
#include "snazzle.tab.h" // to get the token types from Bison
//extern int yylex();
%}
%option noyywrap
%%
[ \t\n] ;
[0-9]+\.[0-9]+ { yylval.fval = atof(yytext); return FLOAT; }
[0-9]+ { yylval.ival = atoi(yytext); return INT; }
[a-zA-Z0-9]+ {
// We have to strdup yytext because Flex will change it for the next token.
// Note that this memory must be freed somewhere, so that's why we call
// free() above in the Bison section. (Aside: we use free() instead of
// delete because strdup is a C function that uses malloc, not a C++
// function that uses new.)
yylval.sval = strdup(yytext);
return STRING;
}
%%
修改后的运行指令如下: