Yacc不允許傳遞對象。因爲%union只能包含POD類型,所以複雜對象必須被新建並且通過指針傳遞。如果發生語法錯誤,則yacc解析器停止運行,並且對所有這些創建的對象的引用都會丟失。在基於yacc的解析器中防止內存泄漏的最佳方法是什麼?
唯一的解決方案,我想出來的是所有new'd對象繼承某個特定的基類,在分配時被添加到一個容器中,如果在該容器中的錯誤都可以被刪除。
有誰知道什麼更好的招數YACC來解決這個問題呢?
請不要告訴我選擇不同的解析器。
Yacc不允許傳遞對象。因爲%union只能包含POD類型,所以複雜對象必須被新建並且通過指針傳遞。如果發生語法錯誤,則yacc解析器停止運行,並且對所有這些創建的對象的引用都會丟失。在基於yacc的解析器中防止內存泄漏的最佳方法是什麼?
唯一的解決方案,我想出來的是所有new'd對象繼承某個特定的基類,在分配時被添加到一個容器中,如果在該容器中的錯誤都可以被刪除。
有誰知道什麼更好的招數YACC來解決這個問題呢?
請不要告訴我選擇不同的解析器。
我愛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接口並調用表達非末端前推本身到堆棧中。這是很多額外的代碼,但它控制對象的生命週期。
更新
表示示例是一個壞的,因爲你不知道的操作,直到後你已經降低了左操作數。儘管如此,這種技術在很多情況下都有效,只需要對錶達式進行一些調整即可。
如果它適合您的項目,請考慮使用Boehm垃圾收集器。這樣你可以自由分配新對象,並讓收集器處理刪除。當然,在使用垃圾收集器方面有一些折衷。你將不得不權衡成本和收益。
爲什麼使用不同的分析器這樣的問題?野牛隨時可用,並且(至少在linux上)yacc通常被實現爲野牛。你不需要對你的語法進行任何修改就可以使用它(除了添加%析構函數來解決你的問題)。
可以顯示如何做到這一點的.ypp文件中使用一個複雜的對象? – 2008-09-16 15:21:26
我接受最好的解決方案是在語法分析器之外創建一個並行數據結構。它使解析器不可重入,因爲解析器必須訪問全局變量,但我可以忍受這一點。 – 2009-05-21 15:37:03