179 lines
6.7 KiB
Markdown
179 lines
6.7 KiB
Markdown
---
|
||
id: 5a23c84252665b21eecc8038
|
||
title: Subleq
|
||
challengeType: 5
|
||
forumTopicId: 302328
|
||
dashedName: subleq
|
||
---
|
||
|
||
# --description--
|
||
|
||
[Subleq](https://rosettacode.org/wiki/eso:Subleq) — приклад a [One-Instruction Set Computer (OISC) (Комп'ютер із набором однієї інструкції)](https://en.wikipedia.org/wiki/One_instruction_set_computer).
|
||
|
||
Назва пішла від перших літер інструкції: **SU**btract і **B**ranch if **L**ess than or **EQ**ual to zero (відняти й перейти, якщо результат менший або рівний нулю).
|
||
|
||
Ваше завдання — створити дешифрувальник, який змоделює принцип дії такої машини.
|
||
|
||
Пам'ять машини складається з масиву цілих чисел зі знаком. Підійде будь-який допустимий розмір слова, але пам'ять повинна підтримувати від'ємні та додатні числа.
|
||
|
||
Виконання починається з лічильника команд, спрямованого на перше слово, яке є адресою 0. Це відбувається наступним чином:
|
||
|
||
<ol>
|
||
<li>Нехай А, В та С будуть значеннями, що зберігаються в трьох послідовних словах у пам'яті, починаючи з лічильника команд.</li>
|
||
<li>Розширте лічильник команд, розташувавши курсор у адресному рядку після компонента, що містить значення C.</li>
|
||
<li>Якщо A = -1, тоді символ зчитується зі стандартного вводу та його кодова точка, що зберігається в адресі, зазначеному у B. C не використовується.</li>
|
||
<li>Якщо B — -1, тоді число, що міститься в адресі, вказаній А, інтерпретується як кодова точка та відповідний символ виходу. C знову не використовується.</li>
|
||
<li>В іншому випадку і A, і B розглядаються як адреси комірок пам'яті. Число, що знаходиться в адресі, що вказана A, віднімається від числа в адресі, вказаній B (а результат зберігається назад в адрес B). Якщо результат дорівнює нулю або від'ємний, значення C стає новим лічильником команд.</li>
|
||
<li>Якщо лічильник команд стає від'ємним — виконання припиняється.</li>
|
||
</ol>
|
||
|
||
Інші негативні адреси, окрім -1, можна вважати еквівалентом -1 або згенерувати помилку — робіть так, як вважаєте за потрібне.
|
||
|
||
Ваше рішення повинно показати, чи надаєте Ви дозвіл програмі виконати дану операцію в комп'ютері незалежно від вхідного потоку самої програми.
|
||
|
||
Ця програма має бути в сирому "машинному коді" subleq — десяткові числа, розділені пробілом з символьним ім'ям чи інші розширення рівня асемблера, які завантажаться у пам'ять, починаючи з адреси 0. Покажіть вивід свого рішення, коли запустите цю програму "Hello, world!". (Зверніть увагу, що цей приклад припускає використання ASCII або його надмножину, таку як будь-який сет символів чи Unicode. Ви можете перекласти його на іншу кодову систему, якщо ваше виконання засноване на середовищі, не сумісному з ASCIL.)
|
||
|
||
<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;
|
||
}
|
||
```
|