问题描述
Yacc不允许传递对象。因为%union只能包含POD类型,复杂对象必须是新的,并通过指针传递。如果发生语法错误,yacc解析器就会停止运行,并且对所有创建的对象的引用都会丢失。
Yacc does not permit objects to be passed around. Because the %union can only contain POD types, complex objects must be new'd and passed around by pointer. If a syntax error occurs, the yacc parser just stops running, and references to all of those created objects are lost.
我想出的唯一解决方案是所有new'd对象继承一个特定的基类,在分配时添加到一个容器中,如果有错误,则该容器中的所有内容都可以被删除。
The only solution I've come up with is that all new'd object inherit a particular base class, be added to a container when allocated, and if there is an error everything in that container can be deleted.
知道任何更好的yacc技巧来解决这个问题?
Does anyone know of any better yacc tricks to solve this problem?
请不要告诉我选择一个不同的解析器。
Please don't tell me to choose a different parser.
推荐答案
我喜欢Yacc,但是区分性的联合堆栈提出了一个挑战。
I love Yacc, but the discriminating union stack does present a challenge.
我不知道你是否使用C或C ++。我修改了Yacc为我自己的目的生成C ++,但这个解决方案可以适应C。
I don't know whether you are using C or C++. I've modified Yacc to generate C++ for my own purposes, but this solution can be adapted to C.
我的首选解决方案是传递一个接口给所有者解析树,而不是在堆栈上构造对象。通过在Yacc之外创建自己的堆栈来做到这一点。在调用分配对象的非终端之前,将该对象的所有者推送到此堆栈。
My preferred solution is to pass an interface to the owner down the parse tree, rather than constructed objects up the stack. Do this by creating your own stack outside of Yacc's. Before you invoke a non-terminal that allocates an object, push the owner of that object to this stack.
例如:
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接口,并在调用表达式非终端。这是很多额外的代码,但它控制对象的生命周期。
Everything that wants an expression has to implement the IExpressionOwner interface and push itself to the stack before invoking the expression non-terminal. It's a lot of extra code, but it controls object lifetime.
更新
表达式示例是一个坏的,因为你不知道操作,直到你减少左操作数。不过,这种技术在许多情况下都有效,并且只需要对表达式进行一些调整。
The expression example is a bad one, since you don't know the operation until after you've reduced the left operand. Still, this technique works in many cases, and requires just a little tweaking for expressions.
这篇关于在基于yacc的解析器中防止内存泄漏的最好方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!