Assembler con label
This commit is contained in:
parent
71266d07c0
commit
c24e2c791f
@ -47,6 +47,7 @@ class InvalidValue(AssemblerException):
|
||||
def __init__(self, instruction):
|
||||
super().__init__("Invalid value while assembling: {}".format(instruction))
|
||||
|
||||
|
||||
class VMAssembler:
|
||||
|
||||
def __init__(self, key):
|
||||
@ -58,7 +59,6 @@ class VMAssembler:
|
||||
action(instruction)
|
||||
|
||||
def process_code_line(self, line):
|
||||
sys.stdout.write("CODE: ")
|
||||
components = [x for x in re.split('\W', line) if x]
|
||||
instruction = VMInstruction(components[0], components[1:])
|
||||
sys.stdout.write(str(instruction) + "\n")
|
||||
@ -166,6 +166,21 @@ class VMAssembler:
|
||||
self.assembled_code += opcode.uint8() + imm.uint16()
|
||||
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):
|
||||
"""
|
||||
Instruction with no arguments
|
||||
@ -242,7 +257,7 @@ class VMComponent:
|
||||
return True
|
||||
|
||||
def isimm(self):
|
||||
if self.name != self.value:
|
||||
if not immediate_re.match(str(self.name)):
|
||||
return False
|
||||
return True
|
||||
|
||||
@ -256,23 +271,59 @@ class VMInstruction:
|
||||
"""
|
||||
|
||||
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)
|
||||
if self.opcode == None:
|
||||
raise InvalidOperation(opcode)
|
||||
self.args = []
|
||||
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
|
||||
reg_comp = next((x for x in regs if x.name == el), None)
|
||||
self.args.append(reg_comp)
|
||||
self.size += 1
|
||||
continue
|
||||
else:
|
||||
# directly append the immediate
|
||||
self.args.append(VMComponent(el, el))
|
||||
# section
|
||||
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):
|
||||
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"],
|
||||
["MOVR", "reg2reg"],
|
||||
["LOAD", "imm2reg"],
|
||||
@ -299,30 +350,54 @@ op_names = [["MOVI", "imm2reg"],
|
||||
["POOP", "regonly"],
|
||||
["CMPI", "imm2reg"],
|
||||
["CMPR", "reg2reg"],
|
||||
["JMPI", "immonly"],
|
||||
["JMPR", "regonly"],
|
||||
["JPAI", "immonly"],
|
||||
["JPAR", "regonly"],
|
||||
["JPBI", "immonly"],
|
||||
["JPBR", "regonly"],
|
||||
["JPEI", "immonly"],
|
||||
["JPER", "regonly"],
|
||||
["JPNI", "immonly"],
|
||||
["JPNR", "regonly"],
|
||||
["JMPI", "jump"],
|
||||
["JMPR", "jump"],
|
||||
["JPAI", "jump"],
|
||||
["JPAR", "jump"],
|
||||
["JPBI", "jump"],
|
||||
["JPBR", "jump"],
|
||||
["JPEI", "jump"],
|
||||
["JPER", "jump"],
|
||||
["JPNI", "jump"],
|
||||
["JPNR", "jump"],
|
||||
["SHIT", "single"],
|
||||
["NOPE", "single"],
|
||||
["GRMN", "single"]]
|
||||
|
||||
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)]
|
||||
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):
|
||||
sys.stdout.write("DATA:\t")
|
||||
sys.stdout.write(line.strip(",") + "\n")
|
||||
def parse_sections(lines):
|
||||
current_size = 0
|
||||
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():
|
||||
@ -330,22 +405,25 @@ def main():
|
||||
print("Usage: {} opcodes_key file_to_assemble output".format(
|
||||
sys.argv[0]))
|
||||
return
|
||||
|
||||
vma = VMAssembler(sys.argv[1])
|
||||
with open(sys.argv[2], 'r') as f:
|
||||
gen = (line.casefold().strip() for line in f if line != "\n")
|
||||
flag = None
|
||||
filedata = f.readlines()
|
||||
filedata = [x.strip() for x in filedata if x.strip()]
|
||||
|
||||
for line in gen:
|
||||
if line in section_flags:
|
||||
flag = section_flags[line]
|
||||
continue
|
||||
if flag == section_flags["data:"]:
|
||||
# let's parse the whole file for labels
|
||||
parse_sections(filedata)
|
||||
|
||||
if "main" not in [x.name for x in sections]:
|
||||
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)
|
||||
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:
|
||||
f.write(vma.assembled_code)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user