在基于yacc的解析器中防止内存泄漏的最佳方法是什么?

时间:2008-09-15 17:31:45

标签: c++ yacc

Yacc不允许传递对象。因为%union只能包含POD类型,所以复杂对象必须是新的并且由指针传递。如果发生语法错误,yacc解析器将停止运行,并且对所有这些创建的对象的引用都将丢失。

我提出的唯一解决方案是所有new'd对象继承特定的基类,在分配时添加到容器中,如果有错误,则可以删除该容器中的所有内容。

有没有人知道有什么更好的yacc技巧来解决这个问题?

请不要告诉我选择不同的解析器。

4 个答案:

答案 0 :(得分:2)

我喜欢Yacc,但是区别性的联盟堆栈确实是一个挑战。

我不知道您使用的是C还是C ++。为了我自己的目的,我已经修改了Yacc以生成C ++,但是这个解决方案可以适应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接口并在调用表达式非终结符之前将其自身推送到堆栈。这是很多额外的代码,但它控制着对象的生命周期。

<强>更新

表达式示例很糟糕,因为在减少左操作数之后才知道操作。尽管如此,这种技术在许多情况下仍然有效,并且需要对表达式进行一些调整。

答案 1 :(得分:1)

如果它适合您的项目,请考虑使用Boehm垃圾收集器。这样你就可以自由地分配新对象并让收集器处理删除。当然,使用垃圾收集器需要权衡。你必须权衡成本和收益。

答案 2 :(得分:0)

为什么使用不同的解析器这样的问题?野牛很容易获得,并且(至少在Linux上)yacc通常被实施为野牛。您不应该对语法进行任何更改(使用%析构函数来解决您的问题)。

答案 3 :(得分:-1)

使用smart pointers

或者,如果您对另一个库感到不舒服,可以随时使用C ++标准库中的auto_ptr