いきおいでb言語の勉強してみた

普段c言語でプログラミングしてるけどそもそもなんでcなのって人多いはず。そこで古い文献から歴史を紐解く歴史学者の気持ちになってb言語の勉強してみました。

# 参考資料
参考資料は検索しても見つからなくwikipediaからたどれるものを参考にしてみました。
[B言語](https://ja.wikipedia.org/wiki/B%E8%A8%80%E8%AA%9E)
[Users' Reference to B](https://web.archive.org/web/20150611114427/https://www.bell-labs.com/usr/dmr/www/kbman.pdf)
あたり

# なぜb?
もともとBCPLって言語を簡略したものらしいです。だから頭文字取ってb(予想)。
そしてその次に生まれたのが有名なプログラミング言語cです。

# c言語との違い

## 型
型が一つしかないみたいです。もちろんポインタも整数型と同じ扱いみたい。よく苦手意識持たれるポインタも整数型ならとっつきやすいですね。

## 文字列
c言語では\\nと書くところを\*nと書きます。慣れなのか\\nの方がしっくりきますね。あの時代は\*nがしっくり来る感覚があったのかな。

## putchar
putchar関数で一文字出力する時は今と変わらないですが8bitより大きい数字の場合は複数文字とみなされるみたいです。例えば比較するとこんな感じです。

```b言語
putchar('*n*n');
```
```c言語
putchar('¥n');
putchar('¥n');
```
これは基本となる型がCPUのメモリアクセスに必要なbit数持っているので

## 代入演算子
おなじみの`+=`や`-=`な演算子は逆になってます。`=+`や`=-`と書きます。これだと`i=-1`と書いた時に`i = i - 1`なのか`i = -1`なのかが判断しにくくなるためc言語では逆にしたみたいです。

## for文がない
BCPLやc言語にはあるのですがb言語には無さそうです(ほんとかな？)。

## 関数の型チェック
関数の引数の数はチェックしていないです(型は一種類だけなのでそもそも型チェックはない)。printfの実装がサンプルで載っているマニュアルなど見ているとこんな感じで宣言して使わない引数は無視するような使い方しています。

```printf.b
printf(fmt,x1,x2,x3,x4,x5,x6,x7,x8,x9) {
```

# 書いてみる

## みんな大好きハローワールド
```hello.b
main() {
    printf("hello, world*n");
}
```
```実行結果
[ec2-user@ip-172-31-43-112 blang]$ ./a.out
hello, world
```

## もっと大好きクイックソート(少し適当だけど)
```qsort.b
list[10]
    "a programing language",
    "b language",
    "BASIC",
    "BCPL",
    "c language",
    "COBOL",
    "FORTRAN",
    "java",
    "LISP",
    "pascal";
tm[2];

display() {
    auto i;

    i = 0;
    while ( i < 10 ) printf("%d: %s*n",i,list[i++]);
    printf("----*n");
}

/* 適当 */
seed 123;
rand() {
    seed = 7*seed+3;
    seed =* (seed>=0) ? 1 : -1;
    return(seed%10);
}

swap(a,b) {
    auto tmp;

    tmp = list[a];
    list[a] = list[b];
    list[b] =tmp;
}

shuffle() {
    auto i;

    time(tm);
    seed = tm[0];

    i = 0;
    while ( ++i < 100 ) swap(rand(),rand());
}

compare(a,b) {
    auto r;

    r = 0;
    if ( list[a] < list[b] ) r = -1;
    if ( list[a] > list[b] ) r = 1;
    return(r);
}

qsort(start,end) {
    auto pivot,i,j;

    if ( start == end ) return;
    if ( start+1 == end ) {
        if ( compare(start,end) <= 0 ) swap(start,end);
        return;
    }

    pivot = i = start;
    j = end;
    while ( i < j ) {
        while ( (i<j) & (compare(pivot,i)<=0) ) i++;
        while ( (i<j) & (compare(pivot,j)>0 ) ) j--;

        if ( (j<=end) & (i<j) ) swap(i++,j);
    }

    if ( j==start ) { /* 全てがpivotより大きい */
        qsort(start+1,end);
        return;
    }
    if ( i==end ) { /* 全てがpivotより小さい */
        if ( compare(start,end) <= 0 ) swap(start,end);
        qsort(start,end-1);
        return;
    }

    qsort(pivot,i-1);
    qsort(j,end);
}

main() {
    display();

    shuffle();
    display();

    qsort(0,9);
    display();
}
```
```実行結果
[ec2-user@ip-172-31-43-112 blang]$ ./a.out
0: a programing language
1: b language
2: BASIC
3: BCPL
4: c language
5: COBOL
6: FORTRAN
7: java
8: LISP
9: pascal
----
0: java
1: b language
2: BASIC
3: LISP
4: a programing language
5: BCPL
6: COBOL
7: FORTRAN
8: pascal
9: c language
----
0: a programing language
1: b language
2: BASIC
3: BCPL
4: c language
5: COBOL
6: FORTRAN
7: java
8: LISP
9: pascal
----
```

# コンパイラ
探してみてもb言語のコンパイラ見つからず作ってみました。llvmの使い方がまだあまりわかっていなくたまにコンパイルに失敗することありますが(^ ^;
[blang](https://github.com/yujnishi/blang)

動作はamazon linuxで試しました。コンパイルにはflex、bisonが必要。動かすにはllvmが必要です。llvm用のソースコードにコンバートしているだけなのでこれらをインストールできるunix系OSならどこでも実行できるはずです。
詳しくはREADME.mdを見てください。

そのほかtestsディレクトリの下にコンパイルしてうまく動いているソースコードがいろいろ入っているのでそちらも漁ってみてください。