1
votes

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++
1
I think we need to see your Makefile, and possibly your code.Steve Friedl
Possible that name mangling and lack of an extern "C" block somewhere is to blame, but yeah, need a minimal reproducible example. Emphasis on minimal.Shawn
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
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

1 Answers

0
votes

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.