whitespace(esolang) メモのまとめ
2018/08/10 ヒープ操作追記
2018/09/06 負整数について追記
whitespaceとは
- esolang
- スタックベース
参考URL
- [https:;hackage.haskell.org/package/whitespace-0.4/src/docs/tutorial.html]
- 以下,「本家」と呼ぶものはwspace 0.3 (ideoneで試せるもの)とする.
以降の表記
空白は見にくいので,次のように表記する
- 半角スペース
S
- タブ
T
- LF改行
L
読みやすさのために,スペースやアンダーバーを入れることがある.
whitespace 0.3と0.4の違い
- shuffleが実装されている
- スタックをランダムに並び替える
S_TTS
命令がある
- スタックをランダムに並び替える
構成
- スタック(ユーザが自由にアクセス出来る.演算に利用)
- ヒープ(ユーザが自由にアクセス出来る.ランダムアクセスメモリ.)
- 標準入出力(char, intに対応.)
その他,プログラムカウンタ,プログラム,サブルーチンスタック.
本家では,多倍長整数として扱われる.264を超える値も利用できる.
コード
整数の表現
0
をS
,1
をT
,終端をL
とする2進数で表現する.
公式実装では,先頭に符号ビットを置き,以降に符号を抜いた非負整数を記述する.2の補数表現では無いので注意.
例えば,6
は,正の数なので符号ビットは S
,6
の2進数表現は100
なので,STTSL
と表現する.
また,-6
は,負の数なので符号ビットは T
,6
の2進数表現は100
なので,TTTSL
と表現する.
SL
は 0
,TL
は 0
になる*1.L
はruntime error.
S_S STTL ; stack_push 3 TL_ST ; print_int LLL ; exit
スタック操作
S
から始まる命令はスタック操作.
S_S SSSL ; stack_push 0 S_S TTTL ; stack_push -1 S_LS ; stack_duplicate TL_ST ; print_int => expected: -1 S_LT ; stack_swap TL_ST ; print_int => expected: 0 S_S STTL ; stack_push 3 S_LL ; stack_remove TL_ST ; print_int => expected: -1 LLL ; exit
算術演算
TS
から始まる命令は算術演算.
S_S STL ; stack_push 1 S_S STSL ; stack_push 2 TS_SS ; add TL_ST ; printint => expected: 3 S_S STSL ; stack_push 2 S_S STL ; stack_push 1 TS_ST ; sub TL_ST ; printint => expected: 1 S_S STSL ; stack_push 2 S_S STTL ; stack_push 3 TS_SL ; mul TL_ST ; printint => expected: 6 S_S STTTL ; stack_push 7 S_S STSL ; stack_push 2 TS_TS ; div TL_ST ; printint => expected: 3 S_S STTTL ; stack_push 7 S_S STSL ; stack_push 2 TS_TT ; mod TL_ST ; printint => expected: 1 LLL ; exit
ヒープ操作
TT
から始まる命令はヒープ操作.
storeはTTS
.アドレス,値の順にスタックにpushしてから呼び出す.
retrieveはTTT
.アドレスをpushしてから呼び出すと,スタックにそのアドレスに格納された値が積まれる.書き込んだことがないアドレスを読み出すとruntime error.
本家実装では,負の値を指定したり,非常に大きな値を指定したりするとruntime error.
S_S SSSTL ; stack_push 1 S_S STTTL ; stack_push 7 TT_S ; heap_store S_S SSTSL ; stack_push 2 S_S SSSTL ; stack_push 1 TT_S ; heap_store S_S SSTSL ; stack_push 2 TT_T ; heap_retrieve TT_T ; heap_retrieve TL_ST ; print_int => expected: 7 LLL ; exit
標準出力
TL
から始まる命令は標準入出力命令.スタックの値を出力する.
S_S TTL ; stack_push -1 TL_ST ; print_int => expected: -1 S_S SSSSTSTSL ; stackpush 10 TL_SS ; printchar => expected: lf LLL ; exit
標準入力
TL
から始まる命令は標準入出力命令.
スタックの先頭の値をヒープのアドレスとして読み込んで,そのヒープの場所に入力値を読み込む.
公式実装では,整数読み込みは改行区切りとなる.1行に123 456
と入力して整数読み込みしたらruntime error.
.
を含んでもダメ.しかし指数表記1e18
は読み込める.
スペース区切りで読み込みたい場合,自前で実装する必要がありそう.
また,EOFに到達した場合もruntime error.
S_S SSSSL ; stack_push 0 TL_TT ; read_int S_S SSSTL ; stack_push 1 TL_TT ; read_int S_S SSSSL ; stack_push 0 TT_T ; heap_retrieve S_S SSSTL ; stack_push 1 TT_T ; heap_retrieve TS_ST ; subtraction TL_ST ; print_int LLL
runtime errorで停止するcat
L_SS SL ; label 0 S_S SL ; stack_push 0 TL_TS ; read_char S_S SL ; stack_push 0 TT_T ; heap_retrieve TL_SS ; print_char L_SL SL ; goto 0
フロー制御
L
から始まる命令はフロー制御.終了命令 LLL
もフロー制御.
コード中にSS
命令でラベルを設定出来る.ラベルの名前は整数で.
gotoLSL
等の命令でラベルにジャンプ出来る.
goto
次のコードは,forループのようなもの.
S_S STSSL ; stack_push 4 L_SS SSSSL ; label 0 S_LS ; stack_dup TL_ST ; print_int => expected: 4,3,2,1 S_S STL ; stack_push 1 TS_ST ; sub S_LS ; stackdup L_TS SSSTL ; if top == 0: goto 1 L_SL SSSSL ; goto 0 L_SS SSSTL ; label 1 S_LL ; stack_remove LLL ; exit
比較命令その2
S_S STSSL ; stack_push 4 L_SS SSSSL ; label 0 S_LS ; stack_dup TL_ST ; print_int => expected: 4,3,2,1,0 S_S STL ; stack_push 1 TS_ST ; sub S_LS ; stackdup L_TT SSSTL ; if top < 0: goto 1 L_SL SSSSL ; goto 0 L_SS SSSTL ; label 1 S_LL ; stack_remove LLL ; exit
subroutine
サブルーチンも書ける.
S_S SSSSSSSTL ; push 1 L_ST STSSL ; gosub 4 TL_ST ; printint => expected: 15 LLL ; exit L_SS STSSL ; label 4 S_S SSSSSSTSL ; push 2 TS_SS ; add L_ST STSTL ; gosub 5 S_S SSSSTSSSL ; push 8 TS_SS ; add L_TL ; return L_SS STSTL ; label 5 S_S SSSSSTSSL ; push 4 TS_SS ; add L_TL ; return
*1:-0の予感がするけれども,負の値ではないらしい