nptclのブログ

Common Lisp処理系nptの開発メモです。https://github.com/nptcl/npt

試しにC言語でCommon Lispを使う

nptの開発は結構進んでおり、 あとはcompile-file, load, stepだけとなりました。
まあバグを含め問題盛りだくさんなんですけどね。

nptの開発目的の一つとして、C言語に組み込んで使うという考えがあります。
だからわざわざnpt-amalgamationという訳の分からないものも作っています。

C言語の組み込みは、自分にとっては結構大切なものなので、 少しくらいは外部インターフェイスを作ろうかと頑張っていたのですが、 やはりなかなか難しいものです。

例えば下記のLispのコードを考えます。

(defun fact (x)
  (if (not (plusp x))
    1
    (* x (fact (1- x)))))

(defun test ()
  (format t "Fact: ~S~%" (fact 200)))

(test)

単なる階乗です。
これをnptのモジュールを使って、C言語で表してみます。
★ただし問題ありバージョン。

addr fact(addr x)
{
    addr y;

    if (! lisp_plusp(x))
        return lisp_fixnum(1);

    lisp_funcall8(&y, "-", x, lisp_fixnum(1), NULL);
    lisp_funcall8(&y, "*", x, fact(y), NULL);

    return y;
}

int test(void)
{
    addr value;

    value = fact(lisp_fixnum(200));
    lisp_format8(lisp_t(), "Fact: ~S~%", value, NULL);

    return 0;
}

実際に動かした結果は下記の通り。

Fact: 78865786736479050355236321393218506229513597768717326329474253324435944996
34033429203042840119846239041772121389196388302576427902426371050619266249528299
31113462857270763317237396988943922445621451664240254033291864131227428294853277
52424240757390324032125740557956866022603190417032406235170085879617892222278962
3703897374720000000000000000000000000000000000000000000000000

初期化などを抜かした一部抜粋ですが、こんな感じになりました。
個人的には割といいんじゃないかと思うんです。
もし上記のようにラフに使えるなら、 便利なモジュールになるんじゃないでしょうか。

でもダメ。
上のコードはGarbage Collectionのタイミングでメモリ破壊をおこします。

これ、なんて言うんでしょうか。
メモリリークの逆なんですよね。
C言語上だとまだ使ってるのに、Common Lispではもういらないだろうと判断して 勝手にメモリを開放していくやつなんですが、 nptの開発では本当に頻繁に起こります。

検索すると、C#とかでも生じる現象みたいです。
たぶんGarbage Collection型のメモリを持った環境だと 典型的な問題なんだと思います。

もちろん対策する方法はあるのですが、 普通の人にメモリ破壊が起きないように C言語でコードを書いてくださいと言われても無理でしょう。

Lispのモジュール化というのもなかなか難しいものです。
まあこのまま作っていく予定ですが。