2008-09-15 22 views
4

Yacc不允許傳遞對象。因爲%union只能包含POD類型,所以複雜對象必須被新建並且通過指針傳遞。如果發生語法錯誤,則yacc解析器停止運行,並且對所有這些創建的對象的引用都會丟失。在基於yacc的解析器中防止內存泄漏的最佳方法是什麼?

唯一的解決方案,我想出來的是所有new'd對象繼承某個特定的基類,在分配時被添加到一個容器中,如果在該容器中的錯誤都可以被刪除。

有誰知道什麼更好的招數YACC來解決這個問題呢?

請不要告訴我選擇不同的解析器。

回答

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接口並調用表達非末端前推本身到堆棧中。這是很多額外的代碼,但它控制對象的生命週期。

更新

表示示例是一個壞的,因爲你不知道的操作,直到後你已經降低了左操作數。儘管如此,這種技術在很多情況下都有效,只需要對錶達式進行一些調整即可。

+0

可以顯示如何做到這一點的.ypp文件中使用一個複雜的對象? – 2008-09-16 15:21:26

+0

我接受最好的解決方案是在語法分析器之外創建一個並行數據結構。它使解析器不可重入,因爲解析器必須訪問全局變量,但我可以忍受這一點。 – 2009-05-21 15:37:03

1

如果它適合您的項目,請考慮使用Boehm垃圾收集器。這樣你可以自由分配新對象,並讓收集器處理刪除。當然,在使用垃圾收集器方面有一些折衷。你將不得不權衡成本和收益。

0

使用smart pointers

或者,如果你依賴於另一個庫不舒服,你可以隨時使用auto_ptr從C++標準庫。

+0

auto_ptr的是,無法通過 – 2008-09-15 19:02:16

1

爲什麼使用不同的分析器這樣的問題?野牛隨時可用,並且(至少在linux上)yacc通常被實現爲野牛。你不需要對你的語法進行任何修改就可以使用它(除了添加%析構函數來解決你的問題)。

相關問題