summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMatthew Hall <hallmatthew314@gmail.com>2022-09-02 22:06:13 +1200
committerMatthew Hall <hallmatthew314@gmail.com>2022-09-02 22:06:13 +1200
commit146f12187abbe8ba18df8f1d417a44cfe557b794 (patch)
treebc2e48f1b43e47add843da55f2d7f121b57a38f1 /src
parent4dd4e596ae6e5da84f2ce4296cbf9c030efe69bb (diff)
Able to interpret brainfuck
Diffstat (limited to 'src')
-rw-r--r--src/brainfuck/brainfuck.cr3
-rw-r--r--src/brainfuck/program.cr75
-rw-r--r--src/flint.cr9
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