179 lines
5.2 KiB
Markdown
179 lines
5.2 KiB
Markdown
![]() |
---
|
||
|
id: 5a23c84252665b21eecc8038
|
||
|
title: Subleq
|
||
|
challengeType: 5
|
||
|
forumTopicId: 302328
|
||
|
dashedName: subleq
|
||
|
---
|
||
|
|
||
|
# --description--
|
||
|
|
||
|
[Subleq](https://rosettacode.org/wiki/eso:Subleq) は [One-Instruction Set Computer (OISC)](https://en.wikipedia.org/wiki/One_instruction_set_computer) の 1 つの例です。
|
||
|
|
||
|
この名前は、**SU**btract and **B**ranch if **L**ess than or **EQ**ual to zero というこのコンピュータの唯一の命令から取られています。
|
||
|
|
||
|
タスクは、このようなマシンをエミュレートするインタプリタを作成することです。
|
||
|
|
||
|
マシンのメモリは、符号付き整数の配列で構成されています。 妥当な単語サイズであれば問題ありませんが、メモリは正の数だけでなく負の数も保持できる必要があります。
|
||
|
|
||
|
アドレス 0 である最初の単語を指す命令ポインタから実行が始まります。 次のように進みます。
|
||
|
|
||
|
<ol>
|
||
|
<li>A、B、C は命令ポインタから始まる 3 つの連続した単語に格納される値とします。</li>
|
||
|
<li>命令ポインタを 3 単語進め、C を含むものの後のアドレスを指します。</li>
|
||
|
<li>A が -1 の場合、標準入力から文字が読み込まれ、そのコードポイントは B が指定するアドレスに格納されます。C は使用されません。</li>
|
||
|
<li>B が -1 の場合、A が指定するアドレスに含まれる数値はコードポイントとして解釈され、対応する文字が出力されます。 Cは今度も使用されません。</li>
|
||
|
<li>それ以外の場合、A と B の両方がメモリ位置のアドレスとして扱われます。 A が指定するアドレスに格納されている数が、B が指定するアドレスの数から引かれます。 (そして、その結果がアドレス B に戻されます) 。 結果がゼロまたは負の場合、値 C が新しい命令ポインタになります。</li>
|
||
|
<li>この命令ポインタが負になると、実行は停止します。</li>
|
||
|
</ol>
|
||
|
|
||
|
-1 以外の負のアドレスを -1 と同等のものとして扱うか、エラーを生成するかは任意とします。
|
||
|
|
||
|
解答では、マシン上で実行するプログラムは、プログラム自体への入力とは別に取り込む必要があります。
|
||
|
|
||
|
このプログラムは、生の subleq "機械語" である必要があります。つまり、 空白で区切られた 10 進数で、シンボリック名やアセンブリレベルの拡張子などを含みません。アドレス 0 からメモリに読み込まれ始めます。 この「Hello, world!」プログラムを与えた場合の、解答の出力を表示してください。 (この例では Latin-N 文字セットや Unicode のような、ASCII またはその上位セットを前提としていることに注意してください。 ASCII 互換でない環境で実装している場合は、別の文字セットに変換してください)。
|
||
|
|
||
|
<pre>15 17 -1 17 -1 -1 16 1 -1 16 3 -1 15 15 0 0 -1 72 101 108 108 111 44 32 119 111 114 108 100 33 10 0</pre>
|
||
|
|
||
|
これは仮想アセンブラ言語では、以下のようになります。
|
||
|
|
||
|
<pre>start:
|
||
|
zero, message, -1
|
||
|
message, -1, -1
|
||
|
neg1, start+1, -1
|
||
|
neg1, start+3, -1
|
||
|
zero, zero, start
|
||
|
zero: 0
|
||
|
neg1: -1
|
||
|
message: "Hello, world!\n\0"
|
||
|
</pre>
|
||
|
|
||
|
# --instructions--
|
||
|
|
||
|
パラメータとして整数の配列を取る関数を記述してください。 これはメモリ要素を表します。 関数は数列を解釈し、出力文字列を返します。 このタスクでは、標準入力がないと仮定します。
|
||
|
|
||
|
# --hints--
|
||
|
|
||
|
`Subleq` は関数とします。
|
||
|
|
||
|
```js
|
||
|
assert(typeof Subleq == 'function');
|
||
|
```
|
||
|
|
||
|
`Subleq([15, 17, -1, 17, -1, -1, 16, 1, -1, 16, 3, -1, 15, 15, 0, 0, -1, 72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33, 0])` は文字列を返す必要があります。
|
||
|
|
||
|
```js
|
||
|
assert(
|
||
|
typeof Subleq([
|
||
|
15,
|
||
|
17,
|
||
|
-1,
|
||
|
17,
|
||
|
-1,
|
||
|
-1,
|
||
|
16,
|
||
|
1,
|
||
|
-1,
|
||
|
16,
|
||
|
3,
|
||
|
-1,
|
||
|
15,
|
||
|
15,
|
||
|
0,
|
||
|
0,
|
||
|
-1,
|
||
|
72,
|
||
|
101,
|
||
|
108,
|
||
|
108,
|
||
|
111,
|
||
|
44,
|
||
|
32,
|
||
|
119,
|
||
|
111,
|
||
|
114,
|
||
|
108,
|
||
|
100,
|
||
|
33,
|
||
|
0
|
||
|
]) == 'string'
|
||
|
);
|
||
|
```
|
||
|
|
||
|
`Subleq([15, 17, -1, 17, -1, -1, 16, 1, -1, 16, 3, -1, 15, 15, 0, 0, -1, 72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33, 0])` は `"Hello, world!"` を返す必要があります。
|
||
|
|
||
|
```js
|
||
|
assert.equal(
|
||
|
Subleq([
|
||
|
15,
|
||
|
17,
|
||
|
-1,
|
||
|
17,
|
||
|
-1,
|
||
|
-1,
|
||
|
16,
|
||
|
1,
|
||
|
-1,
|
||
|
16,
|
||
|
3,
|
||
|
-1,
|
||
|
15,
|
||
|
15,
|
||
|
0,
|
||
|
0,
|
||
|
-1,
|
||
|
72,
|
||
|
101,
|
||
|
108,
|
||
|
108,
|
||
|
111,
|
||
|
44,
|
||
|
32,
|
||
|
119,
|
||
|
111,
|
||
|
114,
|
||
|
108,
|
||
|
100,
|
||
|
33,
|
||
|
0
|
||
|
]),
|
||
|
'Hello, world!'
|
||
|
);
|
||
|
```
|
||
|
|
||
|
# --seed--
|
||
|
|
||
|
## --seed-contents--
|
||
|
|
||
|
```js
|
||
|
function Subleq(mem) {
|
||
|
|
||
|
}
|
||
|
```
|
||
|
|
||
|
# --solutions--
|
||
|
|
||
|
```js
|
||
|
function Subleq(mem) {
|
||
|
var out = '';
|
||
|
var instructionPointer = 0;
|
||
|
do {
|
||
|
var a = mem[instructionPointer];
|
||
|
var b = mem[instructionPointer + 1];
|
||
|
if (a === -1) {
|
||
|
} else if (b === -1) {
|
||
|
out += String.fromCharCode(mem[a]);
|
||
|
} else {
|
||
|
mem[b] -= mem[a];
|
||
|
if (mem[b] < 1) {
|
||
|
instructionPointer = mem[instructionPointer + 2];
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
instructionPointer += 3;
|
||
|
} while (instructionPointer >= 0);
|
||
|
|
||
|
return out;
|
||
|
}
|
||
|
```
|