Undefined reference to yyparse (flex & bison)

2020-05-28 10:28发布

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 :)

2条回答
女痞
2楼-- · 2020-05-28 10:45

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 that make is implementing.

查看更多
别忘想泡老子
3楼-- · 2020-05-28 10:59

Solved it, the command

cc -o $@ fb3-1.tab.c fb3-1.lex.c fb3-1funcs.c

Should be

cc -o fb3 fb3-1.tab.c fb3-1.lex.c fb3-1funcs.c

Not sure why the book didn't specify that for the example.

查看更多
登录 后发表回答