こんにちは、高木です。
前回まででインタープリターの基本的な部分まで作ることができました。通常はプログラム全体でインタープリターはひとつですし、複数ある場合でも一番大本となるインタープリターがあり、それをルートインタープリターといいます。
ルートインタープリターはプログラムのどこからでもアクセスできた方が便利です(というか、そうでないと困ります)。グローバル変数にしてもいいのですが、念のためinterpreterクラスの静的なメンバー関数で設定や取得ができるようにしたいと思います。今回は先にコードから見た方がよさそうですね。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public: static interpreter root() { return root_; } static void root(interpreter interp) { if (root_.interp_) root_.release(); interp.preserve(); root_ = interp; } private: static interpreter root_; |
ルートインタープリターの取得と設定、つまりアクセッサとなるメンバー関数の名前はどちらもrootです。新しいルートインタープリターを設定した場合は、以前に登録されていたインタープリターがあればreleaseして、新しいものをpreserveしています。取得するだけなら単に値を返すだけですので、都度都度preserve/releaseは行いません。
さて、ここまでできたら、以前仮に作っていたobj::get_intメンバー関数を改善していきたいと思います。まずは以前のメンバー関数の定義から見ていきましょう。
0 1 2 3 4 5 6 7 8 9 |
std::optional<std::int_least32_t> get_int() const { extern Tcl_Interp* root_interp; int value; if (Tcl_GetIntFromObj(root_interp, this->obj_, &value) == TCL_OK) return static_cast<std::int_least32_t>(value); return {}; } |
こんな感じでした。仮だったのは、インタープリターをroot_interpというグローバル変数にしていた点です。これを今回作ったinterpreset::rootメンバー関数の呼び出しに変更してみます。
objクラスとinterpreterクラスは相互参照することになるので、メンバー関数の宣言と定義はこのあたりから分離する必要が出てきました。今回は定義部だけを掲載することにして宣言部は割愛します。
0 1 2 3 4 5 6 7 8 |
std::optional<std::int_least32_t> obj::get_int() const { int value; if (Tcl_GetIntFromObj(interpreter::root().get(), this->obj_, &value) == TCL_OK) return static_cast<std::int_least32_t>(value); return {}; } |
objクラスにはget_intメンバー関数以外にもget_wide_intメンバー関数など類似のものをいくつか定義しました。それらもまったく同じことですので、同様にして改善しておきます(コードは割愛します)。
これでインタープリターを何とか使えるようになりましたので、次回からはいよいよTkを扱っていくことにします。必要に応じてTclにも戻ってきますので、ここからは両方を行ったり来たりすることになるでしょう。