用 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.c
中yyerror
的声明与yyerror.c
中yyerror
的定义不同。由于您将这些文件编译为 C++,这很重要:在 C++ 中,函数名称可以用不同的参数类型重载,并且 const char*
是与 char*
不同的参数类型。所以这两个文件无法成功链接:在 main.c
中声明的 yyerror
的重载未在任何地方定义。
虽然您没有显示放在词法分析器文件中的 yyerror
声明,但根据编译器生成的错误消息,我假设它与我的示例相同。错误消息指出无法链接的函数的完整名称(包括参数类型)。
我正在尝试用 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.c
中yyerror
的声明与yyerror.c
中yyerror
的定义不同。由于您将这些文件编译为 C++,这很重要:在 C++ 中,函数名称可以用不同的参数类型重载,并且 const char*
是与 char*
不同的参数类型。所以这两个文件无法成功链接:在 main.c
中声明的 yyerror
的重载未在任何地方定义。
虽然您没有显示放在词法分析器文件中的 yyerror
声明,但根据编译器生成的错误消息,我假设它与我的示例相同。错误消息指出无法链接的函数的完整名称(包括参数类型)。