💡

オブジェクト指向Cコンパイラ neo-c 完成

2024/07/30に公開

version 1.2.0でlcc, 9cc, tccのコンパイルも通り、ある程度のCとの互換性もできました。
C++ほど複雑ではありませんが、シンプルなオブジェクト指向の機能があります。
クラスは

class sA {
    new(int a, int b) {
        int self.a = a;
        int self.b = b;
    }
};

int main(int argc, char* argv)
{
    var a = new sA(111,222);
    return 0;
}

のように書きます。リファレンスカウントのGCもあるので自動的にfreeされます。
と宣伝だけだと規約違反になるので自動的なfreeの仕組みを解説しておきますと

変数テーブルがブロックを抜け出す時、この場合だとaはリファレンスカウントを-1されて
リファレンスカウントが0ならfreeします。

これは単純な場合です。ですが、このアルゴリズムともう一つ以下のアルゴリズムで大体の
自動freeシステムはかけます。

void fun(char* str)
{
    puts(str);
}

int main(int argc, char** argv)
{
     fun(string("ABC"));

     return 0;
}

この場合です。string(stringはtypedef char*% stringです)は
ヒープにオブジェクトを作りますが、funのstrはただのcharなのでリファレンスカウントは+1されません。
funの後に右辺値のfreeを試みます。右辺値は生成されたオブジェクトのリストで、その一覧を
リストに保存しておきます。もし左辺値がvarやchar
%などの型名だとリファレンスカウントは+1
されて、右辺値のfreeはリファレンスカウントが>0なので起こりません。

つまり代入が起こるたびにリファレンスカウントを右辺値のオブジェクトに+1をして、一文が終わるたびに右辺値(生成されたオブジェクト一覧)でリファレンスカウントが0の右辺値をfreeすればいいだけです。

void fun(char*% str)
{
    puts(str);
}

int main(int argc, char** argv)
{
     fun(string("ABC"));

     return 0;
}

この場合だとfunの引数に代入されるときにstring("ABC")のオブジェクトにリファレンスカウントが+1されます。
ただfunが終わるときにstrが消されるためリファレンスカウントは-1されて、mainに戻ってきたときには右辺値のリストから探したヒープはリファレンスカウントは0なのでfreeされます。

おおまかに言えば、それだけのアルゴリズムでC言語にも自動的なfreeシステムが作れます。
要するに代入が起こるたびにチェックをすればいいだけです。

代入はローカル変数への代入、グローバル変数への代入、関数の引数への代入、構造体のメンバへの代入くらいしかありません。

それほど難しくないアルゴリズムであることがわかります。

neo-cでこのようなコンパイラは3作目でLLVM-C++, LLVM-C, C transpilerと作ってきました。neo-cはtranspilerで生成するコードはC言語のソースです。
LLVM-C++はちょっと仕様の変更を追いかけていくのが大変でやめました。
LLVM-Cはあまり仕様の変更はありませんし、シンプルなインターフェースなので書きやすかったです。
ただGCの代わりになるような完全なヒープシステムが作れなかったため、boehmGCを使ったヒープシステムにしました。
neo-cは完全なヒープシステムが作れました。上記のアルゴリズムでメモリリークは全然起きません。
neo-cにはメモリリークを検出する機能もあり、メモリリークがあればわかるのですが、neo-cで作ったvinというviクローン、shshというシェル、mfというファイラー、zedというテキスト処理インタプリタ全てでメモリリークはありません。あとneo-cはneo-c自身で作っていますが、neo-c自体もメモリーリークがありません。

https://github.com/ab25cq/neo-c

にあるので、使ってみてください。
MacOS, Linux, raspberry Pi, termux, userlandで動きます。
多少のソース変更でWindowsでも動くと思います。

インストールはsudoとgitとbashをインストールして

> apk add bash sudo git
> git clone https://github.com/ab25cq/neo-c
> cd neo-c && bash fast_build.sh

だけでいけます。管理者権限は必要ですが、必要なパッケージも自動的にインストールされます。

> bash all_build.sh

も追加するとエディッター、シェル、ファイラ、テキスト処理インタプリタもインストールされます。

Discussion