I like Yacc, but the discriminating union stack is a challenge.
I do not know if you use C or C ++. I modified Yacc to generate C ++ for my own purposes, but this solution can be adapted to C.
My preferred solution is to pass the interface to the owner in the parse tree, rather than constructing objects on the stack. Do this by creating your own stack outside of Yacc's. Before calling the non-terminal that allocates an object, push the owner of this object onto this stack.
For instance:
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; ... };
All that the expression wants is to implement the IExpressionOwner interface and push itself onto the stack before calling the expression without a term. This is a lot of extra code, but it controls the lifetime of the object.
Update
An example expression is bad because you do not know the operation until you reduce the left operand. However, this technique works in many cases and requires a little adjustment for expressions.
source share