


from translator import *
    
    
D = ['OOPS!', 
    'write_ram(%(destination)i, read_ram(%(r1)i) + read_ram(%(r2)i));', 
    'write_ram(%(destination)i, read_ram(%(r1)i) - read_ram(%(r2)i));', 
    'write_ram(%(destination)i, read_ram(%(r1)i) * read_ram(%(r2)i));', 
    'write_ram(%(destination)i, safe_div(read_ram(%(r1)i), read_ram(%(r2)i)));', 
    'write_output(%(r1)i, read_ram(%(r2)i));', 
    'write_ram(%(destination)i, flag() ? read_ram(%(r1)i) : read_ram(%(r2)i));'
]

S = [
    '// offset 0x%(destination)x (%(destination)i): ', 
    'flag(read_ram(%(r1)i) %(imm)s 0.0);', 
    'write_ram(%(destination)i, std::sqrt(read_ram(%(r1)i)));',
    'write_ram(%(destination)i, read_ram(%(r1)i));', 
    'write_ram(%(destination)i, read_input(%(r1)i));'
]

def decode(little_endian_bytes, index):
    parsed = d_opcode.parse(little_endian_bytes)
    OP = parsed.op_code
    if OP:        
        result = D[OP] % dict( 
            r1 = parsed.r1,
            r2 = parsed.r2,
            destination = index, 
        )
        print result
        return result
    else:
        parsed = s_opcode.parse(little_endian_bytes)
        OP = parsed.op_code
        result = S[OP] % dict( 
            r1 = parsed.r1,
            imm = ['<','<=','==','>=','>'][parsed.imm >> 7],
            destination = index, 
        )
        print result
        return result
    return ''
    

    
def generate_cpp_class(instructions, float_data, do, *a, **kw):
    decoded_instructions = []
    index = 0
    for instruction in instructions:
        decoded_instructions.append(decode(instruction, index))
        index += 1
        
    do("""
double safe_div(double a, doube b) {
    if (b == 0.0) return 0.0;
    return a/b;
}

public class machine : icfp::ovm {    
    std::size_t exec_clocktick() {
        %(instructions)s
        return clocktick();
    }
}
    """ % dict(
        instructions = '\n        '.join(decoded_instructions),
        float_data = float_data,
    ), *a, **kw)
    

def write_cpp_class(instructions, float_data, filename):
    generate_cpp_class(instructions, float_data, write_file, filename)
    

translate(open("../binaries/bin1.obf", "rb"), write_cpp_class, "../Python/translated_binaries/bin1.cpp")
translate(open("../binaries/bin2.obf", "rb"), write_cpp_class, "../Python/translated_binaries/bin2.cpp")
translate(open("../binaries/bin3.obf", "rb"), write_cpp_class, "../Python/translated_binaries/bin3.cpp")
