Интерпретатор Malbolge на Ruby

5 Янв
2012

Еще не утихла на Блоге волна радости и восторга от «Новогоднего Квеста» от Nicolette.
Для многих немало времени потребовало последнее задание на тему эзотерического и буквально адского языка Malbolge (ru.wikipedia.org, esolang.org).
Не найдя на просторах интернета рабочего интерпретатора (может плохо искал), решил написать свой, на любимом Ruby.


Кратко как работает Malbolge:
1) загружает код программы в память
2) определяет код одной из восьми команд по значению в текущей ячейке памяти
3) выполняет команду
4) команда шифруется, записывается в память и т.д. до выхода

При этом есть три регистра, операция crazy (аналог битовой операции для троичной системы) и операция сдвига, множество мелких нюансов. Кроме того, Malbolge работает с числами длины 10 в троичной системе счисления. Таким образом Бен Олмстед постарался реализовать самый сложный язык программирования.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# coding: utf-8
 
# операция crazy с 10-значными троичными числами
def crazy(x, y)
  x = x.to_s(3).rjust(10, '0')
  y = y.to_s(3).rjust(10, '0')
  z = '0'*10
  10.times { |i| z[i] = [[1, 0, 0], [1, 0, 2], [2, 2, 1]].at(y[i].to_i).at(x[i].to_i).to_s }
  z.to_i(3)
end
 
# операция сдвига
def rotr(x)
  x.to_s(3).rjust(10, '0').insert(0, x[-1])[0, 10].to_i(3)
end
 
# область памяти
mem = Array.new(59049, 0)
i = 0
 
# загрузка кода программы из файла
File.open(ARGV.last) do |f|
 
  # пробелы, табуляцию и проч. игнорируем
  f.read.gsub(/\s*/, '').each_byte do |x| 
 
    # загружаемый символ после раскодирования должен быть одной из команд
    if [4, 5, 23, 39, 40, 62, 68, 81].include?((x+i) % 94) 
      mem[i] = x
      i += 1 
    end
  end
end
 
#заполняем оставшуюся память по правилу
i.upto(59048) { |j| mem[j] = crazy(mem[j - 1], mem[j - 2]) }
 
# регистры
a, c, d = 0, 0, 0
 
# строка перевода для шифрования
crypt = '9m<.TVac`uY*MK\'X~xDl}REokN:#?G"i@5z]&gqtyfr$(we4{WP)H-Zn,[%\3dL+Q;>U!pJS72FhOA1CB6v^=I_0/8|jsb'
 
# поехали
loop do
 
  case (mem[c] + c) % 94
 
    when 4
      c = mem[d]
 
    when 5
      print (a % 256).chr
 
    when 25
      a = getc
 
    when 39
      a = mem[d] = rotr(mem[d])
 
    when 40
      d = mem[d]
 
    when 62
      a = mem[d] = crazy(a, mem[d])
 
    when 81
      break
 
  end
 
  # шифруемся
  mem[c] = crypt[mem[c] % 94].ord
 
  # инкремент регистров и идем дальше
  c = (c+1) % 59049
  d = (d+1) % 59049
end


P.S.

Возможно кому-то будет интересно повторить подвиг Anthony Youhas и Tomasz Wegrzanowski, написав генератор программ на Malbolge, хотя бы просто выводящих заданный текст.
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх