Обработка уничтожения объектов в стеке

В настоящее время я пишу интерфейс для личного обучения по этой теме и столкнулся с проблемой, касающейся способа обработки определения BNF в C ++ посредством перегрузки операторов.

В настоящее время моя установка выглядит следующим образом:

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

Теперь вот проблема: каждый перегруженный оператор возвращает новый объект по значению. Это означает, что всякий раз, когда я использую 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;

Постскриптум Я знаю о различных генераторах синтаксических анализаторов и Boost.Spirit, но моя цель — написать собственный анализатор.

1

Решение

Вы можете разместить возвращаемые объекты в куче (через фабрику) и вернуть их как ссылки. Фабрика может отслеживать их, чтобы вы не пропустили. Что касается синтаксиса, он будет работать так же, как и при возврате их по значению.

1

Другие решения

Вы можете обойти эту проблему, заменив Rule* (у которых есть проблема, что вы не можете перегрузить операторы для них) с объектами-обертками. То есть ChainRule будет содержать RuleRef next вместо Rule * nextи т. д., и все операторы будут определены для RuleRef, RuleRef будет просто содержать Rule*и быть конструируемым из Rule*, Чтобы упростить обработку памяти, вы можете унаследовать класс интеллектуальных указателей.

1