summaryrefslogtreecommitdiff
path: root/AsmLine.py
blob: fc54cbea67fe8b548f7ca7eff64c471e2911efbd (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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#!/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)