3
votes

Référence non définie à «yylval» et «yyerror»

J'essaye de compiler un exemple du livre flex and Bison . Je me demandais pourquoi j'avais l'erreur de construction suivante et comment puis-je la corriger?

/* recognize tokens for the calculator and print them out */

%{
# include "fb1-5.tab.h"
%}

%%
"+" { return ADD; }
"-" { return SUB; }
"*" { return MUL; }
"/" { return DIV; }
"|"     { return ABS; }
"("     { return OP; }
")"     { return CP; }
[0-9]+  { yylval = atoi(yytext); return NUMBER; }

\n      { return EOL; }
"//".*  
[ \t]   { /* ignore white space */ }
.   { yyerror("Mystery character %c\n", *yytext); }
%%

Makefile:

/* simplest version of calculator */

%{
#  include <stdio.h>
%}

/* declare tokens */
%token NUMBER
%token ADD SUB MUL DIV ABS
%token OP CP
%token EOL

%%

calclist: /* nothing */
 | calclist exp EOL { printf("= %d\n> ", $2); }
 | calclist EOL { printf("> "); } /* blank line or a comment */
 ;

exp: factor
 | exp ADD exp { $$ = $1 + $3; }
 | exp SUB factor { $$ = $1 - $3; }
 | exp ABS factor { $$ = $1 | $3; }
 ;

factor: term
 | factor MUL term { $$ = $1 * $3; }
 | factor DIV term { $$ = $1 / $3; }
 ;

term: NUMBER
 | ABS term { $$ = $2 >= 0? $2 : - $2; }
 | OP exp CP { $$ = $2; }
 ;
%%
main()
{
  printf("> "); 
  yyparse();
}

yyerror(char *s)
{
  fprintf(stderr, "error: %s\n", s);
}

fb1-5.y

fb1-5:  fb1-5.l fb1-5.y
    bison -d fb1-5.y
    flex fb1-5.l
    cc -o  fb1-5.tab.c lex.yy.c -lfl

fb1- 5.l:

$ make
bison -d fb1-5.y
fb1-5.y: warning: 3 shift/reduce conflicts [-Wconflicts-sr]
flex fb1-5.l
cc -o  fb1-5.tab.c lex.yy.c -lfl
fb1-5.l: In function ‘yylex’:
fb1-5.l:27:3: warning: implicit declaration of function ‘yyerror’; did you mean ‘perror’? [-Wimplicit-function-declaration]
 . { yyerror("Mystery character %c\n", *yytext); }
   ^~~~~~~
   perror
/tmp/cctl5WLj.o: In function `yylex':
lex.yy.c:(.text+0x32f): undefined reference to `yylval'
lex.yy.c:(.text+0x363): undefined reference to `yyerror'
collect2: error: ld returned 1 exit status
Makefile:2: recipe for target 'fb1-5' failed
make: *** [fb1-5] Error 1


1 commentaires

cc: error: fb1-5.tab.c: aucun fichier ou répertoire de ce type


3 Réponses :


2
votes

Je suppose que le problème est ici

cc -o   lex.yy.c  fb1-5.tab.c -lfl


4 commentaires

Merci. (1) pouvez-vous expliquer pourquoi l'erreur dans mon message? (2) exécutez votre commande, cc: error: fb1-5.tab.c: No such file or directory . (3) Le fichier de sortie de flex est-il toujours lex.yy.c ? Peut-il y avoir plus d'un fichier flex d'entrée dans le même répertoire, et donc en écrasant les uns les autres?


@tim: vous pouvez dire à flex quel nom de fichier utiliser avec l'option -o , tout comme cc . Dans les deux cas, vous devez suivre l'option avec le nom du fichier de sortie souhaité. (Quel est le problème avec votre appel cc .)


êtes-vous sûr que bison -d fb1-5.y produit réellement fb1-5.tab.c?


non si vous le compilez avec le même nom, il l'écrasera s'il se compile avec succès



2
votes

Il y a deux problèmes distincts ici.

  1. yyerror n'est pas déclaré dans votre scanner (ou, pour ce mattet dans votre analyseur). Bison ne génère pas de déclaration pour cela, vous devez donc le déclarer dans n'importe quelle unité de traduction qui l'utilise.

  2. cc -o fb1-5.tab.c lex.yy.c -lfl indique au compilateur C de compiler lex.yy.c en plaçant le l'exécutable résultant (la sortie du compilateur) dans fb1-5.tab.c . Ce n'est pas ce que vous vouliez. Il écrase l'analyseur généré par un exécutable et ne compile pas l'analyseur généré avec le résultat que les symboles définis dans l'analyseur ne sont pas disponibles pour l'éditeur de liens.


11 commentaires

Merci. (1) yyerror est défini dans fb1-5.y . (2) cc -o fb-1.5 fb1-5.tab.c lex.yy.c -lfl -ly ne fonctionne pas, car cc: erreur: fb1-5.tab .c: aucun fichier ou répertoire de ce type


@tim: le fait que yyerror soit défini dans l'analyseur ne rend pas sa déclaration disponible dans le lexer. Le compilateur se plaint que yyerror n'est pas déclaré, ce qui est différent de l'éditeur de liens se plaignant qu'il n'est pas défini.


Je ne sais pas pourquoi bison ne crée pas fb1-5.tab.c ; cela avait probablement à voir avec un peu de bizarrerie dans votre distribution. Ajoutez -o fb1-5.tab.c à votre commande bison.


J'ai utilisé le fichier make dans le livre, ce qui ne semble pas correct.


@tim: le makefile dans le livre dit -o $ @ . Vous avez omis le $ @ . (Mais $ @ est une syntaxe de création. Cela ne fonctionnera pas sur la ligne de commande.)


pourquoi le livre ne spécifie-t-il pas -ly ? N'est-ce pas nécessaire? Quelles sont exactement les bibliothèques à lier?


@tim: vraiment ni -ly ni -lfl ne sont nécessaires. Les deux bibliothèques définissent une implémentation par défaut de main () . (Celui de -ly appelle yyparse et celui de -lfl appelle yylex .) - lfl contient également une implémentation par défaut de yywrap ; ajoutez plutôt % option noyywrap à votre prologue flex.


Qu'est-ce que bison --version imprime? Et qu'en est-il de quel bison ?


Les deux bibliothèques sont-elles nécessaires au programme et à la liaison? Si oui, comment cc les trouve-t-il? bison (GNU Bison) 3.0.4 / usr / bin / bison


Quelle ligne ajouter au fichier flex? Je trouve que sans -lfl cc signale une erreur, alors que sans -ly cela fonctionne toujours, et je ne comprends toujours pas la raison.


@tim: veuillez relire mon commentaire précédent (commençant par "vraiment ni l'un ni l'autre")



3
votes

Vous devez changer votre makefile en:

fb1-5:  fb1-5.l fb1-5.y
    bison -b fb1-5 -d fb1-5.y
    flex fb1-5.l
    gcc -o fb1-5 fb1-5.tab.c lex.yy.c -lfl -ly

pour produire le fichier de sortie correct et avoir une implémentation standard de yyerror


3 commentaires

Merci. Quelles sont exactement les bibliothèques à lier?


@Tim liby définit une implémentation yyerror () (si aucune autre n'est définie), -lfl fournit une implémentation par défaut yywrap . Au moins sur mon système, d'autres systèmes peuvent gérer cela autrement. Habituellement, -ly et -ll (ou -lfl ) doivent être spécifiés pour être sûrs sur de nombreuses plates-formes.


Vous avez votre propre implémentation de yyerror () , donc vous n'auriez probablement pas besoin de -ly pour cela, mais cela ne fait pas de mal.