1

I am trying to compile lex.yy.c and y.tab.c with C++ code, here is the Make status -

(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

Okay so here is the grammar file 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);

}

and the 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;
}

This is the main routine 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));

}

So there you go! I have added the Minimal Reproducable Example. When I compile everything with g++ I end up getting a linker error that does not find the yyerror() routine 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 function 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: undefined reference to `yylex' collect2: error: ld returned 1 exit status make: *** [Makefile:68: lynx] Error 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++
Rajat Mitra
  • 167
  • 1
  • 11
  • 1
    I think we need to see your Makefile, and possibly your code. – Steve Friedl Nov 14 '20 at 00:37
  • Does this answer your question? [Undefined reference to \`\_yyerror' when compiling with Flex and Bison](https://stackoverflow.com/questions/17127481/undefined-reference-to-yyerror-when-compiling-with-flex-and-bison) – OMGtechy Nov 14 '20 at 00:42
  • 2
    Possible that name mangling and lack of an `extern "C"` block somewhere is to blame, but yeah, need a [mcve]. Emphasis on minimal. – Shawn Nov 14 '20 at 00:45
  • 1
    Bison, at least, can generate C++ code if you tell it to do. But if you're generating C code then you should compile it with a C compiler. C and C++ are distinct languages. – John Bollinger Nov 14 '20 at 00:58
  • I included the Makefile and looked how to specify extern "C"... no such luck. The code base is too big to put all in comments. How would I upload the example ?? – Rajat Mitra Nov 14 '20 at 00:59
  • You have a function `void yyerror(const char *)`; this is different, in C++, from a function `void yyerror(char *)`. Provide the function that is required — even if all it does is call the one you already provided. – Jonathan Leffler Nov 14 '20 at 16:48
  • Okay that seemed to move things forward a little.... I am using void yyerror(const char *s) consistently, but now I have another issue - /usr/lib64/gcc/x86_64-suse-linux/7/../../../../lib64/libfl.so: undefined reference to `yylex' – Rajat Mitra Nov 14 '20 at 17:12
  • @rajat: you should ask that in a different question, but the answer is simple: don't use `-lfl` with C++; it is compiled for C. I don't think you need it fir anything. – rici Nov 14 '20 at 17:56
  • The correct prototype for `yyerror` is `void yyerror(const char* msg);`. You have to use that prototype consistently. I guess consistently using the wrong prototype does let you compile and run your program, but it is still the wrong prototype and that fact will catch up with you eventually. – rici Nov 15 '20 at 03:39

1 Answers1

0

Here's a minimal example which shows the problem:

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);
}

Try to build

$ 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

Note that the declaration of yyerror in main.c is different from the definition of yyerror in yyerror.c. Since you're compiling these files as C++, this matters: in C++, function names can be overloaded with different argument types, and const char* is a different argument type than char*. So the two files cannot be successfully linked: the overload of yyerror declared in main.c is not defined anywhere.

Although you don't show the declaration of yyerror you placed in your lexer file, I'm assuming that it is the same as my example, based on the error message generated by the compiler. The error message indicates the complete name (including argument types) of the function which cannot be linked.

rici
  • 234,347
  • 28
  • 237
  • 341
  • Many thanks to rici and just about everyone had a useful suggestion! I would like to summarize what I did please see the post. I have appended the proper procedure to compile an environment like this. – Rajat Mitra Nov 14 '20 at 19:49