whitespaceを出力するコンパイラのようなものを作った
この記事は何ですか
日記です
興味を持った
コンパイラを作る講習会があったらしく*1, 興味を持ったので自分でもコンパイラを書いてみた.
どんなコンパイラ
- コンパイラから出力されるアセンブリは
whitespace
*2. - CやらjavascriptやらRubyやらが混合した感じのsyntax
成果物
サンプルコード
func: fibo(n) { if (n < 0) { return: 0; } elsif (n == 0 || n == 1) { return: 1; } else { return: fibo(n-1) + fibo(n-2); } } func: main() { let: n; n = __geti(); __puti(fibo(n)); __putc('\n'); }
func: swap(p, q) { let: t; t = *p; *p = *q; *q = t; } func: qsort(begin, end) { if (end - begin <= 1) { return; } let: pv(begin), it(begin + 1); while (it < end) { if (*pv > *it) { swap(pv + 1, it); swap(pv, pv + 1); pv += 1; } it += 1; } qsort(begin, pv); qsort(pv+1, end); } func: main() { let: arr[9](3,1,4,1,5,9,2,6,5); qsort(&arr, &arr+9); let: i(0); while (i < 9) { __puti(arr[i]); __putc(' '); i += 1; } }
実績
yukicoderで戦えるかも!?
- #284948 No.646 逆ピラミッド - yukicoder
- #287176 No.677 10^Nの約数 - yukicoder
- haskellインタプリタが遅すぎるので #287179 No.677 10^Nの約数 - yukicoder
現状の大きな問題点
- コンパイルエラーが極めて雑
- テストが雑
コンパイラ
ここにあります
分割コンパイルしなくて良いやろと思ってたら2000行超えてしまった
なぜ辞めるか
進捗
どの手順で実装したかメモしていたので,順に列挙します.
progress 1
ソースコードの整数を出力できる.
progress 2
2つの整数の足し算が出来る*3.
progress 3
複数の整数の足し算が出来る.
progress 4
複数の整数の足し算・掛け算が出来る.
progress 5
複数の整数のadd/sub/mul/div/modが出来る.
progress 6
括弧を用いた式が書ける.
progress 7
単項演算子-
が使える.-(2+3)
が出来る.
progress 8
変数 abc
が使える.宣言不要. abc=5;abc+2;
が出来る.
progress 9
常に999
を返す組み込み関数 __xyz()
が使える.
progress 10
複数の変数が使える.宣言不要. a=2;b=a+3;c=a*b;c*5;
が出来る.
progress 11
組み込み関数 __puti(x)
__putc(x)
が使える.
progress 12
ユーザ定義関数が使える.main
関数を定義しなければならない.
変数は常にglobalになる.return
は実装されない.
func:f(){__puti(20);};func:main(){f();};
is valid.
progress 13
変数を使うときは必ず宣言しなければならない.
関数内部で有効なローカル変数,全体で有効なグローバル変数が使える.
progress 14
if
と while
が使える.
直前のprogress 13 のローカル変数の実装で戸惑っていて,
結局 let
,func
,式 が書ける範囲に制限を設けた(撤廃したかったけれど).
progress 15
else
, elsif
.
progress 16
__geti()
.
progress 17
operation <
, ==
.
progress 18
operation !=
, <=
, >
, >=
.
progress 19
reference, dereference. &var
, *var
.
progress 20
関数引数. func:foo(a1,a2,a3){}
.
progress 21
返り値. return:0;
.
progress 22
コメントアウト # comment
progress 23
文字リテラル.escape \n
(LF), \t
(TAB), \s
(SPACE), \'
, \\
.
__getc()
, __getiv(ptr)
, __getcv(ptr)
progress 24
配列実装.let:x[5];
.
progress 25
まとめて let
出来るようにした
let:a,b,c[3];
progress 26
operation !
, &&
, ||
progress 27
let時の初期化 let:a(1);
let:x[5](1,2,3,4,5);
as array. let:dp[5](0);
.
progress 28
operator +=
,-=
,*=
,/=
,%=
*1:https://note.mu/ruiu/n/n00ebc977fd60
*2:スペース,タブ,改行を一切入れなくても成立するsyntaxなのでwhitespaceと共存出来る
*3:引き算の方が演算順序が確認出来て良かったと後悔