y.tab.c: 未定义对 yylex 的引用

y.tab.c: undefined reference to yylex

我正在尝试 运行 我在网上找到的计算器示例。但是每次我 运行 我的 gcc 命令都会显示这个错误。这是我 运行:

的命令
flex -l calc3.l
yacc -vd calc3.y
gcc y.tab.c -lm -ll

-> 此时我收到此错误消息:

/tmp/ccPOq58f.o : In function 'yyparse':
y.tab.c: undefined reference to 'yylex' 
collect2: error: ld returned 1 exit status

这是我的代码:

calc3.l

%{
#include <stdlib.h>
#include "calc3.h"
#include "y.tab.h"
void yyerror(char *);
%}

%%

[a-z]       { 
                yylval.sIndex = *yytext - 'a';
                return VARIABLE;
            }

0           {
                yylval.iValue = atoi(yytext);
                return INTEGER;
            }

[1-9][0-9]* {
                yylval.iValue = atoi(yytext);
                return INTEGER;
            }

[-()<>=+*/;{}.] {
                return *yytext;
             }

">="            return GE;
"<="            return LE;
"=="            return EQ;
"!="            return NE;
"while"         return WHILE;
"if"            return IF;
"else"          return ELSE;
"print"         return PRINT;

[ \t\n]+        ;       /* ignore whitespace */

.               yyerror("Unknown character");
%%
int yywrap(void) {
    return 1;
}

这里是calc3.h

typedef enum { typeCon, typeId, typeOpr } nodeEnum;

/* constants */
typedef struct {
    int value;                  /* value of constant */
} conNodeType;

/* identifiers */
typedef struct {
    int i;                      /* subscript to sym array */
} idNodeType;

/* operators */
typedef struct {
    int oper;                   /* operator */
    int nops;                   /* number of operands */
    struct nodeTypeTag **op;    /* operands */
} oprNodeType;

typedef struct nodeTypeTag {
    nodeEnum type;              /* type of node */

    union {
        conNodeType con;        /* constants */
        idNodeType id;          /* identifiers */
        oprNodeType opr;        /* operators */
    };
} nodeType;

extern int sym[26];

这里是calc3.y

%{
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "calc3.h"

/* prototypes */
nodeType *opr(int oper, int nops, ...);
nodeType *id(int i);
nodeType *con(int value);
void freeNode(nodeType *p);
int ex(nodeType *p);
int yylex(void);

void yyerror(char *s);
int sym[26];                    /* symbol table */
%}

%union {
    int iValue;                 /* integer value */
    char sIndex;                /* symbol table index */
    nodeType *nPtr;             /* node pointer */
};

%token <iValue> INTEGER
%token <sIndex> VARIABLE
%token WHILE IF PRINT
%nonassoc IFX
%nonassoc ELSE

%left GE LE EQ NE '>' '<'
%left '+' '-'
%left '*' '/'
%nonassoc UMINUS

%type <nPtr> stmt expr stmt_list

%%

program:
        function                { exit(0); }
        ;

function:
          function stmt         { ex(); freeNode(); }
        | /* NULL */
        ;

stmt:
          ';'                            { $$ = opr(';', 2, NULL, NULL); }
        | expr ';'                       { $$ = ; }
        | PRINT expr ';'                 { $$ = opr(PRINT, 1, ); }
        | VARIABLE '=' expr ';'          { $$ = opr('=', 2, id(), ); }
        | WHILE '(' expr ')' stmt        { $$ = opr(WHILE, 2, , ); }
        | IF '(' expr ')' stmt %prec IFX { $$ = opr(IF, 2, , ); }
        | IF '(' expr ')' stmt ELSE stmt { $$ = opr(IF, 3, , , ); }
        | '{' stmt_list '}'              { $$ = ; }
        ;

stmt_list:
          stmt                  { $$ = ; }
        | stmt_list stmt        { $$ = opr(';', 2, , ); }
        ;

expr:
          INTEGER               { $$ = con(); }
        | VARIABLE              { $$ = id(); }
        | '-' expr %prec UMINUS { $$ = opr(UMINUS, 1, ); }
        | expr '+' expr         { $$ = opr('+', 2, , ); }
        | expr '-' expr         { $$ = opr('-', 2, , ); }
        | expr '*' expr         { $$ = opr('*', 2, , ); }
        | expr '/' expr         { $$ = opr('/', 2, , ); }
        | expr '<' expr         { $$ = opr('<', 2, , ); }
        | expr '>' expr         { $$ = opr('>', 2, , ); }
        | expr GE expr          { $$ = opr(GE, 2, , ); }
        | expr LE expr          { $$ = opr(LE, 2, , ); }
        | expr NE expr          { $$ = opr(NE, 2, , ); }
        | expr EQ expr          { $$ = opr(EQ, 2, , ); }
        | '(' expr ')'          { $$ = ; }
        ;

%%

nodeType *con(int value) {
    nodeType *p;

    /* allocate node */
    if ((p = malloc(sizeof(nodeType))) == NULL)
        yyerror("out of memory");

    /* copy information */
    p->type = typeCon;
    p->con.value = value;

    return p;
}

nodeType *id(int i) {
    nodeType *p;

    /* allocate node */
    if ((p = malloc(sizeof(nodeType))) == NULL)
        yyerror("out of memory");

    /* copy information */
    p->type = typeId;
    p->id.i = i;

    return p;
}

nodeType *opr(int oper, int nops, ...) {
    va_list ap;
    nodeType *p;
    int i;

    /* allocate node */
    if ((p = malloc(sizeof(nodeType))) == NULL)
        yyerror("out of memory");
    if ((p->opr.op = malloc(nops * sizeof(nodeType *))) == NULL)
        yyerror("out of memory");

    /* copy information */
    p->type = typeOpr;
    p->opr.oper = oper;
    p->opr.nops = nops;
    va_start(ap, nops);
    for (i = 0; i < nops; i++)
        p->opr.op[i] = va_arg(ap, nodeType*);
    va_end(ap);
    return p;
}

void freeNode(nodeType *p) {
    int i;

    if (!p) return;
    if (p->type == typeOpr) {
        for (i = 0; i < p->opr.nops; i++)
            freeNode(p->opr.op[i]);
        free (p->opr.op);
    }
    free (p);
}

void yyerror(char *s) {
    fprintf(stdout, "%s\n", s);
}

int main(void) {
    yyparse();
    return 0;
}

如果你只是使用

flex calc3.l

然后 flex 生成一个名为 lex.yy.c 的扫描仪。 (我删除了原始问题中使用的 -l 选项。-l 使 flex 与原始 lex 实用程序的某些方面更加兼容,并且除了编译古老的 lex 扫描器之外没有任何用处。 )

同样,如果你只是使用

yacc -vd calc3.y

野牛将生成名为 y.tab.cy.tab.h 的文件。并且

gcc y.tab.c -lm -ll

将生成一个名为 a.out 的文件。

None 那是个好主意。最好根据输入的文件名给文件起有意义的名字。所有这三个工具都理解 -o 指定输出名称文件的命令行标志。

所以你可以这样做:

flex calc3.l
yacc -vd calc3.y
gcc lex.yy.c y.tab.c -lm -ll

但我会推荐这样的东西:

flex -o calc3.lex.c calc3.l
bison -o calc3.tab.c -vd calc3.y
gcc -o calc3 calc3.lex.c calc3.tab.c -lm -ll

执行此操作时,您需要将 #include "y.tab.h" 更改为 #include "calc3.tab.h"。 (请注意,如果您将 bison 调用为 bison 而不是 yacc,它会自动生成名称基于语法文件的输出文件。但是明确无误。)

如果你把它放在一个 Makefile 中,或者至少是一个脚本文件中,那就更好了。