I'm attempting to learn some flex/bison, and I'm reading Flex & Bison by John Levine (O'Reilly). There is an example that I need to get running, however I can't get it to run as I get the following error:
/tmp/ccKZcRYB.o: In function `yylex':
fb3-1.lex.c:(.text+0x2bd): undefined reference to `yylval'
/tmp/cclBqnOk.o: In function `main':
fb3-1funcs.c:(.text+0x420): undefined reference to `yyparse'
collect2: ld returned 1 exit status
I've got four source files:
fb3-1.h:
/*
* Declarations for calculator fb3-1
*/
/* Interface to the lexer */
extern int yylineno; /* from lexer */
void yyerror(char *s, ...);
/* nodes in the abstract syntax tree */
struct ast {
int nodetype;
struct ast *l;
struct ast *r;
};
struct numval {
int nodetype; /* type K for constant */
double number;
};
/* build an AST */
struct ast *newast(int nodetype, struct ast *l, struct ast *r);
struct ast *newnum(double d);
/* evaluate an AST */
double eval(struct ast *);
/* delete and free an AST */
void treefree(struct ast *);
fb3-1.l
/* recognise tokens for the calculator */
%option noyywrap nodefault yylineno
%{
#include "fb3-1.h"
#include "fb3-1.tab.h"
%}
/* float exponent */
EXP ([Ee][-+]?[0-9]+)
%%
"+" |
"-" |
"*" |
"/" |
"|" |
"(" |
")" { return yytext[0]; }
[0-9]+"."[0-9]*{EXP}? |
"."?[0-9]+{EXP}? { yylval.d = atof(yytext); return NUMBER; }
\n { return EOL; }
"//".*
[ \t] { /* ignore whitespace */ }
. { yyerror("Mystery character %c\n", *yytext); }
%%
fb3-1.y
/* calculator with AST */
%{
#include <stdio.h>
#include <stdlib.h>
#include "fb3-1.h"
%}
%union {
struct ast *a;
double d;
}
/* declare tokens */
%token <d> NUMBER
%token EOL
%type <a> exp factor term
%%
calclist: /* nothing */
| calclist exp EOL {
printf("=%4.4g\n",eval($2));
treefree($2);
printf("> ");
}
| calclist EOL { printf("> "); } /* blank line or a comment */
;
exp: factor
| exp '+' factor { $$ = newast('+', $1, $3); }
| exp '-' factor { $$ = newast('-', $1, $3); }
;
factor: term
| factor '*' term { $$ = newast('*', $1, $3); }
| factor '/' term { $$ = newast('/', $1, $3); }
;
term: NUMBER { $$ = newnum($1); }
| '|' term { $$ = newast('|', $2, NULL); }
| '(' term { $$ = $2; }
| '-' term { $$ = newast('M', $2, NULL); }
;
%%
fb3-1funcs.c
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "fb3-1.h"
struct ast * newast(int nodetype, struct ast *l, struct ast *r)
{
struct ast *a = malloc(sizeof(struct ast));
if(!a) {
yyerror("out of space");
exit(0);
}
a->nodetype = nodetype;
a->l = l;
a->r = r;
return a;
}
struct ast * newnum(double d)
{
struct numval *a = malloc(sizeof(struct numval));
if(!a) {
yyerror("out of space");
exit(0);
}
a->nodetype = 'K';
a->number = d;
return (struct ast *)a;
}
double eval (struct ast *a)
{
double v;
switch(a->nodetype) {
case 'K': v = ((struct numval *)a)->number; break;
case '+': v = eval(a->l) + eval(a->r); break;
case '-': v = eval(a->l) + eval(a->r); break;
case '*': v = eval(a->l) + eval(a->r); break;
case '/': v = eval(a->l) + eval(a->r); break;
case '|': v = eval(a->l); if(v < 0) v = -v; break;
case 'M': v = -eval(a->l); break;
default: printf("internal error: bad node %c\n", a->nodetype);
}
}
void treefree(struct ast *a)
{
switch(a->nodetype)
{
/* two subtrees */
case '+':
case '-':
case '*':
case '/':
treefree(a->r);
/* one subtree */
case '|':
case 'M':
treefree(a->l);
/* no subtree */
case 'K':
free(a);
break;
default: printf("internal error: free bad node %c\n", a->nodetype);
}
}
void yyerror(char *s, ...)
{
va_list ap;
va_start(ap, s);
fprintf(stderr, "%d: error: ", yylineno);
vfprintf(stderr, s, ap);
fprintf(stderr, "\n");
}
int main ()
{
printf("> ");
return yyparse();
}
To Build:
bison -d fb3-1.y
flex -ofb3-1.lex.c fb3-1.l
cc -o $@ fb3-1.tab.c fb3-1.lex.c fb3-1funcs.c
I'm running Ubuntu 10.04 x64, with the packages 'flex' and 'bison' installed. Anyone know why this error is happening, and how to fix it? Thanks in advance :)
I read that chapter as well and I believe the author is indicating that the code should be put in a "Makefile" to automate the build process for said files.
The $@ is a variable expansion used in bash shell scripts (among other places) and probably does the same thing in
make
or is exactly the same thing thatmake
is implementing.Solved it, the command
Should be
Not sure why the book didn't specify that for the example.