2016-09-26 70 views
1

我創建了一個編譯器(用於酷語言)作爲個人項目,並且在設計符號表時遇到了麻煩。對於上下文,我使用類的層次結構作爲我的AST。這裏的AST的一個小片段:玩具編譯器符號表

class NodeAST { 
public: 
    virtual void accept(Visitor&) = 0; 
}; 

class ProgramAST : public NodeAST { 
private: 
    const std::vector<ClassPtr> vClasses; 

public: 
    ProgramAST(std::vector<ClassPtr> vClasses); 

    auto class_cbegin() const { 
    return std::cbegin(vClasses); 
    } 
    auto class_cend() const { 
    return std::cend(vClasses); 
    } 

    virtual void accept(Visitor& v) override; 
}; 

class ClassAST : public NodeAST { 
private: 
    const std::string name; 
    const std::vector<FeaturePtr> vFeatures; 

public: 
    ClassAST(std::string name, std::vector<FeaturePtr> vFeatures); 

    auto getName() const { 
    return name; 
    } 

    auto feature_cbegin() const { 
    return std::cbegin(vFeatures); 
    } 
    auto feature_cend() const { 
    return std::cend(vFeatures); 
    } 

    virtual void accept(Visitor& v) override; 
}; 

目前,在我的符號表的核心定義爲地圖如下:

std::unordered_map<std::string, NodeAST*> table 

它在聲明的名稱映射到其相應的節點AST。這樣,例如,我可以使用我在AST節點中設置的類型來填充鬆散標識符的類型。

但問題是,當我查詢的符號表中的節點,我拿回NodeAST*。因此,我必須將其下降到ClassAST*,MethodAST*VarDecAST*等以實際使用它。

如何設計我的符號表以避免爲向下轉換的需要的呢?

+2

我不會說在這裏downcasting一定是個大問題。你可以從上下文知道目標類型。當然,因爲Cool源代碼包含錯誤,所以downcast仍然會失敗,但在這種情況下,您的'dynamic_cast'失敗,並且您將其作爲直接錯誤輸出,例如'期望一個班,但是「Foo」命名一個功能'。 – MSalters

+0

也許:擺脫基本的'NodeAst'並使所有'accept'函數成爲非虛擬模板。相比之下,您可能會讓訪問者在每種集合類型上運行不同。 –

+0

@DieterLücking:通常幾乎不需要刪除基類;您仍然可以通過繼承實例化碰巧相關的類。 – MSalters

回答

1

我不知道你要實現的編程語言,但我不認爲這是真的可能是你能避免動態蒙上完全。例如,在f(1),f可能是一個函數或變量,如果您的語言有lambda表達式。你需要在符號表中查找它。

如果你能absoluteley排除這種可能性,理論上你可以創建爲每種類型的單獨的符號表。但請記住,如果需要檢測名稱衝突,顯然會更難找到名稱衝突,並且可能意味着您的編程語言稍後難以擴展。我不會推薦這個解決方案。

個人而言,我只是想讓to_class()to_var()is_class()is_var()等方法添加到您的NodeAST類,從而使動態轉換封裝,而不是圍繞整個代碼庫蔓延。你也可以創建一個類爲您的符號表,這樣就可以與get_class()訪問元素,get_var()

如果您擔心在C++中RTTI的運行成本,你可以看看其他的解決方案編譯器使用。對於LLVM是這裏描述:http://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html

1

我已經使用訪問者模式非常成功,在過去訪問指針的容器有一個共同的基礎。在一個實現中,我比dynamic_cast <>實現經歷了大約40%的加速,這對於我正在編寫的數據庫抽象層非常重要。

有一個Dispatcher類被訪問這裏的答案之一多一點的解釋.... Right design pattern to deal with polymorphic collections of objects

Visitor Pattern的維基百科頁面也給基指針的集合的一個漂亮的短C++的例子。

你已經顯示了你的問題了「的Visitable」類的源代碼。我們需要查看您的「訪問者」的實施情況,以瞭解您爲什麼需要dynamic_cast <>。這不應該是必要的。使用正確的visit()函數應該通過函數參數重載來選擇。

乾杯

+0

沒有必要在訪問者模式的非模板實現中向下轉發(如果要使用模板調查通用訪問者實現,請搜索Loki庫)。不確定接受的答案是否正確,但沒有評論的聲譽! –

+0

爲了插入符號表,我使用訪問者模式遍歷AST並插入命名值。這很好。問題出在我的TypeCheckVisitor類中。再次,我使用訪問者模式遍歷併爲每個AST節點執行分析。在分析過程中,我需要查詢符號表。例如,我需要在BinaryOperator節點中獲取LHS和RHS的類型。我需要這些類型在我正在使用的typeCheckBinaryOperator函數中(作爲訪問者模式的結果)。我沒有看到如何做到這一點,而不是先將LHS和RHS向下變爲變量。 – ryan