我目前正在为有关该主题的个人教育编写编译器前端,并且遇到了一个关于我通过运算符重载在 C++ 中处理 BNF 定义的方式的问题。
目前我的设置如下:
规则.h:
class Rule
{
public:
ChainRule operator>>(Rule& right);
OrRule operator|(Rule& right);
KleeneRule operator*();
OptionalRule Rule::operator+();
virtual bool parse(TokenList::iterator& begin, TokenList::iterator end) = 0;
};
规则.cpp:
ChainRule Rule::operator>>(Rule& right) {
return ChainRule(this, &right);
}
OrRule Rule::operator|(Rule& right) {
return OrRule(this, &right);
}
KleeneRule Rule::operator*() {
return KleeneRule(this);
}
OptionalRule Rule::operator+() {
return OptionalRule(this);
}
ChainRule、OrRule、KleeneRule、OptionalRule 和 EmptyRule 的定义很简单,如下所示:
class ChainRule : public Rule
{
private:
Rule* next;
Rule* _this;
public:
ChainRule();
ChainRule(Rule* _this, Rule* right);
bool parse(TokenList::iterator& begin, TokenList::iterator end) override;
};
Rule 的每个子类显然都定义了 parse() 的合理实现。使用这些类,我可以如下定义我的语法:
OrRule assignment_exp = logical_or_exp
| unary_exp >> StringRule("=") >> assignment_exp
;
现在问题来了:每个重载的运算符按值返回一个新对象。这意味着每当我使用 operator>> 或 operator| 从 Rule 类中,一旦我从对 operator>> 或 operator| 的调用返回,这些指针将是垃圾。因为堆栈已被清理并且对象已经消失。
我也不能在我的 Rule 子类的构造函数中使用按值传递,因为这不允许我定义递归语法。
所以我没有按值传递对象的选项,也没有按指针传递对象的选项。谁能指出一个不会强迫我像这样定义我的语法的解决方案?
StringRule s = StringRule("=");
OrRule assignment_exp;
ChainRule temp1 = s >> assignment_exp;
ChainRule temp2 = unary_exp >> temp1;
assignment_exp = logical_or_exp | temp2;
PS 我知道各种解析器生成器和 Boost.Spirit,但我的目标是编写自己的解析器。