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
|
#!/usr/bin/env python
"""Compiles C into assembly for the practicum processor (PP2)
Copyright (C) 2011-2014 Peter Wu <lekensteyn@gmail.com>
Licensed under the MIT license <http://opensource.org/licenses/MIT>.
"""
__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)
|