C ++ 코드로 lex / yacc를 컴파일하기 어려움

Nov 14 2020

lex.yy.c 및 y.tab.c를 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",$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);

}

그리고 어휘 분석기-

%{
 #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 : 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 :`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++

답변

rici Nov 15 2020 at 00:00

다음은 문제를 보여주는 최소한의 예입니다.

파일 : 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

참고 선언 있음 yyerror에는 main.c의 정의와 다르다 yyerror에서 yyerror.c. 당신은 C로이 파일을 컴파일하고 이후 ++,이 문제는 : C ++에서 함수 이름은 다른 인수 형식 오버로드 될 수 있으며, const char*이외의 다른 인수 유형입니다 char*. 따라서 두 파일을 성공적으로 연결할 수 없습니다. yyerror선언 된 의 오버로드는 main.c어디에도 정의 되어 있지 않습니다.

yyerror렉서 파일에 배치 한 선언을 표시하지는 않지만 컴파일러에서 생성 한 오류 메시지를 기반으로 내 예제와 동일하다고 가정합니다. 오류 메시지는 링크 할 수없는 함수의 전체 이름 (인수 유형 포함)을 나타냅니다.