Assembler con label
This commit is contained in:
parent
71266d07c0
commit
c24e2c791f
@ -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)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user