mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
Implement a small elf-script to C transpiler.
This commit is contained in:
162
2018/other/elf2c.py
Executable file
162
2018/other/elf2c.py
Executable file
@@ -0,0 +1,162 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import argparse
|
||||||
|
import string
|
||||||
|
import textwrap
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def preamble():
|
||||||
|
return textwrap.dedent('''\
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int a = 1;
|
||||||
|
int b = 0;
|
||||||
|
int c = 0;
|
||||||
|
int d = 0;
|
||||||
|
int e = 0;
|
||||||
|
int f = 0;''')
|
||||||
|
|
||||||
|
|
||||||
|
def footer():
|
||||||
|
return textwrap.dedent('''\
|
||||||
|
program_end:
|
||||||
|
printf("[%d, %d, %d, %d, %d, %d]", a, b, c, d, e, f);
|
||||||
|
}''')
|
||||||
|
|
||||||
|
|
||||||
|
def reg_name(num):
|
||||||
|
return string.ascii_lowercase[num]
|
||||||
|
|
||||||
|
|
||||||
|
def exhaustive_jump(reg, base, lines):
|
||||||
|
code = '{\n\tswitch (%s + %s) {\n' % (reg_name(reg), base)
|
||||||
|
for i in range(lines):
|
||||||
|
code += '\t\tcase %d: goto line_%d;\n' % (i, i)
|
||||||
|
|
||||||
|
code += textwrap.dedent('''\
|
||||||
|
default: abort();
|
||||||
|
}
|
||||||
|
}''')
|
||||||
|
|
||||||
|
return code
|
||||||
|
|
||||||
|
|
||||||
|
def get_var(ir, var, ip, i):
|
||||||
|
if ir == 'i':
|
||||||
|
return var
|
||||||
|
elif var == ip:
|
||||||
|
return i
|
||||||
|
else:
|
||||||
|
return reg_name(var)
|
||||||
|
|
||||||
|
|
||||||
|
def compile(lines):
|
||||||
|
ip = int(next(lines).strip().split()[-1])
|
||||||
|
|
||||||
|
lines = [line for line in lines]
|
||||||
|
|
||||||
|
code = []
|
||||||
|
|
||||||
|
cond = None
|
||||||
|
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
line = line.strip()
|
||||||
|
parts = line.split()
|
||||||
|
op = parts[0]
|
||||||
|
var = [int(x) for x in parts[1:]]
|
||||||
|
|
||||||
|
code_line = 'line_%d:\n' % i
|
||||||
|
if cond is not None:
|
||||||
|
code_line += '\t'
|
||||||
|
if var[2] == ip:
|
||||||
|
target = None
|
||||||
|
target_reg = None
|
||||||
|
if op == 'seti':
|
||||||
|
target = var[0]
|
||||||
|
elif op == 'addi':
|
||||||
|
if var[0] == ip:
|
||||||
|
target = i + var[1]
|
||||||
|
else:
|
||||||
|
sys.exit('Illegal jump at \'%s\'' % line)
|
||||||
|
elif op == 'addr':
|
||||||
|
if var[0] == ip and cond == var[1] \
|
||||||
|
or var[1] == ip and cond == var[0]:
|
||||||
|
target = i + 1
|
||||||
|
else:
|
||||||
|
if var[0] == ip:
|
||||||
|
target_reg = var[1]
|
||||||
|
elif var[1] == ip:
|
||||||
|
target_reg = var[0]
|
||||||
|
else:
|
||||||
|
sys.exit('Illegal jump at \'%s\'' % line)
|
||||||
|
elif op == 'mulr':
|
||||||
|
if var[0] == ip and var[1] == ip:
|
||||||
|
target = i * i
|
||||||
|
else:
|
||||||
|
sys.exit('Illegal jump at \'%s\'' % line)
|
||||||
|
else:
|
||||||
|
sys.exit('Illegal jump at \'%s\'' % line)
|
||||||
|
|
||||||
|
cond = None
|
||||||
|
if target is not None:
|
||||||
|
if target + 1 < len(lines):
|
||||||
|
code_line += 'goto line_%d;' % (target + 1)
|
||||||
|
else:
|
||||||
|
code_line += 'goto program_end;'
|
||||||
|
elif target_reg is not None:
|
||||||
|
code_line += exhaustive_jump(target_reg, i + 1, len(lines))
|
||||||
|
else:
|
||||||
|
sys.exit('Invalid compiler state')
|
||||||
|
else:
|
||||||
|
cond = None
|
||||||
|
if op[:2] in ['gt', 'eq']:
|
||||||
|
cond = var[2]
|
||||||
|
if op[:2] == 'gt':
|
||||||
|
comp = '>'
|
||||||
|
else:
|
||||||
|
comp = '=='
|
||||||
|
|
||||||
|
var1 = get_var(op[2], var[0], ip, i)
|
||||||
|
var2 = get_var(op[3], var[1], ip, i)
|
||||||
|
code_line += 'if (%s %s %s)' % (var1, comp, var2)
|
||||||
|
elif op[:3] == 'set':
|
||||||
|
var1 = get_var(op[3], var[0], ip, i)
|
||||||
|
target = reg_name(var[2])
|
||||||
|
code_line += '%s = %s;' % (target, var1)
|
||||||
|
else:
|
||||||
|
var1 = get_var('r', var[0], ip, i)
|
||||||
|
var2 = get_var(op[3], var[1], ip, i)
|
||||||
|
target = reg_name(var[2])
|
||||||
|
|
||||||
|
ops = {
|
||||||
|
'mul': '*',
|
||||||
|
'add': '+',
|
||||||
|
'bor': '|',
|
||||||
|
'ban': '&',
|
||||||
|
}
|
||||||
|
|
||||||
|
op = ops[op[:3]]
|
||||||
|
code_line += '%s = %s %s %s;' % (target, var1, op, var2)
|
||||||
|
|
||||||
|
code.append(code_line)
|
||||||
|
|
||||||
|
print(preamble())
|
||||||
|
print('\n'.join(code))
|
||||||
|
print(footer())
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('file')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
with open(args.file, 'rt') as f:
|
||||||
|
compile(f)
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user