Skip to content

Commit

Permalink
Replace FORWARD with offset in JUMP/JUMPBACK
Browse files Browse the repository at this point in the history
Compact extended bytecode and faster run_bytecode2.
  • Loading branch information
Maumagnaguagno committed Jan 19, 2024
1 parent 265e10a commit 35fc55d
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 13 deletions.
22 changes: 13 additions & 9 deletions MindFreak.rb
Original file line number Diff line number Diff line change
Expand Up @@ -128,17 +128,17 @@ def run_bytecode2(program, tape, eof = 0, input = STDIN, output = STDOUT)
else
tape[offset ? offset + @pointer : @pointer] += arg
end
when FORWARD # Pointer
@pointer += arg
when WRITE # Write
c = tape[offset ? offset + @pointer : @pointer]
arg > 1 ? output.print(c.chr * arg) : output.putc(c)
when READ # Read
input.read(arg - 1)
tape[offset ? offset + @pointer : @pointer] = input.getbyte || eof || next
when JUMP # Jump if zero
@pointer += offset if offset
program_counter = arg if tape[@pointer] == 0
when JUMPBACK # Return unless zero
@pointer += offset if offset
program_counter = arg if tape[@pointer] != 0
when MULTIPLY # Multiplication
offset = offset ? offset + @pointer : @pointer
Expand Down Expand Up @@ -166,8 +166,6 @@ def to_ruby(program, tape = TAPE_DEFAULT_SIZE, eof = 0, input = 'STDIN', output
case c
when INCREMENT # Tape
code << "#{indent}tape[#{pointer ? offset ? offset + pointer : pointer : "pointer#{"+#{offset}" if offset}"}] #{'+' unless assign}= #{arg}"
when FORWARD # Pointer
code << (pointer ? "#{indent}pointer = #{pointer += arg}" : "#{indent}pointer += #{arg}")
when WRITE # Write
c = "tape[#{pointer ? offset ? offset + pointer : pointer : "pointer#{"+#{offset}" if offset}"}]"
code << "#{indent}#{arg > 1 ? "#{output}.print #{c}.chr * #{arg}" : "#{output}.putc #{c}"}"
Expand All @@ -179,10 +177,12 @@ def to_ruby(program, tape = TAPE_DEFAULT_SIZE, eof = 0, input = 'STDIN', output
code << "#{indent}c = #{input}.getbyte and tape[#{pointer ? offset ? offset + pointer : pointer : "pointer#{"+#{offset}" if offset}"}] = c"
end
when JUMP # Jump if zero
pointer = nil
code << (pointer ? "#{indent}pointer = #{pointer += offset}" : "#{indent}pointer += #{offset}") if offset
code << "#{indent}while tape[pointer] != 0"
indent << ' '
pointer = nil
when JUMPBACK # Return unless zero
code << (pointer ? "#{indent}pointer = #{pointer += offset}" : "#{indent}pointer += #{offset}") if offset
indent.slice!(-2,2)
code << "#{indent}end"
when MULTIPLY # Multiplication
Expand Down Expand Up @@ -221,8 +221,6 @@ def to_c(program, tape = TAPE_DEFAULT_SIZE, eof = 0, type = 'unsigned int')
case c
when INCREMENT # Tape
code << "#{indent}*(pointer#{"+#{offset}" if offset}) #{'+' unless assign}= #{arg};"
when FORWARD # Pointer
code << "#{indent}pointer += #{arg};"
when WRITE # Write
c = "putchar(*(pointer#{"+#{offset}" if offset}));"
code << "#{indent}#{arg > 1 ? "for(unsigned int i = #{arg}; i--;) #{c}" : c}"
Expand All @@ -239,9 +237,11 @@ def to_c(program, tape = TAPE_DEFAULT_SIZE, eof = 0, type = 'unsigned int')
eof_variable ||= "\n int c;"
end
when JUMP # Jump if zero
code << "#{indent}pointer += #{offset};" if offset
code << "#{indent}while(*pointer){"
indent << ' '
when JUMPBACK # Return unless zero
code << "#{indent}pointer += #{offset};" if offset
indent.slice!(-2,2)
code << "#{indent}}"
when MULTIPLY # Multiplication
Expand Down Expand Up @@ -370,9 +370,9 @@ def optimize(bytecode, blank_tape = false)
# Offset >+< <.>
when FORWARD
if next_inst = bytecode[i+1]
# Original instruction uses offset
offset = bytecode[i]
if next_inst[0] < JUMP
# Original instruction uses offset
offset = bytecode[i]
(bytecode[i] = next_inst.equal?(clear) ? clear.dup : next_inst)[2] = offset[1]
# Push offset to next forward if they do not nullify
if bytecode[i+2] and bytecode[i+2][0] == FORWARD
Expand All @@ -382,6 +382,10 @@ def optimize(bytecode, blank_tape = false)
else bytecode[i+1] = offset
end
i -= 1 if next_inst[0] == MULTIPLY
else
next_inst[2] = offset[1]
bytecode.delete_at(i)
i -= 1
end
# Remove last forward
else bytecode.pop
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,12 @@ Input and output can be redirected from STDIN/STDOUT to objects that respond to
- ``optimize(bytecode, blank_tape = false)`` returns an Array with the optimized bytecodes, which can be further optimized if the tape is blank.

The basic bytecode is described by the tuple ``[instruction, argument]``, in which:
- **instruction** corresponds to the byte value of each instruction char used in BrainFuck;
- **instruction** corresponds to the byte value of <kbd>+</kbd><kbd><</kbd><kbd>.</kbd><kbd>,</kbd><kbd>[</kbd><kbd>]</kbd>;
- **argument** corresponds to the amount of times this instruction is used or the jump index in case of <kbd>[</kbd> or <kbd>]</kbd>.

The extended bytecode adds a multiply instruction, defined by <kbd>*</kbd>, and more information to each bytecode.
Note that <kbd>-</kbd> and <kbd>></kbd> are represented by their counterparts with negative arguments.

The extended bytecode replaces <kbd>></kbd> with offset, adds a multiply instruction, defined by <kbd>*</kbd>, and more information to each bytecode.
It is described by the tuple ``[instruction, argument, offset, assign, multiplier]``, in which:
- **offset** is added to the current pointer;
- **assign** a cell value when used by <kbd>+</kbd> or <kbd>*</kbd>;
Expand All @@ -120,7 +122,7 @@ The [tests](tests/rorschach.rb) include several examples and can be used as a gu
- Created
- Unbounded cell value
- Bounded or unbounded tape
- Interpret <kbd>+</kbd><kbd>-</kbd><kbd>></kbd><kbd><</kbd><kbd>.</kbd><kbd>,</kbd><kbd>[</kbd><kbd>]</kbd> as commands, the rest as comments
- Interpret <kbd>+</kbd><kbd>-</kbd><kbd>></kbd><kbd><</kbd><kbd>.</kbd><kbd>,</kbd><kbd>[</kbd><kbd>]</kbd> as instructions, the rest as comments
- Check brackets before execution
- Output tape when interrupted
- Object oriented style
Expand Down
2 changes: 1 addition & 1 deletion tests/rorschach.rb
Original file line number Diff line number Diff line change
Expand Up @@ -871,7 +871,7 @@ def test_bytecode_mandelbrot
assert_nil(MindFreak.check(program))
bytecode = MindFreak.bytecode(program)
assert_equal(4115, bytecode.size)
assert_equal(2177, MindFreak.optimize(bytecode).size)
assert_equal(1645, MindFreak.optimize(bytecode).size)
# Compare output
File.write(file_c, MindFreak.to_c(program))
['gcc', 'clang'].each {|cc| assert_equal(MANDELBROT, `./#{file_exe}`) if system("#{cc} #{file_c} -o #{file_exe} -O2 -s")}
Expand Down

0 comments on commit 35fc55d

Please sign in to comment.