处理堆栈上的对象销毁



我目前正在编写一个编译器前端,用于该主题的个人教育,我遇到了一个关于如何通过运算符重载处理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;
};

Rule.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
;   

现在的问题是:每个重载运算符都按值返回一个新对象。这意味着,每当我从Rule类中使用运算符>>或运算符|时,一旦我从对运算符>>或操作符|的调用返回,这些指针就会成为垃圾,因为堆栈已经清理完毕,对象也不见了。

我也不能在Rule子类的构造函数中使用pass-by-value,因为这不允许我定义递归语法。

因此,我没有按值传递对象的选项,也没有按指针传递对象的选择。有人能给我指一个不会强迫我这样定义语法的解决方案吗?

StringRule s = StringRule("=");
OrRule assignment_exp;
ChainRule temp1 = s >> assignment_exp;
ChainRule temp2 = unary_exp >> temp1;
assignment_exp = logical_or_exp | temp2;

附言:我知道各种解析器生成器和BoostSpirit,但我的目标是编写自己的解析器。

您可以在堆上分配返回对象(通过工厂),并将它们作为引用返回。工厂可以跟踪它们,这样你就不会泄漏。就语法而言,它的工作原理与按值返回它们时相同。

您可以通过用包装器对象替换Rule*(存在无法为其重载运算符的问题)来解决此问题。即ChainRule将包含RuleRef next而不是Rule * next,等等,并且将为RuleRef定义所有运算符。RuleRef将简单地包含Rule*,并且可以从Rule*构造。为了使内存处理更容易,您可以从智能指针类继承。

最新更新