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

Dav*_*son 5 c++ yacc

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

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

有谁知道有更好的 yacc 技巧来解决这个问题吗?

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

Mic*_*rry 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;

    ...
};
Run Code Online (Sandbox Code Playgroud)

所有需要表达式的东西都必须实现 IExpressionOwner 接口,并在调用非终结符表达式之前将自身推送到堆栈。这是很多额外的代码,但它控制对象的生命周期。

更新

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