2010-03-31 123 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