62 lines
		
	
	
		
			1.5 KiB
		
	
	
	
		
			Crystal
		
	
	
	
	
	
			
		
		
	
	
			62 lines
		
	
	
		
			1.5 KiB
		
	
	
	
		
			Crystal
		
	
	
	
	
	
def new_interpreter(f, p)
 | 
						|
  prog = {} of Int64 => Int64
 | 
						|
  p.each_with_index do |v, i|
 | 
						|
    prog[i.to_i64] = v.to_i64
 | 
						|
  end
 | 
						|
 | 
						|
  input = Channel(Int64).new
 | 
						|
  output = Channel(Int64?).new
 | 
						|
  spawn do
 | 
						|
    op = ""
 | 
						|
    pc = 0_i64
 | 
						|
    base = 0_i64
 | 
						|
    index = ->(i : Int32) {
 | 
						|
      case op[-(3+i)]
 | 
						|
      when '0'
 | 
						|
        prog[pc+1+i]
 | 
						|
      when '1'
 | 
						|
        pc+1+i
 | 
						|
      else
 | 
						|
        prog[pc+1+i] + base
 | 
						|
      end
 | 
						|
    }
 | 
						|
    get = ->(i : Int32) { prog[index.call(i)]? || 0_i64 }
 | 
						|
    set = ->(i : Int32, v : Int64) { prog[index.call(i)] = v }
 | 
						|
    loop do
 | 
						|
      op = "0000" + prog[pc].to_s
 | 
						|
      case op
 | 
						|
      when .ends_with? "1"
 | 
						|
        set.call(2, get.call(0) + get.call(1))
 | 
						|
        pc += 4
 | 
						|
      when .ends_with? "2"
 | 
						|
        set.call(2, get.call(0) * get.call(1))
 | 
						|
        pc += 4
 | 
						|
      when .ends_with? "3"
 | 
						|
        set.call(0, input.receive)
 | 
						|
        pc += 2
 | 
						|
      when .ends_with? "4"
 | 
						|
        output.send(get.call(0))
 | 
						|
        pc += 2
 | 
						|
      when .ends_with? "5"
 | 
						|
        pc = get.call(0) != 0 ? get.call(1) : pc + 3
 | 
						|
      when .ends_with? "6"
 | 
						|
        pc = get.call(0) == 0 ? get.call(1) : pc + 3
 | 
						|
      when .ends_with? "7"
 | 
						|
        set.call(2, get.call(0) < get.call(1) ? 1_i64 : 0_i64)
 | 
						|
        pc += 4
 | 
						|
      when .ends_with? "8"
 | 
						|
        set.call(2, get.call(0) == get.call(1) ? 1_i64 : 0_i64)
 | 
						|
        pc += 4
 | 
						|
      when .ends_with? "99"
 | 
						|
        input.receive
 | 
						|
        output.send(nil)
 | 
						|
        break
 | 
						|
      when .ends_with? "9"
 | 
						|
        base += get.call(0)
 | 
						|
        pc += 2
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
  {input, output}
 | 
						|
end
 |