我正在尝试使用'&'和'|'的运算符重载和C ++的'| ='运算符,以创建嵌入在C ++中的BNF(Backus Naur Form)。 此嵌入式BNF中的两个重要类是Terminal类和NonTerminal类。
作为示例代码段,请考虑字符“ a”或“ b”的列表的BNF描述:
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");
类定义如下:它们目前不执行任何操作,但可以作为逻辑测试。
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); }
};
最后一个类的定义是NonTerminal,这是我遇到的麻烦。而且麻烦涉及C + 11移动语义。
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); }
};
上面的示例基于的代码可以编译,但是当调用“ list.match()”时,它将调用方法Base :: match()而不是生产行为::: match(),这是预期的行为。以相同的方式,调用token.match()还会调用方法Base :: match()而不是Terminal :: match()。那么,如何获得正确的被覆盖的match方法,并为第一个运算符| =方法中接收到的右值正确地实现呢?
谢谢