I'm trying to write a simple parser in lex and doing it in c++. I started off by following the directions here
WIKILINK \133{2}[^\135]+\135{2}
%option noyywrap
%option c++
%{
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <stdio.h>
#include <FlexLexer.h>
class xxFlexLexer : public yyFlexLexer
{
public:
virtual int yylex()
{
std::cout << "hello" << std::endl;
}
private:
vector<string> listOfLinks;
};
using namespace std;
%}
%%
{WIKILINK} {
int size = YYLeng();
string link(YYText());
link.erase(YYLeng()-3, 2);
link.erase(0, 2);
listOfLinks.push_back(link);
}
%%
int main()
{
ifstream in;
ofstream out;
in.open("in.txt");
out.open("out.txt");
yyFlexLexer lexer(&in, &out);
lexer.yylex();
}
When i try to compile the program lex.yy.cc, I get the following errors -
In file included from tmp.cpp:12:0:
/usr/include/FlexLexer.h:112:7: error: redefinition of ‘class yyFlexLexer’
/usr/include/FlexLexer.h:112:7: error: previous definition of ‘class yyFlexLexer’
tmp.cpp: In member function ‘virtual int yyFlexLexer::yylex()’:
tmp.cpp:33:29: error: ‘listOfLinks’ was not declared in this scope
I don't understand this error. What is happening?
Looking on the web I found this FlexLexer.h include file https://www.w3.org/2005/05/22-SPARQL-MySQL/sparql/FlexLexer.h and it appears that the signature for yylex() has an argument FLEXFIX.
virtual int yylex(FLEXFIX) = 0;
// Call yylex with new input/output sources.
int yylex(FLEXFIX, istream* new_in, ostream* new_out = 0 )
{
switch_streams( new_in, new_out );
return yylex(FLEXFIX2);
}
However other versions of the file such as https://www.w3.org/2008/04/SPARQLfed/win/FlexLexer.h do not.
virtual int yylex() = 0;
// Call yylex with new input/output sources.
int yylex( FLEX_STD istream* new_in, FLEX_STD ostream* new_out = 0 )
{
switch_streams( new_in, new_out );
return yylex();
}
By the way your yylex() function is not returning an int value.
See also #Gir comment with a link to a bug report Bug 67277 - Error compiling libclassparser_la.all_cc.cc: "class yyFlexLexer" redefined.
The problem is that the FlexLexer.h header has a strange way of
handling multiple inclusions of itself. tokenizer.l (tokenizer.cc)
and ClassParser.cc both include this header indirectly, and in
separate compilation they work fine; but when compiling concatenated
source, a "#define yyFlexLexer yyFlexLexer" declaration (inserted by
flex) carries through from tokenizer.cc to ClassParser.cc, and causes
havoc on the second inclusion. (In the error message quoted above, the
two FlexLexer.h lines are the second and first inclusions,
respectively.)
The/A solution is to "#undef yyFlexLexer" at the end of tokenizer.l,
and I will attach a patch that does this with an explanation why.
The comments in the FlexLexer.h include file mention using what is in the bug report for multiple instances and includes. Not sure why it would be needed in something this straightforward and simple though.
// This file defines FlexLexer, an abstract class which specifies the
// external interface provided to flex C++ lexer objects, and yyFlexLexer,
// which defines a particular lexer class.
//
// If you want to create multiple lexer classes, you use the -P flag
// to rename each yyFlexLexer to some other xxFlexLexer. You then
// include <FlexLexer.h> in your other sources once per lexer class:
//
// #undef yyFlexLexer
// #define yyFlexLexer xxFlexLexer
// #include <FlexLexer.h>
//
// #undef yyFlexLexer
// #define yyFlexLexer zzFlexLexer
// #include <FlexLexer.h>
// ...
Looking at the link you provided, I wonder if you need to remove the FlexLexer.h include since you have only the one parser.
Related
I'm working on an application that includes this library, let's call Snap.h.
I found that compilation fails if Snap.h is not the last on the includes statements. And on closer look, I find this code in a header file included by Snap.h
#define Try try {
#define Catch } catch (PExcept Except){ErrNotify(Except->GetMsgStr());}
#define CatchFull } catch (PExcept Except){ErrNotify(Except->GetStr());}
#define CatchAll } catch (...){}
Basically this lets try and catch blocks to be used as statements, like so
Try;
<some code>
Catch;
You can see how this is an issue, these generic macros collide with other libraries very easily.
Unfortunately this is tens of thousands of lines of very complicated code and the application I'm working on is built around this library. Its not easily changed.
Cpp is not my strong suit, is there a way to limit the effects of macros in an include?
I not a big fan of #undef things, because you never now what other bad stuff can slumber in that big header. I prefer isolating it in a "compilation barrier" i.e. only including it in a separate wrapper translation unit, which only redefines and forwards what you need. In the following example Snap.h redefines BULLSHIT to std::terminate, but as you can try, main.cpp can use the function in Snap.h without its version of BULLSHIT:
/*! #file main.cpp
*/
#include <iostream>
#define BULLSHIT
#include "snap_wrapper.h"
int main() {
BULLSHIT
std::cout << wrapper::nice_function() << "\n";
}
/*! #file Snap.h
*/
#ifndef UNTITLED5_SNAP_H
#define UNTITLED5_SNAP_H
#define BULLSHIT std::terminate();
int nice_function() {
return 42;
}
#endif //UNTITLED5_SNAP_H
/*! #snap_wrapper.h
*/
#ifndef UNTITLED5_SNAP_WRAPPER_H
#define UNTITLED5_SNAP_WRAPPER_H
namespace wrapper{
int nice_function();
}
#endif //UNTITLED5_SNAP_WRAPPER_H
/*! #file snap_wrapper.c
*/
#include "snap_wrapper.h"
#include "Snap.h"
namespace wrapper {
int nice_function() {
return ::nice_function();
}
}
I have created header file abc.hpp which contains a namespace of multiple functions.
When I use single source file which includes the header and call the function defined in namespace it works well, but when I call the same function in project where I have to include this header in multiple places, compilation gives me multiple definition error.
My other files are created as library and get executed.
abc.hpp:
#ifndef __ABC_HPP__
#define __ABC_HPP__
namespace abc {
void sendtext(const char* msg)
{
create_context(mycontext);
send_context(create_context,msg)
}
void sendtextwitherrno(const char* msg, int errn)
{
create_context(mycontext);
send_context(create_context,msg, errn)
}
};
#endif
test.cpp:
#include"abc.hpp"
int main()
{
abc::sendtext("hello world");
abc::sendtextwitherrno("hello error no",140);
return 0;
}
You can treat header files as if they are copy-pasted into your implementation files. So by putting function definitions into your headers, those definitions appear in multiple translation units (roughly, compiler .cpp files). This is not allowed - how is the compiler supposed to tell between them if they end up different?
Usually you would have a .h/.cpp pair, with function declarations going in the .h, and function definitions going in the .cpp. This way the definition only appears once in your whole program.
I can split your code like this:
abc.hpp:
#ifndef __ABC_HPP__
#define __ABC_HPP__
// function **declarations**
namespace abc{
void sendtext(const char* msg);
void sendtextwitherrno(const char* msg, int errn);
}
#endif
abc.cpp:
#include "abc.hpp"
#include "context.hpp" // I guess this might be where create_context and send_context come from
// function **definitions**
namespace abc{
void sendtext(const char* msg){
create_context(mycontext); // not sure where mycontext is supposed to live?
send_context(create_context,msg)
}
void sendtextwitherrno(const char* msg, int errn){
create_context(mycontext);
send_context(create_context,msg, errn);
}
}
test.cpp:
#include "abc.hpp"
int main(){
abc::sendtext("hello world");
abc::sendtextwitherrno("hello error no",140);
return 0;
}
Another way is to mark the functions as inline - this tells the compiler you are deliberately repeating the function definition all over the place, and you'd better be sure the definition is always identical. How sure are you? Are there different macros or different compiler flags in place in different places the function is used?
I have two namespaces (F and M) where I used typedef to define something. I use the typedef in one namespace to declare a variable in the other namespace.
For example I have these files:
File M.hpp
#ifndef M_HPP
#define M_HPP
#include "F.hpp"
namespace M{
typedef std::vector<F::myD> VectorDouble;
class M{
private:
VectorDouble Diction;
};
}
#endif // M_HPP
File F.hpp
#ifndef F_HPP
#define F_HPP
#include "M.hpp"
namespace F{
typedef double myD;
class MyF{
private:
M::VectorDouble myVar;
};
}
#endif // F_HPP
It is immediately clear that these two header files create a circular dependance so forward declaration may be necessary, but how to do that with namespaces and typedefs?
File namespace.cpp to drive the code:
#include <iostream>
#include <vector>
#include "M.hpp"
#include "F.hpp"
int main(){
std::cout << "Learning how to access stuff in a namespace." << std::endl;
F::MyF myFInstance;
M::M myMInstance;
return 0;
}
When I try to compile, I get an error that my M is an undeclared identifier (see exact error message below). I don't understand why M isn't seen as a namespace.
$ clang++ -std=c++11 -stdlib=libc++ namespace.cpp -o namespace
In file included from namespace.cpp:5:
In file included from ./M.hpp:5:
./F.hpp:12:9: error: use of undeclared identifier 'M'
M::VectorDouble myVar;
^
1 error generated.
How can I access a typedef from another namespace? Is this a forward declaration issue?
Your issue is that you have created circular includes.
By your own coding, your file F.hpp can't be compiled without first including M.hpp.
And M.hpp can't be compiled without first including F.hpp.
Therefore, neither header can be compiled. See this SO post for solutions to circular dependencies.
Edit:
You can forward declare your typedef like this.
File F_fwd.hpp
#ifndef F_FWD_HPP
#define F_FWD_HPP
namespace F{
typedef double myD;
}
#endif // F_FWD_HPP
your two headers are included in each other, that would lead to circular reference and with the header gaurds, one file can be completely excluded in one of the other headers.
I have the following files:
CP.h
#ifndef CP_H_
#define CP_H_
class CP {
public:
enum Cardinalite {VIDE = '\0', PTINT = '?', AST = '*', PLUS = '+'};
CP(Cardinalite myCard);
virtual ~CP();
private:
Cardinalite card;
};
#endif /* CP_H_ */
And dtd.y
%{
using namespace std;
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include "AnalyseurDTD/DtdDocument.h"
#include "AnalyseurDTD/CP.h"
void yyerror(char *msg);
int yywrap(void);
int yylex(void);
DtdDocument * doc = new DtdDocument();
%}
%union {
char *s;
DtdElement * dtdelt;
CP *cpt;
CP::Cardinalite card;
}
And the following strange error:
AnalyseurDTD/dtd.y:20:2: error: ‘CP’ does not name a type
AnalyseurDTD/dtd.y:21:2: error: ‘CP’ does not name a type
The stange thing is that if I put CP *cpt; after DtdDocument * doc = new DtdDocument(); I have no error :/
Include the header in your scanner file before you include *.tab.h
// scanner.l file
%{
#include "myheader.h"
#include "yacc.tab.h"
// other C/C++ code
%}
// helper definitions
%%
// scanner rules
%%
%union is defined in yacc.tab.h so when you compile you need to make sure the compiler sees your new type definitions before it process yacc.tab.h
Recently I am working with flex and bison. There are several advises that may be helpful for you to locate the problem:
Compile the files one by one to make sure there is no obvious compiling error in your code.
Check the header file generated by bison (something like *.tab.h). Find the definition of YYSTYPE. There is a high probability that it doesn't include your header file AnalyseurDTD/CP.h.
If it's just the case, you should always include AnalyseurDTD/CP.h before you include the *.tab.h. Add it wherever needed to make sure the class CP is defined before YYSTYPE.
If you still cannot locate the problem, try use void *cpt; in the union, then add type conversion in the rest of your code.
Are you sure the error is from Bison? I would venture it comes from your compiler. And probably when it was trying to compile the scanner. I would suggest that your YYSTYPE is not properly defined in your generated header. Try
%code requires { #include "AnalyseurDTD/CP.h" }
so that dtd.h is self-contained. See the documentation about %code.
And please, always provide logs that are complete enough so that we can try to understand your problem. Here, you don't even show the tool you ran, and I hardly think it is Bison.
I understand that pre-processor commands are an important part of header files to prevent vars and classes from being defined more than once.
I have been running into issues with my vars being defined multiple times - even with pre-processor wrappers. Here is a sample project that is experiencing compiler errors:
Header:
// TestInclude.h
#ifndef TESTINCLUDE_H_
#define TESTINCLUDE_H_
int myInt;
#endif /*TESTINCLUDE_H_*/
C++:
// TestInclude.cpp
#include <iostream>
#include "IncludeMe.h"
#include "TestInclude.h"
int main( int argc, char* args[] )
{
std::cin >> myInt;
IncludeMe thisClass;
std::cin >> myInt;
}
Header:
// IncludeMe.h
#ifndef INCLUDEME_H_
#define INCLUDEME_H_
class IncludeMe
{
private:
int privateInt;
public:
IncludeMe();
};
#endif /*INCLUDEME_H_*/
C++:
// IncludeMe.cpp
#include <iostream>
#include "IncludeMe.h"
#include "TestInclude.h"
IncludeMe::IncludeMe()
{
std::cout << "myInt: " << myInt;
}
Then I compile like this:
Makefile:
all:
g++ -g -o TestInclude TestInclude.cpp IncludeMe.cpp
And I get the following error:
/tmp/ccrcNqqO.o: In function `IncludeMe':
/home/quakkels/Projects/c++/TestInclude/IncludeMe.cpp:6: multiple definition of `myInt'
/tmp/ccgo6dVT.o:/home/quakkels/Projects/c++/TestInclude/TestInclude.cpp:7: first defined here
collect2: ld returned 1 exit status
make: *** [all] Error 1
Why am I getting this error when I'm using pre-processor conditionals in my header files?
Include guards do not protect against multiple definitions. They only protect against infinite recursive inclusion. (You can of course include the same header in multiple translation units!)
You should never have object definitions* in the header; only declarations:
header.hpp:
extern int a;
file.cpp:
#include "header.hpp"
int a = 12;
*) You can have class definitions in a header file, as well as inline functions and class member functions.
You should use extern int myInt; in header files and only write int myInt; in the single .cpp file where you want to define it.
Some projects use a preprocessor macro like "IN_FOO_CPP" to make that happen automatically with #ifdefs.