二次元言語(Befunge, Fish, Rail, Hexagony,Piet 等)はesolangだが書きにくいわけではない。 コードがn次元ならより書きづらい言語になるのでは? HyperTorusは、コードがn次元トーラスでできている言語です。
python3 interpreter.py sourcecode
- -n [number] 実行の number ステップ毎に内部状態をダンプする
- -b [str]
str の d 文字目が
#
なら、プログラムの座標 d を実行するたびに内部状態をダンプする (-n と -b を同時に指定することもできます)
プログラムは1行で入力される。 たとえば、
abcdefgh
というプログラムは、
g------h
/| /|
/ | / |
e--+---f |
| c---+--d
| / | /
|/ |/
a------b
という3次元トーラス上に配置される。
一般的に、長さ 2^n 以上 2^(n+1) 未満 のプログラムはn次元トーラスを表現する。
以降ではプログラムの各座標を2進数で表現する。たとえば座標(0,0,0) は2進数000、 座標 (0,1,1) は二進数 110 といった具合である。leading zero は適宜省略する。
座標 k にはプログラムの k 文字目が入る。
命令ポインタが1つ、いずれかの座標上に、座標軸と並行な向きを向いて存在している。 実行の1ステップごとに、命令ポインタは現在の座標にある命令を実行し、その後今向いている方向に移動する。
命令ポインタの状態は、命令ポインタの座標と向きによって表現される。 たとえば上の図において、(010,+4) は b に存在して f のほうを向いている命令ポインタの状態を表現している。
初期状態では、メモリポインタの状態は (0,+1) である。
例えば上の例だと、初期状態から命令が a b a b a b ... と実行される。
メモリは、大きさ2^Z(このZは整数の集合)のトーラスでできており、各辺上に(多倍長)整数値を保存する。(発想元はhexagonyのメモリですね)
実際にプログラミングする際に箱性が使われないかんじなので、(befunge,fish,pietなどで)一般的なスタックにします。うまい仕様が思いついたらHyperHyperTorusとかしてみたいですね...
以降、スタックをpopしてその値を返す手続きをpop()、 値xをスタックの先頭に積む手続きをpush(x)と略記する。
char | operation |
---|---|
| | 命令ポインタの向き、つまり向きの符号を反転させる。 |
< | 命令ポインタの向きを左に向ける(たとえばプログラムが4次元トーラスの場合、向きは +1→+2→+4→+8→+1 もしくは -1→-8→-4→-2→-1 と変化する) |
> | 命令ポインタの向きを右に向ける(たとえばプログラムが4次元トーラスの場合、向きは +1→+8→+4→+2→+1 もしくは -1→-2→-4→-8→-1 と変化する) |
? | pop()が0なら < と、そうでないなら > と同じ動きをする |
j | 「pop()をプログラムサイズで割ったあまりの位置」に(命令ポインタの向きはそのままで)ジャンプする |
. | 何もしない(NOP) |
q | プログラムの実行を終了ずる |
char | operation |
---|---|
$ | スタックトップ2つの交換(a = pop(); b = pop(); push(a); push(b);) |
@ | スタックトップ3つの交換(a = pop(); b = pop(); c = pop(); push(a); push(c); push(b);) |
: | スタックトップの複製(a = pop(); push(a); push(a);) |
~ | スタックトップの破棄(pop()) |
} | スタックの先頭要素を底にもっていく |
{ | スタックの底の要素を先頭にもっていく |
char | operation |
---|---|
g | push(「pop()をプログラムサイズで割ったあまりの位置」にあるプログラムのアスキーコード値) |
p | x = pop(); v = pop(); した後、「xをプログラムサイズで割ったあまりの位置」のプログラムの文字を 「vを256で割った値」にする |
char | operation |
---|---|
[0-9a-f] | push(文字の表現する16進の値) |
& | スタックトップをレジスタに出し入れする。&の実行ごとに、命令の意味が「レジスタの値をpop()にする」<->「push(レジスタの値)」 となる。 |
二項演算は、 演算をop として、
r = pop()
l = pop()
push(l op r)
が実行される。
char | operation |
---|---|
+ | 加算 |
- | 減算 |
* | 乗算 |
/ | 整数除算 (0割りはエラー) |
% | 剰余 (0割りはエラー) |
= | l=rなら1,そうでないなら0 |
( | l<rなら1,そうでないなら0 |
) | l>rなら1,そうでないなら0 |
char | operation |
---|---|
r | push(読み込んだ文字のアスキーコード値(EOFなら-1)) |
w | pop()を256で割ったあまりの文字を出力する |
i | push((区切り文字まで)読み込んだ十進数値) |
o | pop()を十進数で出力する |
0<wr.:>j1<.<q+?>
これは、以下のような4次元超立方体状のプログラムを表現している
>------j ?------>
/| /| /| /|
/ | / | / | / |
.--+---: | q--+---+ |
| w---+--r | .---+--<
| / | / | / | /
|/ |/ |/ |/
0------< 1------<
いいかんじのビジュアライザ