rowl0 実装完了
ブートストラッピングの第1段階rowl0の実装が終わりました。
- rowlのサブセット言語
- GNU assemblerで書いてある
こんな感じでrowlコードをアセンブリ言語にコンパイルできます。
% cat hoge.rl fib: (p0) { if (p0 < 2) { return 1; } else { return fib(p0-1) + fib(p0-2); }; }; export main; main: () { syscall(1, fib(10)); # exit(). print系の代用 }; % ./rlc < hoge.rl > hoge.as % as hoge.as -o hoge.o % ld hoge.o -o hoge --nostdlib --entry=main % ./hoge % echo $? 89
rowl0で実装しているもの
- 関数定義, 関数コール
- if文, if-else文, while文, goto文, label文
- 四則演算など(+,-,*,/,%,<,>,<=,>=,==,!=,単項+,単項-,単項!)
- ポインタ, "*p = ...;" (void*のみ)
- システムコール: syscall()
- 名前付きグローバル変数: " x : 0; "
- 名前付きグローバル配列(1次元のみ): " ary : [0,1,2,3]; "
- 名前無しローカル変数
- 整数定数
- 文字定数(一部のエスケープシーケンスも)
- 文字列定数
- 一行コメント "#..."
- マクロ定数的なもの "X => 100;"
構文についてはそのうち書きます。";"が多くて読みにくいかもしれないですが意図があってこうなっています。
アセンブラで実装するという都合上以下のような制限があります。
- 名前管理ができない為、関数パラメータはp0,p1,...、ローカル変数はx0,x1,...という名前限定
- 関数冒頭でallocate(n)命令で変数確保
f: (p0, p1) { allocate(1); x0 = p0+p1; return x0; };
wch(ary, i, c); # write char: *(ary+i) = c rch(ary,i); # read char: *(ary+i)
- 関数末尾ではreturnが絶対に必要
- main末尾ではexitシステムコールが絶対に必要
次はrowl0でrowl0自身のコンパイラを作るというブートストラッピングのメインループに入ります。