如何修复函数 'yyerror' 的隐式声明问题

How to fix implicit declaration of function 'yyerror' problem

您好,我正在制作一个使用 Lex 和 yacc 进行简单算术运算的程序,但我遇到了一个特定错误的问题。

ex1.y

%{
#include <stdio.h>
int sym[26];
%}

%token INTEGER VARIABLE
%left '+' '-'
%left '*' '/' '%'

%%
program:
    program statement '\n'
    |
    ;

statement:
    expr            {printf("%d\n", );}
    | VARIABLE '=' expr {sym[] = ;}
    ;

expr:
    INTEGER
    | VARIABLE      { $$ = sym[];}
    | expr '+' expr { $$ =  + ;}
    | expr '-' expr { $$ =  - ;}
    | expr '*' expr     { $$ =  * ;}
    | expr '/' expr { $$ =  / ;}
    | '(' expr ')'      { $$ = ;}
    ;
%%

main() { return yyparse();}

int yyerror(char *s){
    fprintf(stderr,"%s\n",s);
    return 0;
}

ex1.l

%{
#include <stdlib.h>
#include "y.tab.h"
%}

%%

    /* variables */
[a-z]  {
        yylval = *yytext -'a';
        return VARIABLE;
    }
    
    /* integers */ 
[0-9]+ {
        yylval = atoi(yytext);
        return INTEGER;
    }

    /* operators */
[-+()=/*\n] { return *yytext;}

    /* skip whitespace */
[ \t]   ;

    /* anything else is an error */
.   yyerror("invalid character");

%%

int yywrap (void){
    return 1;
}

当我执行以下指令时

$bison –d -y ex1.y

$lex ex1.l

$gcc lex.yy.c y.tab.c –o ex1

出现以下错误:

ex1.l: In function ‘yylex’:
ex1.l:28:1: warning: implicit declaration of function ‘yyerror’; did you mean ‘perror’? [-Wimplicit-function-declaration]
   28 | 
      | ^      
      | perror
y.tab.c: In function ‘yyparse’:
y.tab.c:1227:16: warning: implicit declaration of function ‘yylex’ [-Wimplicit-function-declaration]
 1227 |       yychar = yylex ();
      |                ^~~~~
y.tab.c:1402:7: warning: implicit declaration of function ‘yyerror’; did you mean ‘yyerrok’? [-Wimplicit-function-declaration]
 1402 |       yyerror (YY_("syntax error"));
      |       ^~~~~~~
      |       yyerrok

我不知道我的代码有什么问题。如果您能告诉我如何解决上述错误,我将不胜感激。

您使用的 bison 版本要求您声明 yylex() 和 yyerror 的原型。这些应该紧跟在文件顶部的 #include <stdio.h> 之后:

    int yylex(void);
    int yyerror(char* s);

我会使用 int yyerror(const char* s) 作为 yyerror 的原型,因为它更准确,但如果您这样做,则必须对定义进行相同的更改。

您在 lex 文件中使用了 yyerror,因此您也必须在该文件中添加它的声明。

main() 本世纪任何时候都不是有效的原型。 Return 类型在函数声明中是必需的,包括 main()。所以我猜你的代码是基于一个非常旧的模板。 examples in the bison manual 中有更好的起点。 (如果您没有使用 C 的经验,不要指望使用解析器生成器会很容易。)