Skip to content

Instantly share code, notes, and snippets.

@gofer
Created March 31, 2016 08:30
Show Gist options
  • Select an option

  • Save gofer/f1857e4ed33944d29c4fc7b7dcf89eeb to your computer and use it in GitHub Desktop.

Select an option

Save gofer/f1857e4ed33944d29c4fc7b7dcf89eeb to your computer and use it in GitHub Desktop.
Brainf*ck compiler implementation by Ruby
#!/usr/bin/ruby
module Token
INCREMENT_POINTER = 0
DECREMENT_POINTER = 1
INCREMENT_VALUE = 2
DECREMENT_VALUE = 3
BYTE_INPUT = 4
BYTE_OUTPUT = 5
LOOP_BEGIN = 6
LOOP_END = 7
end
module Lexer
def lex(s)
l = []
s.split(//).each { |c|
case c
when self.class::StringByToken::INCREMENT_POINTER then
l.push(Token::INCREMENT_POINTER)
when self.class::StringByToken::DECREMENT_POINTER then
l.push(Token::DECREMENT_POINTER)
when self.class::StringByToken::INCREMENT_VALUE then
l.push(Token::INCREMENT_VALUE)
when self.class::StringByToken::DECREMENT_VALUE then
l.push(Token::DECREMENT_VALUE)
when self.class::StringByToken::BYTE_INPUT then
l.push(Token::BYTE_INPUT)
when self.class::StringByToken::BYTE_OUTPUT then
l.push(Token::BYTE_OUTPUT)
when self.class::StringByToken::LOOP_BEGIN then
l.push(Token::LOOP_BEGIN)
when self.class::StringByToken::LOOP_END then
l.push(Token::LOOP_END)
else
# LexerError
# raise ""
end
}
return l
end
end
module BrainfuckToken
module StringByToken
INCREMENT_POINTER = '>'
DECREMENT_POINTER = '<'
INCREMENT_VALUE = '+'
DECREMENT_VALUE = '-'
BYTE_INPUT = ','
BYTE_OUTPUT = '.'
LOOP_BEGIN = '['
LOOP_END = ']'
end
end
class BrainfuckLexer
include BrainfuckToken
include Lexer
end
class Parser
def self.parse(token_list, index = 0)
stack = []
list = []
while index < token_list.size do
token = token_list[index]
case token
when Token::INCREMENT_POINTER,
Token::DECREMENT_POINTER,
Token::INCREMENT_VALUE,
Token::DECREMENT_VALUE,
Token::BYTE_INPUT,
Token::BYTE_OUTPUT
then
list.push(token)
when Token::LOOP_BEGIN then
if list.size > 0 then
stack.push(list)
end
(new_index, new_list) = parse(token_list, index + 1)
stack.push( new_list.unshift(Token::LOOP_BEGIN) )
index = new_index
list = []
when Token::LOOP_END then
if list.size > 0 then
stack.push(list)
end
return [index, stack.push(Token::LOOP_END)]
else
# ParserError
end
index += 1
end
if list.size > 0 then
stack.push(list)
end
return stack
end
end
class VirtualMachine
def initialize()
@BufferSize = 300000
@buffer = [0] * @BufferSize
@ptr = 0
end
def incrementPointer!()
@ptr += 1
end
def decrementPointer!()
@ptr -= 1
end
def incrementValue!()
@buffer[@ptr] += 1
end
def decrementValue!()
@buffer[@ptr] -= 1
end
def byteInput!()
@buffer[@ptr] = STDIN.getc
end
def byteOutput!()
STDOUT.putc(@buffer[@ptr])
end
def getValue()
@buffer[@ptr]
end
end
class Executor
def self.do_it(vm, token)
case token
when Token::INCREMENT_POINTER then
vm.incrementPointer!
when Token::DECREMENT_POINTER then
vm.decrementPointer!
when Token::INCREMENT_VALUE then
vm.incrementValue!
when Token::DECREMENT_VALUE then
vm.decrementValue!
when Token::BYTE_INPUT then
vm.byteInput!
when Token::BYTE_OUTPUT then
vm.byteOutput!
else
# exception
end
end
def self.exec(vm, tree)
loop_flag = false
begin
tree.each { |sub_tree|
if sub_tree.kind_of?(Array) then
vm = exec(vm, sub_tree)
elsif sub_tree.kind_of?(Integer) then
case sub_tree
when Token::LOOP_BEGIN then
if vm.getValue == 0 then
loop_flag = false
break
else
loop_flag = true
end
when Token::LOOP_END then
if vm.getValue != 0 then
loop_flag = true
else
loop_flag = false
break
end
else
do_it(vm, sub_tree)
end
else
# exception
end
}
end while loop_flag
return vm
end
end
def main(argv)
Executor.exec(
VirtualMachine.new,
Parser.parse(
BrainfuckLexer.new.lex(STDIN.gets.chomp)
)
)
STDOUT.puts ''
end
if self.to_s == 'main' then
main(ARGV)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment