Difficoltà a compilare lex / yacc con codice C ++

Nov 14 2020

Sto cercando di compilare lex.yy.c e y.tab.c con codice C ++, ecco lo stato Make -

(base) rajatkmitra@spider:~/modeler> make
flex ./src/lex.l
g++ -I ./    -c -Wall -Wreorder -Wno-write-strings -Wno-unused-variable -Wno-unused-function -Wno-sign-compare -g -lm   -c -o main.o ./src/main.cc
g++ -I ./    -c -Wall -Wreorder -Wno-write-strings -Wno-unused-variable -Wno-unused-function -Wno-sign-compare -g -lm   -c -o convertFloatToFixed.o ./src/convertFloatToFixed.cc
g++ -I ./    -c -Wall -Wreorder -Wno-write-strings -Wno-unused-variable -Wno-unused-function -Wno-sign-compare -g -lm   -c -o convertProductFloatToFixed.o ./src/convertProductFloatToFixed.cc
g++ -I ./    -c -Wall -Wreorder -Wno-write-strings -Wno-unused-variable -Wno-unused-function -Wno-sign-compare -g -lm   -c -o printer.o ./src/printer.cc
g++ -I ./    -c -Wall -Wreorder -Wno-write-strings -Wno-unused-variable -Wno-unused-function -Wno-sign-compare -g -lm   -c -o vectorToString.o ./src/vectorToString.cc
g++ -I ./    -c -Wall -Wreorder -Wno-write-strings -Wno-unused-variable -Wno-unused-function -Wno-sign-compare -g -lm   -c -o printFixedPointProduct.o ./src/printFixedPointProduct.cc
g++ -I ./    -c -Wall -Wreorder -Wno-write-strings -Wno-unused-variable -Wno-unused-function -Wno-sign-compare -g -lm   -c -o fixedPointFormatter.o ./src/fixedPointFormatter.cc
g++ -I ./    -c -Wall -Wreorder -Wno-write-strings -Wno-unused-variable -Wno-unused-function -Wno-sign-compare -g -lm   -c -o tokenize.o ./src/tokenize.cc
g++ -I ./    -c -Wall -Wreorder -Wno-write-strings -Wno-unused-variable -Wno-unused-function -Wno-sign-compare -g -lm   -c -o y.tab.o y.tab.c
bison -y -d  ./src/bison.y 
./src/bison.y: warning: 4 shift/reduce conflicts [-Wconflicts-sr]
g++ -I ./    -c -Wall -Wreorder -Wno-write-strings -Wno-unused-variable -Wno-unused-function -Wno-sign-compare -g -lm   -c -o lex.yy.o lex.yy.c
###############################################################################
# Building main.o convertFloatToFixed.o convertProductFloatToFixed.o printer.o vectorToString.o 
printFixedPointProduct.o fixedPointFormatter.o tokenize.o y.tab.c lex.yy.c
###############################################################################
g++  -Wno-write-strings -I ./  main.o convertFloatToFixed.o convertProductFloatToFixed.o printer.o vectorToString.o printFixedPointProduct.o fixedPointFormatter.o tokenize.o y.tab.c lex.yy.c   -o lynx -lm
/usr/lib64/gcc/x86_64-suse-linux/7/../../../../x86_64-suse-linux/bin/ld: /tmp/cc8jVMLM.o: in function `yylex()':
lex.yy.c:(.text+0x343): undefined reference to `yyerror(char*)'
collect2: error: ld returned 1 exit status
make: *** [Makefile:71: lynx] Error 1

 ----Makefile----
####################################################################
# Library Paths 
####################################################################

####################################################################
#Sources, use vpath and $CC/$LEX/$YACC should have arguments $<
#debug %make --just-print should show simulate make procedure
####################################################################
INCLUDE=-I ./ 
LEXSRC=lex.l
YACCSRC=bison.y
SRC=main.cc convertFloatToFixed.cc convertProductFloatToFixed.cc \
printer.cc vectorToString.cc printFixedPointProduct.cc fixedPointFormatter.cc \
tokenize.cc y.tab.c lex.yy.c
vpath %cc  ./src
vpath %l   ./src
vpath %y   ./src
#####################################################################
#Compiler Settings 
#####################################################################
OBJCC=$(SRC:.cc=.o) OBJC=$(SRC:.c=.o)
EXE=lynx
DEFINE=#-D _XOPEN_SOURCE
CFLAGS=$(INCLUDE) $(DEFINE) $(LIBPATH) -c -Wall -Wreorder -Wno-write-strings \ -Wno-unused-variable -Wno-unused-function -Wno-sign-compare -g -lm CXXFLAGS=$(CFLAGS)
CC=g++
LEX=flex
YACC=bison -y -d

######################################################################
#Build Rules
######################################################################
new: all

all:$(SRC) $(EXE)

# These dependency rules indicate that (1) lex.yy.o depends on
# lex.yy.c and y.tab.h and (2) lex.yy.o and y.tab.o depend on calc.h.
# Make uses the dependencies to figure out what rules must be run when
# a file has changed.

lex.yy.o: lex.yy.c y.tab.h
lex.yy.o y.tab.o: 

## This rule will use yacc to generate the files y.tab.c and y.tab.h
## from our file $(YACCSRC).y y.tab.c y.tab.h: $(YACCSRC)
$(YACC) $< 

## this is the make rule to use lex to generate the file lex.yy.c from
## our file $(LEXSRC).lex lex.yy.c: $(LEXSRC)
$(LEX) $<

## for lex.yy.c and y.tab.c
%.c.o:
$(CC) $(CFLAGS) $< -o $@

## all other C++ files
%.cc.o:
$(CC) $(CFLAGS) $< -o $@

$(EXE):$(OBJCC) $(OBJC) @echo \############################################################################### @echo \# Building $(OBJCC) 
@echo \###############################################################################
$(CC) -Wno-write-strings $(INCLUDE) $(OBJCC) $(LIBPATH) $(LIB) -o $@ -lm

clean:
rm -rf $(EXE) *~ *.o lex.yy.c y.tab.h

Va bene, ecco il file della grammatica bison.y

%{

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>

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

/*|--------------------------
for global parsing
-----------------------------|*/
unsigned int attributeFlag;

%}
        
        
        

/*Possible types from lexer*/
%union {

int ival;
double fval;
const char *sval;
}

        
/*Possible tokens*/
%token          KWREAL
%token  <ival>      INTEGER
%token  <fval>      FLOAT;
%token  <sval>      VARIABLE

 /*associativity*/
%left           GE LE EQ NE '>' '<'
%left           '+' '-'
%left '*' '/'
%nonassoc       UMINUS
        
        
/*parse rules*/
%%
description:
        description decl_attributes    {}
    |   description stmt_list          {}
    |   description real_variable_decl {}
    |   decl_attributes                {}
    |   stmt_list                      {}
    |   real_variable_decl             {}
    ;


decl_attributes:
        attribute                         {}
    |   decl_attributes attribute         {}
        ;  

attribute:
        open_attribute several_attribute_assignments close_attribute 
real_variable_decl 
        { 
            attributeFlag = 0;
        }
        ;

open_attribute: 
        '(' '*' {attributeFlag = 1;}
    ;

close_attribute:
        '*' ')' {}
    ;


several_attribute_assignments:      
        integer_assignment                                 {}
    |   continued_attribute_assignments integer_assignment {}
        ;

continued_attribute_assignments:
        integer_assignment ','                                   {}
        |   continued_attribute_assignments integer_assignment   ',' {}
        ;

real_variable_decl:
        KWREAL VARIABLE ';'     
        {
        

        }
        ;

stmt_list:
        stmt                  { }
        |   stmt_list stmt        { }
        ;

stmt:
        VARIABLE  '=' expr ';'     {printf("%s\n\n",$1); }
        |   integer_assignment ';'     { }
        ;
 
integer_assignment:
        VARIABLE '=' INTEGER 
        {
            if(attributeFlag==1){
            if(strcmp($1, "S")==0){ //attrContainer.isSigned = $3;
                }else if(strcmp($1, "IB")==0){ //attrContainer.intBits = $3;
                }else if(strcmp($1, "FB")==0){ //attrContainer.fracBits = $3;
                }
            }
        }
    ;

expr:
        VARIABLE              { printf("%s\n",$1); } | FLOAT { printf("%f\n",$1); }
        | '-'   expr %prec UMINUS {  }
        |   expr '+' expr         {  }
        |   expr '-' expr         {  }
        |   expr '*' expr         {  }
        |   expr '/' expr         {  }
        |   expr '<' expr         {  }
        |   expr '>' expr         {  }
        |   expr GE expr          {  }
        |   expr LE expr          {  }
        |   expr NE expr          {  }
        |   expr EQ expr          {  }
        | '('   expr ')'          {  }
        ;


%%

    

  /*|-----------------------------------------------------
    Parsing Functions
    -----------------------------------------------------|*/

    
      /*Definition of yyerror*/
void yyerror(const char *s)
{
  extern int yylineno;  // defined and maintained in lex.c
  extern char *yytext;  // defined and maintained in lex.c
  printf("ERROR: %s on line %d\n", yytext, yylineno);

}

e il lexer -

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

void yyerror(char *);
%}

%%
"real"          return KWREAL;

[a-zA-Z][a-zA-Z]*   { 
                    //yylval.sval= *yytext - 'a';
                    yylval.sval = strdup(yytext);
                    return VARIABLE;
                    }

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

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

(([0-9]*\.[0-9]*)([eE][-+]?[0-9]+)?)   {
                  yylval.fval = atof(yytext); 
                  return FLOAT;
            }

[-()<>=+*/;,{}.] {
                return *yytext;
             }
">="            return GE;
"<="            return LE;
"=="            return EQ;
"!="            return NE;

#[^\n]*        { /* Discard preprocessor comments. */ }
"//"[^\n]*     { /* Discard c99 comments. */ }
[ \t\n]+        ;       /* ignore whitespace */

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

Questa è la routine principale main.cc

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

/*------------------------------------------------
  Front end parser
  ------------------------------------------------*/
extern void yyparse(void);
extern FILE *yyin;

int main(int argc, char **argv)
{
   
  /*------------------------
    parse the file
    ------------------------*/
  /*open file handle to a file of interest*/

  if(argc < 2){
    printf("Usage: main <filename> \n");
    exit(-1);
  }

  yyin = fopen(argv[1],"r");

  if(yyin==NULL){
    printf("Could not open file !\n");
    exit(-1);
  }

  /*Parse the design*/
  do{
    yyparse();
  }while(!feof(yyin));

}

Quindi eccoti! Ho aggiunto l'esempio riproducibile minimo. Quando compilo tutto con g ++ finisco per ricevere un errore del linker che non trova la routine yyerror () in yylex ()

g++  -Wno-write-strings -I ./  y.tab.o lex.yy.o main.o   -o lynx -lm -lfl - 

std = c ++ 11 /usr/lib64/gcc/x86_64-suse-linux/7/../../../../x86_64-suse-linux/bin/ld: lex.yy.o: in funzione yylex()': /home/rajatkmitra/modeler/minimal/lex.l:46: undefined reference to yyerror (char *) '/usr/lib64/gcc/x86_64-suse-linux/7/../../../../x86_64-suse-linux/bin/ld: / usr / lib64 / gcc /x86_64-suse-linux/7/../../../../lib64/libfl.so: riferimento non definito a `yylex 'collect2: errore: ld ha restituito 1 stato di uscita make: *** [Makefile: 68: lynx] ​​Errore 1

 Changes Made to get this environment to work -

 (1) Compile ALL sources including the output from lex and yacc with g++
 (2) yyerror arguments are (char *s) and NOT (const char *s)
 (2) do not link with -lfl as this is not not required with g++

Risposte

rici Nov 15 2020 at 00:00

Ecco un esempio minimo che mostra il problema:

file: yyerror.c

#include <iostream>
void yyerror(const char* msg) {
  std::cout << msg;
}

file: main.c

void yyerror(char* msg);
int main(void) {
  char* msg[] = "Hello, world";
  yyerror(msg);
}

Prova a costruire

$ g++ -Wall -o main main.c yyerror.c
/tmp/cc4xbjus.o: In function `main':
main.c:(.text+0x5f): undefined reference to `yyerror(char*)'
collect2: error: ld returned 1 exit status

Si noti che la dichiarazione di yyerrorin main.cè diversa dalla definizione di yyerrorin yyerror.c. Dato che stai compilando questi file come C ++, questo è importante: in C ++, i nomi delle funzioni possono essere sovraccaricati con diversi tipi di argomenti, ed const char*è un tipo di argomento diverso da char*. Quindi i due file non possono essere collegati con successo: il sovraccarico di yyerrordichiarato in main.cnon è definito da nessuna parte.

Sebbene non mostri la tua dichiarazione yyerrorinserita nel tuo file lexer, presumo che sia lo stesso del mio esempio, in base al messaggio di errore generato dal compilatore. Il messaggio di errore indica il nome completo (inclusi i tipi di argomento) della funzione che non può essere collegata.