brainf*ckを書いてみた

```ruby:brainfuck.rb
class Tape
  def initialize
    @position = 0
    @tape = [0]
  end

  def get
    @tape[@position]
  end

  def set(val)
    @tape[@position] = val 
  end

  def inc
    @tape[@position] += 1
  end

  def dec
    @tape[@position] -= 1
  end

  def advance
    @position += 1
    @tape.push(0) if @tape.size <= @position
  end

  def devance
    @position -= 1
  end
end

def mainloop(program, map)
  pc = 0
  tape = Tape.new

  while (pc < program.size)
    c = program[pc]
    case c
    when '+'
      tape.inc
    when '-'
      tape.dec
    when '>'
      tape.advance
    when '<'
      tape.devance
    when '['
      pc = map[pc] if tape.get == 0
    when ']'
      pc = map[pc] if tape.get != 0
    when '.'
      print tape.get.chr
    when ','
    end
    pc += 1
  end
end

def parse(program)
  parsed = []
  map = {}
  stack = []
  keywords = ['[',']','<','>','+','-',',','.']

  pc = 0
  program.each_byte do |c|
    c = c.chr
    next unless keywords.include?(c)
    parsed.push c
    if c == '['
      stack.push pc
    elsif c == ']'
      left = stack.pop
      right = pc
      map[left] = right
      map[right] = left
    end
    pc += 1
  end

  return parsed.join(''), map
end

def run(input)
  program, map = parse(input)
  mainloop(program, map)
end

open(ARGV[0]) do |f|
  run(f.read)
end

```

```javascript:brainfuck.js
var Tape = function() {
  this.tape = [0];
  this.position = 0;
  this.inc = function(){ this.tape[this.position]++; };
  this.dec = function(){ this.tape[this.position]--; };
  this.advance = function(){
    this.position++;
    if(this.tape.length <= this.position)
      this.tape.push(0);
  };
  this.devance = function(){ this.position--; };
  this.get = function(){ return this.tape[this.position]; };
  this.set = function(val){ this.tape[this.position] = val; };
}


function mainloop(program, map){
  var tape = new Tape(),
      pc = 0;
  while(pc < program.length) {
    var c = program[pc];
    switch(c) {
      case '+':
        tape.inc();
        break;
      case '-':
        tape.dec();
        break;
      case '>':
        tape.advance();
        break;
      case '<':
        tape.devance();
        break;
      case '.':
        process.stdout.write(String.fromCharCode(tape.get()));
        break;
      case ',':
        break;
      case '[':
        if(tape.get() === 0)
          pc = map[String(pc)];
        break;
      case ']':
        if(tape.get() !== 0)
          pc = map[String(pc)];
        break;
    }
    pc++;
  }
}

function parse(program){
  var keywords = ['[',']','<','>','+','-',',','.'],
      parsed = [],
      map = {},
      stack = [],
      pc = 0;
  program.split('').forEach(function(c){
    if (keywords.indexOf(c) > -1) {
      parsed.push(c);
      if(c === '['){
        stack.push(pc);
      }else if(c === ']'){
        var left = stack.pop(),
            right = pc;
        map[left] = right;
        map[right] = left;
      }
      pc++;
    }
  });
  return {parsed:parsed.join(''),map:map}
}
function run(input){
  var data = parse(input);
  mainloop(data['parsed'], data['map']);
}

var fs = require('fs');

fs.readFile(process.argv[2], 'utf-8', function(err, data){
  if(err) throw err;
  run(data);
});

```