summaryrefslogtreecommitdiff
path: root/Asm.py
blob: 018b4de3409b55a170bfa0df4ab38a52e6fc81a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#!/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

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"