Created
March 31, 2016 08:30
-
-
Save gofer/f1857e4ed33944d29c4fc7b7dcf89eeb to your computer and use it in GitHub Desktop.
Brainf*ck compiler implementation by Ruby
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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