用 C++ 代码编译 lex/yacc 有困难

Difficulties compiling lex/yacc with C++ code

我正在尝试用 C++ 代码编译 lex.yy.c 和 y.tab.c,这里是 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

好的,这是语法文件 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",); }
        |   integer_assignment ';'     { }
        ;
 
integer_assignment:
        VARIABLE '=' INTEGER 
        {
            if(attributeFlag==1){
            if(strcmp(, "S")==0){
              //attrContainer.isSigned = ;
                }else if(strcmp(, "IB")==0){
              //attrContainer.intBits = ;
                }else if(strcmp(, "FB")==0){
              //attrContainer.fracBits = ;
                }
            }
        }
    ;

expr:
        VARIABLE              { printf("%s\n",); }
        |   FLOAT                 { printf("%f\n",); }
        | '-'   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);

}

和词法分析器 -

%{
 #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;
}

这是主例程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));

}

好了!我添加了最小可重现示例。当我用 g++ 编译所有东西时,我最终得到一个链接器错误,在 yylex()

中找不到 yyerror() 例程
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: 在函数中 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: 未定义 对“yylex”的引用 collect2:错误:ld 返回 1 退出状态 make: *** [Makefile:68: lynx] 错误 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++

这是一个显示问题的最小示例:

文件:yyerror.c

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

文件:main.c

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

尝试构建

$ 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

注意main.cyyerror的声明与yyerror.cyyerror的定义不同。由于您将这些文件编译为 C++,这很重要:在 C++ 中,函数名称可以用不同的参数类型重载,并且 const char* 是与 char* 不同的参数类型。所以这两个文件无法成功链接:在 main.c 中声明的 yyerror 的重载未在任何地方定义。

虽然您没有显示放在词法分析器文件中的 yyerror 声明,但根据编译器生成的错误消息,我假设它与我的示例相同。错误消息指出无法链接的函数的完整名称(包括参数类型)。