2010-03-31 98 views
1

我正在爲實驗性編程語言(教育性,趣味性...)編程解釋器 到目前爲止,一切進展順利(Tokenizer &解析器),但我得到實際運行標記化和解析代碼的部分數據結構存在大問題。C++:設計intepreter的概念性問題

我的編程語言基本上只具有兩種類型,int和串,和它們被表示成C++字符串(STD類)和整數

這裏是數據結構的短版,我使用周圍傳遞值:

enum DataType 
{ 
    Null, 
    Int, 
    String 
} 

class Symbol 
{ 
public: 
string identifier; 

DataType type; 
string stringValue; 
int intValue; 
} 

我不能使用聯合,因爲字符串不允許我。

上面的這個結構開始讓我很頭疼。

我撒這樣的代碼隨處可見,以使其發揮作用,它開始成長不可維護:

if(mySymbol.type == Int) 
{ 
    mySymbol.intValue = 1234; 
} else { 
    mySymbol.stringValue = "abcde"; 
} 

我使用的變量符號數據結構,功能和一般的表示返回值在編程語言中的值。

  • 有沒有更好的方法來解決這個問題?但願如此!

回答

2

問題出在這樣一個事實,即您的符號類是一種包含兩種不同類型的類型,您試圖通過符號類的單一類型進行識別。

這將是更好的多態創建符號:

class Symbol 
{ 
public: 
    virtual Symbol& operator = (int val) = 0; // Pure virtual 
    virtual Symbol& operator = (string val) = 0; // Pure virtual 
private: 
    string identifier; 
}; 

class IntSymbol : public Symbol 
{ 
public: 
    virtual Symbol& operator = (int val) 
    { 
     this->val = val; 
     return *this; // to make multiple assignments possible 
    } 
    virtual Symbol& operator = (string val) 
    { 
     throw new exception("Programm error"); 
     return *this; // to make it compile 
    } 
private: 
    int val; 
}; 

你做同樣的StringSymbol

4

你現在在做什麼是一種discriminated union的混蛋。問題是你沒有使用聯盟,歧視聯盟的功能是Symbol類本身的一部分。

我建議兩個替代方案,按順序或優先選擇:

1)使用變體類型。變體類型就像是類固醇的歧視聯盟。一個實現可以在Boost中找到。

2)創建一個合適的區分聯合,與Symbol類別分開定義。

編輯:歧視的聯盟實際上並不一定是union類型。它也可以是struct

+1

+1暗示'Boost.Variant',還要注意它的效率非常高。 – 2010-03-31 15:54:32

1

我可能會使用繼承 - 定義一個基類來實現您想要支持的基本操作,因此大多數其他代碼可以使用這些基類。例如:

class value { 
public: 
    virtual value &add(value const &other) = 0; 
    virtual value &assign(value const &other) = 0; 
}; 

class string_val : public value { 
    std::string data; 
public: 
    string_val &add(string_val const &other) { data += other.data; return *this; } 
    string_val &assign(string_val const &other) { data = other.data; return *this; } 
}; 

而不是使用純虛的,我這裏有,你可能更喜歡基類實際定義這些功能,但在每次拋出異常。只有在派生類沒有提供重載的情況下才會調用這些方法。這將用於像試圖用「abc」來分割「xyz」的情況。只有兩種派生類型,這不會節省lot,但您可能添加的派生類型越多,它(可能)保存的派生類型就越多。

+0

事實上,您不能實例化string_val,因爲它不會覆蓋抽象方法。 (我可能會誤解,但是你不需要像這樣的雙重調度?) – UncleBens 2010-03-31 15:57:00

+0

是的,這是作爲草圖,而不是可用的代碼。這基本上*是一個雙重派遣的實現。 – 2010-03-31 16:50:57