#!/usr/bin/env python """Compiles C into assembly for the practicum processor (PP2) All rights reserved, you may not redistribute or use this program without prior permission from Peter Wu or Xander Houtman. Use of this program is entirely your own risk. In no circumstances can the authors of this program be held responsible for any damage including, but not limited to, financial damage or data loss. Modification of this program is not allowed without prior permission. The generated output (assembly and messages) are not subject to this license. """ __author__ = "Peter Wu" __copyright__ = "Copyright 2011, Peter Wu" __credits__ = ["Peter Wu"] __license__ = "Proprietary" __version__ = "1.0" __maintainer__ = "Peter Wu" __email__ = "uwretep@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)