diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/brainfuck/brainfuck.cr | 3 | ||||
| -rw-r--r-- | src/brainfuck/program.cr | 75 | ||||
| -rw-r--r-- | src/flint.cr | 9 |
3 files changed, 83 insertions, 4 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 diff --git a/src/flint.cr b/src/flint.cr index 1c67cc9..f2323a2 100644 --- a/src/flint.cr +++ b/src/flint.cr @@ -24,7 +24,9 @@ module Flint memory_size = Brainfuck::DEFAULT_TAPE_SIZE parser.banner = "Useage: flint brainfuck [OPTIONS] [FILE]" - parser.on("-t CELLS", "--tape-size=CELLS", "specify the number of memory cells in the tape, defaults to 30,000") { nil } + parser.on("-t CELLS", "--tape-size=CELLS", "specify the number of memory cells in the tape, defaults to 30,000") do |_cells| + memory_size = _cells.to_i + end end parser.on("-h", "--help", "show this help and exit") do @@ -67,7 +69,7 @@ module Flint if chosen_language == :brainfuck bf_parser = Brainfuck::Parser.new(source_io) - program = Brainfuck::Program.new(bf_parser) + program = Brainfuck::Program.new(bf_parser, memory_size) end begin @@ -76,6 +78,9 @@ module Flint puts "Caught ParserError" puts ex.message exit(1) + rescue ex : Brainfuck::MemoryError + puts "Caught MemoryError" + puts ex.message end end end |
