Assembler con label

This commit is contained in:
Giulio De Pasquale 2017-05-18 20:53:28 +02:00
parent 71266d07c0
commit c24e2c791f

View File

@ -47,6 +47,7 @@ class InvalidValue(AssemblerException):
def __init__(self, instruction): def __init__(self, instruction):
super().__init__("Invalid value while assembling: {}".format(instruction)) super().__init__("Invalid value while assembling: {}".format(instruction))
class VMAssembler: class VMAssembler:
def __init__(self, key): def __init__(self, key):
@ -58,7 +59,6 @@ class VMAssembler:
action(instruction) action(instruction)
def process_code_line(self, line): def process_code_line(self, line):
sys.stdout.write("CODE: ")
components = [x for x in re.split('\W', line) if x] components = [x for x in re.split('\W', line) if x]
instruction = VMInstruction(components[0], components[1:]) instruction = VMInstruction(components[0], components[1:])
sys.stdout.write(str(instruction) + "\n") sys.stdout.write(str(instruction) + "\n")
@ -166,6 +166,21 @@ class VMAssembler:
self.assembled_code += opcode.uint8() + imm.uint16() self.assembled_code += opcode.uint8() + imm.uint16()
return return
def jump(self, instruction):
imm_op_re = re.compile(".*[iI]$")
reg_op_re = re.compile(".*[rR]$")
arg = instruction.args[0]
section = next((x for x in sections if x.name == arg.name), None)
# TODO this is due the VMComponent structure
instruction.args[0].name = section.offset
instruction.args[0].value = section.offset
if imm_op_re.match(instruction.opcode.name):
self.immonly(instruction)
elif reg_op_re.match(instruction.opcode.name):
self.regonly(instruction)
else:
raise AssemblerException()
def single(self, instruction): def single(self, instruction):
""" """
Instruction with no arguments Instruction with no arguments
@ -242,7 +257,7 @@ class VMComponent:
return True return True
def isimm(self): def isimm(self):
if self.name != self.value: if not immediate_re.match(str(self.name)):
return False return False
return True return True
@ -256,23 +271,59 @@ class VMInstruction:
""" """
def __init__(self, opcode, instr_list): def __init__(self, opcode, instr_list):
immediate_regexp = re.compile("^(0x*|[0-9]*$)") self.opcode = None
self.args = None
self.size = 1
self.opcode = next((x for x in ops if x.name == opcode), None) self.opcode = next((x for x in ops if x.name == opcode), None)
if self.opcode == None: if self.opcode == None:
raise InvalidOperation(opcode) raise InvalidOperation(opcode)
self.args = [] self.args = []
for el in instr_list: for el in instr_list:
if not immediate_regexp.match(el): if immediate_re.match(el):
# directly append the immediate
self.args.append(VMComponent(el, el))
self.size += 2
continue
elif register_re.match(el):
# create a VM component for a register # create a VM component for a register
reg_comp = next((x for x in regs if x.name == el), None) reg_comp = next((x for x in regs if x.name == el), None)
self.args.append(reg_comp) self.args.append(reg_comp)
self.size += 1
continue
else: else:
# directly append the immediate # section
self.args.append(VMComponent(el, el)) sec_comp = next((x for x in sections if x.name == el), None)
if sec_comp:
self.args.append(VMComponent(
sec_comp.name, sec_comp.offset))
self.size += 2
continue
raise AssemblerException()
def __repr__(self): def __repr__(self):
return "{} {}".format(self.opcode.name, ", ".join([x.name for x in self.args])) return "{} {}".format(self.opcode.name, ", ".join([x.name for x in self.args]))
class VMSection:
"""
Represents a code section or "label" such as "main:"
"""
def __init__(self, name):
self.name = name
self.size = 0
self.offset = 0
def set_size(self, size):
self.size = size
def set_offset(self, offset):
self.offset = offset
def __repr__(self):
return "{} | s: {}, o: {}".format(self.name, hex(self.size), hex(self.offset))
op_names = [["MOVI", "imm2reg"], op_names = [["MOVI", "imm2reg"],
["MOVR", "reg2reg"], ["MOVR", "reg2reg"],
["LOAD", "imm2reg"], ["LOAD", "imm2reg"],
@ -299,30 +350,54 @@ op_names = [["MOVI", "imm2reg"],
["POOP", "regonly"], ["POOP", "regonly"],
["CMPI", "imm2reg"], ["CMPI", "imm2reg"],
["CMPR", "reg2reg"], ["CMPR", "reg2reg"],
["JMPI", "immonly"], ["JMPI", "jump"],
["JMPR", "regonly"], ["JMPR", "jump"],
["JPAI", "immonly"], ["JPAI", "jump"],
["JPAR", "regonly"], ["JPAR", "jump"],
["JPBI", "immonly"], ["JPBI", "jump"],
["JPBR", "regonly"], ["JPBR", "jump"],
["JPEI", "immonly"], ["JPEI", "jump"],
["JPER", "regonly"], ["JPER", "jump"],
["JPNI", "immonly"], ["JPNI", "jump"],
["JPNR", "regonly"], ["JPNR", "jump"],
["SHIT", "single"], ["SHIT", "single"],
["NOPE", "single"], ["NOPE", "single"],
["GRMN", "single"]] ["GRMN", "single"]]
reg_names = ["R0", "R1", "R2", "R3", "S0", "S1", "S2", "S3", "IP", "BP", "SP"] reg_names = ["R0", "R1", "R2", "R3", "S0", "S1", "S2", "S3", "IP", "BP", "SP"]
section_names = ["DATA:", "CODE:", "STACK:"]
section_flags = {s.casefold(): i + 1 for i, s in enumerate(section_names)}
ops = [VMComponent(le[0], i, le[1]) for i, le in enumerate(op_names)] ops = [VMComponent(le[0], i, le[1]) for i, le in enumerate(op_names)]
regs = [VMComponent(s.casefold(), i) for i, s in enumerate(reg_names)] regs = [VMComponent(s.casefold(), i) for i, s in enumerate(reg_names)]
sections = []
section_re = re.compile("[a-zA-Z]*\:$")
immediate_re = re.compile("^[0-9].*")
register_re = re.compile("(^[rRsS]{1}[0-9]{1}$)|([iIbBsS]{1}[pP]{1}$)")
def assemble_data(line): def parse_sections(lines):
sys.stdout.write("DATA:\t") current_size = 0
sys.stdout.write(line.strip(",") + "\n") current_section = None
for line in lines:
if section_re.match(line):
if current_section:
tmp = next(x for x in sections if x.name == current_section)
tmp.set_size(current_size)
current_section = line.casefold()[:-1]
sections.append(VMSection(current_section))
current_size = 0
continue
components = [x for x in re.split('\W', line) if x]
instruction = VMInstruction(components[0], components[1:])
current_size += instruction.size
tmp = next(x for x in sections if x.name == current_section)
tmp.set_size(current_size)
def calc_section_offsets():
current_offset = 0
for i in range(1, len(sections)):
prev_size = sections[i - 1].size
current_offset += prev_size
sections[i].set_offset(current_offset)
def main(): def main():
@ -330,22 +405,25 @@ def main():
print("Usage: {} opcodes_key file_to_assemble output".format( print("Usage: {} opcodes_key file_to_assemble output".format(
sys.argv[0])) sys.argv[0]))
return return
vma = VMAssembler(sys.argv[1]) vma = VMAssembler(sys.argv[1])
with open(sys.argv[2], 'r') as f: with open(sys.argv[2], 'r') as f:
gen = (line.casefold().strip() for line in f if line != "\n") filedata = f.readlines()
flag = None filedata = [x.strip() for x in filedata if x.strip()]
for line in gen: # let's parse the whole file for labels
if line in section_flags: parse_sections(filedata)
flag = section_flags[line]
continue if "main" not in [x.name for x in sections]:
if flag == section_flags["data:"]: sys.stderr.write("No main specified!")
return
calc_section_offsets()
for line in filedata:
if not section_re.match(line):
vma.process_code_line(line) vma.process_code_line(line)
elif flag == section_flags["code:"]:
vma.process_code_line(line)
if not flag:
sys.stderr.write(
"Nothing was assembled! Did you use the section delimiters?\n")
with open(sys.argv[3], 'wb') as f: with open(sys.argv[3], 'wb') as f:
f.write(vma.assembled_code) f.write(vma.assembled_code)