私はYaccが大好きですが、区別している組合のスタックは挑戦しています。
CまたはC++を使用しているかどうかわかりません。私は自分の目的のためにC++を生成するようにYaccを修正しましたが、この解決策はCに適合させることができます。
私の好みの解決策は、スタックの上に構築されたオブジェクトではなく、これをYaccの外に独自のスタックを作成することで行います。オブジェクトを割り当てる非終端記号を呼び出す前に、そのオブジェクトの所有者をこのスタックにプッシュします。例えば
:式がIExpressionOwnerインターフェイスを実装し、表現非ターミナルを起動する前に、スタックに自分自身をプッシュしていたい
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;
...
};
すべて。余分なコードがたくさんありますが、オブジェクトのライフタイムを制御します。
更新が
表現の例は、あなたが左オペランドを削減した後まで、操作がわからないので、悪いものです。それでも、このテクニックは多くの場合に機能し、表現のためにちょっとした調整が必要です。
これは.yppファイルでどのように使用されるかを表示できますか? –
私は、構文解析ツールの外部で並列データ構造を作成するのが最善の解決策であることを認めます。パーサーはグローバル変数にアクセスしなければならないので、パーサーは非リエントラントになりますが、私はそれで生きることができます。 –