diff options
| author | Matthew Hall <hallmatthew314@gmail.com> | 2022-09-02 22:06:13 +1200 |
|---|---|---|
| committer | Matthew Hall <hallmatthew314@gmail.com> | 2022-09-02 22:06:13 +1200 |
| commit | 146f12187abbe8ba18df8f1d417a44cfe557b794 (patch) | |
| tree | bc2e48f1b43e47add843da55f2d7f121b57a38f1 /src/brainfuck | |
| parent | 4dd4e596ae6e5da84f2ce4296cbf9c030efe69bb (diff) | |
Able to interpret brainfuck
Diffstat (limited to 'src/brainfuck')
| -rw-r--r-- | src/brainfuck/brainfuck.cr | 3 | ||||
| -rw-r--r-- | src/brainfuck/program.cr | 75 |
2 files changed, 76 insertions, 2 deletions
diff --git a/src/brainfuck/brainfuck.cr b/src/brainfuck/brainfuck.cr index b75ad1c..819fe8e 100644 --- a/src/brainfuck/brainfuck.cr +++ b/src/brainfuck/brainfuck.cr @@ -3,6 +3,9 @@ require "./*" module Brainfuck DEFAULT_TAPE_SIZE = 30_000 + class MemoryError < Exception + end + enum Opcode PtrRight PtrLeft diff --git a/src/brainfuck/program.cr b/src/brainfuck/program.cr index cf4a097..5994d40 100644 --- a/src/brainfuck/program.cr +++ b/src/brainfuck/program.cr @@ -1,14 +1,85 @@ require "./parser.cr" class Brainfuck::Program - def initialize(@parser : Brainfuck::Parser) + @mem_size : Int32 + + def initialize(@parser : Parser, mem_size : Int32?) + @mem_size = mem_size || DEFAULT_TAPE_SIZE end def interpret - puts @parser.parse + 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 NotImplementedError.new + 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 |
