minosys script を作ろう (8)
スマートポインタの定義
boost の smart pointer を使ってもよいのですが、
折角なので、ここでは独自に smart pointer を作成してみます。
template <class T> class PtrRef { private: int count; T *value; public: Ptr<T>(T *value) : count(0), value(value) {} Ptr<T>() : count(0), value(NULL) {} ~Ptr<T>() { delete value; } void inc() { ++count; } int release() { return --count; } T *get() const { return value; } T *getvalue() { return value; } }; template<class T> class Ptr { private: PtrRef<T> *ref; public: Ptr<T>() : ref(NULL) {} Ptr<T>(T *value) : ref(new PtrRef<T>(value)) {} ~Ptr<T>() { if (ref && ref->release() < 0) { delete ref; } } T *get() const { if (!ref) { return NULL; } return ref->get(); } T *getvalue() { if (!ref) { return NULL; } return ref->getvalue(); } Ptr<T>(const Ptr<T> &p) : ref(p.ref) { if (ref) { ref->inc(); } } Ptr<T> &operator = (const Ptr<T> &p) { if (ref && ref->release() < 0) { delete ref; } ref = p.ref; if (ref) { ref->inc(); } return *this; } };
変数クラス Var
変数に相当するクラス Var を構築します。
変数には以下の型があります。
型ごとに有効になるメンバー変数が異なります。
型 | 意味 | 有効なメンバー |
---|---|---|
VT_NULL | null値 | なし |
VT_INT | 整数 | inum |
VT_DNUM | 浮動小数点数 | dnum |
VT_STRING | 文字列 | str |
VT_INST | あるクラスのインスタンス | inst |
VT_POINTER | anonymous pointer(FILE *など) | pointer |
VT_ARRAY | 辞書配列 | arrayhash |
VT_FUNC | 関数 | func |
VT_MEMBER | Memeber関数 | member |
関数とメンバー関数が別扱いになっている理由は、両者が単なる
文字列では表現できないためです。
型 | 内容 | 変数型 |
---|---|---|
VT_FUNC | <関数名>.<関数名> | pair< string, string> |
VT_MEMBER | <変数>.<関数名> | pair< Ptr< Var>, string> |
デフォルトパッケージ(実行時に要求されたパッケージ)は
別名として "" を持つものとします。
配列添字クラス VarKey
minosys script では配列添え字として整数、浮動小数点数、文字列の3つを
許可しています。ただし、これらは互いに独立で、相互変換されません。
(整数の 0 と文字列の "0" は異なるということです。)
unordered_map のキーとして使えるようにするため、いくつかのメンバー関数を
追加します。
struct VarKey { VTYPE vtype; union { int inum; int dnum; string *str; } u; VarKey(int inum) : vtype(VT_INT) { u.inum = inum; } VarKey(double dnum) : vtype(VT_DNUM) { u.dnum = dnum; } VarKey(const string &c) : vtype(VT_STRING) { u.str = new string(c); } VarKey(const VarKey &v) : vtype(v.vtype) { switch (vtype) { case VT_INT: u.inum = v.u.inum; break; case VT_DNUM: u.dnum = v.u.dnum; break; case VT_STRING: u.str = new string(*v.u.str); break; } } ~VarKey() { if (vtype == VT_STRING) { delete u.str; } } bool operator == (const VarKey &v) const { if (vtype != v.type) { return false; } switch (vtype) { case VT_INT: return u.inum == v.u.inum; case VT_DNUM: return u.dnum == v.u.dnum; case VT_STRING: return *u.str == *v.u.str; } return false; } bool operator != (const VarKey &v) const { return !(*this == v); } struct Hash { size_t operator()(const VarKey &v) { switch (v.vtype) { case VT_INT: return hash<int>()(v.u.inum); case VT_DNUM: return hash<double>()(v.u.dnum); case VT_STRING: return hash<string>()(*v.u.str); } } return 0; }; };
hash 関数を使うときに括弧()が必要になることに注意してください。
VarKey を使うと、変数 Var の辞書配列のメンバーは
unordered_map<VarKey, Ptr<Var>, VarKey::Hash> araryhash;
と表現されます。
次回は実行エンジンの構成について説明します。