私は現在、このトピックに関する個人教育用のコンパイラ フロント エンドを作成していますが、演算子のオーバーロードによって C++ で BNF 定義を処理する方法に関する問題に遭遇しました。
現在、私のセットアップは次のとおりです。
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;
};
ルール.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 を認識していますが、私の目標は独自のパーサーを作成することです。