私は Yacc が大好きですが、差別的なユニオン スタックには課題があります。
CまたはC++のどちらを使用しているかわかりません。私自身の目的で C++ を生成するように Yacc を変更しましたが、このソリューションは C に適応させることができます。
私の推奨する解決策は、構築されたオブジェクトをスタックの上に渡すのではなく、解析ツリーの下にある所有者にインターフェースを渡すことです。これを行うには、Yacc の外部に独自のスタックを作成します。オブジェクトを割り当てる非ターミナルを呼び出す前に、そのオブジェクトの所有者をこのスタックにプッシュします。
例えば:
class IExpressionOwner
{
public:
virtual ExpressionAdd *newExpressionAdd() = 0;
virtual ExpressionSubstract *newExpressionSubtract() = 0;
virtual ExpressionMultiply *newExpressionMultiply() = 0;
virtual ExpressionDivide *newExpressionDivide() = 0;
};
class ExpressionAdd : public Expression, public IExpressionOwner
{
private:
std::auto_ptr<Expression> left;
std::auto_ptr<Expression> right;
public:
ExpressionAdd *newExpressionAdd()
{
ExpressionAdd *newExpression = new ExpressionAdd();
std::auto_ptr<Expression> autoPtr(newExpression);
if (left.get() == NULL)
left = autoPtr;
else
right = autoPtr;
return newExpression;
}
...
};
class Parser
{
private:
std::stack<IExpressionOwner *> expressionOwner;
...
};
式を必要とするものはすべて、IExpressionOwner インターフェイスを実装し、それ自体をスタックにプッシュしてから、式の非ターミナルを呼び出す必要があります。余分なコードがたくさんありますが、オブジェクトの有効期間を制御します。
アップデート
左のオペランドを減らすまで操作がわからないため、式の例は悪いものです。それでも、この手法は多くの場合に機能し、式を少し調整するだけで済みます。