blob: 5b569df405df6012bcc7ee1370d16a489449a7e3 (
plain)
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
79
80
81
82
83
84
85
|
require "./parser.cr"
class Brainfuck::Program
@mem_size : Int32
def initialize(@parser : Parser, mem_size : Int32?)
@mem_size = mem_size || DEFAULT_TAPE_SIZE
end
def interpret
code = @parser.parse
jumps = find_jumps(code)
code_ptr = 0
memory = [0_u8] * @mem_size
mem_ptr = 0
while code_ptr < code.size
case code[code_ptr]
when Opcode::PtrRight
mem_ptr += 1
when Opcode::PtrLeft
mem_ptr -= 1
when Opcode::Inc
begin
memory[mem_ptr] += 1_u8
rescue OverflowError
memory[mem_ptr] = 0_u8
end
when Opcode::Dec
begin
memory[mem_ptr] -= 1_u8
rescue OverflowError
memory[mem_ptr] = 0_u8
end
when Opcode::Out
print memory[mem_ptr].chr
when Opcode::In
c = STDIN.read_char
memory[mem_ptr] = c.nil? ? 0_u8 : c.ord.to_u8
when Opcode::LoopStart
code_ptr = jumps[code_ptr] if memory[mem_ptr] == 0_u8
when Opcode::LoopEnd
code_ptr = jumps[code_ptr] unless memory[mem_ptr] == 0_u8
end
raise MemoryError.new("Too far left") if mem_ptr < 0
raise MemoryError.new("Too far right") if mem_ptr >= memory.size
code_ptr += 1
end
end
def compile
raise Util::NoCompilerAvailableError.new("No available compiler for brainfuck")
end
# assumes valid code
private def find_jumps(code : Array(Opcode)) : Hash(Int32, Int32)
jumps = Hash(Int32, Int32).new
stack = [] of Int32
code.each_index do |i|
if code[i] == Opcode::LoopStart
stack.push(i)
end
if code[i] == Opcode::LoopEnd
jumps[i] = stack.pop
jumps[jumps[i]] = i
end
end
return jumps
end
end
|