LoginSignup
1
0

More than 5 years have passed since last update.

brainf*ckを書いてみた

Last updated at Posted at 2012-03-16
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

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);
});

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0