shonen.hateblo.jp

やったこと,しらべたことを書く.

whitespaceを出力するコンパイラのようなものを作った

この記事は何ですか

日記です

興味を持った

コンパイラを作る講習会があったらしく*1, 興味を持ったので自分でもコンパイラを書いてみた.

どんなコンパイラ

成果物

サンプルコード

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で戦えるかも!?

現状の大きな問題点

コンパイラ

github.com

ここにあります

分割コンパイルしなくて良いやろと思ってたら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

ifwhile が使える.

直前のprogress 13 のローカル変数の実装で戸惑っていて, 結局 letfunc,式 が書ける範囲に制限を設けた(撤廃したかったけれど).

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:引き算の方が演算順序が確認出来て良かったと後悔