#!/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 class Asm(object): id_re = "[a-zA-Z_][0-9a-zA-Z_]*" re_identifier = re.compile("^" + id_re + "$") re_label = re.compile("^\s*" + id_re + "\s*:") # these instructions accept a label name operators_branch = ("BEQ", "BNE", "BCS", "BCC", "BLS", "BHI", "BVC", "BVS", "BPL", "BMI", "BLT", "BGE", "BLE", "BGT", "BRA", "BRS") # these instructions are weird. operators_unary = ("JMP", "JSR", "CLRI", "SETI", "PSEM", "VSEM") # these instructions accept a register (arg 1) and addressing mode (arg 2) operators_binary = ("LOAD", "ADD", "SUB", "CMP", "MULS", "MULL", "CHCK", "DIV", "MOD", "DVMD", "AND", "OR", "XOR", "STOR") # these operators accept a register operators_misc_reg = ("PUSH", "PULL") # these instructions accept no args operators_misc_noreg = ("RTS", "RTE") operators_misc = operators_misc_reg + operators_misc_noreg # all available operators operators_all = operators_branch + operators_unary + operators_binary operators_all += operators_misc def __init__(self): self.level = 0 def is_identifier(self, text): return self.re_identifier.match(text) is not None def format_line(self, line, label="", indent_size=-1): """Returns an indented line optionally prefixed with label""" if indent_size < 0: indent_size = 8 + self.level * 4 if label: indent_size -= len(label) + 2 if indent_size >= 0: label += ": " else: label += ":" # strip the previous label and indentation line = self.re_label.sub("", line).rstrip("") # whitespace is generated if indent_size > 0 indent = indent_size * " " return indent + label + line def binary_op(self, binop, reg, operand, label=""): # output format: BBBB RR OO... return self.format_line("{:<4} {:<2} {}".format(binop, reg, operand), label) def unary_op(self, unop, operand, label=""): # output format: UUUU OO... return self.format_line("{:<4} {}".format(unop, operand), label) def branch_op(self, brop, branch_label, label=""): # output format: BBB LL... return self.format_line("{:<4} {}".format(brop, branch_label), label) def push(self, register, label=""): return self.format_line("PUSH " + register, label) def pull(self, register, label=""): return self.format_line("PULL " + register, label) def insert_label(self, instruction, label): new_instruction = instruction.lstrip(" ") indent_size = len(instruction) - len(new_instruction) return self.format_line(new_instruction, label, indent_size) def has_label(self, line): """Returns True if a line appears to contain a label, False otherwise""" return self.get_label(line) != "" def get_label(self, line): """Returns the label if any""" label = self.re_label.match(line) if label is None: return "" return label[0].strip(": ") def noop(self, label, register="R0"): """Returns a labelled no operation operator Note that the Zero, Negative and oVerflow flags are modified """ return self.binary_op("LOAD", register, register, label) + " ; NOOP"