summaryrefslogtreecommitdiff
path: root/src/brainfuck/program.cr
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