徒然なる日々を送るソフトウェアデベロッパーの記録(2)

技術上思ったことや感じたことを気ままに記録していくブログです。さくらから移設しました。

minosys script を作ろう (11)

関数の実装

関数にはパッケージ関数とメンバー関数がありますが、
パッケージ関数の実装から考えてみます。

パッケージにはバイナリパッケージと minosys script パッケージが
定義されているのでした。
minosys.hateblo.jp

両者を統一的に扱うために PackageBase というクラスを導入し、

Ptr<Var> start(const string &fname, vector<Var> args);

という純粋仮想関数を導入します。

バイナリパッケージ(PackageDlopen) ではこの関数の実装は start と
いうシンボルを持つ関数が呼び出されて解決しますが、この関数の
「真の定義」は以下のようになっています。

extern "C" int start(Ptr<Var> *rval, Engine *eng, const char *fname, vector<Ptr<Var> > *parg);

実行環境 eng の元で関数名 fname である関数を引数並び parg で呼び出す
という構造になっています。戻り値は rval に返されます。
(もちろん、同時にパラメータスタックトップにも返すことになっています。)
関数呼び出しに成功した場合は 0 を、失敗した場合は -1 を返すことを
想定しています。(失敗した場合は minosys script では NULL 変数に変換
されます。)

minosys script パッケージ(PackageMinosys)ではスクリプト解析木
top が定義されます。minosys script における start 関数の仕事は以下のように
なります。

  1. 引数リストから引数マップを作成し、引数スタックに積む
  2. 3つのスタックのスタックトップの位置を xxxmark 変数に退避する
  3. top->funcs.find(fname) を実行し、関数名に対応する解析木を取り出す
  4. 解析木を実行する
  5. 退避しておいたスタックトップ位置を元に戻し、関数の戻り値を構成する
  6. 関数呼び出しに失敗した場合は NULL 変数を返す

関数の解釈は

Ptr<Var> callfunc(const string &fname, Content *c);

で行われます。実際はこの関数には制御構造が実装されているのみで、
評価式は

Ptr<Var> evalute(Content *c);

で解釈されます(まだメソッド定義を書いていません...)

ビルトイン関数

4つのビルトイン関数を用意しました。

関数名 内容
type 変数の型に対応する数値を返します。数値には VT_NULL, VT_INT などが定義されています。
convert 変数の型変換を行います。VT_INT, VT_DNUM, VT_STRING の相互変換が可能です。変換元の変数と変換先の型を指定します。
print 変数値を文字列出力します。引数は不定数とります。
exit ExitException 例外を投げます。引数はプログラム戻り値です。

次回はメンバー関数の発見と実行、パッケージ関数とメンバー関数の微妙な
違いについて考えてみます。