I am attempting to use operator overloading of the '&' and '|' and '|=' operators of C++ inorder to create a BNF (Backus Naur Form) embedded in C++. The two significant classes in this embedded BNF are class Terminal and class NonTerminal.
As example Snippet, consider the BNF description of a list of the characters 'a' or 'b':
Terminal _a('a'), _b('b');
NonTerminal list, token;
token |= _a | _b;
list |= token | token & list;
// Parse a string of 'a's and 'b's
if(list.match("baabaabaa"))
cout << "matched!!!";
else
cout << "failed!!!";
// Test the token nonterminal
token.match("a");
The class definitions are as follows: They don't do anything at the moment but serve as a test of the logic.
using namespace std;
class Sequence;
class Production;
class Base {
Base() {}
virtual ~Base() {}
friend Sequence operator & (const Base& lhs, const Base& rhs);
friend Production operator | (const Base& lhs, const Base& rhs);
virtual bool match(string) const { return false; }
};
class Terminal : public Base {
char token;
public:
Terminal(char c) : token(c) {}
virtual ~Terminal() {}
virtual bool match(string s) const { return true; }
};
class Sequence : public Base {
const Base& lhs;
const Base& rhs;
public:
Sequence(const Base& lhs, const Base& rhs) : lhs(lhs), rhs(rhs) {}
virtual ~Sequence() {}
virtual bool match(string s) const { return lhs.match(s) && rhs.match(s); }
};
class Production: public Base {
const Base& lhs;
const Base& rhs;
public:
Production(const Base& lhs, const Base& rhs) : lhs(lhs), rhs(rhs) {}
virtual ~Production() {}
virtual bool match(std::string s) const { return lhs.match(s) || rhs.match(s); }
};
The last class definition, NonTerminal, is where I am having trouble. And the trouble involves C+11 move semantics.
class NonTerminal : Base {
Base dummy; // Needed to make initialization work.
Base& ref; // Or maybe Base&& ref or possibly Base ref or could it be Base* ref?
NonTerminal() : ref(dummy) {}
virtual ~NonTerminal() {}
// Used when rhs is of type Sequence or Production
void operator |= (Base&& rhs) {
// The desired action is to capture rhs and keep it in memory.
ref = move(rhs);
}
// Used when rhs is of type Terminal
void operator |= (const Base& rhs) {
// The desired action is to reference rhs.
ref = rhs;
}
virtual bool match(string s) { return ref.match(s); }
};
The code that the above example is based on compiles but when 'list.match()' is called, it calls the method Base::match() and not Production::match() which is the expected behaviour. In the same manner, calling token.match() also calls the method Base::match() and not Terminal::match(). So how do I get the correct overwritten match methods called and do it correctly for the rvalue received in the first operator |= method?
Thanks
Aucun commentaire:
Enregistrer un commentaire