#!/usr/bin/env python """Compiles C into assembly for the practicum processor (PP2) Copyright (C) 2011-2014 Peter Wu Licensed under the MIT license . """ __author__ = "Peter Wu" __copyright__ = "Copyright (C) 2011-2014 Peter Wu" __credits__ = ["Peter Wu"] __license__ = "MIT" __version__ = "1.0" __maintainer__ = "Peter Wu" __email__ = "lekensteyn@gmail.com" import re from Asm import Asm from Registers import Registers from NamedId import NamedId class AsmLine(object): asm = Asm() registers = Registers() re_whitespace = re.compile("\s+") def __init__(self, line, id_dict=None): # for storing NamedId objects self.id_dict = id_dict self.label = "" self.register = "" self.operand = "" line = line.split(";", 1)[0].strip() if ":" in line: self.label, line = line.split(":", 1) self.label = self.label.strip() line = line.strip() if self.asm.is_identifier(self.label): # for easier label name manipulation self.getNamedId(self.label) else: self.label = "" line = label + ":" + line parts = self.re_whitespace.split(line, 1) self.instruction = parts[0] if self.instruction in Asm.operators_binary: # a label for sure reg, operand = self.re_whitespace.split(parts[1], 1) self.register = reg self.setOperand(operand) elif self.instruction in Asm.operators_branch: # skip validation of reg for speed self.register = parts[1] elif self.instruction in Asm.operators_unary: self.setOperand(parts[1]) elif self.instruction in Asm.operators_misc_reg: self.register = parts[1] elif self.instruction in Asm.operators_misc_noreg: # no args pass elif self.instruction == "CONS": # pseudo instruction self.setOperand(parts[1]) else: raise RuntimeError("Unknown instruction '{}'".format(self.instruction)) def setOperand(self, str): """Sets the operand for this object either as a string or an identifier object """ if self.id_dict is None: self.operand = str elif self.registers.is_register(str): # register self.operand = [str] else: if str.startswith("["): # split by [ ] and +, grouping multiple occurences self.operand = re.split("([\[\]+]+)", str) else: # value self.operand = [str] for i, part in enumerate(self.operand): # skip empty elements, registers and [ ] + if (part and not self.registers.is_register(part) and part[0] not in "[]+"): # turn named items in an object for easier manipulation of # the names later # if performance is an issue, you may want to skip the name # validity check on the cost of NamedIds pollution if self.asm.is_identifier(part): self.operand[i] = self.getNamedId(part) def getNamedId(self, name): """Returns an NamedId object for keeping a track of all names at once """ # if there is no dictionary to store names, just return the name if self.id_dict is None: return name if name not in self.id_dict: self.id_dict[name] = NamedId(name) return self.id_dict[name] def __str__(self): """Returns a line of assembly""" line = self.instruction.ljust(4) if self.register: line += " " + self.register if self.operand: # join all operand parts together line += " " + "".join(str(elm) for elm in self.operand) return self.asm.format_line(line, self.label)