Існує багато формалізмів, тому, хоча ви можете знайти інші джерела корисними, я сподіваюся, що це досить чітко вказати, що вони не потрібні.
RM складається з машини кінцевих станів і кінцевої кількості іменованих регістрів, кожен з яких містить невід'ємне ціле число. Для зручності введення тексту це завдання вимагає, щоб штати також були названі.
Існує три типи стану: приріст і декремент, які обоє посилаються на певний реєстр; і припинити. Приріст держави збільшує свій регістр і передає контроль своєму наступнику. Стан декременту має двох наступників: якщо його регістр не дорівнює нулю, він зменшує його і передає контроль першому наступнику; в іншому випадку (тобто регістр дорівнює нулю), він просто передає контроль другому наступнику.
Для "приємності" як мови програмування, термінали завершення беруть для друку жорстко закодований рядок (так що ви можете вказати на виняткове припинення).
Введення з stdin. Формат введення складається з одного рядка за станом, а потім початкового вмісту регістра. Перший рядок - початковий стан. BNF для державних ліній:
line ::= inc_line
| dec_line
inc_line ::= label ' : ' reg_name ' + ' state_name
dec_line ::= label ' : ' reg_name ' - ' state_name ' ' state_name
state_name ::= label
| '"' message '"'
label ::= identifier
reg_name ::= identifier
Існує деяка гнучкість у визначенні ідентифікатора та повідомлення. Ваша програма повинна прийняти не порожню буквено-цифрову рядок як ідентифікатор, але вона може прийняти більш загальні рядки, якщо вам зручніше (наприклад, якщо ваша мова підтримує ідентифікатори з підкресленнями, і вам це легше працювати). Аналогічно, для повідомлення ви повинні прийняти не порожній рядок з буквено-цифрових знаків і пробілів, але ви можете прийняти більш складні рядки, які дозволяють уникнути нових рядків і символів з подвійним цитуванням, якщо ви хочете.
Заключний рядок введення, який дає початкові значення регістру, - це розділений пробілом список призначень id-id = int, який повинен бути не порожнім. Не потрібно, щоб вона ініціалізувала всі регістри, названі в програмі: будь-який, який не ініціалізований, вважається рівним 0.
Ваша програма повинна прочитати вхід і імітувати RM. Коли він досягає стану завершення, він повинен випромінювати повідомлення, новий рядок, а потім значення всіх регістрів (у будь-якому зручному для людини читанні форматі та будь-якому порядку).
Примітка: формально регістри повинні містити цілі числа без обмежень. Однак ви можете припустити, що значення жодного регістру ніколи не перевищуватиме 2 ^ 30.
Кілька простих прикладів
a + = b, a = 0s0 : a - s1 "Ok"
s1 : b + s0
a=3 b=4
Очікувані результати:
Ok
a=0 b=7
b + = a, t = 0
init : t - init d0
d0 : a - d1 a0
d1 : b + d2
d2 : t + d0
a0 : t - a1 "Ok"
a1 : a + a0
a=3 b=4
Очікувані результати:
Ok
a=3 b=7 t=0
Тестові приклади для машин, що складніше розбираються
s0 : t - s0 s1
s1 : t + "t is 1"
t=17
Очікувані результати:
t is 1
t=1
і
s0 : t - "t is nonzero" "t is zero"
t=1
Очікувані результати:
t is nonzero
t=0
Складніший приклад
Взяте з проблеми проблематичного коду Josephus у DailyWTF. Вхід - n (кількість солдатів) і k (заздалегідь), а вихід у r - (нульове індексування) положення людини, яка виживає.
init0 : k - init1 init3
init1 : r + init2
init2 : t + init0
init3 : t - init4 init5
init4 : k + init3
init5 : r - init6 "ERROR k is 0"
init6 : i + init7
init7 : n - loop0 "ERROR n is 0"
loop0 : n - loop1 "Ok"
loop1 : i + loop2
loop2 : k - loop3 loop5
loop3 : r + loop4
loop4 : t + loop2
loop5 : t - loop6 loop7
loop6 : k + loop5
loop7 : i - loop8 loopa
loop8 : r - loop9 loopc
loop9 : t + loop7
loopa : t - loopb loop7
loopb : i + loopa
loopc : t - loopd loopf
loopd : i + loope
loope : r + loopc
loopf : i + loop0
n=40 k=3
Очікувані результати:
Ok
i=40 k=3 n=0 r=27 t=0
Ця програма як зображення, для тих, хто мислить візуально і вважає корисним зрозуміти синтаксис:
Якщо вам сподобався цей гольф, подивіться на продовження .