shonen.hateblo.jp

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

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を超える値も利用できる.

コード

整数の表現

0S1T,終端をLとする2進数で表現する.

公式実装では,先頭に符号ビットを置き,以降に符号を抜いた非負整数を記述する.2の補数表現では無いので注意

例えば,6 は,正の数なので符号ビットは S6の2進数表現は100なので,STTSL と表現する.

また,-6 は,負の数なので符号ビットは T6の2進数表現は100なので,TTTSL と表現する.

SL0TL0になる*1L は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の予感がするけれども,負の値ではないらしい