我正在编写一个实验性编程语言的解释器(教育,有趣,......) 到目前为止,一切进展顺利(Tokenizer& Parser),但是我在实际运行标记化和解析代码的部分中的一些数据结构遇到了巨大的问题。
我的编程语言基本上只有两种类型,int和string,它们表示为C ++字符串(std类)和ints
以下是我用来传递值的数据结构的简短版本:
enum DataType
{
Null,
Int,
String
}
class Symbol
{
public:
string identifier;
DataType type;
string stringValue;
int intValue;
}
我不能使用union,因为string不允许我这样做。
上述结构开始让我头疼。
我必须将这样的代码分散到各处以使其工作,它开始变得不可维护:
if( mySymbol.type == Int )
{
mySymbol.intValue = 1234;
} else {
mySymbol.stringValue = "abcde";
}
我将符号数据结构用于变量,返回函数的值以及编程语言中值的一般表示。
答案 0 :(得分:4)
你现在正在做的是discriminated union的混蛋。问题是你没有使用联合,并且被区分联合的功能是Symbol
类本身的一部分。
我建议两种选择,按顺序或偏好:
1)使用变体类型。变体类型就像类固醇上的区别联合。可以在Boost中找到一个实现。
2)创建一个适当的区分联合,与Symbol
类分开定义。
编辑:受歧视的联合实际上不必是union
类型。它也可以是struct
。
答案 1 :(得分:2)
问题来自这样一个事实:您的符号类是一种类型,它包含两种不同的类型,您尝试通过类Symbol的单一类型来识别它。
以多态方式创建符号会更好:
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
执行相同的操作答案 2 :(得分: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; }
};
不像我在这里使用纯虚拟,你可能更喜欢基类实际定义那些函数,但每个都抛出异常。仅在派生类未提供重载的情况下才会调用它们。这将用于尝试将“xyz”除以“abc”的情况。如果只有两种派生类型,则不会保存批次,但您可能添加的派生类型越多,它(可能)节省的就越多。